Format script component

This commit is contained in:
chansuke 2018-09-18 23:24:15 +09:00 committed by Josh Matthews
parent 2ca7a13473
commit c37a345dc9
357 changed files with 25485 additions and 18076 deletions

View file

@ -35,7 +35,7 @@ pub enum BodyType {
FormData, FormData,
Json, Json,
Text, Text,
ArrayBuffer ArrayBuffer,
} }
pub enum FetchedData { pub enum FetchedData {
@ -44,7 +44,7 @@ pub enum FetchedData {
BlobData(DomRoot<Blob>), BlobData(DomRoot<Blob>),
FormData(DomRoot<FormData>), FormData(DomRoot<FormData>),
ArrayBuffer(RootedTraceableBox<Heap<*mut JSObject>>), ArrayBuffer(RootedTraceableBox<Heap<*mut JSObject>>),
JSException(RootedTraceableBox<Heap<JSVal>>) JSException(RootedTraceableBox<Heap<JSVal>>),
} }
// https://fetch.spec.whatwg.org/#concept-body-consume-body // https://fetch.spec.whatwg.org/#concept-body-consume-body
@ -72,19 +72,19 @@ pub fn consume_body<T: BodyOperations + DomObject>(object: &T, body_type: BodyTy
// https://fetch.spec.whatwg.org/#concept-body-consume-body // https://fetch.spec.whatwg.org/#concept-body-consume-body
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
pub fn consume_body_with_promise<T: BodyOperations + DomObject>(object: &T, pub fn consume_body_with_promise<T: BodyOperations + DomObject>(
object: &T,
body_type: BodyType, body_type: BodyType,
promise: &Promise) { promise: &Promise,
) {
// Step 5 // Step 5
let body = match object.take_body() { let body = match object.take_body() {
Some(body) => body, Some(body) => body,
None => return, None => return,
}; };
let pkg_data_results = run_package_data_algorithm(object, let pkg_data_results =
body, run_package_data_algorithm(object, body, body_type, object.get_mime_type());
body_type,
object.get_mime_type());
match pkg_data_results { match pkg_data_results {
Ok(results) => { Ok(results) => {
@ -103,11 +103,12 @@ pub fn consume_body_with_promise<T: BodyOperations + DomObject>(object: &T,
// https://fetch.spec.whatwg.org/#concept-body-package-data // https://fetch.spec.whatwg.org/#concept-body-package-data
#[allow(unsafe_code)] #[allow(unsafe_code)]
fn run_package_data_algorithm<T: BodyOperations + DomObject>(object: &T, fn run_package_data_algorithm<T: BodyOperations + DomObject>(
object: &T,
bytes: Vec<u8>, bytes: Vec<u8>,
body_type: BodyType, body_type: BodyType,
mime_type: Ref<Vec<u8>>) mime_type: Ref<Vec<u8>>,
-> Fallible<FetchedData> { ) -> Fallible<FetchedData> {
let global = object.global(); let global = object.global();
let cx = global.get_cx(); let cx = global.get_cx();
let mime = &*mime_type; let mime = &*mime_type;
@ -116,40 +117,45 @@ fn run_package_data_algorithm<T: BodyOperations + DomObject>(object: &T,
BodyType::Json => run_json_data_algorithm(cx, bytes), BodyType::Json => run_json_data_algorithm(cx, bytes),
BodyType::Blob => run_blob_data_algorithm(&global, bytes, mime), BodyType::Blob => run_blob_data_algorithm(&global, bytes, mime),
BodyType::FormData => run_form_data_algorithm(&global, bytes, mime), BodyType::FormData => run_form_data_algorithm(&global, bytes, mime),
BodyType::ArrayBuffer => unsafe { BodyType::ArrayBuffer => unsafe { run_array_buffer_data_algorithm(cx, bytes) },
run_array_buffer_data_algorithm(cx, bytes)
}
} }
} }
fn run_text_data_algorithm(bytes: Vec<u8>) -> Fallible<FetchedData> { fn run_text_data_algorithm(bytes: Vec<u8>) -> Fallible<FetchedData> {
Ok(FetchedData::Text(String::from_utf8_lossy(&bytes).into_owned())) Ok(FetchedData::Text(
String::from_utf8_lossy(&bytes).into_owned(),
))
} }
#[allow(unsafe_code)] #[allow(unsafe_code)]
fn run_json_data_algorithm(cx: *mut JSContext, fn run_json_data_algorithm(cx: *mut JSContext, bytes: Vec<u8>) -> Fallible<FetchedData> {
bytes: Vec<u8>) -> Fallible<FetchedData> {
let json_text = String::from_utf8_lossy(&bytes); let json_text = String::from_utf8_lossy(&bytes);
let json_text: Vec<u16> = json_text.encode_utf16().collect(); let json_text: Vec<u16> = json_text.encode_utf16().collect();
rooted!(in(cx) let mut rval = UndefinedValue()); rooted!(in(cx) let mut rval = UndefinedValue());
unsafe { unsafe {
if !JS_ParseJSON(cx, if !JS_ParseJSON(
cx,
json_text.as_ptr(), json_text.as_ptr(),
json_text.len() as u32, json_text.len() as u32,
rval.handle_mut()) { rval.handle_mut(),
) {
rooted!(in(cx) let mut exception = UndefinedValue()); rooted!(in(cx) let mut exception = UndefinedValue());
assert!(JS_GetPendingException(cx, exception.handle_mut())); assert!(JS_GetPendingException(cx, exception.handle_mut()));
JS_ClearPendingException(cx); JS_ClearPendingException(cx);
return Ok(FetchedData::JSException(RootedTraceableBox::from_box(Heap::boxed(exception.get())))); return Ok(FetchedData::JSException(RootedTraceableBox::from_box(
Heap::boxed(exception.get()),
)));
} }
let rooted_heap = RootedTraceableBox::from_box(Heap::boxed(rval.get())); let rooted_heap = RootedTraceableBox::from_box(Heap::boxed(rval.get()));
Ok(FetchedData::Json(rooted_heap)) Ok(FetchedData::Json(rooted_heap))
} }
} }
fn run_blob_data_algorithm(root: &GlobalScope, fn run_blob_data_algorithm(
root: &GlobalScope,
bytes: Vec<u8>, bytes: Vec<u8>,
mime: &[u8]) -> Fallible<FetchedData> { mime: &[u8],
) -> Fallible<FetchedData> {
let mime_string = if let Ok(s) = String::from_utf8(mime.to_vec()) { let mime_string = if let Ok(s) = String::from_utf8(mime.to_vec()) {
s s
} else { } else {
@ -159,14 +165,19 @@ fn run_blob_data_algorithm(root: &GlobalScope,
Ok(FetchedData::BlobData(blob)) Ok(FetchedData::BlobData(blob))
} }
fn run_form_data_algorithm(root: &GlobalScope, bytes: Vec<u8>, mime: &[u8]) -> Fallible<FetchedData> { fn run_form_data_algorithm(
root: &GlobalScope,
bytes: Vec<u8>,
mime: &[u8],
) -> Fallible<FetchedData> {
let mime_str = if let Ok(s) = str::from_utf8(mime) { let mime_str = if let Ok(s) = str::from_utf8(mime) {
s s
} else { } else {
"" ""
}; };
let mime: Mime = mime_str.parse().map_err( let mime: Mime = mime_str
|_| Error::Type("Inappropriate MIME-type for Body".to_string()))?; .parse()
.map_err(|_| Error::Type("Inappropriate MIME-type for Body".to_string()))?;
match mime { match mime {
// TODO // TODO
// ... Parser for Mime(TopLevel::Multipart, SubLevel::FormData, _) // ... Parser for Mime(TopLevel::Multipart, SubLevel::FormData, _)
@ -184,9 +195,13 @@ fn run_form_data_algorithm(root: &GlobalScope, bytes: Vec<u8>, mime: &[u8]) -> F
} }
#[allow(unsafe_code)] #[allow(unsafe_code)]
unsafe fn run_array_buffer_data_algorithm(cx: *mut JSContext, bytes: Vec<u8>) -> Fallible<FetchedData> { unsafe fn run_array_buffer_data_algorithm(
cx: *mut JSContext,
bytes: Vec<u8>,
) -> Fallible<FetchedData> {
rooted!(in(cx) let mut array_buffer_ptr = ptr::null_mut::<JSObject>()); rooted!(in(cx) let mut array_buffer_ptr = ptr::null_mut::<JSObject>());
let arraybuffer = ArrayBuffer::create(cx, CreateWith::Slice(&bytes), array_buffer_ptr.handle_mut()); let arraybuffer =
ArrayBuffer::create(cx, CreateWith::Slice(&bytes), array_buffer_ptr.handle_mut());
if arraybuffer.is_err() { if arraybuffer.is_err() {
return Err(Error::JSFailed); return Err(Error::JSFailed);
} }

View file

@ -31,22 +31,34 @@ fn main() {
build.generator("Ninja"); build.generator("Ninja");
// because we're using ninja, we need to explicitly set these // because we're using ninja, we need to explicitly set these
// to VC++, otherwise it'll try to use cc // to VC++, otherwise it'll try to use cc
build.define("CMAKE_C_COMPILER", "cl.exe") build
.define("CMAKE_C_COMPILER", "cl.exe")
.define("CMAKE_CXX_COMPILER", "cl.exe"); .define("CMAKE_CXX_COMPILER", "cl.exe");
// We have to explicitly specify the full path to link.exe, // We have to explicitly specify the full path to link.exe,
// for reasons that I don't understand. If we just give // for reasons that I don't understand. If we just give
// link.exe, it tries to use script-*/out/link.exe, which of // link.exe, it tries to use script-*/out/link.exe, which of
// course does not exist. // course does not exist.
let link = std::process::Command::new("where").arg("link.exe").output().unwrap(); let link = std::process::Command::new("where")
let link_path: Vec<&str> = std::str::from_utf8(&link.stdout).unwrap().split("\r\n").collect(); .arg("link.exe")
.output()
.unwrap();
let link_path: Vec<&str> = std::str::from_utf8(&link.stdout)
.unwrap()
.split("\r\n")
.collect();
build.define("CMAKE_LINKER", link_path[0]); build.define("CMAKE_LINKER", link_path[0]);
} }
build.build(); build.build();
println!("Binding generation completed in {}s", start.elapsed().as_secs()); println!(
"Binding generation completed in {}s",
start.elapsed().as_secs()
);
let json = PathBuf::from(env::var_os("OUT_DIR").unwrap()).join("build").join("InterfaceObjectMapData.json"); let json = PathBuf::from(env::var_os("OUT_DIR").unwrap())
.join("build")
.join("InterfaceObjectMapData.json");
let json: Value = serde_json::from_reader(File::open(&json).unwrap()).unwrap(); let json: Value = serde_json::from_reader(File::open(&json).unwrap()).unwrap();
let mut map = phf_codegen::Map::new(); let mut map = phf_codegen::Map::new();
for (key, value) in json.as_object().unwrap() { for (key, value) in json.as_object().unwrap() {
@ -54,7 +66,10 @@ fn main() {
} }
let phf = PathBuf::from(env::var_os("OUT_DIR").unwrap()).join("InterfaceObjectMapPhf.rs"); let phf = PathBuf::from(env::var_os("OUT_DIR").unwrap()).join("InterfaceObjectMapPhf.rs");
let mut phf = File::create(&phf).unwrap(); let mut phf = File::create(&phf).unwrap();
write!(&mut phf, "pub static MAP: phf::Map<&'static [u8], unsafe fn(*mut JSContext, HandleObject)> = ").unwrap(); write!(
&mut phf,
"pub static MAP: phf::Map<&'static [u8], unsafe fn(*mut JSContext, HandleObject)> = "
).unwrap();
map.build(&mut phf).unwrap(); map.build(&mut phf).unwrap();
write!(&mut phf, ";\n").unwrap(); write!(&mut phf, ";\n").unwrap();
} }

View file

@ -32,7 +32,6 @@ use std::str;
use style::properties::longhands::{margin_bottom, margin_left, margin_right, margin_top}; use style::properties::longhands::{margin_bottom, margin_left, margin_right, margin_top};
use uuid::Uuid; use uuid::Uuid;
#[allow(unsafe_code)] #[allow(unsafe_code)]
pub fn handle_evaluate_js(global: &GlobalScope, eval: String, reply: IpcSender<EvaluateJSReply>) { pub fn handle_evaluate_js(global: &GlobalScope, eval: String, reply: IpcSender<EvaluateJSReply>) {
// global.get_cx() returns a valid `JSContext` pointer, so this is safe. // global.get_cx() returns a valid `JSContext` pointer, so this is safe.
@ -48,8 +47,11 @@ pub fn handle_evaluate_js(global: &GlobalScope, eval: String, reply: IpcSender<E
} else if rval.is_boolean() { } else if rval.is_boolean() {
EvaluateJSReply::BooleanValue(rval.to_boolean()) EvaluateJSReply::BooleanValue(rval.to_boolean())
} else if rval.is_double() || rval.is_int32() { } else if rval.is_double() || rval.is_int32() {
EvaluateJSReply::NumberValue( EvaluateJSReply::NumberValue(match FromJSValConvertible::from_jsval(
match FromJSValConvertible::from_jsval(cx, rval.handle(), ()) { cx,
rval.handle(),
(),
) {
Ok(ConversionResult::Success(v)) => v, Ok(ConversionResult::Success(v)) => v,
_ => unreachable!(), _ => unreachable!(),
}) })
@ -73,65 +75,84 @@ pub fn handle_evaluate_js(global: &GlobalScope, eval: String, reply: IpcSender<E
reply.send(result).unwrap(); reply.send(result).unwrap();
} }
pub fn handle_get_root_node(documents: &Documents, pipeline: PipelineId, reply: IpcSender<Option<NodeInfo>>) { pub fn handle_get_root_node(
let info = documents.find_document(pipeline) documents: &Documents,
pipeline: PipelineId,
reply: IpcSender<Option<NodeInfo>>,
) {
let info = documents
.find_document(pipeline)
.map(|document| document.upcast::<Node>().summarize()); .map(|document| document.upcast::<Node>().summarize());
reply.send(info).unwrap(); reply.send(info).unwrap();
} }
pub fn handle_get_document_element(documents: &Documents, pub fn handle_get_document_element(
documents: &Documents,
pipeline: PipelineId, pipeline: PipelineId,
reply: IpcSender<Option<NodeInfo>>) { reply: IpcSender<Option<NodeInfo>>,
let info = documents.find_document(pipeline) ) {
let info = documents
.find_document(pipeline)
.and_then(|document| document.GetDocumentElement()) .and_then(|document| document.GetDocumentElement())
.map(|element| element.upcast::<Node>().summarize()); .map(|element| element.upcast::<Node>().summarize());
reply.send(info).unwrap(); reply.send(info).unwrap();
} }
fn find_node_by_unique_id(documents: &Documents, fn find_node_by_unique_id(
documents: &Documents,
pipeline: PipelineId, pipeline: PipelineId,
node_id: &str) node_id: &str,
-> Option<DomRoot<Node>> { ) -> Option<DomRoot<Node>> {
documents.find_document(pipeline).and_then(|document| documents.find_document(pipeline).and_then(|document| {
document.upcast::<Node>().traverse_preorder().find(|candidate| candidate.unique_id() == node_id) document
) .upcast::<Node>()
.traverse_preorder()
.find(|candidate| candidate.unique_id() == node_id)
})
} }
pub fn handle_get_children(documents: &Documents, pub fn handle_get_children(
documents: &Documents,
pipeline: PipelineId, pipeline: PipelineId,
node_id: String, node_id: String,
reply: IpcSender<Option<Vec<NodeInfo>>>) { reply: IpcSender<Option<Vec<NodeInfo>>>,
) {
match find_node_by_unique_id(documents, pipeline, &*node_id) { match find_node_by_unique_id(documents, pipeline, &*node_id) {
None => return reply.send(None).unwrap(), None => return reply.send(None).unwrap(),
Some(parent) => { Some(parent) => {
let children = parent.children() let children = parent.children().map(|child| child.summarize()).collect();
.map(|child| child.summarize())
.collect();
reply.send(Some(children)).unwrap(); reply.send(Some(children)).unwrap();
} },
}; };
} }
pub fn handle_get_layout(documents: &Documents, pub fn handle_get_layout(
documents: &Documents,
pipeline: PipelineId, pipeline: PipelineId,
node_id: String, node_id: String,
reply: IpcSender<Option<ComputedNodeLayout>>) { reply: IpcSender<Option<ComputedNodeLayout>>,
) {
let node = match find_node_by_unique_id(documents, pipeline, &*node_id) { let node = match find_node_by_unique_id(documents, pipeline, &*node_id) {
None => return reply.send(None).unwrap(), None => return reply.send(None).unwrap(),
Some(found_node) => found_node Some(found_node) => found_node,
}; };
let elem = node.downcast::<Element>().expect("should be getting layout of element"); let elem = node
.downcast::<Element>()
.expect("should be getting layout of element");
let rect = elem.GetBoundingClientRect(); let rect = elem.GetBoundingClientRect();
let width = rect.Width() as f32; let width = rect.Width() as f32;
let height = rect.Height() as f32; let height = rect.Height() as f32;
let window = window_from_node(&*node); let window = window_from_node(&*node);
let elem = node.downcast::<Element>().expect("should be getting layout of element"); let elem = node
.downcast::<Element>()
.expect("should be getting layout of element");
let computed_style = window.GetComputedStyle(elem, None); let computed_style = window.GetComputedStyle(elem, None);
reply.send(Some(ComputedNodeLayout { reply
.send(Some(ComputedNodeLayout {
display: String::from(computed_style.Display()), display: String::from(computed_style.Display()),
position: String::from(computed_style.Position()), position: String::from(computed_style.Position()),
zIndex: String::from(computed_style.ZIndex()), zIndex: String::from(computed_style.ZIndex()),
@ -165,9 +186,11 @@ fn determine_auto_margins(window: &Window, node: &Node) -> AutoMargins {
} }
} }
pub fn handle_get_cached_messages(_pipeline_id: PipelineId, pub fn handle_get_cached_messages(
_pipeline_id: PipelineId,
message_types: CachedConsoleMessageTypes, message_types: CachedConsoleMessageTypes,
reply: IpcSender<Vec<CachedConsoleMessage>>) { reply: IpcSender<Vec<CachedConsoleMessage>>,
) {
// TODO: check the messageTypes against a global Cache for console messages and page exceptions // TODO: check the messageTypes against a global Cache for console messages and page exceptions
let mut messages = Vec::new(); let mut messages = Vec::new();
if message_types.contains(CachedConsoleMessageTypes::PAGE_ERROR) { if message_types.contains(CachedConsoleMessageTypes::PAGE_ERROR) {
@ -207,22 +230,33 @@ pub fn handle_get_cached_messages(_pipeline_id: PipelineId,
reply.send(messages).unwrap(); reply.send(messages).unwrap();
} }
pub fn handle_modify_attribute(documents: &Documents, pub fn handle_modify_attribute(
documents: &Documents,
pipeline: PipelineId, pipeline: PipelineId,
node_id: String, node_id: String,
modifications: Vec<Modification>) { modifications: Vec<Modification>,
) {
let node = match find_node_by_unique_id(documents, pipeline, &*node_id) { let node = match find_node_by_unique_id(documents, pipeline, &*node_id) {
None => return warn!("node id {} for pipeline id {} is not found", &node_id, &pipeline), None => {
Some(found_node) => found_node return warn!(
"node id {} for pipeline id {} is not found",
&node_id, &pipeline
)
},
Some(found_node) => found_node,
}; };
let elem = node.downcast::<Element>().expect("should be getting layout of element"); let elem = node
.downcast::<Element>()
.expect("should be getting layout of element");
for modification in modifications { for modification in modifications {
match modification.newValue { match modification.newValue {
Some(string) => { Some(string) => {
let _ = elem.SetAttribute(DOMString::from(modification.attributeName), let _ = elem.SetAttribute(
DOMString::from(string)); DOMString::from(modification.attributeName),
DOMString::from(string),
);
}, },
None => elem.RemoveAttribute(DOMString::from(modification.attributeName)), None => elem.RemoveAttribute(DOMString::from(modification.attributeName)),
} }
@ -233,34 +267,35 @@ pub fn handle_wants_live_notifications(global: &GlobalScope, send_notifications:
global.set_devtools_wants_updates(send_notifications); global.set_devtools_wants_updates(send_notifications);
} }
pub fn handle_set_timeline_markers(documents: &Documents, pub fn handle_set_timeline_markers(
documents: &Documents,
pipeline: PipelineId, pipeline: PipelineId,
marker_types: Vec<TimelineMarkerType>, marker_types: Vec<TimelineMarkerType>,
reply: IpcSender<Option<TimelineMarker>>) { reply: IpcSender<Option<TimelineMarker>>,
) {
match documents.find_window(pipeline) { match documents.find_window(pipeline) {
None => reply.send(None).unwrap(), None => reply.send(None).unwrap(),
Some(window) => window.set_devtools_timeline_markers(marker_types, reply), Some(window) => window.set_devtools_timeline_markers(marker_types, reply),
} }
} }
pub fn handle_drop_timeline_markers(documents: &Documents, pub fn handle_drop_timeline_markers(
documents: &Documents,
pipeline: PipelineId, pipeline: PipelineId,
marker_types: Vec<TimelineMarkerType>) { marker_types: Vec<TimelineMarkerType>,
) {
if let Some(window) = documents.find_window(pipeline) { if let Some(window) = documents.find_window(pipeline) {
window.drop_devtools_timeline_markers(marker_types); window.drop_devtools_timeline_markers(marker_types);
} }
} }
pub fn handle_request_animation_frame(documents: &Documents, pub fn handle_request_animation_frame(documents: &Documents, id: PipelineId, actor_name: String) {
id: PipelineId,
actor_name: String) {
if let Some(doc) = documents.find_document(id) { if let Some(doc) = documents.find_document(id) {
doc.request_animation_frame(AnimationFrameCallback::DevtoolsFramerateTick { actor_name }); doc.request_animation_frame(AnimationFrameCallback::DevtoolsFramerateTick { actor_name });
} }
} }
pub fn handle_reload(documents: &Documents, pub fn handle_reload(documents: &Documents, id: PipelineId) {
id: PipelineId) {
if let Some(win) = documents.find_window(id) { if let Some(win) = documents.find_window(id) {
win.Location().reload_without_origin_check(); win.Location().reload_without_origin_check();
} }

View file

@ -96,8 +96,10 @@ impl DocumentLoader {
DocumentLoader::new_with_threads(existing.resource_threads.clone(), None) DocumentLoader::new_with_threads(existing.resource_threads.clone(), None)
} }
pub fn new_with_threads(resource_threads: ResourceThreads, pub fn new_with_threads(
initial_load: Option<ServoUrl>) -> DocumentLoader { resource_threads: ResourceThreads,
initial_load: Option<ServoUrl>,
) -> DocumentLoader {
debug!("Initial blocking load {:?}.", initial_load); debug!("Initial blocking load {:?}.", initial_load);
let initial_loads = initial_load.into_iter().map(LoadType::PageSource).collect(); let initial_loads = initial_load.into_iter().map(LoadType::PageSource).collect();
@ -105,7 +107,7 @@ impl DocumentLoader {
resource_threads: resource_threads, resource_threads: resource_threads,
blocking_loads: initial_loads, blocking_loads: initial_loads,
events_inhibited: false, events_inhibited: false,
cancellers: Vec::new() cancellers: Vec::new(),
} }
} }
@ -118,35 +120,55 @@ impl DocumentLoader {
/// Add a load to the list of blocking loads. /// Add a load to the list of blocking loads.
fn add_blocking_load(&mut self, load: LoadType) { fn add_blocking_load(&mut self, load: LoadType) {
debug!("Adding blocking load {:?} ({}).", load, self.blocking_loads.len()); debug!(
"Adding blocking load {:?} ({}).",
load,
self.blocking_loads.len()
);
self.blocking_loads.push(load); self.blocking_loads.push(load);
} }
/// Initiate a new fetch. /// Initiate a new fetch.
pub fn fetch_async(&mut self, pub fn fetch_async(
&mut self,
load: LoadType, load: LoadType,
request: RequestInit, request: RequestInit,
fetch_target: IpcSender<FetchResponseMsg>) { fetch_target: IpcSender<FetchResponseMsg>,
) {
self.add_blocking_load(load); self.add_blocking_load(load);
self.fetch_async_background(request, fetch_target); self.fetch_async_background(request, fetch_target);
} }
/// Initiate a new fetch that does not block the document load event. /// Initiate a new fetch that does not block the document load event.
pub fn fetch_async_background(&mut self, pub fn fetch_async_background(
&mut self,
request: RequestInit, request: RequestInit,
fetch_target: IpcSender<FetchResponseMsg>) { fetch_target: IpcSender<FetchResponseMsg>,
) {
let mut canceller = FetchCanceller::new(); let mut canceller = FetchCanceller::new();
let cancel_receiver = canceller.initialize(); let cancel_receiver = canceller.initialize();
self.cancellers.push(canceller); self.cancellers.push(canceller);
self.resource_threads.sender().send( self.resource_threads
CoreResourceMsg::Fetch(request, FetchChannels::ResponseMsg(fetch_target, Some(cancel_receiver)))).unwrap(); .sender()
.send(CoreResourceMsg::Fetch(
request,
FetchChannels::ResponseMsg(fetch_target, Some(cancel_receiver)),
)).unwrap();
} }
/// Mark an in-progress network request complete. /// Mark an in-progress network request complete.
pub fn finish_load(&mut self, load: &LoadType) { pub fn finish_load(&mut self, load: &LoadType) {
debug!("Removing blocking load {:?} ({}).", load, self.blocking_loads.len()); debug!(
let idx = self.blocking_loads.iter().position(|unfinished| *unfinished == *load); "Removing blocking load {:?} ({}).",
self.blocking_loads.remove(idx.unwrap_or_else(|| panic!("unknown completed load {:?}", load))); load,
self.blocking_loads.len()
);
let idx = self
.blocking_loads
.iter()
.position(|unfinished| *unfinished == *load);
self.blocking_loads
.remove(idx.unwrap_or_else(|| panic!("unknown completed load {:?}", load)));
} }
pub fn is_blocked(&self) -> bool { pub fn is_blocked(&self) -> bool {
@ -157,7 +179,7 @@ impl DocumentLoader {
pub fn is_only_blocked_by_iframes(&self) -> bool { pub fn is_only_blocked_by_iframes(&self) -> bool {
self.blocking_loads.iter().all(|load| match *load { self.blocking_loads.iter().all(|load| match *load {
LoadType::Subframe(_) => true, LoadType::Subframe(_) => true,
_ => false _ => false,
}) })
} }

View file

@ -12,7 +12,7 @@ pub enum WorkerScriptMsg {
/// Common variants associated with the script messages /// Common variants associated with the script messages
Common(CommonScriptMsg), Common(CommonScriptMsg),
/// Message sent through Worker.postMessage /// Message sent through Worker.postMessage
DOMMessage(StructuredCloneData) DOMMessage(StructuredCloneData),
} }
pub struct SimpleWorkerErrorHandler<T: DomObject> { pub struct SimpleWorkerErrorHandler<T: DomObject> {
@ -21,8 +21,6 @@ pub struct SimpleWorkerErrorHandler<T: DomObject> {
impl<T: DomObject> SimpleWorkerErrorHandler<T> { impl<T: DomObject> SimpleWorkerErrorHandler<T> {
pub fn new(addr: Trusted<T>) -> SimpleWorkerErrorHandler<T> { pub fn new(addr: Trusted<T>) -> SimpleWorkerErrorHandler<T> {
SimpleWorkerErrorHandler { SimpleWorkerErrorHandler { addr: addr }
addr: addr
}
} }
} }

View file

@ -25,7 +25,10 @@ pub struct SendableWorkerScriptChan {
impl ScriptChan for SendableWorkerScriptChan { impl ScriptChan for SendableWorkerScriptChan {
fn send(&self, msg: CommonScriptMsg) -> Result<(), ()> { fn send(&self, msg: CommonScriptMsg) -> Result<(), ()> {
let msg = DedicatedWorkerScriptMsg::CommonWorker(self.worker.clone(), WorkerScriptMsg::Common(msg)); let msg = DedicatedWorkerScriptMsg::CommonWorker(
self.worker.clone(),
WorkerScriptMsg::Common(msg),
);
self.sender.send(msg).map_err(|_| ()) self.sender.send(msg).map_err(|_| ())
} }
@ -48,10 +51,11 @@ pub struct WorkerThreadWorkerChan {
impl ScriptChan for WorkerThreadWorkerChan { impl ScriptChan for WorkerThreadWorkerChan {
fn send(&self, msg: CommonScriptMsg) -> Result<(), ()> { fn send(&self, msg: CommonScriptMsg) -> Result<(), ()> {
let msg = DedicatedWorkerScriptMsg::CommonWorker(self.worker.clone(), WorkerScriptMsg::Common(msg)); let msg = DedicatedWorkerScriptMsg::CommonWorker(
self.sender self.worker.clone(),
.send(msg) WorkerScriptMsg::Common(msg),
.map_err(|_| ()) );
self.sender.send(msg).map_err(|_| ())
} }
fn clone(&self) -> Box<ScriptChan + Send> { fn clone(&self) -> Box<ScriptChan + Send> {
@ -67,7 +71,7 @@ impl ScriptPort for Receiver<DedicatedWorkerScriptMsg> {
let common_msg = match self.recv() { let common_msg = match self.recv() {
Some(DedicatedWorkerScriptMsg::CommonWorker(_worker, common_msg)) => common_msg, Some(DedicatedWorkerScriptMsg::CommonWorker(_worker, common_msg)) => common_msg,
None => return Err(()), None => return Err(()),
Some(DedicatedWorkerScriptMsg::WakeUp) => panic!("unexpected worker event message!") Some(DedicatedWorkerScriptMsg::WakeUp) => panic!("unexpected worker event message!"),
}; };
match common_msg { match common_msg {
WorkerScriptMsg::Common(script_msg) => Ok(script_msg), WorkerScriptMsg::Common(script_msg) => Ok(script_msg),
@ -90,14 +94,17 @@ pub trait WorkerEventLoopMethods {
} }
// https://html.spec.whatwg.org/multipage/#worker-event-loop // https://html.spec.whatwg.org/multipage/#worker-event-loop
pub fn run_worker_event_loop<T, TimerMsg, WorkerMsg, Event>(worker_scope: &T, pub fn run_worker_event_loop<T, TimerMsg, WorkerMsg, Event>(
worker: Option<&TrustedWorkerAddress>) worker_scope: &T,
where worker: Option<&TrustedWorkerAddress>,
) where
TimerMsg: Send, TimerMsg: Send,
WorkerMsg: QueuedTaskConversion + Send, WorkerMsg: QueuedTaskConversion + Send,
T: WorkerEventLoopMethods<TimerMsg = TimerMsg, WorkerMsg = WorkerMsg, Event = Event> T: WorkerEventLoopMethods<TimerMsg = TimerMsg, WorkerMsg = WorkerMsg, Event = Event>
+ DerivedFrom<WorkerGlobalScope> + DerivedFrom<GlobalScope> + DerivedFrom<WorkerGlobalScope>
+ DomObject { + DerivedFrom<GlobalScope>
+ DomObject,
{
let scope = worker_scope.upcast::<WorkerGlobalScope>(); let scope = worker_scope.upcast::<WorkerGlobalScope>();
let timer_event_port = worker_scope.timer_event_port(); let timer_event_port = worker_scope.timer_event_port();
let devtools_port = match scope.from_devtools_sender() { let devtools_port = match scope.from_devtools_sender() {
@ -140,8 +147,10 @@ where
// Step 6 // Step 6
let _ar = match worker { let _ar = match worker {
Some(worker) => worker_scope.handle_worker_post_event(worker), Some(worker) => worker_scope.handle_worker_post_event(worker),
None => None None => None,
}; };
worker_scope.upcast::<GlobalScope>().perform_a_microtask_checkpoint(); worker_scope
.upcast::<GlobalScope>()
.perform_a_microtask_checkpoint();
} }
} }

View file

@ -56,12 +56,14 @@ pub enum ActivationSource {
} }
// https://html.spec.whatwg.org/multipage/#run-synthetic-click-activation-steps // https://html.spec.whatwg.org/multipage/#run-synthetic-click-activation-steps
pub fn synthetic_click_activation(element: &Element, pub fn synthetic_click_activation(
element: &Element,
ctrl_key: bool, ctrl_key: bool,
shift_key: bool, shift_key: bool,
alt_key: bool, alt_key: bool,
meta_key: bool, meta_key: bool,
source: ActivationSource) { source: ActivationSource,
) {
// Step 1 // Step 1
if element.click_in_progress() { if element.click_in_progress() {
return; return;
@ -78,7 +80,8 @@ pub fn synthetic_click_activation(element: &Element,
// https://html.spec.whatwg.org/multipage/#fire-a-synthetic-mouse-event // https://html.spec.whatwg.org/multipage/#fire-a-synthetic-mouse-event
let win = window_from_node(element); let win = window_from_node(element);
let target = element.upcast::<EventTarget>(); let target = element.upcast::<EventTarget>();
let mouse = MouseEvent::new(&win, let mouse = MouseEvent::new(
&win,
DOMString::from("click"), DOMString::from("click"),
EventBubbles::DoesNotBubble, EventBubbles::DoesNotBubble,
EventCancelable::NotCancelable, EventCancelable::NotCancelable,
@ -94,7 +97,8 @@ pub fn synthetic_click_activation(element: &Element,
meta_key, meta_key,
0, 0,
None, None,
None); None,
);
let event = mouse.upcast::<Event>(); let event = mouse.upcast::<Event>();
if source == ActivationSource::FromClick { if source == ActivationSource::FromClick {
event.set_trusted(false); event.set_trusted(false);

View file

@ -36,13 +36,14 @@ pub struct Attr {
} }
impl Attr { impl Attr {
fn new_inherited(local_name: LocalName, fn new_inherited(
local_name: LocalName,
value: AttrValue, value: AttrValue,
name: LocalName, name: LocalName,
namespace: Namespace, namespace: Namespace,
prefix: Option<Prefix>, prefix: Option<Prefix>,
owner: Option<&Element>) owner: Option<&Element>,
-> Attr { ) -> Attr {
Attr { Attr {
reflector_: Reflector::new(), reflector_: Reflector::new(),
identifier: AttrIdentifier { identifier: AttrIdentifier {
@ -56,25 +57,21 @@ impl Attr {
} }
} }
pub fn new(window: &Window, pub fn new(
window: &Window,
local_name: LocalName, local_name: LocalName,
value: AttrValue, value: AttrValue,
name: LocalName, name: LocalName,
namespace: Namespace, namespace: Namespace,
prefix: Option<Prefix>, prefix: Option<Prefix>,
owner: Option<&Element>) owner: Option<&Element>,
-> DomRoot<Attr> { ) -> DomRoot<Attr> {
reflect_dom_object( reflect_dom_object(
Box::new(Attr::new_inherited( Box::new(Attr::new_inherited(
local_name, local_name, value, name, namespace, prefix, owner,
value,
name,
namespace,
prefix,
owner
)), )),
window, window,
AttrBinding::Wrap AttrBinding::Wrap,
) )
} }
@ -110,9 +107,7 @@ impl AttrMethods for Attr {
// https://dom.spec.whatwg.org/#dom-attr-value // https://dom.spec.whatwg.org/#dom-attr-value
fn SetValue(&self, value: DOMString) { fn SetValue(&self, value: DOMString) {
if let Some(owner) = self.owner() { if let Some(owner) = self.owner() {
let value = owner.parse_attribute(&self.identifier.namespace, let value = owner.parse_attribute(&self.identifier.namespace, self.local_name(), value);
self.local_name(),
value);
self.set_value(value, &owner); self.set_value(value, &owner);
} else { } else {
*self.value.borrow_mut() = AttrValue::String(value.into()); *self.value.borrow_mut() = AttrValue::String(value.into());
@ -175,7 +170,6 @@ impl AttrMethods for Attr {
} }
} }
impl Attr { impl Attr {
pub fn set_value(&self, mut value: AttrValue, owner: &Element) { pub fn set_value(&self, mut value: AttrValue, owner: &Element) {
let name = self.local_name().clone(); let name = self.local_name().clone();
@ -191,7 +185,12 @@ impl Attr {
MutationObserver::queue_a_mutation_record(owner.upcast::<Node>(), mutation); MutationObserver::queue_a_mutation_record(owner.upcast::<Node>(), mutation);
if owner.get_custom_element_definition().is_some() { if owner.get_custom_element_definition().is_some() {
let reaction = CallbackReaction::AttributeChanged(name, Some(old_value), Some(new_value), namespace); let reaction = CallbackReaction::AttributeChanged(
name,
Some(old_value),
Some(new_value),
namespace,
);
ScriptThread::enqueue_callback_reaction(owner, reaction, None); ScriptThread::enqueue_callback_reaction(owner, reaction, None);
} }
@ -229,7 +228,7 @@ impl Attr {
(Some(old), None) => { (Some(old), None) => {
// Already gone from the list of attributes of old owner. // Already gone from the list of attributes of old owner.
assert!(old.get_attribute(&ns, &self.identifier.local_name).r() != Some(self)) assert!(old.get_attribute(&ns, &self.identifier.local_name).r() != Some(self))
} },
(Some(old), Some(new)) => assert_eq!(&*old, new), (Some(old), Some(new)) => assert_eq!(&*old, new),
_ => {}, _ => {},
} }

View file

@ -98,7 +98,11 @@ impl AudioBufferSourceNode {
options: &AudioBufferSourceOptions, options: &AudioBufferSourceOptions,
) -> Fallible<DomRoot<AudioBufferSourceNode>> { ) -> Fallible<DomRoot<AudioBufferSourceNode>> {
let node = AudioBufferSourceNode::new_inherited(window, context, options)?; let node = AudioBufferSourceNode::new_inherited(window, context, options)?;
Ok(reflect_dom_object(Box::new(node), window, AudioBufferSourceNodeBinding::Wrap)) Ok(reflect_dom_object(
Box::new(node),
window,
AudioBufferSourceNodeBinding::Wrap,
))
} }
pub fn Constructor( pub fn Constructor(

View file

@ -36,9 +36,8 @@ impl AudioContext {
// https://webaudio.github.io/web-audio-api/#AudioContext-constructors // https://webaudio.github.io/web-audio-api/#AudioContext-constructors
fn new_inherited(options: &AudioContextOptions) -> AudioContext { fn new_inherited(options: &AudioContextOptions) -> AudioContext {
// Steps 1-3. // Steps 1-3.
let context = BaseAudioContext::new_inherited( let context =
BaseAudioContextOptions::AudioContext(options.into()), BaseAudioContext::new_inherited(BaseAudioContextOptions::AudioContext(options.into()));
);
// Step 4.1. // Step 4.1.
let latency_hint = options.latencyHint; let latency_hint = options.latencyHint;

View file

@ -22,8 +22,8 @@ impl AudioDestinationNode {
context: &BaseAudioContext, context: &BaseAudioContext,
options: &AudioNodeOptions, options: &AudioNodeOptions,
) -> AudioDestinationNode { ) -> AudioDestinationNode {
let node_options = options.unwrap_or(2, ChannelCountMode::Max, let node_options =
ChannelInterpretation::Speakers); options.unwrap_or(2, ChannelCountMode::Max, ChannelInterpretation::Speakers);
AudioDestinationNode { AudioDestinationNode {
node: AudioNode::new_inherited_for_id( node: AudioNode::new_inherited_for_id(
context.destination_node(), context.destination_node(),

View file

@ -28,10 +28,7 @@ pub struct AudioListener {
} }
impl AudioListener { impl AudioListener {
fn new_inherited( fn new_inherited(window: &Window, context: &BaseAudioContext) -> AudioListener {
window: &Window,
context: &BaseAudioContext,
) -> AudioListener {
let node = context.listener(); let node = context.listener();
let position_x = AudioParam::new( let position_x = AudioParam::new(
@ -139,10 +136,7 @@ impl AudioListener {
} }
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
pub fn new( pub fn new(window: &Window, context: &BaseAudioContext) -> DomRoot<AudioListener> {
window: &Window,
context: &BaseAudioContext,
) -> DomRoot<AudioListener> {
let node = AudioListener::new_inherited(window, context); let node = AudioListener::new_inherited(window, context);
reflect_dom_object(Box::new(node), window, AudioListenerBinding::Wrap) reflect_dom_object(Box::new(node), window, AudioListenerBinding::Wrap)
} }

View file

@ -36,7 +36,6 @@ pub struct AudioNode {
channel_interpretation: Cell<ChannelInterpretation>, channel_interpretation: Cell<ChannelInterpretation>,
} }
impl AudioNode { impl AudioNode {
pub fn new_inherited( pub fn new_inherited(
node_type: AudioNodeInit, node_type: AudioNodeInit,
@ -54,7 +53,13 @@ impl AudioNode {
interpretation: options.interpretation.into(), interpretation: options.interpretation.into(),
}; };
let node_id = context.audio_context_impl().create_node(node_type, ch); let node_id = context.audio_context_impl().create_node(node_type, ch);
Ok(AudioNode::new_inherited_for_id(node_id, context, options, number_of_inputs, number_of_outputs)) Ok(AudioNode::new_inherited_for_id(
node_id,
context,
options,
number_of_inputs,
number_of_outputs,
))
} }
pub fn new_inherited_for_id( pub fn new_inherited_for_id(
@ -177,8 +182,7 @@ impl AudioNodeMethods for AudioNode {
fn Disconnect_____(&self, param: &AudioParam) -> ErrorResult { fn Disconnect_____(&self, param: &AudioParam) -> ErrorResult {
self.context self.context
.audio_context_impl() .audio_context_impl()
.disconnect_to(self.node_id(), .disconnect_to(self.node_id(), param.node_id().param(param.param_type()));
param.node_id().param(param.param_type()));
Ok(()) Ok(())
} }
@ -186,8 +190,10 @@ impl AudioNodeMethods for AudioNode {
fn Disconnect______(&self, param: &AudioParam, out: u32) -> ErrorResult { fn Disconnect______(&self, param: &AudioParam, out: u32) -> ErrorResult {
self.context self.context
.audio_context_impl() .audio_context_impl()
.disconnect_output_between_to(self.node_id().output(out), .disconnect_output_between_to(
param.node_id().param(param.param_type())); self.node_id().output(out),
param.node_id().param(param.param_type()),
);
Ok(()) Ok(())
} }
@ -223,14 +229,14 @@ impl AudioNodeMethods for AudioNode {
}, },
EventTargetTypeId::AudioNode(AudioNodeTypeId::PannerNode) => { EventTargetTypeId::AudioNode(AudioNodeTypeId::PannerNode) => {
if value > 2 { if value > 2 {
return Err(Error::NotSupported) return Err(Error::NotSupported);
}
} }
},
EventTargetTypeId::AudioNode(AudioNodeTypeId::ChannelMergerNode) => { EventTargetTypeId::AudioNode(AudioNodeTypeId::ChannelMergerNode) => {
if value != 1 { if value != 1 {
return Err(Error::InvalidState) return Err(Error::InvalidState);
}
} }
},
// XXX We do not support any of the other AudioNodes with // XXX We do not support any of the other AudioNodes with
// constraints yet. Add more cases here as we add support // constraints yet. Add more cases here as we add support
// for new AudioNodes. // for new AudioNodes.
@ -266,14 +272,14 @@ impl AudioNodeMethods for AudioNode {
}, },
EventTargetTypeId::AudioNode(AudioNodeTypeId::PannerNode) => { EventTargetTypeId::AudioNode(AudioNodeTypeId::PannerNode) => {
if value == ChannelCountMode::Max { if value == ChannelCountMode::Max {
return Err(Error::NotSupported) return Err(Error::NotSupported);
}
} }
},
EventTargetTypeId::AudioNode(AudioNodeTypeId::ChannelMergerNode) => { EventTargetTypeId::AudioNode(AudioNodeTypeId::ChannelMergerNode) => {
if value != ChannelCountMode::Explicit { if value != ChannelCountMode::Explicit {
return Err(Error::InvalidState) return Err(Error::InvalidState);
}
} }
},
// XXX We do not support any of the other AudioNodes with // XXX We do not support any of the other AudioNodes with
// constraints yet. Add more cases here as we add support // constraints yet. Add more cases here as we add support
// for new AudioNodes. // for new AudioNodes.
@ -321,14 +327,17 @@ impl From<ChannelInterpretation> for ServoMediaChannelInterpretation {
} }
} }
impl AudioNodeOptions { impl AudioNodeOptions {
pub fn unwrap_or(&self, count: u32, mode: ChannelCountMode, pub fn unwrap_or(
interpretation: ChannelInterpretation) -> UnwrappedAudioNodeOptions { &self,
count: u32,
mode: ChannelCountMode,
interpretation: ChannelInterpretation,
) -> UnwrappedAudioNodeOptions {
UnwrappedAudioNodeOptions { UnwrappedAudioNodeOptions {
count: self.channelCount.unwrap_or(count), count: self.channelCount.unwrap_or(count),
mode: self.channelCountMode.unwrap_or(mode), mode: self.channelCountMode.unwrap_or(mode),
interpretation: self.channelInterpretation.unwrap_or(interpretation) interpretation: self.channelInterpretation.unwrap_or(interpretation),
} }
} }
} }

View file

@ -76,7 +76,9 @@ impl AudioParam {
} }
fn message_node(&self, message: AudioNodeMessage) { fn message_node(&self, message: AudioNodeMessage) {
self.context.audio_context_impl().message_node(self.node, message); self.context
.audio_context_impl()
.message_node(self.node, message);
} }
pub fn context(&self) -> &BaseAudioContext { pub fn context(&self) -> &BaseAudioContext {
@ -101,25 +103,25 @@ impl AudioParamMethods for AudioParam {
// https://webaudio.github.io/web-audio-api/#dom-audioparam-automationrate // https://webaudio.github.io/web-audio-api/#dom-audioparam-automationrate
fn SetAutomationRate(&self, automation_rate: AutomationRate) { fn SetAutomationRate(&self, automation_rate: AutomationRate) {
self.automation_rate.set(automation_rate); self.automation_rate.set(automation_rate);
self.message_node( self.message_node(AudioNodeMessage::SetParamRate(
AudioNodeMessage::SetParamRate(self.param, automation_rate.into()) self.param,
); automation_rate.into(),
));
} }
// https://webaudio.github.io/web-audio-api/#dom-audioparam-value // https://webaudio.github.io/web-audio-api/#dom-audioparam-value
fn Value(&self) -> Finite<f32> { fn Value(&self) -> Finite<f32> {
let (tx, rx) = mpsc::channel(); let (tx, rx) = mpsc::channel();
self.message_node( self.message_node(AudioNodeMessage::GetParamValue(self.param, tx));
AudioNodeMessage::GetParamValue(self.param, tx)
);
Finite::wrap(rx.recv().unwrap()) Finite::wrap(rx.recv().unwrap())
} }
// https://webaudio.github.io/web-audio-api/#dom-audioparam-value // https://webaudio.github.io/web-audio-api/#dom-audioparam-value
fn SetValue(&self, value: Finite<f32>) { fn SetValue(&self, value: Finite<f32>) {
self.message_node( self.message_node(AudioNodeMessage::SetParam(
AudioNodeMessage::SetParam(self.param, UserAutomationEvent::SetValue(*value)), self.param,
); UserAutomationEvent::SetValue(*value),
));
} }
// https://webaudio.github.io/web-audio-api/#dom-audioparam-defaultvalue // https://webaudio.github.io/web-audio-api/#dom-audioparam-defaultvalue
@ -139,12 +141,10 @@ impl AudioParamMethods for AudioParam {
// https://webaudio.github.io/web-audio-api/#dom-audioparam-setvalueattime // https://webaudio.github.io/web-audio-api/#dom-audioparam-setvalueattime
fn SetValueAtTime(&self, value: Finite<f32>, start_time: Finite<f64>) -> DomRoot<AudioParam> { fn SetValueAtTime(&self, value: Finite<f32>, start_time: Finite<f64>) -> DomRoot<AudioParam> {
self.message_node( self.message_node(AudioNodeMessage::SetParam(
AudioNodeMessage::SetParam(
self.param, self.param,
UserAutomationEvent::SetValueAtTime(*value, *start_time), UserAutomationEvent::SetValueAtTime(*value, *start_time),
) ));
);
DomRoot::from_ref(self) DomRoot::from_ref(self)
} }
@ -154,12 +154,10 @@ impl AudioParamMethods for AudioParam {
value: Finite<f32>, value: Finite<f32>,
end_time: Finite<f64>, end_time: Finite<f64>,
) -> DomRoot<AudioParam> { ) -> DomRoot<AudioParam> {
self.message_node( self.message_node(AudioNodeMessage::SetParam(
AudioNodeMessage::SetParam(
self.param, self.param,
UserAutomationEvent::RampToValueAtTime(RampKind::Linear, *value, *end_time), UserAutomationEvent::RampToValueAtTime(RampKind::Linear, *value, *end_time),
), ));
);
DomRoot::from_ref(self) DomRoot::from_ref(self)
} }
@ -169,12 +167,10 @@ impl AudioParamMethods for AudioParam {
value: Finite<f32>, value: Finite<f32>,
end_time: Finite<f64>, end_time: Finite<f64>,
) -> DomRoot<AudioParam> { ) -> DomRoot<AudioParam> {
self.message_node( self.message_node(AudioNodeMessage::SetParam(
AudioNodeMessage::SetParam(
self.param, self.param,
UserAutomationEvent::RampToValueAtTime(RampKind::Exponential, *value, *end_time), UserAutomationEvent::RampToValueAtTime(RampKind::Exponential, *value, *end_time),
), ));
);
DomRoot::from_ref(self) DomRoot::from_ref(self)
} }
@ -185,34 +181,28 @@ impl AudioParamMethods for AudioParam {
start_time: Finite<f64>, start_time: Finite<f64>,
time_constant: Finite<f32>, time_constant: Finite<f32>,
) -> DomRoot<AudioParam> { ) -> DomRoot<AudioParam> {
self.message_node( self.message_node(AudioNodeMessage::SetParam(
AudioNodeMessage::SetParam(
self.param, self.param,
UserAutomationEvent::SetTargetAtTime(*target, *start_time, (*time_constant).into()), UserAutomationEvent::SetTargetAtTime(*target, *start_time, (*time_constant).into()),
), ));
);
DomRoot::from_ref(self) DomRoot::from_ref(self)
} }
// https://webaudio.github.io/web-audio-api/#dom-audioparam-cancelscheduledvalues // https://webaudio.github.io/web-audio-api/#dom-audioparam-cancelscheduledvalues
fn CancelScheduledValues(&self, cancel_time: Finite<f64>) -> DomRoot<AudioParam> { fn CancelScheduledValues(&self, cancel_time: Finite<f64>) -> DomRoot<AudioParam> {
self.message_node( self.message_node(AudioNodeMessage::SetParam(
AudioNodeMessage::SetParam(
self.param, self.param,
UserAutomationEvent::CancelScheduledValues(*cancel_time), UserAutomationEvent::CancelScheduledValues(*cancel_time),
), ));
);
DomRoot::from_ref(self) DomRoot::from_ref(self)
} }
// https://webaudio.github.io/web-audio-api/#dom-audioparam-cancelandholdattime // https://webaudio.github.io/web-audio-api/#dom-audioparam-cancelandholdattime
fn CancelAndHoldAtTime(&self, cancel_time: Finite<f64>) -> DomRoot<AudioParam> { fn CancelAndHoldAtTime(&self, cancel_time: Finite<f64>) -> DomRoot<AudioParam> {
self.message_node( self.message_node(AudioNodeMessage::SetParam(
AudioNodeMessage::SetParam(
self.param, self.param,
UserAutomationEvent::CancelAndHoldAtTime(*cancel_time), UserAutomationEvent::CancelAndHoldAtTime(*cancel_time),
), ));
);
DomRoot::from_ref(self) DomRoot::from_ref(self)
} }
} }

View file

@ -84,9 +84,10 @@ impl AudioScheduledSourceNodeMethods for AudioScheduledSourceNode {
); );
}); });
self.node().message( self.node()
AudioNodeMessage::AudioScheduledSourceNode( .message(AudioNodeMessage::AudioScheduledSourceNode(
AudioScheduledSourceNodeMessage::RegisterOnEndedCallback(callback))); AudioScheduledSourceNodeMessage::RegisterOnEndedCallback(callback),
));
self.started.set(true); self.started.set(true);
self.node self.node

View file

@ -98,7 +98,9 @@ impl BaseAudioContext {
pub fn new_inherited(options: BaseAudioContextOptions) -> BaseAudioContext { pub fn new_inherited(options: BaseAudioContextOptions) -> BaseAudioContext {
let (sample_rate, channel_count) = match options { let (sample_rate, channel_count) = match options {
BaseAudioContextOptions::AudioContext(ref opt) => (opt.sample_rate, 2), BaseAudioContextOptions::AudioContext(ref opt) => (opt.sample_rate, 2),
BaseAudioContextOptions::OfflineAudioContext(ref opt) => (opt.sample_rate, opt.channels), BaseAudioContextOptions::OfflineAudioContext(ref opt) => {
(opt.sample_rate, opt.channels)
},
}; };
let context = BaseAudioContext { let context = BaseAudioContext {
@ -312,9 +314,7 @@ impl BaseAudioContextMethods for BaseAudioContext {
fn Listener(&self) -> DomRoot<AudioListener> { fn Listener(&self) -> DomRoot<AudioListener> {
let global = self.global(); let global = self.global();
let window = global.as_window(); let window = global.as_window();
self.listener.or_init(|| { self.listener.or_init(|| AudioListener::new(&window, self))
AudioListener::new(&window, self)
})
} }
/// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-onstatechange /// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-onstatechange
@ -425,12 +425,10 @@ impl BaseAudioContextMethods for BaseAudioContext {
.lock() .lock()
.unwrap() .unwrap()
.resize(channel_count as usize, Vec::new()); .resize(channel_count as usize, Vec::new());
}) }).progress(move |buffer, channel| {
.progress(move |buffer, channel| {
let mut decoded_audio = decoded_audio_.lock().unwrap(); let mut decoded_audio = decoded_audio_.lock().unwrap();
decoded_audio[(channel - 1) as usize].extend_from_slice((*buffer).as_ref()); decoded_audio[(channel - 1) as usize].extend_from_slice((*buffer).as_ref());
}) }).eos(move || {
.eos(move || {
let _ = task_source.queue_with_canceller( let _ = task_source.queue_with_canceller(
task!(audio_decode_eos: move || { task!(audio_decode_eos: move || {
let this = this.root(); let this = this.root();
@ -456,8 +454,7 @@ impl BaseAudioContextMethods for BaseAudioContext {
}), }),
&canceller, &canceller,
); );
}) }).error(move || {
.error(move || {
let _ = task_source_.queue_with_canceller( let _ = task_source_.queue_with_canceller(
task!(audio_decode_eos: move || { task!(audio_decode_eos: move || {
let this = this_.root(); let this = this_.root();
@ -473,8 +470,7 @@ impl BaseAudioContextMethods for BaseAudioContext {
}), }),
&canceller_, &canceller_,
); );
}) }).build();
.build();
self.audio_context_impl self.audio_context_impl
.decode_audio_data(audio_data, callbacks); .decode_audio_data(audio_data, callbacks);
} else { } else {
@ -491,10 +487,12 @@ impl BaseAudioContextMethods for BaseAudioContext {
impl From<BaseAudioContextOptions> for AudioContextOptions { impl From<BaseAudioContextOptions> for AudioContextOptions {
fn from(options: BaseAudioContextOptions) -> Self { fn from(options: BaseAudioContextOptions) -> Self {
match options { match options {
BaseAudioContextOptions::AudioContext(options) => BaseAudioContextOptions::AudioContext(options) => {
AudioContextOptions::RealTimeAudioContext(options), AudioContextOptions::RealTimeAudioContext(options)
BaseAudioContextOptions::OfflineAudioContext(options) => },
AudioContextOptions::OfflineAudioContext(options), BaseAudioContextOptions::OfflineAudioContext(options) => {
AudioContextOptions::OfflineAudioContext(options)
},
} }
} }
} }

View file

@ -33,20 +33,23 @@ impl BeforeUnloadEvent {
} }
pub fn new_uninitialized(window: &Window) -> DomRoot<BeforeUnloadEvent> { pub fn new_uninitialized(window: &Window) -> DomRoot<BeforeUnloadEvent> {
reflect_dom_object(Box::new(BeforeUnloadEvent::new_inherited()), reflect_dom_object(
Box::new(BeforeUnloadEvent::new_inherited()),
window, window,
BeforeUnloadEventBinding::Wrap) BeforeUnloadEventBinding::Wrap,
)
} }
pub fn new(window: &Window, pub fn new(
window: &Window,
type_: Atom, type_: Atom,
bubbles: EventBubbles, bubbles: EventBubbles,
cancelable: EventCancelable) -> DomRoot<BeforeUnloadEvent> { cancelable: EventCancelable,
) -> DomRoot<BeforeUnloadEvent> {
let ev = BeforeUnloadEvent::new_uninitialized(window); let ev = BeforeUnloadEvent::new_uninitialized(window);
{ {
let event = ev.upcast::<Event>(); let event = ev.upcast::<Event>();
event.init_event(type_, bool::from(bubbles), event.init_event(type_, bool::from(bubbles), bool::from(cancelable));
bool::from(cancelable));
} }
ev ev
} }

View file

@ -53,7 +53,7 @@ pub struct CallbackObject {
/// ///
/// ["callback context"]: https://heycam.github.io/webidl/#dfn-callback-context /// ["callback context"]: https://heycam.github.io/webidl/#dfn-callback-context
/// [sometimes]: https://github.com/whatwg/html/issues/2248 /// [sometimes]: https://github.com/whatwg/html/issues/2248
incumbent: Option<Dom<GlobalScope>> incumbent: Option<Dom<GlobalScope>>,
} }
impl Default for CallbackObject { impl Default for CallbackObject {
@ -81,8 +81,11 @@ impl CallbackObject {
unsafe fn init(&mut self, cx: *mut JSContext, callback: *mut JSObject) { unsafe fn init(&mut self, cx: *mut JSContext, callback: *mut JSObject) {
self.callback.set(callback); self.callback.set(callback);
self.permanent_js_root.set(ObjectValue(callback)); self.permanent_js_root.set(ObjectValue(callback));
assert!(AddRawValueRoot(cx, self.permanent_js_root.get_unsafe(), assert!(AddRawValueRoot(
b"CallbackObject::root\n".as_c_char_ptr())); cx,
self.permanent_js_root.get_unsafe(),
b"CallbackObject::root\n".as_c_char_ptr()
));
} }
} }
@ -94,7 +97,6 @@ impl Drop for CallbackObject {
RemoveRawValueRoot(cx, self.permanent_js_root.get_unsafe()); RemoveRawValueRoot(cx, self.permanent_js_root.get_unsafe());
} }
} }
} }
impl PartialEq for CallbackObject { impl PartialEq for CallbackObject {
@ -103,7 +105,6 @@ impl PartialEq for CallbackObject {
} }
} }
/// A trait to be implemented by concrete IDL callback function and /// A trait to be implemented by concrete IDL callback function and
/// callback interface types. /// callback interface types.
pub trait CallbackContainer { pub trait CallbackContainer {
@ -124,7 +125,6 @@ pub trait CallbackContainer {
} }
} }
/// A common base class for representing IDL callback function types. /// A common base class for representing IDL callback function types.
#[derive(JSTraceable, PartialEq)] #[derive(JSTraceable, PartialEq)]
#[must_root] #[must_root]
@ -153,9 +153,6 @@ impl CallbackFunction {
} }
} }
/// A common base class for representing IDL callback interface types. /// A common base class for representing IDL callback interface types.
#[derive(JSTraceable, PartialEq)] #[derive(JSTraceable, PartialEq)]
#[must_root] #[must_root]
@ -194,19 +191,22 @@ impl CallbackInterface {
} }
if !callable.is_object() || !IsCallable(callable.to_object()) { if !callable.is_object() || !IsCallable(callable.to_object()) {
return Err(Error::Type(format!("The value of the {} property is not callable", return Err(Error::Type(format!(
name))); "The value of the {} property is not callable",
name
)));
} }
} }
Ok(callable.get()) Ok(callable.get())
} }
} }
/// Wraps the reflector for `p` into the compartment of `cx`. /// Wraps the reflector for `p` into the compartment of `cx`.
pub fn wrap_call_this_object<T: DomObject>(cx: *mut JSContext, pub fn wrap_call_this_object<T: DomObject>(
cx: *mut JSContext,
p: &T, p: &T,
mut rval: MutableHandleObject) { mut rval: MutableHandleObject,
) {
rval.set(p.reflector().get_jsobject().get()); rval.set(p.reflector().get_jsobject().get());
assert!(!rval.get().is_null()); assert!(!rval.get().is_null());
@ -217,7 +217,6 @@ pub fn wrap_call_this_object<T: DomObject>(cx: *mut JSContext,
} }
} }
/// A class that performs whatever setup we need to safely make a call while /// A class that performs whatever setup we need to safely make a call while
/// this class is on the stack. After `new` returns, the call is safe to make. /// this class is on the stack. After `new` returns, the call is safe to make.
pub struct CallSetup { pub struct CallSetup {
@ -241,9 +240,7 @@ pub struct CallSetup {
impl CallSetup { impl CallSetup {
/// Performs the setup needed to make a call. /// Performs the setup needed to make a call.
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
pub fn new<T: CallbackContainer>(callback: &T, pub fn new<T: CallbackContainer>(callback: &T, handling: ExceptionHandling) -> CallSetup {
handling: ExceptionHandling)
-> CallSetup {
let global = unsafe { GlobalScope::from_object(callback.callback()) }; let global = unsafe { GlobalScope::from_object(callback.callback()) };
let cx = global.get_cx(); let cx = global.get_cx();
@ -270,8 +267,10 @@ impl Drop for CallSetup {
unsafe { unsafe {
JS_LeaveCompartment(self.cx, self.old_compartment); JS_LeaveCompartment(self.cx, self.old_compartment);
if self.handling == ExceptionHandling::Report { if self.handling == ExceptionHandling::Report {
let _ac = JSAutoCompartment::new(self.cx, let _ac = JSAutoCompartment::new(
self.exception_global.reflector().get_jsobject().get()); self.cx,
self.exception_global.reflector().get_jsobject().get(),
);
report_pending_exception(self.cx, true); report_pending_exception(self.cx, true);
} }
drop(self.incumbent_script.take()); drop(self.incumbent_script.take());

View file

@ -55,7 +55,6 @@ impl<T> DomRefCell<T> {
} }
} }
/// Immutably borrows the wrapped value. /// Immutably borrows the wrapped value.
/// ///
/// The borrow lasts until the returned `Ref` exits scope. Multiple /// The borrow lasts until the returned `Ref` exits scope. Multiple
@ -67,7 +66,8 @@ impl<T> DomRefCell<T> {
/// ///
/// Panics if the value is currently mutably borrowed. /// Panics if the value is currently mutably borrowed.
pub fn borrow(&self) -> Ref<T> { pub fn borrow(&self) -> Ref<T> {
self.try_borrow().expect("DomRefCell<T> already mutably borrowed") self.try_borrow()
.expect("DomRefCell<T> already mutably borrowed")
} }
/// Mutably borrows the wrapped value. /// Mutably borrows the wrapped value.
@ -81,7 +81,8 @@ impl<T> DomRefCell<T> {
/// ///
/// Panics if the value is currently borrowed. /// Panics if the value is currently borrowed.
pub fn borrow_mut(&self) -> RefMut<T> { pub fn borrow_mut(&self) -> RefMut<T> {
self.try_borrow_mut().expect("DomRefCell<T> already borrowed") self.try_borrow_mut()
.expect("DomRefCell<T> already borrowed")
} }
/// Attempts to immutably borrow the wrapped value. /// Attempts to immutably borrow the wrapped value.

View file

@ -51,16 +51,15 @@ impl ConstantSpec {
/// Defines constants on `obj`. /// Defines constants on `obj`.
/// Fails on JSAPI failure. /// Fails on JSAPI failure.
pub unsafe fn define_constants( pub unsafe fn define_constants(cx: *mut JSContext, obj: HandleObject, constants: &[ConstantSpec]) {
cx: *mut JSContext,
obj: HandleObject,
constants: &[ConstantSpec]) {
for spec in constants { for spec in constants {
rooted!(in(cx) let value = spec.get_value()); rooted!(in(cx) let value = spec.get_value());
assert!(JS_DefineProperty(cx, assert!(JS_DefineProperty(
cx,
obj, obj,
spec.name.as_ptr() as *const libc::c_char, spec.name.as_ptr() as *const libc::c_char,
value.handle(), value.handle(),
(JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT) as u32)); (JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT) as u32
));
} }
} }

View file

@ -69,8 +69,10 @@ pub trait IDLInterface {
} }
/// A trait to mark an IDL interface as deriving from another one. /// A trait to mark an IDL interface as deriving from another one.
#[cfg_attr(feature = "unstable", #[cfg_attr(
rustc_on_unimplemented = "The IDL interface `{Self}` is not derived from `{T}`.")] feature = "unstable",
rustc_on_unimplemented = "The IDL interface `{Self}` is not derived from `{T}`."
)]
pub trait DerivedFrom<T: Castable>: Castable {} pub trait DerivedFrom<T: Castable>: Castable {}
impl<T: Float + ToJSValConvertible> ToJSValConvertible for Finite<T> { impl<T: Float + ToJSValConvertible> ToJSValConvertible for Finite<T> {
@ -81,20 +83,21 @@ impl<T: Float + ToJSValConvertible> ToJSValConvertible for Finite<T> {
} }
} }
impl<T: Float + FromJSValConvertible<Config=()>> FromJSValConvertible for Finite<T> { impl<T: Float + FromJSValConvertible<Config = ()>> FromJSValConvertible for Finite<T> {
type Config = (); type Config = ();
unsafe fn from_jsval(cx: *mut JSContext, unsafe fn from_jsval(
cx: *mut JSContext,
value: HandleValue, value: HandleValue,
option: ()) option: (),
-> Result<ConversionResult<Finite<T>>, ()> { ) -> Result<ConversionResult<Finite<T>>, ()> {
let result = match FromJSValConvertible::from_jsval(cx, value, option)? { let result = match FromJSValConvertible::from_jsval(cx, value, option)? {
ConversionResult::Success(v) => v, ConversionResult::Success(v) => v,
ConversionResult::Failure(error) => { ConversionResult::Failure(error) => {
// FIXME(emilio): Why throwing instead of propagating the error? // FIXME(emilio): Why throwing instead of propagating the error?
throw_type_error(cx, &error); throw_type_error(cx, &error);
return Err(()); return Err(());
} },
}; };
match Finite::new(result) { match Finite::new(result) {
Some(v) => Ok(ConversionResult::Success(v)), Some(v) => Ok(ConversionResult::Success(v)),
@ -106,13 +109,14 @@ impl<T: Float + FromJSValConvertible<Config=()>> FromJSValConvertible for Finite
} }
} }
impl <T: DomObject + IDLInterface> FromJSValConvertible for DomRoot<T> { impl<T: DomObject + IDLInterface> FromJSValConvertible for DomRoot<T> {
type Config = (); type Config = ();
unsafe fn from_jsval(_cx: *mut JSContext, unsafe fn from_jsval(
_cx: *mut JSContext,
value: HandleValue, value: HandleValue,
_config: Self::Config) _config: Self::Config,
-> Result<ConversionResult<DomRoot<T>>, ()> { ) -> Result<ConversionResult<DomRoot<T>>, ()> {
Ok(match root_from_handlevalue(value) { Ok(match root_from_handlevalue(value) {
Ok(result) => ConversionResult::Success(result), Ok(result) => ConversionResult::Success(result),
Err(()) => ConversionResult::Failure("value is not an object".into()), Err(()) => ConversionResult::Failure("value is not an object".into()),
@ -129,19 +133,21 @@ impl<T: ToJSValConvertible + JSTraceable> ToJSValConvertible for RootedTraceable
} }
impl<T> FromJSValConvertible for RootedTraceableBox<Heap<T>> impl<T> FromJSValConvertible for RootedTraceableBox<Heap<T>>
where where
T: FromJSValConvertible + js::rust::GCMethods + Copy, T: FromJSValConvertible + js::rust::GCMethods + Copy,
Heap<T>: JSTraceable + Default Heap<T>: JSTraceable + Default,
{ {
type Config = T::Config; type Config = T::Config;
unsafe fn from_jsval(cx: *mut JSContext, unsafe fn from_jsval(
cx: *mut JSContext,
value: HandleValue, value: HandleValue,
config: Self::Config) config: Self::Config,
-> Result<ConversionResult<Self>, ()> { ) -> Result<ConversionResult<Self>, ()> {
T::from_jsval(cx, value, config).map(|result| match result { T::from_jsval(cx, value, config).map(|result| match result {
ConversionResult::Success(inner) => ConversionResult::Success(inner) => {
ConversionResult::Success(RootedTraceableBox::from_box(Heap::boxed(inner))), ConversionResult::Success(RootedTraceableBox::from_box(Heap::boxed(inner)))
},
ConversionResult::Failure(msg) => ConversionResult::Failure(msg), ConversionResult::Failure(msg) => ConversionResult::Failure(msg),
}) })
} }
@ -190,12 +196,12 @@ impl ToJSValConvertible for DOMString {
// https://heycam.github.io/webidl/#es-DOMString // https://heycam.github.io/webidl/#es-DOMString
impl FromJSValConvertible for DOMString { impl FromJSValConvertible for DOMString {
type Config = StringificationBehavior; type Config = StringificationBehavior;
unsafe fn from_jsval(cx: *mut JSContext, unsafe fn from_jsval(
cx: *mut JSContext,
value: HandleValue, value: HandleValue,
null_behavior: StringificationBehavior) null_behavior: StringificationBehavior,
-> Result<ConversionResult<DOMString>, ()> { ) -> Result<ConversionResult<DOMString>, ()> {
if null_behavior == StringificationBehavior::Empty && if null_behavior == StringificationBehavior::Empty && value.get().is_null() {
value.get().is_null() {
Ok(ConversionResult::Success(DOMString::new())) Ok(ConversionResult::Success(DOMString::new()))
} else { } else {
let jsstr = ToString(cx, value); let jsstr = ToString(cx, value);
@ -231,16 +237,19 @@ pub unsafe fn jsstring_to_str(cx: *mut JSContext, s: *mut JSString) -> DOMString
"Found an unpaired surrogate in a DOM string. \ "Found an unpaired surrogate in a DOM string. \
If you see this in real web content, \ If you see this in real web content, \
please comment on https://github.com/servo/servo/issues/6564" please comment on https://github.com/servo/servo/issues/6564"
} };
} }
if opts::get().replace_surrogates { if opts::get().replace_surrogates {
error!(message!()); error!(message!());
s.push('\u{FFFD}'); s.push('\u{FFFD}');
} else { } else {
panic!(concat!(message!(), " Use `-Z replace-surrogates` \ panic!(concat!(
on the command line to make this non-fatal.")); message!(),
} " Use `-Z replace-surrogates` \
on the command line to make this non-fatal."
));
} }
},
} }
} }
s s
@ -250,8 +259,11 @@ pub unsafe fn jsstring_to_str(cx: *mut JSContext, s: *mut JSString) -> DOMString
// http://heycam.github.io/webidl/#es-USVString // http://heycam.github.io/webidl/#es-USVString
impl FromJSValConvertible for USVString { impl FromJSValConvertible for USVString {
type Config = (); type Config = ();
unsafe fn from_jsval(cx: *mut JSContext, value: HandleValue, _: ()) unsafe fn from_jsval(
-> Result<ConversionResult<USVString>, ()> { cx: *mut JSContext,
value: HandleValue,
_: (),
) -> Result<ConversionResult<USVString>, ()> {
let jsstr = ToString(cx, value); let jsstr = ToString(cx, value);
if jsstr.is_null() { if jsstr.is_null() {
debug!("ToString failed"); debug!("ToString failed");
@ -260,23 +272,28 @@ impl FromJSValConvertible for USVString {
let latin1 = JS_StringHasLatin1Chars(jsstr); let latin1 = JS_StringHasLatin1Chars(jsstr);
if latin1 { if latin1 {
// FIXME(ajeffrey): Convert directly from DOMString to USVString // FIXME(ajeffrey): Convert directly from DOMString to USVString
return Ok(ConversionResult::Success( return Ok(ConversionResult::Success(USVString(String::from(
USVString(String::from(jsstring_to_str(cx, jsstr))))); jsstring_to_str(cx, jsstr),
))));
} }
let mut length = 0; let mut length = 0;
let chars = JS_GetTwoByteStringCharsAndLength(cx, ptr::null(), jsstr, &mut length); let chars = JS_GetTwoByteStringCharsAndLength(cx, ptr::null(), jsstr, &mut length);
assert!(!chars.is_null()); assert!(!chars.is_null());
let char_vec = slice::from_raw_parts(chars as *const u16, length as usize); let char_vec = slice::from_raw_parts(chars as *const u16, length as usize);
Ok(ConversionResult::Success(USVString(String::from_utf16_lossy(char_vec)))) Ok(ConversionResult::Success(USVString(
String::from_utf16_lossy(char_vec),
)))
} }
} }
// http://heycam.github.io/webidl/#es-ByteString // http://heycam.github.io/webidl/#es-ByteString
impl ToJSValConvertible for ByteString { impl ToJSValConvertible for ByteString {
unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) { unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {
let jsstr = JS_NewStringCopyN(cx, let jsstr = JS_NewStringCopyN(
cx,
self.as_ptr() as *const libc::c_char, self.as_ptr() as *const libc::c_char,
self.len() as libc::size_t); self.len() as libc::size_t,
);
if jsstr.is_null() { if jsstr.is_null() {
panic!("JS_NewStringCopyN failed"); panic!("JS_NewStringCopyN failed");
} }
@ -287,10 +304,11 @@ impl ToJSValConvertible for ByteString {
// http://heycam.github.io/webidl/#es-ByteString // http://heycam.github.io/webidl/#es-ByteString
impl FromJSValConvertible for ByteString { impl FromJSValConvertible for ByteString {
type Config = (); type Config = ();
unsafe fn from_jsval(cx: *mut JSContext, unsafe fn from_jsval(
cx: *mut JSContext,
value: HandleValue, value: HandleValue,
_option: ()) _option: (),
-> Result<ConversionResult<ByteString>, ()> { ) -> Result<ConversionResult<ByteString>, ()> {
let string = ToString(cx, value); let string = ToString(cx, value);
if string.is_null() { if string.is_null() {
debug!("ToString failed"); debug!("ToString failed");
@ -304,7 +322,9 @@ impl FromJSValConvertible for ByteString {
assert!(!chars.is_null()); assert!(!chars.is_null());
let char_slice = slice::from_raw_parts(chars as *mut u8, length as usize); let char_slice = slice::from_raw_parts(chars as *mut u8, length as usize);
return Ok(ConversionResult::Success(ByteString::new(char_slice.to_vec()))); return Ok(ConversionResult::Success(ByteString::new(
char_slice.to_vec(),
)));
} }
let mut length = 0; let mut length = 0;
@ -315,13 +335,13 @@ impl FromJSValConvertible for ByteString {
throw_type_error(cx, "Invalid ByteString"); throw_type_error(cx, "Invalid ByteString");
Err(()) Err(())
} else { } else {
Ok(ConversionResult::Success( Ok(ConversionResult::Success(ByteString::new(
ByteString::new(char_vec.iter().map(|&c| c as u8).collect()))) char_vec.iter().map(|&c| c as u8).collect(),
)))
} }
} }
} }
impl ToJSValConvertible for Reflector { impl ToJSValConvertible for Reflector {
unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) { unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {
let obj = self.get_jsobject().get(); let obj = self.get_jsobject().get();
@ -389,10 +409,12 @@ pub unsafe fn get_dom_class(obj: *mut JSObject) -> Result<&'static DOMClass, ()>
/// not an object for a DOM object of the given type (as defined by the /// not an object for a DOM object of the given type (as defined by the
/// proto_id and proto_depth). /// proto_id and proto_depth).
#[inline] #[inline]
pub unsafe fn private_from_proto_check<F>(mut obj: *mut JSObject, pub unsafe fn private_from_proto_check<F>(
proto_check: F) mut obj: *mut JSObject,
-> Result<*const libc::c_void, ()> proto_check: F,
where F: Fn(&'static DOMClass) -> bool ) -> Result<*const libc::c_void, ()>
where
F: Fn(&'static DOMClass) -> bool,
{ {
let dom_class = get_dom_class(obj).or_else(|_| { let dom_class = get_dom_class(obj).or_else(|_| {
if IsWrapper(obj) { if IsWrapper(obj) {
@ -423,11 +445,10 @@ pub unsafe fn private_from_proto_check<F>(mut obj: *mut JSObject,
/// Get a `*const T` for a DOM object accessible from a `JSObject`. /// Get a `*const T` for a DOM object accessible from a `JSObject`.
pub fn native_from_object<T>(obj: *mut JSObject) -> Result<*const T, ()> pub fn native_from_object<T>(obj: *mut JSObject) -> Result<*const T, ()>
where T: DomObject + IDLInterface where
T: DomObject + IDLInterface,
{ {
unsafe { unsafe { private_from_proto_check(obj, T::derives).map(|ptr| ptr as *const T) }
private_from_proto_check(obj, T::derives).map(|ptr| ptr as *const T)
}
} }
/// Get a `DomRoot<T>` for the given DOM object, unwrapping any wrapper /// Get a `DomRoot<T>` for the given DOM object, unwrapping any wrapper
@ -437,7 +458,8 @@ pub fn native_from_object<T>(obj: *mut JSObject) -> Result<*const T, ()>
/// not a reflector for a DOM object of the given type (as defined by the /// not a reflector for a DOM object of the given type (as defined by the
/// proto_id and proto_depth). /// proto_id and proto_depth).
pub fn root_from_object<T>(obj: *mut JSObject) -> Result<DomRoot<T>, ()> pub fn root_from_object<T>(obj: *mut JSObject) -> Result<DomRoot<T>, ()>
where T: DomObject + IDLInterface where
T: DomObject + IDLInterface,
{ {
native_from_object(obj).map(|ptr| unsafe { DomRoot::from_ref(&*ptr) }) native_from_object(obj).map(|ptr| unsafe { DomRoot::from_ref(&*ptr) })
} }
@ -445,7 +467,8 @@ pub fn root_from_object<T>(obj: *mut JSObject) -> Result<DomRoot<T>, ()>
/// Get a `*const T` for a DOM object accessible from a `HandleValue`. /// Get a `*const T` for a DOM object accessible from a `HandleValue`.
/// Caller is responsible for throwing a JS exception if needed in case of error. /// Caller is responsible for throwing a JS exception if needed in case of error.
pub fn native_from_handlevalue<T>(v: HandleValue) -> Result<*const T, ()> pub fn native_from_handlevalue<T>(v: HandleValue) -> Result<*const T, ()>
where T: DomObject + IDLInterface where
T: DomObject + IDLInterface,
{ {
if !v.get().is_object() { if !v.get().is_object() {
return Err(()); return Err(());
@ -456,7 +479,8 @@ pub fn native_from_handlevalue<T>(v: HandleValue) -> Result<*const T, ()>
/// Get a `DomRoot<T>` for a DOM object accessible from a `HandleValue`. /// Get a `DomRoot<T>` for a DOM object accessible from a `HandleValue`.
/// Caller is responsible for throwing a JS exception if needed in case of error. /// Caller is responsible for throwing a JS exception if needed in case of error.
pub fn root_from_handlevalue<T>(v: HandleValue) -> Result<DomRoot<T>, ()> pub fn root_from_handlevalue<T>(v: HandleValue) -> Result<DomRoot<T>, ()>
where T: DomObject + IDLInterface where
T: DomObject + IDLInterface,
{ {
if !v.get().is_object() { if !v.get().is_object() {
return Err(()); return Err(());
@ -466,7 +490,8 @@ pub fn root_from_handlevalue<T>(v: HandleValue) -> Result<DomRoot<T>, ()>
/// Get a `DomRoot<T>` for a DOM object accessible from a `HandleObject`. /// Get a `DomRoot<T>` for a DOM object accessible from a `HandleObject`.
pub fn root_from_handleobject<T>(obj: HandleObject) -> Result<DomRoot<T>, ()> pub fn root_from_handleobject<T>(obj: HandleObject) -> Result<DomRoot<T>, ()>
where T: DomObject + IDLInterface where
T: DomObject + IDLInterface,
{ {
root_from_object(obj.get()) root_from_object(obj.get())
} }
@ -487,12 +512,12 @@ pub unsafe fn is_array_like(cx: *mut JSContext, value: HandleValue) -> bool {
} }
/// Get a property from a JS object. /// Get a property from a JS object.
pub unsafe fn get_property_jsval(cx: *mut JSContext, pub unsafe fn get_property_jsval(
cx: *mut JSContext,
object: HandleObject, object: HandleObject,
name: &str, name: &str,
mut rval: MutableHandleValue) mut rval: MutableHandleValue,
-> Fallible<()> ) -> Fallible<()> {
{
rval.set(UndefinedValue()); rval.set(UndefinedValue());
let cname = match ffi::CString::new(name) { let cname = match ffi::CString::new(name) {
Ok(cname) => cname, Ok(cname) => cname,
@ -506,12 +531,14 @@ pub unsafe fn get_property_jsval(cx: *mut JSContext,
} }
/// Get a property from a JS object, and convert it to a Rust value. /// Get a property from a JS object, and convert it to a Rust value.
pub unsafe fn get_property<T>(cx: *mut JSContext, pub unsafe fn get_property<T>(
cx: *mut JSContext,
object: HandleObject, object: HandleObject,
name: &str, name: &str,
option: T::Config) option: T::Config,
-> Fallible<Option<T>> where ) -> Fallible<Option<T>>
T: FromJSValConvertible where
T: FromJSValConvertible,
{ {
debug!("Getting property {}.", name); debug!("Getting property {}.", name);
rooted!(in(cx) let mut result = UndefinedValue()); rooted!(in(cx) let mut result = UndefinedValue());

View file

@ -126,7 +126,7 @@ pub unsafe fn throw_dom_exception(cx: *mut JSContext, global: &GlobalScope, resu
Error::JSFailed => { Error::JSFailed => {
assert!(JS_IsExceptionPending(cx)); assert!(JS_IsExceptionPending(cx));
return; return;
} },
}; };
assert!(!JS_IsExceptionPending(cx)); assert!(!JS_IsExceptionPending(cx));
@ -149,8 +149,7 @@ pub struct ErrorInfo {
} }
impl ErrorInfo { impl ErrorInfo {
unsafe fn from_native_error(cx: *mut JSContext, object: HandleObject) unsafe fn from_native_error(cx: *mut JSContext, object: HandleObject) -> Option<ErrorInfo> {
-> Option<ErrorInfo> {
let report = JS_ErrorFromException(cx, object); let report = JS_ErrorFromException(cx, object);
if report.is_null() { if report.is_null() {
return None; return None;
@ -205,7 +204,9 @@ impl ErrorInfo {
/// The `dispatch_event` argument is temporary and non-standard; passing false /// The `dispatch_event` argument is temporary and non-standard; passing false
/// prevents dispatching the `error` event. /// prevents dispatching the `error` event.
pub unsafe fn report_pending_exception(cx: *mut JSContext, dispatch_event: bool) { pub unsafe fn report_pending_exception(cx: *mut JSContext, dispatch_event: bool) {
if !JS_IsExceptionPending(cx) { return; } if !JS_IsExceptionPending(cx) {
return;
}
rooted!(in(cx) let mut value = UndefinedValue()); rooted!(in(cx) let mut value = UndefinedValue());
if !JS_GetPendingException(cx, value.handle_mut()) { if !JS_GetPendingException(cx, value.handle_mut()) {
@ -219,23 +220,19 @@ pub unsafe fn report_pending_exception(cx: *mut JSContext, dispatch_event: bool)
rooted!(in(cx) let object = value.to_object()); rooted!(in(cx) let object = value.to_object());
ErrorInfo::from_native_error(cx, object.handle()) ErrorInfo::from_native_error(cx, object.handle())
.or_else(|| ErrorInfo::from_dom_exception(object.handle())) .or_else(|| ErrorInfo::from_dom_exception(object.handle()))
.unwrap_or_else(|| { .unwrap_or_else(|| ErrorInfo {
ErrorInfo {
message: format!("uncaught exception: unknown (can't convert to string)"), message: format!("uncaught exception: unknown (can't convert to string)"),
filename: String::new(), filename: String::new(),
lineno: 0, lineno: 0,
column: 0, column: 0,
}
}) })
} else { } else {
match USVString::from_jsval(cx, value.handle(), ()) { match USVString::from_jsval(cx, value.handle(), ()) {
Ok(ConversionResult::Success(USVString(string))) => { Ok(ConversionResult::Success(USVString(string))) => ErrorInfo {
ErrorInfo {
message: format!("uncaught exception: {}", string), message: format!("uncaught exception: {}", string),
filename: String::new(), filename: String::new(),
lineno: 0, lineno: 0,
column: 0, column: 0,
}
}, },
_ => { _ => {
panic!("Uncaught exception: failed to stringify primitive"); panic!("Uncaught exception: failed to stringify primitive");
@ -243,15 +240,13 @@ pub unsafe fn report_pending_exception(cx: *mut JSContext, dispatch_event: bool)
} }
}; };
error!("Error at {}:{}:{} {}", error!(
error_info.filename, "Error at {}:{}:{} {}",
error_info.lineno, error_info.filename, error_info.lineno, error_info.column, error_info.message
error_info.column, );
error_info.message);
if dispatch_event { if dispatch_event {
GlobalScope::from_context(cx) GlobalScope::from_context(cx).report_an_error(error_info, value.handle());
.report_an_error(error_info, value.handle());
} }
} }
@ -259,14 +254,21 @@ pub unsafe fn report_pending_exception(cx: *mut JSContext, dispatch_event: bool)
/// given DOM type. /// given DOM type.
pub unsafe fn throw_invalid_this(cx: *mut JSContext, proto_id: u16) { pub unsafe fn throw_invalid_this(cx: *mut JSContext, proto_id: u16) {
debug_assert!(!JS_IsExceptionPending(cx)); debug_assert!(!JS_IsExceptionPending(cx));
let error = format!("\"this\" object does not implement interface {}.", let error = format!(
proto_id_to_name(proto_id)); "\"this\" object does not implement interface {}.",
proto_id_to_name(proto_id)
);
throw_type_error(cx, &error); throw_type_error(cx, &error);
} }
impl Error { impl Error {
/// Convert this error value to a JS value, consuming it in the process. /// Convert this error value to a JS value, consuming it in the process.
pub unsafe fn to_jsval(self, cx: *mut JSContext, global: &GlobalScope, rval: MutableHandleValue) { pub unsafe fn to_jsval(
self,
cx: *mut JSContext,
global: &GlobalScope,
rval: MutableHandleValue,
) {
assert!(!JS_IsExceptionPending(cx)); assert!(!JS_IsExceptionPending(cx));
throw_dom_exception(cx, global, self); throw_dom_exception(cx, global, self);
assert!(JS_IsExceptionPending(cx)); assert!(JS_IsExceptionPending(cx));

View file

@ -89,7 +89,9 @@ use std::ptr;
// https://html.spec.whatwg.org/multipage/#htmlconstructor // https://html.spec.whatwg.org/multipage/#htmlconstructor
pub unsafe fn html_constructor<T>(window: &Window, call_args: &CallArgs) -> Fallible<DomRoot<T>> pub unsafe fn html_constructor<T>(window: &Window, call_args: &CallArgs) -> Fallible<DomRoot<T>>
where T: DerivedFrom<Element> { where
T: DerivedFrom<Element>,
{
let document = window.Document(); let document = window.Document();
// Step 1 // Step 1
@ -101,7 +103,11 @@ pub unsafe fn html_constructor<T>(window: &Window, call_args: &CallArgs) -> Fall
rooted!(in(window.get_cx()) let new_target = call_args.new_target().to_object()); rooted!(in(window.get_cx()) let new_target = call_args.new_target().to_object());
let definition = match registry.lookup_definition_by_constructor(new_target.handle()) { let definition = match registry.lookup_definition_by_constructor(new_target.handle()) {
Some(definition) => definition, Some(definition) => definition,
None => return Err(Error::Type("No custom element definition found for new.target".to_owned())), None => {
return Err(Error::Type(
"No custom element definition found for new.target".to_owned(),
))
},
}; };
rooted!(in(window.get_cx()) let callee = UnwrapObject(call_args.callee(), 1)); rooted!(in(window.get_cx()) let callee = UnwrapObject(call_args.callee(), 1));
@ -119,18 +125,25 @@ pub unsafe fn html_constructor<T>(window: &Window, call_args: &CallArgs) -> Fall
// Since this element is autonomous, its active function object must be the HTMLElement // Since this element is autonomous, its active function object must be the HTMLElement
// Retrieve the constructor object for HTMLElement // Retrieve the constructor object for HTMLElement
HTMLElementBinding::GetConstructorObject(window.get_cx(), global_object.handle(), constructor.handle_mut()); HTMLElementBinding::GetConstructorObject(
} else {
// Step 5
get_constructor_object_from_local_name(definition.local_name.clone(),
window.get_cx(), window.get_cx(),
global_object.handle(), global_object.handle(),
constructor.handle_mut()); constructor.handle_mut(),
);
} else {
// Step 5
get_constructor_object_from_local_name(
definition.local_name.clone(),
window.get_cx(),
global_object.handle(),
constructor.handle_mut(),
);
} }
// Callee must be the same as the element interface's constructor object. // Callee must be the same as the element interface's constructor object.
if constructor.get() != callee.get() { if constructor.get() != callee.get() {
return Err(Error::Type("Custom element does not extend the proper interface".to_owned())); return Err(Error::Type(
"Custom element does not extend the proper interface".to_owned(),
));
} }
} }
@ -176,11 +189,12 @@ pub unsafe fn html_constructor<T>(window: &Window, call_args: &CallArgs) -> Fall
/// Returns the constructor object for the element associated with the given local name. /// Returns the constructor object for the element associated with the given local name.
/// This list should only include elements marked with the [HTMLConstructor] extended attribute. /// This list should only include elements marked with the [HTMLConstructor] extended attribute.
pub fn get_constructor_object_from_local_name(name: LocalName, pub fn get_constructor_object_from_local_name(
name: LocalName,
cx: *mut JSContext, cx: *mut JSContext,
global: HandleObject, global: HandleObject,
rval: MutableHandleObject) rval: MutableHandleObject,
-> bool { ) -> bool {
macro_rules! get_constructor( macro_rules! get_constructor(
($binding:ident) => ({ ($binding:ident) => ({
unsafe { $binding::GetConstructorObject(cx, global, rval); } unsafe { $binding::GetConstructorObject(cx, global, rval); }

View file

@ -16,7 +16,8 @@ use std::mem;
pub trait Castable: IDLInterface + DomObject + Sized { pub trait Castable: IDLInterface + DomObject + Sized {
/// Check whether a DOM object implements one of its deriving interfaces. /// Check whether a DOM object implements one of its deriving interfaces.
fn is<T>(&self) -> bool fn is<T>(&self) -> bool
where T: DerivedFrom<Self> where
T: DerivedFrom<Self>,
{ {
let class = unsafe { get_dom_class(self.reflector().get_jsobject().get()).unwrap() }; let class = unsafe { get_dom_class(self.reflector().get_jsobject().get()).unwrap() };
T::derives(class) T::derives(class)
@ -24,15 +25,17 @@ pub trait Castable: IDLInterface + DomObject + Sized {
/// Cast a DOM object upwards to one of the interfaces it derives from. /// Cast a DOM object upwards to one of the interfaces it derives from.
fn upcast<T>(&self) -> &T fn upcast<T>(&self) -> &T
where T: Castable, where
Self: DerivedFrom<T> T: Castable,
Self: DerivedFrom<T>,
{ {
unsafe { mem::transmute(self) } unsafe { mem::transmute(self) }
} }
/// Cast a DOM object downwards to one of the interfaces it might implement. /// Cast a DOM object downwards to one of the interfaces it might implement.
fn downcast<T>(&self) -> Option<&T> fn downcast<T>(&self) -> Option<&T>
where T: DerivedFrom<Self> where
T: DerivedFrom<Self>,
{ {
if self.is::<T>() { if self.is::<T>() {
Some(unsafe { mem::transmute(self) }) Some(unsafe { mem::transmute(self) })

View file

@ -52,11 +52,12 @@ unsafe impl Sync for NonCallbackInterfaceObjectClass {}
impl NonCallbackInterfaceObjectClass { impl NonCallbackInterfaceObjectClass {
/// Create a new `NonCallbackInterfaceObjectClass` structure. /// Create a new `NonCallbackInterfaceObjectClass` structure.
pub const fn new(constructor_behavior: &'static InterfaceConstructorBehavior, pub const fn new(
constructor_behavior: &'static InterfaceConstructorBehavior,
string_rep: &'static [u8], string_rep: &'static [u8],
proto_id: PrototypeList::ID, proto_id: PrototypeList::ID,
proto_depth: u16) proto_depth: u16,
-> NonCallbackInterfaceObjectClass { ) -> NonCallbackInterfaceObjectClass {
NonCallbackInterfaceObjectClass { NonCallbackInterfaceObjectClass {
class: Class { class: Class {
name: b"Function\0" as *const _ as *const libc::c_char, name: b"Function\0" as *const _ as *const libc::c_char,
@ -74,9 +75,7 @@ impl NonCallbackInterfaceObjectClass {
/// cast own reference to `JSClass` reference /// cast own reference to `JSClass` reference
pub fn as_jsclass(&self) -> &JSClass { pub fn as_jsclass(&self) -> &JSClass {
unsafe { unsafe { &*(self as *const _ as *const JSClass) }
&*(self as *const _ as *const JSClass)
}
} }
} }
@ -124,8 +123,7 @@ impl InterfaceConstructorBehavior {
} }
/// A trace hook. /// A trace hook.
pub type TraceHook = pub type TraceHook = unsafe extern "C" fn(trc: *mut JSTracer, obj: *mut JSObject);
unsafe extern "C" fn(trc: *mut JSTracer, obj: *mut JSObject);
/// Create a global object with the given class. /// Create a global object with the given class.
pub unsafe fn create_global_object( pub unsafe fn create_global_object(
@ -133,18 +131,21 @@ pub unsafe fn create_global_object(
class: &'static JSClass, class: &'static JSClass,
private: *const libc::c_void, private: *const libc::c_void,
trace: TraceHook, trace: TraceHook,
mut rval: MutableHandleObject) { mut rval: MutableHandleObject,
) {
assert!(rval.is_null()); assert!(rval.is_null());
let mut options = CompartmentOptions::default(); let mut options = CompartmentOptions::default();
options.creationOptions_.traceGlobal_ = Some(trace); options.creationOptions_.traceGlobal_ = Some(trace);
options.creationOptions_.sharedMemoryAndAtomics_ = true; options.creationOptions_.sharedMemoryAndAtomics_ = true;
rval.set(JS_NewGlobalObject(cx, rval.set(JS_NewGlobalObject(
cx,
class, class,
ptr::null_mut(), ptr::null_mut(),
OnNewGlobalHookOption::DontFireOnNewGlobalHook, OnNewGlobalHookOption::DontFireOnNewGlobalHook,
&options)); &options,
));
assert!(!rval.is_null()); assert!(!rval.is_null());
// Initialize the reserved slots before doing anything that can GC, to // Initialize the reserved slots before doing anything that can GC, to
@ -166,7 +167,8 @@ pub unsafe fn create_callback_interface_object(
global: HandleObject, global: HandleObject,
constants: &[Guard<&[ConstantSpec]>], constants: &[Guard<&[ConstantSpec]>],
name: &[u8], name: &[u8],
mut rval: MutableHandleObject) { mut rval: MutableHandleObject,
) {
assert!(!constants.is_empty()); assert!(!constants.is_empty());
rval.set(JS_NewObject(cx, ptr::null())); rval.set(JS_NewObject(cx, ptr::null()));
assert!(!rval.is_null()); assert!(!rval.is_null());
@ -184,8 +186,17 @@ pub unsafe fn create_interface_prototype_object(
regular_properties: &[Guard<&'static [JSPropertySpec]>], regular_properties: &[Guard<&'static [JSPropertySpec]>],
constants: &[Guard<&[ConstantSpec]>], constants: &[Guard<&[ConstantSpec]>],
unscopable_names: &[&[u8]], unscopable_names: &[&[u8]],
rval: MutableHandleObject) { rval: MutableHandleObject,
create_object(cx, proto, class, regular_methods, regular_properties, constants, rval); ) {
create_object(
cx,
proto,
class,
regular_methods,
regular_properties,
constants,
rval,
);
if !unscopable_names.is_empty() { if !unscopable_names.is_empty() {
rooted!(in(cx) let mut unscopable_obj = ptr::null_mut::<JSObject>()); rooted!(in(cx) let mut unscopable_obj = ptr::null_mut::<JSObject>());
@ -196,8 +207,12 @@ pub unsafe fn create_interface_prototype_object(
rooted!(in(cx) let unscopable_id = RUST_SYMBOL_TO_JSID(unscopable_symbol)); rooted!(in(cx) let unscopable_id = RUST_SYMBOL_TO_JSID(unscopable_symbol));
assert!(JS_DefinePropertyById4( assert!(JS_DefinePropertyById4(
cx, rval.handle(), unscopable_id.handle(), unscopable_obj.handle(), cx,
JSPROP_READONLY as u32)) rval.handle(),
unscopable_id.handle(),
unscopable_obj.handle(),
JSPROP_READONLY as u32
))
} }
} }
@ -213,15 +228,22 @@ pub unsafe fn create_noncallback_interface_object(
interface_prototype_object: HandleObject, interface_prototype_object: HandleObject,
name: &[u8], name: &[u8],
length: u32, length: u32,
rval: MutableHandleObject) { rval: MutableHandleObject,
create_object(cx, ) {
create_object(
cx,
proto, proto,
class.as_jsclass(), class.as_jsclass(),
static_methods, static_methods,
static_properties, static_properties,
constants, constants,
rval); rval,
assert!(JS_LinkConstructorAndPrototype(cx, rval.handle(), interface_prototype_object)); );
assert!(JS_LinkConstructorAndPrototype(
cx,
rval.handle(),
interface_prototype_object
));
define_name(cx, rval.handle(), name); define_name(cx, rval.handle(), name);
define_length(cx, rval.handle(), i32::try_from(length).expect("overflow")); define_length(cx, rval.handle(), i32::try_from(length).expect("overflow"));
define_on_global_object(cx, global, name, rval.handle()); define_on_global_object(cx, global, name, rval.handle());
@ -232,26 +254,31 @@ pub unsafe fn create_named_constructors(
cx: *mut JSContext, cx: *mut JSContext,
global: HandleObject, global: HandleObject,
named_constructors: &[(ConstructorClassHook, &[u8], u32)], named_constructors: &[(ConstructorClassHook, &[u8], u32)],
interface_prototype_object: HandleObject) { interface_prototype_object: HandleObject,
) {
rooted!(in(cx) let mut constructor = ptr::null_mut::<JSObject>()); rooted!(in(cx) let mut constructor = ptr::null_mut::<JSObject>());
for &(native, name, arity) in named_constructors { for &(native, name, arity) in named_constructors {
assert_eq!(*name.last().unwrap(), b'\0'); assert_eq!(*name.last().unwrap(), b'\0');
let fun = JS_NewFunction(cx, let fun = JS_NewFunction(
cx,
Some(native), Some(native),
arity, arity,
JSFUN_CONSTRUCTOR, JSFUN_CONSTRUCTOR,
name.as_ptr() as *const libc::c_char); name.as_ptr() as *const libc::c_char,
);
assert!(!fun.is_null()); assert!(!fun.is_null());
constructor.set(JS_GetFunctionObject(fun)); constructor.set(JS_GetFunctionObject(fun));
assert!(!constructor.is_null()); assert!(!constructor.is_null());
assert!(JS_DefineProperty2(cx, assert!(JS_DefineProperty2(
cx,
constructor.handle(), constructor.handle(),
b"prototype\0".as_ptr() as *const libc::c_char, b"prototype\0".as_ptr() as *const libc::c_char,
interface_prototype_object, interface_prototype_object,
(JSPROP_PERMANENT | JSPROP_READONLY) as u32)); (JSPROP_PERMANENT | JSPROP_READONLY) as u32
));
define_on_global_object(cx, global, name, constructor.handle()); define_on_global_object(cx, global, name, constructor.handle());
} }
@ -265,7 +292,8 @@ pub unsafe fn create_object(
methods: &[Guard<&'static [JSFunctionSpec]>], methods: &[Guard<&'static [JSFunctionSpec]>],
properties: &[Guard<&'static [JSPropertySpec]>], properties: &[Guard<&'static [JSPropertySpec]>],
constants: &[Guard<&[ConstantSpec]>], constants: &[Guard<&[ConstantSpec]>],
mut rval: MutableHandleObject) { mut rval: MutableHandleObject,
) {
rval.set(JS_NewObjectWithUniqueType(cx, class, proto)); rval.set(JS_NewObjectWithUniqueType(cx, class, proto));
assert!(!rval.is_null()); assert!(!rval.is_null());
define_guarded_methods(cx, rval.handle(), methods); define_guarded_methods(cx, rval.handle(), methods);
@ -277,7 +305,8 @@ pub unsafe fn create_object(
pub unsafe fn define_guarded_constants( pub unsafe fn define_guarded_constants(
cx: *mut JSContext, cx: *mut JSContext,
obj: HandleObject, obj: HandleObject,
constants: &[Guard<&[ConstantSpec]>]) { constants: &[Guard<&[ConstantSpec]>],
) {
for guard in constants { for guard in constants {
if let Some(specs) = guard.expose(cx, obj) { if let Some(specs) = guard.expose(cx, obj) {
define_constants(cx, obj, specs); define_constants(cx, obj, specs);
@ -289,7 +318,8 @@ pub unsafe fn define_guarded_constants(
pub unsafe fn define_guarded_methods( pub unsafe fn define_guarded_methods(
cx: *mut JSContext, cx: *mut JSContext,
obj: HandleObject, obj: HandleObject,
methods: &[Guard<&'static [JSFunctionSpec]>]) { methods: &[Guard<&'static [JSFunctionSpec]>],
) {
for guard in methods { for guard in methods {
if let Some(specs) = guard.expose(cx, obj) { if let Some(specs) = guard.expose(cx, obj) {
define_methods(cx, obj, specs).unwrap(); define_methods(cx, obj, specs).unwrap();
@ -301,7 +331,8 @@ pub unsafe fn define_guarded_methods(
pub unsafe fn define_guarded_properties( pub unsafe fn define_guarded_properties(
cx: *mut JSContext, cx: *mut JSContext,
obj: HandleObject, obj: HandleObject,
properties: &[Guard<&'static [JSPropertySpec]>]) { properties: &[Guard<&'static [JSPropertySpec]>],
) {
for guard in properties { for guard in properties {
if let Some(specs) = guard.expose(cx, obj) { if let Some(specs) = guard.expose(cx, obj) {
define_properties(cx, obj, specs).unwrap(); define_properties(cx, obj, specs).unwrap();
@ -323,13 +354,16 @@ pub unsafe fn define_on_global_object(
cx: *mut JSContext, cx: *mut JSContext,
global: HandleObject, global: HandleObject,
name: &[u8], name: &[u8],
obj: HandleObject) { obj: HandleObject,
) {
assert_eq!(*name.last().unwrap(), b'\0'); assert_eq!(*name.last().unwrap(), b'\0');
assert!(JS_DefineProperty2(cx, assert!(JS_DefineProperty2(
cx,
global, global,
name.as_ptr() as *const libc::c_char, name.as_ptr() as *const libc::c_char,
obj, obj,
JSPROP_RESOLVING)); JSPROP_RESOLVING
));
} }
const OBJECT_OPS: ObjectOps = ObjectOps { const OBJECT_OPS: ObjectOps = ObjectOps {
@ -344,10 +378,11 @@ const OBJECT_OPS: ObjectOps = ObjectOps {
funToString: Some(fun_to_string_hook), funToString: Some(fun_to_string_hook),
}; };
unsafe extern "C" fn fun_to_string_hook(cx: *mut JSContext, unsafe extern "C" fn fun_to_string_hook(
cx: *mut JSContext,
obj: RawHandleObject, obj: RawHandleObject,
_is_to_source: bool) _is_to_source: bool,
-> *mut JSString { ) -> *mut JSString {
let js_class = get_object_class(obj.get()); let js_class = get_object_class(obj.get());
assert!(!js_class.is_null()); assert!(!js_class.is_null());
let repr = (*(js_class as *const NonCallbackInterfaceObjectClass)).representation; let repr = (*(js_class as *const NonCallbackInterfaceObjectClass)).representation;
@ -358,17 +393,19 @@ unsafe extern "C" fn fun_to_string_hook(cx: *mut JSContext,
} }
/// Hook for instanceof on interface objects. /// Hook for instanceof on interface objects.
unsafe extern "C" fn has_instance_hook(cx: *mut JSContext, unsafe extern "C" fn has_instance_hook(
cx: *mut JSContext,
obj: RawHandleObject, obj: RawHandleObject,
value: RawMutableHandleValue, value: RawMutableHandleValue,
rval: *mut bool) -> bool { rval: *mut bool,
) -> bool {
let obj_raw = HandleObject::from_raw(obj); let obj_raw = HandleObject::from_raw(obj);
let val_raw = HandleValue::from_raw(value.handle()); let val_raw = HandleValue::from_raw(value.handle());
match has_instance(cx, obj_raw, val_raw) { match has_instance(cx, obj_raw, val_raw) {
Ok(result) => { Ok(result) => {
*rval = result; *rval = result;
true true
} },
Err(()) => false, Err(()) => false,
} }
} }
@ -378,8 +415,8 @@ unsafe extern "C" fn has_instance_hook(cx: *mut JSContext,
unsafe fn has_instance( unsafe fn has_instance(
cx: *mut JSContext, cx: *mut JSContext,
interface_object: HandleObject, interface_object: HandleObject,
value: HandleValue) value: HandleValue,
-> Result<bool, ()> { ) -> Result<bool, ()> {
if !value.is_object() { if !value.is_object() {
// Step 1. // Step 1.
return Ok(false); return Ok(false);
@ -391,8 +428,10 @@ unsafe fn has_instance(
let js_class = get_object_class(interface_object.get()); let js_class = get_object_class(interface_object.get());
let object_class = &*(js_class as *const NonCallbackInterfaceObjectClass); let object_class = &*(js_class as *const NonCallbackInterfaceObjectClass);
if let Ok(dom_class) = get_dom_class(UncheckedUnwrapObject(value.get(), if let Ok(dom_class) = get_dom_class(UncheckedUnwrapObject(
/* stopAtWindowProxy = */ 0)) { value.get(),
/* stopAtWindowProxy = */ 0,
)) {
if dom_class.interface_chain[object_class.proto_depth as usize] == object_class.proto_id { if dom_class.interface_chain[object_class.proto_depth as usize] == object_class.proto_id {
// Step 4. // Step 4.
return Ok(true); return Ok(true);
@ -424,7 +463,8 @@ unsafe fn has_instance(
unsafe fn create_unscopable_object( unsafe fn create_unscopable_object(
cx: *mut JSContext, cx: *mut JSContext,
names: &[&[u8]], names: &[&[u8]],
mut rval: MutableHandleObject) { mut rval: MutableHandleObject,
) {
assert!(!names.is_empty()); assert!(!names.is_empty());
assert!(rval.is_null()); assert!(rval.is_null());
rval.set(JS_NewPlainObject(cx)); rval.set(JS_NewPlainObject(cx));
@ -445,26 +485,30 @@ unsafe fn define_name(cx: *mut JSContext, obj: HandleObject, name: &[u8]) {
assert_eq!(*name.last().unwrap(), b'\0'); assert_eq!(*name.last().unwrap(), b'\0');
rooted!(in(cx) let name = JS_AtomizeAndPinString(cx, name.as_ptr() as *const libc::c_char)); rooted!(in(cx) let name = JS_AtomizeAndPinString(cx, name.as_ptr() as *const libc::c_char));
assert!(!name.is_null()); assert!(!name.is_null());
assert!(JS_DefineProperty3(cx, assert!(JS_DefineProperty3(
cx,
obj, obj,
b"name\0".as_ptr() as *const libc::c_char, b"name\0".as_ptr() as *const libc::c_char,
name.handle().into(), name.handle().into(),
JSPROP_READONLY as u32)); JSPROP_READONLY as u32
));
} }
unsafe fn define_length(cx: *mut JSContext, obj: HandleObject, length: i32) { unsafe fn define_length(cx: *mut JSContext, obj: HandleObject, length: i32) {
assert!(JS_DefineProperty4(cx, assert!(JS_DefineProperty4(
cx,
obj, obj,
b"length\0".as_ptr() as *const libc::c_char, b"length\0".as_ptr() as *const libc::c_char,
length, length,
JSPROP_READONLY as u32)); JSPROP_READONLY as u32
));
} }
unsafe extern "C" fn invalid_constructor( unsafe extern "C" fn invalid_constructor(
cx: *mut JSContext, cx: *mut JSContext,
_argc: libc::c_uint, _argc: libc::c_uint,
_vp: *mut JSVal) _vp: *mut JSVal,
-> bool { ) -> bool {
throw_type_error(cx, "Illegal constructor."); throw_type_error(cx, "Illegal constructor.");
false false
} }
@ -472,8 +516,8 @@ unsafe extern "C" fn invalid_constructor(
unsafe extern "C" fn non_new_constructor( unsafe extern "C" fn non_new_constructor(
cx: *mut JSContext, cx: *mut JSContext,
_argc: libc::c_uint, _argc: libc::c_uint,
_vp: *mut JSVal) _vp: *mut JSVal,
-> bool { ) -> bool {
throw_type_error(cx, "This constructor needs to be called with `new`."); throw_type_error(cx, "This constructor needs to be called with `new`.");
false false
} }

View file

@ -59,10 +59,11 @@ pub struct IterableIterator<T: DomObject + JSTraceable + Iterable> {
impl<T: DomObject + JSTraceable + Iterable> IterableIterator<T> { impl<T: DomObject + JSTraceable + Iterable> IterableIterator<T> {
/// Create a new iterator instance for the provided iterable DOM interface. /// Create a new iterator instance for the provided iterable DOM interface.
pub fn new(iterable: &T, pub fn new(
iterable: &T,
type_: IteratorType, type_: IteratorType,
wrap: unsafe fn(*mut JSContext, &GlobalScope, Box<IterableIterator<T>>) wrap: unsafe fn(*mut JSContext, &GlobalScope, Box<IterableIterator<T>>) -> DomRoot<Self>,
-> DomRoot<Self>) -> DomRoot<Self> { ) -> DomRoot<Self> {
let iterator = Box::new(IterableIterator { let iterator = Box::new(IterableIterator {
reflector: Reflector::new(), reflector: Reflector::new(),
type_: type_, type_: type_,
@ -84,37 +85,45 @@ impl<T: DomObject + JSTraceable + Iterable> IterableIterator<T> {
match self.type_ { match self.type_ {
IteratorType::Keys => { IteratorType::Keys => {
unsafe { unsafe {
self.iterable.get_key_at_index(index).to_jsval(cx, value.handle_mut()); self.iterable
.get_key_at_index(index)
.to_jsval(cx, value.handle_mut());
} }
dict_return(cx, rval.handle_mut(), false, value.handle()) dict_return(cx, rval.handle_mut(), false, value.handle())
} },
IteratorType::Values => { IteratorType::Values => {
unsafe { unsafe {
self.iterable.get_value_at_index(index).to_jsval(cx, value.handle_mut()); self.iterable
.get_value_at_index(index)
.to_jsval(cx, value.handle_mut());
} }
dict_return(cx, rval.handle_mut(), false, value.handle()) dict_return(cx, rval.handle_mut(), false, value.handle())
} },
IteratorType::Entries => { IteratorType::Entries => {
rooted!(in(cx) let mut key = UndefinedValue()); rooted!(in(cx) let mut key = UndefinedValue());
unsafe { unsafe {
self.iterable.get_key_at_index(index).to_jsval(cx, key.handle_mut()); self.iterable
self.iterable.get_value_at_index(index).to_jsval(cx, value.handle_mut()); .get_key_at_index(index)
.to_jsval(cx, key.handle_mut());
self.iterable
.get_value_at_index(index)
.to_jsval(cx, value.handle_mut());
} }
key_and_value_return(cx, rval.handle_mut(), key.handle(), value.handle()) key_and_value_return(cx, rval.handle_mut(), key.handle(), value.handle())
} },
} }
}; };
self.index.set(index + 1); self.index.set(index + 1);
result.map(|_| { result.map(|_| NonNull::new(rval.get()).expect("got a null pointer"))
NonNull::new(rval.get()).expect("got a null pointer")
})
} }
} }
fn dict_return(cx: *mut JSContext, fn dict_return(
cx: *mut JSContext,
mut result: MutableHandleObject, mut result: MutableHandleObject,
done: bool, done: bool,
value: HandleValue) -> Fallible<()> { value: HandleValue,
) -> Fallible<()> {
let mut dict = IterableKeyOrValueResult::empty(); let mut dict = IterableKeyOrValueResult::empty();
dict.done = done; dict.done = done;
dict.value.set(value.get()); dict.value.set(value.get());
@ -126,16 +135,20 @@ fn dict_return(cx: *mut JSContext,
Ok(()) Ok(())
} }
fn key_and_value_return(cx: *mut JSContext, fn key_and_value_return(
cx: *mut JSContext,
mut result: MutableHandleObject, mut result: MutableHandleObject,
key: HandleValue, key: HandleValue,
value: HandleValue) -> Fallible<()> { value: HandleValue,
) -> Fallible<()> {
let mut dict = IterableKeyAndValueResult::empty(); let mut dict = IterableKeyAndValueResult::empty();
dict.done = false; dict.done = false;
dict.value = Some(vec![key, value] dict.value = Some(
vec![key, value]
.into_iter() .into_iter()
.map(|handle| RootedTraceableBox::from_box(Heap::boxed(handle.get()))) .map(|handle| RootedTraceableBox::from_box(Heap::boxed(handle.get())))
.collect()); .collect(),
);
rooted!(in(cx) let mut dict_value = UndefinedValue()); rooted!(in(cx) let mut dict_value = UndefinedValue());
unsafe { unsafe {
dict.to_jsval(cx, dict_value.handle_mut()); dict.to_jsval(cx, dict_value.handle_mut());

View file

@ -49,24 +49,37 @@ impl<T> Deref for MozMap<T> {
} }
impl<T, C> FromJSValConvertible for MozMap<T> impl<T, C> FromJSValConvertible for MozMap<T>
where T: FromJSValConvertible<Config=C>, where
T: FromJSValConvertible<Config = C>,
C: Clone, C: Clone,
{ {
type Config = C; type Config = C;
unsafe fn from_jsval(cx: *mut JSContext, value: HandleValue, config: C) unsafe fn from_jsval(
-> Result<ConversionResult<Self>, ()> { cx: *mut JSContext,
value: HandleValue,
config: C,
) -> Result<ConversionResult<Self>, ()> {
if !value.is_object() { if !value.is_object() {
return Ok(ConversionResult::Failure("MozMap value was not an object".into())); return Ok(ConversionResult::Failure(
"MozMap value was not an object".into(),
));
} }
rooted!(in(cx) let object = value.to_object()); rooted!(in(cx) let object = value.to_object());
let ids = IdVector::new(cx); let ids = IdVector::new(cx);
if !GetPropertyKeys(cx, object.handle(), JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, ids.get()) { if !GetPropertyKeys(
cx,
object.handle(),
JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS,
ids.get(),
) {
// TODO: can GetPropertyKeys fail? // TODO: can GetPropertyKeys fail?
// (it does so if the object has duplicate keys) // (it does so if the object has duplicate keys)
// https://github.com/servo/servo/issues/21462 // https://github.com/servo/servo/issues/21462
report_pending_exception(cx, false); report_pending_exception(cx, false);
return Ok(ConversionResult::Failure("Getting MozMap value property keys failed".into())); return Ok(ConversionResult::Failure(
"Getting MozMap value property keys failed".into(),
));
} }
let mut map = HashMap::new(); let mut map = HashMap::new();
@ -90,9 +103,7 @@ impl<T, C> FromJSValConvertible for MozMap<T>
} }
} }
Ok(ConversionResult::Success(MozMap { Ok(ConversionResult::Success(MozMap { map: map }))
map: map,
}))
} }
} }
@ -107,12 +118,14 @@ impl<T: ToJSValConvertible> ToJSValConvertible for MozMap<T> {
let key = key.encode_utf16().collect::<Vec<_>>(); let key = key.encode_utf16().collect::<Vec<_>>();
value.to_jsval(cx, js_value.handle_mut()); value.to_jsval(cx, js_value.handle_mut());
assert!(JS_DefineUCProperty2(cx, assert!(JS_DefineUCProperty2(
cx,
js_object.handle(), js_object.handle(),
key.as_ptr(), key.as_ptr(),
key.len(), key.len(),
js_value.handle(), js_value.handle(),
JSPROP_ENUMERATE as u32)); JSPROP_ENUMERATE as u32
));
} }
rval.set(ObjectValue(js_object.handle().get())); rval.set(ObjectValue(js_object.handle().get()));

View file

@ -36,7 +36,8 @@ pub unsafe fn create_namespace_object(
class: &'static NamespaceObjectClass, class: &'static NamespaceObjectClass,
methods: &[Guard<&'static [JSFunctionSpec]>], methods: &[Guard<&'static [JSFunctionSpec]>],
name: &[u8], name: &[u8],
rval: MutableHandleObject) { rval: MutableHandleObject,
) {
create_object(cx, proto, &class.0, methods, &[], &[], rval); create_object(cx, proto, &class.0, methods, &[], &[], rval);
define_on_global_object(cx, global, name, rval.handle()); define_on_global_object(cx, global, name, rval.handle());
} }

View file

@ -26,8 +26,10 @@ impl<T: Float> Finite<T> {
/// Create a new `Finite<T: Float>`. /// Create a new `Finite<T: Float>`.
#[inline] #[inline]
pub fn wrap(value: T) -> Finite<T> { pub fn wrap(value: T) -> Finite<T> {
assert!(value.is_finite(), assert!(
"Finite<T> doesn't encapsulate unrestricted value."); value.is_finite(),
"Finite<T> doesn't encapsulate unrestricted value."
);
Finite(value) Finite(value)
} }
} }

View file

@ -30,12 +30,12 @@ use js::rust::wrappers::JS_AlreadyHasOwnPropertyById;
use js::rust::wrappers::JS_NewObjectWithGivenProto; use js::rust::wrappers::JS_NewObjectWithGivenProto;
use std::ptr; use std::ptr;
/// Determine if this id shadows any existing properties for this proxy. /// Determine if this id shadows any existing properties for this proxy.
pub unsafe extern "C" fn shadow_check_callback(cx: *mut JSContext, pub unsafe extern "C" fn shadow_check_callback(
cx: *mut JSContext,
object: RawHandleObject, object: RawHandleObject,
id: RawHandleId) id: RawHandleId,
-> DOMProxyShadowsResult { ) -> DOMProxyShadowsResult {
// TODO: support OverrideBuiltins when #12978 is fixed. // TODO: support OverrideBuiltins when #12978 is fixed.
rooted!(in(cx) let mut expando = ptr::null_mut::<JSObject>()); rooted!(in(cx) let mut expando = ptr::null_mut::<JSObject>());
@ -59,19 +59,19 @@ pub unsafe extern "C" fn shadow_check_callback(cx: *mut JSContext,
/// Initialize the infrastructure for DOM proxy objects. /// Initialize the infrastructure for DOM proxy objects.
pub unsafe fn init() { pub unsafe fn init() {
SetDOMProxyInformation(GetProxyHandlerFamily(), SetDOMProxyInformation(GetProxyHandlerFamily(), Some(shadow_check_callback));
Some(shadow_check_callback));
} }
/// Invoke the [[GetOwnProperty]] trap (`getOwnPropertyDescriptor`) on `proxy`, /// Invoke the [[GetOwnProperty]] trap (`getOwnPropertyDescriptor`) on `proxy`,
/// with argument `id` and return the result, if it is not `undefined`. /// with argument `id` and return the result, if it is not `undefined`.
/// Otherwise, walk along the prototype chain to find a property with that /// Otherwise, walk along the prototype chain to find a property with that
/// name. /// name.
pub unsafe extern "C" fn get_property_descriptor(cx: *mut JSContext, pub unsafe extern "C" fn get_property_descriptor(
cx: *mut JSContext,
proxy: RawHandleObject, proxy: RawHandleObject,
id: RawHandleId, id: RawHandleId,
desc: RawMutableHandle<PropertyDescriptor>) desc: RawMutableHandle<PropertyDescriptor>,
-> bool { ) -> bool {
let handler = GetProxyHandler(proxy.get()); let handler = GetProxyHandler(proxy.get());
if !InvokeGetOwnPropertyDescriptor(handler, cx, proxy, id, desc) { if !InvokeGetOwnPropertyDescriptor(handler, cx, proxy, id, desc) {
return false; return false;
@ -91,23 +91,25 @@ pub unsafe extern "C" fn get_property_descriptor(cx: *mut JSContext,
} }
/// Defines an expando on the given `proxy`. /// Defines an expando on the given `proxy`.
pub unsafe extern "C" fn define_property(cx: *mut JSContext, pub unsafe extern "C" fn define_property(
cx: *mut JSContext,
proxy: RawHandleObject, proxy: RawHandleObject,
id: RawHandleId, id: RawHandleId,
desc: RawHandle<PropertyDescriptor>, desc: RawHandle<PropertyDescriptor>,
result: *mut ObjectOpResult) result: *mut ObjectOpResult,
-> bool { ) -> bool {
rooted!(in(cx) let mut expando = ptr::null_mut::<JSObject>()); rooted!(in(cx) let mut expando = ptr::null_mut::<JSObject>());
ensure_expando_object(cx, proxy, expando.handle_mut()); ensure_expando_object(cx, proxy, expando.handle_mut());
JS_DefinePropertyById(cx, expando.handle().into(), id, desc, result) JS_DefinePropertyById(cx, expando.handle().into(), id, desc, result)
} }
/// Deletes an expando off the given `proxy`. /// Deletes an expando off the given `proxy`.
pub unsafe extern "C" fn delete(cx: *mut JSContext, pub unsafe extern "C" fn delete(
cx: *mut JSContext,
proxy: RawHandleObject, proxy: RawHandleObject,
id: RawHandleId, id: RawHandleId,
bp: *mut ObjectOpResult) bp: *mut ObjectOpResult,
-> bool { ) -> bool {
rooted!(in(cx) let mut expando = ptr::null_mut::<JSObject>()); rooted!(in(cx) let mut expando = ptr::null_mut::<JSObject>());
get_expando_object(proxy, expando.handle_mut()); get_expando_object(proxy, expando.handle_mut());
if expando.is_null() { if expando.is_null() {
@ -119,19 +121,21 @@ pub unsafe extern "C" fn delete(cx: *mut JSContext,
} }
/// Controls whether the Extensible bit can be changed /// Controls whether the Extensible bit can be changed
pub unsafe extern "C" fn prevent_extensions(_cx: *mut JSContext, pub unsafe extern "C" fn prevent_extensions(
_cx: *mut JSContext,
_proxy: RawHandleObject, _proxy: RawHandleObject,
result: *mut ObjectOpResult) result: *mut ObjectOpResult,
-> bool { ) -> bool {
(*result).code_ = JSErrNum::JSMSG_CANT_PREVENT_EXTENSIONS as ::libc::uintptr_t; (*result).code_ = JSErrNum::JSMSG_CANT_PREVENT_EXTENSIONS as ::libc::uintptr_t;
true true
} }
/// Reports whether the object is Extensible /// Reports whether the object is Extensible
pub unsafe extern "C" fn is_extensible(_cx: *mut JSContext, pub unsafe extern "C" fn is_extensible(
_cx: *mut JSContext,
_proxy: RawHandleObject, _proxy: RawHandleObject,
succeeded: *mut bool) succeeded: *mut bool,
-> bool { ) -> bool {
*succeeded = true; *succeeded = true;
true true
} }
@ -145,11 +149,12 @@ pub unsafe extern "C" fn is_extensible(_cx: *mut JSContext,
/// This implementation always handles the case of the ordinary /// This implementation always handles the case of the ordinary
/// `[[GetPrototypeOf]]` behavior. An alternative implementation will be /// `[[GetPrototypeOf]]` behavior. An alternative implementation will be
/// necessary for the Location object. /// necessary for the Location object.
pub unsafe extern "C" fn get_prototype_if_ordinary(_: *mut JSContext, pub unsafe extern "C" fn get_prototype_if_ordinary(
_: *mut JSContext,
proxy: RawHandleObject, proxy: RawHandleObject,
is_ordinary: *mut bool, is_ordinary: *mut bool,
proto: RawMutableHandleObject) proto: RawMutableHandleObject,
-> bool { ) -> bool {
*is_ordinary = true; *is_ordinary = true;
proto.set(GetStaticPrototype(proxy.get())); proto.set(GetStaticPrototype(proxy.get()));
true true
@ -169,11 +174,19 @@ pub unsafe fn get_expando_object(obj: RawHandleObject, mut expando: MutableHandl
/// Get the expando object, or create it if it doesn't exist yet. /// Get the expando object, or create it if it doesn't exist yet.
/// Fails on JSAPI failure. /// Fails on JSAPI failure.
pub unsafe fn ensure_expando_object(cx: *mut JSContext, obj: RawHandleObject, mut expando: MutableHandleObject) { pub unsafe fn ensure_expando_object(
cx: *mut JSContext,
obj: RawHandleObject,
mut expando: MutableHandleObject,
) {
assert!(is_dom_proxy(obj.get())); assert!(is_dom_proxy(obj.get()));
get_expando_object(obj, expando); get_expando_object(obj, expando);
if expando.is_null() { if expando.is_null() {
expando.set(JS_NewObjectWithGivenProto(cx, ptr::null_mut(), HandleObject::null())); expando.set(JS_NewObjectWithGivenProto(
cx,
ptr::null_mut(),
HandleObject::null(),
));
assert!(!expando.is_null()); assert!(!expando.is_null());
SetProxyPrivate(obj.get(), &ObjectValue(expando.get())); SetProxyPrivate(obj.get(), &ObjectValue(expando.get()));
@ -182,9 +195,11 @@ pub unsafe fn ensure_expando_object(cx: *mut JSContext, obj: RawHandleObject, mu
/// Set the property descriptor's object to `obj` and set it to enumerable, /// Set the property descriptor's object to `obj` and set it to enumerable,
/// and writable if `readonly` is true. /// and writable if `readonly` is true.
pub fn fill_property_descriptor(mut desc: MutableHandle<PropertyDescriptor>, pub fn fill_property_descriptor(
mut desc: MutableHandle<PropertyDescriptor>,
obj: *mut JSObject, obj: *mut JSObject,
attrs: u32) { attrs: u32,
) {
desc.obj = obj; desc.obj = obj;
desc.attrs = attrs; desc.attrs = attrs;
desc.getter = None; desc.getter = None;

View file

@ -39,9 +39,9 @@ use std::rc::Rc;
use std::sync::{Arc, Weak}; use std::sync::{Arc, Weak};
use task::TaskOnce; use task::TaskOnce;
#[allow(missing_docs)] // FIXME #[allow(missing_docs)] // FIXME
mod dummy { // Attributes dont apply through the macro. mod dummy {
// Attributes dont apply through the macro.
use std::cell::RefCell; use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
use super::LiveDOMReferences; use super::LiveDOMReferences;
@ -50,7 +50,6 @@ mod dummy { // Attributes dont apply through the macro.
} }
pub use self::dummy::LIVE_REFERENCES; pub use self::dummy::LIVE_REFERENCES;
/// A pointer to a Rust DOM object that needs to be destroyed. /// A pointer to a Rust DOM object that needs to be destroyed.
pub struct TrustedReference(*const libc::c_void); pub struct TrustedReference(*const libc::c_void);
unsafe impl Send for TrustedReference {} unsafe impl Send for TrustedReference {}
@ -98,19 +97,28 @@ impl TrustedPromise {
LIVE_REFERENCES.with(|ref r| { LIVE_REFERENCES.with(|ref r| {
let r = r.borrow(); let r = r.borrow();
let live_references = r.as_ref().unwrap(); let live_references = r.as_ref().unwrap();
assert_eq!(self.owner_thread, (&*live_references) as *const _ as *const libc::c_void); assert_eq!(
self.owner_thread,
(&*live_references) as *const _ as *const libc::c_void
);
// Borrow-check error requires the redundant `let promise = ...; promise` here. // Borrow-check error requires the redundant `let promise = ...; promise` here.
let promise = match live_references.promise_table.borrow_mut().entry(self.dom_object) { let promise = match live_references
.promise_table
.borrow_mut()
.entry(self.dom_object)
{
Occupied(mut entry) => { Occupied(mut entry) => {
let promise = { let promise = {
let promises = entry.get_mut(); let promises = entry.get_mut();
promises.pop().expect("rooted promise list unexpectedly empty") promises
.pop()
.expect("rooted promise list unexpectedly empty")
}; };
if entry.get().is_empty() { if entry.get().is_empty() {
entry.remove(); entry.remove();
} }
promise promise
} },
Vacant(_) => unreachable!(), Vacant(_) => unreachable!(),
}; };
promise promise
@ -182,9 +190,7 @@ impl<T: DomObject> Trusted<T> {
let live_references = r.as_ref().unwrap(); let live_references = r.as_ref().unwrap();
self.owner_thread == (&*live_references) as *const _ as *const libc::c_void self.owner_thread == (&*live_references) as *const _ as *const libc::c_void
})); }));
unsafe { unsafe { DomRoot::from_ref(&*(self.refcount.0 as *const T)) }
DomRoot::from_ref(&*(self.refcount.0 as *const T))
}
} }
} }
@ -246,15 +252,15 @@ impl LiveDOMReferences {
let refcount = Arc::new(TrustedReference::new(ptr)); let refcount = Arc::new(TrustedReference::new(ptr));
entry.insert(Arc::downgrade(&refcount)); entry.insert(Arc::downgrade(&refcount));
refcount refcount
} },
} }
} }
} }
/// Remove null entries from the live references table /// Remove null entries from the live references table
fn remove_nulls<K: Eq + Hash + Clone, V> (table: &mut HashMap<K, Weak<V>>) { fn remove_nulls<K: Eq + Hash + Clone, V>(table: &mut HashMap<K, Weak<V>>) {
let to_remove: Vec<K> = let to_remove: Vec<K> = table
table.iter() .iter()
.filter(|&(_, value)| Weak::upgrade(value).is_none()) .filter(|&(_, value)| Weak::upgrade(value).is_none())
.map(|(key, _)| key.clone()) .map(|(key, _)| key.clone())
.collect(); .collect();

View file

@ -16,14 +16,14 @@ use std::default::Default;
pub fn reflect_dom_object<T, U>( pub fn reflect_dom_object<T, U>(
obj: Box<T>, obj: Box<T>,
global: &U, global: &U,
wrap_fn: unsafe fn(*mut JSContext, &GlobalScope, Box<T>) -> DomRoot<T>) wrap_fn: unsafe fn(*mut JSContext, &GlobalScope, Box<T>) -> DomRoot<T>,
-> DomRoot<T> ) -> DomRoot<T>
where T: DomObject, U: DerivedFrom<GlobalScope> where
T: DomObject,
U: DerivedFrom<GlobalScope>,
{ {
let global_scope = global.upcast(); let global_scope = global.upcast();
unsafe { unsafe { wrap_fn(global_scope.get_cx(), global_scope, obj) }
wrap_fn(global_scope.get_cx(), global_scope, obj)
}
} }
/// A struct to store a reference to the reflector of a DOM object. /// A struct to store a reference to the reflector of a DOM object.
@ -79,7 +79,10 @@ pub trait DomObject: 'static {
fn reflector(&self) -> &Reflector; fn reflector(&self) -> &Reflector;
/// Returns the global scope of the realm that the DomObject was created in. /// Returns the global scope of the realm that the DomObject was created in.
fn global(&self) -> DomRoot<GlobalScope> where Self: Sized { fn global(&self) -> DomRoot<GlobalScope>
where
Self: Sized,
{
GlobalScope::from_reflector(self) GlobalScope::from_reflector(self)
} }
} }

View file

@ -96,9 +96,7 @@ where
trace_reflector(tracer, "on stack", &self.0); trace_reflector(tracer, "on stack", &self.0);
} }
} }
unsafe { unsafe { &*(self.reflector() as *const Reflector as *const ReflectorStackRoot) }
&*(self.reflector() as *const Reflector as *const ReflectorStackRoot)
}
} }
} }
@ -131,15 +129,17 @@ pub type DomRoot<T> = Root<Dom<T>>;
impl<T: Castable> DomRoot<T> { impl<T: Castable> DomRoot<T> {
/// Cast a DOM object root upwards to one of the interfaces it derives from. /// Cast a DOM object root upwards to one of the interfaces it derives from.
pub fn upcast<U>(root: DomRoot<T>) -> DomRoot<U> pub fn upcast<U>(root: DomRoot<T>) -> DomRoot<U>
where U: Castable, where
T: DerivedFrom<U> U: Castable,
T: DerivedFrom<U>,
{ {
unsafe { mem::transmute(root) } unsafe { mem::transmute(root) }
} }
/// Cast a DOM object root downwards to one of the interfaces it might implement. /// Cast a DOM object root downwards to one of the interfaces it might implement.
pub fn downcast<U>(root: DomRoot<T>) -> Option<DomRoot<U>> pub fn downcast<U>(root: DomRoot<T>) -> Option<DomRoot<U>>
where U: DerivedFrom<T> where
U: DerivedFrom<T>,
{ {
if root.is::<U>() { if root.is::<U>() {
Some(unsafe { mem::transmute(root) }) Some(unsafe { mem::transmute(root) })
@ -207,9 +207,7 @@ pub struct ThreadLocalStackRoots<'a>(PhantomData<&'a u32>);
impl<'a> ThreadLocalStackRoots<'a> { impl<'a> ThreadLocalStackRoots<'a> {
pub fn new(roots: &'a RootCollection) -> Self { pub fn new(roots: &'a RootCollection) -> Self {
STACK_ROOTS.with(|ref r| { STACK_ROOTS.with(|ref r| r.set(Some(roots)));
r.set(Some(roots))
});
ThreadLocalStackRoots(PhantomData) ThreadLocalStackRoots(PhantomData)
} }
} }
@ -363,9 +361,7 @@ unsafe impl<T: DomObject> JSTraceable for Dom<T> {
#[cfg(not(all(feature = "unstable", debug_assertions)))] #[cfg(not(all(feature = "unstable", debug_assertions)))]
let trace_info = "for DOM object on heap"; let trace_info = "for DOM object on heap";
trace_reflector(trc, trace_reflector(trc, trace_info, (*self.ptr.as_ptr()).reflector());
trace_info,
(*self.ptr.as_ptr()).reflector());
} }
} }
@ -379,8 +375,9 @@ pub struct LayoutDom<T> {
impl<T: Castable> LayoutDom<T> { impl<T: Castable> LayoutDom<T> {
/// Cast a DOM object root upwards to one of the interfaces it derives from. /// Cast a DOM object root upwards to one of the interfaces it derives from.
pub fn upcast<U>(&self) -> LayoutDom<U> pub fn upcast<U>(&self) -> LayoutDom<U>
where U: Castable, where
T: DerivedFrom<U> U: Castable,
T: DerivedFrom<U>,
{ {
debug_assert!(thread_state::get().is_layout()); debug_assert!(thread_state::get().is_layout());
let ptr: *mut T = self.ptr.as_ptr(); let ptr: *mut T = self.ptr.as_ptr();
@ -391,7 +388,8 @@ impl<T: Castable> LayoutDom<T> {
/// Cast a DOM object downwards to one of the interfaces it might implement. /// Cast a DOM object downwards to one of the interfaces it might implement.
pub fn downcast<U>(&self) -> Option<LayoutDom<U>> pub fn downcast<U>(&self) -> Option<LayoutDom<U>>
where U: DerivedFrom<T> where
U: DerivedFrom<T>,
{ {
debug_assert!(thread_state::get().is_layout()); debug_assert!(thread_state::get().is_layout());
unsafe { unsafe {
@ -429,7 +427,6 @@ impl<'a, T: DomObject> PartialEq<&'a T> for Dom<T> {
} }
} }
impl<T> Eq for Dom<T> {} impl<T> Eq for Dom<T> {}
impl<T> PartialEq for LayoutDom<T> { impl<T> PartialEq for LayoutDom<T> {
@ -452,7 +449,7 @@ impl<T> Hash for LayoutDom<T> {
} }
} }
impl <T> Clone for Dom<T> { impl<T> Clone for Dom<T> {
#[inline] #[inline]
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
fn clone(&self) -> Dom<T> { fn clone(&self) -> Dom<T> {
@ -463,7 +460,7 @@ impl <T> Clone for Dom<T> {
} }
} }
impl <T> Clone for LayoutDom<T> { impl<T> Clone for LayoutDom<T> {
#[inline] #[inline]
fn clone(&self) -> LayoutDom<T> { fn clone(&self) -> LayoutDom<T> {
debug_assert!(thread_state::get().is_layout()); debug_assert!(thread_state::get().is_layout());
@ -516,9 +513,7 @@ impl<T: DomObject> MutDom<T> {
/// Get the value in this `MutDom`. /// Get the value in this `MutDom`.
pub fn get(&self) -> DomRoot<T> { pub fn get(&self) -> DomRoot<T> {
debug_assert!(thread_state::get().is_script()); debug_assert!(thread_state::get().is_script());
unsafe { unsafe { DomRoot::from_ref(&*ptr::read(self.val.get())) }
DomRoot::from_ref(&*ptr::read(self.val.get()))
}
} }
} }
@ -531,17 +526,13 @@ impl<T: DomObject> MallocSizeOf for MutDom<T> {
impl<T: DomObject> PartialEq for MutDom<T> { impl<T: DomObject> PartialEq for MutDom<T> {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
unsafe { unsafe { *self.val.get() == *other.val.get() }
*self.val.get() == *other.val.get()
}
} }
} }
impl<T: DomObject + PartialEq> PartialEq<T> for MutDom<T> { impl<T: DomObject + PartialEq> PartialEq<T> for MutDom<T> {
fn eq(&self, other: &T) -> bool { fn eq(&self, other: &T) -> bool {
unsafe { unsafe { **self.val.get() == *other }
**self.val.get() == *other
}
} }
} }
@ -569,7 +560,8 @@ impl<T: DomObject> MutNullableDom<T> {
/// Retrieve a copy of the current inner value. If it is `None`, it is /// Retrieve a copy of the current inner value. If it is `None`, it is
/// initialized with the result of `cb` first. /// initialized with the result of `cb` first.
pub fn or_init<F>(&self, cb: F) -> DomRoot<T> pub fn or_init<F>(&self, cb: F) -> DomRoot<T>
where F: FnOnce() -> DomRoot<T> where
F: FnOnce() -> DomRoot<T>,
{ {
debug_assert!(thread_state::get().is_script()); debug_assert!(thread_state::get().is_script());
match self.get() { match self.get() {
@ -594,9 +586,7 @@ impl<T: DomObject> MutNullableDom<T> {
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
pub fn get(&self) -> Option<DomRoot<T>> { pub fn get(&self) -> Option<DomRoot<T>> {
debug_assert!(thread_state::get().is_script()); debug_assert!(thread_state::get().is_script());
unsafe { unsafe { ptr::read(self.ptr.get()).map(|o| DomRoot::from_ref(&*o)) }
ptr::read(self.ptr.get()).map(|o| DomRoot::from_ref(&*o))
}
} }
/// Set this `MutNullableDom` to the given value. /// Set this `MutNullableDom` to the given value.
@ -617,17 +607,13 @@ impl<T: DomObject> MutNullableDom<T> {
impl<T: DomObject> PartialEq for MutNullableDom<T> { impl<T: DomObject> PartialEq for MutNullableDom<T> {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
unsafe { unsafe { *self.ptr.get() == *other.ptr.get() }
*self.ptr.get() == *other.ptr.get()
}
} }
} }
impl<'a, T: DomObject> PartialEq<Option<&'a T>> for MutNullableDom<T> { impl<'a, T: DomObject> PartialEq<Option<&'a T>> for MutNullableDom<T> {
fn eq(&self, other: &Option<&T>) -> bool { fn eq(&self, other: &Option<&T>) -> bool {
unsafe { unsafe { *self.ptr.get() == other.map(Dom::from_ref) }
*self.ptr.get() == other.map(Dom::from_ref)
}
} }
} }
@ -661,13 +647,14 @@ pub struct DomOnceCell<T: DomObject> {
impl<T> DomOnceCell<T> impl<T> DomOnceCell<T>
where where
T: DomObject T: DomObject,
{ {
/// Retrieve a copy of the current inner value. If it is `None`, it is /// Retrieve a copy of the current inner value. If it is `None`, it is
/// initialized with the result of `cb` first. /// initialized with the result of `cb` first.
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
pub fn init_once<F>(&self, cb: F) -> &T pub fn init_once<F>(&self, cb: F) -> &T
where F: FnOnce() -> DomRoot<T> where
F: FnOnce() -> DomRoot<T>,
{ {
debug_assert!(thread_state::get().is_script()); debug_assert!(thread_state::get().is_script());
&self.ptr.init_once(|| Dom::from_ref(&cb())) &self.ptr.init_once(|| Dom::from_ref(&cb()))
@ -725,14 +712,17 @@ pub trait OptionalHeapSetter {
fn set(&mut self, v: Option<Self::Value>); fn set(&mut self, v: Option<Self::Value>);
} }
impl<T: GCMethods + Copy> OptionalHeapSetter for Option<Heap<T>> where Heap<T>: Default { impl<T: GCMethods + Copy> OptionalHeapSetter for Option<Heap<T>>
where
Heap<T>: Default,
{
type Value = T; type Value = T;
fn set(&mut self, v: Option<T>) { fn set(&mut self, v: Option<T>) {
let v = match v { let v = match v {
None => { None => {
*self = None; *self = None;
return; return;
} },
Some(v) => v, Some(v) => v,
}; };

View file

@ -36,9 +36,7 @@ pub unsafe fn trace(tracer: *mut JSTracer) {
} }
pub fn is_execution_stack_empty() -> bool { pub fn is_execution_stack_empty() -> bool {
STACK.with(|stack| { STACK.with(|stack| stack.borrow().is_empty())
stack.borrow().is_empty()
})
} }
/// RAII struct that pushes and pops entries from the script settings stack. /// RAII struct that pushes and pops entries from the script settings stack.
@ -69,9 +67,10 @@ impl Drop for AutoEntryScript {
STACK.with(|stack| { STACK.with(|stack| {
let mut stack = stack.borrow_mut(); let mut stack = stack.borrow_mut();
let entry = stack.pop().unwrap(); let entry = stack.pop().unwrap();
assert_eq!(&*entry.global as *const GlobalScope, assert_eq!(
&*self.global as *const GlobalScope, &*entry.global as *const GlobalScope, &*self.global as *const GlobalScope,
"Dropped AutoEntryScript out of order."); "Dropped AutoEntryScript out of order."
);
assert_eq!(entry.kind, StackEntryKind::Entry); assert_eq!(entry.kind, StackEntryKind::Entry);
trace!("Clean up after running script with {:p}", &*entry.global); trace!("Clean up after running script with {:p}", &*entry.global);
}); });
@ -87,8 +86,10 @@ impl Drop for AutoEntryScript {
/// ///
/// ["entry"]: https://html.spec.whatwg.org/multipage/#entry /// ["entry"]: https://html.spec.whatwg.org/multipage/#entry
pub fn entry_global() -> DomRoot<GlobalScope> { pub fn entry_global() -> DomRoot<GlobalScope> {
STACK.with(|stack| { STACK
stack.borrow() .with(|stack| {
stack
.borrow()
.iter() .iter()
.rev() .rev()
.find(|entry| entry.kind == StackEntryKind::Entry) .find(|entry| entry.kind == StackEntryKind::Entry)
@ -133,11 +134,15 @@ impl Drop for AutoIncumbentScript {
let mut stack = stack.borrow_mut(); let mut stack = stack.borrow_mut();
let entry = stack.pop().unwrap(); let entry = stack.pop().unwrap();
// Step 3. // Step 3.
assert_eq!(&*entry.global as *const GlobalScope as usize, assert_eq!(
self.global, &*entry.global as *const GlobalScope as usize, self.global,
"Dropped AutoIncumbentScript out of order."); "Dropped AutoIncumbentScript out of order."
);
assert_eq!(entry.kind, StackEntryKind::Incumbent); assert_eq!(entry.kind, StackEntryKind::Incumbent);
trace!("Clean up after running a callback with {:p}", &*entry.global); trace!(
"Clean up after running a callback with {:p}",
&*entry.global
);
}); });
unsafe { unsafe {
// Step 1-2. // Step 1-2.
@ -169,7 +174,8 @@ pub fn incumbent_global() -> Option<DomRoot<GlobalScope>> {
// Step 2: nothing from the JS engine. Let's use whatever's on the explicit stack. // Step 2: nothing from the JS engine. Let's use whatever's on the explicit stack.
STACK.with(|stack| { STACK.with(|stack| {
stack.borrow() stack
.borrow()
.last() .last()
.map(|entry| DomRoot::from_ref(&*entry.global)) .map(|entry| DomRoot::from_ref(&*entry.global))
}) })

View file

@ -82,7 +82,6 @@ impl ops::Deref for ByteString {
#[derive(Clone, Default, MallocSizeOf)] #[derive(Clone, Default, MallocSizeOf)]
pub struct USVString(pub String); pub struct USVString(pub String);
/// Returns whether `s` is a `token`, as defined by /// Returns whether `s` is a `token`, as defined by
/// [RFC 2616](http://tools.ietf.org/html/rfc2616#page-17). /// [RFC 2616](http://tools.ietf.org/html/rfc2616#page-17).
pub fn is_token(s: &[u8]) -> bool { pub fn is_token(s: &[u8]) -> bool {
@ -93,31 +92,14 @@ pub fn is_token(s: &[u8]) -> bool {
// http://tools.ietf.org/html/rfc2616#section-2.2 // http://tools.ietf.org/html/rfc2616#section-2.2
match x { match x {
0...31 | 127 => false, // CTLs 0...31 | 127 => false, // CTLs
40 | 40 | 41 | 60 | 62 | 64 | 44 | 59 | 58 | 92 | 34 | 47 | 91 | 93 | 63 | 61 | 123 |
41 | 125 | 32 => false, // separators
60 |
62 |
64 |
44 |
59 |
58 |
92 |
34 |
47 |
91 |
93 |
63 |
61 |
123 |
125 |
32 => false, // separators
x if x > 127 => false, // non-CHARs x if x > 127 => false, // non-CHARs
_ => true, _ => true,
} }
}) })
} }
/// A DOMString. /// A DOMString.
/// ///
/// This type corresponds to the [`DOMString`](idl) type in WebIDL. /// This type corresponds to the [`DOMString`](idl) type in WebIDL.
@ -196,14 +178,16 @@ impl DOMString {
/// Removes leading and trailing ASCII whitespaces according to /// Removes leading and trailing ASCII whitespaces according to
/// <https://infra.spec.whatwg.org/#strip-leading-and-trailing-ascii-whitespace>. /// <https://infra.spec.whatwg.org/#strip-leading-and-trailing-ascii-whitespace>.
pub fn strip_leading_and_trailing_ascii_whitespace(&mut self) { pub fn strip_leading_and_trailing_ascii_whitespace(&mut self) {
if self.0.len() == 0 { return; } if self.0.len() == 0 {
return;
}
let last_non_whitespace = match self.0.rfind(|ref c| !char::is_ascii_whitespace(c)) { let last_non_whitespace = match self.0.rfind(|ref c| !char::is_ascii_whitespace(c)) {
Some(idx) => idx + 1, Some(idx) => idx + 1,
None => { None => {
self.0.clear(); self.0.clear();
return; return;
} },
}; };
let first_non_whitespace = self.0.find(|ref c| !char::is_ascii_whitespace(c)).unwrap(); let first_non_whitespace = self.0.find(|ref c| !char::is_ascii_whitespace(c)).unwrap();
@ -231,17 +215,21 @@ impl DOMString {
Done, Done,
Error, Error,
} }
let next_state = |valid: bool, next: State| -> State { if valid { next } else { State::Error } }; let next_state = |valid: bool, next: State| -> State {
if valid {
next
} else {
State::Error
}
};
let state = self.chars().fold(State::HourHigh, |state, c| { let state = self.chars().fold(State::HourHigh, |state, c| {
match state { match state {
// Step 1 "HH" // Step 1 "HH"
State::HourHigh => { State::HourHigh => match c {
match c {
'0' | '1' => State::HourLow09, '0' | '1' => State::HourLow09,
'2' => State::HourLow03, '2' => State::HourLow03,
_ => State::Error, _ => State::Error,
}
}, },
State::HourLow09 => next_state(c.is_digit(10), State::MinuteColon), State::HourLow09 => next_state(c.is_digit(10), State::MinuteColon),
State::HourLow03 => next_state(c.is_digit(4), State::MinuteColon), State::HourLow03 => next_state(c.is_digit(4), State::MinuteColon),
@ -323,15 +311,21 @@ impl DOMString {
/// where date and time are both valid, and the time string must be as short as possible /// where date and time are both valid, and the time string must be as short as possible
/// https://html.spec.whatwg.org/multipage/#valid-normalised-local-date-and-time-string /// https://html.spec.whatwg.org/multipage/#valid-normalised-local-date-and-time-string
pub fn convert_valid_normalized_local_date_and_time_string(&mut self) -> Result<(), ()> { pub fn convert_valid_normalized_local_date_and_time_string(&mut self) -> Result<(), ()> {
let ((year, month, day), (hour, minute, second)) = parse_local_date_and_time_string(&*self.0)?; let ((year, month, day), (hour, minute, second)) =
parse_local_date_and_time_string(&*self.0)?;
if second == 0.0 { if second == 0.0 {
self.0 = format!("{:04}-{:02}-{:02}T{:02}:{:02}", year, month, day, hour, minute); self.0 = format!(
"{:04}-{:02}-{:02}T{:02}:{:02}",
year, month, day, hour, minute
);
} else { } else {
self.0 = format!("{:04}-{:02}-{:02}T{:02}:{:02}:{}", year, month, day, hour, minute, second); self.0 = format!(
"{:04}-{:02}-{:02}T{:02}:{:02}:{}",
year, month, day, hour, minute, second
);
} }
Ok(()) Ok(())
} }
} }
impl Borrow<str> for DOMString { impl Borrow<str> for DOMString {
@ -452,7 +446,10 @@ impl<'a> Into<CowRcStr<'a>> for DOMString {
} }
impl Extend<char> for DOMString { impl Extend<char> for DOMString {
fn extend<I>(&mut self, iterable: I) where I: IntoIterator<Item=char> { fn extend<I>(&mut self, iterable: I)
where
I: IntoIterator<Item = char>,
{
self.0.extend(iterable) self.0.extend(iterable)
} }
} }
@ -611,12 +608,12 @@ fn parse_time_component(value: &str) -> Result<(u32, u32, f32), ()> {
return Err(()); return Err(());
} }
}, },
None => {} None => {},
} }
second.parse::<f32>().map_err(|_| ())? second.parse::<f32>().map_err(|_| ())?
}, },
None => 0.0 None => 0.0,
}; };
// Step 8 // Step 8
@ -651,8 +648,8 @@ fn parse_local_date_and_time_string(value: &str) -> Result<((u32, u32, u32), (u
fn max_day_in_month(year_num: u32, month_num: u32) -> Result<u32, ()> { fn max_day_in_month(year_num: u32, month_num: u32) -> Result<u32, ()> {
match month_num { match month_num {
1|3|5|7|8|10|12 => Ok(31), 1 | 3 | 5 | 7 | 8 | 10 | 12 => Ok(31),
4|6|9|11 => Ok(30), 4 | 6 | 9 | 11 => Ok(30),
2 => { 2 => {
if is_leap_year(year_num) { if is_leap_year(year_num) {
Ok(29) Ok(29)
@ -660,7 +657,7 @@ fn max_day_in_month(year_num: u32, month_num: u32) -> Result<u32, ()> {
Ok(28) Ok(28)
} }
}, },
_ => Err(()) _ => Err(()),
} }
} }
@ -669,7 +666,7 @@ fn max_week_in_year(year: u32) -> u32 {
match Utc.ymd(year as i32, 1, 1).weekday() { match Utc.ymd(year as i32, 1, 1).weekday() {
Weekday::Thu => 53, Weekday::Thu => 53,
Weekday::Wed if is_leap_year(year) => 53, Weekday::Wed if is_leap_year(year) => 53,
_ => 52 _ => 52,
} }
} }
@ -681,14 +678,16 @@ fn is_leap_year(year: u32) -> bool {
/// https://html.spec.whatwg.org/multipage/#rules-for-parsing-floating-point-number-values /// https://html.spec.whatwg.org/multipage/#rules-for-parsing-floating-point-number-values
fn parse_floating_point_number(input: &str) -> Result<f64, ()> { fn parse_floating_point_number(input: &str) -> Result<f64, ()> {
match input.trim().parse::<f64>() { match input.trim().parse::<f64>() {
Ok(val) if !( Ok(val)
if !(
// A valid number is the same as what rust considers to be valid, // A valid number is the same as what rust considers to be valid,
// except for +1., NaN, and Infinity. // except for +1., NaN, and Infinity.
val.is_infinite() || val.is_nan() || input.ends_with(".") || input.starts_with("+") val.is_infinite() || val.is_nan() || input.ends_with(".") || input.starts_with("+")
) => { ) =>
{
// TODO(#19773): need consider `min`, `max`, `step`, when they are implemented // TODO(#19773): need consider `min`, `max`, `step`, when they are implemented
Ok(val.round()) Ok(val.round())
}, }
_ => Err(()) _ => Err(()),
} }
} }

View file

@ -47,34 +47,38 @@ enum StructuredCloneTags {
} }
#[cfg(target_pointer_width = "64")] #[cfg(target_pointer_width = "64")]
unsafe fn write_length(w: *mut JSStructuredCloneWriter, unsafe fn write_length(w: *mut JSStructuredCloneWriter, length: usize) {
length: usize) {
let high: u32 = (length >> 32) as u32; let high: u32 = (length >> 32) as u32;
let low: u32 = length as u32; let low: u32 = length as u32;
assert!(JS_WriteUint32Pair(w, high, low)); assert!(JS_WriteUint32Pair(w, high, low));
} }
#[cfg(target_pointer_width = "32")] #[cfg(target_pointer_width = "32")]
unsafe fn write_length(w: *mut JSStructuredCloneWriter, unsafe fn write_length(w: *mut JSStructuredCloneWriter, length: usize) {
length: usize) {
assert!(JS_WriteUint32Pair(w, length as u32, 0)); assert!(JS_WriteUint32Pair(w, length as u32, 0));
} }
#[cfg(target_pointer_width = "64")] #[cfg(target_pointer_width = "64")]
unsafe fn read_length(r: *mut JSStructuredCloneReader) unsafe fn read_length(r: *mut JSStructuredCloneReader) -> usize {
-> usize {
let mut high: u32 = 0; let mut high: u32 = 0;
let mut low: u32 = 0; let mut low: u32 = 0;
assert!(JS_ReadUint32Pair(r, &mut high as *mut u32, &mut low as *mut u32)); assert!(JS_ReadUint32Pair(
r,
&mut high as *mut u32,
&mut low as *mut u32
));
return (low << high) as usize; return (low << high) as usize;
} }
#[cfg(target_pointer_width = "32")] #[cfg(target_pointer_width = "32")]
unsafe fn read_length(r: *mut JSStructuredCloneReader) unsafe fn read_length(r: *mut JSStructuredCloneReader) -> usize {
-> usize {
let mut length: u32 = 0; let mut length: u32 = 0;
let mut zero: u32 = 0; let mut zero: u32 = 0;
assert!(JS_ReadUint32Pair(r, &mut length as *mut u32, &mut zero as *mut u32)); assert!(JS_ReadUint32Pair(
r,
&mut length as *mut u32,
&mut zero as *mut u32
));
return length as usize; return length as usize;
} }
@ -86,7 +90,11 @@ impl StructuredCloneWriter {
unsafe fn write_slice(&self, v: &[u8]) { unsafe fn write_slice(&self, v: &[u8]) {
let type_length = v.len(); let type_length = v.len();
write_length(self.w, type_length); write_length(self.w, type_length);
assert!(JS_WriteBytes(self.w, v.as_ptr() as *const raw::c_void, type_length)); assert!(JS_WriteBytes(
self.w,
v.as_ptr() as *const raw::c_void,
type_length
));
} }
unsafe fn write_str(&self, s: &str) { unsafe fn write_str(&self, s: &str) {
self.write_slice(s.as_bytes()); self.write_slice(s.as_bytes());
@ -101,7 +109,11 @@ impl StructuredCloneReader {
unsafe fn read_bytes(&self) -> Vec<u8> { unsafe fn read_bytes(&self) -> Vec<u8> {
let mut bytes = vec![0u8; read_length(self.r)]; let mut bytes = vec![0u8; read_length(self.r)];
let blob_length = bytes.len(); let blob_length = bytes.len();
assert!(JS_ReadBytes(self.r, bytes.as_mut_ptr() as *mut raw::c_void, blob_length)); assert!(JS_ReadBytes(
self.r,
bytes.as_mut_ptr() as *mut raw::c_void,
blob_length
));
return bytes; return bytes;
} }
unsafe fn read_str(&self) -> String { unsafe fn read_str(&self) -> String {
@ -110,87 +122,105 @@ impl StructuredCloneReader {
} }
} }
unsafe fn read_blob(cx: *mut JSContext, unsafe fn read_blob(
cx: *mut JSContext,
r: *mut JSStructuredCloneReader, r: *mut JSStructuredCloneReader,
sc_holder: &mut StructuredCloneHolder) sc_holder: &mut StructuredCloneHolder,
-> *mut JSObject { ) -> *mut JSObject {
let structured_reader = StructuredCloneReader { r: r }; let structured_reader = StructuredCloneReader { r: r };
let blob_buffer = structured_reader.read_bytes(); let blob_buffer = structured_reader.read_bytes();
let type_str = structured_reader.read_str(); let type_str = structured_reader.read_str();
let target_global = GlobalScope::from_context(cx); let target_global = GlobalScope::from_context(cx);
let blob = Blob::new(&target_global, BlobImpl::new_from_bytes(blob_buffer), type_str); let blob = Blob::new(
&target_global,
BlobImpl::new_from_bytes(blob_buffer),
type_str,
);
let js_object = blob.reflector().get_jsobject().get(); let js_object = blob.reflector().get_jsobject().get();
sc_holder.blob = Some(blob); sc_holder.blob = Some(blob);
js_object js_object
} }
unsafe fn write_blob(blob: DomRoot<Blob>, unsafe fn write_blob(blob: DomRoot<Blob>, w: *mut JSStructuredCloneWriter) -> Result<(), ()> {
w: *mut JSStructuredCloneWriter)
-> Result<(), ()> {
let structured_writer = StructuredCloneWriter { w: w }; let structured_writer = StructuredCloneWriter { w: w };
let blob_vec = blob.get_bytes()?; let blob_vec = blob.get_bytes()?;
assert!(JS_WriteUint32Pair(w, StructuredCloneTags::DomBlob as u32, 0)); assert!(JS_WriteUint32Pair(
w,
StructuredCloneTags::DomBlob as u32,
0
));
structured_writer.write_slice(&blob_vec); structured_writer.write_slice(&blob_vec);
structured_writer.write_str(&blob.type_string()); structured_writer.write_str(&blob.type_string());
return Ok(()) return Ok(());
} }
unsafe extern "C" fn read_callback(cx: *mut JSContext, unsafe extern "C" fn read_callback(
cx: *mut JSContext,
r: *mut JSStructuredCloneReader, r: *mut JSStructuredCloneReader,
tag: u32, tag: u32,
_data: u32, _data: u32,
closure: *mut raw::c_void) closure: *mut raw::c_void,
-> *mut JSObject { ) -> *mut JSObject {
assert!(tag < StructuredCloneTags::Max as u32, "tag should be lower than StructuredCloneTags::Max"); assert!(
assert!(tag > StructuredCloneTags::Min as u32, "tag should be higher than StructuredCloneTags::Min"); tag < StructuredCloneTags::Max as u32,
"tag should be lower than StructuredCloneTags::Max"
);
assert!(
tag > StructuredCloneTags::Min as u32,
"tag should be higher than StructuredCloneTags::Min"
);
if tag == StructuredCloneTags::DomBlob as u32 { if tag == StructuredCloneTags::DomBlob as u32 {
return read_blob(cx, r, &mut *(closure as *mut StructuredCloneHolder)) return read_blob(cx, r, &mut *(closure as *mut StructuredCloneHolder));
} }
return ptr::null_mut() return ptr::null_mut();
} }
unsafe extern "C" fn write_callback(_cx: *mut JSContext, unsafe extern "C" fn write_callback(
_cx: *mut JSContext,
w: *mut JSStructuredCloneWriter, w: *mut JSStructuredCloneWriter,
obj: RawHandleObject, obj: RawHandleObject,
_closure: *mut raw::c_void) _closure: *mut raw::c_void,
-> bool { ) -> bool {
if let Ok(blob) = root_from_handleobject::<Blob>(Handle::from_raw(obj)) { if let Ok(blob) = root_from_handleobject::<Blob>(Handle::from_raw(obj)) {
return write_blob(blob, w).is_ok() return write_blob(blob, w).is_ok();
} }
return false return false;
} }
unsafe extern "C" fn read_transfer_callback(_cx: *mut JSContext, unsafe extern "C" fn read_transfer_callback(
_cx: *mut JSContext,
_r: *mut JSStructuredCloneReader, _r: *mut JSStructuredCloneReader,
_tag: u32, _tag: u32,
_content: *mut raw::c_void, _content: *mut raw::c_void,
_extra_data: u64, _extra_data: u64,
_closure: *mut raw::c_void, _closure: *mut raw::c_void,
_return_object: RawMutableHandleObject) _return_object: RawMutableHandleObject,
-> bool { ) -> bool {
false false
} }
unsafe extern "C" fn write_transfer_callback(_cx: *mut JSContext, unsafe extern "C" fn write_transfer_callback(
_cx: *mut JSContext,
_obj: RawHandleObject, _obj: RawHandleObject,
_closure: *mut raw::c_void, _closure: *mut raw::c_void,
_tag: *mut u32, _tag: *mut u32,
_ownership: *mut TransferableOwnership, _ownership: *mut TransferableOwnership,
_content: *mut *mut raw::c_void, _content: *mut *mut raw::c_void,
_extra_data: *mut u64) _extra_data: *mut u64,
-> bool { ) -> bool {
false false
} }
unsafe extern "C" fn free_transfer_callback(_tag: u32, unsafe extern "C" fn free_transfer_callback(
_tag: u32,
_ownership: TransferableOwnership, _ownership: TransferableOwnership,
_content: *mut raw::c_void, _content: *mut raw::c_void,
_extra_data: u64, _extra_data: u64,
_closure: *mut raw::c_void) { _closure: *mut raw::c_void,
) {
} }
unsafe extern "C" fn report_error_callback(_cx: *mut JSContext, _errorid: u32) { unsafe extern "C" fn report_error_callback(_cx: *mut JSContext, _errorid: u32) {}
}
static STRUCTURED_CLONE_CALLBACKS: JSStructuredCloneCallbacks = JSStructuredCloneCallbacks { static STRUCTURED_CLONE_CALLBACKS: JSStructuredCloneCallbacks = JSStructuredCloneCallbacks {
read: Some(read_callback), read: Some(read_callback),
@ -202,7 +232,7 @@ static STRUCTURED_CLONE_CALLBACKS: JSStructuredCloneCallbacks = JSStructuredClon
}; };
struct StructuredCloneHolder { struct StructuredCloneHolder {
blob: Option<DomRoot<Blob>> blob: Option<DomRoot<Blob>>,
} }
/// A buffer for a structured clone. /// A buffer for a structured clone.
@ -210,7 +240,7 @@ pub enum StructuredCloneData {
/// A non-serializable (default) variant /// A non-serializable (default) variant
Struct(*mut u64, size_t), Struct(*mut u64, size_t),
/// A variant that can be serialized /// A variant that can be serialized
Vector(Vec<u8>) Vector(Vec<u8>),
} }
impl StructuredCloneData { impl StructuredCloneData {
@ -218,21 +248,25 @@ impl StructuredCloneData {
/// Writes a structured clone. Returns a `DataClone` error if that fails. /// Writes a structured clone. Returns a `DataClone` error if that fails.
pub fn write(cx: *mut JSContext, message: HandleValue) -> Fallible<StructuredCloneData> { pub fn write(cx: *mut JSContext, message: HandleValue) -> Fallible<StructuredCloneData> {
unsafe { unsafe {
let scbuf = NewJSAutoStructuredCloneBuffer(StructuredCloneScope::DifferentProcess, let scbuf = NewJSAutoStructuredCloneBuffer(
&STRUCTURED_CLONE_CALLBACKS); StructuredCloneScope::DifferentProcess,
&STRUCTURED_CLONE_CALLBACKS,
);
let scdata = &mut ((*scbuf).data_); let scdata = &mut ((*scbuf).data_);
let policy = CloneDataPolicy { let policy = CloneDataPolicy {
// TODO: SAB? // TODO: SAB?
sharedArrayBuffer_: false, sharedArrayBuffer_: false,
}; };
let result = JS_WriteStructuredClone(cx, let result = JS_WriteStructuredClone(
cx,
message, message,
scdata, scdata,
StructuredCloneScope::DifferentProcess, StructuredCloneScope::DifferentProcess,
policy, policy,
&STRUCTURED_CLONE_CALLBACKS, &STRUCTURED_CLONE_CALLBACKS,
ptr::null_mut(), ptr::null_mut(),
HandleValue::undefined()); HandleValue::undefined(),
);
if !result { if !result {
JS_ClearPendingException(cx); JS_ClearPendingException(cx);
return Err(Error::DataClone); return Err(Error::DataClone);
@ -252,41 +286,40 @@ impl StructuredCloneData {
/// Converts a StructuredCloneData to Vec<u8> for inter-thread sharing /// Converts a StructuredCloneData to Vec<u8> for inter-thread sharing
pub fn move_to_arraybuffer(self) -> Vec<u8> { pub fn move_to_arraybuffer(self) -> Vec<u8> {
match self { match self {
StructuredCloneData::Struct(data, nbytes) => { StructuredCloneData::Struct(data, nbytes) => unsafe {
unsafe {
slice::from_raw_parts(data as *mut u8, nbytes).to_vec() slice::from_raw_parts(data as *mut u8, nbytes).to_vec()
} },
} StructuredCloneData::Vector(msg) => msg,
StructuredCloneData::Vector(msg) => msg
} }
} }
/// Reads a structured clone. /// Reads a structured clone.
/// ///
/// Panics if `JS_ReadStructuredClone` fails. /// Panics if `JS_ReadStructuredClone` fails.
fn read_clone(global: &GlobalScope, fn read_clone(global: &GlobalScope, data: *mut u64, nbytes: size_t, rval: MutableHandleValue) {
data: *mut u64,
nbytes: size_t,
rval: MutableHandleValue) {
let cx = global.get_cx(); let cx = global.get_cx();
let globalhandle = global.reflector().get_jsobject(); let globalhandle = global.reflector().get_jsobject();
let _ac = JSAutoCompartment::new(cx, globalhandle.get()); let _ac = JSAutoCompartment::new(cx, globalhandle.get());
let mut sc_holder = StructuredCloneHolder { blob: None }; let mut sc_holder = StructuredCloneHolder { blob: None };
let sc_holder_ptr = &mut sc_holder as *mut _; let sc_holder_ptr = &mut sc_holder as *mut _;
unsafe { unsafe {
let scbuf = NewJSAutoStructuredCloneBuffer(StructuredCloneScope::DifferentProcess, let scbuf = NewJSAutoStructuredCloneBuffer(
&STRUCTURED_CLONE_CALLBACKS); StructuredCloneScope::DifferentProcess,
&STRUCTURED_CLONE_CALLBACKS,
);
let scdata = &mut ((*scbuf).data_); let scdata = &mut ((*scbuf).data_);
WriteBytesToJSStructuredCloneData(data as *const u8, nbytes, scdata); WriteBytesToJSStructuredCloneData(data as *const u8, nbytes, scdata);
assert!(JS_ReadStructuredClone(cx, assert!(JS_ReadStructuredClone(
cx,
scdata, scdata,
JS_STRUCTURED_CLONE_VERSION, JS_STRUCTURED_CLONE_VERSION,
StructuredCloneScope::DifferentProcess, StructuredCloneScope::DifferentProcess,
rval, rval,
&STRUCTURED_CLONE_CALLBACKS, &STRUCTURED_CLONE_CALLBACKS,
sc_holder_ptr as *mut raw::c_void)); sc_holder_ptr as *mut raw::c_void
));
DeleteJSAutoStructuredCloneBuffer(scbuf); DeleteJSAutoStructuredCloneBuffer(scbuf);
} }
@ -299,8 +332,10 @@ impl StructuredCloneData {
let nbytes = vec_msg.len(); let nbytes = vec_msg.len();
let data = vec_msg.as_mut_ptr() as *mut u64; let data = vec_msg.as_mut_ptr() as *mut u64;
StructuredCloneData::read_clone(global, data, nbytes, rval); StructuredCloneData::read_clone(global, data, nbytes, rval);
} },
StructuredCloneData::Struct(data, nbytes) => StructuredCloneData::read_clone(global, data, nbytes, rval) StructuredCloneData::Struct(data, nbytes) => {
StructuredCloneData::read_clone(global, data, nbytes, rval)
},
} }
} }
} }

View file

@ -149,9 +149,11 @@ pub fn trace_jsval(tracer: *mut JSTracer, description: &str, val: &Heap<JSVal>)
} }
trace!("tracing value {}", description); trace!("tracing value {}", description);
CallValueTracer(tracer, CallValueTracer(
tracer,
val.ptr.get() as *mut _, val.ptr.get() as *mut _,
GCTraceKindToAscii(val.get().trace_kind())); GCTraceKindToAscii(val.get().trace_kind()),
);
} }
} }
@ -166,9 +168,11 @@ pub fn trace_reflector(tracer: *mut JSTracer, description: &str, reflector: &Ref
pub fn trace_object(tracer: *mut JSTracer, description: &str, obj: &Heap<*mut JSObject>) { pub fn trace_object(tracer: *mut JSTracer, description: &str, obj: &Heap<*mut JSObject>) {
unsafe { unsafe {
trace!("tracing {}", description); trace!("tracing {}", description);
CallObjectTracer(tracer, CallObjectTracer(
tracer,
obj.ptr.get() as *mut _, obj.ptr.get() as *mut _,
GCTraceKindToAscii(TraceKind::Object)); GCTraceKindToAscii(TraceKind::Object),
);
} }
} }
@ -295,7 +299,8 @@ unsafe impl<T: JSTraceable, U: JSTraceable> JSTraceable for Result<T, U> {
} }
unsafe impl<K, V, S> JSTraceable for HashMap<K, V, S> unsafe impl<K, V, S> JSTraceable for HashMap<K, V, S>
where K: Hash + Eq + JSTraceable, where
K: Hash + Eq + JSTraceable,
V: JSTraceable, V: JSTraceable,
S: BuildHasher, S: BuildHasher,
{ {
@ -309,7 +314,8 @@ unsafe impl<K, V, S> JSTraceable for HashMap<K, V, S>
} }
unsafe impl<T, S> JSTraceable for HashSet<T, S> unsafe impl<T, S> JSTraceable for HashSet<T, S>
where T: Hash + Eq + JSTraceable, where
T: Hash + Eq + JSTraceable,
S: BuildHasher, S: BuildHasher,
{ {
#[inline] #[inline]
@ -365,7 +371,12 @@ unsafe_no_jsmanaged_fields!(PropertyDeclarationBlock);
// These three are interdependent, if you plan to put jsmanaged data // These three are interdependent, if you plan to put jsmanaged data
// in one of these make sure it is propagated properly to containing structs // in one of these make sure it is propagated properly to containing structs
unsafe_no_jsmanaged_fields!(DocumentActivity, WindowSizeData, WindowSizeType); unsafe_no_jsmanaged_fields!(DocumentActivity, WindowSizeData, WindowSizeType);
unsafe_no_jsmanaged_fields!(BrowsingContextId, HistoryStateId, PipelineId, TopLevelBrowsingContextId); unsafe_no_jsmanaged_fields!(
BrowsingContextId,
HistoryStateId,
PipelineId,
TopLevelBrowsingContextId
);
unsafe_no_jsmanaged_fields!(TimerEventId, TimerSource); unsafe_no_jsmanaged_fields!(TimerEventId, TimerSource);
unsafe_no_jsmanaged_fields!(TimelineMarkerType); unsafe_no_jsmanaged_fields!(TimelineMarkerType);
unsafe_no_jsmanaged_fields!(WorkerId); unsafe_no_jsmanaged_fields!(WorkerId);
@ -459,7 +470,10 @@ unsafe impl<'a, A, B> JSTraceable for fn(&A) -> B {
} }
} }
unsafe impl<T> JSTraceable for IpcSender<T> where T: for<'de> Deserialize<'de> + Serialize { unsafe impl<T> JSTraceable for IpcSender<T>
where
T: for<'de> Deserialize<'de> + Serialize,
{
#[inline] #[inline]
unsafe fn trace(&self, _: *mut JSTracer) { unsafe fn trace(&self, _: *mut JSTracer) {
// Do nothing // Do nothing
@ -481,7 +495,10 @@ unsafe impl JSTraceable for () {
} }
} }
unsafe impl<T> JSTraceable for IpcReceiver<T> where T: for<'de> Deserialize<'de> + Serialize { unsafe impl<T> JSTraceable for IpcReceiver<T>
where
T: for<'de> Deserialize<'de> + Serialize,
{
#[inline] #[inline]
unsafe fn trace(&self, _: *mut JSTracer) { unsafe fn trace(&self, _: *mut JSTracer) {
// Do nothing // Do nothing
@ -509,14 +526,20 @@ unsafe impl<T: Send> JSTraceable for Sender<T> {
} }
} }
unsafe impl<T: Send> JSTraceable for WebGLReceiver<T> where T: for<'de> Deserialize<'de> + Serialize { unsafe impl<T: Send> JSTraceable for WebGLReceiver<T>
where
T: for<'de> Deserialize<'de> + Serialize,
{
#[inline] #[inline]
unsafe fn trace(&self, _: *mut JSTracer) { unsafe fn trace(&self, _: *mut JSTracer) {
// Do nothing // Do nothing
} }
} }
unsafe impl<T: Send> JSTraceable for WebGLSender<T> where T: for<'de> Deserialize<'de> + Serialize { unsafe impl<T: Send> JSTraceable for WebGLSender<T>
where
T: for<'de> Deserialize<'de> + Serialize,
{
#[inline] #[inline]
unsafe fn trace(&self, _: *mut JSTracer) { unsafe fn trace(&self, _: *mut JSTracer) {
// Do nothing // Do nothing
@ -665,7 +688,10 @@ unsafe impl JSTraceable for StyleLocked<MediaList> {
} }
} }
unsafe impl<T> JSTraceable for TypedArray<T, Box<Heap<*mut JSObject>>> where T: TypedArrayElement { unsafe impl<T> JSTraceable for TypedArray<T, Box<Heap<*mut JSObject>>>
where
T: TypedArrayElement,
{
unsafe fn trace(&self, trc: *mut JSTracer) { unsafe fn trace(&self, trc: *mut JSTracer) {
self.underlying_object().trace(trc); self.underlying_object().trace(trc);
} }
@ -682,31 +708,23 @@ where
} }
} }
/// Holds a set of JSTraceables that need to be rooted /// Holds a set of JSTraceables that need to be rooted
struct RootedTraceableSet { struct RootedTraceableSet {
set: Vec<*const JSTraceable>, set: Vec<*const JSTraceable>,
} }
thread_local!( thread_local!(/// TLV Holds a set of JSTraceables that need to be rooted
/// TLV Holds a set of JSTraceables that need to be rooted static ROOTED_TRACEABLES: RefCell<RootedTraceableSet> = RefCell::new(RootedTraceableSet::new()););
static ROOTED_TRACEABLES: RefCell<RootedTraceableSet> =
RefCell::new(RootedTraceableSet::new());
);
impl RootedTraceableSet { impl RootedTraceableSet {
fn new() -> RootedTraceableSet { fn new() -> RootedTraceableSet {
RootedTraceableSet { RootedTraceableSet { set: vec![] }
set: vec![],
}
} }
unsafe fn remove(traceable: *const JSTraceable) { unsafe fn remove(traceable: *const JSTraceable) {
ROOTED_TRACEABLES.with(|ref traceables| { ROOTED_TRACEABLES.with(|ref traceables| {
let mut traceables = traceables.borrow_mut(); let mut traceables = traceables.borrow_mut();
let idx = let idx = match traceables.set.iter().rposition(|x| *x == traceable) {
match traceables.set.iter()
.rposition(|x| *x == traceable) {
Some(idx) => idx, Some(idx) => idx,
None => unreachable!(), None => unreachable!(),
}; };
@ -744,9 +762,7 @@ impl<'a, T: JSTraceable + 'static> RootedTraceable<'a, T> {
unsafe { unsafe {
RootedTraceableSet::add(traceable); RootedTraceableSet::add(traceable);
} }
RootedTraceable { RootedTraceable { ptr: traceable }
ptr: traceable,
}
} }
} }
@ -787,14 +803,12 @@ impl<T: JSTraceable + 'static> RootedTraceableBox<T> {
unsafe { unsafe {
RootedTraceableSet::add(traceable); RootedTraceableSet::add(traceable);
} }
RootedTraceableBox { RootedTraceableBox { ptr: traceable }
ptr: traceable,
}
} }
} }
impl<T> RootedTraceableBox<Heap<T>> impl<T> RootedTraceableBox<Heap<T>>
where where
Heap<T>: JSTraceable + 'static, Heap<T>: JSTraceable + 'static,
T: GCMethods + Copy, T: GCMethods + Copy,
{ {
@ -812,17 +826,13 @@ impl<T: JSTraceable + Default> Default for RootedTraceableBox<T> {
impl<T: JSTraceable> Deref for RootedTraceableBox<T> { impl<T: JSTraceable> Deref for RootedTraceableBox<T> {
type Target = T; type Target = T;
fn deref(&self) -> &T { fn deref(&self) -> &T {
unsafe { unsafe { &*self.ptr }
&*self.ptr
}
} }
} }
impl<T: JSTraceable> DerefMut for RootedTraceableBox<T> { impl<T: JSTraceable> DerefMut for RootedTraceableBox<T> {
fn deref_mut(&mut self) -> &mut T { fn deref_mut(&mut self) -> &mut T {
unsafe { unsafe { &mut *self.ptr }
&mut *self.ptr
}
} }
} }
@ -849,9 +859,7 @@ pub struct RootableVec<T: JSTraceable> {
impl<T: JSTraceable> RootableVec<T> { impl<T: JSTraceable> RootableVec<T> {
/// Create a vector of items of type T that can be rooted later. /// Create a vector of items of type T that can be rooted later.
pub fn new_unrooted() -> RootableVec<T> { pub fn new_unrooted() -> RootableVec<T> {
RootableVec { RootableVec { v: vec![] }
v: vec![],
}
} }
} }
@ -868,9 +876,7 @@ impl<'a, T: 'static + JSTraceable> RootedVec<'a, T> {
unsafe { unsafe {
RootedTraceableSet::add(root); RootedTraceableSet::add(root);
} }
RootedVec { RootedVec { root: root }
root: root,
}
} }
} }
@ -878,15 +884,14 @@ impl<'a, T: 'static + JSTraceable + DomObject> RootedVec<'a, Dom<T>> {
/// Create a vector of items of type Dom<T> that is rooted for /// Create a vector of items of type Dom<T> that is rooted for
/// the lifetime of this struct /// the lifetime of this struct
pub fn from_iter<I>(root: &'a mut RootableVec<Dom<T>>, iter: I) -> Self pub fn from_iter<I>(root: &'a mut RootableVec<Dom<T>>, iter: I) -> Self
where I: Iterator<Item = DomRoot<T>> where
I: Iterator<Item = DomRoot<T>>,
{ {
unsafe { unsafe {
RootedTraceableSet::add(root); RootedTraceableSet::add(root);
} }
root.v.extend(iter.map(|item| Dom::from_ref(&*item))); root.v.extend(iter.map(|item| Dom::from_ref(&*item)));
RootedVec { RootedVec { root: root }
root: root,
}
} }
} }

View file

@ -85,7 +85,6 @@ pub const DOM_PROTOTYPE_SLOT: u32 = js::JSCLASS_GLOBAL_SLOT_COUNT;
// changes. // changes.
pub const JSCLASS_DOM_GLOBAL: u32 = js::JSCLASS_USERBIT1; pub const JSCLASS_DOM_GLOBAL: u32 = js::JSCLASS_USERBIT1;
/// The struct that holds inheritance information for DOM object reflectors. /// The struct that holds inheritance information for DOM object reflectors.
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub struct DOMClass { pub struct DOMClass {
@ -137,13 +136,14 @@ pub type ProtoOrIfaceArray = [*mut JSObject; PROTO_OR_IFACE_LENGTH];
/// set to true and `*vp` to the value, otherwise `*found` is set to false. /// set to true and `*vp` to the value, otherwise `*found` is set to false.
/// ///
/// Returns false on JSAPI failure. /// Returns false on JSAPI failure.
pub unsafe fn get_property_on_prototype(cx: *mut JSContext, pub unsafe fn get_property_on_prototype(
cx: *mut JSContext,
proxy: HandleObject, proxy: HandleObject,
receiver: HandleValue, receiver: HandleValue,
id: HandleId, id: HandleId,
found: *mut bool, found: *mut bool,
vp: MutableHandleValue) vp: MutableHandleValue,
-> bool { ) -> bool {
rooted!(in(cx) let mut proto = ptr::null_mut::<JSObject>()); rooted!(in(cx) let mut proto = ptr::null_mut::<JSObject>());
if !JS_GetPrototype(cx, proxy, proto.handle_mut()) || proto.is_null() { if !JS_GetPrototype(cx, proxy, proto.handle_mut()) || proto.is_null() {
*found = false; *found = false;
@ -184,23 +184,29 @@ pub fn get_array_index_from_id(_cx: *mut JSContext, id: HandleId) -> Option<u32>
return if StringIsArray(str, &mut i) != 0 { i } else { -1 } return if StringIsArray(str, &mut i) != 0 { i } else { -1 }
} else { } else {
IdToInt32(cx, id); IdToInt32(cx, id);
}*/ }*/}
}
/// Find the enum equivelent of a string given by `v` in `pairs`. /// Find the enum equivelent of a string given by `v` in `pairs`.
/// Returns `Err(())` on JSAPI failure (there is a pending exception), and /// Returns `Err(())` on JSAPI failure (there is a pending exception), and
/// `Ok((None, value))` if there was no matching string. /// `Ok((None, value))` if there was no matching string.
pub unsafe fn find_enum_value<'a, T>(cx: *mut JSContext, pub unsafe fn find_enum_value<'a, T>(
cx: *mut JSContext,
v: HandleValue, v: HandleValue,
pairs: &'a [(&'static str, T)]) pairs: &'a [(&'static str, T)],
-> Result<(Option<&'a T>, DOMString), ()> { ) -> Result<(Option<&'a T>, DOMString), ()> {
let jsstr = ToString(cx, v); let jsstr = ToString(cx, v);
if jsstr.is_null() { if jsstr.is_null() {
return Err(()); return Err(());
} }
let search = jsstring_to_str(cx, jsstr); let search = jsstring_to_str(cx, jsstr);
Ok((pairs.iter().find(|&&(key, _)| search == *key).map(|&(_, ref ev)| ev), search)) Ok((
pairs
.iter()
.find(|&&(key, _)| search == *key)
.map(|&(_, ref ev)| ev),
search,
))
} }
/// Returns wether `obj` is a platform object /// Returns wether `obj` is a platform object
@ -228,23 +234,26 @@ pub fn is_platform_object(obj: *mut JSObject) -> bool {
/// Get the property with name `property` from `object`. /// Get the property with name `property` from `object`.
/// Returns `Err(())` on JSAPI failure (there is a pending exception), and /// Returns `Err(())` on JSAPI failure (there is a pending exception), and
/// `Ok(false)` if there was no property with the given name. /// `Ok(false)` if there was no property with the given name.
pub fn get_dictionary_property(cx: *mut JSContext, pub fn get_dictionary_property(
cx: *mut JSContext,
object: HandleObject, object: HandleObject,
property: &str, property: &str,
rval: MutableHandleValue) rval: MutableHandleValue,
-> Result<bool, ()> { ) -> Result<bool, ()> {
fn has_property(cx: *mut JSContext, fn has_property(
cx: *mut JSContext,
object: HandleObject, object: HandleObject,
property: &CString, property: &CString,
found: &mut bool) found: &mut bool,
-> bool { ) -> bool {
unsafe { JS_HasProperty(cx, object, property.as_ptr(), found) } unsafe { JS_HasProperty(cx, object, property.as_ptr(), found) }
} }
fn get_property(cx: *mut JSContext, fn get_property(
cx: *mut JSContext,
object: HandleObject, object: HandleObject,
property: &CString, property: &CString,
value: MutableHandleValue) value: MutableHandleValue,
-> bool { ) -> bool {
unsafe { JS_GetProperty(cx, object, property.as_ptr(), value) } unsafe { JS_GetProperty(cx, object, property.as_ptr(), value) }
} }
@ -272,11 +281,12 @@ pub fn get_dictionary_property(cx: *mut JSContext,
/// Set the property with name `property` from `object`. /// Set the property with name `property` from `object`.
/// Returns `Err(())` on JSAPI failure, or null object, /// Returns `Err(())` on JSAPI failure, or null object,
/// and Ok(()) otherwise /// and Ok(()) otherwise
pub fn set_dictionary_property(cx: *mut JSContext, pub fn set_dictionary_property(
cx: *mut JSContext,
object: HandleObject, object: HandleObject,
property: &str, property: &str,
value: HandleValue) value: HandleValue,
-> Result<(), ()> { ) -> Result<(), ()> {
if object.get().is_null() { if object.get().is_null() {
return Err(()); return Err(());
} }
@ -292,11 +302,12 @@ pub fn set_dictionary_property(cx: *mut JSContext,
} }
/// Returns whether `proxy` has a property `id` on its prototype. /// Returns whether `proxy` has a property `id` on its prototype.
pub unsafe fn has_property_on_prototype(cx: *mut JSContext, pub unsafe fn has_property_on_prototype(
cx: *mut JSContext,
proxy: HandleObject, proxy: HandleObject,
id: HandleId, id: HandleId,
found: &mut bool) found: &mut bool,
-> bool { ) -> bool {
rooted!(in(cx) let mut proto = ptr::null_mut::<JSObject>()); rooted!(in(cx) let mut proto = ptr::null_mut::<JSObject>());
if !JS_GetPrototype(cx, proxy, proto.handle_mut()) { if !JS_GetPrototype(cx, proxy, proto.handle_mut()) {
return false; return false;
@ -322,9 +333,11 @@ pub unsafe fn trace_global(tracer: *mut JSTracer, obj: *mut JSObject) {
let array = get_proto_or_iface_array(obj); let array = get_proto_or_iface_array(obj);
for proto in (*array).iter() { for proto in (*array).iter() {
if !proto.is_null() { if !proto.is_null() {
trace_object(tracer, trace_object(
tracer,
"prototype", "prototype",
&*(proto as *const *mut JSObject as *const Heap<*mut JSObject>)); &*(proto as *const *mut JSObject as *const Heap<*mut JSObject>),
);
} }
} }
} }
@ -346,8 +359,8 @@ pub unsafe extern "C" fn resolve_global(
cx: *mut JSContext, cx: *mut JSContext,
obj: RawHandleObject, obj: RawHandleObject,
id: RawHandleId, id: RawHandleId,
rval: *mut bool) rval: *mut bool,
-> bool { ) -> bool {
assert!(JS_IsGlobalObject(obj.get())); assert!(JS_IsGlobalObject(obj.get()));
if !JS_ResolveStandardClass(cx, obj, id, rval) { if !JS_ResolveStandardClass(cx, obj, id, rval) {
return false; return false;
@ -379,20 +392,23 @@ pub unsafe extern "C" fn resolve_global(
true true
} }
unsafe extern "C" fn wrap(cx: *mut JSContext, unsafe extern "C" fn wrap(
cx: *mut JSContext,
_existing: RawHandleObject, _existing: RawHandleObject,
obj: RawHandleObject) obj: RawHandleObject,
-> *mut JSObject { ) -> *mut JSObject {
// FIXME terrible idea. need security wrappers // FIXME terrible idea. need security wrappers
// https://github.com/servo/servo/issues/2382 // https://github.com/servo/servo/issues/2382
WrapperNew(cx, obj, GetCrossCompartmentWrapper(), ptr::null(), false) WrapperNew(cx, obj, GetCrossCompartmentWrapper(), ptr::null(), false)
} }
unsafe extern "C" fn pre_wrap(cx: *mut JSContext, unsafe extern "C" fn pre_wrap(
cx: *mut JSContext,
_scope: RawHandleObject, _scope: RawHandleObject,
obj: RawHandleObject, obj: RawHandleObject,
_object_passed_to_wrap: RawHandleObject, _object_passed_to_wrap: RawHandleObject,
rval: RawMutableHandleObject) { rval: RawMutableHandleObject,
) {
let _ac = JSAutoCompartment::new(cx, obj.get()); let _ac = JSAutoCompartment::new(cx, obj.get());
let obj = ToWindowProxyIfWindow(obj.get()); let obj = ToWindowProxyIfWindow(obj.get());
assert!(!obj.is_null()); assert!(!obj.is_null());
@ -406,23 +422,29 @@ pub static WRAP_CALLBACKS: JSWrapObjectCallbacks = JSWrapObjectCallbacks {
}; };
/// Deletes the property `id` from `object`. /// Deletes the property `id` from `object`.
pub unsafe fn delete_property_by_id(cx: *mut JSContext, pub unsafe fn delete_property_by_id(
cx: *mut JSContext,
object: HandleObject, object: HandleObject,
id: HandleId, id: HandleId,
bp: *mut ObjectOpResult) bp: *mut ObjectOpResult,
-> bool { ) -> bool {
JS_DeletePropertyById(cx, object, id, bp) JS_DeletePropertyById(cx, object, id, bp)
} }
unsafe fn generic_call(cx: *mut JSContext, unsafe fn generic_call(
cx: *mut JSContext,
argc: libc::c_uint, argc: libc::c_uint,
vp: *mut JSVal, vp: *mut JSVal,
is_lenient: bool, is_lenient: bool,
call: unsafe extern fn(*const JSJitInfo, *mut JSContext, call: unsafe extern "C" fn(
RawHandleObject, *mut libc::c_void, u32, *const JSJitInfo,
*mut JSVal) *mut JSContext,
-> bool) RawHandleObject,
-> bool { *mut libc::c_void,
u32,
*mut JSVal,
) -> bool,
) -> bool {
let args = CallArgs::from_vp(vp, argc); let args = CallArgs::from_vp(vp, argc);
let info = RUST_FUNCTION_VALUE_TO_JITINFO(JS_CALLEE(cx, vp)); let info = RUST_FUNCTION_VALUE_TO_JITINFO(JS_CALLEE(cx, vp));
@ -441,9 +463,8 @@ unsafe fn generic_call(cx: *mut JSContext,
}; };
rooted!(in(cx) let obj = obj); rooted!(in(cx) let obj = obj);
let depth = (*info).depth; let depth = (*info).depth;
let proto_check = |class: &'static DOMClass| { let proto_check =
class.interface_chain[depth as usize] as u16 == proto_id |class: &'static DOMClass| class.interface_chain[depth as usize] as u16 == proto_id;
};
let this = match private_from_proto_check(obj.get(), proto_check) { let this = match private_from_proto_check(obj.get(), proto_check) {
Ok(val) => val, Ok(val) => val,
Err(()) => { Err(()) => {
@ -455,42 +476,53 @@ unsafe fn generic_call(cx: *mut JSContext,
throw_invalid_this(cx, proto_id); throw_invalid_this(cx, proto_id);
return false; return false;
} }
} },
}; };
call(info, cx, obj.handle().into(), this as *mut libc::c_void, argc, vp) call(
info,
cx,
obj.handle().into(),
this as *mut libc::c_void,
argc,
vp,
)
} }
/// Generic method of IDL interface. /// Generic method of IDL interface.
pub unsafe extern "C" fn generic_method(cx: *mut JSContext, pub unsafe extern "C" fn generic_method(
cx: *mut JSContext,
argc: libc::c_uint, argc: libc::c_uint,
vp: *mut JSVal) vp: *mut JSVal,
-> bool { ) -> bool {
generic_call(cx, argc, vp, false, CallJitMethodOp) generic_call(cx, argc, vp, false, CallJitMethodOp)
} }
/// Generic getter of IDL interface. /// Generic getter of IDL interface.
pub unsafe extern "C" fn generic_getter(cx: *mut JSContext, pub unsafe extern "C" fn generic_getter(
cx: *mut JSContext,
argc: libc::c_uint, argc: libc::c_uint,
vp: *mut JSVal) vp: *mut JSVal,
-> bool { ) -> bool {
generic_call(cx, argc, vp, false, CallJitGetterOp) generic_call(cx, argc, vp, false, CallJitGetterOp)
} }
/// Generic lenient getter of IDL interface. /// Generic lenient getter of IDL interface.
pub unsafe extern "C" fn generic_lenient_getter(cx: *mut JSContext, pub unsafe extern "C" fn generic_lenient_getter(
cx: *mut JSContext,
argc: libc::c_uint, argc: libc::c_uint,
vp: *mut JSVal) vp: *mut JSVal,
-> bool { ) -> bool {
generic_call(cx, argc, vp, true, CallJitGetterOp) generic_call(cx, argc, vp, true, CallJitGetterOp)
} }
unsafe extern "C" fn call_setter(info: *const JSJitInfo, unsafe extern "C" fn call_setter(
info: *const JSJitInfo,
cx: *mut JSContext, cx: *mut JSContext,
handle: RawHandleObject, handle: RawHandleObject,
this: *mut libc::c_void, this: *mut libc::c_void,
argc: u32, argc: u32,
vp: *mut JSVal) vp: *mut JSVal,
-> bool { ) -> bool {
if !CallJitSetterOp(info, cx, handle, this, argc, vp) { if !CallJitSetterOp(info, cx, handle, this, argc, vp) {
return false; return false;
} }
@ -499,25 +531,28 @@ unsafe extern "C" fn call_setter(info: *const JSJitInfo,
} }
/// Generic setter of IDL interface. /// Generic setter of IDL interface.
pub unsafe extern "C" fn generic_setter(cx: *mut JSContext, pub unsafe extern "C" fn generic_setter(
cx: *mut JSContext,
argc: libc::c_uint, argc: libc::c_uint,
vp: *mut JSVal) vp: *mut JSVal,
-> bool { ) -> bool {
generic_call(cx, argc, vp, false, call_setter) generic_call(cx, argc, vp, false, call_setter)
} }
/// Generic lenient setter of IDL interface. /// Generic lenient setter of IDL interface.
pub unsafe extern "C" fn generic_lenient_setter(cx: *mut JSContext, pub unsafe extern "C" fn generic_lenient_setter(
cx: *mut JSContext,
argc: libc::c_uint, argc: libc::c_uint,
vp: *mut JSVal) vp: *mut JSVal,
-> bool { ) -> bool {
generic_call(cx, argc, vp, true, call_setter) generic_call(cx, argc, vp, true, call_setter)
} }
unsafe extern "C" fn instance_class_has_proto_at_depth(clasp: *const js::jsapi::Class, unsafe extern "C" fn instance_class_has_proto_at_depth(
clasp: *const js::jsapi::Class,
proto_id: u32, proto_id: u32,
depth: u32) depth: u32,
-> bool { ) -> bool {
let domclass: *const DOMJSClass = clasp as *const _; let domclass: *const DOMJSClass = clasp as *const _;
let domclass = &*domclass; let domclass = &*domclass;
domclass.dom_class.interface_chain[depth as usize] as u32 == proto_id domclass.dom_class.interface_chain[depth as usize] as u32 == proto_id

View file

@ -70,9 +70,11 @@ pub trait WeakReferenceable: DomObject + Sized {
let box_ = &*ptr; let box_ = &*ptr;
assert!(box_.value.get().is_some()); assert!(box_.value.get().is_some());
let new_count = box_.count.get() + 1; let new_count = box_.count.get() + 1;
trace!("Incrementing WeakBox refcount for {:p} to {}.", trace!(
"Incrementing WeakBox refcount for {:p} to {}.",
self, self,
new_count); new_count
);
box_.count.set(new_count); box_.count.set(new_count);
WeakRef { WeakRef {
ptr: ptr::NonNull::new_unchecked(ptr), ptr: ptr::NonNull::new_unchecked(ptr),
@ -91,9 +93,10 @@ impl<T: WeakReferenceable> WeakRef<T> {
/// DomRoot a weak reference. Returns `None` if the object was already collected. /// DomRoot a weak reference. Returns `None` if the object was already collected.
pub fn root(&self) -> Option<DomRoot<T>> { pub fn root(&self) -> Option<DomRoot<T>> {
unsafe { &*self.ptr.as_ptr() }.value.get().map(|ptr| unsafe { unsafe { &*self.ptr.as_ptr() }
DomRoot::from_ref(&*ptr.as_ptr()) .value
}) .get()
.map(|ptr| unsafe { DomRoot::from_ref(&*ptr.as_ptr()) })
} }
/// Return whether the weakly-referenced object is still alive. /// Return whether the weakly-referenced object is still alive.
@ -108,9 +111,7 @@ impl<T: WeakReferenceable> Clone for WeakRef<T> {
let box_ = &*self.ptr.as_ptr(); let box_ = &*self.ptr.as_ptr();
let new_count = box_.count.get() + 1; let new_count = box_.count.get() + 1;
box_.count.set(new_count); box_.count.set(new_count);
WeakRef { WeakRef { ptr: self.ptr }
ptr: self.ptr,
}
} }
} }
} }
@ -190,7 +191,9 @@ impl<T: WeakReferenceable> MutableWeakRef<T> {
/// DomRoot a mutable weak reference. Returns `None` if the object /// DomRoot a mutable weak reference. Returns `None` if the object
/// was already collected. /// was already collected.
pub fn root(&self) -> Option<DomRoot<T>> { pub fn root(&self) -> Option<DomRoot<T>> {
unsafe { &*self.cell.get() }.as_ref().and_then(WeakRef::root) unsafe { &*self.cell.get() }
.as_ref()
.and_then(WeakRef::root)
} }
} }
@ -233,7 +236,10 @@ impl<T: WeakReferenceable> WeakRefVec<T> {
let mut i = 0; let mut i = 0;
while i < self.vec.len() { while i < self.vec.len() {
if self.vec[i].is_alive() { if self.vec[i].is_alive() {
f(WeakRefEntry { vec: self, index: &mut i }); f(WeakRefEntry {
vec: self,
index: &mut i,
});
} else { } else {
self.vec.swap_remove(i); self.vec.swap_remove(i);
} }
@ -293,13 +299,13 @@ impl<'a, T: WeakReferenceable + 'a> Drop for WeakRefEntry<'a, T> {
#[derive(MallocSizeOf)] #[derive(MallocSizeOf)]
pub struct DOMTracker<T: WeakReferenceable> { pub struct DOMTracker<T: WeakReferenceable> {
dom_objects: DomRefCell<WeakRefVec<T>> dom_objects: DomRefCell<WeakRefVec<T>>,
} }
impl<T: WeakReferenceable> DOMTracker<T> { impl<T: WeakReferenceable> DOMTracker<T> {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
dom_objects: DomRefCell::new(WeakRefVec::new()) dom_objects: DomRefCell::new(WeakRefVec::new()),
} }
} }

View file

@ -25,9 +25,10 @@ pub fn validate_qualified_name(qualified_name: &str) -> ErrorResult {
/// Validate a namespace and qualified name and extract their parts. /// Validate a namespace and qualified name and extract their parts.
/// See https://dom.spec.whatwg.org/#validate-and-extract for details. /// See https://dom.spec.whatwg.org/#validate-and-extract for details.
pub fn validate_and_extract(namespace: Option<DOMString>, pub fn validate_and_extract(
qualified_name: &str) namespace: Option<DOMString>,
-> Fallible<(Namespace, Option<Prefix>, LocalName)> { qualified_name: &str,
) -> Fallible<(Namespace, Option<Prefix>, LocalName)> {
// Step 1. // Step 1.
let namespace = namespace_from_domstring(namespace); let namespace = namespace_from_domstring(namespace);
@ -76,7 +77,7 @@ pub fn validate_and_extract(namespace: Option<DOMString>,
(ns, p) => { (ns, p) => {
// Step 10. // Step 10.
Ok((ns, p.map(Prefix::from), LocalName::from(local_name))) Ok((ns, p.map(Prefix::from), LocalName::from(local_name)))
} },
} }
} }
@ -115,14 +116,10 @@ pub fn xml_name_type(name: &str) -> XMLName {
} }
fn is_valid_continuation(c: char) -> bool { fn is_valid_continuation(c: char) -> bool {
is_valid_start(c) || is_valid_start(c) || match c {
match c { '-' | '.' | '0'...'9' | '\u{B7}' | '\u{300}'...'\u{36F}' | '\u{203F}'...'\u{2040}' => {
'-' | true
'.' | },
'0'...'9' |
'\u{B7}' |
'\u{300}'...'\u{36F}' |
'\u{203F}'...'\u{2040}' => true,
_ => false, _ => false,
} }
} }
@ -140,7 +137,7 @@ pub fn xml_name_type(name: &str) -> XMLName {
non_qname_colons = true; non_qname_colons = true;
} }
c c
} },
}; };
for c in iter { for c in iter {

View file

@ -30,7 +30,6 @@ pub struct FileBlob {
size: u64, size: u64,
} }
/// Different backends of Blob /// Different backends of Blob
#[must_root] #[must_root]
#[derive(JSTraceable)] #[derive(JSTraceable)]
@ -43,7 +42,7 @@ pub enum BlobImpl {
/// relative positions of current slicing range, /// relative positions of current slicing range,
/// IMPORTANT: The depth of tree is only two, i.e. the parent Blob must be /// IMPORTANT: The depth of tree is only two, i.e. the parent Blob must be
/// either File-based or Memory-based /// either File-based or Memory-based
Sliced(Dom<Blob>, RelativePos) Sliced(Dom<Blob>, RelativePos),
} }
impl BlobImpl { impl BlobImpl {
@ -76,9 +75,7 @@ pub struct Blob {
impl Blob { impl Blob {
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
pub fn new( pub fn new(global: &GlobalScope, blob_impl: BlobImpl, typeString: String) -> DomRoot<Blob> {
global: &GlobalScope, blob_impl: BlobImpl, typeString: String)
-> DomRoot<Blob> {
let boxed_blob = Box::new(Blob::new_inherited(blob_impl, typeString)); let boxed_blob = Box::new(Blob::new_inherited(blob_impl, typeString));
reflect_dom_object(boxed_blob, global, BlobBinding::Wrap) reflect_dom_object(boxed_blob, global, BlobBinding::Wrap)
} }
@ -95,41 +92,49 @@ impl Blob {
} }
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
fn new_sliced(parent: &Blob, rel_pos: RelativePos, fn new_sliced(
relative_content_type: DOMString) -> DomRoot<Blob> { parent: &Blob,
rel_pos: RelativePos,
relative_content_type: DOMString,
) -> DomRoot<Blob> {
let blob_impl = match *parent.blob_impl.borrow() { let blob_impl = match *parent.blob_impl.borrow() {
BlobImpl::File(_) => { BlobImpl::File(_) => {
// Create new parent node // Create new parent node
BlobImpl::Sliced(Dom::from_ref(parent), rel_pos) BlobImpl::Sliced(Dom::from_ref(parent), rel_pos)
} },
BlobImpl::Memory(_) => { BlobImpl::Memory(_) => {
// Create new parent node // Create new parent node
BlobImpl::Sliced(Dom::from_ref(parent), rel_pos) BlobImpl::Sliced(Dom::from_ref(parent), rel_pos)
} },
BlobImpl::Sliced(ref grandparent, ref old_rel_pos) => { BlobImpl::Sliced(ref grandparent, ref old_rel_pos) => {
// Adjust the slicing position, using same parent // Adjust the slicing position, using same parent
BlobImpl::Sliced(grandparent.clone(), old_rel_pos.slice_inner(&rel_pos)) BlobImpl::Sliced(grandparent.clone(), old_rel_pos.slice_inner(&rel_pos))
} },
}; };
Blob::new(&parent.global(), blob_impl, relative_content_type.into()) Blob::new(&parent.global(), blob_impl, relative_content_type.into())
} }
// https://w3c.github.io/FileAPI/#constructorBlob // https://w3c.github.io/FileAPI/#constructorBlob
pub fn Constructor(global: &GlobalScope, pub fn Constructor(
global: &GlobalScope,
blobParts: Option<Vec<ArrayBufferOrArrayBufferViewOrBlobOrString>>, blobParts: Option<Vec<ArrayBufferOrArrayBufferViewOrBlobOrString>>,
blobPropertyBag: &BlobBinding::BlobPropertyBag) blobPropertyBag: &BlobBinding::BlobPropertyBag,
-> Fallible<DomRoot<Blob>> { ) -> Fallible<DomRoot<Blob>> {
// TODO: accept other blobParts types - ArrayBuffer or ArrayBufferView // TODO: accept other blobParts types - ArrayBuffer or ArrayBufferView
let bytes: Vec<u8> = match blobParts { let bytes: Vec<u8> = match blobParts {
None => Vec::new(), None => Vec::new(),
Some(blobparts) => match blob_parts_to_bytes(blobparts) { Some(blobparts) => match blob_parts_to_bytes(blobparts) {
Ok(bytes) => bytes, Ok(bytes) => bytes,
Err(_) => return Err(Error::InvalidCharacter), Err(_) => return Err(Error::InvalidCharacter),
} },
}; };
Ok(Blob::new(global, BlobImpl::new_from_bytes(bytes), blobPropertyBag.type_.to_string())) Ok(Blob::new(
global,
BlobImpl::new_from_bytes(bytes),
blobPropertyBag.type_.to_string(),
))
} }
/// Get a slice to inner data, this might incur synchronous read and caching /// Get a slice to inner data, this might incur synchronous read and caching
@ -141,7 +146,7 @@ impl Blob {
None => { None => {
let bytes = read_file(&self.global(), f.id.clone())?; let bytes = read_file(&self.global(), f.id.clone())?;
(bytes, true) (bytes, true)
} },
}; };
// Cache // Cache
@ -150,14 +155,12 @@ impl Blob {
} }
Ok(buffer) Ok(buffer)
} },
BlobImpl::Memory(ref s) => Ok(s.clone()), BlobImpl::Memory(ref s) => Ok(s.clone()),
BlobImpl::Sliced(ref parent, ref rel_pos) => { BlobImpl::Sliced(ref parent, ref rel_pos) => parent.get_bytes().map(|v| {
parent.get_bytes().map(|v| {
let range = rel_pos.to_abs_range(v.len()); let range = rel_pos.to_abs_range(v.len());
v.index(range).to_vec() v.index(range).to_vec()
}) }),
}
} }
} }
@ -171,13 +174,19 @@ impl Blob {
pub fn get_blob_url_id(&self) -> Uuid { pub fn get_blob_url_id(&self) -> Uuid {
let opt_sliced_parent = match *self.blob_impl.borrow() { let opt_sliced_parent = match *self.blob_impl.borrow() {
BlobImpl::Sliced(ref parent, ref rel_pos) => { BlobImpl::Sliced(ref parent, ref rel_pos) => {
Some((parent.promote(/* set_valid is */ false), rel_pos.clone(), parent.Size())) Some((
} parent.promote(/* set_valid is */ false),
_ => None rel_pos.clone(),
parent.Size(),
))
},
_ => None,
}; };
match opt_sliced_parent { match opt_sliced_parent {
Some((parent_id, rel_pos, size)) => self.create_sliced_url_id(&parent_id, &rel_pos, size), Some((parent_id, rel_pos, size)) => {
self.create_sliced_url_id(&parent_id, &rel_pos, size)
},
None => self.promote(/* set_valid is */ true), None => self.promote(/* set_valid is */ true),
} }
} }
@ -196,13 +205,15 @@ impl Blob {
debug!("Sliced can't have a sliced parent"); debug!("Sliced can't have a sliced parent");
// Return dummy id // Return dummy id
return Uuid::new_v4(); return Uuid::new_v4();
} },
BlobImpl::File(ref f) => { BlobImpl::File(ref f) => {
if set_valid { if set_valid {
let origin = get_blob_origin(&global_url); let origin = get_blob_origin(&global_url);
let (tx, rx) = ipc::channel(self.global().time_profiler_chan().clone()).unwrap(); let (tx, rx) =
ipc::channel(self.global().time_profiler_chan().clone()).unwrap();
let msg = FileManagerThreadMsg::ActivateBlobURL(f.id.clone(), tx, origin.clone()); let msg =
FileManagerThreadMsg::ActivateBlobURL(f.id.clone(), tx, origin.clone());
self.send_to_file_manager(msg); self.send_to_file_manager(msg);
match rx.recv().unwrap() { match rx.recv().unwrap() {
@ -214,7 +225,7 @@ impl Blob {
// no need to activate // no need to activate
return f.id.clone(); return f.id.clone();
} }
} },
BlobImpl::Memory(ref mut bytes_in) => mem::swap(bytes_in, &mut bytes), BlobImpl::Memory(ref mut bytes_in) => mem::swap(bytes_in, &mut bytes),
}; };
@ -240,21 +251,28 @@ impl Blob {
size: bytes.len() as u64, size: bytes.len() as u64,
}); });
id id
} },
// Dummy id // Dummy id
Err(_) => Uuid::new_v4(), Err(_) => Uuid::new_v4(),
} }
} }
/// Get a FileID representing sliced parent-blob content /// Get a FileID representing sliced parent-blob content
fn create_sliced_url_id(&self, parent_id: &Uuid, fn create_sliced_url_id(
rel_pos: &RelativePos, parent_len: u64) -> Uuid { &self,
parent_id: &Uuid,
rel_pos: &RelativePos,
parent_len: u64,
) -> Uuid {
let origin = get_blob_origin(&self.global().get_url()); let origin = get_blob_origin(&self.global().get_url());
let (tx, rx) = ipc::channel(self.global().time_profiler_chan().clone()).unwrap(); let (tx, rx) = ipc::channel(self.global().time_profiler_chan().clone()).unwrap();
let msg = FileManagerThreadMsg::AddSlicedURLEntry(parent_id.clone(), let msg = FileManagerThreadMsg::AddSlicedURLEntry(
parent_id.clone(),
rel_pos.clone(), rel_pos.clone(),
tx, origin.clone()); tx,
origin.clone(),
);
self.send_to_file_manager(msg); self.send_to_file_manager(msg);
match rx.recv().expect("File manager thread is down") { match rx.recv().expect("File manager thread is down") {
Ok(new_id) => { Ok(new_id) => {
@ -267,11 +285,11 @@ impl Blob {
// Return the indirect id reference // Return the indirect id reference
new_id new_id
} },
Err(_) => { Err(_) => {
// Return dummy id // Return dummy id
Uuid::new_v4() Uuid::new_v4()
} },
} }
} }
@ -303,7 +321,7 @@ impl Drop for Blob {
fn read_file(global: &GlobalScope, id: Uuid) -> Result<Vec<u8>, ()> { fn read_file(global: &GlobalScope, id: Uuid) -> Result<Vec<u8>, ()> {
let resource_threads = global.resource_threads(); let resource_threads = global.resource_threads();
let (chan, recv) = ipc::channel(global.time_profiler_chan().clone()).map_err(|_|())?; let (chan, recv) = ipc::channel(global.time_profiler_chan().clone()).map_err(|_| ())?;
let origin = get_blob_origin(&global.get_url()); let origin = get_blob_origin(&global.get_url());
let check_url_validity = false; let check_url_validity = false;
let msg = FileManagerThreadMsg::ReadFile(chan, id, check_url_validity, origin); let msg = FileManagerThreadMsg::ReadFile(chan, id, check_url_validity, origin);
@ -315,13 +333,13 @@ fn read_file(global: &GlobalScope, id: Uuid) -> Result<Vec<u8>, ()> {
match recv.recv().unwrap() { match recv.recv().unwrap() {
Ok(ReadFileProgress::Meta(mut blob_buf)) => { Ok(ReadFileProgress::Meta(mut blob_buf)) => {
bytes.append(&mut blob_buf.bytes); bytes.append(&mut blob_buf.bytes);
} },
Ok(ReadFileProgress::Partial(mut bytes_in)) => { Ok(ReadFileProgress::Partial(mut bytes_in)) => {
bytes.append(&mut bytes_in); bytes.append(&mut bytes_in);
} },
Ok(ReadFileProgress::EOF) => { Ok(ReadFileProgress::EOF) => {
return Ok(bytes); return Ok(bytes);
} },
Err(_) => return Err(()), Err(_) => return Err(()),
} }
} }
@ -330,7 +348,9 @@ fn read_file(global: &GlobalScope, id: Uuid) -> Result<Vec<u8>, ()> {
/// Extract bytes from BlobParts, used by Blob and File constructor /// Extract bytes from BlobParts, used by Blob and File constructor
/// <https://w3c.github.io/FileAPI/#constructorBlob> /// <https://w3c.github.io/FileAPI/#constructorBlob>
#[allow(unsafe_code)] #[allow(unsafe_code)]
pub fn blob_parts_to_bytes(mut blobparts: Vec<ArrayBufferOrArrayBufferViewOrBlobOrString>) -> Result<Vec<u8>, ()> { pub fn blob_parts_to_bytes(
mut blobparts: Vec<ArrayBufferOrArrayBufferViewOrBlobOrString>,
) -> Result<Vec<u8>, ()> {
let mut ret = vec![]; let mut ret = vec![];
for blobpart in &mut blobparts { for blobpart in &mut blobparts {
match blobpart { match blobpart {
@ -348,7 +368,7 @@ pub fn blob_parts_to_bytes(mut blobparts: Vec<ArrayBufferOrArrayBufferViewOrBlob
&mut ArrayBufferOrArrayBufferViewOrBlobOrString::ArrayBufferView(ref mut a) => unsafe { &mut ArrayBufferOrArrayBufferViewOrBlobOrString::ArrayBufferView(ref mut a) => unsafe {
let bytes = a.as_slice(); let bytes = a.as_slice();
ret.extend(bytes); ret.extend(bytes);
} },
} }
} }
@ -361,8 +381,9 @@ impl BlobMethods for Blob {
match *self.blob_impl.borrow() { match *self.blob_impl.borrow() {
BlobImpl::File(ref f) => f.size, BlobImpl::File(ref f) => f.size,
BlobImpl::Memory(ref v) => v.len() as u64, BlobImpl::Memory(ref v) => v.len() as u64,
BlobImpl::Sliced(ref parent, ref rel_pos) => BlobImpl::Sliced(ref parent, ref rel_pos) => {
rel_pos.to_abs_range(parent.Size() as usize).len() as u64, rel_pos.to_abs_range(parent.Size() as usize).len() as u64
},
} }
} }
@ -372,11 +393,12 @@ impl BlobMethods for Blob {
} }
// https://w3c.github.io/FileAPI/#slice-method-algo // https://w3c.github.io/FileAPI/#slice-method-algo
fn Slice(&self, fn Slice(
&self,
start: Option<i64>, start: Option<i64>,
end: Option<i64>, end: Option<i64>,
content_type: Option<DOMString>) content_type: Option<DOMString>,
-> DomRoot<Blob> { ) -> DomRoot<Blob> {
let rel_pos = RelativePos::from_opts(start, end); let rel_pos = RelativePos::from_opts(start, end);
Blob::new_sliced(self, rel_pos, content_type.unwrap_or(DOMString::from(""))) Blob::new_sliced(self, rel_pos, content_type.unwrap_or(DOMString::from("")))
} }

View file

@ -12,7 +12,7 @@ use dom::bindings::codegen::Bindings::BluetoothBinding::{self, BluetoothDataFilt
use dom::bindings::codegen::Bindings::BluetoothBinding::{BluetoothMethods, RequestDeviceOptions}; use dom::bindings::codegen::Bindings::BluetoothBinding::{BluetoothMethods, RequestDeviceOptions};
use dom::bindings::codegen::Bindings::BluetoothPermissionResultBinding::BluetoothPermissionDescriptor; use dom::bindings::codegen::Bindings::BluetoothPermissionResultBinding::BluetoothPermissionDescriptor;
use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServerBinding::BluetoothRemoteGATTServerBinding:: use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServerBinding::BluetoothRemoteGATTServerBinding::
BluetoothRemoteGATTServerMethods; BluetoothRemoteGATTServerMethods;
use dom::bindings::codegen::Bindings::PermissionStatusBinding::{PermissionName, PermissionState}; use dom::bindings::codegen::Bindings::PermissionStatusBinding::{PermissionName, PermissionState};
use dom::bindings::codegen::UnionTypes::{ArrayBufferViewOrArrayBuffer, StringOrUnsignedLong}; use dom::bindings::codegen::UnionTypes::{ArrayBufferViewOrArrayBuffer, StringOrUnsignedLong};
use dom::bindings::error::Error::{self, Network, Security, Type}; use dom::bindings::error::Error::{self, Network, Security, Type};
@ -42,20 +42,26 @@ use std::str::FromStr;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use task::TaskOnce; use task::TaskOnce;
const KEY_CONVERSION_ERROR: &'static str = "This `manufacturerData` key can not be parsed as unsigned short:"; const KEY_CONVERSION_ERROR: &'static str =
const FILTER_EMPTY_ERROR: &'static str = "'filters' member, if present, must be nonempty to find any devices."; "This `manufacturerData` key can not be parsed as unsigned short:";
const FILTER_EMPTY_ERROR: &'static str =
"'filters' member, if present, must be nonempty to find any devices.";
const FILTER_ERROR: &'static str = "A filter must restrict the devices in some way."; const FILTER_ERROR: &'static str = "A filter must restrict the devices in some way.";
const MANUFACTURER_DATA_ERROR: &'static str = "'manufacturerData', if present, must be non-empty to filter devices."; const MANUFACTURER_DATA_ERROR: &'static str =
const MASK_LENGTH_ERROR: &'static str = "`mask`, if present, must have the same length as `dataPrefix`."; "'manufacturerData', if present, must be non-empty to filter devices.";
const MASK_LENGTH_ERROR: &'static str =
"`mask`, if present, must have the same length as `dataPrefix`.";
// 248 is the maximum number of UTF-8 code units in a Bluetooth Device Name. // 248 is the maximum number of UTF-8 code units in a Bluetooth Device Name.
const MAX_DEVICE_NAME_LENGTH: usize = 248; const MAX_DEVICE_NAME_LENGTH: usize = 248;
const NAME_PREFIX_ERROR: &'static str = "'namePrefix', if present, must be nonempty."; const NAME_PREFIX_ERROR: &'static str = "'namePrefix', if present, must be nonempty.";
const NAME_TOO_LONG_ERROR: &'static str = "A device name can't be longer than 248 bytes."; const NAME_TOO_LONG_ERROR: &'static str = "A device name can't be longer than 248 bytes.";
const SERVICE_DATA_ERROR: &'static str = "'serviceData', if present, must be non-empty to filter devices."; const SERVICE_DATA_ERROR: &'static str =
"'serviceData', if present, must be non-empty to filter devices.";
const SERVICE_ERROR: &'static str = "'services', if present, must contain at least one service."; const SERVICE_ERROR: &'static str = "'services', if present, must contain at least one service.";
const OPTIONS_ERROR: &'static str = "Fields of 'options' conflict with each other. const OPTIONS_ERROR: &'static str = "Fields of 'options' conflict with each other.
Either 'acceptAllDevices' member must be true, or 'filters' member must be set to a value."; Either 'acceptAllDevices' member must be true, or 'filters' member must be set to a value.";
const BT_DESC_CONVERSION_ERROR: &'static str = "Can't convert to an IDL value of type BluetoothPermissionDescriptor"; const BT_DESC_CONVERSION_ERROR: &'static str =
"Can't convert to an IDL value of type BluetoothPermissionDescriptor";
#[derive(JSTraceable, MallocSizeOf)] #[derive(JSTraceable, MallocSizeOf)]
pub struct AllowedBluetoothDevice { pub struct AllowedBluetoothDevice {
@ -84,7 +90,10 @@ impl BluetoothExtraPermissionData {
} }
pub fn allowed_devices_contains_id(&self, id: DOMString) -> bool { pub fn allowed_devices_contains_id(&self, id: DOMString) -> bool {
self.allowed_devices.borrow().iter().any(|d| d.deviceId == id) self.allowed_devices
.borrow()
.iter()
.any(|d| d.deviceId == id)
} }
} }
@ -132,9 +141,11 @@ impl Bluetooth {
} }
pub fn new(global: &GlobalScope) -> DomRoot<Bluetooth> { pub fn new(global: &GlobalScope) -> DomRoot<Bluetooth> {
reflect_dom_object(Box::new(Bluetooth::new_inherited()), reflect_dom_object(
Box::new(Bluetooth::new_inherited()),
global, global,
BluetoothBinding::Wrap) BluetoothBinding::Wrap,
)
} }
fn get_bluetooth_thread(&self) -> IpcSender<BluetoothRequest> { fn get_bluetooth_thread(&self) -> IpcSender<BluetoothRequest> {
@ -146,15 +157,17 @@ impl Bluetooth {
} }
// https://webbluetoothcg.github.io/web-bluetooth/#request-bluetooth-devices // https://webbluetoothcg.github.io/web-bluetooth/#request-bluetooth-devices
fn request_bluetooth_devices(&self, fn request_bluetooth_devices(
&self,
p: &Rc<Promise>, p: &Rc<Promise>,
filters: &Option<Vec<BluetoothLEScanFilterInit>>, filters: &Option<Vec<BluetoothLEScanFilterInit>>,
optional_services: &Option<Vec<BluetoothServiceUUID>>, optional_services: &Option<Vec<BluetoothServiceUUID>>,
sender: IpcSender<BluetoothResponseResult>) { sender: IpcSender<BluetoothResponseResult>,
) {
// TODO: Step 1: Triggered by user activation. // TODO: Step 1: Triggered by user activation.
// Step 2.2: There are no requiredServiceUUIDS, we scan for all devices. // Step 2.2: There are no requiredServiceUUIDS, we scan for all devices.
let mut uuid_filters = vec!(); let mut uuid_filters = vec![];
if let &Some(ref filters) = filters { if let &Some(ref filters) = filters {
// Step 2.1. // Step 2.1.
@ -180,7 +193,7 @@ impl Bluetooth {
} }
} }
let mut optional_services_uuids = vec!(); let mut optional_services_uuids = vec![];
if let &Some(ref opt_services) = optional_services { if let &Some(ref opt_services) = optional_services {
for opt_service in opt_services { for opt_service in opt_services {
// Step 2.5 - 2.6. // Step 2.5 - 2.6.
@ -201,30 +214,39 @@ impl Bluetooth {
} }
} }
let option = RequestDeviceoptions::new(BluetoothScanfilterSequence::new(uuid_filters), let option = RequestDeviceoptions::new(
ServiceUUIDSequence::new(optional_services_uuids)); BluetoothScanfilterSequence::new(uuid_filters),
ServiceUUIDSequence::new(optional_services_uuids),
);
// Step 4 - 5. // Step 4 - 5.
if let PermissionState::Denied = get_descriptor_permission_state(PermissionName::Bluetooth, None) { if let PermissionState::Denied =
get_descriptor_permission_state(PermissionName::Bluetooth, None)
{
return p.reject_error(Error::NotFound); return p.reject_error(Error::NotFound);
} }
// Note: Step 3, 6 - 8 are implemented in // Note: Step 3, 6 - 8 are implemented in
// components/net/bluetooth_thread.rs in request_device function. // components/net/bluetooth_thread.rs in request_device function.
self.get_bluetooth_thread().send(BluetoothRequest::RequestDevice(option, sender)).unwrap(); self.get_bluetooth_thread()
.send(BluetoothRequest::RequestDevice(option, sender))
.unwrap();
} }
} }
pub fn response_async<T: AsyncBluetoothListener + DomObject + 'static>( pub fn response_async<T: AsyncBluetoothListener + DomObject + 'static>(
promise: &Rc<Promise>, promise: &Rc<Promise>,
receiver: &T) -> IpcSender<BluetoothResponseResult> { receiver: &T,
) -> IpcSender<BluetoothResponseResult> {
let (action_sender, action_receiver) = ipc::channel().unwrap(); let (action_sender, action_receiver) = ipc::channel().unwrap();
let task_source = receiver.global().networking_task_source(); let task_source = receiver.global().networking_task_source();
let context = Arc::new(Mutex::new(BluetoothContext { let context = Arc::new(Mutex::new(BluetoothContext {
promise: Some(TrustedPromise::new(promise.clone())), promise: Some(TrustedPromise::new(promise.clone())),
receiver: Trusted::new(receiver), receiver: Trusted::new(receiver),
})); }));
ROUTER.add_route(action_receiver.to_opaque(), Box::new(move |message| { ROUTER.add_route(
action_receiver.to_opaque(),
Box::new(move |message| {
struct ListenerTask<T: AsyncBluetoothListener + DomObject> { struct ListenerTask<T: AsyncBluetoothListener + DomObject> {
context: Arc<Mutex<BluetoothContext<T>>>, context: Arc<Mutex<BluetoothContext<T>>>,
action: BluetoothResponseResult, action: BluetoothResponseResult,
@ -249,23 +271,26 @@ pub fn response_async<T: AsyncBluetoothListener + DomObject + 'static>(
if let Err(err) = result { if let Err(err) = result {
warn!("failed to deliver network data: {:?}", err); warn!("failed to deliver network data: {:?}", err);
} }
})); }),
);
action_sender action_sender
} }
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
// https://webbluetoothcg.github.io/web-bluetooth/#getgattchildren // https://webbluetoothcg.github.io/web-bluetooth/#getgattchildren
pub fn get_gatt_children<T, F> ( pub fn get_gatt_children<T, F>(
attribute: &T, attribute: &T,
single: bool, single: bool,
uuid_canonicalizer: F, uuid_canonicalizer: F,
uuid: Option<StringOrUnsignedLong>, uuid: Option<StringOrUnsignedLong>,
instance_id: String, instance_id: String,
connected: bool, connected: bool,
child_type: GATTType) child_type: GATTType,
-> Rc<Promise> ) -> Rc<Promise>
where T: AsyncBluetoothListener + DomObject + 'static, where
F: FnOnce(StringOrUnsignedLong) -> Fallible<UUID> { T: AsyncBluetoothListener + DomObject + 'static,
F: FnOnce(StringOrUnsignedLong) -> Fallible<UUID>,
{
let p = Promise::new(&attribute.global()); let p = Promise::new(&attribute.global());
let result_uuid = if let Some(u) = uuid { let result_uuid = if let Some(u) = uuid {
@ -275,7 +300,7 @@ pub fn get_gatt_children<T, F> (
Err(e) => { Err(e) => {
p.reject_error(e); p.reject_error(e);
return p; return p;
} },
}; };
// Step 2. // Step 2.
if uuid_is_blocklisted(canonicalized.as_ref(), Blocklist::All) { if uuid_is_blocklisted(canonicalized.as_ref(), Blocklist::All) {
@ -298,8 +323,17 @@ pub fn get_gatt_children<T, F> (
// Note: Steps 6 - 7 are implemented in components/bluetooth/lib.rs in get_descriptor function // Note: Steps 6 - 7 are implemented in components/bluetooth/lib.rs in get_descriptor function
// and in handle_response function. // and in handle_response function.
let sender = response_async(&p, attribute); let sender = response_async(&p, attribute);
attribute.global().as_window().bluetooth_thread().send( attribute
BluetoothRequest::GetGATTChildren(instance_id, result_uuid, single, child_type, sender)).unwrap(); .global()
.as_window()
.bluetooth_thread()
.send(BluetoothRequest::GetGATTChildren(
instance_id,
result_uuid,
single,
child_type,
sender,
)).unwrap();
return p; return p;
} }
@ -310,7 +344,8 @@ fn canonicalize_filter(filter: &BluetoothLEScanFilterInit) -> Fallible<Bluetooth
filter.name.is_none() && filter.name.is_none() &&
filter.namePrefix.is_none() && filter.namePrefix.is_none() &&
filter.manufacturerData.is_none() && filter.manufacturerData.is_none() &&
filter.serviceData.is_none() { filter.serviceData.is_none()
{
return Err(Type(FILTER_ERROR.to_owned())); return Err(Type(FILTER_ERROR.to_owned()));
} }
@ -325,7 +360,7 @@ fn canonicalize_filter(filter: &BluetoothLEScanFilterInit) -> Fallible<Bluetooth
return Err(Type(SERVICE_ERROR.to_owned())); return Err(Type(SERVICE_ERROR.to_owned()));
} }
let mut services_vec = vec!(); let mut services_vec = vec![];
for service in services { for service in services {
// Step 3.2 - 3.3. // Step 3.2 - 3.3.
@ -333,7 +368,7 @@ fn canonicalize_filter(filter: &BluetoothLEScanFilterInit) -> Fallible<Bluetooth
// Step 3.4. // Step 3.4.
if uuid_is_blocklisted(uuid.as_ref(), Blocklist::All) { if uuid_is_blocklisted(uuid.as_ref(), Blocklist::All) {
return Err(Security) return Err(Security);
} }
services_vec.push(uuid); services_vec.push(uuid);
@ -341,7 +376,7 @@ fn canonicalize_filter(filter: &BluetoothLEScanFilterInit) -> Fallible<Bluetooth
// Step 3.5. // Step 3.5.
services_vec services_vec
}, },
None => vec!(), None => vec![],
}; };
// Step 4. // Step 4.
@ -388,13 +423,18 @@ fn canonicalize_filter(filter: &BluetoothLEScanFilterInit) -> Fallible<Bluetooth
// Step 7.1 - 7.2. // Step 7.1 - 7.2.
let manufacturer_id = match u16::from_str(key.as_ref()) { let manufacturer_id = match u16::from_str(key.as_ref()) {
Ok(id) => id, Ok(id) => id,
Err(err) => return Err(Type(format!("{} {} {}", KEY_CONVERSION_ERROR, key, err))), Err(err) => {
return Err(Type(format!("{} {} {}", KEY_CONVERSION_ERROR, key, err)))
},
}; };
// Step 7.3: No need to convert to IDL values since this is only used by native code. // Step 7.3: No need to convert to IDL values since this is only used by native code.
// Step 7.4 - 7.5. // Step 7.4 - 7.5.
map.insert(manufacturer_id, canonicalize_bluetooth_data_filter_init(bdfi)?); map.insert(
manufacturer_id,
canonicalize_bluetooth_data_filter_init(bdfi)?,
);
} }
Some(map) Some(map)
}, },
@ -414,7 +454,7 @@ fn canonicalize_filter(filter: &BluetoothLEScanFilterInit) -> Fallible<Bluetooth
// Step 9.1. // Step 9.1.
Ok(number) => StringOrUnsignedLong::UnsignedLong(number), Ok(number) => StringOrUnsignedLong::UnsignedLong(number),
// Step 9.2. // Step 9.2.
_ => StringOrUnsignedLong::String(key.clone()) _ => StringOrUnsignedLong::String(key.clone()),
}; };
// Step 9.3 - 9.4. // Step 9.3 - 9.4.
@ -436,16 +476,24 @@ fn canonicalize_filter(filter: &BluetoothLEScanFilterInit) -> Fallible<Bluetooth
}; };
// Step 10. // Step 10.
Ok(BluetoothScanfilter::new(name, name_prefix, services_vec, manufacturer_data, service_data)) Ok(BluetoothScanfilter::new(
name,
name_prefix,
services_vec,
manufacturer_data,
service_data,
))
} }
// https://webbluetoothcg.github.io/web-bluetooth/#bluetoothdatafilterinit-canonicalizing // https://webbluetoothcg.github.io/web-bluetooth/#bluetoothdatafilterinit-canonicalizing
fn canonicalize_bluetooth_data_filter_init(bdfi: &BluetoothDataFilterInit) -> Fallible<(Vec<u8>, Vec<u8>)> { fn canonicalize_bluetooth_data_filter_init(
bdfi: &BluetoothDataFilterInit,
) -> Fallible<(Vec<u8>, Vec<u8>)> {
// Step 1. // Step 1.
let data_prefix = match bdfi.dataPrefix { let data_prefix = match bdfi.dataPrefix {
Some(ArrayBufferViewOrArrayBuffer::ArrayBufferView(ref avb)) => avb.to_vec(), Some(ArrayBufferViewOrArrayBuffer::ArrayBufferView(ref avb)) => avb.to_vec(),
Some(ArrayBufferViewOrArrayBuffer::ArrayBuffer(ref ab)) => ab.to_vec(), Some(ArrayBufferViewOrArrayBuffer::ArrayBuffer(ref ab)) => ab.to_vec(),
None => vec![] None => vec![],
}; };
// Step 2. // Step 2.
@ -454,7 +502,7 @@ fn canonicalize_bluetooth_data_filter_init(bdfi: &BluetoothDataFilterInit) -> Fa
let mask = match bdfi.mask { let mask = match bdfi.mask {
Some(ArrayBufferViewOrArrayBuffer::ArrayBufferView(ref avb)) => avb.to_vec(), Some(ArrayBufferViewOrArrayBuffer::ArrayBufferView(ref avb)) => avb.to_vec(),
Some(ArrayBufferViewOrArrayBuffer::ArrayBuffer(ref ab)) => ab.to_vec(), Some(ArrayBufferViewOrArrayBuffer::ArrayBuffer(ref ab)) => ab.to_vec(),
None => vec![0xFF; data_prefix.len()] None => vec![0xFF; data_prefix.len()],
}; };
// Step 3. // Step 3.
@ -486,7 +534,8 @@ impl BluetoothMethods for Bluetooth {
let p = Promise::new(&self.global()); let p = Promise::new(&self.global());
// Step 1. // Step 1.
if (option.filters.is_some() && option.acceptAllDevices) || if (option.filters.is_some() && option.acceptAllDevices) ||
(option.filters.is_none() && !option.acceptAllDevices) { (option.filters.is_none() && !option.acceptAllDevices)
{
p.reject_error(Error::Type(OPTIONS_ERROR.to_owned())); p.reject_error(Error::Type(OPTIONS_ERROR.to_owned()));
return p; return p;
} }
@ -505,13 +554,18 @@ impl BluetoothMethods for Bluetooth {
// Step 1. We did not override the method // Step 1. We did not override the method
// Step 2 - 3. in handle_response // Step 2 - 3. in handle_response
let sender = response_async(&p, self); let sender = response_async(&p, self);
self.get_bluetooth_thread().send( self.get_bluetooth_thread()
BluetoothRequest::GetAvailability(sender)).unwrap(); .send(BluetoothRequest::GetAvailability(sender))
.unwrap();
p p
} }
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetooth-onavailabilitychanged // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetooth-onavailabilitychanged
event_handler!(availabilitychanged, GetOnavailabilitychanged, SetOnavailabilitychanged); event_handler!(
availabilitychanged,
GetOnavailabilitychanged,
SetOnavailabilitychanged
);
} }
impl AsyncBluetoothListener for Bluetooth { impl AsyncBluetoothListener for Bluetooth {
@ -524,18 +578,21 @@ impl AsyncBluetoothListener for Bluetooth {
if let Some(existing_device) = device_instance_map.get(&device.id.clone()) { if let Some(existing_device) = device_instance_map.get(&device.id.clone()) {
return promise.resolve_native(&**existing_device); return promise.resolve_native(&**existing_device);
} }
let bt_device = BluetoothDevice::new(&self.global(), let bt_device = BluetoothDevice::new(
&self.global(),
DOMString::from(device.id.clone()), DOMString::from(device.id.clone()),
device.name.map(DOMString::from), device.name.map(DOMString::from),
&self); &self,
);
device_instance_map.insert(device.id.clone(), Dom::from_ref(&bt_device)); device_instance_map.insert(device.id.clone(), Dom::from_ref(&bt_device));
self.global().as_window().bluetooth_extra_permission_data().add_new_allowed_device( self.global()
AllowedBluetoothDevice { .as_window()
.bluetooth_extra_permission_data()
.add_new_allowed_device(AllowedBluetoothDevice {
deviceId: DOMString::from(device.id), deviceId: DOMString::from(device.id),
mayUseGATT: true, mayUseGATT: true,
} });
);
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetooth-requestdevice // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetooth-requestdevice
// Step 5. // Step 5.
promise.resolve_native(&bt_device); promise.resolve_native(&bt_device);
@ -544,7 +601,7 @@ impl AsyncBluetoothListener for Bluetooth {
// Step 2 - 3. // Step 2 - 3.
BluetoothResponse::GetAvailability(is_available) => { BluetoothResponse::GetAvailability(is_available) => {
promise.resolve_native(&is_available); promise.resolve_native(&is_available);
} },
_ => promise.reject_error(Error::Type("Something went wrong...".to_owned())), _ => promise.reject_error(Error::Type("Something went wrong...".to_owned())),
} }
} }
@ -555,11 +612,14 @@ impl PermissionAlgorithm for Bluetooth {
type Status = BluetoothPermissionResult; type Status = BluetoothPermissionResult;
#[allow(unsafe_code)] #[allow(unsafe_code)]
fn create_descriptor(cx: *mut JSContext, fn create_descriptor(
permission_descriptor_obj: *mut JSObject) cx: *mut JSContext,
-> Result<BluetoothPermissionDescriptor, Error> { permission_descriptor_obj: *mut JSObject,
) -> Result<BluetoothPermissionDescriptor, Error> {
rooted!(in(cx) let mut property = UndefinedValue()); rooted!(in(cx) let mut property = UndefinedValue());
property.handle_mut().set(ObjectValue(permission_descriptor_obj)); property
.handle_mut()
.set(ObjectValue(permission_descriptor_obj));
unsafe { unsafe {
match BluetoothPermissionDescriptor::new(cx, property.handle()) { match BluetoothPermissionDescriptor::new(cx, property.handle()) {
Ok(ConversionResult::Success(descriptor)) => Ok(descriptor), Ok(ConversionResult::Success(descriptor)) => Ok(descriptor),
@ -592,7 +652,10 @@ impl PermissionAlgorithm for Bluetooth {
// Step 5. // Step 5.
let global = status.global(); let global = status.global();
let allowed_devices = global.as_window().bluetooth_extra_permission_data().get_allowed_devices(); let allowed_devices = global
.as_window()
.bluetooth_extra_permission_data()
.get_allowed_devices();
let bluetooth = status.get_bluetooth(); let bluetooth = status.get_bluetooth();
let device_map = bluetooth.get_device_map().borrow(); let device_map = bluetooth.get_device_map().borrow();
@ -622,11 +685,15 @@ impl PermissionAlgorithm for Bluetooth {
// Step 6.2.2. // Step 6.2.2.
// Instead of creating an internal slot we send an ipc message to the Bluetooth thread // Instead of creating an internal slot we send an ipc message to the Bluetooth thread
// to check if one of the filters matches. // to check if one of the filters matches.
let (sender, receiver) = ProfiledIpc::channel(global.time_profiler_chan().clone()).unwrap(); let (sender, receiver) =
status.get_bluetooth_thread() ProfiledIpc::channel(global.time_profiler_chan().clone()).unwrap();
.send(BluetoothRequest::MatchesFilter(device_id.clone(), status
.get_bluetooth_thread()
.send(BluetoothRequest::MatchesFilter(
device_id.clone(),
BluetoothScanfilterSequence::new(scan_filters), BluetoothScanfilterSequence::new(scan_filters),
sender)).unwrap(); sender,
)).unwrap();
match receiver.recv().unwrap() { match receiver.recv().unwrap() {
Ok(true) => (), Ok(true) => (),
@ -666,17 +733,28 @@ impl PermissionAlgorithm for Bluetooth {
// Step 2. // Step 2.
let sender = response_async(promise, status); let sender = response_async(promise, status);
let bluetooth = status.get_bluetooth(); let bluetooth = status.get_bluetooth();
bluetooth.request_bluetooth_devices(promise, &descriptor.filters, &descriptor.optionalServices, sender); bluetooth.request_bluetooth_devices(
promise,
&descriptor.filters,
&descriptor.optionalServices,
sender,
);
// NOTE: Step 3. is in BluetoothPermissionResult's `handle_response` function. // NOTE: Step 3. is in BluetoothPermissionResult's `handle_response` function.
} }
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
// https://webbluetoothcg.github.io/web-bluetooth/#revoke-bluetooth-access // https://webbluetoothcg.github.io/web-bluetooth/#revoke-bluetooth-access
fn permission_revoke(_descriptor: &BluetoothPermissionDescriptor, status: &BluetoothPermissionResult) { fn permission_revoke(
_descriptor: &BluetoothPermissionDescriptor,
status: &BluetoothPermissionResult,
) {
// Step 1. // Step 1.
let global = status.global(); let global = status.global();
let allowed_devices = global.as_window().bluetooth_extra_permission_data().get_allowed_devices(); let allowed_devices = global
.as_window()
.bluetooth_extra_permission_data()
.get_allowed_devices();
// Step 2. // Step 2.
let bluetooth = status.get_bluetooth(); let bluetooth = status.get_bluetooth();
let device_map = bluetooth.get_device_map().borrow(); let device_map = bluetooth.get_device_map().borrow();
@ -684,7 +762,8 @@ impl PermissionAlgorithm for Bluetooth {
let id = DOMString::from(id.clone()); let id = DOMString::from(id.clone());
// Step 2.1. // Step 2.1.
if allowed_devices.iter().any(|d| d.deviceId == id) && if allowed_devices.iter().any(|d| d.deviceId == id) &&
!device.is_represented_device_null() { !device.is_represented_device_null()
{
// Note: We don't need to update the allowed_services, // Note: We don't need to update the allowed_services,
// because we store it in the lower level // because we store it in the lower level
// where it is already up-to-date // where it is already up-to-date

View file

@ -29,12 +29,13 @@ pub struct BluetoothAdvertisingEvent {
} }
impl BluetoothAdvertisingEvent { impl BluetoothAdvertisingEvent {
pub fn new_inherited(device: &BluetoothDevice, pub fn new_inherited(
device: &BluetoothDevice,
name: Option<DOMString>, name: Option<DOMString>,
appearance: Option<u16>, appearance: Option<u16>,
tx_power: Option<i8>, tx_power: Option<i8>,
rssi: Option<i8>) rssi: Option<i8>,
-> BluetoothAdvertisingEvent { ) -> BluetoothAdvertisingEvent {
BluetoothAdvertisingEvent { BluetoothAdvertisingEvent {
event: Event::new_inherited(), event: Event::new_inherited(),
device: Dom::from_ref(device), device: Dom::from_ref(device),
@ -45,7 +46,8 @@ impl BluetoothAdvertisingEvent {
} }
} }
pub fn new(global: &GlobalScope, pub fn new(
global: &GlobalScope,
type_: Atom, type_: Atom,
bubbles: EventBubbles, bubbles: EventBubbles,
cancelable: EventCancelable, cancelable: EventCancelable,
@ -53,18 +55,14 @@ impl BluetoothAdvertisingEvent {
name: Option<DOMString>, name: Option<DOMString>,
appearance: Option<u16>, appearance: Option<u16>,
txPower: Option<i8>, txPower: Option<i8>,
rssi: Option<i8>) rssi: Option<i8>,
-> DomRoot<BluetoothAdvertisingEvent> { ) -> DomRoot<BluetoothAdvertisingEvent> {
let ev = reflect_dom_object( let ev = reflect_dom_object(
Box::new(BluetoothAdvertisingEvent::new_inherited( Box::new(BluetoothAdvertisingEvent::new_inherited(
device, device, name, appearance, txPower, rssi,
name,
appearance,
txPower,
rssi
)), )),
global, global,
BluetoothAdvertisingEventBinding::Wrap BluetoothAdvertisingEventBinding::Wrap,
); );
{ {
let event = ev.upcast::<Event>(); let event = ev.upcast::<Event>();
@ -74,10 +72,11 @@ impl BluetoothAdvertisingEvent {
} }
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothadvertisingevent-bluetoothadvertisingevent // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothadvertisingevent-bluetoothadvertisingevent
pub fn Constructor(window: &Window, pub fn Constructor(
window: &Window,
type_: DOMString, type_: DOMString,
init: &BluetoothAdvertisingEventInit) init: &BluetoothAdvertisingEventInit,
-> Fallible<DomRoot<BluetoothAdvertisingEvent>> { ) -> Fallible<DomRoot<BluetoothAdvertisingEvent>> {
let global = window.upcast::<GlobalScope>(); let global = window.upcast::<GlobalScope>();
let device = init.device.r(); let device = init.device.r();
let name = init.name.clone(); let name = init.name.clone();
@ -86,7 +85,8 @@ impl BluetoothAdvertisingEvent {
let rssi = init.rssi.clone(); let rssi = init.rssi.clone();
let bubbles = EventBubbles::from(init.parent.bubbles); let bubbles = EventBubbles::from(init.parent.bubbles);
let cancelable = EventCancelable::from(init.parent.cancelable); let cancelable = EventCancelable::from(init.parent.cancelable);
Ok(BluetoothAdvertisingEvent::new(global, Ok(BluetoothAdvertisingEvent::new(
global,
Atom::from(type_), Atom::from(type_),
bubbles, bubbles,
cancelable, cancelable,
@ -94,7 +94,8 @@ impl BluetoothAdvertisingEvent {
name, name,
appearance, appearance,
txPower, txPower,
rssi)) rssi,
))
} }
} }

View file

@ -4,14 +4,14 @@
use dom::bindings::codegen::Bindings::BluetoothCharacteristicPropertiesBinding; use dom::bindings::codegen::Bindings::BluetoothCharacteristicPropertiesBinding;
use dom::bindings::codegen::Bindings::BluetoothCharacteristicPropertiesBinding:: use dom::bindings::codegen::Bindings::BluetoothCharacteristicPropertiesBinding::
BluetoothCharacteristicPropertiesMethods; BluetoothCharacteristicPropertiesMethods;
use dom::bindings::reflector::{Reflector, reflect_dom_object}; use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::bindings::root::DomRoot; use dom::bindings::root::DomRoot;
use dom::globalscope::GlobalScope; use dom::globalscope::GlobalScope;
use dom_struct::dom_struct; use dom_struct::dom_struct;
// https://webbluetoothcg.github.io/web-bluetooth/#characteristicproperties // https://webbluetoothcg.github.io/web-bluetooth/#characteristicproperties
#[dom_struct] #[dom_struct]
pub struct BluetoothCharacteristicProperties { pub struct BluetoothCharacteristicProperties {
reflector_: Reflector, reflector_: Reflector,
broadcast: bool, broadcast: bool,
@ -26,7 +26,8 @@ pub struct BluetoothCharacteristicProperties {
} }
impl BluetoothCharacteristicProperties { impl BluetoothCharacteristicProperties {
pub fn new_inherited(broadcast: bool, pub fn new_inherited(
broadcast: bool,
read: bool, read: bool,
write_without_response: bool, write_without_response: bool,
write: bool, write: bool,
@ -34,8 +35,8 @@ impl BluetoothCharacteristicProperties {
indicate: bool, indicate: bool,
authenticated_signed_writes: bool, authenticated_signed_writes: bool,
reliable_write: bool, reliable_write: bool,
writable_auxiliaries: bool) writable_auxiliaries: bool,
-> BluetoothCharacteristicProperties { ) -> BluetoothCharacteristicProperties {
BluetoothCharacteristicProperties { BluetoothCharacteristicProperties {
reflector_: Reflector::new(), reflector_: Reflector::new(),
broadcast: broadcast, broadcast: broadcast,
@ -50,7 +51,8 @@ impl BluetoothCharacteristicProperties {
} }
} }
pub fn new(global: &GlobalScope, pub fn new(
global: &GlobalScope,
broadcast: bool, broadcast: bool,
read: bool, read: bool,
writeWithoutResponse: bool, writeWithoutResponse: bool,
@ -59,8 +61,8 @@ impl BluetoothCharacteristicProperties {
indicate: bool, indicate: bool,
authenticatedSignedWrites: bool, authenticatedSignedWrites: bool,
reliableWrite: bool, reliableWrite: bool,
writableAuxiliaries: bool) writableAuxiliaries: bool,
-> DomRoot<BluetoothCharacteristicProperties> { ) -> DomRoot<BluetoothCharacteristicProperties> {
reflect_dom_object( reflect_dom_object(
Box::new(BluetoothCharacteristicProperties::new_inherited( Box::new(BluetoothCharacteristicProperties::new_inherited(
broadcast, broadcast,
@ -71,10 +73,10 @@ impl BluetoothCharacteristicProperties {
indicate, indicate,
authenticatedSignedWrites, authenticatedSignedWrites,
reliableWrite, reliableWrite,
writableAuxiliaries writableAuxiliaries,
)), )),
global, global,
BluetoothCharacteristicPropertiesBinding::Wrap BluetoothCharacteristicPropertiesBinding::Wrap,
) )
} }
} }

View file

@ -38,79 +38,90 @@ pub struct BluetoothDevice {
name: Option<DOMString>, name: Option<DOMString>,
gatt: MutNullableDom<BluetoothRemoteGATTServer>, gatt: MutNullableDom<BluetoothRemoteGATTServer>,
context: Dom<Bluetooth>, context: Dom<Bluetooth>,
attribute_instance_map: (DomRefCell<HashMap<String, Dom<BluetoothRemoteGATTService>>>, attribute_instance_map: (
DomRefCell<HashMap<String, Dom<BluetoothRemoteGATTService>>>,
DomRefCell<HashMap<String, Dom<BluetoothRemoteGATTCharacteristic>>>, DomRefCell<HashMap<String, Dom<BluetoothRemoteGATTCharacteristic>>>,
DomRefCell<HashMap<String, Dom<BluetoothRemoteGATTDescriptor>>>), DomRefCell<HashMap<String, Dom<BluetoothRemoteGATTDescriptor>>>,
),
watching_advertisements: Cell<bool>, watching_advertisements: Cell<bool>,
} }
impl BluetoothDevice { impl BluetoothDevice {
pub fn new_inherited(id: DOMString, pub fn new_inherited(
id: DOMString,
name: Option<DOMString>, name: Option<DOMString>,
context: &Bluetooth) context: &Bluetooth,
-> BluetoothDevice { ) -> BluetoothDevice {
BluetoothDevice { BluetoothDevice {
eventtarget: EventTarget::new_inherited(), eventtarget: EventTarget::new_inherited(),
id: id, id: id,
name: name, name: name,
gatt: Default::default(), gatt: Default::default(),
context: Dom::from_ref(context), context: Dom::from_ref(context),
attribute_instance_map: (DomRefCell::new(HashMap::new()), attribute_instance_map: (
DomRefCell::new(HashMap::new()), DomRefCell::new(HashMap::new()),
DomRefCell::new(HashMap::new())), DomRefCell::new(HashMap::new()),
DomRefCell::new(HashMap::new()),
),
watching_advertisements: Cell::new(false), watching_advertisements: Cell::new(false),
} }
} }
pub fn new(global: &GlobalScope, pub fn new(
global: &GlobalScope,
id: DOMString, id: DOMString,
name: Option<DOMString>, name: Option<DOMString>,
context: &Bluetooth) context: &Bluetooth,
-> DomRoot<BluetoothDevice> { ) -> DomRoot<BluetoothDevice> {
reflect_dom_object(Box::new(BluetoothDevice::new_inherited(id, name, context)), reflect_dom_object(
Box::new(BluetoothDevice::new_inherited(id, name, context)),
global, global,
BluetoothDeviceBinding::Wrap) BluetoothDeviceBinding::Wrap,
)
} }
pub fn get_gatt(&self) -> DomRoot<BluetoothRemoteGATTServer> { pub fn get_gatt(&self) -> DomRoot<BluetoothRemoteGATTServer> {
self.gatt.or_init(|| { self.gatt
BluetoothRemoteGATTServer::new(&self.global(), self) .or_init(|| BluetoothRemoteGATTServer::new(&self.global(), self))
})
} }
fn get_context(&self) -> DomRoot<Bluetooth> { fn get_context(&self) -> DomRoot<Bluetooth> {
DomRoot::from_ref(&self.context) DomRoot::from_ref(&self.context)
} }
pub fn get_or_create_service(&self, pub fn get_or_create_service(
&self,
service: &BluetoothServiceMsg, service: &BluetoothServiceMsg,
server: &BluetoothRemoteGATTServer) server: &BluetoothRemoteGATTServer,
-> DomRoot<BluetoothRemoteGATTService> { ) -> DomRoot<BluetoothRemoteGATTService> {
let (ref service_map_ref, _, _) = self.attribute_instance_map; let (ref service_map_ref, _, _) = self.attribute_instance_map;
let mut service_map = service_map_ref.borrow_mut(); let mut service_map = service_map_ref.borrow_mut();
if let Some(existing_service) = service_map.get(&service.instance_id) { if let Some(existing_service) = service_map.get(&service.instance_id) {
return DomRoot::from_ref(&existing_service); return DomRoot::from_ref(&existing_service);
} }
let bt_service = BluetoothRemoteGATTService::new(&server.global(), let bt_service = BluetoothRemoteGATTService::new(
&server.global(),
&server.Device(), &server.Device(),
DOMString::from(service.uuid.clone()), DOMString::from(service.uuid.clone()),
service.is_primary, service.is_primary,
service.instance_id.clone()); service.instance_id.clone(),
);
service_map.insert(service.instance_id.clone(), Dom::from_ref(&bt_service)); service_map.insert(service.instance_id.clone(), Dom::from_ref(&bt_service));
return bt_service; return bt_service;
} }
pub fn get_or_create_characteristic(&self, pub fn get_or_create_characteristic(
&self,
characteristic: &BluetoothCharacteristicMsg, characteristic: &BluetoothCharacteristicMsg,
service: &BluetoothRemoteGATTService) service: &BluetoothRemoteGATTService,
-> DomRoot<BluetoothRemoteGATTCharacteristic> { ) -> DomRoot<BluetoothRemoteGATTCharacteristic> {
let (_, ref characteristic_map_ref, _) = self.attribute_instance_map; let (_, ref characteristic_map_ref, _) = self.attribute_instance_map;
let mut characteristic_map = characteristic_map_ref.borrow_mut(); let mut characteristic_map = characteristic_map_ref.borrow_mut();
if let Some(existing_characteristic) = characteristic_map.get(&characteristic.instance_id) { if let Some(existing_characteristic) = characteristic_map.get(&characteristic.instance_id) {
return DomRoot::from_ref(&existing_characteristic); return DomRoot::from_ref(&existing_characteristic);
} }
let properties = let properties = BluetoothCharacteristicProperties::new(
BluetoothCharacteristicProperties::new(&service.global(), &service.global(),
characteristic.broadcast, characteristic.broadcast,
characteristic.read, characteristic.read,
characteristic.write_without_response, characteristic.write_without_response,
@ -119,37 +130,52 @@ impl BluetoothDevice {
characteristic.indicate, characteristic.indicate,
characteristic.authenticated_signed_writes, characteristic.authenticated_signed_writes,
characteristic.reliable_write, characteristic.reliable_write,
characteristic.writable_auxiliaries); characteristic.writable_auxiliaries,
let bt_characteristic = BluetoothRemoteGATTCharacteristic::new(&service.global(), );
let bt_characteristic = BluetoothRemoteGATTCharacteristic::new(
&service.global(),
service, service,
DOMString::from(characteristic.uuid.clone()), DOMString::from(characteristic.uuid.clone()),
&properties, &properties,
characteristic.instance_id.clone()); characteristic.instance_id.clone(),
characteristic_map.insert(characteristic.instance_id.clone(), Dom::from_ref(&bt_characteristic)); );
characteristic_map.insert(
characteristic.instance_id.clone(),
Dom::from_ref(&bt_characteristic),
);
return bt_characteristic; return bt_characteristic;
} }
pub fn is_represented_device_null(&self) -> bool { pub fn is_represented_device_null(&self) -> bool {
let (sender, receiver) = ipc::channel(self.global().time_profiler_chan().clone()).unwrap(); let (sender, receiver) = ipc::channel(self.global().time_profiler_chan().clone()).unwrap();
self.get_bluetooth_thread().send( self.get_bluetooth_thread()
BluetoothRequest::IsRepresentedDeviceNull(self.Id().to_string(), sender)).unwrap(); .send(BluetoothRequest::IsRepresentedDeviceNull(
self.Id().to_string(),
sender,
)).unwrap();
receiver.recv().unwrap() receiver.recv().unwrap()
} }
pub fn get_or_create_descriptor(&self, pub fn get_or_create_descriptor(
&self,
descriptor: &BluetoothDescriptorMsg, descriptor: &BluetoothDescriptorMsg,
characteristic: &BluetoothRemoteGATTCharacteristic) characteristic: &BluetoothRemoteGATTCharacteristic,
-> DomRoot<BluetoothRemoteGATTDescriptor> { ) -> DomRoot<BluetoothRemoteGATTDescriptor> {
let (_, _, ref descriptor_map_ref) = self.attribute_instance_map; let (_, _, ref descriptor_map_ref) = self.attribute_instance_map;
let mut descriptor_map = descriptor_map_ref.borrow_mut(); let mut descriptor_map = descriptor_map_ref.borrow_mut();
if let Some(existing_descriptor) = descriptor_map.get(&descriptor.instance_id) { if let Some(existing_descriptor) = descriptor_map.get(&descriptor.instance_id) {
return DomRoot::from_ref(&existing_descriptor); return DomRoot::from_ref(&existing_descriptor);
} }
let bt_descriptor = BluetoothRemoteGATTDescriptor::new(&characteristic.global(), let bt_descriptor = BluetoothRemoteGATTDescriptor::new(
&characteristic.global(),
characteristic, characteristic,
DOMString::from(descriptor.uuid.clone()), DOMString::from(descriptor.uuid.clone()),
descriptor.instance_id.clone()); descriptor.instance_id.clone(),
descriptor_map.insert(descriptor.instance_id.clone(), Dom::from_ref(&bt_descriptor)); );
descriptor_map.insert(
descriptor.instance_id.clone(),
Dom::from_ref(&bt_descriptor),
);
return bt_descriptor; return bt_descriptor;
} }
@ -180,11 +206,17 @@ impl BluetoothDevice {
// Step 5, 6.4, 7. // Step 5, 6.4, 7.
// TODO: Step 6: Implement `active notification context set` for BluetoothRemoteGATTCharacteristic. // TODO: Step 6: Implement `active notification context set` for BluetoothRemoteGATTCharacteristic.
let _ = self.get_bluetooth_thread().send( let _ = self
BluetoothRequest::SetRepresentedToNull(service_ids, characteristic_ids, descriptor_ids)); .get_bluetooth_thread()
.send(BluetoothRequest::SetRepresentedToNull(
service_ids,
characteristic_ids,
descriptor_ids,
));
// Step 8. // Step 8.
self.upcast::<EventTarget>().fire_bubbling_event(atom!("gattserverdisconnected")); self.upcast::<EventTarget>()
.fire_bubbling_event(atom!("gattserverdisconnected"));
} }
// https://webbluetoothcg.github.io/web-bluetooth/#garbage-collect-the-connection // https://webbluetoothcg.github.io/web-bluetooth/#garbage-collect-the-connection
@ -206,8 +238,11 @@ impl BluetoothDevice {
// Step 3. // Step 3.
let (sender, receiver) = ipc::channel(self.global().time_profiler_chan().clone()).unwrap(); let (sender, receiver) = ipc::channel(self.global().time_profiler_chan().clone()).unwrap();
self.get_bluetooth_thread().send( self.get_bluetooth_thread()
BluetoothRequest::GATTServerDisconnect(String::from(self.Id()), sender)).unwrap(); .send(BluetoothRequest::GATTServerDisconnect(
String::from(self.Id()),
sender,
)).unwrap();
receiver.recv().unwrap().map_err(Error::from) receiver.recv().unwrap().map_err(Error::from)
} }
} }
@ -226,9 +261,14 @@ impl BluetoothDeviceMethods for BluetoothDevice {
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdevice-gatt // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdevice-gatt
fn GetGatt(&self) -> Option<DomRoot<BluetoothRemoteGATTServer>> { fn GetGatt(&self) -> Option<DomRoot<BluetoothRemoteGATTServer>> {
// Step 1. // Step 1.
if self.global().as_window().bluetooth_extra_permission_data() if self
.allowed_devices_contains_id(self.id.clone()) && !self.is_represented_device_null() { .global()
return Some(self.get_gatt()) .as_window()
.bluetooth_extra_permission_data()
.allowed_devices_contains_id(self.id.clone()) &&
!self.is_represented_device_null()
{
return Some(self.get_gatt());
} }
// Step 2. // Step 2.
None None
@ -242,8 +282,11 @@ impl BluetoothDeviceMethods for BluetoothDevice {
// TODO: Step 1. // TODO: Step 1.
// Note: Steps 2 - 3 are implemented in components/bluetooth/lib.rs in watch_advertisements function // Note: Steps 2 - 3 are implemented in components/bluetooth/lib.rs in watch_advertisements function
// and in handle_response function. // and in handle_response function.
self.get_bluetooth_thread().send( self.get_bluetooth_thread()
BluetoothRequest::WatchAdvertisements(String::from(self.Id()), sender)).unwrap(); .send(BluetoothRequest::WatchAdvertisements(
String::from(self.Id()),
sender,
)).unwrap();
return p; return p;
} }
@ -260,7 +303,11 @@ impl BluetoothDeviceMethods for BluetoothDevice {
} }
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdeviceeventhandlers-ongattserverdisconnected // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdeviceeventhandlers-ongattserverdisconnected
event_handler!(gattserverdisconnected, GetOngattserverdisconnected, SetOngattserverdisconnected); event_handler!(
gattserverdisconnected,
GetOngattserverdisconnected,
SetOngattserverdisconnected
);
} }
impl AsyncBluetoothListener for BluetoothDevice { impl AsyncBluetoothListener for BluetoothDevice {

View file

@ -40,10 +40,15 @@ impl BluetoothPermissionResult {
result result
} }
pub fn new(global: &GlobalScope, status: &PermissionStatus) -> DomRoot<BluetoothPermissionResult> { pub fn new(
reflect_dom_object(Box::new(BluetoothPermissionResult::new_inherited(status)), global: &GlobalScope,
status: &PermissionStatus,
) -> DomRoot<BluetoothPermissionResult> {
reflect_dom_object(
Box::new(BluetoothPermissionResult::new_inherited(status)),
global, global,
BluetoothPermissionResultBinding::Wrap) BluetoothPermissionResultBinding::Wrap,
)
} }
pub fn get_bluetooth(&self) -> DomRoot<Bluetooth> { pub fn get_bluetooth(&self) -> DomRoot<Bluetooth> {
@ -75,8 +80,12 @@ impl BluetoothPermissionResult {
impl BluetoothPermissionResultMethods for BluetoothPermissionResult { impl BluetoothPermissionResultMethods for BluetoothPermissionResult {
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothpermissionresult-devices // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothpermissionresult-devices
fn Devices(&self) -> Vec<DomRoot<BluetoothDevice>> { fn Devices(&self) -> Vec<DomRoot<BluetoothDevice>> {
let device_vec: Vec<DomRoot<BluetoothDevice>> = let device_vec: Vec<DomRoot<BluetoothDevice>> = self
self.devices.borrow().iter().map(|d| DomRoot::from_ref(&**d)).collect(); .devices
.borrow()
.iter()
.map(|d| DomRoot::from_ref(&**d))
.collect();
device_vec device_vec
} }
} }
@ -93,26 +102,29 @@ impl AsyncBluetoothListener for BluetoothPermissionResult {
if let Some(ref existing_device) = device_instance_map.get(&device.id) { if let Some(ref existing_device) = device_instance_map.get(&device.id) {
// https://webbluetoothcg.github.io/web-bluetooth/#request-the-bluetooth-permission // https://webbluetoothcg.github.io/web-bluetooth/#request-the-bluetooth-permission
// Step 3. // Step 3.
self.set_devices(vec!(Dom::from_ref(&*existing_device))); self.set_devices(vec![Dom::from_ref(&*existing_device)]);
// https://w3c.github.io/permissions/#dom-permissions-request // https://w3c.github.io/permissions/#dom-permissions-request
// Step 8. // Step 8.
return promise.resolve_native(self); return promise.resolve_native(self);
} }
let bt_device = BluetoothDevice::new(&self.global(), let bt_device = BluetoothDevice::new(
&self.global(),
DOMString::from(device.id.clone()), DOMString::from(device.id.clone()),
device.name.map(DOMString::from), device.name.map(DOMString::from),
&bluetooth); &bluetooth,
);
device_instance_map.insert(device.id.clone(), Dom::from_ref(&bt_device)); device_instance_map.insert(device.id.clone(), Dom::from_ref(&bt_device));
self.global().as_window().bluetooth_extra_permission_data().add_new_allowed_device( self.global()
AllowedBluetoothDevice { .as_window()
.bluetooth_extra_permission_data()
.add_new_allowed_device(AllowedBluetoothDevice {
deviceId: DOMString::from(device.id), deviceId: DOMString::from(device.id),
mayUseGATT: true, mayUseGATT: true,
} });
);
// https://webbluetoothcg.github.io/web-bluetooth/#request-the-bluetooth-permission // https://webbluetoothcg.github.io/web-bluetooth/#request-the-bluetooth-permission
// Step 3. // Step 3.
self.set_devices(vec!(Dom::from_ref(&bt_device))); self.set_devices(vec![Dom::from_ref(&bt_device)]);
// https://w3c.github.io/permissions/#dom-permissions-request // https://w3c.github.io/permissions/#dom-permissions-request
// Step 8. // Step 8.

View file

@ -6,10 +6,10 @@ use bluetooth_traits::{BluetoothRequest, BluetoothResponse, GATTType};
use bluetooth_traits::blocklist::{Blocklist, uuid_is_blocklisted}; use bluetooth_traits::blocklist::{Blocklist, uuid_is_blocklisted};
use dom::bindings::cell::DomRefCell; use dom::bindings::cell::DomRefCell;
use dom::bindings::codegen::Bindings::BluetoothCharacteristicPropertiesBinding:: use dom::bindings::codegen::Bindings::BluetoothCharacteristicPropertiesBinding::
BluetoothCharacteristicPropertiesMethods; BluetoothCharacteristicPropertiesMethods;
use dom::bindings::codegen::Bindings::BluetoothRemoteGATTCharacteristicBinding; use dom::bindings::codegen::Bindings::BluetoothRemoteGATTCharacteristicBinding;
use dom::bindings::codegen::Bindings::BluetoothRemoteGATTCharacteristicBinding:: use dom::bindings::codegen::Bindings::BluetoothRemoteGATTCharacteristicBinding::
BluetoothRemoteGATTCharacteristicMethods; BluetoothRemoteGATTCharacteristicMethods;
use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServerBinding::BluetoothRemoteGATTServerMethods; use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServerBinding::BluetoothRemoteGATTServerMethods;
use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServiceBinding::BluetoothRemoteGATTServiceMethods; use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServiceBinding::BluetoothRemoteGATTServiceMethods;
use dom::bindings::codegen::UnionTypes::ArrayBufferViewOrArrayBuffer; use dom::bindings::codegen::UnionTypes::ArrayBufferViewOrArrayBuffer;
@ -45,11 +45,12 @@ pub struct BluetoothRemoteGATTCharacteristic {
} }
impl BluetoothRemoteGATTCharacteristic { impl BluetoothRemoteGATTCharacteristic {
pub fn new_inherited(service: &BluetoothRemoteGATTService, pub fn new_inherited(
service: &BluetoothRemoteGATTService,
uuid: DOMString, uuid: DOMString,
properties: &BluetoothCharacteristicProperties, properties: &BluetoothCharacteristicProperties,
instance_id: String) instance_id: String,
-> BluetoothRemoteGATTCharacteristic { ) -> BluetoothRemoteGATTCharacteristic {
BluetoothRemoteGATTCharacteristic { BluetoothRemoteGATTCharacteristic {
eventtarget: EventTarget::new_inherited(), eventtarget: EventTarget::new_inherited(),
service: Dom::from_ref(service), service: Dom::from_ref(service),
@ -60,18 +61,19 @@ impl BluetoothRemoteGATTCharacteristic {
} }
} }
pub fn new(global: &GlobalScope, pub fn new(
global: &GlobalScope,
service: &BluetoothRemoteGATTService, service: &BluetoothRemoteGATTService,
uuid: DOMString, uuid: DOMString,
properties: &BluetoothCharacteristicProperties, properties: &BluetoothCharacteristicProperties,
instanceID: String) instanceID: String,
-> DomRoot<BluetoothRemoteGATTCharacteristic> { ) -> DomRoot<BluetoothRemoteGATTCharacteristic> {
reflect_dom_object( reflect_dom_object(
Box::new(BluetoothRemoteGATTCharacteristic::new_inherited( Box::new(BluetoothRemoteGATTCharacteristic::new_inherited(
service, uuid, properties, instanceID service, uuid, properties, instanceID,
)), )),
global, global,
BluetoothRemoteGATTCharacteristicBinding::Wrap BluetoothRemoteGATTCharacteristicBinding::Wrap,
) )
} }
@ -103,17 +105,29 @@ impl BluetoothRemoteGATTCharacteristicMethods for BluetoothRemoteGATTCharacteris
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-getdescriptor // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-getdescriptor
fn GetDescriptor(&self, descriptor: BluetoothDescriptorUUID) -> Rc<Promise> { fn GetDescriptor(&self, descriptor: BluetoothDescriptorUUID) -> Rc<Promise> {
get_gatt_children(self, true, BluetoothUUID::descriptor, Some(descriptor), self.get_instance_id(), get_gatt_children(
self.Service().Device().get_gatt().Connected(), GATTType::Descriptor) self,
true,
BluetoothUUID::descriptor,
Some(descriptor),
self.get_instance_id(),
self.Service().Device().get_gatt().Connected(),
GATTType::Descriptor,
)
} }
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-getdescriptors // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-getdescriptors
fn GetDescriptors(&self, fn GetDescriptors(&self, descriptor: Option<BluetoothDescriptorUUID>) -> Rc<Promise> {
descriptor: Option<BluetoothDescriptorUUID>) get_gatt_children(
-> Rc<Promise> { self,
get_gatt_children(self, false, BluetoothUUID::descriptor, descriptor, self.get_instance_id(), false,
self.Service().Device().get_gatt().Connected(), GATTType::Descriptor) BluetoothUUID::descriptor,
descriptor,
self.get_instance_id(),
self.Service().Device().get_gatt().Connected(),
GATTType::Descriptor,
)
} }
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-value // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-value
@ -149,8 +163,9 @@ impl BluetoothRemoteGATTCharacteristicMethods for BluetoothRemoteGATTCharacteris
// Note: Steps 3 - 4 and the remaining substeps of Step 5 are implemented in components/bluetooth/lib.rs // Note: Steps 3 - 4 and the remaining substeps of Step 5 are implemented in components/bluetooth/lib.rs
// in readValue function and in handle_response function. // in readValue function and in handle_response function.
let sender = response_async(&p, self); let sender = response_async(&p, self);
self.get_bluetooth_thread().send( self.get_bluetooth_thread()
BluetoothRequest::ReadValue(self.get_instance_id(), sender)).unwrap(); .send(BluetoothRequest::ReadValue(self.get_instance_id(), sender))
.unwrap();
return p; return p;
} }
@ -187,7 +202,8 @@ impl BluetoothRemoteGATTCharacteristicMethods for BluetoothRemoteGATTCharacteris
// Step 7.1. // Step 7.1.
if !(self.Properties().Write() || if !(self.Properties().Write() ||
self.Properties().WriteWithoutResponse() || self.Properties().WriteWithoutResponse() ||
self.Properties().AuthenticatedSignedWrites()) { self.Properties().AuthenticatedSignedWrites())
{
p.reject_error(NotSupported); p.reject_error(NotSupported);
return p; return p;
} }
@ -195,8 +211,12 @@ impl BluetoothRemoteGATTCharacteristicMethods for BluetoothRemoteGATTCharacteris
// Note: Steps 5 - 6 and the remaining substeps of Step 7 are implemented in components/bluetooth/lib.rs // Note: Steps 5 - 6 and the remaining substeps of Step 7 are implemented in components/bluetooth/lib.rs
// in writeValue function and in handle_response function. // in writeValue function and in handle_response function.
let sender = response_async(&p, self); let sender = response_async(&p, self);
self.get_bluetooth_thread().send( self.get_bluetooth_thread()
BluetoothRequest::WriteValue(self.get_instance_id(), vec, sender)).unwrap(); .send(BluetoothRequest::WriteValue(
self.get_instance_id(),
vec,
sender,
)).unwrap();
return p; return p;
} }
@ -218,8 +238,7 @@ impl BluetoothRemoteGATTCharacteristicMethods for BluetoothRemoteGATTCharacteris
} }
// Step 5. // Step 5.
if !(self.Properties().Notify() || if !(self.Properties().Notify() || self.Properties().Indicate()) {
self.Properties().Indicate()) {
p.reject_error(NotSupported); p.reject_error(NotSupported);
return p; return p;
} }
@ -229,10 +248,12 @@ impl BluetoothRemoteGATTCharacteristicMethods for BluetoothRemoteGATTCharacteris
// Note: Steps 3 - 4, 7 - 11 are implemented in components/bluetooth/lib.rs in enable_notification function // Note: Steps 3 - 4, 7 - 11 are implemented in components/bluetooth/lib.rs in enable_notification function
// and in handle_response function. // and in handle_response function.
let sender = response_async(&p, self); let sender = response_async(&p, self);
self.get_bluetooth_thread().send( self.get_bluetooth_thread()
BluetoothRequest::EnableNotification(self.get_instance_id(), .send(BluetoothRequest::EnableNotification(
self.get_instance_id(),
true, true,
sender)).unwrap(); sender,
)).unwrap();
return p; return p;
} }
@ -246,15 +267,21 @@ impl BluetoothRemoteGATTCharacteristicMethods for BluetoothRemoteGATTCharacteris
// Note: Steps 1 - 2, and part of Step 4 and Step 5 are implemented in components/bluetooth/lib.rs // Note: Steps 1 - 2, and part of Step 4 and Step 5 are implemented in components/bluetooth/lib.rs
// in enable_notification function and in handle_response function. // in enable_notification function and in handle_response function.
self.get_bluetooth_thread().send( self.get_bluetooth_thread()
BluetoothRequest::EnableNotification(self.get_instance_id(), .send(BluetoothRequest::EnableNotification(
self.get_instance_id(),
false, false,
sender)).unwrap(); sender,
)).unwrap();
return p; return p;
} }
// https://webbluetoothcg.github.io/web-bluetooth/#dom-characteristiceventhandlers-oncharacteristicvaluechanged // https://webbluetoothcg.github.io/web-bluetooth/#dom-characteristiceventhandlers-oncharacteristicvaluechanged
event_handler!(characteristicvaluechanged, GetOncharacteristicvaluechanged, SetOncharacteristicvaluechanged); event_handler!(
characteristicvaluechanged,
GetOncharacteristicvaluechanged,
SetOncharacteristicvaluechanged
);
} }
impl AsyncBluetoothListener for BluetoothRemoteGATTCharacteristic { impl AsyncBluetoothListener for BluetoothRemoteGATTCharacteristic {
@ -265,10 +292,12 @@ impl AsyncBluetoothListener for BluetoothRemoteGATTCharacteristic {
// Step 7. // Step 7.
BluetoothResponse::GetDescriptors(descriptors_vec, single) => { BluetoothResponse::GetDescriptors(descriptors_vec, single) => {
if single { if single {
promise.resolve_native(&device.get_or_create_descriptor(&descriptors_vec[0], &self)); promise.resolve_native(
&device.get_or_create_descriptor(&descriptors_vec[0], &self),
);
return; return;
} }
let mut descriptors = vec!(); let mut descriptors = vec![];
for descriptor in descriptors_vec { for descriptor in descriptors_vec {
let bt_descriptor = device.get_or_create_descriptor(&descriptor, &self); let bt_descriptor = device.get_or_create_descriptor(&descriptor, &self);
descriptors.push(bt_descriptor); descriptors.push(bt_descriptor);
@ -285,7 +314,8 @@ impl AsyncBluetoothListener for BluetoothRemoteGATTCharacteristic {
*self.value.borrow_mut() = Some(value.clone()); *self.value.borrow_mut() = Some(value.clone());
// Step 5.5.3. // Step 5.5.3.
self.upcast::<EventTarget>().fire_bubbling_event(atom!("characteristicvaluechanged")); self.upcast::<EventTarget>()
.fire_bubbling_event(atom!("characteristicvaluechanged"));
// Step 5.5.4. // Step 5.5.4.
promise.resolve_native(&value); promise.resolve_native(&value);

View file

@ -6,7 +6,7 @@ use bluetooth_traits::{BluetoothRequest, BluetoothResponse};
use bluetooth_traits::blocklist::{Blocklist, uuid_is_blocklisted}; use bluetooth_traits::blocklist::{Blocklist, uuid_is_blocklisted};
use dom::bindings::cell::DomRefCell; use dom::bindings::cell::DomRefCell;
use dom::bindings::codegen::Bindings::BluetoothRemoteGATTCharacteristicBinding:: use dom::bindings::codegen::Bindings::BluetoothRemoteGATTCharacteristicBinding::
BluetoothRemoteGATTCharacteristicMethods; BluetoothRemoteGATTCharacteristicMethods;
use dom::bindings::codegen::Bindings::BluetoothRemoteGATTDescriptorBinding; use dom::bindings::codegen::Bindings::BluetoothRemoteGATTDescriptorBinding;
use dom::bindings::codegen::Bindings::BluetoothRemoteGATTDescriptorBinding::BluetoothRemoteGATTDescriptorMethods; use dom::bindings::codegen::Bindings::BluetoothRemoteGATTDescriptorBinding::BluetoothRemoteGATTDescriptorMethods;
use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServerBinding::BluetoothRemoteGATTServerMethods; use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServerBinding::BluetoothRemoteGATTServerMethods;
@ -35,10 +35,11 @@ pub struct BluetoothRemoteGATTDescriptor {
} }
impl BluetoothRemoteGATTDescriptor { impl BluetoothRemoteGATTDescriptor {
pub fn new_inherited(characteristic: &BluetoothRemoteGATTCharacteristic, pub fn new_inherited(
characteristic: &BluetoothRemoteGATTCharacteristic,
uuid: DOMString, uuid: DOMString,
instance_id: String) instance_id: String,
-> BluetoothRemoteGATTDescriptor { ) -> BluetoothRemoteGATTDescriptor {
BluetoothRemoteGATTDescriptor { BluetoothRemoteGATTDescriptor {
reflector_: Reflector::new(), reflector_: Reflector::new(),
characteristic: Dom::from_ref(characteristic), characteristic: Dom::from_ref(characteristic),
@ -48,17 +49,20 @@ impl BluetoothRemoteGATTDescriptor {
} }
} }
pub fn new(global: &GlobalScope, pub fn new(
global: &GlobalScope,
characteristic: &BluetoothRemoteGATTCharacteristic, characteristic: &BluetoothRemoteGATTCharacteristic,
uuid: DOMString, uuid: DOMString,
instanceID: String) instanceID: String,
-> DomRoot<BluetoothRemoteGATTDescriptor>{ ) -> DomRoot<BluetoothRemoteGATTDescriptor> {
reflect_dom_object( reflect_dom_object(
Box::new(BluetoothRemoteGATTDescriptor::new_inherited( Box::new(BluetoothRemoteGATTDescriptor::new_inherited(
characteristic, uuid, instanceID characteristic,
uuid,
instanceID,
)), )),
global, global,
BluetoothRemoteGATTDescriptorBinding::Wrap BluetoothRemoteGATTDescriptorBinding::Wrap,
) )
} }
@ -99,7 +103,13 @@ impl BluetoothRemoteGATTDescriptorMethods for BluetoothRemoteGATTDescriptor {
} }
// Step 2. // Step 2.
if !self.Characteristic().Service().Device().get_gatt().Connected() { if !self
.Characteristic()
.Service()
.Device()
.get_gatt()
.Connected()
{
p.reject_error(Network); p.reject_error(Network);
return p; return p;
} }
@ -108,8 +118,9 @@ impl BluetoothRemoteGATTDescriptorMethods for BluetoothRemoteGATTDescriptor {
// Note: Steps 3 - 4 and substeps of Step 5 are implemented in components/bluetooth/lib.rs // Note: Steps 3 - 4 and substeps of Step 5 are implemented in components/bluetooth/lib.rs
// in readValue function and in handle_response function. // in readValue function and in handle_response function.
let sender = response_async(&p, self); let sender = response_async(&p, self);
self.get_bluetooth_thread().send( self.get_bluetooth_thread()
BluetoothRequest::ReadValue(self.get_instance_id(), sender)).unwrap(); .send(BluetoothRequest::ReadValue(self.get_instance_id(), sender))
.unwrap();
return p; return p;
} }
@ -135,7 +146,13 @@ impl BluetoothRemoteGATTDescriptorMethods for BluetoothRemoteGATTDescriptor {
} }
// Step 4. // Step 4.
if !self.Characteristic().Service().Device().get_gatt().Connected() { if !self
.Characteristic()
.Service()
.Device()
.get_gatt()
.Connected()
{
p.reject_error(Network); p.reject_error(Network);
return p; return p;
} }
@ -144,8 +161,12 @@ impl BluetoothRemoteGATTDescriptorMethods for BluetoothRemoteGATTDescriptor {
// Note: Steps 5 - 6 and substeps of Step 7 are implemented in components/bluetooth/lib.rs // Note: Steps 5 - 6 and substeps of Step 7 are implemented in components/bluetooth/lib.rs
// in writeValue function and in handle_response function. // in writeValue function and in handle_response function.
let sender = response_async(&p, self); let sender = response_async(&p, self);
self.get_bluetooth_thread().send( self.get_bluetooth_thread()
BluetoothRequest::WriteValue(self.get_instance_id(), vec, sender)).unwrap(); .send(BluetoothRequest::WriteValue(
self.get_instance_id(),
vec,
sender,
)).unwrap();
return p; return p;
} }
} }

View file

@ -37,10 +37,15 @@ impl BluetoothRemoteGATTServer {
} }
} }
pub fn new(global: &GlobalScope, device: &BluetoothDevice) -> DomRoot<BluetoothRemoteGATTServer> { pub fn new(
reflect_dom_object(Box::new(BluetoothRemoteGATTServer::new_inherited(device)), global: &GlobalScope,
device: &BluetoothDevice,
) -> DomRoot<BluetoothRemoteGATTServer> {
reflect_dom_object(
Box::new(BluetoothRemoteGATTServer::new_inherited(device)),
global, global,
BluetoothRemoteGATTServerBinding::Wrap) BluetoothRemoteGATTServerBinding::Wrap,
)
} }
fn get_bluetooth_thread(&self) -> IpcSender<BluetoothRequest> { fn get_bluetooth_thread(&self) -> IpcSender<BluetoothRequest> {
@ -78,8 +83,11 @@ impl BluetoothRemoteGATTServerMethods for BluetoothRemoteGATTServer {
// Note: Steps 2, 5.1.1 and 5.1.3 are in components/bluetooth/lib.rs in the gatt_server_connect function. // Note: Steps 2, 5.1.1 and 5.1.3 are in components/bluetooth/lib.rs in the gatt_server_connect function.
// Steps 5.2.3 - 5.2.5 are in response function. // Steps 5.2.3 - 5.2.5 are in response function.
self.get_bluetooth_thread().send( self.get_bluetooth_thread()
BluetoothRequest::GATTServerConnect(String::from(self.Device().Id()), sender)).unwrap(); .send(BluetoothRequest::GATTServerConnect(
String::from(self.Device().Id()),
sender,
)).unwrap();
// Step 5: return promise. // Step 5: return promise.
return p; return p;
} }
@ -90,7 +98,7 @@ impl BluetoothRemoteGATTServerMethods for BluetoothRemoteGATTServer {
// Step 2. // Step 2.
if !self.Connected() { if !self.Connected() {
return Ok(()) return Ok(());
} }
// Step 3. // Step 3.
@ -104,17 +112,30 @@ impl BluetoothRemoteGATTServerMethods for BluetoothRemoteGATTServer {
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-getprimaryservice // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-getprimaryservice
fn GetPrimaryService(&self, service: BluetoothServiceUUID) -> Rc<Promise> { fn GetPrimaryService(&self, service: BluetoothServiceUUID) -> Rc<Promise> {
// Step 1 - 2. // Step 1 - 2.
get_gatt_children(self, true, BluetoothUUID::service, Some(service), String::from(self.Device().Id()), get_gatt_children(
self.Device().get_gatt().Connected(), GATTType::PrimaryService) self,
true,
BluetoothUUID::service,
Some(service),
String::from(self.Device().Id()),
self.Device().get_gatt().Connected(),
GATTType::PrimaryService,
)
} }
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-getprimaryservices // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-getprimaryservices
fn GetPrimaryServices(&self, service: Option<BluetoothServiceUUID>) -> Rc<Promise> { fn GetPrimaryServices(&self, service: Option<BluetoothServiceUUID>) -> Rc<Promise> {
// Step 1 - 2. // Step 1 - 2.
get_gatt_children(self, false, BluetoothUUID::service, service, String::from(self.Device().Id()), get_gatt_children(
self.Connected(), GATTType::PrimaryService) self,
false,
BluetoothUUID::service,
service,
String::from(self.Device().Id()),
self.Connected(),
GATTType::PrimaryService,
)
} }
} }
@ -145,7 +166,7 @@ impl AsyncBluetoothListener for BluetoothRemoteGATTServer {
promise.resolve_native(&device.get_or_create_service(&services_vec[0], &self)); promise.resolve_native(&device.get_or_create_service(&services_vec[0], &self));
return; return;
} }
let mut services = vec!(); let mut services = vec![];
for service in services_vec { for service in services_vec {
let bt_service = device.get_or_create_service(&service, &self); let bt_service = device.get_or_create_service(&service, &self);
services.push(bt_service); services.push(bt_service);

View file

@ -30,11 +30,12 @@ pub struct BluetoothRemoteGATTService {
} }
impl BluetoothRemoteGATTService { impl BluetoothRemoteGATTService {
pub fn new_inherited(device: &BluetoothDevice, pub fn new_inherited(
device: &BluetoothDevice,
uuid: DOMString, uuid: DOMString,
is_primary: bool, is_primary: bool,
instance_id: String) instance_id: String,
-> BluetoothRemoteGATTService { ) -> BluetoothRemoteGATTService {
BluetoothRemoteGATTService { BluetoothRemoteGATTService {
eventtarget: EventTarget::new_inherited(), eventtarget: EventTarget::new_inherited(),
device: Dom::from_ref(device), device: Dom::from_ref(device),
@ -44,18 +45,19 @@ impl BluetoothRemoteGATTService {
} }
} }
pub fn new(global: &GlobalScope, pub fn new(
global: &GlobalScope,
device: &BluetoothDevice, device: &BluetoothDevice,
uuid: DOMString, uuid: DOMString,
isPrimary: bool, isPrimary: bool,
instanceID: String) instanceID: String,
-> DomRoot<BluetoothRemoteGATTService> { ) -> DomRoot<BluetoothRemoteGATTService> {
reflect_dom_object( reflect_dom_object(
Box::new(BluetoothRemoteGATTService::new_inherited( Box::new(BluetoothRemoteGATTService::new_inherited(
device, uuid, isPrimary, instanceID device, uuid, isPrimary, instanceID,
)), )),
global, global,
BluetoothRemoteGATTServiceBinding::Wrap BluetoothRemoteGATTServiceBinding::Wrap,
) )
} }
@ -82,39 +84,61 @@ impl BluetoothRemoteGATTServiceMethods for BluetoothRemoteGATTService {
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getcharacteristic // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getcharacteristic
fn GetCharacteristic(&self, fn GetCharacteristic(&self, characteristic: BluetoothCharacteristicUUID) -> Rc<Promise> {
characteristic: BluetoothCharacteristicUUID) get_gatt_children(
-> Rc<Promise> { self,
get_gatt_children(self, true, BluetoothUUID::characteristic, Some(characteristic), self.get_instance_id(), true,
self.Device().get_gatt().Connected(), GATTType::Characteristic) BluetoothUUID::characteristic,
Some(characteristic),
self.get_instance_id(),
self.Device().get_gatt().Connected(),
GATTType::Characteristic,
)
} }
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getcharacteristics // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getcharacteristics
fn GetCharacteristics(&self, fn GetCharacteristics(
characteristic: Option<BluetoothCharacteristicUUID>) &self,
-> Rc<Promise> { characteristic: Option<BluetoothCharacteristicUUID>,
get_gatt_children(self, false, BluetoothUUID::characteristic, characteristic, self.get_instance_id(), ) -> Rc<Promise> {
self.Device().get_gatt().Connected(), GATTType::Characteristic) get_gatt_children(
self,
false,
BluetoothUUID::characteristic,
characteristic,
self.get_instance_id(),
self.Device().get_gatt().Connected(),
GATTType::Characteristic,
)
} }
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getincludedservice // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getincludedservice
fn GetIncludedService(&self, fn GetIncludedService(&self, service: BluetoothServiceUUID) -> Rc<Promise> {
service: BluetoothServiceUUID) get_gatt_children(
-> Rc<Promise> { self,
get_gatt_children(self, false, BluetoothUUID::service, Some(service), self.get_instance_id(), false,
self.Device().get_gatt().Connected(), GATTType::IncludedService) BluetoothUUID::service,
Some(service),
self.get_instance_id(),
self.Device().get_gatt().Connected(),
GATTType::IncludedService,
)
} }
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getincludedservices // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getincludedservices
fn GetIncludedServices(&self, fn GetIncludedServices(&self, service: Option<BluetoothServiceUUID>) -> Rc<Promise> {
service: Option<BluetoothServiceUUID>) get_gatt_children(
-> Rc<Promise> { self,
get_gatt_children(self, false, BluetoothUUID::service, service, self.get_instance_id(), false,
self.Device().get_gatt().Connected(), GATTType::IncludedService) BluetoothUUID::service,
service,
self.get_instance_id(),
self.Device().get_gatt().Connected(),
GATTType::IncludedService,
)
} }
// https://webbluetoothcg.github.io/web-bluetooth/#dom-serviceeventhandlers-onserviceadded // https://webbluetoothcg.github.io/web-bluetooth/#dom-serviceeventhandlers-onserviceadded
@ -135,12 +159,15 @@ impl AsyncBluetoothListener for BluetoothRemoteGATTService {
// Step 7. // Step 7.
BluetoothResponse::GetCharacteristics(characteristics_vec, single) => { BluetoothResponse::GetCharacteristics(characteristics_vec, single) => {
if single { if single {
promise.resolve_native(&device.get_or_create_characteristic(&characteristics_vec[0], &self)); promise.resolve_native(
&device.get_or_create_characteristic(&characteristics_vec[0], &self),
);
return; return;
} }
let mut characteristics = vec!(); let mut characteristics = vec![];
for characteristic in characteristics_vec { for characteristic in characteristics_vec {
let bt_characteristic = device.get_or_create_characteristic(&characteristic, &self); let bt_characteristic =
device.get_or_create_characteristic(&characteristic, &self);
characteristics.push(bt_characteristic); characteristics.push(bt_characteristic);
} }
promise.resolve_native(&characteristics); promise.resolve_native(&characteristics);
@ -149,9 +176,11 @@ impl AsyncBluetoothListener for BluetoothRemoteGATTService {
// Step 7. // Step 7.
BluetoothResponse::GetIncludedServices(services_vec, single) => { BluetoothResponse::GetIncludedServices(services_vec, single) => {
if single { if single {
return promise.resolve_native(&device.get_or_create_service(&services_vec[0], &device.get_gatt())); return promise.resolve_native(
&device.get_or_create_service(&services_vec[0], &device.get_gatt()),
);
} }
let mut services = vec!(); let mut services = vec![];
for service in services_vec { for service in services_vec {
let bt_service = device.get_or_create_service(&service, &device.get_gatt()); let bt_service = device.get_or_create_service(&service, &device.get_gatt());
services.push(bt_service); services.push(bt_service);

View file

@ -17,7 +17,7 @@ pub type BluetoothCharacteristicUUID = StringOrUnsignedLong;
pub type BluetoothDescriptorUUID = StringOrUnsignedLong; pub type BluetoothDescriptorUUID = StringOrUnsignedLong;
// https://webbluetoothcg.github.io/web-bluetooth/#bluetoothuuid // https://webbluetoothcg.github.io/web-bluetooth/#bluetoothuuid
#[dom_struct] #[dom_struct]
pub struct BluetoothUUID { pub struct BluetoothUUID {
reflector_: Reflector, reflector_: Reflector,
} }
@ -30,10 +30,16 @@ const BLUETOOTH_ASSIGNED_SERVICES: &'static [(&'static str, u32)] = &[
("org.bluetooth.service.blood_pressure", 0x1810_u32), ("org.bluetooth.service.blood_pressure", 0x1810_u32),
("org.bluetooth.service.body_composition", 0x181b_u32), ("org.bluetooth.service.body_composition", 0x181b_u32),
("org.bluetooth.service.bond_management", 0x181e_u32), ("org.bluetooth.service.bond_management", 0x181e_u32),
("org.bluetooth.service.continuous_glucose_monitoring", 0x181f_u32), (
"org.bluetooth.service.continuous_glucose_monitoring",
0x181f_u32,
),
("org.bluetooth.service.current_time", 0x1805_u32), ("org.bluetooth.service.current_time", 0x1805_u32),
("org.bluetooth.service.cycling_power", 0x1818_u32), ("org.bluetooth.service.cycling_power", 0x1818_u32),
("org.bluetooth.service.cycling_speed_and_cadence", 0x1816_u32), (
"org.bluetooth.service.cycling_speed_and_cadence",
0x1816_u32,
),
("org.bluetooth.service.device_information", 0x180a_u32), ("org.bluetooth.service.device_information", 0x180a_u32),
("org.bluetooth.service.environmental_sensing", 0x181a_u32), ("org.bluetooth.service.environmental_sensing", 0x181a_u32),
("org.bluetooth.service.generic_access", 0x1800_u32), ("org.bluetooth.service.generic_access", 0x1800_u32),
@ -45,7 +51,10 @@ const BLUETOOTH_ASSIGNED_SERVICES: &'static [(&'static str, u32)] = &[
("org.bluetooth.service.human_interface_device", 0x1812_u32), ("org.bluetooth.service.human_interface_device", 0x1812_u32),
("org.bluetooth.service.immediate_alert", 0x1802_u32), ("org.bluetooth.service.immediate_alert", 0x1802_u32),
("org.bluetooth.service.indoor_positioning", 0x1821_u32), ("org.bluetooth.service.indoor_positioning", 0x1821_u32),
("org.bluetooth.service.internet_protocol_support", 0x1820_u32), (
"org.bluetooth.service.internet_protocol_support",
0x1820_u32,
),
("org.bluetooth.service.link_loss", 0x1803_u32), ("org.bluetooth.service.link_loss", 0x1803_u32),
("org.bluetooth.service.location_and_navigation", 0x1819_u32), ("org.bluetooth.service.location_and_navigation", 0x1819_u32),
("org.bluetooth.service.next_dst_change", 0x1807_u32), ("org.bluetooth.service.next_dst_change", 0x1807_u32),
@ -53,7 +62,10 @@ const BLUETOOTH_ASSIGNED_SERVICES: &'static [(&'static str, u32)] = &[
("org.bluetooth.service.phone_alert_status", 0x180e_u32), ("org.bluetooth.service.phone_alert_status", 0x180e_u32),
("org.bluetooth.service.pulse_oximeter", 0x1822_u32), ("org.bluetooth.service.pulse_oximeter", 0x1822_u32),
("org.bluetooth.service.reference_time_update", 0x1806_u32), ("org.bluetooth.service.reference_time_update", 0x1806_u32),
("org.bluetooth.service.running_speed_and_cadence", 0x1814_u32), (
"org.bluetooth.service.running_speed_and_cadence",
0x1814_u32,
),
("org.bluetooth.service.scan_parameters", 0x1813_u32), ("org.bluetooth.service.scan_parameters", 0x1813_u32),
("org.bluetooth.service.transport_discovery", 0x1824), ("org.bluetooth.service.transport_discovery", 0x1824),
("org.bluetooth.service.tx_power", 0x1804_u32), ("org.bluetooth.service.tx_power", 0x1804_u32),
@ -63,57 +75,150 @@ const BLUETOOTH_ASSIGNED_SERVICES: &'static [(&'static str, u32)] = &[
//https://developer.bluetooth.org/gatt/services/Pages/ServicesHome.aspx //https://developer.bluetooth.org/gatt/services/Pages/ServicesHome.aspx
const BLUETOOTH_ASSIGNED_CHARCTERISTICS: &'static [(&'static str, u32)] = &[ const BLUETOOTH_ASSIGNED_CHARCTERISTICS: &'static [(&'static str, u32)] = &[
("org.bluetooth.characteristic.aerobic_heart_rate_lower_limit", 0x2a7e_u32), (
("org.bluetooth.characteristic.aerobic_heart_rate_upper_limit", 0x2a84_u32), "org.bluetooth.characteristic.aerobic_heart_rate_lower_limit",
0x2a7e_u32,
),
(
"org.bluetooth.characteristic.aerobic_heart_rate_upper_limit",
0x2a84_u32,
),
("org.bluetooth.characteristic.aerobic_threshold", 0x2a7f_u32), ("org.bluetooth.characteristic.aerobic_threshold", 0x2a7f_u32),
("org.bluetooth.characteristic.age", 0x2a80_u32), ("org.bluetooth.characteristic.age", 0x2a80_u32),
("org.bluetooth.characteristic.aggregate", 0x2a5a_u32), ("org.bluetooth.characteristic.aggregate", 0x2a5a_u32),
("org.bluetooth.characteristic.alert_category_id", 0x2a43_u32), ("org.bluetooth.characteristic.alert_category_id", 0x2a43_u32),
("org.bluetooth.characteristic.alert_category_id_bit_mask", 0x2a42_u32), (
"org.bluetooth.characteristic.alert_category_id_bit_mask",
0x2a42_u32,
),
("org.bluetooth.characteristic.alert_level", 0x2a06_u32), ("org.bluetooth.characteristic.alert_level", 0x2a06_u32),
("org.bluetooth.characteristic.alert_notification_control_point", 0x2a44_u32), (
"org.bluetooth.characteristic.alert_notification_control_point",
0x2a44_u32,
),
("org.bluetooth.characteristic.alert_status", 0x2a3f_u32), ("org.bluetooth.characteristic.alert_status", 0x2a3f_u32),
("org.bluetooth.characteristic.altitude", 0x2ab3_u32), ("org.bluetooth.characteristic.altitude", 0x2ab3_u32),
("org.bluetooth.characteristic.anaerobic_heart_rate_lower_limit", 0x2a81_u32), (
("org.bluetooth.characteristic.anaerobic_heart_rate_upper_limit", 0x2a82_u32), "org.bluetooth.characteristic.anaerobic_heart_rate_lower_limit",
("org.bluetooth.characteristic.anaerobic_threshold", 0x2a83_u32), 0x2a81_u32,
),
(
"org.bluetooth.characteristic.anaerobic_heart_rate_upper_limit",
0x2a82_u32,
),
(
"org.bluetooth.characteristic.anaerobic_threshold",
0x2a83_u32,
),
("org.bluetooth.characteristic.analog", 0x2a58_u32), ("org.bluetooth.characteristic.analog", 0x2a58_u32),
("org.bluetooth.characteristic.apparent_wind_direction", 0x2a73_u32), (
("org.bluetooth.characteristic.apparent_wind_speed", 0x2a72_u32), "org.bluetooth.characteristic.apparent_wind_direction",
0x2a73_u32,
),
(
"org.bluetooth.characteristic.apparent_wind_speed",
0x2a72_u32,
),
("org.bluetooth.characteristic.gap.appearance", 0x2a01_u32), ("org.bluetooth.characteristic.gap.appearance", 0x2a01_u32),
("org.bluetooth.characteristic.barometric_pressure_trend", 0x2aa3_u32), (
"org.bluetooth.characteristic.barometric_pressure_trend",
0x2aa3_u32,
),
("org.bluetooth.characteristic.battery_level", 0x2a19_u32), ("org.bluetooth.characteristic.battery_level", 0x2a19_u32),
("org.bluetooth.characteristic.blood_pressure_feature", 0x2a49_u32), (
("org.bluetooth.characteristic.blood_pressure_measurement", 0x2a35_u32), "org.bluetooth.characteristic.blood_pressure_feature",
("org.bluetooth.characteristic.body_composition_feature", 0x2a9b_u32), 0x2a49_u32,
("org.bluetooth.characteristic.body_composition_measurement", 0x2a9c_u32), ),
("org.bluetooth.characteristic.body_sensor_location", 0x2a38_u32), (
("org.bluetooth.characteristic.bond_management_control_point", 0x2aa4_u32), "org.bluetooth.characteristic.blood_pressure_measurement",
("org.bluetooth.characteristic.bond_management_feature", 0x2aa5_u32), 0x2a35_u32,
("org.bluetooth.characteristic.boot_keyboard_input_report", 0x2a22_u32), ),
("org.bluetooth.characteristic.boot_keyboard_output_report", 0x2a32_u32), (
("org.bluetooth.characteristic.boot_mouse_input_report", 0x2a33_u32), "org.bluetooth.characteristic.body_composition_feature",
("org.bluetooth.characteristic.gap.central_address_resolution_support", 0x2aa6_u32), 0x2a9b_u32,
),
(
"org.bluetooth.characteristic.body_composition_measurement",
0x2a9c_u32,
),
(
"org.bluetooth.characteristic.body_sensor_location",
0x2a38_u32,
),
(
"org.bluetooth.characteristic.bond_management_control_point",
0x2aa4_u32,
),
(
"org.bluetooth.characteristic.bond_management_feature",
0x2aa5_u32,
),
(
"org.bluetooth.characteristic.boot_keyboard_input_report",
0x2a22_u32,
),
(
"org.bluetooth.characteristic.boot_keyboard_output_report",
0x2a32_u32,
),
(
"org.bluetooth.characteristic.boot_mouse_input_report",
0x2a33_u32,
),
(
"org.bluetooth.characteristic.gap.central_address_resolution_support",
0x2aa6_u32,
),
("org.bluetooth.characteristic.cgm_feature", 0x2aa8_u32), ("org.bluetooth.characteristic.cgm_feature", 0x2aa8_u32),
("org.bluetooth.characteristic.cgm_measurement", 0x2aa7_u32), ("org.bluetooth.characteristic.cgm_measurement", 0x2aa7_u32),
("org.bluetooth.characteristic.cgm_session_run_time", 0x2aab_u32), (
("org.bluetooth.characteristic.cgm_session_start_time", 0x2aaa_u32), "org.bluetooth.characteristic.cgm_session_run_time",
("org.bluetooth.characteristic.cgm_specific_ops_control_point", 0x2aac_u32), 0x2aab_u32,
),
(
"org.bluetooth.characteristic.cgm_session_start_time",
0x2aaa_u32,
),
(
"org.bluetooth.characteristic.cgm_specific_ops_control_point",
0x2aac_u32,
),
("org.bluetooth.characteristic.cgm_status", 0x2aa9_u32), ("org.bluetooth.characteristic.cgm_status", 0x2aa9_u32),
("org.bluetooth.characteristic.csc_feature", 0x2a5c_u32), ("org.bluetooth.characteristic.csc_feature", 0x2a5c_u32),
("org.bluetooth.characteristic.csc_measurement", 0x2a5b_u32), ("org.bluetooth.characteristic.csc_measurement", 0x2a5b_u32),
("org.bluetooth.characteristic.current_time", 0x2a2b_u32), ("org.bluetooth.characteristic.current_time", 0x2a2b_u32),
("org.bluetooth.characteristic.cycling_power_control_point", 0x2a66_u32), (
("org.bluetooth.characteristic.cycling_power_feature", 0x2a65_u32), "org.bluetooth.characteristic.cycling_power_control_point",
("org.bluetooth.characteristic.cycling_power_measurement", 0x2a63_u32), 0x2a66_u32,
("org.bluetooth.characteristic.cycling_power_vector", 0x2a64_u32), ),
("org.bluetooth.characteristic.database_change_increment", 0x2a99_u32), (
"org.bluetooth.characteristic.cycling_power_feature",
0x2a65_u32,
),
(
"org.bluetooth.characteristic.cycling_power_measurement",
0x2a63_u32,
),
(
"org.bluetooth.characteristic.cycling_power_vector",
0x2a64_u32,
),
(
"org.bluetooth.characteristic.database_change_increment",
0x2a99_u32,
),
("org.bluetooth.characteristic.date_of_birth", 0x2a85_u32), ("org.bluetooth.characteristic.date_of_birth", 0x2a85_u32),
("org.bluetooth.characteristic.date_of_threshold_assessment", 0x2a86_u32), (
"org.bluetooth.characteristic.date_of_threshold_assessment",
0x2a86_u32,
),
("org.bluetooth.characteristic.date_time", 0x2a08_u32), ("org.bluetooth.characteristic.date_time", 0x2a08_u32),
("org.bluetooth.characteristic.day_date_time", 0x2a0a_u32), ("org.bluetooth.characteristic.day_date_time", 0x2a0a_u32),
("org.bluetooth.characteristic.day_of_week", 0x2a09_u32), ("org.bluetooth.characteristic.day_of_week", 0x2a09_u32),
("org.bluetooth.characteristic.descriptor_value_changed", 0x2a7d_u32), (
"org.bluetooth.characteristic.descriptor_value_changed",
0x2a7d_u32,
),
("org.bluetooth.characteristic.gap.device_name", 0x2a00_u32), ("org.bluetooth.characteristic.gap.device_name", 0x2a00_u32),
("org.bluetooth.characteristic.dew_point", 0x2a7b_u32), ("org.bluetooth.characteristic.dew_point", 0x2a7b_u32),
("org.bluetooth.characteristic.digital", 0x2a56_u32), ("org.bluetooth.characteristic.digital", 0x2a56_u32),
@ -121,140 +226,332 @@ const BLUETOOTH_ASSIGNED_CHARCTERISTICS: &'static [(&'static str, u32)] = &[
("org.bluetooth.characteristic.elevation", 0x2a6c_u32), ("org.bluetooth.characteristic.elevation", 0x2a6c_u32),
("org.bluetooth.characteristic.email_address", 0x2a87_u32), ("org.bluetooth.characteristic.email_address", 0x2a87_u32),
("org.bluetooth.characteristic.exact_time_256", 0x2a0c_u32), ("org.bluetooth.characteristic.exact_time_256", 0x2a0c_u32),
("org.bluetooth.characteristic.fat_burn_heart_rate_lower_limit", 0x2a88_u32), (
("org.bluetooth.characteristic.fat_burn_heart_rate_upper_limit", 0x2a89_u32), "org.bluetooth.characteristic.fat_burn_heart_rate_lower_limit",
("org.bluetooth.characteristic.firmware_revision_string", 0x2a26_u32), 0x2a88_u32,
),
(
"org.bluetooth.characteristic.fat_burn_heart_rate_upper_limit",
0x2a89_u32,
),
(
"org.bluetooth.characteristic.firmware_revision_string",
0x2a26_u32,
),
("org.bluetooth.characteristic.first_name", 0x2a8a_u32), ("org.bluetooth.characteristic.first_name", 0x2a8a_u32),
("org.bluetooth.characteristic.five_zone_heart_rate_limits", 0x2a8b_u32), (
"org.bluetooth.characteristic.five_zone_heart_rate_limits",
0x2a8b_u32,
),
("org.bluetooth.characteristic.floor_number", 0x2ab2_u32), ("org.bluetooth.characteristic.floor_number", 0x2ab2_u32),
("org.bluetooth.characteristic.gender", 0x2a8c_u32), ("org.bluetooth.characteristic.gender", 0x2a8c_u32),
("org.bluetooth.characteristic.glucose_feature", 0x2a51_u32), ("org.bluetooth.characteristic.glucose_feature", 0x2a51_u32),
("org.bluetooth.characteristic.glucose_measurement", 0x2a18_u32), (
("org.bluetooth.characteristic.glucose_measurement_context", 0x2a34_u32), "org.bluetooth.characteristic.glucose_measurement",
0x2a18_u32,
),
(
"org.bluetooth.characteristic.glucose_measurement_context",
0x2a34_u32,
),
("org.bluetooth.characteristic.gust_factor", 0x2a74_u32), ("org.bluetooth.characteristic.gust_factor", 0x2a74_u32),
("org.bluetooth.characteristic.hardware_revision_string", 0x2a27_u32), (
("org.bluetooth.characteristic.heart_rate_control_point", 0x2a39_u32), "org.bluetooth.characteristic.hardware_revision_string",
0x2a27_u32,
),
(
"org.bluetooth.characteristic.heart_rate_control_point",
0x2a39_u32,
),
("org.bluetooth.characteristic.heart_rate_max", 0x2a8d_u32), ("org.bluetooth.characteristic.heart_rate_max", 0x2a8d_u32),
("org.bluetooth.characteristic.heart_rate_measurement", 0x2a37_u32), (
"org.bluetooth.characteristic.heart_rate_measurement",
0x2a37_u32,
),
("org.bluetooth.characteristic.heat_index", 0x2a7a_u32), ("org.bluetooth.characteristic.heat_index", 0x2a7a_u32),
("org.bluetooth.characteristic.height", 0x2a8e_u32), ("org.bluetooth.characteristic.height", 0x2a8e_u32),
("org.bluetooth.characteristic.hid_control_point", 0x2a4c_u32), ("org.bluetooth.characteristic.hid_control_point", 0x2a4c_u32),
("org.bluetooth.characteristic.hid_information", 0x2a4a_u32), ("org.bluetooth.characteristic.hid_information", 0x2a4a_u32),
("org.bluetooth.characteristic.hip_circumference", 0x2a8f_u32), ("org.bluetooth.characteristic.hip_circumference", 0x2a8f_u32),
("org.bluetooth.characteristic.http_control_point", 0x2aba_u32), (
"org.bluetooth.characteristic.http_control_point",
0x2aba_u32,
),
("org.bluetooth.characteristic.http_entity_body", 0x2ab9_u32), ("org.bluetooth.characteristic.http_entity_body", 0x2ab9_u32),
("org.bluetooth.characteristic.http_headers", 0x2ab7_u32), ("org.bluetooth.characteristic.http_headers", 0x2ab7_u32),
("org.bluetooth.characteristic.http_status_code", 0x2ab8_u32), ("org.bluetooth.characteristic.http_status_code", 0x2ab8_u32),
("org.bluetooth.characteristic.https_security", 0x2abb_u32), ("org.bluetooth.characteristic.https_security", 0x2abb_u32),
("org.bluetooth.characteristic.humidity", 0x2a6f_u32), ("org.bluetooth.characteristic.humidity", 0x2a6f_u32),
("org.bluetooth.characteristic.ieee_11073-20601_regulatory_certification_data_list", 0x2a2a_u32), (
("org.bluetooth.characteristic.indoor_positioning_configuration", 0x2aad_u32), "org.bluetooth.characteristic.ieee_11073-20601_regulatory_certification_data_list",
("org.bluetooth.characteristic.intermediate_cuff_pressure", 0x2a36_u32), 0x2a2a_u32,
("org.bluetooth.characteristic.intermediate_temperature", 0x2a1e_u32), ),
(
"org.bluetooth.characteristic.indoor_positioning_configuration",
0x2aad_u32,
),
(
"org.bluetooth.characteristic.intermediate_cuff_pressure",
0x2a36_u32,
),
(
"org.bluetooth.characteristic.intermediate_temperature",
0x2a1e_u32,
),
("org.bluetooth.characteristic.irradiance", 0x2a77_u32), ("org.bluetooth.characteristic.irradiance", 0x2a77_u32),
("org.bluetooth.characteristic.language", 0x2aa2_u32), ("org.bluetooth.characteristic.language", 0x2aa2_u32),
("org.bluetooth.characteristic.last_name", 0x2a90_u32), ("org.bluetooth.characteristic.last_name", 0x2a90_u32),
("org.bluetooth.characteristic.latitude", 0x2aae_u32), ("org.bluetooth.characteristic.latitude", 0x2aae_u32),
("org.bluetooth.characteristic.ln_control_point", 0x2a6b_u32), ("org.bluetooth.characteristic.ln_control_point", 0x2a6b_u32),
("org.bluetooth.characteristic.ln_feature", 0x2a6a_u32), ("org.bluetooth.characteristic.ln_feature", 0x2a6a_u32),
("org.bluetooth.characteristic.local_east_coordinate.xml", 0x2ab1_u32), (
("org.bluetooth.characteristic.local_north_coordinate", 0x2ab0_u32), "org.bluetooth.characteristic.local_east_coordinate.xml",
("org.bluetooth.characteristic.local_time_information", 0x2a0f_u32), 0x2ab1_u32,
("org.bluetooth.characteristic.location_and_speed", 0x2a67_u32), ),
(
"org.bluetooth.characteristic.local_north_coordinate",
0x2ab0_u32,
),
(
"org.bluetooth.characteristic.local_time_information",
0x2a0f_u32,
),
(
"org.bluetooth.characteristic.location_and_speed",
0x2a67_u32,
),
("org.bluetooth.characteristic.location_name", 0x2ab5_u32), ("org.bluetooth.characteristic.location_name", 0x2ab5_u32),
("org.bluetooth.characteristic.longitude", 0x2aaf_u32), ("org.bluetooth.characteristic.longitude", 0x2aaf_u32),
("org.bluetooth.characteristic.magnetic_declination", 0x2a2c_u32), (
("org.bluetooth.characteristic.magnetic_flux_density_2d", 0x2aa0_u32), "org.bluetooth.characteristic.magnetic_declination",
("org.bluetooth.characteristic.magnetic_flux_density_3d", 0x2aa1_u32), 0x2a2c_u32,
("org.bluetooth.characteristic.manufacturer_name_string", 0x2a29_u32), ),
("org.bluetooth.characteristic.maximum_recommended_heart_rate", 0x2a91_u32), (
("org.bluetooth.characteristic.measurement_interval", 0x2a21_u32), "org.bluetooth.characteristic.magnetic_flux_density_2d",
("org.bluetooth.characteristic.model_number_string", 0x2a24_u32), 0x2aa0_u32,
),
(
"org.bluetooth.characteristic.magnetic_flux_density_3d",
0x2aa1_u32,
),
(
"org.bluetooth.characteristic.manufacturer_name_string",
0x2a29_u32,
),
(
"org.bluetooth.characteristic.maximum_recommended_heart_rate",
0x2a91_u32,
),
(
"org.bluetooth.characteristic.measurement_interval",
0x2a21_u32,
),
(
"org.bluetooth.characteristic.model_number_string",
0x2a24_u32,
),
("org.bluetooth.characteristic.navigation", 0x2a68_u32), ("org.bluetooth.characteristic.navigation", 0x2a68_u32),
("org.bluetooth.characteristic.new_alert", 0x2a46_u32), ("org.bluetooth.characteristic.new_alert", 0x2a46_u32),
("org.bluetooth.characteristic.object_action_control_point", 0x2ac5_u32), (
"org.bluetooth.characteristic.object_action_control_point",
0x2ac5_u32,
),
("org.bluetooth.characteristic.object_changed", 0x2ac8_u32), ("org.bluetooth.characteristic.object_changed", 0x2ac8_u32),
("org.bluetooth.characteristic.object_first_created", 0x2ac1_u32), (
"org.bluetooth.characteristic.object_first_created",
0x2ac1_u32,
),
("org.bluetooth.characteristic.object_id", 0x2ac3_u32), ("org.bluetooth.characteristic.object_id", 0x2ac3_u32),
("org.bluetooth.characteristic.object_last_modified", 0x2ac2_u32), (
("org.bluetooth.characteristic.object_list_control_point", 0x2ac6_u32), "org.bluetooth.characteristic.object_last_modified",
("org.bluetooth.characteristic.object_list_filter", 0x2ac7_u32), 0x2ac2_u32,
),
(
"org.bluetooth.characteristic.object_list_control_point",
0x2ac6_u32,
),
(
"org.bluetooth.characteristic.object_list_filter",
0x2ac7_u32,
),
("org.bluetooth.characteristic.object_name", 0x2abe_u32), ("org.bluetooth.characteristic.object_name", 0x2abe_u32),
("org.bluetooth.characteristic.object_properties", 0x2ac4_u32), ("org.bluetooth.characteristic.object_properties", 0x2ac4_u32),
("org.bluetooth.characteristic.object_size", 0x2ac0_u32), ("org.bluetooth.characteristic.object_size", 0x2ac0_u32),
("org.bluetooth.characteristic.object_type", 0x2abf_u32), ("org.bluetooth.characteristic.object_type", 0x2abf_u32),
("org.bluetooth.characteristic.ots_feature", 0x2abd_u32), ("org.bluetooth.characteristic.ots_feature", 0x2abd_u32),
("org.bluetooth.characteristic.gap.peripheral_preferred_connection_parameters", 0x2a04_u32), (
("org.bluetooth.characteristic.gap.peripheral_privacy_flag", 0x2a02_u32), "org.bluetooth.characteristic.gap.peripheral_preferred_connection_parameters",
("org.bluetooth.characteristic.plx_continuous_measurement", 0x2a5f_u32), 0x2a04_u32,
),
(
"org.bluetooth.characteristic.gap.peripheral_privacy_flag",
0x2a02_u32,
),
(
"org.bluetooth.characteristic.plx_continuous_measurement",
0x2a5f_u32,
),
("org.bluetooth.characteristic.plx_features", 0x2a60_u32), ("org.bluetooth.characteristic.plx_features", 0x2a60_u32),
("org.bluetooth.characteristic.plx_spot_check_measurement", 0x2a5e_u32), (
"org.bluetooth.characteristic.plx_spot_check_measurement",
0x2a5e_u32,
),
("org.bluetooth.characteristic.pnp_id", 0x2a50_u32), ("org.bluetooth.characteristic.pnp_id", 0x2a50_u32),
("org.bluetooth.characteristic.pollen_concentration", 0x2a75_u32), (
"org.bluetooth.characteristic.pollen_concentration",
0x2a75_u32,
),
("org.bluetooth.characteristic.position_quality", 0x2a69_u32), ("org.bluetooth.characteristic.position_quality", 0x2a69_u32),
("org.bluetooth.characteristic.pressure", 0x2a6d_u32), ("org.bluetooth.characteristic.pressure", 0x2a6d_u32),
("org.bluetooth.characteristic.protocol_mode", 0x2a4e_u32), ("org.bluetooth.characteristic.protocol_mode", 0x2a4e_u32),
("org.bluetooth.characteristic.rainfall", 0x2a78_u32), ("org.bluetooth.characteristic.rainfall", 0x2a78_u32),
("org.bluetooth.characteristic.gap.reconnection_address", 0x2a03_u32), (
("org.bluetooth.characteristic.record_access_control_point", 0x2a52_u32), "org.bluetooth.characteristic.gap.reconnection_address",
("org.bluetooth.characteristic.reference_time_information", 0x2a14_u32), 0x2a03_u32,
),
(
"org.bluetooth.characteristic.record_access_control_point",
0x2a52_u32,
),
(
"org.bluetooth.characteristic.reference_time_information",
0x2a14_u32,
),
("org.bluetooth.characteristic.report", 0x2a4d_u32), ("org.bluetooth.characteristic.report", 0x2a4d_u32),
("org.bluetooth.characteristic.report_map", 0x2a4b_u32), ("org.bluetooth.characteristic.report_map", 0x2a4b_u32),
("org.bluetooth.characteristic.resting_heart_rate", 0x2a92_u32), (
("org.bluetooth.characteristic.ringer_control_point", 0x2a40_u32), "org.bluetooth.characteristic.resting_heart_rate",
0x2a92_u32,
),
(
"org.bluetooth.characteristic.ringer_control_point",
0x2a40_u32,
),
("org.bluetooth.characteristic.ringer_setting", 0x2a41_u32), ("org.bluetooth.characteristic.ringer_setting", 0x2a41_u32),
("org.bluetooth.characteristic.rsc_feature", 0x2a54_u32), ("org.bluetooth.characteristic.rsc_feature", 0x2a54_u32),
("org.bluetooth.characteristic.rsc_measurement", 0x2a53_u32), ("org.bluetooth.characteristic.rsc_measurement", 0x2a53_u32),
("org.bluetooth.characteristic.sc_control_point", 0x2a55_u32), ("org.bluetooth.characteristic.sc_control_point", 0x2a55_u32),
("org.bluetooth.characteristic.scan_interval_window", 0x2a4f_u32), (
"org.bluetooth.characteristic.scan_interval_window",
0x2a4f_u32,
),
("org.bluetooth.characteristic.scan_refresh", 0x2a31_u32), ("org.bluetooth.characteristic.scan_refresh", 0x2a31_u32),
("org.bluetooth.characteristic.sensor_location", 0x2a5d_u32), ("org.bluetooth.characteristic.sensor_location", 0x2a5d_u32),
("org.bluetooth.characteristic.serial_number_string", 0x2a25_u32), (
("org.bluetooth.characteristic.gatt.service_changed", 0x2a05_u32), "org.bluetooth.characteristic.serial_number_string",
("org.bluetooth.characteristic.software_revision_string", 0x2a28_u32), 0x2a25_u32,
("org.bluetooth.characteristic.sport_type_for_aerobic_and_anaerobic_thresholds", 0x2a93_u32), ),
("org.bluetooth.characteristic.supported_new_alert_category", 0x2a47_u32), (
("org.bluetooth.characteristic.supported_unread_alert_category", 0x2a48_u32), "org.bluetooth.characteristic.gatt.service_changed",
0x2a05_u32,
),
(
"org.bluetooth.characteristic.software_revision_string",
0x2a28_u32,
),
(
"org.bluetooth.characteristic.sport_type_for_aerobic_and_anaerobic_thresholds",
0x2a93_u32,
),
(
"org.bluetooth.characteristic.supported_new_alert_category",
0x2a47_u32,
),
(
"org.bluetooth.characteristic.supported_unread_alert_category",
0x2a48_u32,
),
("org.bluetooth.characteristic.system_id", 0x2a23_u32), ("org.bluetooth.characteristic.system_id", 0x2a23_u32),
("org.bluetooth.characteristic.tds_control_point", 0x2abc_u32), ("org.bluetooth.characteristic.tds_control_point", 0x2abc_u32),
("org.bluetooth.characteristic.temperature", 0x2a6e_u32), ("org.bluetooth.characteristic.temperature", 0x2a6e_u32),
("org.bluetooth.characteristic.temperature_measurement", 0x2a1c_u32), (
"org.bluetooth.characteristic.temperature_measurement",
0x2a1c_u32,
),
("org.bluetooth.characteristic.temperature_type", 0x2a1d_u32), ("org.bluetooth.characteristic.temperature_type", 0x2a1d_u32),
("org.bluetooth.characteristic.three_zone_heart_rate_limits", 0x2a94_u32), (
"org.bluetooth.characteristic.three_zone_heart_rate_limits",
0x2a94_u32,
),
("org.bluetooth.characteristic.time_accuracy", 0x2a12_u32), ("org.bluetooth.characteristic.time_accuracy", 0x2a12_u32),
("org.bluetooth.characteristic.time_source", 0x2a13_u32), ("org.bluetooth.characteristic.time_source", 0x2a13_u32),
("org.bluetooth.characteristic.time_update_control_point", 0x2a16_u32), (
"org.bluetooth.characteristic.time_update_control_point",
0x2a16_u32,
),
("org.bluetooth.characteristic.time_update_state", 0x2a17_u32), ("org.bluetooth.characteristic.time_update_state", 0x2a17_u32),
("org.bluetooth.characteristic.time_with_dst", 0x2a11_u32), ("org.bluetooth.characteristic.time_with_dst", 0x2a11_u32),
("org.bluetooth.characteristic.time_zone", 0x2a0e_u32), ("org.bluetooth.characteristic.time_zone", 0x2a0e_u32),
("org.bluetooth.characteristic.true_wind_direction", 0x2a71_u32), (
"org.bluetooth.characteristic.true_wind_direction",
0x2a71_u32,
),
("org.bluetooth.characteristic.true_wind_speed", 0x2a70_u32), ("org.bluetooth.characteristic.true_wind_speed", 0x2a70_u32),
("org.bluetooth.characteristic.two_zone_heart_rate_limit", 0x2a95_u32), (
"org.bluetooth.characteristic.two_zone_heart_rate_limit",
0x2a95_u32,
),
("org.bluetooth.characteristic.tx_power_level", 0x2a07_u32), ("org.bluetooth.characteristic.tx_power_level", 0x2a07_u32),
("org.bluetooth.characteristic.uncertainty", 0x2ab4_u32), ("org.bluetooth.characteristic.uncertainty", 0x2ab4_u32),
("org.bluetooth.characteristic.unread_alert_status", 0x2a45_u32), (
"org.bluetooth.characteristic.unread_alert_status",
0x2a45_u32,
),
("org.bluetooth.characteristic.uri", 0x2ab6_u32), ("org.bluetooth.characteristic.uri", 0x2ab6_u32),
("org.bluetooth.characteristic.user_control_point", 0x2a9f_u32), (
"org.bluetooth.characteristic.user_control_point",
0x2a9f_u32,
),
("org.bluetooth.characteristic.user_index", 0x2a9a_u32), ("org.bluetooth.characteristic.user_index", 0x2a9a_u32),
("org.bluetooth.characteristic.uv_index", 0x2a76_u32), ("org.bluetooth.characteristic.uv_index", 0x2a76_u32),
("org.bluetooth.characteristic.vo2_max", 0x2a96_u32), ("org.bluetooth.characteristic.vo2_max", 0x2a96_u32),
("org.bluetooth.characteristic.waist_circumference", 0x2a97_u32), (
"org.bluetooth.characteristic.waist_circumference",
0x2a97_u32,
),
("org.bluetooth.characteristic.weight", 0x2a98_u32), ("org.bluetooth.characteristic.weight", 0x2a98_u32),
("org.bluetooth.characteristic.weight_measurement", 0x2a9d_u32), (
("org.bluetooth.characteristic.weight_scale_feature", 0x2a9e_u32), "org.bluetooth.characteristic.weight_measurement",
0x2a9d_u32,
),
(
"org.bluetooth.characteristic.weight_scale_feature",
0x2a9e_u32,
),
("org.bluetooth.characteristic.wind_chill", 0x2a79_u32), ("org.bluetooth.characteristic.wind_chill", 0x2a79_u32),
]; ];
//https://developer.bluetooth.org/gatt/services/Pages/ServicesHome.aspx //https://developer.bluetooth.org/gatt/services/Pages/ServicesHome.aspx
const BLUETOOTH_ASSIGNED_DESCRIPTORS: &'static [(&'static str, u32)] = &[ const BLUETOOTH_ASSIGNED_DESCRIPTORS: &'static [(&'static str, u32)] = &[
("org.bluetooth.descriptor.gatt.characteristic_extended_properties", 0x2900_u32), (
("org.bluetooth.descriptor.gatt.characteristic_user_description", 0x2901_u32), "org.bluetooth.descriptor.gatt.characteristic_extended_properties",
("org.bluetooth.descriptor.gatt.client_characteristic_configuration", 0x2902_u32), 0x2900_u32,
("org.bluetooth.descriptor.gatt.server_characteristic_configuration", 0x2903_u32), ),
("org.bluetooth.descriptor.gatt.characteristic_presentation_format", 0x2904_u32), (
("org.bluetooth.descriptor.gatt.characteristic_aggregate_format", 0x2905_u32), "org.bluetooth.descriptor.gatt.characteristic_user_description",
0x2901_u32,
),
(
"org.bluetooth.descriptor.gatt.client_characteristic_configuration",
0x2902_u32,
),
(
"org.bluetooth.descriptor.gatt.server_characteristic_configuration",
0x2903_u32,
),
(
"org.bluetooth.descriptor.gatt.characteristic_presentation_format",
0x2904_u32,
),
(
"org.bluetooth.descriptor.gatt.characteristic_aggregate_format",
0x2905_u32,
),
("org.bluetooth.descriptor.valid_range", 0x2906_u32), ("org.bluetooth.descriptor.valid_range", 0x2906_u32),
("org.bluetooth.descriptor.external_report_reference", 0x2907_u32), (
"org.bluetooth.descriptor.external_report_reference",
0x2907_u32,
),
("org.bluetooth.descriptor.report_reference", 0x2908_u32), ("org.bluetooth.descriptor.report_reference", 0x2908_u32),
("org.bluetooth.descriptor.number_of_digitals", 0x2909_u32), ("org.bluetooth.descriptor.number_of_digitals", 0x2909_u32),
("org.bluetooth.descriptor.value_trigger_setting", 0x290a_u32), ("org.bluetooth.descriptor.value_trigger_setting", 0x290a_u32),
@ -268,18 +565,22 @@ const BASE_UUID: &'static str = "-0000-1000-8000-00805f9b34fb";
const SERVICE_PREFIX: &'static str = "org.bluetooth.service"; const SERVICE_PREFIX: &'static str = "org.bluetooth.service";
const CHARACTERISTIC_PREFIX: &'static str = "org.bluetooth.characteristic"; const CHARACTERISTIC_PREFIX: &'static str = "org.bluetooth.characteristic";
const DESCRIPTOR_PREFIX: &'static str = "org.bluetooth.descriptor"; const DESCRIPTOR_PREFIX: &'static str = "org.bluetooth.descriptor";
const VALID_UUID_REGEX: &'static str = "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"; const VALID_UUID_REGEX: &'static str =
"^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$";
// https://cs.chromium.org/chromium/src/third_party/WebKit/Source/modules/bluetooth/BluetoothUUID.cpp?l=314 // https://cs.chromium.org/chromium/src/third_party/WebKit/Source/modules/bluetooth/BluetoothUUID.cpp?l=314
const UUID_ERROR_MESSAGE: &'static str = "It must be a valid UUID alias (e.g. 0x1234), \ const UUID_ERROR_MESSAGE: &'static str = "It must be a valid UUID alias (e.g. 0x1234), \
UUID (lowercase hex characters e.g. '00001234-0000-1000-8000-00805f9b34fb'),\nor recognized standard name from"; UUID (lowercase hex characters e.g. '00001234-0000-1000-8000-00805f9b34fb'),\nor recognized standard name from";
// https://cs.chromium.org/chromium/src/third_party/WebKit/Source/modules/bluetooth/BluetoothUUID.cpp?l=321 // https://cs.chromium.org/chromium/src/third_party/WebKit/Source/modules/bluetooth/BluetoothUUID.cpp?l=321
const SERVICES_ERROR_MESSAGE: &'static str = "https://developer.bluetooth.org/gatt/services/Pages/ServicesHome.aspx\ const SERVICES_ERROR_MESSAGE: &'static str =
"https://developer.bluetooth.org/gatt/services/Pages/ServicesHome.aspx\
\ne.g. 'alert_notification'."; \ne.g. 'alert_notification'.";
// https://cs.chromium.org/chromium/src/third_party/WebKit/Source/modules/bluetooth/BluetoothUUID.cpp?l=327 // https://cs.chromium.org/chromium/src/third_party/WebKit/Source/modules/bluetooth/BluetoothUUID.cpp?l=327
const CHARACTERISTIC_ERROR_MESSAGE: &'static str = "https://developer.bluetooth.org/gatt/characteristics/Pages/\ const CHARACTERISTIC_ERROR_MESSAGE: &'static str =
"https://developer.bluetooth.org/gatt/characteristics/Pages/\
CharacteristicsHome.aspx\ne.g. 'aerobic_heart_rate_lower_limit'."; CharacteristicsHome.aspx\ne.g. 'aerobic_heart_rate_lower_limit'.";
// https://cs.chromium.org/chromium/src/third_party/WebKit/Source/modules/bluetooth/BluetoothUUID.cpp?l=333 // https://cs.chromium.org/chromium/src/third_party/WebKit/Source/modules/bluetooth/BluetoothUUID.cpp?l=333
const DESCRIPTOR_ERROR_MESSAGE: &'static str = "https://developer.bluetooth.org/gatt/descriptors/Pages/\ const DESCRIPTOR_ERROR_MESSAGE: &'static str =
"https://developer.bluetooth.org/gatt/descriptors/Pages/\
DescriptorsHomePage.aspx\ne.g. 'gatt.characteristic_presentation_format'."; DescriptorsHomePage.aspx\ne.g. 'gatt.characteristic_presentation_format'.";
impl BluetoothUUID { impl BluetoothUUID {
@ -310,7 +611,11 @@ impl BluetoothUUID {
} }
pub fn characteristic(name: BluetoothCharacteristicUUID) -> Fallible<UUID> { pub fn characteristic(name: BluetoothCharacteristicUUID) -> Fallible<UUID> {
resolve_uuid_name(name, BLUETOOTH_ASSIGNED_CHARCTERISTICS, CHARACTERISTIC_PREFIX) resolve_uuid_name(
name,
BLUETOOTH_ASSIGNED_CHARCTERISTICS,
CHARACTERISTIC_PREFIX,
)
} }
pub fn descriptor(name: BluetoothDescriptorUUID) -> Fallible<UUID> { pub fn descriptor(name: BluetoothDescriptorUUID) -> Fallible<UUID> {
@ -335,13 +640,11 @@ fn canonical_uuid(alias: u32) -> UUID {
fn resolve_uuid_name( fn resolve_uuid_name(
name: StringOrUnsignedLong, name: StringOrUnsignedLong,
assigned_numbers_table: &'static [(&'static str, u32)], assigned_numbers_table: &'static [(&'static str, u32)],
prefix: &str) prefix: &str,
-> Fallible<DOMString> { ) -> Fallible<DOMString> {
match name { match name {
// Step 1. // Step 1.
StringOrUnsignedLong::UnsignedLong(unsigned32) => { StringOrUnsignedLong::UnsignedLong(unsigned32) => Ok(canonical_uuid(unsigned32)),
Ok(canonical_uuid(unsigned32))
},
StringOrUnsignedLong::String(dstring) => { StringOrUnsignedLong::String(dstring) => {
// Step 2. // Step 2.
let regex = Regex::new(VALID_UUID_REGEX).unwrap(); let regex = Regex::new(VALID_UUID_REGEX).unwrap();
@ -356,16 +659,17 @@ fn resolve_uuid_name(
None => { None => {
let (attribute_type, error_url_message) = match prefix { let (attribute_type, error_url_message) = match prefix {
SERVICE_PREFIX => ("Service", SERVICES_ERROR_MESSAGE), SERVICE_PREFIX => ("Service", SERVICES_ERROR_MESSAGE),
CHARACTERISTIC_PREFIX => ("Characteristic", CHARACTERISTIC_ERROR_MESSAGE), CHARACTERISTIC_PREFIX => {
("Characteristic", CHARACTERISTIC_ERROR_MESSAGE)
},
DESCRIPTOR_PREFIX => ("Descriptor", DESCRIPTOR_ERROR_MESSAGE), DESCRIPTOR_PREFIX => ("Descriptor", DESCRIPTOR_ERROR_MESSAGE),
_ => unreachable!(), _ => unreachable!(),
}; };
// Step 4. // Step 4.
return Err(Type(format!("Invalid {} name : '{}'.\n{} {}", return Err(Type(format!(
attribute_type, "Invalid {} name : '{}'.\n{} {}",
dstring, attribute_type, dstring, UUID_ERROR_MESSAGE, error_url_message
UUID_ERROR_MESSAGE, )));
error_url_message)));
}, },
} }
} }

View file

@ -40,9 +40,11 @@ impl CanvasGradient {
} }
pub fn new(global: &GlobalScope, style: CanvasGradientStyle) -> DomRoot<CanvasGradient> { pub fn new(global: &GlobalScope, style: CanvasGradientStyle) -> DomRoot<CanvasGradient> {
reflect_dom_object(Box::new(CanvasGradient::new_inherited(style)), reflect_dom_object(
Box::new(CanvasGradient::new_inherited(style)),
global, global,
CanvasGradientBinding::Wrap) CanvasGradientBinding::Wrap,
)
} }
} }
@ -60,10 +62,10 @@ impl CanvasGradientMethods for CanvasGradient {
match color { match color {
Ok(CSSColor::RGBA(rgba)) => rgba, Ok(CSSColor::RGBA(rgba)) => rgba,
Ok(CSSColor::CurrentColor) => RGBA::new(0, 0, 0, 255), Ok(CSSColor::CurrentColor) => RGBA::new(0, 0, 0, 255),
_ => return Err(Error::Syntax) _ => return Err(Error::Syntax),
} }
} else { } else {
return Err(Error::Syntax) return Err(Error::Syntax);
}; };
self.stops.borrow_mut().push(CanvasGradientStop { self.stops.borrow_mut().push(CanvasGradientStop {
@ -83,21 +85,25 @@ impl<'a> ToFillOrStrokeStyle for &'a CanvasGradient {
let gradient_stops = self.stops.borrow().clone(); let gradient_stops = self.stops.borrow().clone();
match self.style { match self.style {
CanvasGradientStyle::Linear(ref gradient) => { CanvasGradientStyle::Linear(ref gradient) => {
FillOrStrokeStyle::LinearGradient(LinearGradientStyle::new(gradient.x0, FillOrStrokeStyle::LinearGradient(LinearGradientStyle::new(
gradient.x0,
gradient.y0, gradient.y0,
gradient.x1, gradient.x1,
gradient.y1, gradient.y1,
gradient_stops)) gradient_stops,
} ))
},
CanvasGradientStyle::Radial(ref gradient) => { CanvasGradientStyle::Radial(ref gradient) => {
FillOrStrokeStyle::RadialGradient(RadialGradientStyle::new(gradient.x0, FillOrStrokeStyle::RadialGradient(RadialGradientStyle::new(
gradient.x0,
gradient.y0, gradient.y0,
gradient.r0, gradient.r0,
gradient.x1, gradient.x1,
gradient.y1, gradient.y1,
gradient.r1, gradient.r1,
gradient_stops)) gradient_stops,
} ))
},
} }
} }
} }

View file

@ -23,11 +23,12 @@ pub struct CanvasPattern {
} }
impl CanvasPattern { impl CanvasPattern {
fn new_inherited(surface_data: Vec<u8>, fn new_inherited(
surface_data: Vec<u8>,
surface_size: Size2D<i32>, surface_size: Size2D<i32>,
repeat: RepetitionStyle, repeat: RepetitionStyle,
origin_clean: bool) origin_clean: bool,
-> CanvasPattern { ) -> CanvasPattern {
let (x, y) = match repeat { let (x, y) = match repeat {
RepetitionStyle::Repeat => (true, true), RepetitionStyle::Repeat => (true, true),
RepetitionStyle::RepeatX => (true, false), RepetitionStyle::RepeatX => (true, false),
@ -44,18 +45,22 @@ impl CanvasPattern {
origin_clean: origin_clean, origin_clean: origin_clean,
} }
} }
pub fn new(global: &GlobalScope, pub fn new(
global: &GlobalScope,
surface_data: Vec<u8>, surface_data: Vec<u8>,
surface_size: Size2D<i32>, surface_size: Size2D<i32>,
repeat: RepetitionStyle, repeat: RepetitionStyle,
origin_clean: bool) origin_clean: bool,
-> DomRoot<CanvasPattern> { ) -> DomRoot<CanvasPattern> {
reflect_dom_object( reflect_dom_object(
Box::new(CanvasPattern::new_inherited( Box::new(CanvasPattern::new_inherited(
surface_data, surface_size, repeat, origin_clean surface_data,
surface_size,
repeat,
origin_clean,
)), )),
global, global,
CanvasPatternBinding::Wrap CanvasPatternBinding::Wrap,
) )
} }
pub fn origin_is_clean(&self) -> bool { pub fn origin_is_clean(&self) -> bool {
@ -65,9 +70,11 @@ impl CanvasPattern {
impl<'a> ToFillOrStrokeStyle for &'a CanvasPattern { impl<'a> ToFillOrStrokeStyle for &'a CanvasPattern {
fn to_fill_or_stroke_style(self) -> FillOrStrokeStyle { fn to_fill_or_stroke_style(self) -> FillOrStrokeStyle {
FillOrStrokeStyle::Surface(SurfaceStyle::new(self.surface_data.clone(), FillOrStrokeStyle::Surface(SurfaceStyle::new(
self.surface_data.clone(),
self.surface_size, self.surface_size,
self.repeat_x, self.repeat_x,
self.repeat_y)) self.repeat_y,
))
} }
} }

View file

@ -123,17 +123,21 @@ impl CanvasContextState {
} }
impl CanvasRenderingContext2D { impl CanvasRenderingContext2D {
pub fn new_inherited(global: &GlobalScope, pub fn new_inherited(
global: &GlobalScope,
canvas: Option<&HTMLCanvasElement>, canvas: Option<&HTMLCanvasElement>,
image_cache: Arc<ImageCache>, image_cache: Arc<ImageCache>,
base_url: ServoUrl, base_url: ServoUrl,
size: Size2D<i32>) size: Size2D<i32>,
-> CanvasRenderingContext2D { ) -> CanvasRenderingContext2D {
debug!("Creating new canvas rendering context."); debug!("Creating new canvas rendering context.");
let (sender, receiver) = profiled_ipc::channel(global.time_profiler_chan().clone()).unwrap(); let (sender, receiver) =
profiled_ipc::channel(global.time_profiler_chan().clone()).unwrap();
let script_to_constellation_chan = global.script_to_constellation_chan(); let script_to_constellation_chan = global.script_to_constellation_chan();
debug!("Asking constellation to create new canvas thread."); debug!("Asking constellation to create new canvas thread.");
script_to_constellation_chan.send(ScriptMsg::CreateCanvasPaintThread(size, sender)).unwrap(); script_to_constellation_chan
.send(ScriptMsg::CreateCanvasPaintThread(size, sender))
.unwrap();
let (ipc_renderer, canvas_id) = receiver.recv().unwrap(); let (ipc_renderer, canvas_id) = receiver.recv().unwrap();
debug!("Done."); debug!("Done.");
CanvasRenderingContext2D { CanvasRenderingContext2D {
@ -150,15 +154,20 @@ impl CanvasRenderingContext2D {
} }
} }
pub fn new(global: &GlobalScope, pub fn new(
global: &GlobalScope,
canvas: &HTMLCanvasElement, canvas: &HTMLCanvasElement,
size: Size2D<i32>) size: Size2D<i32>,
-> DomRoot<CanvasRenderingContext2D> { ) -> DomRoot<CanvasRenderingContext2D> {
let window = window_from_node(canvas); let window = window_from_node(canvas);
let image_cache = window.image_cache(); let image_cache = window.image_cache();
let base_url = window.get_url(); let base_url = window.get_url();
let boxed = Box::new(CanvasRenderingContext2D::new_inherited( let boxed = Box::new(CanvasRenderingContext2D::new_inherited(
global, Some(canvas), image_cache, base_url, size global,
Some(canvas),
image_cache,
base_url,
size,
)); ));
reflect_dom_object(boxed, global, CanvasRenderingContext2DBinding::Wrap) reflect_dom_object(boxed, global, CanvasRenderingContext2DBinding::Wrap)
} }
@ -191,7 +200,8 @@ impl CanvasRenderingContext2D {
// on the drawImage call arguments // on the drawImage call arguments
// source rectangle = area of the original image to be copied // source rectangle = area of the original image to be copied
// destination rectangle = area of the destination canvas where the source image is going to be drawn // destination rectangle = area of the destination canvas where the source image is going to be drawn
fn adjust_source_dest_rects(&self, fn adjust_source_dest_rects(
&self,
image_size: Size2D<f64>, image_size: Size2D<f64>,
sx: f64, sx: f64,
sy: f64, sy: f64,
@ -200,19 +210,25 @@ impl CanvasRenderingContext2D {
dx: f64, dx: f64,
dy: f64, dy: f64,
dw: f64, dw: f64,
dh: f64) dh: f64,
-> (Rect<f64>, Rect<f64>) { ) -> (Rect<f64>, Rect<f64>) {
let image_rect = Rect::new(Point2D::new(0f64, 0f64), let image_rect = Rect::new(
Size2D::new(image_size.width as f64, image_size.height as f64)); Point2D::new(0f64, 0f64),
Size2D::new(image_size.width as f64, image_size.height as f64),
);
// The source rectangle is the rectangle whose corners are the four points (sx, sy), // The source rectangle is the rectangle whose corners are the four points (sx, sy),
// (sx+sw, sy), (sx+sw, sy+sh), (sx, sy+sh). // (sx+sw, sy), (sx+sw, sy+sh), (sx, sy+sh).
let source_rect = Rect::new(Point2D::new(sx.min(sx + sw), sy.min(sy + sh)), let source_rect = Rect::new(
Size2D::new(sw.abs(), sh.abs())); Point2D::new(sx.min(sx + sw), sy.min(sy + sh)),
Size2D::new(sw.abs(), sh.abs()),
);
// When the source rectangle is outside the source image, // When the source rectangle is outside the source image,
// the source rectangle must be clipped to the source image // the source rectangle must be clipped to the source image
let source_rect_clipped = source_rect.intersection(&image_rect).unwrap_or(Rect::zero()); let source_rect_clipped = source_rect
.intersection(&image_rect)
.unwrap_or(Rect::zero());
// Width and height ratios between the non clipped and clipped source rectangles // Width and height ratios between the non clipped and clipped source rectangles
let width_ratio: f64 = source_rect_clipped.size.width / source_rect.size.width; let width_ratio: f64 = source_rect_clipped.size.width / source_rect.size.width;
@ -225,27 +241,29 @@ impl CanvasRenderingContext2D {
// The destination rectangle is the rectangle whose corners are the four points (dx, dy), // The destination rectangle is the rectangle whose corners are the four points (dx, dy),
// (dx+dw, dy), (dx+dw, dy+dh), (dx, dy+dh). // (dx+dw, dy), (dx+dw, dy+dh), (dx, dy+dh).
let dest_rect = Rect::new(Point2D::new(dx.min(dx + dest_rect_width_scaled), let dest_rect = Rect::new(
dy.min(dy + dest_rect_height_scaled)), Point2D::new(
Size2D::new(dest_rect_width_scaled.abs(), dx.min(dx + dest_rect_width_scaled),
dest_rect_height_scaled.abs())); dy.min(dy + dest_rect_height_scaled),
),
Size2D::new(dest_rect_width_scaled.abs(), dest_rect_height_scaled.abs()),
);
let source_rect = Rect::new(Point2D::new(source_rect_clipped.origin.x, let source_rect = Rect::new(
source_rect_clipped.origin.y), Point2D::new(source_rect_clipped.origin.x, source_rect_clipped.origin.y),
Size2D::new(source_rect_clipped.size.width, Size2D::new(
source_rect_clipped.size.height)); source_rect_clipped.size.width,
source_rect_clipped.size.height,
),
);
(source_rect, dest_rect) (source_rect, dest_rect)
} }
// https://html.spec.whatwg.org/multipage/#the-image-argument-is-not-origin-clean // https://html.spec.whatwg.org/multipage/#the-image-argument-is-not-origin-clean
fn is_origin_clean(&self, fn is_origin_clean(&self, image: CanvasImageSource) -> bool {
image: CanvasImageSource)
-> bool {
match image { match image {
CanvasImageSource::HTMLCanvasElement(canvas) => { CanvasImageSource::HTMLCanvasElement(canvas) => canvas.origin_is_clean(),
canvas.origin_is_clean()
}
CanvasImageSource::HTMLImageElement(image) => { CanvasImageSource::HTMLImageElement(image) => {
image.same_origin(GlobalScope::entry().origin()) image.same_origin(GlobalScope::entry().origin())
} }
@ -274,7 +292,8 @@ impl CanvasRenderingContext2D {
// is copied on the rectangle (dx, dy, dh, dw) of the destination canvas // is copied on the rectangle (dx, dy, dh, dw) of the destination canvas
// //
// https://html.spec.whatwg.org/multipage/#dom-context-2d-drawimage // https://html.spec.whatwg.org/multipage/#dom-context-2d-drawimage
fn draw_image(&self, fn draw_image(
&self,
image: CanvasImageSource, image: CanvasImageSource,
sx: f64, sx: f64,
sy: f64, sy: f64,
@ -283,29 +302,25 @@ impl CanvasRenderingContext2D {
dx: f64, dx: f64,
dy: f64, dy: f64,
dw: Option<f64>, dw: Option<f64>,
dh: Option<f64>) dh: Option<f64>,
-> ErrorResult { ) -> ErrorResult {
let result = match image { let result = match image {
CanvasImageSource::HTMLCanvasElement(ref canvas) => { CanvasImageSource::HTMLCanvasElement(ref canvas) => {
self.draw_html_canvas_element(&canvas, self.draw_html_canvas_element(&canvas, sx, sy, sw, sh, dx, dy, dw, dh)
sx, sy, sw, sh, },
dx, dy, dw, dh)
}
CanvasImageSource::HTMLImageElement(ref image) => { CanvasImageSource::HTMLImageElement(ref image) => {
// https://html.spec.whatwg.org/multipage/#img-error // https://html.spec.whatwg.org/multipage/#img-error
// If the image argument is an HTMLImageElement object that is in the broken state, // If the image argument is an HTMLImageElement object that is in the broken state,
// then throw an InvalidStateError exception // then throw an InvalidStateError exception
let url = image.get_url().ok_or(Error::InvalidState)?; let url = image.get_url().ok_or(Error::InvalidState)?;
self.fetch_and_draw_image_data(url, self.fetch_and_draw_image_data(url, sx, sy, sw, sh, dx, dy, dw, dh)
sx, sy, sw, sh, },
dx, dy, dw, dh)
}
CanvasImageSource::CSSStyleValue(ref value) => { CanvasImageSource::CSSStyleValue(ref value) => {
let url = value.get_url(self.base_url.clone()).ok_or(Error::InvalidState)?; let url = value
self.fetch_and_draw_image_data(url, .get_url(self.base_url.clone())
sx, sy, sw, sh, .ok_or(Error::InvalidState)?;
dx, dy, dw, dh) self.fetch_and_draw_image_data(url, sx, sy, sw, sh, dx, dy, dw, dh)
} },
}; };
if result.is_ok() && !self.is_origin_clean(image) { if result.is_ok() && !self.is_origin_clean(image) {
@ -339,17 +354,8 @@ impl CanvasRenderingContext2D {
let image_size = Size2D::new(canvas_size.width as f64, canvas_size.height as f64); let image_size = Size2D::new(canvas_size.width as f64, canvas_size.height as f64);
// 2. Establish the source and destination rectangles // 2. Establish the source and destination rectangles
let (source_rect, dest_rect) = self.adjust_source_dest_rects( let (source_rect, dest_rect) =
image_size, self.adjust_source_dest_rects(image_size, sx, sy, sw, sh, dx, dy, dw, dh);
sx,
sy,
sw,
sh,
dx,
dy,
dw,
dh,
);
if !is_rect_valid(source_rect) || !is_rect_valid(dest_rect) { if !is_rect_valid(source_rect) || !is_rect_valid(dest_rect) {
return Ok(()); return Ok(());
@ -384,7 +390,8 @@ impl CanvasRenderingContext2D {
Ok(()) Ok(())
} }
fn fetch_and_draw_image_data(&self, fn fetch_and_draw_image_data(
&self,
url: ServoUrl, url: ServoUrl,
sx: f64, sx: f64,
sy: f64, sy: f64,
@ -393,8 +400,8 @@ impl CanvasRenderingContext2D {
dx: f64, dx: f64,
dy: f64, dy: f64,
dw: Option<f64>, dw: Option<f64>,
dh: Option<f64>) dh: Option<f64>,
-> ErrorResult { ) -> ErrorResult {
debug!("Fetching image {}.", url); debug!("Fetching image {}.", url);
// https://html.spec.whatwg.org/multipage/#img-error // https://html.spec.whatwg.org/multipage/#img-error
// If the image argument is an HTMLImageElement object that is in the broken state, // If the image argument is an HTMLImageElement object that is in the broken state,
@ -413,13 +420,11 @@ impl CanvasRenderingContext2D {
let dh = dh.unwrap_or(image_size.height); let dh = dh.unwrap_or(image_size.height);
let sw = sw.unwrap_or(image_size.width); let sw = sw.unwrap_or(image_size.width);
let sh = sh.unwrap_or(image_size.height); let sh = sh.unwrap_or(image_size.height);
self.draw_image_data(image_data, self.draw_image_data(image_data, image_size, sx, sy, sw, sh, dx, dy, dw, dh)
image_size,
sx, sy, sw, sh,
dx, dy, dw, dh)
} }
fn draw_image_data(&self, fn draw_image_data(
&self,
image_data: Vec<u8>, image_data: Vec<u8>,
image_size: Size2D<f64>, image_size: Size2D<f64>,
sx: f64, sx: f64,
@ -429,18 +434,11 @@ impl CanvasRenderingContext2D {
dx: f64, dx: f64,
dy: f64, dy: f64,
dw: f64, dw: f64,
dh: f64) dh: f64,
-> ErrorResult { ) -> ErrorResult {
// Establish the source and destination rectangles // Establish the source and destination rectangles
let (source_rect, dest_rect) = self.adjust_source_dest_rects(image_size, let (source_rect, dest_rect) =
sx, self.adjust_source_dest_rects(image_size, sx, sy, sw, sh, dx, dy, dw, dh);
sy,
sw,
sh,
dx,
dy,
dw,
dh);
if !is_rect_valid(source_rect) || !is_rect_valid(dest_rect) { if !is_rect_valid(source_rect) || !is_rect_valid(dest_rect) {
return Ok(()); return Ok(());
@ -465,7 +463,7 @@ impl CanvasRenderingContext2D {
ImageResponse::None | ImageResponse::None |
ImageResponse::MetadataLoaded(_) => { ImageResponse::MetadataLoaded(_) => {
return None; return None;
} },
}; };
let image_size = Size2D::new(img.width as i32, img.height as i32); let image_size = Size2D::new(img.width as i32, img.height as i32);
@ -481,15 +479,16 @@ impl CanvasRenderingContext2D {
#[inline] #[inline]
fn request_image_from_cache(&self, url: ServoUrl) -> ImageResponse { fn request_image_from_cache(&self, url: ServoUrl) -> ImageResponse {
let response = self.image_cache let response = self.image_cache.find_image_or_metadata(
.find_image_or_metadata(url.clone(), url.clone(),
UsePlaceholder::No, UsePlaceholder::No,
CanRequestImages::No); CanRequestImages::No,
);
match response { match response {
Ok(ImageOrMetadataAvailable::ImageAvailable(image, url)) => Ok(ImageOrMetadataAvailable::ImageAvailable(image, url)) => {
ImageResponse::Loaded(image, url), ImageResponse::Loaded(image, url)
Err(ImageState::Pending(_)) => },
ImageResponse::None, Err(ImageState::Pending(_)) => ImageResponse::None,
_ => { _ => {
// Rather annoyingly, we get the same response back from // Rather annoyingly, we get the same response back from
// A load which really failed and from a load which hasn't started yet. // A load which really failed and from a load which hasn't started yet.
@ -512,8 +511,10 @@ impl CanvasRenderingContext2D {
return None; return None;
} }
Some(Rect::new(Point2D::new(x as f32, y as f32), Some(Rect::new(
Size2D::new(w as f32, h as f32))) Point2D::new(x as f32, y as f32),
Size2D::new(w as f32, h as f32),
))
} }
fn parse_color(&self, string: &str) -> Result<RGBA, ()> { fn parse_color(&self, string: &str) -> Result<RGBA, ()> {
@ -540,11 +541,13 @@ impl CanvasRenderingContext2D {
let canvas_element = canvas.upcast::<Element>(); let canvas_element = canvas.upcast::<Element>();
match canvas_element.style() { match canvas_element.style() {
Some(ref s) if canvas_element.has_css_layout_box() => Ok(s.get_color().color), Some(ref s) if canvas_element.has_css_layout_box() => {
_ => Ok(RGBA::new(0, 0, 0, 255)) Ok(s.get_color().color)
},
_ => Ok(RGBA::new(0, 0, 0, 255)),
} }
}, },
_ => Err(()) _ => Err(()),
} }
} else { } else {
Err(()) Err(())
@ -556,7 +559,9 @@ impl CanvasRenderingContext2D {
} }
pub fn send_canvas_2d_msg(&self, msg: Canvas2dMsg) { pub fn send_canvas_2d_msg(&self, msg: Canvas2dMsg) {
self.ipc_renderer.send(CanvasMsg::Canvas2d(msg, self.get_canvas_id())).unwrap() self.ipc_renderer
.send(CanvasMsg::Canvas2d(msg, self.get_canvas_id()))
.unwrap()
} }
pub fn get_ipc_renderer(&self) -> IpcSender<CanvasMsg> { pub fn get_ipc_renderer(&self) -> IpcSender<CanvasMsg> {
@ -610,7 +615,9 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
// https://html.spec.whatwg.org/multipage/#dom-context-2d-save // https://html.spec.whatwg.org/multipage/#dom-context-2d-save
fn Save(&self) { fn Save(&self) {
self.saved_states.borrow_mut().push(self.state.borrow().clone()); self.saved_states
.borrow_mut()
.push(self.state.borrow().clone());
self.send_canvas_2d_msg(Canvas2dMsg::SaveContext); self.send_canvas_2d_msg(Canvas2dMsg::SaveContext);
} }
@ -643,10 +650,14 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
let (sin, cos) = (angle.sin(), angle.cos()); let (sin, cos) = (angle.sin(), angle.cos());
let transform = self.state.borrow().transform; let transform = self.state.borrow().transform;
self.state.borrow_mut().transform = transform.pre_mul( self.state.borrow_mut().transform = transform.pre_mul(&Transform2D::row_major(
&Transform2D::row_major(cos as f32, sin as f32, cos as f32,
-sin as f32, cos as f32, sin as f32,
0.0, 0.0)); -sin as f32,
cos as f32,
0.0,
0.0,
));
self.update_transform() self.update_transform()
} }
@ -663,21 +674,32 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
// https://html.spec.whatwg.org/multipage/#dom-context-2d-transform // https://html.spec.whatwg.org/multipage/#dom-context-2d-transform
fn Transform(&self, a: f64, b: f64, c: f64, d: f64, e: f64, f: f64) { fn Transform(&self, a: f64, b: f64, c: f64, d: f64, e: f64, f: f64) {
if !(a.is_finite() && b.is_finite() && c.is_finite() && if !(a.is_finite() &&
d.is_finite() && e.is_finite() && f.is_finite()) { b.is_finite() &&
c.is_finite() &&
d.is_finite() &&
e.is_finite() &&
f.is_finite())
{
return; return;
} }
let transform = self.state.borrow().transform; let transform = self.state.borrow().transform;
self.state.borrow_mut().transform = transform.pre_mul( self.state.borrow_mut().transform = transform.pre_mul(&Transform2D::row_major(
&Transform2D::row_major(a as f32, b as f32, c as f32, d as f32, e as f32, f as f32)); a as f32, b as f32, c as f32, d as f32, e as f32, f as f32,
));
self.update_transform() self.update_transform()
} }
// https://html.spec.whatwg.org/multipage/#dom-context-2d-settransform // https://html.spec.whatwg.org/multipage/#dom-context-2d-settransform
fn SetTransform(&self, a: f64, b: f64, c: f64, d: f64, e: f64, f: f64) { fn SetTransform(&self, a: f64, b: f64, c: f64, d: f64, e: f64, f: f64) {
if !(a.is_finite() && b.is_finite() && c.is_finite() && if !(a.is_finite() &&
d.is_finite() && e.is_finite() && f.is_finite()) { b.is_finite() &&
c.is_finite() &&
d.is_finite() &&
e.is_finite() &&
f.is_finite())
{
return; return;
} }
@ -784,7 +806,8 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
CanvasFillRule::Nonzero => FillRule::Nonzero, CanvasFillRule::Nonzero => FillRule::Nonzero,
CanvasFillRule::Evenodd => FillRule::Evenodd, CanvasFillRule::Evenodd => FillRule::Evenodd,
}; };
let (sender, receiver) = profiled_ipc::channel::<bool>(self.global().time_profiler_chan().clone()).unwrap(); let (sender, receiver) =
profiled_ipc::channel::<bool>(self.global().time_profiler_chan().clone()).unwrap();
self.send_canvas_2d_msg(Canvas2dMsg::IsPointInPath(x, y, fill_rule, sender)); self.send_canvas_2d_msg(Canvas2dMsg::IsPointInPath(x, y, fill_rule, sender));
receiver.recv().unwrap() receiver.recv().unwrap()
} }
@ -797,11 +820,7 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
} }
// https://html.spec.whatwg.org/multipage/#dom-context-2d-drawimage // https://html.spec.whatwg.org/multipage/#dom-context-2d-drawimage
fn DrawImage(&self, fn DrawImage(&self, image: CanvasImageSource, dx: f64, dy: f64) -> ErrorResult {
image: CanvasImageSource,
dx: f64,
dy: f64)
-> ErrorResult {
if !(dx.is_finite() && dy.is_finite()) { if !(dx.is_finite() && dy.is_finite()) {
return Ok(()); return Ok(());
} }
@ -810,13 +829,14 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
} }
// https://html.spec.whatwg.org/multipage/#dom-context-2d-drawimage // https://html.spec.whatwg.org/multipage/#dom-context-2d-drawimage
fn DrawImage_(&self, fn DrawImage_(
&self,
image: CanvasImageSource, image: CanvasImageSource,
dx: f64, dx: f64,
dy: f64, dy: f64,
dw: f64, dw: f64,
dh: f64) dh: f64,
-> ErrorResult { ) -> ErrorResult {
if !(dx.is_finite() && dy.is_finite() && dw.is_finite() && dh.is_finite()) { if !(dx.is_finite() && dy.is_finite() && dw.is_finite() && dh.is_finite()) {
return Ok(()); return Ok(());
} }
@ -825,7 +845,8 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
} }
// https://html.spec.whatwg.org/multipage/#dom-context-2d-drawimage // https://html.spec.whatwg.org/multipage/#dom-context-2d-drawimage
fn DrawImage__(&self, fn DrawImage__(
&self,
image: CanvasImageSource, image: CanvasImageSource,
sx: f64, sx: f64,
sy: f64, sy: f64,
@ -834,14 +855,22 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
dx: f64, dx: f64,
dy: f64, dy: f64,
dw: f64, dw: f64,
dh: f64) dh: f64,
-> ErrorResult { ) -> ErrorResult {
if !(sx.is_finite() && sy.is_finite() && sw.is_finite() && sh.is_finite() && if !(sx.is_finite() &&
dx.is_finite() && dy.is_finite() && dw.is_finite() && dh.is_finite()) { sy.is_finite() &&
sw.is_finite() &&
sh.is_finite() &&
dx.is_finite() &&
dy.is_finite() &&
dw.is_finite() &&
dh.is_finite())
{
return Ok(()); return Ok(());
} }
self.draw_image(image, self.draw_image(
image,
sx, sx,
sy, sy,
Some(sw), Some(sw),
@ -849,7 +878,8 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
dx, dx,
dy, dy,
Some(dw), Some(dw),
Some(dh)) Some(dh),
)
} }
// https://html.spec.whatwg.org/multipage/#dom-context-2d-moveto // https://html.spec.whatwg.org/multipage/#dom-context-2d-moveto
@ -871,8 +901,10 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
// https://html.spec.whatwg.org/multipage/#dom-context-2d-rect // https://html.spec.whatwg.org/multipage/#dom-context-2d-rect
fn Rect(&self, x: f64, y: f64, width: f64, height: f64) { fn Rect(&self, x: f64, y: f64, width: f64, height: f64) {
if [x, y, width, height].iter().all(|val| val.is_finite()) { if [x, y, width, height].iter().all(|val| val.is_finite()) {
let rect = Rect::new(Point2D::new(x as f32, y as f32), let rect = Rect::new(
Size2D::new(width as f32, height as f32)); Point2D::new(x as f32, y as f32),
Size2D::new(width as f32, height as f32),
);
self.send_canvas_2d_msg(Canvas2dMsg::Rect(rect)); self.send_canvas_2d_msg(Canvas2dMsg::Rect(rect));
} }
} }
@ -882,23 +914,28 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
if !(cpx.is_finite() && cpy.is_finite() && x.is_finite() && y.is_finite()) { if !(cpx.is_finite() && cpy.is_finite() && x.is_finite() && y.is_finite()) {
return; return;
} }
self.send_canvas_2d_msg(Canvas2dMsg::QuadraticCurveTo(Point2D::new(cpx as f32, self.send_canvas_2d_msg(Canvas2dMsg::QuadraticCurveTo(
cpy as f32), Point2D::new(cpx as f32, cpy as f32),
Point2D::new(x as f32, Point2D::new(x as f32, y as f32),
y as f32))); ));
} }
// https://html.spec.whatwg.org/multipage/#dom-context-2d-beziercurveto // https://html.spec.whatwg.org/multipage/#dom-context-2d-beziercurveto
fn BezierCurveTo(&self, cp1x: f64, cp1y: f64, cp2x: f64, cp2y: f64, x: f64, y: f64) { fn BezierCurveTo(&self, cp1x: f64, cp1y: f64, cp2x: f64, cp2y: f64, x: f64, y: f64) {
if !(cp1x.is_finite() && cp1y.is_finite() && cp2x.is_finite() && cp2y.is_finite() && if !(cp1x.is_finite() &&
x.is_finite() && y.is_finite()) { cp1y.is_finite() &&
cp2x.is_finite() &&
cp2y.is_finite() &&
x.is_finite() &&
y.is_finite())
{
return; return;
} }
self.send_canvas_2d_msg(Canvas2dMsg::BezierCurveTo(Point2D::new(cp1x as f32, self.send_canvas_2d_msg(Canvas2dMsg::BezierCurveTo(
cp1y as f32), Point2D::new(cp1x as f32, cp1y as f32),
Point2D::new(cp2x as f32, Point2D::new(cp2x as f32, cp2y as f32),
cp2y as f32), Point2D::new(x as f32, y as f32),
Point2D::new(x as f32, y as f32))); ));
} }
// https://html.spec.whatwg.org/multipage/#dom-context-2d-arc // https://html.spec.whatwg.org/multipage/#dom-context-2d-arc
@ -911,11 +948,13 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
return Err(Error::IndexSize); return Err(Error::IndexSize);
} }
self.send_canvas_2d_msg(Canvas2dMsg::Arc(Point2D::new(x as f32, y as f32), self.send_canvas_2d_msg(Canvas2dMsg::Arc(
Point2D::new(x as f32, y as f32),
r as f32, r as f32,
start as f32, start as f32,
end as f32, end as f32,
ccw)); ccw,
));
Ok(()) Ok(())
} }
@ -928,28 +967,45 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
return Err(Error::IndexSize); return Err(Error::IndexSize);
} }
self.send_canvas_2d_msg(Canvas2dMsg::ArcTo(Point2D::new(cp1x as f32, cp1y as f32), self.send_canvas_2d_msg(Canvas2dMsg::ArcTo(
Point2D::new(cp1x as f32, cp1y as f32),
Point2D::new(cp2x as f32, cp2y as f32), Point2D::new(cp2x as f32, cp2y as f32),
r as f32)); r as f32,
));
Ok(()) Ok(())
} }
// https://html.spec.whatwg.org/multipage/#dom-context-2d-ellipse // https://html.spec.whatwg.org/multipage/#dom-context-2d-ellipse
fn Ellipse(&self, x: f64, y: f64, rx: f64, ry: f64, rotation: f64, start: f64, end: f64, ccw: bool) -> ErrorResult { fn Ellipse(
if !([x, y, rx, ry, rotation, start, end].iter().all(|x| x.is_finite())) { &self,
x: f64,
y: f64,
rx: f64,
ry: f64,
rotation: f64,
start: f64,
end: f64,
ccw: bool,
) -> ErrorResult {
if !([x, y, rx, ry, rotation, start, end]
.iter()
.all(|x| x.is_finite()))
{
return Ok(()); return Ok(());
} }
if rx < 0.0 || ry < 0.0 { if rx < 0.0 || ry < 0.0 {
return Err(Error::IndexSize); return Err(Error::IndexSize);
} }
self.send_canvas_2d_msg(Canvas2dMsg::Ellipse(Point2D::new(x as f32, y as f32), self.send_canvas_2d_msg(Canvas2dMsg::Ellipse(
Point2D::new(x as f32, y as f32),
rx as f32, rx as f32,
ry as f32, ry as f32,
rotation as f32, rotation as f32,
start as f32, start as f32,
end as f32, end as f32,
ccw)); ccw,
));
Ok(()) Ok(())
} }
@ -977,7 +1033,7 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
}, },
CanvasFillOrStrokeStyle::Pattern(ref pattern) => { CanvasFillOrStrokeStyle::Pattern(ref pattern) => {
StringOrCanvasGradientOrCanvasPattern::CanvasPattern(DomRoot::from_ref(&*pattern)) StringOrCanvasGradientOrCanvasPattern::CanvasPattern(DomRoot::from_ref(&*pattern))
} },
} }
} }
@ -987,23 +1043,28 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
StringOrCanvasGradientOrCanvasPattern::String(string) => { StringOrCanvasGradientOrCanvasPattern::String(string) => {
if let Ok(rgba) = self.parse_color(&string) { if let Ok(rgba) = self.parse_color(&string) {
self.state.borrow_mut().stroke_style = CanvasFillOrStrokeStyle::Color(rgba); self.state.borrow_mut().stroke_style = CanvasFillOrStrokeStyle::Color(rgba);
self.send_canvas_2d_msg(Canvas2dMsg::SetStrokeStyle( self.send_canvas_2d_msg(Canvas2dMsg::SetStrokeStyle(FillOrStrokeStyle::Color(
FillOrStrokeStyle::Color(rgba))); rgba,
)));
} }
}, },
StringOrCanvasGradientOrCanvasPattern::CanvasGradient(gradient) => { StringOrCanvasGradientOrCanvasPattern::CanvasGradient(gradient) => {
self.state.borrow_mut().stroke_style = self.state.borrow_mut().stroke_style =
CanvasFillOrStrokeStyle::Gradient(Dom::from_ref(&*gradient)); CanvasFillOrStrokeStyle::Gradient(Dom::from_ref(&*gradient));
self.send_canvas_2d_msg(Canvas2dMsg::SetStrokeStyle(gradient.to_fill_or_stroke_style())); self.send_canvas_2d_msg(Canvas2dMsg::SetStrokeStyle(
gradient.to_fill_or_stroke_style(),
));
}, },
StringOrCanvasGradientOrCanvasPattern::CanvasPattern(pattern) => { StringOrCanvasGradientOrCanvasPattern::CanvasPattern(pattern) => {
self.state.borrow_mut().stroke_style = self.state.borrow_mut().stroke_style =
CanvasFillOrStrokeStyle::Pattern(Dom::from_ref(&*pattern)); CanvasFillOrStrokeStyle::Pattern(Dom::from_ref(&*pattern));
self.send_canvas_2d_msg(Canvas2dMsg::SetStrokeStyle(pattern.to_fill_or_stroke_style())); self.send_canvas_2d_msg(Canvas2dMsg::SetStrokeStyle(
pattern.to_fill_or_stroke_style(),
));
if !pattern.origin_is_clean() { if !pattern.origin_is_clean() {
self.set_origin_unclean(); self.set_origin_unclean();
} }
} },
} }
} }
@ -1020,7 +1081,7 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
}, },
CanvasFillOrStrokeStyle::Pattern(ref pattern) => { CanvasFillOrStrokeStyle::Pattern(ref pattern) => {
StringOrCanvasGradientOrCanvasPattern::CanvasPattern(DomRoot::from_ref(&*pattern)) StringOrCanvasGradientOrCanvasPattern::CanvasPattern(DomRoot::from_ref(&*pattern))
} },
} }
} }
@ -1030,23 +1091,28 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
StringOrCanvasGradientOrCanvasPattern::String(string) => { StringOrCanvasGradientOrCanvasPattern::String(string) => {
if let Ok(rgba) = self.parse_color(&string) { if let Ok(rgba) = self.parse_color(&string) {
self.state.borrow_mut().fill_style = CanvasFillOrStrokeStyle::Color(rgba); self.state.borrow_mut().fill_style = CanvasFillOrStrokeStyle::Color(rgba);
self.send_canvas_2d_msg(Canvas2dMsg::SetFillStyle( self.send_canvas_2d_msg(Canvas2dMsg::SetFillStyle(FillOrStrokeStyle::Color(
FillOrStrokeStyle::Color(rgba))) rgba,
} )))
} }
},
StringOrCanvasGradientOrCanvasPattern::CanvasGradient(gradient) => { StringOrCanvasGradientOrCanvasPattern::CanvasGradient(gradient) => {
self.state.borrow_mut().fill_style = self.state.borrow_mut().fill_style =
CanvasFillOrStrokeStyle::Gradient(Dom::from_ref(&*gradient)); CanvasFillOrStrokeStyle::Gradient(Dom::from_ref(&*gradient));
self.send_canvas_2d_msg(Canvas2dMsg::SetFillStyle(gradient.to_fill_or_stroke_style())); self.send_canvas_2d_msg(Canvas2dMsg::SetFillStyle(
} gradient.to_fill_or_stroke_style(),
));
},
StringOrCanvasGradientOrCanvasPattern::CanvasPattern(pattern) => { StringOrCanvasGradientOrCanvasPattern::CanvasPattern(pattern) => {
self.state.borrow_mut().fill_style = self.state.borrow_mut().fill_style =
CanvasFillOrStrokeStyle::Pattern(Dom::from_ref(&*pattern)); CanvasFillOrStrokeStyle::Pattern(Dom::from_ref(&*pattern));
self.send_canvas_2d_msg(Canvas2dMsg::SetFillStyle(pattern.to_fill_or_stroke_style())); self.send_canvas_2d_msg(Canvas2dMsg::SetFillStyle(
pattern.to_fill_or_stroke_style(),
));
if !pattern.origin_is_clean() { if !pattern.origin_is_clean() {
self.set_origin_unclean(); self.set_origin_unclean();
} }
} },
} }
} }
@ -1063,21 +1129,19 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
// https://html.spec.whatwg.org/multipage/#dom-context-2d-createimagedata // https://html.spec.whatwg.org/multipage/#dom-context-2d-createimagedata
fn CreateImageData_(&self, imagedata: &ImageData) -> Fallible<DomRoot<ImageData>> { fn CreateImageData_(&self, imagedata: &ImageData) -> Fallible<DomRoot<ImageData>> {
ImageData::new(&self.global(), ImageData::new(&self.global(), imagedata.Width(), imagedata.Height(), None)
imagedata.Width(),
imagedata.Height(),
None)
} }
// https://html.spec.whatwg.org/multipage/#dom-context-2d-getimagedata // https://html.spec.whatwg.org/multipage/#dom-context-2d-getimagedata
fn GetImageData(&self, fn GetImageData(
&self,
sx: Finite<f64>, sx: Finite<f64>,
sy: Finite<f64>, sy: Finite<f64>,
sw: Finite<f64>, sw: Finite<f64>,
sh: Finite<f64>) sh: Finite<f64>,
-> Fallible<DomRoot<ImageData>> { ) -> Fallible<DomRoot<ImageData>> {
if !self.origin_is_clean() { if !self.origin_is_clean() {
return Err(Error::Security) return Err(Error::Security);
} }
let mut sx = *sx; let mut sx = *sx;
@ -1102,9 +1166,15 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
let sw = cmp::max(1, sw.to_u32().unwrap()); let sw = cmp::max(1, sw.to_u32().unwrap());
let (sender, receiver) = ipc::bytes_channel().unwrap(); let (sender, receiver) = ipc::bytes_channel().unwrap();
let dest_rect = Rect::new(Point2D::new(sx.to_i32().unwrap(), sy.to_i32().unwrap()), let dest_rect = Rect::new(
Size2D::new(sw as i32, sh as i32)); Point2D::new(sx.to_i32().unwrap(), sy.to_i32().unwrap()),
let canvas_size = self.canvas.as_ref().map(|c| c.get_size()).unwrap_or(Size2D::zero()); Size2D::new(sw as i32, sh as i32),
);
let canvas_size = self
.canvas
.as_ref()
.map(|c| c.get_size())
.unwrap_or(Size2D::zero());
let canvas_size = Size2D::new(canvas_size.width as f64, canvas_size.height as f64); let canvas_size = Size2D::new(canvas_size.width as f64, canvas_size.height as f64);
self.send_canvas_2d_msg(Canvas2dMsg::GetImageData(dest_rect, canvas_size, sender)); self.send_canvas_2d_msg(Canvas2dMsg::GetImageData(dest_rect, canvas_size, sender));
let mut data = receiver.recv().unwrap(); let mut data = receiver.recv().unwrap();
@ -1122,97 +1192,110 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
// https://html.spec.whatwg.org/multipage/#dom-context-2d-putimagedata // https://html.spec.whatwg.org/multipage/#dom-context-2d-putimagedata
fn PutImageData(&self, imagedata: &ImageData, dx: Finite<f64>, dy: Finite<f64>) { fn PutImageData(&self, imagedata: &ImageData, dx: Finite<f64>, dy: Finite<f64>) {
self.PutImageData_(imagedata, self.PutImageData_(
imagedata,
dx, dx,
dy, dy,
Finite::wrap(0f64), Finite::wrap(0f64),
Finite::wrap(0f64), Finite::wrap(0f64),
Finite::wrap(imagedata.Width() as f64), Finite::wrap(imagedata.Width() as f64),
Finite::wrap(imagedata.Height() as f64)) Finite::wrap(imagedata.Height() as f64),
)
} }
// https://html.spec.whatwg.org/multipage/#dom-context-2d-putimagedata // https://html.spec.whatwg.org/multipage/#dom-context-2d-putimagedata
fn PutImageData_(&self, fn PutImageData_(
&self,
imagedata: &ImageData, imagedata: &ImageData,
dx: Finite<f64>, dx: Finite<f64>,
dy: Finite<f64>, dy: Finite<f64>,
dirty_x: Finite<f64>, dirty_x: Finite<f64>,
dirty_y: Finite<f64>, dirty_y: Finite<f64>,
dirty_width: Finite<f64>, dirty_width: Finite<f64>,
dirty_height: Finite<f64>) { dirty_height: Finite<f64>,
) {
let data = imagedata.get_data_array(); let data = imagedata.get_data_array();
let offset = Vector2D::new(*dx, *dy); let offset = Vector2D::new(*dx, *dy);
let image_data_size = Size2D::new(imagedata.Width() as f64, imagedata.Height() as f64); let image_data_size = Size2D::new(imagedata.Width() as f64, imagedata.Height() as f64);
let dirty_rect = Rect::new(Point2D::new(*dirty_x, *dirty_y), let dirty_rect = Rect::new(
Size2D::new(*dirty_width, *dirty_height)); Point2D::new(*dirty_x, *dirty_y),
self.send_canvas_2d_msg(Canvas2dMsg::PutImageData(data.into(), Size2D::new(*dirty_width, *dirty_height),
);
self.send_canvas_2d_msg(Canvas2dMsg::PutImageData(
data.into(),
offset, offset,
image_data_size, image_data_size,
dirty_rect)); dirty_rect,
));
self.mark_as_dirty(); self.mark_as_dirty();
} }
// https://html.spec.whatwg.org/multipage/#dom-context-2d-createlineargradient // https://html.spec.whatwg.org/multipage/#dom-context-2d-createlineargradient
fn CreateLinearGradient(&self, fn CreateLinearGradient(
&self,
x0: Finite<f64>, x0: Finite<f64>,
y0: Finite<f64>, y0: Finite<f64>,
x1: Finite<f64>, x1: Finite<f64>,
y1: Finite<f64>) y1: Finite<f64>,
-> DomRoot<CanvasGradient> { ) -> DomRoot<CanvasGradient> {
CanvasGradient::new(&self.global(), CanvasGradient::new(
CanvasGradientStyle::Linear(LinearGradientStyle::new(*x0, &self.global(),
*y0, CanvasGradientStyle::Linear(LinearGradientStyle::new(*x0, *y0, *x1, *y1, Vec::new())),
*x1, )
*y1,
Vec::new())))
} }
// https://html.spec.whatwg.org/multipage/#dom-context-2d-createradialgradient // https://html.spec.whatwg.org/multipage/#dom-context-2d-createradialgradient
fn CreateRadialGradient(&self, fn CreateRadialGradient(
&self,
x0: Finite<f64>, x0: Finite<f64>,
y0: Finite<f64>, y0: Finite<f64>,
r0: Finite<f64>, r0: Finite<f64>,
x1: Finite<f64>, x1: Finite<f64>,
y1: Finite<f64>, y1: Finite<f64>,
r1: Finite<f64>) r1: Finite<f64>,
-> Fallible<DomRoot<CanvasGradient>> { ) -> Fallible<DomRoot<CanvasGradient>> {
if *r0 < 0. || *r1 < 0. { if *r0 < 0. || *r1 < 0. {
return Err(Error::IndexSize); return Err(Error::IndexSize);
} }
Ok(CanvasGradient::new(&self.global(), Ok(CanvasGradient::new(
CanvasGradientStyle::Radial(RadialGradientStyle::new(*x0, &self.global(),
CanvasGradientStyle::Radial(RadialGradientStyle::new(
*x0,
*y0, *y0,
*r0, *r0,
*x1, *x1,
*y1, *y1,
*r1, *r1,
Vec::new())))) Vec::new(),
)),
))
} }
// https://html.spec.whatwg.org/multipage/#dom-context-2d-createpattern // https://html.spec.whatwg.org/multipage/#dom-context-2d-createpattern
fn CreatePattern(&self, fn CreatePattern(
&self,
image: CanvasImageSource, image: CanvasImageSource,
mut repetition: DOMString) mut repetition: DOMString,
-> Fallible<DomRoot<CanvasPattern>> { ) -> Fallible<DomRoot<CanvasPattern>> {
let (image_data, image_size) = match image { let (image_data, image_size) = match image {
CanvasImageSource::HTMLImageElement(ref image) => { CanvasImageSource::HTMLImageElement(ref image) => {
// https://html.spec.whatwg.org/multipage/#img-error // https://html.spec.whatwg.org/multipage/#img-error
// If the image argument is an HTMLImageElement object that is in the broken state, // If the image argument is an HTMLImageElement object that is in the broken state,
// then throw an InvalidStateError exception // then throw an InvalidStateError exception
image.get_url() image
.get_url()
.and_then(|url| self.fetch_image_data(url)) .and_then(|url| self.fetch_image_data(url))
.ok_or(Error::InvalidState)? .ok_or(Error::InvalidState)?
}, },
CanvasImageSource::HTMLCanvasElement(ref canvas) => { CanvasImageSource::HTMLCanvasElement(ref canvas) => {
canvas.fetch_all_data().ok_or(Error::InvalidState)? canvas.fetch_all_data().ok_or(Error::InvalidState)?
}, },
CanvasImageSource::CSSStyleValue(ref value) => { CanvasImageSource::CSSStyleValue(ref value) => value
value.get_url(self.base_url.clone()) .get_url(self.base_url.clone())
.and_then(|url| self.fetch_image_data(url)) .and_then(|url| self.fetch_image_data(url))
.ok_or(Error::InvalidState)? .ok_or(Error::InvalidState)?,
}
}; };
if repetition.is_empty() { if repetition.is_empty() {
@ -1220,11 +1303,13 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
} }
if let Ok(rep) = RepetitionStyle::from_str(&repetition) { if let Ok(rep) = RepetitionStyle::from_str(&repetition) {
Ok(CanvasPattern::new(&self.global(), Ok(CanvasPattern::new(
&self.global(),
image_data, image_data,
image_size, image_size,
rep, rep,
self.is_origin_clean(image))) self.is_origin_clean(image),
))
} else { } else {
Err(Error::Syntax) Err(Error::Syntax)
} }
@ -1362,7 +1447,10 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
impl Drop for CanvasRenderingContext2D { impl Drop for CanvasRenderingContext2D {
fn drop(&mut self) { fn drop(&mut self) {
if let Err(err) = self.ipc_renderer.send(CanvasMsg::Close(self.get_canvas_id())) { if let Err(err) = self
.ipc_renderer
.send(CanvasMsg::Close(self.get_canvas_id()))
{
warn!("Could not close canvas: {}", err) warn!("Could not close canvas: {}", err)
} }
} }
@ -1391,22 +1479,32 @@ fn is_rect_valid(rect: Rect<f64>) -> bool {
// https://html.spec.whatwg.org/multipage/#serialisation-of-a-colour // https://html.spec.whatwg.org/multipage/#serialisation-of-a-colour
fn serialize<W>(color: &RGBA, dest: &mut W) -> fmt::Result fn serialize<W>(color: &RGBA, dest: &mut W) -> fmt::Result
where W: fmt::Write where
W: fmt::Write,
{ {
let red = color.red; let red = color.red;
let green = color.green; let green = color.green;
let blue = color.blue; let blue = color.blue;
if color.alpha == 255 { if color.alpha == 255 {
write!(dest, write!(
dest,
"#{:x}{:x}{:x}{:x}{:x}{:x}", "#{:x}{:x}{:x}{:x}{:x}{:x}",
red >> 4, red >> 4,
red & 0xF, red & 0xF,
green >> 4, green >> 4,
green & 0xF, green & 0xF,
blue >> 4, blue >> 4,
blue & 0xF) blue & 0xF
)
} else { } else {
write!(dest, "rgba({}, {}, {}, {})", red, green, blue, color.alpha_f32()) write!(
dest,
"rgba({}, {}, {}, {})",
red,
green,
blue,
color.alpha_f32()
)
} }
} }

View file

@ -26,16 +26,18 @@ impl ChannelMergerNode {
context: &BaseAudioContext, context: &BaseAudioContext,
options: &ChannelMergerOptions, options: &ChannelMergerOptions,
) -> Fallible<ChannelMergerNode> { ) -> Fallible<ChannelMergerNode> {
let node_options = options.parent let node_options = options.parent.unwrap_or(
.unwrap_or(1, ChannelCountMode::Explicit, 1,
ChannelInterpretation::Speakers); ChannelCountMode::Explicit,
ChannelInterpretation::Speakers,
);
if node_options.count != 1 || node_options.mode != ChannelCountMode::Explicit { if node_options.count != 1 || node_options.mode != ChannelCountMode::Explicit {
return Err(Error::InvalidState) return Err(Error::InvalidState);
} }
if options.numberOfInputs < 1 || options.numberOfInputs > MAX_CHANNEL_COUNT { if options.numberOfInputs < 1 || options.numberOfInputs > MAX_CHANNEL_COUNT {
return Err(Error::IndexSize) return Err(Error::IndexSize);
} }
let node = AudioNode::new_inherited( let node = AudioNode::new_inherited(
@ -45,9 +47,7 @@ impl ChannelMergerNode {
options.numberOfInputs, // inputs options.numberOfInputs, // inputs
1, // outputs 1, // outputs
)?; )?;
Ok(ChannelMergerNode { Ok(ChannelMergerNode { node })
node,
})
} }
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
@ -57,7 +57,11 @@ impl ChannelMergerNode {
options: &ChannelMergerOptions, options: &ChannelMergerOptions,
) -> Fallible<DomRoot<ChannelMergerNode>> { ) -> Fallible<DomRoot<ChannelMergerNode>> {
let node = ChannelMergerNode::new_inherited(window, context, options)?; let node = ChannelMergerNode::new_inherited(window, context, options)?;
Ok(reflect_dom_object(Box::new(node), window, ChannelMergerNodeBinding::Wrap)) Ok(reflect_dom_object(
Box::new(node),
window,
ChannelMergerNodeBinding::Wrap,
))
} }
pub fn Constructor( pub fn Constructor(

View file

@ -45,7 +45,7 @@ impl CharacterData {
match self.upcast::<Node>().type_id() { match self.upcast::<Node>().type_id() {
NodeTypeId::CharacterData(CharacterDataTypeId::Comment) => { NodeTypeId::CharacterData(CharacterDataTypeId::Comment) => {
DomRoot::upcast(Comment::new(data, &document)) DomRoot::upcast(Comment::new(data, &document))
} },
NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) => { NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) => {
let pi = self.downcast::<ProcessingInstruction>().unwrap(); let pi = self.downcast::<ProcessingInstruction>().unwrap();
DomRoot::upcast(ProcessingInstruction::new(pi.Target(), data, &document)) DomRoot::upcast(ProcessingInstruction::new(pi.Target(), data, &document))
@ -107,7 +107,8 @@ impl CharacterDataMethods for CharacterData {
*self.data.borrow_mut() = data; *self.data.borrow_mut() = data;
self.content_changed(); self.content_changed();
let node = self.upcast::<Node>(); let node = self.upcast::<Node>();
node.ranges().replace_code_units(node, 0, old_length, new_length); node.ranges()
.replace_code_units(node, 0, old_length, new_length);
} }
// https://dom.spec.whatwg.org/#dom-characterdata-length // https://dom.spec.whatwg.org/#dom-characterdata-length
@ -130,7 +131,7 @@ impl CharacterDataMethods for CharacterData {
substring = substring + "\u{FFFD}"; substring = substring + "\u{FFFD}";
} }
remaining = s; remaining = s;
} },
// Step 2. // Step 2.
Err(()) => return Err(Error::IndexSize), Err(()) => return Err(Error::IndexSize),
} }
@ -146,7 +147,7 @@ impl CharacterDataMethods for CharacterData {
if astral.is_some() { if astral.is_some() {
substring = substring + "\u{FFFD}"; substring = substring + "\u{FFFD}";
} }
} },
}; };
Ok(DOMString::from(substring)) Ok(DOMString::from(substring))
} }
@ -183,7 +184,7 @@ impl CharacterDataMethods for CharacterData {
// since our DOMString is currently strict UTF-8. // since our DOMString is currently strict UTF-8.
replacement_before = if astral.is_some() { "\u{FFFD}" } else { "" }; replacement_before = if astral.is_some() { "\u{FFFD}" } else { "" };
remaining = r; remaining = r;
} },
// Step 2. // Step 2.
Err(()) => return Err(Error::IndexSize), Err(()) => return Err(Error::IndexSize),
}; };
@ -194,14 +195,14 @@ impl CharacterDataMethods for CharacterData {
Err(()) => { Err(()) => {
replacement_after = ""; replacement_after = "";
suffix = ""; suffix = "";
} },
Ok((_, astral, s)) => { Ok((_, astral, s)) => {
// As if we had split the UTF-16 surrogate pair in half // As if we had split the UTF-16 surrogate pair in half
// and then transcoded that to UTF-8 lossily, // and then transcoded that to UTF-8 lossily,
// since our DOMString is currently strict UTF-8. // since our DOMString is currently strict UTF-8.
replacement_after = if astral.is_some() { "\u{FFFD}" } else { "" }; replacement_after = if astral.is_some() { "\u{FFFD}" } else { "" };
suffix = s; suffix = s;
} },
}; };
// Step 4: Mutation observers. // Step 4: Mutation observers.
self.queue_mutation_record(); self.queue_mutation_record();
@ -212,7 +213,8 @@ impl CharacterDataMethods for CharacterData {
replacement_before.len() + replacement_before.len() +
arg.len() + arg.len() +
replacement_after.len() + replacement_after.len() +
suffix.len()); suffix.len(),
);
new_data.push_str(prefix); new_data.push_str(prefix);
new_data.push_str(replacement_before); new_data.push_str(replacement_before);
new_data.push_str(&arg); new_data.push_str(&arg);
@ -223,8 +225,8 @@ impl CharacterDataMethods for CharacterData {
self.content_changed(); self.content_changed();
// Steps 8-11. // Steps 8-11.
let node = self.upcast::<Node>(); let node = self.upcast::<Node>();
node.ranges().replace_code_units( node.ranges()
node, offset, count, arg.encode_utf16().count() as u32); .replace_code_units(node, offset, count, arg.encode_utf16().count() as u32);
Ok(()) Ok(())
} }
@ -251,12 +253,18 @@ impl CharacterDataMethods for CharacterData {
// https://dom.spec.whatwg.org/#dom-nondocumenttypechildnode-previouselementsibling // https://dom.spec.whatwg.org/#dom-nondocumenttypechildnode-previouselementsibling
fn GetPreviousElementSibling(&self) -> Option<DomRoot<Element>> { fn GetPreviousElementSibling(&self) -> Option<DomRoot<Element>> {
self.upcast::<Node>().preceding_siblings().filter_map(DomRoot::downcast).next() self.upcast::<Node>()
.preceding_siblings()
.filter_map(DomRoot::downcast)
.next()
} }
// https://dom.spec.whatwg.org/#dom-nondocumenttypechildnode-nextelementsibling // https://dom.spec.whatwg.org/#dom-nondocumenttypechildnode-nextelementsibling
fn GetNextElementSibling(&self) -> Option<DomRoot<Element>> { fn GetNextElementSibling(&self) -> Option<DomRoot<Element>> {
self.upcast::<Node>().following_siblings().filter_map(DomRoot::downcast).next() self.upcast::<Node>()
.following_siblings()
.filter_map(DomRoot::downcast)
.next()
} }
} }
@ -305,13 +313,15 @@ fn split_at_utf16_code_unit_offset(s: &str, offset: u32) -> Result<(&str, Option
if code_units == offset { if code_units == offset {
if opts::get().replace_surrogates { if opts::get().replace_surrogates {
debug_assert_eq!(c.len_utf8(), 4); debug_assert_eq!(c.len_utf8(), 4);
return Ok((&s[..i], Some(c), &s[i + c.len_utf8()..])) return Ok((&s[..i], Some(c), &s[i + c.len_utf8()..]));
} }
panic!("\n\n\ panic!(
"\n\n\
Would split a surrogate pair in CharacterData API.\n\ Would split a surrogate pair in CharacterData API.\n\
If you see this in real content, please comment with the URL\n\ If you see this in real content, please comment with the URL\n\
on https://github.com/servo/servo/issues/6873\n\ on https://github.com/servo/servo/issues/6873\n\
\n"); \n"
);
} }
code_units += 1; code_units += 1;
} }

View file

@ -21,7 +21,7 @@ pub struct Client {
url: ServoUrl, url: ServoUrl,
frame_type: FrameType, frame_type: FrameType,
#[ignore_malloc_size_of = "Defined in uuid"] #[ignore_malloc_size_of = "Defined in uuid"]
id: Uuid id: Uuid,
} }
impl Client { impl Client {
@ -31,14 +31,16 @@ impl Client {
active_worker: Default::default(), active_worker: Default::default(),
url: url, url: url,
frame_type: FrameType::None, frame_type: FrameType::None,
id: Uuid::new_v4() id: Uuid::new_v4(),
} }
} }
pub fn new(window: &Window) -> DomRoot<Client> { pub fn new(window: &Window) -> DomRoot<Client> {
reflect_dom_object(Box::new(Client::new_inherited(window.get_url())), reflect_dom_object(
Box::new(Client::new_inherited(window.get_url())),
window, window,
Wrap) Wrap,
)
} }
pub fn creation_url(&self) -> ServoUrl { pub fn creation_url(&self) -> ServoUrl {

View file

@ -34,45 +34,48 @@ impl CloseEvent {
} }
pub fn new_uninitialized(global: &GlobalScope) -> DomRoot<CloseEvent> { pub fn new_uninitialized(global: &GlobalScope) -> DomRoot<CloseEvent> {
reflect_dom_object(Box::new(CloseEvent::new_inherited(false, 0, DOMString::new())), reflect_dom_object(
Box::new(CloseEvent::new_inherited(false, 0, DOMString::new())),
global, global,
CloseEventBinding::Wrap) CloseEventBinding::Wrap,
)
} }
pub fn new(global: &GlobalScope, pub fn new(
global: &GlobalScope,
type_: Atom, type_: Atom,
bubbles: EventBubbles, bubbles: EventBubbles,
cancelable: EventCancelable, cancelable: EventCancelable,
wasClean: bool, wasClean: bool,
code: u16, code: u16,
reason: DOMString) reason: DOMString,
-> DomRoot<CloseEvent> { ) -> DomRoot<CloseEvent> {
let event = Box::new(CloseEvent::new_inherited(wasClean, code, reason)); let event = Box::new(CloseEvent::new_inherited(wasClean, code, reason));
let ev = reflect_dom_object(event, global, CloseEventBinding::Wrap); let ev = reflect_dom_object(event, global, CloseEventBinding::Wrap);
{ {
let event = ev.upcast::<Event>(); let event = ev.upcast::<Event>();
event.init_event(type_, event.init_event(type_, bool::from(bubbles), bool::from(cancelable));
bool::from(bubbles),
bool::from(cancelable));
} }
ev ev
} }
pub fn Constructor(global: &GlobalScope, pub fn Constructor(
global: &GlobalScope,
type_: DOMString, type_: DOMString,
init: &CloseEventBinding::CloseEventInit) init: &CloseEventBinding::CloseEventInit,
-> Fallible<DomRoot<CloseEvent>> { ) -> Fallible<DomRoot<CloseEvent>> {
let bubbles = EventBubbles::from(init.parent.bubbles); let bubbles = EventBubbles::from(init.parent.bubbles);
let cancelable = EventCancelable::from(init.parent.cancelable); let cancelable = EventCancelable::from(init.parent.cancelable);
Ok(CloseEvent::new(global, Ok(CloseEvent::new(
global,
Atom::from(type_), Atom::from(type_),
bubbles, bubbles,
cancelable, cancelable,
init.wasClean, init.wasClean,
init.code, init.code,
init.reason.clone())) init.reason.clone(),
))
} }
} }
impl CloseEventMethods for CloseEvent { impl CloseEventMethods for CloseEvent {

View file

@ -27,9 +27,11 @@ impl Comment {
} }
pub fn new(text: DOMString, document: &Document) -> DomRoot<Comment> { pub fn new(text: DOMString, document: &Document) -> DomRoot<Comment> {
Node::reflect_node(Box::new(Comment::new_inherited(text, document)), Node::reflect_node(
Box::new(Comment::new_inherited(text, document)),
document, document,
CommentBinding::Wrap) CommentBinding::Wrap,
)
} }
pub fn Constructor(window: &Window, data: DOMString) -> Fallible<DomRoot<Comment>> { pub fn Constructor(window: &Window, data: DOMString) -> Fallible<DomRoot<Comment>> {

View file

@ -19,34 +19,42 @@ pub struct CompositionEvent {
} }
impl CompositionEvent { impl CompositionEvent {
pub fn new(window: &Window, pub fn new(
window: &Window,
type_: DOMString, type_: DOMString,
can_bubble: bool, can_bubble: bool,
cancelable: bool, cancelable: bool,
view: Option<&Window>, view: Option<&Window>,
detail: i32, detail: i32,
data: DOMString) -> DomRoot<CompositionEvent> { data: DOMString,
let ev = reflect_dom_object(Box::new(CompositionEvent { ) -> DomRoot<CompositionEvent> {
let ev = reflect_dom_object(
Box::new(CompositionEvent {
uievent: UIEvent::new_inherited(), uievent: UIEvent::new_inherited(),
data: data, data: data,
}), }),
window, window,
CompositionEventBinding::Wrap); CompositionEventBinding::Wrap,
ev.uievent.InitUIEvent(type_, can_bubble, cancelable, view, detail); );
ev.uievent
.InitUIEvent(type_, can_bubble, cancelable, view, detail);
ev ev
} }
pub fn Constructor(window: &Window, pub fn Constructor(
window: &Window,
type_: DOMString, type_: DOMString,
init: &CompositionEventBinding::CompositionEventInit) init: &CompositionEventBinding::CompositionEventInit,
-> Fallible<DomRoot<CompositionEvent>> { ) -> Fallible<DomRoot<CompositionEvent>> {
let event = CompositionEvent::new(window, let event = CompositionEvent::new(
window,
type_, type_,
init.parent.parent.bubbles, init.parent.parent.bubbles,
init.parent.parent.cancelable, init.parent.parent.cancelable,
init.parent.view.r(), init.parent.view.r(),
init.parent.detail, init.parent.detail,
init.data.clone()); init.data.clone(),
);
Ok(event) Ok(event)
} }
} }

View file

@ -16,13 +16,14 @@ impl Console {
fn send_to_devtools(global: &GlobalScope, level: LogLevel, message: DOMString) { fn send_to_devtools(global: &GlobalScope, level: LogLevel, message: DOMString) {
if let Some(chan) = global.devtools_chan() { if let Some(chan) = global.devtools_chan() {
let console_message = prepare_message(level, message); let console_message = prepare_message(level, message);
let worker_id = global.downcast::<WorkerGlobalScope>().map(|worker| { let worker_id = global
worker.get_worker_id() .downcast::<WorkerGlobalScope>()
}); .map(|worker| worker.get_worker_id());
let devtools_message = ScriptToDevtoolsControlMsg::ConsoleAPI( let devtools_message = ScriptToDevtoolsControlMsg::ConsoleAPI(
global.pipeline_id(), global.pipeline_id(),
console_message, console_message,
worker_id); worker_id,
);
chan.send(devtools_message).unwrap(); chan.send(devtools_message).unwrap();
} }
} }
@ -33,7 +34,10 @@ impl Console {
// we're finished with stdout. Since the stderr lock is reentrant, there is // we're finished with stdout. Since the stderr lock is reentrant, there is
// no risk of deadlock if the callback ends up trying to write to stderr for // no risk of deadlock if the callback ends up trying to write to stderr for
// any reason. // any reason.
fn with_stderr_lock<F>(f: F) where F: FnOnce() { fn with_stderr_lock<F>(f: F)
where
F: FnOnce(),
{
let stderr = io::stderr(); let stderr = io::stderr();
let _handle = stderr.lock(); let _handle = stderr.lock();
f() f()
@ -116,9 +120,7 @@ impl Console {
pub fn TimeEnd(global: &GlobalScope, label: DOMString) { pub fn TimeEnd(global: &GlobalScope, label: DOMString) {
with_stderr_lock(move || { with_stderr_lock(move || {
if let Ok(delta) = global.time_end(&label) { if let Ok(delta) = global.time_end(&label) {
let message = DOMString::from( let message = DOMString::from(format!("{}: {}ms", label, delta));
format!("{}: {}ms", label, delta)
);
println!("{}", message); println!("{}", message);
Self::send_to_devtools(global, LogLevel::Log, message); Self::send_to_devtools(global, LogLevel::Log, message);
}; };

View file

@ -84,10 +84,11 @@ use js::jsapi::JSAutoCompartment;
use script_thread::ScriptThread; use script_thread::ScriptThread;
use servo_config::prefs::PREFS; use servo_config::prefs::PREFS;
fn create_svg_element(name: QualName, fn create_svg_element(
name: QualName,
prefix: Option<Prefix>, prefix: Option<Prefix>,
document: &Document) document: &Document,
-> DomRoot<Element> { ) -> DomRoot<Element> {
assert_eq!(name.ns, ns!(svg)); assert_eq!(name.ns, ns!(svg));
macro_rules! make( macro_rules! make(
@ -113,13 +114,14 @@ fn create_svg_element(name: QualName,
// https://dom.spec.whatwg.org/#concept-create-element // https://dom.spec.whatwg.org/#concept-create-element
#[allow(unsafe_code)] #[allow(unsafe_code)]
fn create_html_element(name: QualName, fn create_html_element(
name: QualName,
prefix: Option<Prefix>, prefix: Option<Prefix>,
is: Option<LocalName>, is: Option<LocalName>,
document: &Document, document: &Document,
creator: ElementCreator, creator: ElementCreator,
mode: CustomElementCreationMode) mode: CustomElementCreationMode,
-> DomRoot<Element> { ) -> DomRoot<Element> {
assert_eq!(name.ns, ns!(html)); assert_eq!(name.ns, ns!(html));
// Step 4 // Step 4
@ -129,8 +131,11 @@ fn create_html_element(name: QualName,
if definition.is_autonomous() { if definition.is_autonomous() {
match mode { match mode {
CustomElementCreationMode::Asynchronous => { CustomElementCreationMode::Asynchronous => {
let result = DomRoot::upcast::<Element>( let result = DomRoot::upcast::<Element>(HTMLElement::new(
HTMLElement::new(name.local.clone(), prefix.clone(), document)); name.local.clone(),
prefix.clone(),
document,
));
result.set_custom_element_state(CustomElementState::Undefined); result.set_custom_element_state(CustomElementState::Undefined);
ScriptThread::enqueue_upgrade_reaction(&*result, definition); ScriptThread::enqueue_upgrade_reaction(&*result, definition);
return result; return result;
@ -144,19 +149,24 @@ fn create_html_element(name: QualName,
}, },
Err(error) => { Err(error) => {
// Step 6. Recovering from exception. // Step 6. Recovering from exception.
let global = GlobalScope::current().unwrap_or_else(|| document.global()); let global =
GlobalScope::current().unwrap_or_else(|| document.global());
let cx = global.get_cx(); let cx = global.get_cx();
// Step 6.1.1 // Step 6.1.1
unsafe { unsafe {
let _ac = JSAutoCompartment::new(cx, global.reflector().get_jsobject().get()); let _ac = JSAutoCompartment::new(
cx,
global.reflector().get_jsobject().get(),
);
throw_dom_exception(cx, &global, error); throw_dom_exception(cx, &global, error);
report_pending_exception(cx, true); report_pending_exception(cx, true);
} }
// Step 6.1.2 // Step 6.1.2
let element = DomRoot::upcast::<Element>( let element = DomRoot::upcast::<Element>(HTMLUnknownElement::new(
HTMLUnknownElement::new(local_name, prefix, document)); local_name, prefix, document,
));
element.set_custom_element_state(CustomElementState::Failed); element.set_custom_element_state(CustomElementState::Failed);
element element
}, },
@ -170,11 +180,11 @@ fn create_html_element(name: QualName,
element.set_custom_element_state(CustomElementState::Undefined); element.set_custom_element_state(CustomElementState::Undefined);
match mode { match mode {
// Step 5.3 // Step 5.3
CustomElementCreationMode::Synchronous => CustomElementCreationMode::Synchronous => upgrade_element(definition, &*element),
upgrade_element(definition, &*element),
// Step 5.4 // Step 5.4
CustomElementCreationMode::Asynchronous => CustomElementCreationMode::Asynchronous => {
ScriptThread::enqueue_upgrade_reaction(&*element, definition), ScriptThread::enqueue_upgrade_reaction(&*element, definition)
},
} }
return element; return element;
} }
@ -360,16 +370,17 @@ pub fn create_native_html_element(
} }
} }
pub fn create_element(name: QualName, pub fn create_element(
name: QualName,
is: Option<LocalName>, is: Option<LocalName>,
document: &Document, document: &Document,
creator: ElementCreator, creator: ElementCreator,
mode: CustomElementCreationMode) mode: CustomElementCreationMode,
-> DomRoot<Element> { ) -> DomRoot<Element> {
let prefix = name.prefix.clone(); let prefix = name.prefix.clone();
match name.ns { match name.ns {
ns!(html) => create_html_element(name, prefix, is, document, creator, mode), ns!(html) => create_html_element(name, prefix, is, document, creator, mode),
ns!(svg) => create_svg_element(name, prefix, document), ns!(svg) => create_svg_element(name, prefix, document),
_ => Element::new(name.local, name.ns, prefix, document) _ => Element::new(name.local, name.ns, prefix, document),
} }
} }

View file

@ -36,17 +36,22 @@ impl Crypto {
} }
pub fn new(global: &GlobalScope) -> DomRoot<Crypto> { pub fn new(global: &GlobalScope) -> DomRoot<Crypto> {
reflect_dom_object(Box::new(Crypto::new_inherited()), global, CryptoBinding::Wrap) reflect_dom_object(
Box::new(Crypto::new_inherited()),
global,
CryptoBinding::Wrap,
)
} }
} }
impl CryptoMethods for Crypto { impl CryptoMethods for Crypto {
#[allow(unsafe_code)] #[allow(unsafe_code)]
// https://dvcs.w3.org/hg/webcrypto-api/raw-file/tip/spec/Overview.html#Crypto-method-getRandomValues // https://dvcs.w3.org/hg/webcrypto-api/raw-file/tip/spec/Overview.html#Crypto-method-getRandomValues
unsafe fn GetRandomValues(&self, unsafe fn GetRandomValues(
&self,
_cx: *mut JSContext, _cx: *mut JSContext,
mut input: CustomAutoRooterGuard<ArrayBufferView>) mut input: CustomAutoRooterGuard<ArrayBufferView>,
-> Fallible<NonNull<JSObject>> { ) -> Fallible<NonNull<JSObject>> {
let array_type = input.get_array_type(); let array_type = input.get_array_type();
if !is_integer_buffer(array_type) { if !is_integer_buffer(array_type) {

View file

@ -20,8 +20,10 @@ pub struct CSSConditionRule {
} }
impl CSSConditionRule { impl CSSConditionRule {
pub fn new_inherited(parent_stylesheet: &CSSStyleSheet, pub fn new_inherited(
rules: Arc<Locked<StyleCssRules>>) -> CSSConditionRule { parent_stylesheet: &CSSStyleSheet,
rules: Arc<Locked<StyleCssRules>>,
) -> CSSConditionRule {
CSSConditionRule { CSSConditionRule {
cssgroupingrule: CSSGroupingRule::new_inherited(parent_stylesheet, rules), cssgroupingrule: CSSGroupingRule::new_inherited(parent_stylesheet, rules),
} }

View file

@ -22,8 +22,10 @@ pub struct CSSFontFaceRule {
} }
impl CSSFontFaceRule { impl CSSFontFaceRule {
fn new_inherited(parent_stylesheet: &CSSStyleSheet, fontfacerule: Arc<Locked<FontFaceRule>>) fn new_inherited(
-> CSSFontFaceRule { parent_stylesheet: &CSSStyleSheet,
fontfacerule: Arc<Locked<FontFaceRule>>,
) -> CSSFontFaceRule {
CSSFontFaceRule { CSSFontFaceRule {
cssrule: CSSRule::new_inherited(parent_stylesheet), cssrule: CSSRule::new_inherited(parent_stylesheet),
fontfacerule: fontfacerule, fontfacerule: fontfacerule,
@ -31,11 +33,19 @@ impl CSSFontFaceRule {
} }
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet, pub fn new(
fontfacerule: Arc<Locked<FontFaceRule>>) -> DomRoot<CSSFontFaceRule> { window: &Window,
reflect_dom_object(Box::new(CSSFontFaceRule::new_inherited(parent_stylesheet, fontfacerule)), parent_stylesheet: &CSSStyleSheet,
fontfacerule: Arc<Locked<FontFaceRule>>,
) -> DomRoot<CSSFontFaceRule> {
reflect_dom_object(
Box::new(CSSFontFaceRule::new_inherited(
parent_stylesheet,
fontfacerule,
)),
window, window,
CSSFontFaceRuleBinding::Wrap) CSSFontFaceRuleBinding::Wrap,
)
} }
} }
@ -47,6 +57,9 @@ impl SpecificCSSRule for CSSFontFaceRule {
fn get_css(&self) -> DOMString { fn get_css(&self) -> DOMString {
let guard = self.cssrule.shared_lock().read(); let guard = self.cssrule.shared_lock().read();
self.fontfacerule.read_with(&guard).to_css_string(&guard).into() self.fontfacerule
.read_with(&guard)
.to_css_string(&guard)
.into()
} }
} }

View file

@ -25,8 +25,10 @@ pub struct CSSGroupingRule {
} }
impl CSSGroupingRule { impl CSSGroupingRule {
pub fn new_inherited(parent_stylesheet: &CSSStyleSheet, pub fn new_inherited(
rules: Arc<Locked<StyleCssRules>>) -> CSSGroupingRule { parent_stylesheet: &CSSStyleSheet,
rules: Arc<Locked<StyleCssRules>>,
) -> CSSGroupingRule {
CSSGroupingRule { CSSGroupingRule {
cssrule: CSSRule::new_inherited(parent_stylesheet), cssrule: CSSRule::new_inherited(parent_stylesheet),
rules: rules, rules: rules,
@ -36,9 +38,13 @@ impl CSSGroupingRule {
fn rulelist(&self) -> DomRoot<CSSRuleList> { fn rulelist(&self) -> DomRoot<CSSRuleList> {
let parent_stylesheet = self.upcast::<CSSRule>().parent_stylesheet(); let parent_stylesheet = self.upcast::<CSSRule>().parent_stylesheet();
self.rulelist.or_init(|| CSSRuleList::new(self.global().as_window(), self.rulelist.or_init(|| {
CSSRuleList::new(
self.global().as_window(),
parent_stylesheet, parent_stylesheet,
RulesSource::Rules(self.rules.clone()))) RulesSource::Rules(self.rules.clone()),
)
})
} }
pub fn parent_stylesheet(&self) -> &CSSStyleSheet { pub fn parent_stylesheet(&self) -> &CSSStyleSheet {

View file

@ -22,9 +22,10 @@ pub struct CSSImportRule {
} }
impl CSSImportRule { impl CSSImportRule {
fn new_inherited(parent_stylesheet: &CSSStyleSheet, fn new_inherited(
import_rule: Arc<Locked<ImportRule>>) parent_stylesheet: &CSSStyleSheet,
-> Self { import_rule: Arc<Locked<ImportRule>>,
) -> Self {
CSSImportRule { CSSImportRule {
cssrule: CSSRule::new_inherited(parent_stylesheet), cssrule: CSSRule::new_inherited(parent_stylesheet),
import_rule: import_rule, import_rule: import_rule,
@ -32,12 +33,16 @@ impl CSSImportRule {
} }
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
pub fn new(window: &Window, pub fn new(
window: &Window,
parent_stylesheet: &CSSStyleSheet, parent_stylesheet: &CSSStyleSheet,
import_rule: Arc<Locked<ImportRule>>) -> DomRoot<Self> { import_rule: Arc<Locked<ImportRule>>,
reflect_dom_object(Box::new(Self::new_inherited(parent_stylesheet, import_rule)), ) -> DomRoot<Self> {
reflect_dom_object(
Box::new(Self::new_inherited(parent_stylesheet, import_rule)),
window, window,
CSSImportRuleBinding::Wrap) CSSImportRuleBinding::Wrap,
)
} }
} }
@ -49,6 +54,9 @@ impl SpecificCSSRule for CSSImportRule {
fn get_css(&self) -> DOMString { fn get_css(&self) -> DOMString {
let guard = self.cssrule.shared_lock().read(); let guard = self.cssrule.shared_lock().read();
self.import_rule.read_with(&guard).to_css_string(&guard).into() self.import_rule
.read_with(&guard)
.to_css_string(&guard)
.into()
} }
} }

View file

@ -25,8 +25,10 @@ pub struct CSSKeyframeRule {
} }
impl CSSKeyframeRule { impl CSSKeyframeRule {
fn new_inherited(parent_stylesheet: &CSSStyleSheet, keyframerule: Arc<Locked<Keyframe>>) fn new_inherited(
-> CSSKeyframeRule { parent_stylesheet: &CSSStyleSheet,
keyframerule: Arc<Locked<Keyframe>>,
) -> CSSKeyframeRule {
CSSKeyframeRule { CSSKeyframeRule {
cssrule: CSSRule::new_inherited(parent_stylesheet), cssrule: CSSRule::new_inherited(parent_stylesheet),
keyframerule: keyframerule, keyframerule: keyframerule,
@ -35,11 +37,19 @@ impl CSSKeyframeRule {
} }
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet, pub fn new(
keyframerule: Arc<Locked<Keyframe>>) -> DomRoot<CSSKeyframeRule> { window: &Window,
reflect_dom_object(Box::new(CSSKeyframeRule::new_inherited(parent_stylesheet, keyframerule)), parent_stylesheet: &CSSStyleSheet,
keyframerule: Arc<Locked<Keyframe>>,
) -> DomRoot<CSSKeyframeRule> {
reflect_dom_object(
Box::new(CSSKeyframeRule::new_inherited(
parent_stylesheet,
keyframerule,
)),
window, window,
CSSKeyframeRuleBinding::Wrap) CSSKeyframeRuleBinding::Wrap,
)
} }
} }
@ -69,6 +79,9 @@ impl SpecificCSSRule for CSSKeyframeRule {
fn get_css(&self) -> DOMString { fn get_css(&self) -> DOMString {
let guard = self.cssrule.shared_lock().read(); let guard = self.cssrule.shared_lock().read();
self.keyframerule.read_with(&guard).to_css_string(&guard).into() self.keyframerule
.read_with(&guard)
.to_css_string(&guard)
.into()
} }
} }

View file

@ -30,8 +30,10 @@ pub struct CSSKeyframesRule {
} }
impl CSSKeyframesRule { impl CSSKeyframesRule {
fn new_inherited(parent_stylesheet: &CSSStyleSheet, keyframesrule: Arc<Locked<KeyframesRule>>) fn new_inherited(
-> CSSKeyframesRule { parent_stylesheet: &CSSStyleSheet,
keyframesrule: Arc<Locked<KeyframesRule>>,
) -> CSSKeyframesRule {
CSSKeyframesRule { CSSKeyframesRule {
cssrule: CSSRule::new_inherited(parent_stylesheet), cssrule: CSSRule::new_inherited(parent_stylesheet),
keyframesrule: keyframesrule, keyframesrule: keyframesrule,
@ -40,19 +42,29 @@ impl CSSKeyframesRule {
} }
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet, pub fn new(
keyframesrule: Arc<Locked<KeyframesRule>>) -> DomRoot<CSSKeyframesRule> { window: &Window,
reflect_dom_object(Box::new(CSSKeyframesRule::new_inherited(parent_stylesheet, keyframesrule)), parent_stylesheet: &CSSStyleSheet,
keyframesrule: Arc<Locked<KeyframesRule>>,
) -> DomRoot<CSSKeyframesRule> {
reflect_dom_object(
Box::new(CSSKeyframesRule::new_inherited(
parent_stylesheet,
keyframesrule,
)),
window, window,
CSSKeyframesRuleBinding::Wrap) CSSKeyframesRuleBinding::Wrap,
)
} }
fn rulelist(&self) -> DomRoot<CSSRuleList> { fn rulelist(&self) -> DomRoot<CSSRuleList> {
self.rulelist.or_init(|| { self.rulelist.or_init(|| {
let parent_stylesheet = &self.upcast::<CSSRule>().parent_stylesheet(); let parent_stylesheet = &self.upcast::<CSSRule>().parent_stylesheet();
CSSRuleList::new(self.global().as_window(), CSSRuleList::new(
self.global().as_window(),
parent_stylesheet, parent_stylesheet,
RulesSource::Keyframes(self.keyframesrule.clone())) RulesSource::Keyframes(self.keyframesrule.clone()),
)
}) })
} }
@ -64,10 +76,11 @@ impl CSSKeyframesRule {
let guard = self.cssrule.shared_lock().read(); let guard = self.cssrule.shared_lock().read();
// This finds the *last* element matching a selector // This finds the *last* element matching a selector
// because that's the rule that applies. Thus, rposition // because that's the rule that applies. Thus, rposition
self.keyframesrule.read_with(&guard) self.keyframesrule
.keyframes.iter().rposition(|frame| { .read_with(&guard)
frame.read_with(&guard).selector == sel .keyframes
}) .iter()
.rposition(|frame| frame.read_with(&guard).selector == sel)
} else { } else {
None None
} }
@ -86,12 +99,15 @@ impl CSSKeyframesRuleMethods for CSSKeyframesRule {
let rule = Keyframe::parse( let rule = Keyframe::parse(
&rule, &rule,
&style_stylesheet.contents, &style_stylesheet.contents,
&style_stylesheet.shared_lock &style_stylesheet.shared_lock,
); );
if let Ok(rule) = rule { if let Ok(rule) = rule {
let mut guard = self.cssrule.shared_lock().write(); let mut guard = self.cssrule.shared_lock().write();
self.keyframesrule.write_with(&mut guard).keyframes.push(rule); self.keyframesrule
.write_with(&mut guard)
.keyframes
.push(rule);
self.rulelist().append_lazy_dom_rule(); self.rulelist().append_lazy_dom_rule();
} }
} }
@ -105,9 +121,9 @@ impl CSSKeyframesRuleMethods for CSSKeyframesRule {
// https://drafts.csswg.org/css-animations/#dom-csskeyframesrule-findrule // https://drafts.csswg.org/css-animations/#dom-csskeyframesrule-findrule
fn FindRule(&self, selector: DOMString) -> Option<DomRoot<CSSKeyframeRule>> { fn FindRule(&self, selector: DOMString) -> Option<DomRoot<CSSKeyframeRule>> {
self.find_rule(&selector).and_then(|idx| { self.find_rule(&selector)
self.rulelist().item(idx as u32) .and_then(|idx| self.rulelist().item(idx as u32))
}).and_then(DomRoot::downcast) .and_then(DomRoot::downcast)
} }
// https://drafts.csswg.org/css-animations/#dom-csskeyframesrule-name // https://drafts.csswg.org/css-animations/#dom-csskeyframesrule-name
@ -136,7 +152,10 @@ impl SpecificCSSRule for CSSKeyframesRule {
fn get_css(&self) -> DOMString { fn get_css(&self) -> DOMString {
let guard = self.cssrule.shared_lock().read(); let guard = self.cssrule.shared_lock().read();
self.keyframesrule.read_with(&guard).to_css_string(&guard).into() self.keyframesrule
.read_with(&guard)
.to_css_string(&guard)
.into()
} }
fn deparent_children(&self) { fn deparent_children(&self) {

View file

@ -31,8 +31,10 @@ pub struct CSSMediaRule {
} }
impl CSSMediaRule { impl CSSMediaRule {
fn new_inherited(parent_stylesheet: &CSSStyleSheet, mediarule: Arc<Locked<MediaRule>>) fn new_inherited(
-> CSSMediaRule { parent_stylesheet: &CSSStyleSheet,
mediarule: Arc<Locked<MediaRule>>,
) -> CSSMediaRule {
let guard = parent_stylesheet.shared_lock().read(); let guard = parent_stylesheet.shared_lock().read();
let list = mediarule.read_with(&guard).rules.clone(); let list = mediarule.read_with(&guard).rules.clone();
CSSMediaRule { CSSMediaRule {
@ -43,19 +45,26 @@ impl CSSMediaRule {
} }
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet, pub fn new(
mediarule: Arc<Locked<MediaRule>>) -> DomRoot<CSSMediaRule> { window: &Window,
reflect_dom_object(Box::new(CSSMediaRule::new_inherited(parent_stylesheet, mediarule)), parent_stylesheet: &CSSStyleSheet,
mediarule: Arc<Locked<MediaRule>>,
) -> DomRoot<CSSMediaRule> {
reflect_dom_object(
Box::new(CSSMediaRule::new_inherited(parent_stylesheet, mediarule)),
window, window,
CSSMediaRuleBinding::Wrap) CSSMediaRuleBinding::Wrap,
)
} }
fn medialist(&self) -> DomRoot<MediaList> { fn medialist(&self) -> DomRoot<MediaList> {
self.medialist.or_init(|| { self.medialist.or_init(|| {
let guard = self.cssconditionrule.shared_lock().read(); let guard = self.cssconditionrule.shared_lock().read();
MediaList::new(self.global().as_window(), MediaList::new(
self.global().as_window(),
self.cssconditionrule.parent_stylesheet(), self.cssconditionrule.parent_stylesheet(),
self.mediarule.read_with(&guard).media_queries.clone()) self.mediarule.read_with(&guard).media_queries.clone(),
)
}) })
} }
@ -106,7 +115,10 @@ impl SpecificCSSRule for CSSMediaRule {
fn get_css(&self) -> DOMString { fn get_css(&self) -> DOMString {
let guard = self.cssconditionrule.shared_lock().read(); let guard = self.cssconditionrule.shared_lock().read();
self.mediarule.read_with(&guard).to_css_string(&guard).into() self.mediarule
.read_with(&guard)
.to_css_string(&guard)
.into()
} }
} }

View file

@ -23,8 +23,10 @@ pub struct CSSNamespaceRule {
} }
impl CSSNamespaceRule { impl CSSNamespaceRule {
fn new_inherited(parent_stylesheet: &CSSStyleSheet, namespacerule: Arc<Locked<NamespaceRule>>) fn new_inherited(
-> CSSNamespaceRule { parent_stylesheet: &CSSStyleSheet,
namespacerule: Arc<Locked<NamespaceRule>>,
) -> CSSNamespaceRule {
CSSNamespaceRule { CSSNamespaceRule {
cssrule: CSSRule::new_inherited(parent_stylesheet), cssrule: CSSRule::new_inherited(parent_stylesheet),
namespacerule: namespacerule, namespacerule: namespacerule,
@ -32,11 +34,19 @@ impl CSSNamespaceRule {
} }
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet, pub fn new(
namespacerule: Arc<Locked<NamespaceRule>>) -> DomRoot<CSSNamespaceRule> { window: &Window,
reflect_dom_object(Box::new(CSSNamespaceRule::new_inherited(parent_stylesheet, namespacerule)), parent_stylesheet: &CSSStyleSheet,
namespacerule: Arc<Locked<NamespaceRule>>,
) -> DomRoot<CSSNamespaceRule> {
reflect_dom_object(
Box::new(CSSNamespaceRule::new_inherited(
parent_stylesheet,
namespacerule,
)),
window, window,
CSSNamespaceRuleBinding::Wrap) CSSNamespaceRuleBinding::Wrap,
)
} }
} }
@ -44,8 +54,11 @@ impl CSSNamespaceRuleMethods for CSSNamespaceRule {
// https://drafts.csswg.org/cssom/#dom-cssnamespacerule-prefix // https://drafts.csswg.org/cssom/#dom-cssnamespacerule-prefix
fn Prefix(&self) -> DOMString { fn Prefix(&self) -> DOMString {
let guard = self.cssrule.shared_lock().read(); let guard = self.cssrule.shared_lock().read();
self.namespacerule.read_with(&guard).prefix self.namespacerule
.as_ref().map(|s| s.to_string().into()) .read_with(&guard)
.prefix
.as_ref()
.map(|s| s.to_string().into())
.unwrap_or(DOMString::new()) .unwrap_or(DOMString::new())
} }
@ -64,6 +77,9 @@ impl SpecificCSSRule for CSSNamespaceRule {
fn get_css(&self) -> DOMString { fn get_css(&self) -> DOMString {
let guard = self.cssrule.shared_lock().read(); let guard = self.cssrule.shared_lock().read();
self.namespacerule.read_with(&guard).to_css_string(&guard).into() self.namespacerule
.read_with(&guard)
.to_css_string(&guard)
.into()
} }
} }

View file

@ -23,7 +23,6 @@ use std::cell::Cell;
use style::shared_lock::SharedRwLock; use style::shared_lock::SharedRwLock;
use style::stylesheets::CssRule as StyleCssRule; use style::stylesheets::CssRule as StyleCssRule;
#[dom_struct] #[dom_struct]
pub struct CSSRule { pub struct CSSRule {
reflector_: Reflector, reflector_: Reflector,
@ -71,20 +70,39 @@ impl CSSRule {
// Given a StyleCssRule, create a new instance of a derived class of // Given a StyleCssRule, create a new instance of a derived class of
// CSSRule based on which rule it is // CSSRule based on which rule it is
pub fn new_specific(window: &Window, parent_stylesheet: &CSSStyleSheet, pub fn new_specific(
rule: StyleCssRule) -> DomRoot<CSSRule> { window: &Window,
parent_stylesheet: &CSSStyleSheet,
rule: StyleCssRule,
) -> DomRoot<CSSRule> {
// be sure to update the match in as_specific when this is updated // be sure to update the match in as_specific when this is updated
match rule { match rule {
StyleCssRule::Import(s) => DomRoot::upcast(CSSImportRule::new(window, parent_stylesheet, s)), StyleCssRule::Import(s) => {
StyleCssRule::Style(s) => DomRoot::upcast(CSSStyleRule::new(window, parent_stylesheet, s)), DomRoot::upcast(CSSImportRule::new(window, parent_stylesheet, s))
StyleCssRule::FontFace(s) => DomRoot::upcast(CSSFontFaceRule::new(window, parent_stylesheet, s)), },
StyleCssRule::Style(s) => {
DomRoot::upcast(CSSStyleRule::new(window, parent_stylesheet, s))
},
StyleCssRule::FontFace(s) => {
DomRoot::upcast(CSSFontFaceRule::new(window, parent_stylesheet, s))
},
StyleCssRule::FontFeatureValues(_) => unimplemented!(), StyleCssRule::FontFeatureValues(_) => unimplemented!(),
StyleCssRule::CounterStyle(_) => unimplemented!(), StyleCssRule::CounterStyle(_) => unimplemented!(),
StyleCssRule::Keyframes(s) => DomRoot::upcast(CSSKeyframesRule::new(window, parent_stylesheet, s)), StyleCssRule::Keyframes(s) => {
StyleCssRule::Media(s) => DomRoot::upcast(CSSMediaRule::new(window, parent_stylesheet, s)), DomRoot::upcast(CSSKeyframesRule::new(window, parent_stylesheet, s))
StyleCssRule::Namespace(s) => DomRoot::upcast(CSSNamespaceRule::new(window, parent_stylesheet, s)), },
StyleCssRule::Viewport(s) => DomRoot::upcast(CSSViewportRule::new(window, parent_stylesheet, s)), StyleCssRule::Media(s) => {
StyleCssRule::Supports(s) => DomRoot::upcast(CSSSupportsRule::new(window, parent_stylesheet, s)), DomRoot::upcast(CSSMediaRule::new(window, parent_stylesheet, s))
},
StyleCssRule::Namespace(s) => {
DomRoot::upcast(CSSNamespaceRule::new(window, parent_stylesheet, s))
},
StyleCssRule::Viewport(s) => {
DomRoot::upcast(CSSViewportRule::new(window, parent_stylesheet, s))
},
StyleCssRule::Supports(s) => {
DomRoot::upcast(CSSSupportsRule::new(window, parent_stylesheet, s))
},
StyleCssRule::Page(_) => unreachable!(), StyleCssRule::Page(_) => unreachable!(),
StyleCssRule::Document(_) => unimplemented!(), // TODO StyleCssRule::Document(_) => unimplemented!(), // TODO
} }

View file

@ -39,7 +39,7 @@ pub struct CSSRuleList {
parent_stylesheet: Dom<CSSStyleSheet>, parent_stylesheet: Dom<CSSStyleSheet>,
#[ignore_malloc_size_of = "Arc"] #[ignore_malloc_size_of = "Arc"]
rules: RulesSource, rules: RulesSource,
dom_rules: DomRefCell<Vec<MutNullableDom<CSSRule>>> dom_rules: DomRefCell<Vec<MutNullableDom<CSSRule>>>,
} }
pub enum RulesSource { pub enum RulesSource {
@ -52,12 +52,18 @@ impl CSSRuleList {
pub fn new_inherited(parent_stylesheet: &CSSStyleSheet, rules: RulesSource) -> CSSRuleList { pub fn new_inherited(parent_stylesheet: &CSSStyleSheet, rules: RulesSource) -> CSSRuleList {
let guard = parent_stylesheet.shared_lock().read(); let guard = parent_stylesheet.shared_lock().read();
let dom_rules = match rules { let dom_rules = match rules {
RulesSource::Rules(ref rules) => { RulesSource::Rules(ref rules) => rules
rules.read_with(&guard).0.iter().map(|_| MutNullableDom::new(None)).collect() .read_with(&guard)
} .0
RulesSource::Keyframes(ref rules) => { .iter()
rules.read_with(&guard).keyframes.iter().map(|_| MutNullableDom::new(None)).collect() .map(|_| MutNullableDom::new(None))
} .collect(),
RulesSource::Keyframes(ref rules) => rules
.read_with(&guard)
.keyframes
.iter()
.map(|_| MutNullableDom::new(None))
.collect(),
}; };
CSSRuleList { CSSRuleList {
@ -69,11 +75,16 @@ impl CSSRuleList {
} }
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet, pub fn new(
rules: RulesSource) -> DomRoot<CSSRuleList> { window: &Window,
reflect_dom_object(Box::new(CSSRuleList::new_inherited(parent_stylesheet, rules)), parent_stylesheet: &CSSStyleSheet,
rules: RulesSource,
) -> DomRoot<CSSRuleList> {
reflect_dom_object(
Box::new(CSSRuleList::new_inherited(parent_stylesheet, rules)),
window, window,
CSSRuleListBinding::Wrap) CSSRuleListBinding::Wrap,
)
} }
/// Should only be called for CssRules-backed rules. Use append_lazy_rule /// Should only be called for CssRules-backed rules. Use append_lazy_rule
@ -91,18 +102,21 @@ impl CSSRuleList {
let parent_stylesheet = self.parent_stylesheet.style_stylesheet(); let parent_stylesheet = self.parent_stylesheet.style_stylesheet();
let new_rule = css_rules.with_raw_offset_arc(|arc| { let new_rule = css_rules.with_raw_offset_arc(|arc| {
arc.insert_rule(&parent_stylesheet.shared_lock, arc.insert_rule(
&parent_stylesheet.shared_lock,
rule, rule,
&parent_stylesheet.contents, &parent_stylesheet.contents,
index, index,
nested, nested,
None) None,
)
})?; })?;
let parent_stylesheet = &*self.parent_stylesheet; let parent_stylesheet = &*self.parent_stylesheet;
let dom_rule = CSSRule::new_specific(&window, parent_stylesheet, new_rule); let dom_rule = CSSRule::new_specific(&window, parent_stylesheet, new_rule);
self.dom_rules.borrow_mut().insert(index, MutNullableDom::new(Some(&*dom_rule))); self.dom_rules
.borrow_mut()
.insert(index, MutNullableDom::new(Some(&*dom_rule)));
Ok(idx) Ok(idx)
} }
@ -118,7 +132,7 @@ impl CSSRuleList {
dom_rules[index].get().map(|r| r.detach()); dom_rules[index].get().map(|r| r.detach());
dom_rules.remove(index); dom_rules.remove(index);
Ok(()) Ok(())
} },
RulesSource::Keyframes(ref kf) => { RulesSource::Keyframes(ref kf) => {
// https://drafts.csswg.org/css-animations/#dom-csskeyframesrule-deleterule // https://drafts.csswg.org/css-animations/#dom-csskeyframesrule-deleterule
let mut dom_rules = self.dom_rules.borrow_mut(); let mut dom_rules = self.dom_rules.borrow_mut();
@ -126,7 +140,7 @@ impl CSSRuleList {
dom_rules.remove(index); dom_rules.remove(index);
kf.write_with(&mut guard).keyframes.remove(index); kf.write_with(&mut guard).keyframes.remove(index);
Ok(()) Ok(())
} },
} }
} }
@ -143,20 +157,17 @@ impl CSSRuleList {
let parent_stylesheet = &self.parent_stylesheet; let parent_stylesheet = &self.parent_stylesheet;
let guard = parent_stylesheet.shared_lock().read(); let guard = parent_stylesheet.shared_lock().read();
match self.rules { match self.rules {
RulesSource::Rules(ref rules) => { RulesSource::Rules(ref rules) => CSSRule::new_specific(
CSSRule::new_specific(self.global().as_window(), self.global().as_window(),
parent_stylesheet, parent_stylesheet,
rules.read_with(&guard).0[idx as usize].clone()) rules.read_with(&guard).0[idx as usize].clone(),
} ),
RulesSource::Keyframes(ref rules) => { RulesSource::Keyframes(ref rules) => DomRoot::upcast(CSSKeyframeRule::new(
DomRoot::upcast(CSSKeyframeRule::new(self.global().as_window(), self.global().as_window(),
parent_stylesheet, parent_stylesheet,
rules.read_with(&guard) rules.read_with(&guard).keyframes[idx as usize].clone(),
.keyframes[idx as usize] )),
.clone()))
} }
}
}) })
}) })
} }
@ -190,4 +201,3 @@ impl CSSRuleListMethods for CSSRuleList {
self.Item(index) self.Item(index)
} }
} }

View file

@ -36,16 +36,18 @@ pub struct CSSStyleDeclaration {
#[must_root] #[must_root]
pub enum CSSStyleOwner { pub enum CSSStyleOwner {
Element(Dom<Element>), Element(Dom<Element>),
CSSRule(Dom<CSSRule>, CSSRule(
#[ignore_malloc_size_of = "Arc"] Dom<CSSRule>,
Arc<Locked<PropertyDeclarationBlock>>), #[ignore_malloc_size_of = "Arc"] Arc<Locked<PropertyDeclarationBlock>>,
),
} }
impl CSSStyleOwner { impl CSSStyleOwner {
// Mutate the declaration block associated to this style owner, and // Mutate the declaration block associated to this style owner, and
// optionally indicate if it has changed (assumed to be true). // optionally indicate if it has changed (assumed to be true).
fn mutate_associated_block<F, R>(&self, f: F) -> R fn mutate_associated_block<F, R>(&self, f: F) -> R
where F: FnOnce(&mut PropertyDeclarationBlock, &mut bool) -> R, where
F: FnOnce(&mut PropertyDeclarationBlock, &mut bool) -> R,
{ {
// TODO(emilio): This has some duplication just to avoid dummy clones. // TODO(emilio): This has some duplication just to avoid dummy clones.
// //
@ -87,9 +89,10 @@ impl CSSStyleOwner {
let guard = shared_lock.read(); let guard = shared_lock.read();
let mut serialization = String::new(); let mut serialization = String::new();
pdb.read_with(&guard).to_css(&mut serialization).unwrap(); pdb.read_with(&guard).to_css(&mut serialization).unwrap();
el.set_attribute(&local_name!("style"), el.set_attribute(
AttrValue::Declaration(serialization, &local_name!("style"),
pdb)); AttrValue::Declaration(serialization, pdb),
);
} }
} else { } else {
// Remember to put it back. // Remember to put it back.
@ -97,7 +100,7 @@ impl CSSStyleOwner {
} }
result result
} },
CSSStyleOwner::CSSRule(ref rule, ref pdb) => { CSSStyleOwner::CSSRule(ref rule, ref pdb) => {
let result = { let result = {
let mut guard = rule.shared_lock().write(); let mut guard = rule.shared_lock().write();
@ -106,34 +109,36 @@ impl CSSStyleOwner {
if changed { if changed {
// If this is changed, see also // If this is changed, see also
// CSSStyleRule::SetSelectorText, which does the same thing. // CSSStyleRule::SetSelectorText, which does the same thing.
rule.global().as_window().Document().invalidate_stylesheets(); rule.global()
.as_window()
.Document()
.invalidate_stylesheets();
} }
result result
} },
} }
} }
fn with_block<F, R>(&self, f: F) -> R fn with_block<F, R>(&self, f: F) -> R
where F: FnOnce(&PropertyDeclarationBlock) -> R, where
F: FnOnce(&PropertyDeclarationBlock) -> R,
{ {
match *self { match *self {
CSSStyleOwner::Element(ref el) => { CSSStyleOwner::Element(ref el) => match *el.style_attribute().borrow() {
match *el.style_attribute().borrow() {
Some(ref pdb) => { Some(ref pdb) => {
let document = document_from_node(&**el); let document = document_from_node(&**el);
let guard = document.style_shared_lock().read(); let guard = document.style_shared_lock().read();
f(pdb.read_with(&guard)) f(pdb.read_with(&guard))
} },
None => { None => {
let pdb = PropertyDeclarationBlock::new(); let pdb = PropertyDeclarationBlock::new();
f(&pdb) f(&pdb)
} },
} },
}
CSSStyleOwner::CSSRule(ref rule, ref pdb) => { CSSStyleOwner::CSSRule(ref rule, ref pdb) => {
let guard = rule.shared_lock().read(); let guard = rule.shared_lock().read();
f(pdb.read_with(&guard)) f(pdb.read_with(&guard))
} },
} }
} }
@ -147,9 +152,12 @@ impl CSSStyleOwner {
fn base_url(&self) -> ServoUrl { fn base_url(&self) -> ServoUrl {
match *self { match *self {
CSSStyleOwner::Element(ref el) => window_from_node(&**el).Document().base_url(), CSSStyleOwner::Element(ref el) => window_from_node(&**el).Document().base_url(),
CSSStyleOwner::CSSRule(ref rule, _) => { CSSStyleOwner::CSSRule(ref rule, _) => (*rule
(*rule.parent_stylesheet().style_stylesheet().contents.url_data.read()).clone() .parent_stylesheet()
} .style_stylesheet()
.contents
.url_data
.read()).clone(),
} }
} }
} }
@ -181,10 +189,7 @@ macro_rules! css_properties(
); );
); );
fn remove_property( fn remove_property(decls: &mut PropertyDeclarationBlock, id: &PropertyId) -> bool {
decls: &mut PropertyDeclarationBlock,
id: &PropertyId,
) -> bool {
let first_declaration = decls.first_declaration_to_remove(id); let first_declaration = decls.first_declaration_to_remove(id);
let first_declaration = match first_declaration { let first_declaration = match first_declaration {
Some(i) => i, Some(i) => i,
@ -196,10 +201,11 @@ fn remove_property(
impl CSSStyleDeclaration { impl CSSStyleDeclaration {
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
pub fn new_inherited(owner: CSSStyleOwner, pub fn new_inherited(
owner: CSSStyleOwner,
pseudo: Option<PseudoElement>, pseudo: Option<PseudoElement>,
modification_access: CSSModificationAccess) modification_access: CSSModificationAccess,
-> CSSStyleDeclaration { ) -> CSSStyleDeclaration {
CSSStyleDeclaration { CSSStyleDeclaration {
reflector_: Reflector::new(), reflector_: Reflector::new(),
owner: owner, owner: owner,
@ -209,22 +215,28 @@ impl CSSStyleDeclaration {
} }
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
pub fn new(global: &Window, pub fn new(
global: &Window,
owner: CSSStyleOwner, owner: CSSStyleOwner,
pseudo: Option<PseudoElement>, pseudo: Option<PseudoElement>,
modification_access: CSSModificationAccess) modification_access: CSSModificationAccess,
-> DomRoot<CSSStyleDeclaration> { ) -> DomRoot<CSSStyleDeclaration> {
reflect_dom_object( reflect_dom_object(
Box::new(CSSStyleDeclaration::new_inherited(owner, pseudo, modification_access)), Box::new(CSSStyleDeclaration::new_inherited(
owner,
pseudo,
modification_access,
)),
global, global,
CSSStyleDeclarationBinding::Wrap CSSStyleDeclarationBinding::Wrap,
) )
} }
fn get_computed_style(&self, property: PropertyId) -> DOMString { fn get_computed_style(&self, property: PropertyId) -> DOMString {
match self.owner { match self.owner {
CSSStyleOwner::CSSRule(..) => CSSStyleOwner::CSSRule(..) => {
panic!("get_computed_style called on CSSStyleDeclaration with a CSSRule owner"), panic!("get_computed_style called on CSSStyleDeclaration with a CSSRule owner")
},
CSSStyleOwner::Element(ref el) => { CSSStyleOwner::Element(ref el) => {
let node = el.upcast::<Node>(); let node = el.upcast::<Node>();
if !node.is_in_doc() { if !node.is_in_doc() {
@ -234,7 +246,7 @@ impl CSSStyleDeclaration {
} }
let addr = node.to_trusted_node_address(); let addr = node.to_trusted_node_address();
window_from_node(node).resolved_style_query(addr, self.pseudo.clone(), property) window_from_node(node).resolved_style_query(addr, self.pseudo.clone(), property)
} },
} }
} }
@ -277,7 +289,7 @@ impl CSSStyleDeclaration {
_ => { _ => {
*changed = false; *changed = false;
return Ok(()); return Ok(());
} },
}; };
// Step 5 // Step 5
@ -300,12 +312,11 @@ impl CSSStyleDeclaration {
Err(_) => { Err(_) => {
*changed = false; *changed = false;
return Ok(()); return Ok(());
} },
} }
let mut updates = Default::default(); let mut updates = Default::default();
*changed = *changed = pdb.prepare_for_update(&declarations, importance, &mut updates);
pdb.prepare_for_update(&declarations, importance, &mut updates);
if !*changed { if !*changed {
return Ok(()); return Ok(());
@ -323,9 +334,7 @@ impl CSSStyleDeclaration {
impl CSSStyleDeclarationMethods for CSSStyleDeclaration { impl CSSStyleDeclarationMethods for CSSStyleDeclaration {
// https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-length // https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-length
fn Length(&self) -> u32 { fn Length(&self) -> u32 {
self.owner.with_block(|pdb| { self.owner.with_block(|pdb| pdb.declarations().len() as u32)
pdb.declarations().len() as u32
})
} }
// https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-item // https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-item
@ -360,11 +369,12 @@ impl CSSStyleDeclarationMethods for CSSStyleDeclaration {
} }
// https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-setproperty // https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-setproperty
fn SetProperty(&self, fn SetProperty(
&self,
property: DOMString, property: DOMString,
value: DOMString, value: DOMString,
priority: DOMString) priority: DOMString,
-> ErrorResult { ) -> ErrorResult {
// Step 3 // Step 3
let id = match PropertyId::parse_enabled_for_all_content(&property) { let id = match PropertyId::parse_enabled_for_all_content(&property) {
Ok(id) => id, Ok(id) => id,
@ -444,10 +454,12 @@ impl CSSStyleDeclarationMethods for CSSStyleDeclaration {
let quirks_mode = window.Document().quirks_mode(); let quirks_mode = window.Document().quirks_mode();
self.owner.mutate_associated_block(|pdb, _changed| { self.owner.mutate_associated_block(|pdb, _changed| {
// Step 3 // Step 3
*pdb = parse_style_attribute(&value, *pdb = parse_style_attribute(
&value,
&self.owner.base_url(), &self.owner.base_url(),
window.css_error_reporter(), window.css_error_reporter(),
quirks_mode); quirks_mode,
);
}); });
Ok(()) Ok(())

View file

@ -31,8 +31,10 @@ pub struct CSSStyleRule {
} }
impl CSSStyleRule { impl CSSStyleRule {
fn new_inherited(parent_stylesheet: &CSSStyleSheet, stylerule: Arc<Locked<StyleRule>>) fn new_inherited(
-> CSSStyleRule { parent_stylesheet: &CSSStyleSheet,
stylerule: Arc<Locked<StyleRule>>,
) -> CSSStyleRule {
CSSStyleRule { CSSStyleRule {
cssrule: CSSRule::new_inherited(parent_stylesheet), cssrule: CSSRule::new_inherited(parent_stylesheet),
stylerule: stylerule, stylerule: stylerule,
@ -41,11 +43,16 @@ impl CSSStyleRule {
} }
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet, pub fn new(
stylerule: Arc<Locked<StyleRule>>) -> DomRoot<CSSStyleRule> { window: &Window,
reflect_dom_object(Box::new(CSSStyleRule::new_inherited(parent_stylesheet, stylerule)), parent_stylesheet: &CSSStyleSheet,
stylerule: Arc<Locked<StyleRule>>,
) -> DomRoot<CSSStyleRule> {
reflect_dom_object(
Box::new(CSSStyleRule::new_inherited(parent_stylesheet, stylerule)),
window, window,
CSSStyleRuleBinding::Wrap) CSSStyleRuleBinding::Wrap,
)
} }
} }
@ -57,7 +64,10 @@ impl SpecificCSSRule for CSSStyleRule {
fn get_css(&self) -> DOMString { fn get_css(&self) -> DOMString {
let guard = self.cssrule.shared_lock().read(); let guard = self.cssrule.shared_lock().read();
self.stylerule.read_with(&guard).to_css_string(&guard).into() self.stylerule
.read_with(&guard)
.to_css_string(&guard)
.into()
} }
} }
@ -70,10 +80,10 @@ impl CSSStyleRuleMethods for CSSStyleRule {
self.global().as_window(), self.global().as_window(),
CSSStyleOwner::CSSRule( CSSStyleOwner::CSSRule(
Dom::from_ref(self.upcast()), Dom::from_ref(self.upcast()),
self.stylerule.read_with(&guard).block.clone() self.stylerule.read_with(&guard).block.clone(),
), ),
None, None,
CSSModificationAccess::ReadWrite CSSModificationAccess::ReadWrite,
) )
}) })
} }
@ -89,7 +99,13 @@ impl CSSStyleRuleMethods for CSSStyleRule {
fn SetSelectorText(&self, value: DOMString) { fn SetSelectorText(&self, value: DOMString) {
// It's not clear from the spec if we should use the stylesheet's namespaces. // It's not clear from the spec if we should use the stylesheet's namespaces.
// https://github.com/w3c/csswg-drafts/issues/1511 // https://github.com/w3c/csswg-drafts/issues/1511
let namespaces = self.cssrule.parent_stylesheet().style_stylesheet().contents.namespaces.read(); let namespaces = self
.cssrule
.parent_stylesheet()
.style_stylesheet()
.contents
.namespaces
.read();
let parser = SelectorParser { let parser = SelectorParser {
stylesheet_origin: Origin::Author, stylesheet_origin: Origin::Author,
namespaces: &namespaces, namespaces: &namespaces,
@ -104,7 +120,10 @@ impl CSSStyleRuleMethods for CSSStyleRule {
mem::swap(&mut stylerule.selectors, &mut s); mem::swap(&mut stylerule.selectors, &mut s);
// It seems like we will want to avoid having to invalidate all // It seems like we will want to avoid having to invalidate all
// stylesheets eventually! // stylesheets eventually!
self.global().as_window().Document().invalidate_stylesheets(); self.global()
.as_window()
.Document()
.invalidate_stylesheets();
} }
} }
} }

View file

@ -30,11 +30,13 @@ pub struct CSSStyleSheet {
} }
impl CSSStyleSheet { impl CSSStyleSheet {
fn new_inherited(owner: &Element, fn new_inherited(
owner: &Element,
type_: DOMString, type_: DOMString,
href: Option<DOMString>, href: Option<DOMString>,
title: Option<DOMString>, title: Option<DOMString>,
stylesheet: Arc<StyleStyleSheet>) -> CSSStyleSheet { stylesheet: Arc<StyleStyleSheet>,
) -> CSSStyleSheet {
CSSStyleSheet { CSSStyleSheet {
stylesheet: StyleSheet::new_inherited(type_, href, title), stylesheet: StyleSheet::new_inherited(type_, href, title),
owner: Dom::from_ref(owner), owner: Dom::from_ref(owner),
@ -45,25 +47,27 @@ impl CSSStyleSheet {
} }
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
pub fn new(window: &Window, pub fn new(
window: &Window,
owner: &Element, owner: &Element,
type_: DOMString, type_: DOMString,
href: Option<DOMString>, href: Option<DOMString>,
title: Option<DOMString>, title: Option<DOMString>,
stylesheet: Arc<StyleStyleSheet>) -> DomRoot<CSSStyleSheet> { stylesheet: Arc<StyleStyleSheet>,
reflect_dom_object(Box::new(CSSStyleSheet::new_inherited(owner, type_, href, title, stylesheet)), ) -> DomRoot<CSSStyleSheet> {
reflect_dom_object(
Box::new(CSSStyleSheet::new_inherited(
owner, type_, href, title, stylesheet,
)),
window, window,
CSSStyleSheetBinding::Wrap) CSSStyleSheetBinding::Wrap,
)
} }
fn rulelist(&self) -> DomRoot<CSSRuleList> { fn rulelist(&self) -> DomRoot<CSSRuleList> {
self.rulelist.or_init(|| { self.rulelist.or_init(|| {
let rules = self.style_stylesheet.contents.rules.clone(); let rules = self.style_stylesheet.contents.rules.clone();
CSSRuleList::new( CSSRuleList::new(self.global().as_window(), self, RulesSource::Rules(rules))
self.global().as_window(),
self,
RulesSource::Rules(rules)
)
}) })
} }
@ -73,7 +77,10 @@ impl CSSStyleSheet {
pub fn set_disabled(&self, disabled: bool) { pub fn set_disabled(&self, disabled: bool) {
if self.style_stylesheet.set_disabled(disabled) { if self.style_stylesheet.set_disabled(disabled) {
self.global().as_window().Document().invalidate_stylesheets(); self.global()
.as_window()
.Document()
.invalidate_stylesheets();
} }
} }
@ -104,7 +111,8 @@ impl CSSStyleSheetMethods for CSSStyleSheet {
if !self.origin_clean.get() { if !self.origin_clean.get() {
return Err(Error::Security); return Err(Error::Security);
} }
self.rulelist().insert_rule(&rule, index, /* nested */ false) self.rulelist()
.insert_rule(&rule, index, /* nested */ false)
} }
// https://drafts.csswg.org/cssom/#dom-cssstylesheet-deleterule // https://drafts.csswg.org/cssom/#dom-cssstylesheet-deleterule
@ -115,4 +123,3 @@ impl CSSStyleSheetMethods for CSSStyleSheet {
self.rulelist().remove_rule(index) self.rulelist().remove_rule(index)
} }
} }

View file

@ -48,7 +48,9 @@ impl CSSStyleValue {
pub fn get_url(&self, base_url: ServoUrl) -> Option<ServoUrl> { pub fn get_url(&self, base_url: ServoUrl) -> Option<ServoUrl> {
let mut input = ParserInput::new(&*self.value); let mut input = ParserInput::new(&*self.value);
let mut parser = Parser::new(&mut input); let mut parser = Parser::new(&mut input);
parser.expect_url().ok() parser
.expect_url()
.ok()
.and_then(|string| base_url.join(&*string).ok()) .and_then(|string| base_url.join(&*string).ok())
} }
} }

View file

@ -28,8 +28,10 @@ pub struct CSSSupportsRule {
} }
impl CSSSupportsRule { impl CSSSupportsRule {
fn new_inherited(parent_stylesheet: &CSSStyleSheet, supportsrule: Arc<Locked<SupportsRule>>) fn new_inherited(
-> CSSSupportsRule { parent_stylesheet: &CSSStyleSheet,
supportsrule: Arc<Locked<SupportsRule>>,
) -> CSSSupportsRule {
let guard = parent_stylesheet.shared_lock().read(); let guard = parent_stylesheet.shared_lock().read();
let list = supportsrule.read_with(&guard).rules.clone(); let list = supportsrule.read_with(&guard).rules.clone();
CSSSupportsRule { CSSSupportsRule {
@ -39,11 +41,19 @@ impl CSSSupportsRule {
} }
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet, pub fn new(
supportsrule: Arc<Locked<SupportsRule>>) -> DomRoot<CSSSupportsRule> { window: &Window,
reflect_dom_object(Box::new(CSSSupportsRule::new_inherited(parent_stylesheet, supportsrule)), parent_stylesheet: &CSSStyleSheet,
supportsrule: Arc<Locked<SupportsRule>>,
) -> DomRoot<CSSSupportsRule> {
reflect_dom_object(
Box::new(CSSSupportsRule::new_inherited(
parent_stylesheet,
supportsrule,
)),
window, window,
CSSSupportsRuleBinding::Wrap) CSSSupportsRuleBinding::Wrap,
)
} }
/// <https://drafts.csswg.org/css-conditional-3/#the-csssupportsrule-interface> /// <https://drafts.csswg.org/css-conditional-3/#the-csssupportsrule-interface>
@ -88,6 +98,9 @@ impl SpecificCSSRule for CSSSupportsRule {
fn get_css(&self) -> DOMString { fn get_css(&self) -> DOMString {
let guard = self.cssconditionrule.shared_lock().read(); let guard = self.cssconditionrule.shared_lock().read();
self.supportsrule.read_with(&guard).to_css_string(&guard).into() self.supportsrule
.read_with(&guard)
.to_css_string(&guard)
.into()
} }
} }

View file

@ -22,7 +22,10 @@ pub struct CSSViewportRule {
} }
impl CSSViewportRule { impl CSSViewportRule {
fn new_inherited(parent_stylesheet: &CSSStyleSheet, viewportrule: Arc<Locked<ViewportRule>>) -> CSSViewportRule { fn new_inherited(
parent_stylesheet: &CSSStyleSheet,
viewportrule: Arc<Locked<ViewportRule>>,
) -> CSSViewportRule {
CSSViewportRule { CSSViewportRule {
cssrule: CSSRule::new_inherited(parent_stylesheet), cssrule: CSSRule::new_inherited(parent_stylesheet),
viewportrule: viewportrule, viewportrule: viewportrule,
@ -30,11 +33,19 @@ impl CSSViewportRule {
} }
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet, pub fn new(
viewportrule: Arc<Locked<ViewportRule>>) -> DomRoot<CSSViewportRule> { window: &Window,
reflect_dom_object(Box::new(CSSViewportRule::new_inherited(parent_stylesheet, viewportrule)), parent_stylesheet: &CSSStyleSheet,
viewportrule: Arc<Locked<ViewportRule>>,
) -> DomRoot<CSSViewportRule> {
reflect_dom_object(
Box::new(CSSViewportRule::new_inherited(
parent_stylesheet,
viewportrule,
)),
window, window,
CSSViewportRuleBinding::Wrap) CSSViewportRuleBinding::Wrap,
)
} }
} }
@ -46,6 +57,9 @@ impl SpecificCSSRule for CSSViewportRule {
fn get_css(&self) -> DOMString { fn get_css(&self) -> DOMString {
let guard = self.cssrule.shared_lock().read(); let guard = self.cssrule.shared_lock().read();
self.viewportrule.read_with(&guard).to_css_string(&guard).into() self.viewportrule
.read_with(&guard)
.to_css_string(&guard)
.into()
} }
} }

View file

@ -71,9 +71,11 @@ impl CustomElementRegistry {
} }
pub fn new(window: &Window) -> DomRoot<CustomElementRegistry> { pub fn new(window: &Window) -> DomRoot<CustomElementRegistry> {
reflect_dom_object(Box::new(CustomElementRegistry::new_inherited(window)), reflect_dom_object(
Box::new(CustomElementRegistry::new_inherited(window)),
window, window,
CustomElementRegistryBinding::Wrap) CustomElementRegistryBinding::Wrap,
)
} }
/// Cleans up any active promises /// Cleans up any active promises
@ -83,40 +85,57 @@ impl CustomElementRegistry {
} }
/// <https://html.spec.whatwg.org/multipage/#look-up-a-custom-element-definition> /// <https://html.spec.whatwg.org/multipage/#look-up-a-custom-element-definition>
pub fn lookup_definition(&self, pub fn lookup_definition(
&self,
local_name: &LocalName, local_name: &LocalName,
is: Option<&LocalName>) is: Option<&LocalName>,
-> Option<Rc<CustomElementDefinition>> { ) -> Option<Rc<CustomElementDefinition>> {
self.definitions.borrow().values().find(|definition| { self.definitions
.borrow()
.values()
.find(|definition| {
// Step 4-5 // Step 4-5
definition.local_name == *local_name && definition.local_name == *local_name &&
(definition.name == *local_name || Some(&definition.name) == is) (definition.name == *local_name || Some(&definition.name) == is)
}).cloned() }).cloned()
} }
pub fn lookup_definition_by_constructor(&self, constructor: HandleObject) -> Option<Rc<CustomElementDefinition>> { pub fn lookup_definition_by_constructor(
self.definitions.borrow().values().find(|definition| { &self,
definition.constructor.callback() == constructor.get() constructor: HandleObject,
}).cloned() ) -> Option<Rc<CustomElementDefinition>> {
self.definitions
.borrow()
.values()
.find(|definition| definition.constructor.callback() == constructor.get())
.cloned()
} }
/// <https://html.spec.whatwg.org/multipage/#dom-customelementregistry-define> /// <https://html.spec.whatwg.org/multipage/#dom-customelementregistry-define>
/// Steps 10.1, 10.2 /// Steps 10.1, 10.2
#[allow(unsafe_code)] #[allow(unsafe_code)]
fn check_prototype(&self, constructor: HandleObject, prototype: MutableHandleValue) -> ErrorResult { fn check_prototype(
&self,
constructor: HandleObject,
prototype: MutableHandleValue,
) -> ErrorResult {
let global_scope = self.window.upcast::<GlobalScope>(); let global_scope = self.window.upcast::<GlobalScope>();
unsafe { unsafe {
// Step 10.1 // Step 10.1
if !JS_GetProperty(global_scope.get_cx(), if !JS_GetProperty(
global_scope.get_cx(),
constructor, constructor,
b"prototype\0".as_ptr() as *const _, b"prototype\0".as_ptr() as *const _,
prototype) { prototype,
) {
return Err(Error::JSFailed); return Err(Error::JSFailed);
} }
// Step 10.2 // Step 10.2
if !prototype.is_object() { if !prototype.is_object() {
return Err(Error::Type("constructor.prototype is not an object".to_owned())); return Err(Error::Type(
"constructor.prototype is not an object".to_owned(),
));
} }
} }
Ok(()) Ok(())
@ -143,10 +162,14 @@ impl CustomElementRegistry {
fn get_observed_attributes(&self, constructor: HandleObject) -> Fallible<Vec<DOMString>> { fn get_observed_attributes(&self, constructor: HandleObject) -> Fallible<Vec<DOMString>> {
let cx = self.window.get_cx(); let cx = self.window.get_cx();
rooted!(in(cx) let mut observed_attributes = UndefinedValue()); rooted!(in(cx) let mut observed_attributes = UndefinedValue());
if unsafe { !JS_GetProperty(cx, if unsafe {
!JS_GetProperty(
cx,
constructor, constructor,
b"observedAttributes\0".as_ptr() as *const _, b"observedAttributes\0".as_ptr() as *const _,
observed_attributes.handle_mut()) } { observed_attributes.handle_mut(),
)
} {
return Err(Error::JSFailed); return Err(Error::JSFailed);
} }
@ -155,7 +178,11 @@ impl CustomElementRegistry {
} }
let conversion = unsafe { let conversion = unsafe {
FromJSValConvertible::from_jsval(cx, observed_attributes.handle(), StringificationBehavior::Default) FromJSValConvertible::from_jsval(
cx,
observed_attributes.handle(),
StringificationBehavior::Default,
)
}; };
match conversion { match conversion {
Ok(ConversionResult::Success(attributes)) => Ok(attributes), Ok(ConversionResult::Success(attributes)) => Ok(attributes),
@ -176,7 +203,12 @@ unsafe fn get_callback(
rooted!(in(cx) let mut callback = UndefinedValue()); rooted!(in(cx) let mut callback = UndefinedValue());
// Step 10.4.1 // Step 10.4.1
if !JS_GetProperty(cx, prototype, name.as_ptr() as *const _, callback.handle_mut()) { if !JS_GetProperty(
cx,
prototype,
name.as_ptr() as *const _,
callback.handle_mut(),
) {
return Err(Error::JSFailed); return Err(Error::JSFailed);
} }
@ -195,9 +227,10 @@ impl CustomElementRegistryMethods for CustomElementRegistry {
#[allow(unsafe_code, unrooted_must_root)] #[allow(unsafe_code, unrooted_must_root)]
/// <https://html.spec.whatwg.org/multipage/#dom-customelementregistry-define> /// <https://html.spec.whatwg.org/multipage/#dom-customelementregistry-define>
fn Define( fn Define(
&self, name: DOMString, &self,
name: DOMString,
constructor_: Rc<CustomElementConstructor>, constructor_: Rc<CustomElementConstructor>,
options: &ElementDefinitionOptions options: &ElementDefinitionOptions,
) -> ErrorResult { ) -> ErrorResult {
let cx = self.window.get_cx(); let cx = self.window.get_cx();
rooted!(in(cx) let constructor = constructor_.callback()); rooted!(in(cx) let constructor = constructor_.callback());
@ -213,12 +246,14 @@ impl CustomElementRegistryMethods for CustomElementRegistry {
} }
if unsafe { !IsConstructor(unwrapped_constructor.get()) } { if unsafe { !IsConstructor(unwrapped_constructor.get()) } {
return Err(Error::Type("Second argument of CustomElementRegistry.define is not a constructor".to_owned())); return Err(Error::Type(
"Second argument of CustomElementRegistry.define is not a constructor".to_owned(),
));
} }
// Step 2 // Step 2
if !is_valid_custom_element_name(&name) { if !is_valid_custom_element_name(&name) {
return Err(Error::Syntax) return Err(Error::Syntax);
} }
// Step 3 // Step 3
@ -227,7 +262,12 @@ impl CustomElementRegistryMethods for CustomElementRegistry {
} }
// Step 4 // Step 4
if self.definitions.borrow().iter().any(|(_, ref def)| def.constructor == constructor_) { if self
.definitions
.borrow()
.iter()
.any(|(_, ref def)| def.constructor == constructor_)
{
return Err(Error::NotSupported); return Err(Error::NotSupported);
} }
@ -238,12 +278,12 @@ impl CustomElementRegistryMethods for CustomElementRegistry {
let local_name = if let Some(ref extended_name) = *extends { let local_name = if let Some(ref extended_name) = *extends {
// Step 7.1 // Step 7.1
if is_valid_custom_element_name(extended_name) { if is_valid_custom_element_name(extended_name) {
return Err(Error::NotSupported) return Err(Error::NotSupported);
} }
// Step 7.2 // Step 7.2
if !is_extendable_element_interface(extended_name) { if !is_extendable_element_interface(extended_name) {
return Err(Error::NotSupported) return Err(Error::NotSupported);
} }
LocalName::from(&**extended_name) LocalName::from(&**extended_name)
@ -300,20 +340,28 @@ impl CustomElementRegistryMethods for CustomElementRegistry {
self.element_definition_is_running.set(false); self.element_definition_is_running.set(false);
// Step 11 // Step 11
let definition = Rc::new(CustomElementDefinition::new(name.clone(), let definition = Rc::new(CustomElementDefinition::new(
name.clone(),
local_name.clone(), local_name.clone(),
constructor_, constructor_,
observed_attributes, observed_attributes,
callbacks)); callbacks,
));
// Step 12 // Step 12
self.definitions.borrow_mut().insert(name.clone(), definition.clone()); self.definitions
.borrow_mut()
.insert(name.clone(), definition.clone());
// Step 13 // Step 13
let document = self.window.Document(); let document = self.window.Document();
// Steps 14-15 // Steps 14-15
for candidate in document.upcast::<Node>().traverse_preorder().filter_map(DomRoot::downcast::<Element>) { for candidate in document
.upcast::<Node>()
.traverse_preorder()
.filter_map(DomRoot::downcast::<Element>)
{
let is = candidate.get_is(); let is = candidate.get_is();
if *candidate.local_name() == local_name && if *candidate.local_name() == local_name &&
*candidate.namespace() == ns!(html) && *candidate.namespace() == ns!(html) &&
@ -336,7 +384,9 @@ impl CustomElementRegistryMethods for CustomElementRegistry {
match self.definitions.borrow().get(&LocalName::from(&*name)) { match self.definitions.borrow().get(&LocalName::from(&*name)) {
Some(definition) => { Some(definition) => {
rooted!(in(cx) let mut constructor = UndefinedValue()); rooted!(in(cx) let mut constructor = UndefinedValue());
definition.constructor.to_jsval(cx, constructor.handle_mut()); definition
.constructor
.to_jsval(cx, constructor.handle_mut());
constructor.get() constructor.get()
}, },
None => UndefinedValue(), None => UndefinedValue(),
@ -353,14 +403,14 @@ impl CustomElementRegistryMethods for CustomElementRegistry {
if !is_valid_custom_element_name(&name) { if !is_valid_custom_element_name(&name) {
let promise = Promise::new(global_scope); let promise = Promise::new(global_scope);
promise.reject_native(&DOMException::new(global_scope, DOMErrorName::SyntaxError)); promise.reject_native(&DOMException::new(global_scope, DOMErrorName::SyntaxError));
return promise return promise;
} }
// Step 2 // Step 2
if self.definitions.borrow().contains_key(&name) { if self.definitions.borrow().contains_key(&name) {
let promise = Promise::new(global_scope); let promise = Promise::new(global_scope);
promise.resolve_native(&UndefinedValue()); promise.resolve_native(&UndefinedValue());
return promise return promise;
} }
// Step 3 // Step 3
@ -417,12 +467,13 @@ pub struct CustomElementDefinition {
} }
impl CustomElementDefinition { impl CustomElementDefinition {
fn new(name: LocalName, fn new(
name: LocalName,
local_name: LocalName, local_name: LocalName,
constructor: Rc<CustomElementConstructor>, constructor: Rc<CustomElementConstructor>,
observed_attributes: Vec<DOMString>, observed_attributes: Vec<DOMString>,
callbacks: LifecycleCallbacks) callbacks: LifecycleCallbacks,
-> CustomElementDefinition { ) -> CustomElementDefinition {
CustomElementDefinition { CustomElementDefinition {
name: name, name: name,
local_name: local_name, local_name: local_name,
@ -440,7 +491,11 @@ impl CustomElementDefinition {
/// https://dom.spec.whatwg.org/#concept-create-element Step 6.1 /// https://dom.spec.whatwg.org/#concept-create-element Step 6.1
#[allow(unsafe_code)] #[allow(unsafe_code)]
pub fn create_element(&self, document: &Document, prefix: Option<Prefix>) -> Fallible<DomRoot<Element>> { pub fn create_element(
&self,
document: &Document,
prefix: Option<Prefix>,
) -> Fallible<DomRoot<Element>> {
let window = document.window(); let window = document.window();
let cx = window.get_cx(); let cx = window.get_cx();
// Step 2 // Step 2
@ -456,16 +511,22 @@ impl CustomElementDefinition {
} }
rooted!(in(cx) let element_val = ObjectValue(element.get())); rooted!(in(cx) let element_val = ObjectValue(element.get()));
let element: DomRoot<Element> = match unsafe { DomRoot::from_jsval(cx, element_val.handle(), ()) } { let element: DomRoot<Element> =
match unsafe { DomRoot::from_jsval(cx, element_val.handle(), ()) } {
Ok(ConversionResult::Success(element)) => element, Ok(ConversionResult::Success(element)) => element,
Ok(ConversionResult::Failure(..)) => Ok(ConversionResult::Failure(..)) => {
return Err(Error::Type("Constructor did not return a DOM node".to_owned())), return Err(Error::Type(
"Constructor did not return a DOM node".to_owned(),
))
},
_ => return Err(Error::JSFailed), _ => return Err(Error::JSFailed),
}; };
// Step 3 // Step 3
if !element.is::<HTMLElement>() { if !element.is::<HTMLElement>() {
return Err(Error::Type("Constructor did not return a DOM node".to_owned())); return Err(Error::Type(
"Constructor did not return a DOM node".to_owned(),
));
} }
// Steps 4-9 // Steps 4-9
@ -503,17 +564,27 @@ pub fn upgrade_element(definition: Rc<CustomElementDefinition>, element: &Elemen
let local_name = attr.local_name().clone(); let local_name = attr.local_name().clone();
let value = DOMString::from(&**attr.value()); let value = DOMString::from(&**attr.value());
let namespace = attr.namespace().clone(); let namespace = attr.namespace().clone();
ScriptThread::enqueue_callback_reaction(element, ScriptThread::enqueue_callback_reaction(
CallbackReaction::AttributeChanged(local_name, None, Some(value), namespace), Some(definition.clone())); element,
CallbackReaction::AttributeChanged(local_name, None, Some(value), namespace),
Some(definition.clone()),
);
} }
// Step 4 // Step 4
if element.is_connected() { if element.is_connected() {
ScriptThread::enqueue_callback_reaction(element, CallbackReaction::Connected, Some(definition.clone())); ScriptThread::enqueue_callback_reaction(
element,
CallbackReaction::Connected,
Some(definition.clone()),
);
} }
// Step 5 // Step 5
definition.construction_stack.borrow_mut().push(ConstructionStackEntry::Element(DomRoot::from_ref(element))); definition
.construction_stack
.borrow_mut()
.push(ConstructionStackEntry::Element(DomRoot::from_ref(element)));
// Step 7 // Step 7
let result = run_upgrade_constructor(&definition.constructor, element); let result = run_upgrade_constructor(&definition.constructor, element);
@ -548,25 +619,44 @@ pub fn upgrade_element(definition: Rc<CustomElementDefinition>, element: &Elemen
/// <https://html.spec.whatwg.org/multipage/#concept-upgrade-an-element> /// <https://html.spec.whatwg.org/multipage/#concept-upgrade-an-element>
/// Steps 7.1-7.2 /// Steps 7.1-7.2
#[allow(unsafe_code)] #[allow(unsafe_code)]
fn run_upgrade_constructor(constructor: &Rc<CustomElementConstructor>, element: &Element) -> ErrorResult { fn run_upgrade_constructor(
constructor: &Rc<CustomElementConstructor>,
element: &Element,
) -> ErrorResult {
let window = window_from_node(element); let window = window_from_node(element);
let cx = window.get_cx(); let cx = window.get_cx();
rooted!(in(cx) let constructor_val = ObjectValue(constructor.callback())); rooted!(in(cx) let constructor_val = ObjectValue(constructor.callback()));
rooted!(in(cx) let mut element_val = UndefinedValue()); rooted!(in(cx) let mut element_val = UndefinedValue());
unsafe { element.to_jsval(cx, element_val.handle_mut()); } unsafe {
element.to_jsval(cx, element_val.handle_mut());
}
rooted!(in(cx) let mut construct_result = ptr::null_mut::<JSObject>()); rooted!(in(cx) let mut construct_result = ptr::null_mut::<JSObject>());
{ {
// Go into the constructor's compartment // Go into the constructor's compartment
let _ac = JSAutoCompartment::new(cx, constructor.callback()); let _ac = JSAutoCompartment::new(cx, constructor.callback());
let args = HandleValueArray::new(); let args = HandleValueArray::new();
// Step 7.1 // Step 7.1
if unsafe { !Construct1(cx, constructor_val.handle(), &args, construct_result.handle_mut()) } { if unsafe {
!Construct1(
cx,
constructor_val.handle(),
&args,
construct_result.handle_mut(),
)
} {
return Err(Error::JSFailed); return Err(Error::JSFailed);
} }
// Step 7.2 // Step 7.2
let mut same = false; let mut same = false;
rooted!(in(cx) let construct_result_val = ObjectValue(construct_result.get())); rooted!(in(cx) let construct_result_val = ObjectValue(construct_result.get()));
if unsafe { !JS_SameValue(cx, construct_result_val.handle(), element_val.handle(), &mut same) } { if unsafe {
!JS_SameValue(
cx,
construct_result_val.handle(),
element_val.handle(),
&mut same,
)
} {
return Err(Error::JSFailed); return Err(Error::JSFailed);
} }
if !same { if !same {
@ -583,7 +673,9 @@ pub fn try_upgrade_element(element: &Element) {
let namespace = element.namespace(); let namespace = element.namespace();
let local_name = element.local_name(); let local_name = element.local_name();
let is = element.get_is(); let is = element.get_is();
if let Some(definition) = document.lookup_custom_element_definition(namespace, local_name, is.as_ref()) { if let Some(definition) =
document.lookup_custom_element_definition(namespace, local_name, is.as_ref())
{
// Step 2 // Step 2
ScriptThread::enqueue_upgrade_reaction(element, definition); ScriptThread::enqueue_upgrade_reaction(element, definition);
} }
@ -592,14 +684,10 @@ pub fn try_upgrade_element(element: &Element) {
#[derive(JSTraceable, MallocSizeOf)] #[derive(JSTraceable, MallocSizeOf)]
#[must_root] #[must_root]
pub enum CustomElementReaction { pub enum CustomElementReaction {
Upgrade( Upgrade(#[ignore_malloc_size_of = "Rc"] Rc<CustomElementDefinition>),
#[ignore_malloc_size_of = "Rc"]
Rc<CustomElementDefinition>
),
Callback( Callback(
#[ignore_malloc_size_of = "Rc"] #[ignore_malloc_size_of = "Rc"] Rc<Function>,
Rc<Function>, Box<[Heap<JSVal>]>,
Box<[Heap<JSVal>]>
), ),
} }
@ -609,12 +697,17 @@ impl CustomElementReaction {
pub fn invoke(&self, element: &Element) { pub fn invoke(&self, element: &Element) {
// Step 2.1 // Step 2.1
match *self { match *self {
CustomElementReaction::Upgrade(ref definition) => upgrade_element(definition.clone(), element), CustomElementReaction::Upgrade(ref definition) => {
upgrade_element(definition.clone(), element)
},
CustomElementReaction::Callback(ref callback, ref arguments) => { CustomElementReaction::Callback(ref callback, ref arguments) => {
// We're rooted, so it's safe to hand out a handle to objects in Heap // We're rooted, so it's safe to hand out a handle to objects in Heap
let arguments = arguments.iter().map(|arg| unsafe { HandleValue::from_raw(arg.handle()) }).collect(); let arguments = arguments
.iter()
.map(|arg| unsafe { HandleValue::from_raw(arg.handle()) })
.collect();
let _ = callback.Call_(&*element, arguments, ExceptionHandling::Report); let _ = callback.Call_(&*element, arguments, ExceptionHandling::Report);
} },
} }
} }
} }
@ -675,7 +768,8 @@ impl CustomElementReactionStack {
self.backup_queue.invoke_reactions(); self.backup_queue.invoke_reactions();
// Step 4.2 // Step 4.2
self.processing_backup_element_queue.set(BackupElementQueueFlag::NotProcessing); self.processing_backup_element_queue
.set(BackupElementQueueFlag::NotProcessing);
} }
/// <https://html.spec.whatwg.org/multipage/#enqueue-an-element-on-the-appropriate-element-queue> /// <https://html.spec.whatwg.org/multipage/#enqueue-an-element-on-the-appropriate-element-queue>
@ -693,7 +787,8 @@ impl CustomElementReactionStack {
} }
// Step 1.3 // Step 1.3
self.processing_backup_element_queue.set(BackupElementQueueFlag::Processing); self.processing_backup_element_queue
.set(BackupElementQueueFlag::Processing);
// Step 4 // Step 4
ScriptThread::enqueue_microtask(Microtask::CustomElementReaction); ScriptThread::enqueue_microtask(Microtask::CustomElementReaction);
@ -702,10 +797,12 @@ impl CustomElementReactionStack {
/// <https://html.spec.whatwg.org/multipage/#enqueue-a-custom-element-callback-reaction> /// <https://html.spec.whatwg.org/multipage/#enqueue-a-custom-element-callback-reaction>
#[allow(unsafe_code)] #[allow(unsafe_code)]
pub fn enqueue_callback_reaction(&self, pub fn enqueue_callback_reaction(
&self,
element: &Element, element: &Element,
reaction: CallbackReaction, reaction: CallbackReaction,
definition: Option<Rc<CustomElementDefinition>>) { definition: Option<Rc<CustomElementDefinition>>,
) {
// Step 1 // Step 1
let definition = match definition.or_else(|| element.get_custom_element_definition()) { let definition = match definition.or_else(|| element.get_custom_element_definition()) {
Some(definition) => definition, Some(definition) => definition,
@ -714,8 +811,13 @@ impl CustomElementReactionStack {
// Step 2 // Step 2
let (callback, args) = match reaction { let (callback, args) = match reaction {
CallbackReaction::Connected => (definition.callbacks.connected_callback.clone(), Vec::new()), CallbackReaction::Connected => {
CallbackReaction::Disconnected => (definition.callbacks.disconnected_callback.clone(), Vec::new()), (definition.callbacks.connected_callback.clone(), Vec::new())
},
CallbackReaction::Disconnected => (
definition.callbacks.disconnected_callback.clone(),
Vec::new(),
),
CallbackReaction::Adopted(ref old_doc, ref new_doc) => { CallbackReaction::Adopted(ref old_doc, ref new_doc) => {
let args = vec![Heap::default(), Heap::default()]; let args = vec![Heap::default(), Heap::default()];
args[0].set(ObjectValue(old_doc.reflector().get_jsobject().get())); args[0].set(ObjectValue(old_doc.reflector().get_jsobject().get()));
@ -724,7 +826,11 @@ impl CustomElementReactionStack {
}, },
CallbackReaction::AttributeChanged(local_name, old_val, val, namespace) => { CallbackReaction::AttributeChanged(local_name, old_val, val, namespace) => {
// Step 4 // Step 4
if !definition.observed_attributes.iter().any(|attr| *attr == *local_name) { if !definition
.observed_attributes
.iter()
.any(|attr| *attr == *local_name)
{
return; return;
} }
@ -732,31 +838,47 @@ impl CustomElementReactionStack {
let local_name = DOMString::from(&*local_name); let local_name = DOMString::from(&*local_name);
rooted!(in(cx) let mut name_value = UndefinedValue()); rooted!(in(cx) let mut name_value = UndefinedValue());
unsafe { local_name.to_jsval(cx, name_value.handle_mut()); } unsafe {
local_name.to_jsval(cx, name_value.handle_mut());
}
rooted!(in(cx) let mut old_value = NullValue()); rooted!(in(cx) let mut old_value = NullValue());
if let Some(old_val) = old_val { if let Some(old_val) = old_val {
unsafe { old_val.to_jsval(cx, old_value.handle_mut()); } unsafe {
old_val.to_jsval(cx, old_value.handle_mut());
}
} }
rooted!(in(cx) let mut value = NullValue()); rooted!(in(cx) let mut value = NullValue());
if let Some(val) = val { if let Some(val) = val {
unsafe { val.to_jsval(cx, value.handle_mut()); } unsafe {
val.to_jsval(cx, value.handle_mut());
}
} }
rooted!(in(cx) let mut namespace_value = NullValue()); rooted!(in(cx) let mut namespace_value = NullValue());
if namespace != ns!() { if namespace != ns!() {
let namespace = DOMString::from(&*namespace); let namespace = DOMString::from(&*namespace);
unsafe { namespace.to_jsval(cx, namespace_value.handle_mut()); } unsafe {
namespace.to_jsval(cx, namespace_value.handle_mut());
}
} }
let args = vec![Heap::default(), Heap::default(), Heap::default(), Heap::default()]; let args = vec![
Heap::default(),
Heap::default(),
Heap::default(),
Heap::default(),
];
args[0].set(name_value.get()); args[0].set(name_value.get());
args[1].set(old_value.get()); args[1].set(old_value.get());
args[2].set(value.get()); args[2].set(value.get());
args[3].set(namespace_value.get()); args[3].set(namespace_value.get());
(definition.callbacks.attribute_changed_callback.clone(), args) (
definition.callbacks.attribute_changed_callback.clone(),
args,
)
}, },
}; };
@ -774,7 +896,11 @@ impl CustomElementReactionStack {
} }
/// <https://html.spec.whatwg.org/multipage/#enqueue-a-custom-element-upgrade-reaction> /// <https://html.spec.whatwg.org/multipage/#enqueue-a-custom-element-upgrade-reaction>
pub fn enqueue_upgrade_reaction(&self, element: &Element, definition: Rc<CustomElementDefinition>) { pub fn enqueue_upgrade_reaction(
&self,
element: &Element,
definition: Rc<CustomElementDefinition>,
) {
// Step 1 // Step 1
element.push_upgrade_reaction(definition); element.push_upgrade_reaction(definition);
// Step 2 // Step 2
@ -806,7 +932,12 @@ impl ElementQueue {
} }
fn next_element(&self) -> Option<DomRoot<Element>> { fn next_element(&self) -> Option<DomRoot<Element>> {
self.queue.borrow_mut().pop_front().as_ref().map(Dom::deref).map(DomRoot::from_ref) self.queue
.borrow_mut()
.pop_front()
.as_ref()
.map(Dom::deref)
.map(DomRoot::from_ref)
} }
fn append_element(&self, element: &Element) { fn append_element(&self, element: &Element) {
@ -859,7 +990,10 @@ pub fn is_valid_custom_element_name(name: &str) -> bool {
/// Check if this character is a PCENChar /// Check if this character is a PCENChar
/// <https://html.spec.whatwg.org/multipage/#prod-pcenchar> /// <https://html.spec.whatwg.org/multipage/#prod-pcenchar>
fn is_potential_custom_element_char(c: char) -> bool { fn is_potential_custom_element_char(c: char) -> bool {
c == '-' || c == '.' || c == '_' || c == '\u{B7}' || c == '-' ||
c == '.' ||
c == '_' ||
c == '\u{B7}' ||
(c >= '0' && c <= '9') || (c >= '0' && c <= '9') ||
(c >= 'a' && c <= 'z') || (c >= 'a' && c <= 'z') ||
(c >= '\u{C0}' && c <= '\u{D6}') || (c >= '\u{C0}' && c <= '\u{D6}') ||

View file

@ -36,38 +36,46 @@ impl CustomEvent {
} }
pub fn new_uninitialized(global: &GlobalScope) -> DomRoot<CustomEvent> { pub fn new_uninitialized(global: &GlobalScope) -> DomRoot<CustomEvent> {
reflect_dom_object(Box::new(CustomEvent::new_inherited()), reflect_dom_object(
Box::new(CustomEvent::new_inherited()),
global, global,
CustomEventBinding::Wrap) CustomEventBinding::Wrap,
)
} }
pub fn new(global: &GlobalScope, pub fn new(
global: &GlobalScope,
type_: Atom, type_: Atom,
bubbles: bool, bubbles: bool,
cancelable: bool, cancelable: bool,
detail: HandleValue) detail: HandleValue,
-> DomRoot<CustomEvent> { ) -> DomRoot<CustomEvent> {
let ev = CustomEvent::new_uninitialized(global); let ev = CustomEvent::new_uninitialized(global);
ev.init_custom_event(type_, bubbles, cancelable, detail); ev.init_custom_event(type_, bubbles, cancelable, detail);
ev ev
} }
#[allow(unsafe_code)] #[allow(unsafe_code)]
pub fn Constructor(global: &GlobalScope, pub fn Constructor(
global: &GlobalScope,
type_: DOMString, type_: DOMString,
init: RootedTraceableBox<CustomEventBinding::CustomEventInit>) init: RootedTraceableBox<CustomEventBinding::CustomEventInit>,
-> Fallible<DomRoot<CustomEvent>> { ) -> Fallible<DomRoot<CustomEvent>> {
Ok(CustomEvent::new(global, Ok(CustomEvent::new(
global,
Atom::from(type_), Atom::from(type_),
init.parent.bubbles, init.parent.bubbles,
init.parent.cancelable, init.parent.cancelable,
init.detail.handle())) init.detail.handle(),
))
} }
fn init_custom_event(&self, fn init_custom_event(
&self,
type_: Atom, type_: Atom,
can_bubble: bool, can_bubble: bool,
cancelable: bool, cancelable: bool,
detail: HandleValue) { detail: HandleValue,
) {
let event = self.upcast::<Event>(); let event = self.upcast::<Event>();
if event.dispatching() { if event.dispatching() {
return; return;
@ -87,12 +95,14 @@ impl CustomEventMethods for CustomEvent {
#[allow(unsafe_code)] #[allow(unsafe_code)]
// https://dom.spec.whatwg.org/#dom-customevent-initcustomevent // https://dom.spec.whatwg.org/#dom-customevent-initcustomevent
unsafe fn InitCustomEvent(&self, unsafe fn InitCustomEvent(
&self,
_cx: *mut JSContext, _cx: *mut JSContext,
type_: DOMString, type_: DOMString,
can_bubble: bool, can_bubble: bool,
cancelable: bool, cancelable: bool,
detail: HandleValue) { detail: HandleValue,
) {
self.init_custom_event(Atom::from(type_), can_bubble, cancelable, detail) self.init_custom_event(Atom::from(type_), can_bubble, cancelable, detail)
} }

View file

@ -57,9 +57,10 @@ pub struct AutoWorkerReset<'a> {
} }
impl<'a> AutoWorkerReset<'a> { impl<'a> AutoWorkerReset<'a> {
fn new(workerscope: &'a DedicatedWorkerGlobalScope, fn new(
worker: TrustedWorkerAddress) workerscope: &'a DedicatedWorkerGlobalScope,
-> AutoWorkerReset<'a> { worker: TrustedWorkerAddress,
) -> AutoWorkerReset<'a> {
AutoWorkerReset { AutoWorkerReset {
workerscope: workerscope, workerscope: workerscope,
old_worker: replace(&mut *workerscope.worker.borrow_mut(), Some(worker)), old_worker: replace(&mut *workerscope.worker.borrow_mut(), Some(worker)),
@ -83,7 +84,7 @@ pub enum DedicatedWorkerScriptMsg {
pub enum MixedMessage { pub enum MixedMessage {
FromWorker(DedicatedWorkerScriptMsg), FromWorker(DedicatedWorkerScriptMsg),
FromScheduler((TrustedWorkerAddress, TimerEvent)), FromScheduler((TrustedWorkerAddress, TimerEvent)),
FromDevtools(DevtoolScriptControlMsg) FromDevtools(DevtoolScriptControlMsg),
} }
impl QueuedTaskConversion for DedicatedWorkerScriptMsg { impl QueuedTaskConversion for DedicatedWorkerScriptMsg {
@ -97,14 +98,18 @@ impl QueuedTaskConversion for DedicatedWorkerScriptMsg {
_ => return None, _ => return None,
}; };
match script_msg { match script_msg {
CommonScriptMsg::Task(_category, _boxed, _pipeline_id, source_name) => Some(&source_name), CommonScriptMsg::Task(_category, _boxed, _pipeline_id, source_name) => {
Some(&source_name)
},
_ => return None, _ => return None,
} }
} }
fn into_queued_task(self) -> Option<QueuedTask> { fn into_queued_task(self) -> Option<QueuedTask> {
let (worker, common_worker_msg) = match self { let (worker, common_worker_msg) = match self {
DedicatedWorkerScriptMsg::CommonWorker(worker, common_worker_msg) => (worker, common_worker_msg), DedicatedWorkerScriptMsg::CommonWorker(worker, common_worker_msg) => {
(worker, common_worker_msg)
},
_ => return None, _ => return None,
}; };
let script_msg = match common_worker_msg { let script_msg = match common_worker_msg {
@ -112,8 +117,9 @@ impl QueuedTaskConversion for DedicatedWorkerScriptMsg {
_ => return None, _ => return None,
}; };
let (category, boxed, pipeline_id, task_source) = match script_msg { let (category, boxed, pipeline_id, task_source) = match script_msg {
CommonScriptMsg::Task(category, boxed, pipeline_id, task_source) => CommonScriptMsg::Task(category, boxed, pipeline_id, task_source) => {
(category, boxed, pipeline_id, task_source), (category, boxed, pipeline_id, task_source)
},
_ => return None, _ => return None,
}; };
Some((Some(worker), category, boxed, pipeline_id, task_source)) Some((Some(worker), category, boxed, pipeline_id, task_source))
@ -121,12 +127,7 @@ impl QueuedTaskConversion for DedicatedWorkerScriptMsg {
fn from_queued_task(queued_task: QueuedTask) -> Self { fn from_queued_task(queued_task: QueuedTask) -> Self {
let (worker, category, boxed, pipeline_id, task_source) = queued_task; let (worker, category, boxed, pipeline_id, task_source) = queued_task;
let script_msg = CommonScriptMsg::Task( let script_msg = CommonScriptMsg::Task(category, boxed, pipeline_id, task_source);
category,
boxed,
pipeline_id,
task_source
);
DedicatedWorkerScriptMsg::CommonWorker(worker.unwrap(), WorkerScriptMsg::Common(script_msg)) DedicatedWorkerScriptMsg::CommonWorker(worker.unwrap(), WorkerScriptMsg::Common(script_msg))
} }
@ -197,7 +198,8 @@ impl WorkerEventLoopMethods for DedicatedWorkerGlobalScope {
} }
impl DedicatedWorkerGlobalScope { impl DedicatedWorkerGlobalScope {
fn new_inherited(init: WorkerGlobalScopeInit, fn new_inherited(
init: WorkerGlobalScopeInit,
worker_url: ServoUrl, worker_url: ServoUrl,
from_devtools_receiver: Receiver<DevtoolScriptControlMsg>, from_devtools_receiver: Receiver<DevtoolScriptControlMsg>,
runtime: Runtime, runtime: Runtime,
@ -206,15 +208,17 @@ impl DedicatedWorkerGlobalScope {
receiver: Receiver<DedicatedWorkerScriptMsg>, receiver: Receiver<DedicatedWorkerScriptMsg>,
timer_event_chan: IpcSender<TimerEvent>, timer_event_chan: IpcSender<TimerEvent>,
timer_event_port: Receiver<(TrustedWorkerAddress, TimerEvent)>, timer_event_port: Receiver<(TrustedWorkerAddress, TimerEvent)>,
closing: Arc<AtomicBool>) closing: Arc<AtomicBool>,
-> DedicatedWorkerGlobalScope { ) -> DedicatedWorkerGlobalScope {
DedicatedWorkerGlobalScope { DedicatedWorkerGlobalScope {
workerglobalscope: WorkerGlobalScope::new_inherited(init, workerglobalscope: WorkerGlobalScope::new_inherited(
init,
worker_url, worker_url,
runtime, runtime,
from_devtools_receiver, from_devtools_receiver,
timer_event_chan, timer_event_chan,
Some(closing)), Some(closing),
),
task_queue: TaskQueue::new(receiver, own_sender.clone()), task_queue: TaskQueue::new(receiver, own_sender.clone()),
own_sender: own_sender, own_sender: own_sender,
timer_event_port: timer_event_port, timer_event_port: timer_event_port,
@ -224,7 +228,8 @@ impl DedicatedWorkerGlobalScope {
} }
#[allow(unsafe_code)] #[allow(unsafe_code)]
pub fn new(init: WorkerGlobalScopeInit, pub fn new(
init: WorkerGlobalScopeInit,
worker_url: ServoUrl, worker_url: ServoUrl,
from_devtools_receiver: Receiver<DevtoolScriptControlMsg>, from_devtools_receiver: Receiver<DevtoolScriptControlMsg>,
runtime: Runtime, runtime: Runtime,
@ -233,8 +238,8 @@ impl DedicatedWorkerGlobalScope {
receiver: Receiver<DedicatedWorkerScriptMsg>, receiver: Receiver<DedicatedWorkerScriptMsg>,
timer_event_chan: IpcSender<TimerEvent>, timer_event_chan: IpcSender<TimerEvent>,
timer_event_port: Receiver<(TrustedWorkerAddress, TimerEvent)>, timer_event_port: Receiver<(TrustedWorkerAddress, TimerEvent)>,
closing: Arc<AtomicBool>) closing: Arc<AtomicBool>,
-> DomRoot<DedicatedWorkerGlobalScope> { ) -> DomRoot<DedicatedWorkerGlobalScope> {
let cx = runtime.cx(); let cx = runtime.cx();
let scope = Box::new(DedicatedWorkerGlobalScope::new_inherited( let scope = Box::new(DedicatedWorkerGlobalScope::new_inherited(
init, init,
@ -246,16 +251,15 @@ impl DedicatedWorkerGlobalScope {
receiver, receiver,
timer_event_chan, timer_event_chan,
timer_event_port, timer_event_port,
closing closing,
)); ));
unsafe { unsafe { DedicatedWorkerGlobalScopeBinding::Wrap(cx, scope) }
DedicatedWorkerGlobalScopeBinding::Wrap(cx, scope)
}
} }
#[allow(unsafe_code)] #[allow(unsafe_code)]
// https://html.spec.whatwg.org/multipage/#run-a-worker // https://html.spec.whatwg.org/multipage/#run-a-worker
pub fn run_worker_scope(init: WorkerGlobalScopeInit, pub fn run_worker_scope(
init: WorkerGlobalScopeInit,
worker_url: ServoUrl, worker_url: ServoUrl,
from_devtools_receiver: IpcReceiver<DevtoolScriptControlMsg>, from_devtools_receiver: IpcReceiver<DevtoolScriptControlMsg>,
worker: TrustedWorkerAddress, worker: TrustedWorkerAddress,
@ -263,13 +267,20 @@ impl DedicatedWorkerGlobalScope {
own_sender: Sender<DedicatedWorkerScriptMsg>, own_sender: Sender<DedicatedWorkerScriptMsg>,
receiver: Receiver<DedicatedWorkerScriptMsg>, receiver: Receiver<DedicatedWorkerScriptMsg>,
worker_load_origin: WorkerScriptLoadOrigin, worker_load_origin: WorkerScriptLoadOrigin,
closing: Arc<AtomicBool>) { closing: Arc<AtomicBool>,
) {
let serialized_worker_url = worker_url.to_string(); let serialized_worker_url = worker_url.to_string();
let name = format!("WebWorker for {}", serialized_worker_url); let name = format!("WebWorker for {}", serialized_worker_url);
let top_level_browsing_context_id = TopLevelBrowsingContextId::installed(); let top_level_browsing_context_id = TopLevelBrowsingContextId::installed();
let origin = GlobalScope::current().expect("No current global object").origin().immutable().clone(); let origin = GlobalScope::current()
.expect("No current global object")
.origin()
.immutable()
.clone();
thread::Builder::new().name(name).spawn(move || { thread::Builder::new()
.name(name)
.spawn(move || {
thread_state::initialize(ThreadState::SCRIPT | ThreadState::IN_WORKER); thread_state::initialize(ThreadState::SCRIPT | ThreadState::IN_WORKER);
if let Some(top_level_browsing_context_id) = top_level_browsing_context_id { if let Some(top_level_browsing_context_id) = top_level_browsing_context_id {
@ -279,7 +290,11 @@ impl DedicatedWorkerGlobalScope {
let roots = RootCollection::new(); let roots = RootCollection::new();
let _stack_roots = ThreadLocalStackRoots::new(&roots); let _stack_roots = ThreadLocalStackRoots::new(&roots);
let WorkerScriptLoadOrigin { referrer_url, referrer_policy, pipeline_id } = worker_load_origin; let WorkerScriptLoadOrigin {
referrer_url,
referrer_policy,
pipeline_id,
} = worker_load_origin;
let request = RequestInit { let request = RequestInit {
url: worker_url.clone(), url: worker_url.clone(),
@ -290,22 +305,23 @@ impl DedicatedWorkerGlobalScope {
referrer_url: referrer_url, referrer_url: referrer_url,
referrer_policy: referrer_policy, referrer_policy: referrer_policy,
origin, origin,
.. RequestInit::default() ..RequestInit::default()
}; };
let (metadata, bytes) = match load_whole_resource(request, let (metadata, bytes) =
&init.resource_threads.sender()) { match load_whole_resource(request, &init.resource_threads.sender()) {
Err(_) => { Err(_) => {
println!("error loading script {}", serialized_worker_url); println!("error loading script {}", serialized_worker_url);
parent_sender.send(CommonScriptMsg::Task( parent_sender
.send(CommonScriptMsg::Task(
WorkerEvent, WorkerEvent,
Box::new(SimpleWorkerErrorHandler::new(worker)), Box::new(SimpleWorkerErrorHandler::new(worker)),
pipeline_id, pipeline_id,
TaskSourceName::DOMManipulation, TaskSourceName::DOMManipulation,
)).unwrap(); )).unwrap();
return; return;
} },
Ok((metadata, bytes)) => (metadata, bytes) Ok((metadata, bytes)) => (metadata, bytes),
}; };
let url = metadata.final_url; let url = metadata.final_url;
let source = String::from_utf8_lossy(&bytes); let source = String::from_utf8_lossy(&bytes);
@ -318,15 +334,26 @@ impl DedicatedWorkerGlobalScope {
let (timer_tx, timer_rx) = channel(); let (timer_tx, timer_rx) = channel();
let (timer_ipc_chan, timer_ipc_port) = ipc::channel().unwrap(); let (timer_ipc_chan, timer_ipc_port) = ipc::channel().unwrap();
let worker_for_route = worker.clone(); let worker_for_route = worker.clone();
ROUTER.add_route(timer_ipc_port.to_opaque(), Box::new(move |message| { ROUTER.add_route(
timer_ipc_port.to_opaque(),
Box::new(move |message| {
let event = message.to().unwrap(); let event = message.to().unwrap();
timer_tx.send((worker_for_route.clone(), event)).unwrap(); timer_tx.send((worker_for_route.clone(), event)).unwrap();
})); }),
);
let global = DedicatedWorkerGlobalScope::new( let global = DedicatedWorkerGlobalScope::new(
init, url, devtools_mpsc_port, runtime, init,
parent_sender.clone(), own_sender, receiver, url,
timer_ipc_chan, timer_rx, closing); devtools_mpsc_port,
runtime,
parent_sender.clone(),
own_sender,
receiver,
timer_ipc_chan,
timer_rx,
closing,
);
// FIXME(njn): workers currently don't have a unique ID suitable for using in reporter // 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. // registration (#6631), so we instead use a random number and cross our fingers.
let scope = global.upcast::<WorkerGlobalScope>(); let scope = global.upcast::<WorkerGlobalScope>();
@ -346,14 +373,24 @@ impl DedicatedWorkerGlobalScope {
} }
let reporter_name = format!("dedicated-worker-reporter-{}", random::<u64>()); let reporter_name = format!("dedicated-worker-reporter-{}", random::<u64>());
scope.upcast::<GlobalScope>().mem_profiler_chan().run_with_memory_reporting(|| { scope
// Step 29, Run the responsible event loop specified by inside settings until it is destroyed. .upcast::<GlobalScope>()
// The worker processing model remains on this step until the event loop is destroyed, .mem_profiler_chan()
.run_with_memory_reporting(
|| {
// Step 29, Run the responsible event loop specified
// by inside settings until it is destroyed.
// The worker processing model remains on this step
// until the event loop is destroyed,
// which happens after the closing flag is set to true. // which happens after the closing flag is set to true.
while !scope.is_closing() { while !scope.is_closing() {
run_worker_event_loop(&*global, Some(&worker)); run_worker_event_loop(&*global, Some(&worker));
} }
}, reporter_name, parent_sender, CommonScriptMsg::CollectReports); },
reporter_name,
parent_sender,
CommonScriptMsg::CollectReports,
);
}).expect("Thread spawning failed"); }).expect("Thread spawning failed");
} }
@ -378,8 +415,8 @@ impl DedicatedWorkerGlobalScope {
WorkerScriptMsg::DOMMessage(data) => { WorkerScriptMsg::DOMMessage(data) => {
let scope = self.upcast::<WorkerGlobalScope>(); let scope = self.upcast::<WorkerGlobalScope>();
let target = self.upcast(); let target = self.upcast();
let _ac = JSAutoCompartment::new(scope.get_cx(), let _ac =
scope.reflector().get_jsobject().get()); JSAutoCompartment::new(scope.get_cx(), scope.reflector().get_jsobject().get());
rooted!(in(scope.get_cx()) let mut message = UndefinedValue()); rooted!(in(scope.get_cx()) let mut message = UndefinedValue());
data.read(scope.upcast(), message.handle_mut()); data.read(scope.upcast(), message.handle_mut());
MessageEvent::dispatch_jsval(target, scope.upcast(), message.handle(), None); MessageEvent::dispatch_jsval(target, scope.upcast(), message.handle(), None);
@ -392,33 +429,33 @@ impl DedicatedWorkerGlobalScope {
fn handle_mixed_message(&self, msg: MixedMessage) { fn handle_mixed_message(&self, msg: MixedMessage) {
match msg { match msg {
MixedMessage::FromDevtools(msg) => { MixedMessage::FromDevtools(msg) => match msg {
match msg { DevtoolScriptControlMsg::EvaluateJS(_pipe_id, string, sender) => {
DevtoolScriptControlMsg::EvaluateJS(_pipe_id, string, sender) => devtools::handle_evaluate_js(self.upcast(), string, sender)
devtools::handle_evaluate_js(self.upcast(), string, sender),
DevtoolScriptControlMsg::GetCachedMessages(pipe_id, message_types, sender) =>
devtools::handle_get_cached_messages(pipe_id, message_types, sender),
DevtoolScriptControlMsg::WantsLiveNotifications(_pipe_id, bool_val) =>
devtools::handle_wants_live_notifications(self.upcast(), bool_val),
_ => debug!("got an unusable devtools control message inside the worker!"),
}
}, },
MixedMessage::FromScheduler((linked_worker, timer_event)) => { DevtoolScriptControlMsg::GetCachedMessages(pipe_id, message_types, sender) => {
match timer_event { devtools::handle_get_cached_messages(pipe_id, message_types, sender)
},
DevtoolScriptControlMsg::WantsLiveNotifications(_pipe_id, bool_val) => {
devtools::handle_wants_live_notifications(self.upcast(), bool_val)
},
_ => debug!("got an unusable devtools control message inside the worker!"),
},
MixedMessage::FromScheduler((linked_worker, timer_event)) => match timer_event {
TimerEvent(TimerSource::FromWorker, id) => { TimerEvent(TimerSource::FromWorker, id) => {
let _ar = AutoWorkerReset::new(self, linked_worker); let _ar = AutoWorkerReset::new(self, linked_worker);
let scope = self.upcast::<WorkerGlobalScope>(); let scope = self.upcast::<WorkerGlobalScope>();
scope.handle_fire_timer(id); scope.handle_fire_timer(id);
}, },
TimerEvent(_, _) => { TimerEvent(_, _) => panic!("A worker received a TimerEvent from a window."),
panic!("A worker received a TimerEvent from a window.") },
} MixedMessage::FromWorker(DedicatedWorkerScriptMsg::CommonWorker(
} linked_worker,
} msg,
MixedMessage::FromWorker(DedicatedWorkerScriptMsg::CommonWorker(linked_worker, msg)) => { )) => {
let _ar = AutoWorkerReset::new(self, linked_worker); let _ar = AutoWorkerReset::new(self, linked_worker);
self.handle_script_event(msg); self.handle_script_event(msg);
} },
MixedMessage::FromWorker(DedicatedWorkerScriptMsg::WakeUp) => {}, MixedMessage::FromWorker(DedicatedWorkerScriptMsg::WakeUp) => {},
} }
} }
@ -452,7 +489,8 @@ impl DedicatedWorkerGlobalScope {
global.report_an_error(error_info, HandleValue::null()); global.report_an_error(error_info, HandleValue::null());
} }
})); }));
self.parent_sender.send(CommonScriptMsg::Task( self.parent_sender
.send(CommonScriptMsg::Task(
WorkerEvent, WorkerEvent,
task, task,
Some(pipeline_id), Some(pipeline_id),
@ -463,8 +501,7 @@ impl DedicatedWorkerGlobalScope {
#[allow(unsafe_code)] #[allow(unsafe_code)]
unsafe extern "C" fn interrupt_callback(cx: *mut JSContext) -> bool { unsafe extern "C" fn interrupt_callback(cx: *mut JSContext) -> bool {
let worker = let worker = DomRoot::downcast::<WorkerGlobalScope>(GlobalScope::from_context(cx))
DomRoot::downcast::<WorkerGlobalScope>(GlobalScope::from_context(cx))
.expect("global is not a worker scope"); .expect("global is not a worker scope");
assert!(worker.is::<DedicatedWorkerGlobalScope>()); assert!(worker.is::<DedicatedWorkerGlobalScope>());
@ -483,7 +520,8 @@ impl DedicatedWorkerGlobalScopeMethods for DedicatedWorkerGlobalScope {
Worker::handle_message(worker, data); Worker::handle_message(worker, data);
})); }));
// TODO: Change this task source to a new `unshipped-port-message-queue` task source // TODO: Change this task source to a new `unshipped-port-message-queue` task source
self.parent_sender.send(CommonScriptMsg::Task( self.parent_sender
.send(CommonScriptMsg::Task(
WorkerEvent, WorkerEvent,
task, task,
Some(pipeline_id), Some(pipeline_id),

View file

@ -40,9 +40,11 @@ impl DissimilarOriginLocation {
} }
pub fn new(window: &DissimilarOriginWindow) -> DomRoot<DissimilarOriginLocation> { pub fn new(window: &DissimilarOriginWindow) -> DomRoot<DissimilarOriginLocation> {
reflect_dom_object(Box::new(DissimilarOriginLocation::new_inherited(window)), reflect_dom_object(
Box::new(DissimilarOriginLocation::new_inherited(window)),
window, window,
DissimilarOriginLocationBinding::Wrap) DissimilarOriginLocationBinding::Wrap,
)
} }
#[allow(dead_code)] #[allow(dead_code)]

View file

@ -46,10 +46,7 @@ pub struct DissimilarOriginWindow {
impl DissimilarOriginWindow { impl DissimilarOriginWindow {
#[allow(unsafe_code)] #[allow(unsafe_code)]
pub fn new( pub fn new(global_to_clone_from: &GlobalScope, window_proxy: &WindowProxy) -> DomRoot<Self> {
global_to_clone_from: &GlobalScope,
window_proxy: &WindowProxy,
) -> DomRoot<Self> {
let cx = global_to_clone_from.get_cx(); let cx = global_to_clone_from.get_cx();
// Any timer events fired on this window are ignored. // Any timer events fired on this window are ignored.
let (timer_event_chan, _) = ipc::channel().unwrap(); let (timer_event_chan, _) = ipc::channel().unwrap();
@ -142,7 +139,12 @@ impl DissimilarOriginWindowMethods for DissimilarOriginWindow {
#[allow(unsafe_code)] #[allow(unsafe_code)]
// https://html.spec.whatwg.org/multipage/#dom-window-postmessage // https://html.spec.whatwg.org/multipage/#dom-window-postmessage
unsafe fn PostMessage(&self, cx: *mut JSContext, message: HandleValue, origin: DOMString) -> ErrorResult { unsafe fn PostMessage(
&self,
cx: *mut JSContext,
message: HandleValue,
origin: DOMString,
) -> ErrorResult {
// Step 3-5. // Step 3-5.
let origin = match &origin[..] { let origin = match &origin[..] {
"*" => None, "*" => None,
@ -153,7 +155,7 @@ impl DissimilarOriginWindowMethods for DissimilarOriginWindow {
url => match ServoUrl::parse(&url) { url => match ServoUrl::parse(&url) {
Ok(url) => Some(url.origin()), Ok(url) => Some(url.origin()),
Err(_) => return Err(Error::Syntax), Err(_) => return Err(Error::Syntax),
} },
}; };
// Step 1-2, 6-8. // Step 1-2, 6-8.
@ -190,7 +192,8 @@ impl DissimilarOriginWindowMethods for DissimilarOriginWindow {
// https://html.spec.whatwg.org/multipage/#dom-location // https://html.spec.whatwg.org/multipage/#dom-location
fn Location(&self) -> DomRoot<DissimilarOriginLocation> { fn Location(&self) -> DomRoot<DissimilarOriginLocation> {
self.location.or_init(|| DissimilarOriginLocation::new(self)) self.location
.or_init(|| DissimilarOriginLocation::new(self))
} }
} }
@ -200,9 +203,11 @@ impl DissimilarOriginWindow {
None => return warn!("postMessage called with no incumbent global"), None => return warn!("postMessage called with no incumbent global"),
Some(incumbent) => incumbent, Some(incumbent) => incumbent,
}; };
let msg = ScriptMsg::PostMessage(self.window_proxy.browsing_context_id(), let msg = ScriptMsg::PostMessage(
self.window_proxy.browsing_context_id(),
origin, origin,
data.move_to_arraybuffer()); data.move_to_arraybuffer(),
);
let _ = incumbent.script_to_constellation_chan().send(msg); let _ = incumbent.script_to_constellation_chan().send(msg);
} }
} }

File diff suppressed because it is too large Load diff

View file

@ -34,9 +34,11 @@ impl DocumentFragment {
} }
pub fn new(document: &Document) -> DomRoot<DocumentFragment> { pub fn new(document: &Document) -> DomRoot<DocumentFragment> {
Node::reflect_node(Box::new(DocumentFragment::new_inherited(document)), Node::reflect_node(
Box::new(DocumentFragment::new_inherited(document)),
document, document,
DocumentFragmentBinding::Wrap) DocumentFragmentBinding::Wrap,
)
} }
pub fn Constructor(window: &Window) -> Fallible<DomRoot<DocumentFragment>> { pub fn Constructor(window: &Window) -> Fallible<DomRoot<DocumentFragment>> {
@ -57,12 +59,14 @@ impl DocumentFragmentMethods for DocumentFragment {
fn GetElementById(&self, id: DOMString) -> Option<DomRoot<Element>> { fn GetElementById(&self, id: DOMString) -> Option<DomRoot<Element>> {
let node = self.upcast::<Node>(); let node = self.upcast::<Node>();
let id = Atom::from(id); let id = Atom::from(id);
node.traverse_preorder().filter_map(DomRoot::downcast::<Element>).find(|descendant| { node.traverse_preorder()
match descendant.get_attribute(&ns!(), &local_name!("id")) { .filter_map(DomRoot::downcast::<Element>)
.find(
|descendant| match descendant.get_attribute(&ns!(), &local_name!("id")) {
None => false, None => false,
Some(attr) => *attr.value().as_atom() == id, Some(attr) => *attr.value().as_atom() == id,
} },
}) )
} }
// https://dom.spec.whatwg.org/#dom-parentnode-firstelementchild // https://dom.spec.whatwg.org/#dom-parentnode-firstelementchild
@ -72,7 +76,10 @@ impl DocumentFragmentMethods for DocumentFragment {
// https://dom.spec.whatwg.org/#dom-parentnode-lastelementchild // https://dom.spec.whatwg.org/#dom-parentnode-lastelementchild
fn GetLastElementChild(&self) -> Option<DomRoot<Element>> { fn GetLastElementChild(&self) -> Option<DomRoot<Element>> {
self.upcast::<Node>().rev_children().filter_map(DomRoot::downcast::<Element>).next() self.upcast::<Node>()
.rev_children()
.filter_map(DomRoot::downcast::<Element>)
.next()
} }
// https://dom.spec.whatwg.org/#dom-parentnode-childelementcount // https://dom.spec.whatwg.org/#dom-parentnode-childelementcount

View file

@ -24,11 +24,12 @@ pub struct DocumentType {
} }
impl DocumentType { impl DocumentType {
fn new_inherited(name: DOMString, fn new_inherited(
name: DOMString,
public_id: Option<DOMString>, public_id: Option<DOMString>,
system_id: Option<DOMString>, system_id: Option<DOMString>,
document: &Document) document: &Document,
-> DocumentType { ) -> DocumentType {
DocumentType { DocumentType {
node: Node::new_inherited(document), node: Node::new_inherited(document),
name: name, name: name,
@ -37,14 +38,19 @@ impl DocumentType {
} }
} }
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
pub fn new(name: DOMString, pub fn new(
name: DOMString,
public_id: Option<DOMString>, public_id: Option<DOMString>,
system_id: Option<DOMString>, system_id: Option<DOMString>,
document: &Document) document: &Document,
-> DomRoot<DocumentType> { ) -> DomRoot<DocumentType> {
Node::reflect_node(Box::new(DocumentType::new_inherited(name, public_id, system_id, document)), Node::reflect_node(
Box::new(DocumentType::new_inherited(
name, public_id, system_id, document,
)),
document, document,
DocumentTypeBinding::Wrap) DocumentTypeBinding::Wrap,
)
} }
#[inline] #[inline]

View file

@ -53,9 +53,11 @@ impl DOMException {
} }
pub fn new(global: &GlobalScope, code: DOMErrorName) -> DomRoot<DOMException> { pub fn new(global: &GlobalScope, code: DOMErrorName) -> DomRoot<DOMException> {
reflect_dom_object(Box::new(DOMException::new_inherited(code)), reflect_dom_object(
Box::new(DOMException::new_inherited(code)),
global, global,
DOMExceptionBinding::Wrap) DOMExceptionBinding::Wrap,
)
} }
} }
@ -74,7 +76,9 @@ impl DOMExceptionMethods for DOMException {
fn Message(&self) -> DOMString { fn Message(&self) -> DOMString {
let message = match self.code { let message = match self.code {
DOMErrorName::IndexSizeError => "The index is not in the allowed range.", DOMErrorName::IndexSizeError => "The index is not in the allowed range.",
DOMErrorName::HierarchyRequestError => "The operation would yield an incorrect node tree.", DOMErrorName::HierarchyRequestError => {
"The operation would yield an incorrect node tree."
},
DOMErrorName::WrongDocumentError => "The object is in the wrong document.", DOMErrorName::WrongDocumentError => "The object is in the wrong document.",
DOMErrorName::InvalidCharacterError => "The string contains invalid characters.", DOMErrorName::InvalidCharacterError => "The string contains invalid characters.",
DOMErrorName::NoModificationAllowedError => "The object can not be modified.", DOMErrorName::NoModificationAllowedError => "The object can not be modified.",
@ -85,17 +89,20 @@ impl DOMExceptionMethods for DOMException {
DOMErrorName::SyntaxError => "The string did not match the expected pattern.", DOMErrorName::SyntaxError => "The string did not match the expected pattern.",
DOMErrorName::InvalidModificationError => "The object can not be modified in this way.", DOMErrorName::InvalidModificationError => "The object can not be modified in this way.",
DOMErrorName::NamespaceError => "The operation is not allowed by Namespaces in XML.", DOMErrorName::NamespaceError => "The operation is not allowed by Namespaces in XML.",
DOMErrorName::InvalidAccessError => "The object does not support the operation or argument.", DOMErrorName::InvalidAccessError => {
"The object does not support the operation or argument."
},
DOMErrorName::SecurityError => "The operation is insecure.", DOMErrorName::SecurityError => "The operation is insecure.",
DOMErrorName::NetworkError => "A network error occurred.", DOMErrorName::NetworkError => "A network error occurred.",
DOMErrorName::AbortError => "The operation was aborted.", DOMErrorName::AbortError => "The operation was aborted.",
DOMErrorName::TypeMismatchError => "The given type does not match any expected type.", DOMErrorName::TypeMismatchError => "The given type does not match any expected type.",
DOMErrorName::QuotaExceededError => "The quota has been exceeded.", DOMErrorName::QuotaExceededError => "The quota has been exceeded.",
DOMErrorName::TimeoutError => "The operation timed out.", DOMErrorName::TimeoutError => "The operation timed out.",
DOMErrorName::InvalidNodeTypeError => DOMErrorName::InvalidNodeTypeError => {
"The supplied node is incorrect or has an incorrect ancestor for this operation.", "The supplied node is incorrect or has an incorrect ancestor for this operation."
},
DOMErrorName::DataCloneError => "The object can not be cloned.", DOMErrorName::DataCloneError => "The object can not be cloned.",
DOMErrorName::NotReadableError => "The I/O read operation failed." DOMErrorName::NotReadableError => "The I/O read operation failed.",
}; };
DOMString::from(message) DOMString::from(message)

View file

@ -44,42 +44,60 @@ impl DOMImplementation {
pub fn new(document: &Document) -> DomRoot<DOMImplementation> { pub fn new(document: &Document) -> DomRoot<DOMImplementation> {
let window = document.window(); let window = document.window();
reflect_dom_object(Box::new(DOMImplementation::new_inherited(document)), reflect_dom_object(
Box::new(DOMImplementation::new_inherited(document)),
window, window,
DOMImplementationBinding::Wrap) DOMImplementationBinding::Wrap,
)
} }
} }
// https://dom.spec.whatwg.org/#domimplementation // https://dom.spec.whatwg.org/#domimplementation
impl DOMImplementationMethods for DOMImplementation { impl DOMImplementationMethods for DOMImplementation {
// https://dom.spec.whatwg.org/#dom-domimplementation-createdocumenttype // https://dom.spec.whatwg.org/#dom-domimplementation-createdocumenttype
fn CreateDocumentType(&self, fn CreateDocumentType(
&self,
qualified_name: DOMString, qualified_name: DOMString,
pubid: DOMString, pubid: DOMString,
sysid: DOMString) sysid: DOMString,
-> Fallible<DomRoot<DocumentType>> { ) -> Fallible<DomRoot<DocumentType>> {
validate_qualified_name(&qualified_name)?; validate_qualified_name(&qualified_name)?;
Ok(DocumentType::new(qualified_name, Some(pubid), Some(sysid), &self.document)) Ok(DocumentType::new(
qualified_name,
Some(pubid),
Some(sysid),
&self.document,
))
} }
// https://dom.spec.whatwg.org/#dom-domimplementation-createdocument // https://dom.spec.whatwg.org/#dom-domimplementation-createdocument
fn CreateDocument(&self, fn CreateDocument(
&self,
maybe_namespace: Option<DOMString>, maybe_namespace: Option<DOMString>,
qname: DOMString, qname: DOMString,
maybe_doctype: Option<&DocumentType>) maybe_doctype: Option<&DocumentType>,
-> Fallible<DomRoot<XMLDocument>> { ) -> Fallible<DomRoot<XMLDocument>> {
let win = self.document.window(); let win = self.document.window();
let loader = DocumentLoader::new(&self.document.loader()); let loader = DocumentLoader::new(&self.document.loader());
let namespace = namespace_from_domstring(maybe_namespace.to_owned()); let namespace = namespace_from_domstring(maybe_namespace.to_owned());
let content_type = match namespace { let content_type = match namespace {
ns!(html) => Mime(TopLevel::Application, SubLevel::Ext("xhtml+xml".to_string()), vec![]), ns!(html) => Mime(
ns!(svg) => Mime(TopLevel::Image, SubLevel::Ext("svg+xml".to_string()), vec![]), TopLevel::Application,
_ => Mime(TopLevel::Application, SubLevel::Xml, vec![]) SubLevel::Ext("xhtml+xml".to_string()),
vec![],
),
ns!(svg) => Mime(
TopLevel::Image,
SubLevel::Ext("svg+xml".to_string()),
vec![],
),
_ => Mime(TopLevel::Application, SubLevel::Xml, vec![]),
}; };
// Step 1. // Step 1.
let doc = XMLDocument::new(win, let doc = XMLDocument::new(
win,
HasBrowsingContext::No, HasBrowsingContext::No,
None, None,
self.document.origin().clone(), self.document.origin().clone(),
@ -88,13 +106,17 @@ impl DOMImplementationMethods for DOMImplementation {
None, None,
DocumentActivity::Inactive, DocumentActivity::Inactive,
DocumentSource::NotFromParser, DocumentSource::NotFromParser,
loader); loader,
);
// Step 2-3. // Step 2-3.
let maybe_elem = if qname.is_empty() { let maybe_elem = if qname.is_empty() {
None None
} else { } else {
let options = ElementCreationOptions { is: None }; let options = ElementCreationOptions { is: None };
match doc.upcast::<Document>().CreateElementNS(maybe_namespace, qname, &options) { match doc
.upcast::<Document>()
.CreateElementNS(maybe_namespace, qname, &options)
{
Err(error) => return Err(error), Err(error) => return Err(error),
Ok(elem) => Some(elem), Ok(elem) => Some(elem),
} }
@ -127,7 +149,8 @@ impl DOMImplementationMethods for DOMImplementation {
let loader = DocumentLoader::new(&self.document.loader()); let loader = DocumentLoader::new(&self.document.loader());
// Step 1-2. // Step 1-2.
let doc = Document::new(win, let doc = Document::new(
win,
HasBrowsingContext::No, HasBrowsingContext::No,
None, None,
self.document.origin().clone(), self.document.origin().clone(),
@ -139,7 +162,8 @@ impl DOMImplementationMethods for DOMImplementation {
loader, loader,
None, None,
None, None,
Default::default()); Default::default(),
);
{ {
// Step 3. // Step 3.
@ -151,25 +175,24 @@ impl DOMImplementationMethods for DOMImplementation {
{ {
// Step 4. // Step 4.
let doc_node = doc.upcast::<Node>(); let doc_node = doc.upcast::<Node>();
let doc_html = DomRoot::upcast::<Node>(HTMLHtmlElement::new(local_name!("html"), let doc_html =
None, DomRoot::upcast::<Node>(HTMLHtmlElement::new(local_name!("html"), None, &doc));
&doc));
doc_node.AppendChild(&doc_html).expect("Appending failed"); doc_node.AppendChild(&doc_html).expect("Appending failed");
{ {
// Step 5. // Step 5.
let doc_head = DomRoot::upcast::<Node>(HTMLHeadElement::new(local_name!("head"), let doc_head =
None, DomRoot::upcast::<Node>(HTMLHeadElement::new(local_name!("head"), None, &doc));
&doc));
doc_html.AppendChild(&doc_head).unwrap(); doc_html.AppendChild(&doc_head).unwrap();
// Step 6. // Step 6.
if let Some(title_str) = title { if let Some(title_str) = title {
// Step 6.1. // Step 6.1.
let doc_title = let doc_title = DomRoot::upcast::<Node>(HTMLTitleElement::new(
DomRoot::upcast::<Node>(HTMLTitleElement::new(local_name!("title"), local_name!("title"),
None, None,
&doc)); &doc,
));
doc_head.AppendChild(&doc_title).unwrap(); doc_head.AppendChild(&doc_title).unwrap();
// Step 6.2. // Step 6.2.

View file

@ -17,7 +17,7 @@ use js::typedarray::{Float32Array, Float64Array};
#[dom_struct] #[dom_struct]
pub struct DOMMatrix { pub struct DOMMatrix {
parent: DOMMatrixReadOnly parent: DOMMatrixReadOnly,
} }
impl DOMMatrix { impl DOMMatrix {
@ -29,7 +29,7 @@ impl DOMMatrix {
pub fn new_inherited(is2D: bool, matrix: Transform3D<f64>) -> Self { pub fn new_inherited(is2D: bool, matrix: Transform3D<f64>) -> Self {
DOMMatrix { DOMMatrix {
parent: DOMMatrixReadOnly::new_inherited(is2D, matrix) parent: DOMMatrixReadOnly::new_inherited(is2D, matrix),
} }
} }
@ -40,18 +40,12 @@ impl DOMMatrix {
// https://drafts.fxtf.org/geometry-1/#dom-dommatrix-dommatrix-numbersequence // https://drafts.fxtf.org/geometry-1/#dom-dommatrix-dommatrix-numbersequence
pub fn Constructor_(global: &GlobalScope, entries: Vec<f64>) -> Fallible<DomRoot<Self>> { pub fn Constructor_(global: &GlobalScope, entries: Vec<f64>) -> Fallible<DomRoot<Self>> {
entries_to_matrix(&entries[..]) entries_to_matrix(&entries[..]).map(|(is2D, matrix)| Self::new(global, is2D, matrix))
.map(|(is2D, matrix)| {
Self::new(global, is2D, matrix)
})
} }
// https://drafts.fxtf.org/geometry-1/#dom-dommatrix-frommatrix // https://drafts.fxtf.org/geometry-1/#dom-dommatrix-frommatrix
pub fn FromMatrix(global: &GlobalScope, other: &DOMMatrixInit) -> Fallible<DomRoot<Self>> { pub fn FromMatrix(global: &GlobalScope, other: &DOMMatrixInit) -> Fallible<DomRoot<Self>> {
dommatrixinit_to_matrix(&other) dommatrixinit_to_matrix(&other).map(|(is2D, matrix)| Self::new(global, is2D, matrix))
.map(|(is2D, matrix)| {
Self::new(global, is2D, matrix)
})
} }
pub fn from_readonly(global: &GlobalScope, ro: &DOMMatrixReadOnly) -> DomRoot<Self> { pub fn from_readonly(global: &GlobalScope, ro: &DOMMatrixReadOnly) -> DomRoot<Self> {
@ -299,7 +293,7 @@ impl DOMMatrixMethods for DOMMatrix {
} }
// https://drafts.fxtf.org/geometry-1/#dom-dommatrix-multiplyself // https://drafts.fxtf.org/geometry-1/#dom-dommatrix-multiplyself
fn MultiplySelf(&self, other:&DOMMatrixInit) -> Fallible<DomRoot<DOMMatrix>> { fn MultiplySelf(&self, other: &DOMMatrixInit) -> Fallible<DomRoot<DOMMatrix>> {
// Steps 1-3. // Steps 1-3.
self.upcast::<DOMMatrixReadOnly>().multiply_self(other) self.upcast::<DOMMatrixReadOnly>().multiply_self(other)
// Step 4. // Step 4.
@ -307,7 +301,7 @@ impl DOMMatrixMethods for DOMMatrix {
} }
// https://drafts.fxtf.org/geometry-1/#dom-dommatrix-premultiplyself // https://drafts.fxtf.org/geometry-1/#dom-dommatrix-premultiplyself
fn PreMultiplySelf(&self, other:&DOMMatrixInit) -> Fallible<DomRoot<DOMMatrix>> { fn PreMultiplySelf(&self, other: &DOMMatrixInit) -> Fallible<DomRoot<DOMMatrix>> {
// Steps 1-3. // Steps 1-3.
self.upcast::<DOMMatrixReadOnly>().pre_multiply_self(other) self.upcast::<DOMMatrixReadOnly>().pre_multiply_self(other)
// Step 4. // Step 4.
@ -317,24 +311,40 @@ impl DOMMatrixMethods for DOMMatrix {
// https://drafts.fxtf.org/geometry-1/#dom-dommatrix-translateself // https://drafts.fxtf.org/geometry-1/#dom-dommatrix-translateself
fn TranslateSelf(&self, tx: f64, ty: f64, tz: f64) -> DomRoot<DOMMatrix> { fn TranslateSelf(&self, tx: f64, ty: f64, tz: f64) -> DomRoot<DOMMatrix> {
// Steps 1-2. // Steps 1-2.
self.upcast::<DOMMatrixReadOnly>().translate_self(tx, ty, tz); self.upcast::<DOMMatrixReadOnly>()
.translate_self(tx, ty, tz);
// Step 3. // Step 3.
DomRoot::from_ref(&self) DomRoot::from_ref(&self)
} }
// https://drafts.fxtf.org/geometry-1/#dom-dommatrix-scaleself // https://drafts.fxtf.org/geometry-1/#dom-dommatrix-scaleself
fn ScaleSelf(&self, scaleX: f64, scaleY: Option<f64>, scaleZ: f64, fn ScaleSelf(
originX: f64, originY: f64, originZ: f64) -> DomRoot<DOMMatrix> { &self,
scaleX: f64,
scaleY: Option<f64>,
scaleZ: f64,
originX: f64,
originY: f64,
originZ: f64,
) -> DomRoot<DOMMatrix> {
// Steps 1-6. // Steps 1-6.
self.upcast::<DOMMatrixReadOnly>().scale_self(scaleX, scaleY, scaleZ, originX, originY, originZ); self.upcast::<DOMMatrixReadOnly>()
.scale_self(scaleX, scaleY, scaleZ, originX, originY, originZ);
// Step 7. // Step 7.
DomRoot::from_ref(&self) DomRoot::from_ref(&self)
} }
// https://drafts.fxtf.org/geometry-1/#dom-dommatrix-scale3dself // https://drafts.fxtf.org/geometry-1/#dom-dommatrix-scale3dself
fn Scale3dSelf(&self, scale: f64, originX: f64, originY: f64, originZ: f64) -> DomRoot<DOMMatrix> { fn Scale3dSelf(
&self,
scale: f64,
originX: f64,
originY: f64,
originZ: f64,
) -> DomRoot<DOMMatrix> {
// Steps 1-4. // Steps 1-4.
self.upcast::<DOMMatrixReadOnly>().scale_3d_self(scale, originX, originY, originZ); self.upcast::<DOMMatrixReadOnly>()
.scale_3d_self(scale, originX, originY, originZ);
// Step 5. // Step 5.
DomRoot::from_ref(&self) DomRoot::from_ref(&self)
} }
@ -342,7 +352,8 @@ impl DOMMatrixMethods for DOMMatrix {
// https://drafts.fxtf.org/geometry-1/#dom-dommatrix-rotateself // https://drafts.fxtf.org/geometry-1/#dom-dommatrix-rotateself
fn RotateSelf(&self, rotX: f64, rotY: Option<f64>, rotZ: Option<f64>) -> DomRoot<DOMMatrix> { fn RotateSelf(&self, rotX: f64, rotY: Option<f64>, rotZ: Option<f64>) -> DomRoot<DOMMatrix> {
// Steps 1-7. // Steps 1-7.
self.upcast::<DOMMatrixReadOnly>().rotate_self(rotX, rotY, rotZ); self.upcast::<DOMMatrixReadOnly>()
.rotate_self(rotX, rotY, rotZ);
// Step 8. // Step 8.
DomRoot::from_ref(&self) DomRoot::from_ref(&self)
} }
@ -350,7 +361,8 @@ impl DOMMatrixMethods for DOMMatrix {
// https://drafts.fxtf.org/geometry-1/#dom-dommatrix-rotatefromvectorself // https://drafts.fxtf.org/geometry-1/#dom-dommatrix-rotatefromvectorself
fn RotateFromVectorSelf(&self, x: f64, y: f64) -> DomRoot<DOMMatrix> { fn RotateFromVectorSelf(&self, x: f64, y: f64) -> DomRoot<DOMMatrix> {
// Step 1. // Step 1.
self.upcast::<DOMMatrixReadOnly>().rotate_from_vector_self(x, y); self.upcast::<DOMMatrixReadOnly>()
.rotate_from_vector_self(x, y);
// Step 2. // Step 2.
DomRoot::from_ref(&self) DomRoot::from_ref(&self)
} }
@ -358,7 +370,8 @@ impl DOMMatrixMethods for DOMMatrix {
// https://drafts.fxtf.org/geometry-1/#dom-dommatrix-rotateaxisangleself // https://drafts.fxtf.org/geometry-1/#dom-dommatrix-rotateaxisangleself
fn RotateAxisAngleSelf(&self, x: f64, y: f64, z: f64, angle: f64) -> DomRoot<DOMMatrix> { fn RotateAxisAngleSelf(&self, x: f64, y: f64, z: f64, angle: f64) -> DomRoot<DOMMatrix> {
// Steps 1-2. // Steps 1-2.
self.upcast::<DOMMatrixReadOnly>().rotate_axis_angle_self(x, y, z, angle); self.upcast::<DOMMatrixReadOnly>()
.rotate_axis_angle_self(x, y, z, angle);
// Step 3. // Step 3.
DomRoot::from_ref(&self) DomRoot::from_ref(&self)
} }

View file

@ -53,18 +53,12 @@ impl DOMMatrixReadOnly {
// https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-dommatrixreadonly-numbersequence // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-dommatrixreadonly-numbersequence
pub fn Constructor_(global: &GlobalScope, entries: Vec<f64>) -> Fallible<DomRoot<Self>> { pub fn Constructor_(global: &GlobalScope, entries: Vec<f64>) -> Fallible<DomRoot<Self>> {
entries_to_matrix(&entries[..]) entries_to_matrix(&entries[..]).map(|(is2D, matrix)| Self::new(global, is2D, matrix))
.map(|(is2D, matrix)| {
Self::new(global, is2D, matrix)
})
} }
// https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-frommatrix // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-frommatrix
pub fn FromMatrix(global: &GlobalScope, other: &DOMMatrixInit) -> Fallible<DomRoot<Self>> { pub fn FromMatrix(global: &GlobalScope, other: &DOMMatrixInit) -> Fallible<DomRoot<Self>> {
dommatrixinit_to_matrix(&other) dommatrixinit_to_matrix(&other).map(|(is2D, matrix)| Self::new(global, is2D, matrix))
.map(|(is2D, matrix)| {
Self::new(global, is2D, matrix)
})
} }
pub fn matrix(&self) -> Ref<Transform3D<f64>> { pub fn matrix(&self) -> Ref<Transform3D<f64>> {
@ -155,7 +149,6 @@ impl DOMMatrixReadOnly {
self.matrix.borrow_mut().m44 = value; self.matrix.borrow_mut().m44 = value;
} }
// https://drafts.fxtf.org/geometry-1/#dom-dommatrix-multiplyself // https://drafts.fxtf.org/geometry-1/#dom-dommatrix-multiplyself
pub fn multiply_self(&self, other: &DOMMatrixInit) -> Fallible<()> { pub fn multiply_self(&self, other: &DOMMatrixInit) -> Fallible<()> {
// Step 1. // Step 1.
@ -200,8 +193,15 @@ impl DOMMatrixReadOnly {
} }
// https://drafts.fxtf.org/geometry-1/#dom-dommatrix-scaleself // https://drafts.fxtf.org/geometry-1/#dom-dommatrix-scaleself
pub fn scale_self(&self, scaleX: f64, scaleY: Option<f64>, scaleZ: f64, pub fn scale_self(
mut originX: f64, mut originY: f64, mut originZ: f64) { &self,
scaleX: f64,
scaleY: Option<f64>,
scaleZ: f64,
mut originX: f64,
mut originY: f64,
mut originZ: f64,
) {
// Step 1. // Step 1.
self.translate_self(originX, originY, originZ); self.translate_self(originX, originY, originZ);
// Step 2. // Step 2.
@ -262,19 +262,22 @@ impl DOMMatrixReadOnly {
} }
if rotZ != 0.0 { if rotZ != 0.0 {
// Step 5. // Step 5.
let rotation = Transform3D::create_rotation(0.0, 0.0, 1.0, Angle::radians(rotZ.to_radians())); let rotation =
Transform3D::create_rotation(0.0, 0.0, 1.0, Angle::radians(rotZ.to_radians()));
let mut matrix = self.matrix.borrow_mut(); let mut matrix = self.matrix.borrow_mut();
*matrix = rotation.post_mul(&matrix); *matrix = rotation.post_mul(&matrix);
} }
if rotY != 0.0 { if rotY != 0.0 {
// Step 6. // Step 6.
let rotation = Transform3D::create_rotation(0.0, 1.0, 0.0, Angle::radians(rotY.to_radians())); let rotation =
Transform3D::create_rotation(0.0, 1.0, 0.0, Angle::radians(rotY.to_radians()));
let mut matrix = self.matrix.borrow_mut(); let mut matrix = self.matrix.borrow_mut();
*matrix = rotation.post_mul(&matrix); *matrix = rotation.post_mul(&matrix);
} }
if rotX != 0.0 { if rotX != 0.0 {
// Step 7. // Step 7.
let rotation = Transform3D::create_rotation(1.0, 0.0, 0.0, Angle::radians(rotX.to_radians())); let rotation =
Transform3D::create_rotation(1.0, 0.0, 0.0, Angle::radians(rotX.to_radians()));
let mut matrix = self.matrix.borrow_mut(); let mut matrix = self.matrix.borrow_mut();
*matrix = rotation.post_mul(&matrix); *matrix = rotation.post_mul(&matrix);
} }
@ -298,7 +301,12 @@ impl DOMMatrixReadOnly {
pub fn rotate_axis_angle_self(&self, x: f64, y: f64, z: f64, angle: f64) { pub fn rotate_axis_angle_self(&self, x: f64, y: f64, z: f64, angle: f64) {
// Step 1. // Step 1.
let (norm_x, norm_y, norm_z) = normalize_point(x, y, z); let (norm_x, norm_y, norm_z) = normalize_point(x, y, z);
let rotation = Transform3D::create_rotation(norm_x, norm_y, norm_z, Angle::radians(angle.to_radians())); let rotation = Transform3D::create_rotation(
norm_x,
norm_y,
norm_z,
Angle::radians(angle.to_radians()),
);
let mut matrix = self.matrix.borrow_mut(); let mut matrix = self.matrix.borrow_mut();
*matrix = rotation.post_mul(&matrix); *matrix = rotation.post_mul(&matrix);
// Step 2. // Step 2.
@ -333,10 +341,24 @@ impl DOMMatrixReadOnly {
*matrix = matrix.inverse().unwrap_or_else(|| { *matrix = matrix.inverse().unwrap_or_else(|| {
// Step 2. // Step 2.
self.is2D.set(false); self.is2D.set(false);
Transform3D::row_major(f64::NAN, f64::NAN, f64::NAN, f64::NAN, Transform3D::row_major(
f64::NAN, f64::NAN, f64::NAN, f64::NAN, f64::NAN,
f64::NAN, f64::NAN, f64::NAN, f64::NAN, f64::NAN,
f64::NAN, f64::NAN, f64::NAN, f64::NAN) f64::NAN,
f64::NAN,
f64::NAN,
f64::NAN,
f64::NAN,
f64::NAN,
f64::NAN,
f64::NAN,
f64::NAN,
f64::NAN,
f64::NAN,
f64::NAN,
f64::NAN,
f64::NAN,
)
}) })
// Step 3 in DOMMatrix.InvertSelf // Step 3 in DOMMatrix.InvertSelf
} }
@ -362,7 +384,6 @@ impl DOMMatrixReadOnly {
} }
} }
impl DOMMatrixReadOnlyMethods for DOMMatrixReadOnly { impl DOMMatrixReadOnlyMethods for DOMMatrixReadOnly {
// https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m11 // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m11
fn M11(&self) -> f64 { fn M11(&self) -> f64 {
@ -482,10 +503,22 @@ impl DOMMatrixReadOnlyMethods for DOMMatrixReadOnly {
// https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-isidentity // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-isidentity
fn IsIdentity(&self) -> bool { fn IsIdentity(&self) -> bool {
let matrix = self.matrix.borrow(); let matrix = self.matrix.borrow();
matrix.m12 == 0.0 && matrix.m13 == 0.0 && matrix.m14 == 0.0 && matrix.m21 == 0.0 && matrix.m12 == 0.0 &&
matrix.m23 == 0.0 && matrix.m24 == 0.0 && matrix.m31 == 0.0 && matrix.m32 == 0.0 && matrix.m13 == 0.0 &&
matrix.m34 == 0.0 && matrix.m41 == 0.0 && matrix.m42 == 0.0 && matrix.m43 == 0.0 && matrix.m14 == 0.0 &&
matrix.m11 == 1.0 && matrix.m22 == 1.0 && matrix.m33 == 1.0 && matrix.m44 == 1.0 matrix.m21 == 0.0 &&
matrix.m23 == 0.0 &&
matrix.m24 == 0.0 &&
matrix.m31 == 0.0 &&
matrix.m32 == 0.0 &&
matrix.m34 == 0.0 &&
matrix.m41 == 0.0 &&
matrix.m42 == 0.0 &&
matrix.m43 == 0.0 &&
matrix.m11 == 1.0 &&
matrix.m22 == 1.0 &&
matrix.m33 == 1.0 &&
matrix.m44 == 1.0
} }
// https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-translate // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-translate
@ -494,16 +527,22 @@ impl DOMMatrixReadOnlyMethods for DOMMatrixReadOnly {
} }
// https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-scale // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-scale
fn Scale(&self, scaleX: f64, scaleY: Option<f64>, scaleZ: f64, fn Scale(
originX: f64, originY: f64, originZ: f64) -> DomRoot<DOMMatrix> { &self,
scaleX: f64,
scaleY: Option<f64>,
scaleZ: f64,
originX: f64,
originY: f64,
originZ: f64,
) -> DomRoot<DOMMatrix> {
DOMMatrix::from_readonly(&self.global(), self) DOMMatrix::from_readonly(&self.global(), self)
.ScaleSelf(scaleX, scaleY, scaleZ, originX, originY, originZ) .ScaleSelf(scaleX, scaleY, scaleZ, originX, originY, originZ)
} }
// https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-scale3d // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-scale3d
fn Scale3d(&self, scale: f64, originX: f64, originY: f64, originZ: f64) -> DomRoot<DOMMatrix> { fn Scale3d(&self, scale: f64, originX: f64, originY: f64, originZ: f64) -> DomRoot<DOMMatrix> {
DOMMatrix::from_readonly(&self.global(), self) DOMMatrix::from_readonly(&self.global(), self).Scale3dSelf(scale, originX, originY, originZ)
.Scale3dSelf(scale, originX, originY, originZ)
} }
// https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-rotate // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-rotate
@ -539,10 +578,9 @@ impl DOMMatrixReadOnlyMethods for DOMMatrixReadOnly {
// https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-flipx // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-flipx
fn FlipX(&self) -> DomRoot<DOMMatrix> { fn FlipX(&self) -> DomRoot<DOMMatrix> {
let is2D = self.is2D.get(); let is2D = self.is2D.get();
let flip = Transform3D::row_major(-1.0, 0.0, 0.0, 0.0, let flip = Transform3D::row_major(
0.0, 1.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0,
0.0, 0.0, 1.0, 0.0, );
0.0, 0.0, 0.0, 1.0);
let matrix = flip.post_mul(&self.matrix.borrow()); let matrix = flip.post_mul(&self.matrix.borrow());
DOMMatrix::new(&self.global(), is2D, matrix) DOMMatrix::new(&self.global(), is2D, matrix)
} }
@ -550,10 +588,9 @@ impl DOMMatrixReadOnlyMethods for DOMMatrixReadOnly {
// https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-flipy // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-flipy
fn FlipY(&self) -> DomRoot<DOMMatrix> { fn FlipY(&self) -> DomRoot<DOMMatrix> {
let is2D = self.is2D.get(); let is2D = self.is2D.get();
let flip = Transform3D::row_major(1.0, 0.0, 0.0, 0.0, let flip = Transform3D::row_major(
0.0, -1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0,
0.0, 0.0, 1.0, 0.0, );
0.0, 0.0, 0.0, 1.0);
let matrix = flip.post_mul(&self.matrix.borrow()); let matrix = flip.post_mul(&self.matrix.borrow());
DOMMatrix::new(&self.global(), is2D, matrix) DOMMatrix::new(&self.global(), is2D, matrix)
} }
@ -583,11 +620,15 @@ impl DOMMatrixReadOnlyMethods for DOMMatrixReadOnly {
// https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-tofloat32array // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-tofloat32array
#[allow(unsafe_code)] #[allow(unsafe_code)]
unsafe fn ToFloat32Array(&self, cx: *mut JSContext) -> NonNull<JSObject> { unsafe fn ToFloat32Array(&self, cx: *mut JSContext) -> NonNull<JSObject> {
let vec: Vec<f32> = self.matrix let vec: Vec<f32> = self
.borrow().to_row_major_array().iter().map(|&x| x as f32).collect(); .matrix
.borrow()
.to_row_major_array()
.iter()
.map(|&x| x as f32)
.collect();
rooted!(in (cx) let mut array = ptr::null_mut::<JSObject>()); rooted!(in (cx) let mut array = ptr::null_mut::<JSObject>());
let _ = Float32Array::create(cx, CreateWith::Slice(&vec), array.handle_mut()) let _ = Float32Array::create(cx, CreateWith::Slice(&vec), array.handle_mut()).unwrap();
.unwrap();
NonNull::new_unchecked(array.get()) NonNull::new_unchecked(array.get())
} }
@ -596,28 +637,39 @@ impl DOMMatrixReadOnlyMethods for DOMMatrixReadOnly {
unsafe fn ToFloat64Array(&self, cx: *mut JSContext) -> NonNull<JSObject> { unsafe fn ToFloat64Array(&self, cx: *mut JSContext) -> NonNull<JSObject> {
let arr = self.matrix.borrow().to_row_major_array(); let arr = self.matrix.borrow().to_row_major_array();
rooted!(in (cx) let mut array = ptr::null_mut::<JSObject>()); rooted!(in (cx) let mut array = ptr::null_mut::<JSObject>());
let _ = Float64Array::create(cx, CreateWith::Slice(&arr), array.handle_mut()) let _ = Float64Array::create(cx, CreateWith::Slice(&arr), array.handle_mut()).unwrap();
.unwrap();
NonNull::new_unchecked(array.get()) NonNull::new_unchecked(array.get())
} }
} }
// https://drafts.fxtf.org/geometry-1/#create-a-2d-matrix // https://drafts.fxtf.org/geometry-1/#create-a-2d-matrix
fn create_2d_matrix(entries: &[f64]) -> Transform3D<f64> { fn create_2d_matrix(entries: &[f64]) -> Transform3D<f64> {
Transform3D::row_major(entries[0], entries[1], 0.0, 0.0, Transform3D::row_major(
entries[2], entries[3], 0.0, 0.0, entries[0], entries[1], 0.0, 0.0, entries[2], entries[3], 0.0, 0.0, 0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 1.0, 0.0, entries[4], entries[5], 0.0, 1.0,
entries[4], entries[5], 0.0, 1.0) )
} }
// https://drafts.fxtf.org/geometry-1/#create-a-3d-matrix // https://drafts.fxtf.org/geometry-1/#create-a-3d-matrix
fn create_3d_matrix(entries: &[f64]) -> Transform3D<f64> { fn create_3d_matrix(entries: &[f64]) -> Transform3D<f64> {
Transform3D::row_major(entries[0], entries[1], entries[2], entries[3], Transform3D::row_major(
entries[4], entries[5], entries[6], entries[7], entries[0],
entries[8], entries[9], entries[10], entries[11], entries[1],
entries[12], entries[13], entries[14], entries[15]) entries[2],
entries[3],
entries[4],
entries[5],
entries[6],
entries[7],
entries[8],
entries[9],
entries[10],
entries[11],
entries[12],
entries[13],
entries[14],
entries[15],
)
} }
// https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-dommatrixreadonly-numbersequence // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-dommatrixreadonly-numbersequence
@ -632,7 +684,6 @@ pub fn entries_to_matrix(entries: &[f64]) -> Fallible<(bool, Transform3D<f64>)>
} }
} }
// https://drafts.fxtf.org/geometry-1/#validate-and-fixup // https://drafts.fxtf.org/geometry-1/#validate-and-fixup
pub fn dommatrixinit_to_matrix(dict: &DOMMatrixInit) -> Fallible<(bool, Transform3D<f64>)> { pub fn dommatrixinit_to_matrix(dict: &DOMMatrixInit) -> Fallible<(bool, Transform3D<f64>)> {
// Step 1. // Step 1.
@ -642,10 +693,19 @@ pub fn dommatrixinit_to_matrix(dict: &DOMMatrixInit) -> Fallible<(bool, Transfor
dict.d.is_some() && dict.m22.is_some() && dict.d.unwrap() != dict.m22.unwrap() || dict.d.is_some() && dict.m22.is_some() && dict.d.unwrap() != dict.m22.unwrap() ||
dict.e.is_some() && dict.m41.is_some() && dict.e.unwrap() != dict.m41.unwrap() || dict.e.is_some() && dict.m41.is_some() && dict.e.unwrap() != dict.m41.unwrap() ||
dict.f.is_some() && dict.m42.is_some() && dict.f.unwrap() != dict.m42.unwrap() || dict.f.is_some() && dict.m42.is_some() && dict.f.unwrap() != dict.m42.unwrap() ||
dict.is2D.is_some() && dict.is2D.unwrap() && dict.is2D.is_some() &&
(dict.m31 != 0.0 || dict.m32 != 0.0 || dict.m13 != 0.0 || dict.m23 != 0.0 || dict.is2D.unwrap() &&
dict.m43 != 0.0 || dict.m14 != 0.0 || dict.m24 != 0.0 || dict.m34 != 0.0 || (dict.m31 != 0.0 ||
dict.m33 != 1.0 || dict.m44 != 1.0) { dict.m32 != 0.0 ||
dict.m13 != 0.0 ||
dict.m23 != 0.0 ||
dict.m43 != 0.0 ||
dict.m14 != 0.0 ||
dict.m24 != 0.0 ||
dict.m34 != 0.0 ||
dict.m33 != 1.0 ||
dict.m44 != 1.0)
{
Err(error::Error::Type("Invalid matrix initializer.".to_owned())) Err(error::Error::Type("Invalid matrix initializer.".to_owned()))
} else { } else {
let mut is2D = dict.is2D; let mut is2D = dict.is2D;
@ -663,25 +723,31 @@ pub fn dommatrixinit_to_matrix(dict: &DOMMatrixInit) -> Fallible<(bool, Transfor
let m42 = dict.m42.unwrap_or(dict.f.unwrap_or(0.0)); let m42 = dict.m42.unwrap_or(dict.f.unwrap_or(0.0));
// Step 8. // Step 8.
if is2D.is_none() && if is2D.is_none() &&
(dict.m31 != 0.0 || dict.m32 != 0.0 || dict.m13 != 0.0 || (dict.m31 != 0.0 ||
dict.m23 != 0.0 || dict.m43 != 0.0 || dict.m14 != 0.0 || dict.m32 != 0.0 ||
dict.m24 != 0.0 || dict.m34 != 0.0 || dict.m13 != 0.0 ||
dict.m33 != 1.0 || dict.m44 != 1.0) { dict.m23 != 0.0 ||
dict.m43 != 0.0 ||
dict.m14 != 0.0 ||
dict.m24 != 0.0 ||
dict.m34 != 0.0 ||
dict.m33 != 1.0 ||
dict.m44 != 1.0)
{
is2D = Some(false); is2D = Some(false);
} }
// Step 9. // Step 9.
if is2D.is_none() { if is2D.is_none() {
is2D = Some(true); is2D = Some(true);
} }
let matrix = Transform3D::row_major(m11, m12, dict.m13, dict.m14, let matrix = Transform3D::row_major(
m21, m22, dict.m23, dict.m24, m11, m12, dict.m13, dict.m14, m21, m22, dict.m23, dict.m24, dict.m31, dict.m32,
dict.m31, dict.m32, dict.m33, dict.m34, dict.m33, dict.m34, m41, m42, dict.m43, dict.m44,
m41, m42, dict.m43, dict.m44); );
Ok((is2D.unwrap(), matrix)) Ok((is2D.unwrap(), matrix))
} }
} }
#[inline] #[inline]
fn normalize_point(x: f64, y: f64, z: f64) -> (f64, f64, f64) { fn normalize_point(x: f64, y: f64, z: f64) -> (f64, f64, f64) {
let len = (x * x + y * y + z * z).sqrt(); let len = (x * x + y * y + z * z).sqrt();

View file

@ -37,9 +37,11 @@ impl DOMParser {
} }
pub fn new(window: &Window) -> DomRoot<DOMParser> { pub fn new(window: &Window) -> DomRoot<DOMParser> {
reflect_dom_object(Box::new(DOMParser::new_inherited(window)), reflect_dom_object(
Box::new(DOMParser::new_inherited(window)),
window, window,
DOMParserBinding::Wrap) DOMParserBinding::Wrap,
)
} }
pub fn Constructor(window: &Window) -> Fallible<DomRoot<DOMParser>> { pub fn Constructor(window: &Window) -> Fallible<DomRoot<DOMParser>> {
@ -49,17 +51,22 @@ impl DOMParser {
impl DOMParserMethods for DOMParser { impl DOMParserMethods for DOMParser {
// https://w3c.github.io/DOM-Parsing/#the-domparser-interface // https://w3c.github.io/DOM-Parsing/#the-domparser-interface
fn ParseFromString(&self, fn ParseFromString(
&self,
s: DOMString, s: DOMString,
ty: DOMParserBinding::SupportedType) ty: DOMParserBinding::SupportedType,
-> Fallible<DomRoot<Document>> { ) -> Fallible<DomRoot<Document>> {
let url = self.window.get_url(); let url = self.window.get_url();
let content_type = ty.as_str().parse().expect("Supported type is not a MIME type"); let content_type = ty
.as_str()
.parse()
.expect("Supported type is not a MIME type");
let doc = self.window.Document(); let doc = self.window.Document();
let loader = DocumentLoader::new(&*doc.loader()); let loader = DocumentLoader::new(&*doc.loader());
match ty { match ty {
Text_html => { Text_html => {
let document = Document::new(&self.window, let document = Document::new(
&self.window,
HasBrowsingContext::No, HasBrowsingContext::No,
Some(url.clone()), Some(url.clone()),
doc.origin().clone(), doc.origin().clone(),
@ -71,13 +78,15 @@ impl DOMParserMethods for DOMParser {
loader, loader,
None, None,
None, None,
Default::default()); Default::default(),
);
ServoParser::parse_html_document(&document, s, url); ServoParser::parse_html_document(&document, s, url);
document.set_ready_state(DocumentReadyState::Complete); document.set_ready_state(DocumentReadyState::Complete);
Ok(document) Ok(document)
} },
Text_xml | Application_xml | Application_xhtml_xml => { Text_xml | Application_xml | Application_xhtml_xml => {
let document = Document::new(&self.window, let document = Document::new(
&self.window,
HasBrowsingContext::No, HasBrowsingContext::No,
Some(url.clone()), Some(url.clone()),
doc.origin().clone(), doc.origin().clone(),
@ -89,11 +98,12 @@ impl DOMParserMethods for DOMParser {
loader, loader,
None, None,
None, None,
Default::default()); Default::default(),
);
ServoParser::parse_xml_document(&document, s, url); ServoParser::parse_xml_document(&document, s, url);
document.set_ready_state(DocumentReadyState::Complete); document.set_ready_state(DocumentReadyState::Complete);
Ok(document) Ok(document)
} },
} }
} }
} }

View file

@ -28,12 +28,13 @@ impl DOMPoint {
reflect_dom_object(Box::new(DOMPoint::new_inherited(x, y, z, w)), global, Wrap) reflect_dom_object(Box::new(DOMPoint::new_inherited(x, y, z, w)), global, Wrap)
} }
pub fn Constructor(global: &GlobalScope, pub fn Constructor(
global: &GlobalScope,
x: f64, x: f64,
y: f64, y: f64,
z: f64, z: f64,
w: f64) w: f64,
-> Fallible<DomRoot<DOMPoint>> { ) -> Fallible<DomRoot<DOMPoint>> {
Ok(DOMPoint::new(global, x, y, z, w)) Ok(DOMPoint::new(global, x, y, z, w))
} }

View file

@ -32,17 +32,20 @@ impl DOMPointReadOnly {
} }
pub fn new(global: &GlobalScope, x: f64, y: f64, z: f64, w: f64) -> DomRoot<DOMPointReadOnly> { pub fn new(global: &GlobalScope, x: f64, y: f64, z: f64, w: f64) -> DomRoot<DOMPointReadOnly> {
reflect_dom_object(Box::new(DOMPointReadOnly::new_inherited(x, y, z, w)), reflect_dom_object(
Box::new(DOMPointReadOnly::new_inherited(x, y, z, w)),
global, global,
Wrap) Wrap,
)
} }
pub fn Constructor(global: &GlobalScope, pub fn Constructor(
global: &GlobalScope,
x: f64, x: f64,
y: f64, y: f64,
z: f64, z: f64,
w: f64) w: f64,
-> Fallible<DomRoot<DOMPointReadOnly>> { ) -> Fallible<DomRoot<DOMPointReadOnly>> {
Ok(DOMPointReadOnly::new(global, x, y, z, w)) Ok(DOMPointReadOnly::new(global, x, y, z, w))
} }
} }

View file

@ -24,11 +24,7 @@ pub struct DOMQuad {
} }
impl DOMQuad { impl DOMQuad {
fn new_inherited(p1: &DOMPoint, fn new_inherited(p1: &DOMPoint, p2: &DOMPoint, p3: &DOMPoint, p4: &DOMPoint) -> DOMQuad {
p2: &DOMPoint,
p3: &DOMPoint,
p4: &DOMPoint)
-> DOMQuad {
DOMQuad { DOMQuad {
reflector_: Reflector::new(), reflector_: Reflector::new(),
p1: Dom::from_ref(p1), p1: Dom::from_ref(p1),
@ -38,45 +34,62 @@ impl DOMQuad {
} }
} }
pub fn new(global: &GlobalScope, pub fn new(
global: &GlobalScope,
p1: &DOMPoint, p1: &DOMPoint,
p2: &DOMPoint, p2: &DOMPoint,
p3: &DOMPoint, p3: &DOMPoint,
p4: &DOMPoint) -> DomRoot<DOMQuad> { p4: &DOMPoint,
reflect_dom_object(Box::new(DOMQuad::new_inherited(p1, p2, p3, p4)), ) -> DomRoot<DOMQuad> {
reflect_dom_object(
Box::new(DOMQuad::new_inherited(p1, p2, p3, p4)),
global, global,
Wrap) Wrap,
)
} }
pub fn Constructor(global: &GlobalScope, pub fn Constructor(
global: &GlobalScope,
p1: &DOMPointInit, p1: &DOMPointInit,
p2: &DOMPointInit, p2: &DOMPointInit,
p3: &DOMPointInit, p3: &DOMPointInit,
p4: &DOMPointInit) p4: &DOMPointInit,
-> Fallible<DomRoot<DOMQuad>> { ) -> Fallible<DomRoot<DOMQuad>> {
Ok(DOMQuad::new(global, Ok(DOMQuad::new(
global,
&*DOMPoint::new_from_init(global, p1), &*DOMPoint::new_from_init(global, p1),
&*DOMPoint::new_from_init(global, p2), &*DOMPoint::new_from_init(global, p2),
&*DOMPoint::new_from_init(global, p3), &*DOMPoint::new_from_init(global, p3),
&*DOMPoint::new_from_init(global, p4))) &*DOMPoint::new_from_init(global, p4),
))
} }
// https://drafts.fxtf.org/geometry/#dom-domquad-fromrect // https://drafts.fxtf.org/geometry/#dom-domquad-fromrect
pub fn FromRect(global: &GlobalScope, other: &DOMRectInit) -> DomRoot<DOMQuad> { pub fn FromRect(global: &GlobalScope, other: &DOMRectInit) -> DomRoot<DOMQuad> {
DOMQuad::new(global, DOMQuad::new(
global,
&*DOMPoint::new(global, other.x, other.y, 0f64, 1f64), &*DOMPoint::new(global, other.x, other.y, 0f64, 1f64),
&*DOMPoint::new(global, other.x + other.width, other.y, 0f64, 1f64), &*DOMPoint::new(global, other.x + other.width, other.y, 0f64, 1f64),
&*DOMPoint::new(global, other.x + other.width, other.y + other.height, 0f64, 1f64), &*DOMPoint::new(
&*DOMPoint::new(global, other.x, other.y + other.height, 0f64, 1f64)) global,
other.x + other.width,
other.y + other.height,
0f64,
1f64,
),
&*DOMPoint::new(global, other.x, other.y + other.height, 0f64, 1f64),
)
} }
// https://drafts.fxtf.org/geometry/#dom-domquad-fromquad // https://drafts.fxtf.org/geometry/#dom-domquad-fromquad
pub fn FromQuad(global: &GlobalScope, other: &DOMQuadInit) -> DomRoot<DOMQuad> { pub fn FromQuad(global: &GlobalScope, other: &DOMQuadInit) -> DomRoot<DOMQuad> {
DOMQuad::new(global, DOMQuad::new(
global,
&DOMPoint::new_from_init(global, &other.p1), &DOMPoint::new_from_init(global, &other.p1),
&DOMPoint::new_from_init(global, &other.p2), &DOMPoint::new_from_init(global, &other.p2),
&DOMPoint::new_from_init(global, &other.p3), &DOMPoint::new_from_init(global, &other.p3),
&DOMPoint::new_from_init(global, &other.p4)) &DOMPoint::new_from_init(global, &other.p4),
)
} }
} }
@ -103,15 +116,31 @@ impl DOMQuadMethods for DOMQuad {
// https://drafts.fxtf.org/geometry/#dom-domquad-getbounds // https://drafts.fxtf.org/geometry/#dom-domquad-getbounds
fn GetBounds(&self) -> DomRoot<DOMRect> { fn GetBounds(&self) -> DomRoot<DOMRect> {
let left = self.p1.X().min(self.p2.X()).min(self.p3.X()).min(self.p4.X()); let left = self
let top = self.p1.Y().min(self.p2.Y()).min(self.p3.Y()).min(self.p4.Y()); .p1
let right = self.p1.X().max(self.p2.X()).max(self.p3.X()).max(self.p4.X()); .X()
let bottom = self.p1.Y().max(self.p2.Y()).max(self.p3.Y()).max(self.p4.Y()); .min(self.p2.X())
.min(self.p3.X())
.min(self.p4.X());
let top = self
.p1
.Y()
.min(self.p2.Y())
.min(self.p3.Y())
.min(self.p4.Y());
let right = self
.p1
.X()
.max(self.p2.X())
.max(self.p3.X())
.max(self.p4.X());
let bottom = self
.p1
.Y()
.max(self.p2.Y())
.max(self.p3.Y())
.max(self.p4.Y());
DOMRect::new(&self.global(), DOMRect::new(&self.global(), left, top, right - left, bottom - top)
left,
top,
right - left,
bottom - top)
} }
} }

View file

@ -25,17 +25,20 @@ impl DOMRect {
} }
pub fn new(global: &GlobalScope, x: f64, y: f64, width: f64, height: f64) -> DomRoot<DOMRect> { pub fn new(global: &GlobalScope, x: f64, y: f64, width: f64, height: f64) -> DomRoot<DOMRect> {
reflect_dom_object(Box::new(DOMRect::new_inherited(x, y, width, height)), reflect_dom_object(
Box::new(DOMRect::new_inherited(x, y, width, height)),
global, global,
DOMRectBinding::Wrap) DOMRectBinding::Wrap,
)
} }
pub fn Constructor(global: &GlobalScope, pub fn Constructor(
global: &GlobalScope,
x: f64, x: f64,
y: f64, y: f64,
width: f64, width: f64,
height: f64) height: f64,
-> Fallible<DomRoot<DOMRect>> { ) -> Fallible<DomRoot<DOMRect>> {
Ok(DOMRect::new(global, x, y, width, height)) Ok(DOMRect::new(global, x, y, width, height))
} }
} }

View file

@ -30,23 +30,27 @@ impl DOMRectReadOnly {
} }
} }
pub fn new(global: &GlobalScope, pub fn new(
global: &GlobalScope,
x: f64, x: f64,
y: f64, y: f64,
width: f64, width: f64,
height: f64) height: f64,
-> DomRoot<DOMRectReadOnly> { ) -> DomRoot<DOMRectReadOnly> {
reflect_dom_object(Box::new(DOMRectReadOnly::new_inherited(x, y, width, height)), reflect_dom_object(
Box::new(DOMRectReadOnly::new_inherited(x, y, width, height)),
global, global,
Wrap) Wrap,
)
} }
pub fn Constructor(global: &GlobalScope, pub fn Constructor(
global: &GlobalScope,
x: f64, x: f64,
y: f64, y: f64,
width: f64, width: f64,
height: f64) height: f64,
-> Fallible<DomRoot<DOMRectReadOnly>> { ) -> Fallible<DomRoot<DOMRectReadOnly>> {
Ok(DOMRectReadOnly::new(global, x, y, width, height)) Ok(DOMRectReadOnly::new(global, x, y, width, height))
} }

View file

@ -28,9 +28,11 @@ impl DOMStringMap {
pub fn new(element: &HTMLElement) -> DomRoot<DOMStringMap> { pub fn new(element: &HTMLElement) -> DomRoot<DOMStringMap> {
let window = window_from_node(element); let window = window_from_node(element);
reflect_dom_object(Box::new(DOMStringMap::new_inherited(element)), reflect_dom_object(
Box::new(DOMStringMap::new_inherited(element)),
&*window, &*window,
DOMStringMapBinding::Wrap) DOMStringMapBinding::Wrap,
)
} }
} }
@ -53,6 +55,10 @@ impl DOMStringMapMethods for DOMStringMap {
// https://html.spec.whatwg.org/multipage/#the-domstringmap-interface:supported-property-names // https://html.spec.whatwg.org/multipage/#the-domstringmap-interface:supported-property-names
fn SupportedPropertyNames(&self) -> Vec<DOMString> { fn SupportedPropertyNames(&self) -> Vec<DOMString> {
self.element.supported_prop_names_custom_attr().iter().cloned().collect() self.element
.supported_prop_names_custom_attr()
.iter()
.cloned()
.collect()
} }
} }

View file

@ -34,9 +34,11 @@ impl DOMTokenList {
pub fn new(element: &Element, local_name: &LocalName) -> DomRoot<DOMTokenList> { pub fn new(element: &Element, local_name: &LocalName) -> DomRoot<DOMTokenList> {
let window = window_from_node(element); let window = window_from_node(element);
reflect_dom_object(Box::new(DOMTokenList::new_inherited(element, local_name.clone())), reflect_dom_object(
Box::new(DOMTokenList::new_inherited(element, local_name.clone())),
&*window, &*window,
DOMTokenListBinding::Wrap) DOMTokenListBinding::Wrap,
)
} }
fn attribute(&self) -> Option<DomRoot<Attr>> { fn attribute(&self) -> Option<DomRoot<Attr>> {
@ -56,16 +58,18 @@ impl DOMTokenList {
impl DOMTokenListMethods for DOMTokenList { impl DOMTokenListMethods for DOMTokenList {
// https://dom.spec.whatwg.org/#dom-domtokenlist-length // https://dom.spec.whatwg.org/#dom-domtokenlist-length
fn Length(&self) -> u32 { fn Length(&self) -> u32 {
self.attribute().map_or(0, |attr| { self.attribute()
attr.value().as_tokens().len() .map_or(0, |attr| attr.value().as_tokens().len()) as u32
}) as u32
} }
// https://dom.spec.whatwg.org/#dom-domtokenlist-item // https://dom.spec.whatwg.org/#dom-domtokenlist-item
fn Item(&self, index: u32) -> Option<DOMString> { fn Item(&self, index: u32) -> Option<DOMString> {
self.attribute().and_then(|attr| { self.attribute().and_then(|attr| {
// FIXME(ajeffrey): Convert directly from Atom to DOMString // FIXME(ajeffrey): Convert directly from Atom to DOMString
attr.value().as_tokens().get(index as usize).map(|token| DOMString::from(&**token)) attr.value()
.as_tokens()
.get(index as usize)
.map(|token| DOMString::from(&**token))
}) })
} }
@ -89,7 +93,8 @@ impl DOMTokenListMethods for DOMTokenList {
atoms.push(token); atoms.push(token);
} }
} }
self.element.set_atomic_tokenlist_attribute(&self.local_name, atoms); self.element
.set_atomic_tokenlist_attribute(&self.local_name, atoms);
Ok(()) Ok(())
} }
@ -98,9 +103,13 @@ impl DOMTokenListMethods for DOMTokenList {
let mut atoms = self.element.get_tokenlist_attribute(&self.local_name); let mut atoms = self.element.get_tokenlist_attribute(&self.local_name);
for token in &tokens { for token in &tokens {
let token = self.check_token_exceptions(&token)?; let token = self.check_token_exceptions(&token)?;
atoms.iter().position(|atom| *atom == token).map(|index| atoms.remove(index)); atoms
.iter()
.position(|atom| *atom == token)
.map(|index| atoms.remove(index));
} }
self.element.set_atomic_tokenlist_attribute(&self.local_name, atoms); self.element
.set_atomic_tokenlist_attribute(&self.local_name, atoms);
Ok(()) Ok(())
} }
@ -113,17 +122,19 @@ impl DOMTokenListMethods for DOMTokenList {
Some(true) => Ok(true), Some(true) => Ok(true),
_ => { _ => {
atoms.remove(index); atoms.remove(index);
self.element.set_atomic_tokenlist_attribute(&self.local_name, atoms); self.element
.set_atomic_tokenlist_attribute(&self.local_name, atoms);
Ok(false) Ok(false)
} },
}, },
None => match force { None => match force {
Some(false) => Ok(false), Some(false) => Ok(false),
_ => { _ => {
atoms.push(token); atoms.push(token);
self.element.set_atomic_tokenlist_attribute(&self.local_name, atoms); self.element
.set_atomic_tokenlist_attribute(&self.local_name, atoms);
Ok(true) Ok(true)
} },
}, },
} }
} }
@ -135,7 +146,8 @@ impl DOMTokenListMethods for DOMTokenList {
// https://dom.spec.whatwg.org/#dom-domtokenlist-value // https://dom.spec.whatwg.org/#dom-domtokenlist-value
fn SetValue(&self, value: DOMString) { fn SetValue(&self, value: DOMString) {
self.element.set_tokenlist_attribute(&self.local_name, value); self.element
.set_tokenlist_attribute(&self.local_name, value);
} }
// https://dom.spec.whatwg.org/#dom-domtokenlist-replace // https://dom.spec.whatwg.org/#dom-domtokenlist-replace
@ -159,7 +171,8 @@ impl DOMTokenListMethods for DOMTokenList {
atoms.remove(pos); atoms.remove(pos);
} }
// Step 5. // Step 5.
self.element.set_atomic_tokenlist_attribute(&self.local_name, atoms); self.element
.set_atomic_tokenlist_attribute(&self.local_name, atoms);
} }
Ok(()) Ok(())
} }

File diff suppressed because it is too large Load diff

Some files were not shown because too many files have changed in this diff Show more