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>(
body_type: BodyType, object: &T,
promise: &Promise) { body_type: BodyType,
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>(
bytes: Vec<u8>, object: &T,
body_type: BodyType, bytes: Vec<u8>,
mime_type: Ref<Vec<u8>>) body_type: BodyType,
-> Fallible<FetchedData> { mime_type: Ref<Vec<u8>>,
) -> 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(
json_text.as_ptr(), cx,
json_text.len() as u32, json_text.as_ptr(),
rval.handle_mut()) { json_text.len() as u32,
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(
bytes: Vec<u8>, root: &GlobalScope,
mime: &[u8]) -> Fallible<FetchedData> { bytes: Vec<u8>,
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_CXX_COMPILER", "cl.exe"); .define("CMAKE_C_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,11 +47,14 @@ 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,
Ok(ConversionResult::Success(v)) => v, rval.handle(),
_ => unreachable!(), (),
}) ) {
Ok(ConversionResult::Success(v)) => v,
_ => unreachable!(),
})
} else if rval.is_string() { } else if rval.is_string() {
EvaluateJSReply::StringValue(String::from(jsstring_to_str(cx, rval.to_string()))) EvaluateJSReply::StringValue(String::from(jsstring_to_str(cx, rval.to_string())))
} else if rval.is_null() { } else if rval.is_null() {
@ -73,85 +75,104 @@ 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(
pipeline: PipelineId, documents: &Documents,
reply: IpcSender<Option<NodeInfo>>) { pipeline: PipelineId,
let info = documents.find_document(pipeline) reply: IpcSender<Option<NodeInfo>>,
) {
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(
pipeline: PipelineId, documents: &Documents,
node_id: &str) pipeline: PipelineId,
-> Option<DomRoot<Node>> { node_id: &str,
documents.find_document(pipeline).and_then(|document| ) -> Option<DomRoot<Node>> {
document.upcast::<Node>().traverse_preorder().find(|candidate| candidate.unique_id() == node_id) documents.find_document(pipeline).and_then(|document| {
) document
.upcast::<Node>()
.traverse_preorder()
.find(|candidate| candidate.unique_id() == node_id)
})
} }
pub fn handle_get_children(documents: &Documents, pub fn handle_get_children(
pipeline: PipelineId, documents: &Documents,
node_id: String, pipeline: PipelineId,
reply: IpcSender<Option<Vec<NodeInfo>>>) { node_id: String,
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(
pipeline: PipelineId, documents: &Documents,
node_id: String, pipeline: PipelineId,
reply: IpcSender<Option<ComputedNodeLayout>>) { node_id: String,
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
display: String::from(computed_style.Display()), .send(Some(ComputedNodeLayout {
position: String::from(computed_style.Position()), display: String::from(computed_style.Display()),
zIndex: String::from(computed_style.ZIndex()), position: String::from(computed_style.Position()),
boxSizing: String::from(computed_style.BoxSizing()), zIndex: String::from(computed_style.ZIndex()),
autoMargins: determine_auto_margins(&window, &*node), boxSizing: String::from(computed_style.BoxSizing()),
marginTop: String::from(computed_style.MarginTop()), autoMargins: determine_auto_margins(&window, &*node),
marginRight: String::from(computed_style.MarginRight()), marginTop: String::from(computed_style.MarginTop()),
marginBottom: String::from(computed_style.MarginBottom()), marginRight: String::from(computed_style.MarginRight()),
marginLeft: String::from(computed_style.MarginLeft()), marginBottom: String::from(computed_style.MarginBottom()),
borderTopWidth: String::from(computed_style.BorderTopWidth()), marginLeft: String::from(computed_style.MarginLeft()),
borderRightWidth: String::from(computed_style.BorderRightWidth()), borderTopWidth: String::from(computed_style.BorderTopWidth()),
borderBottomWidth: String::from(computed_style.BorderBottomWidth()), borderRightWidth: String::from(computed_style.BorderRightWidth()),
borderLeftWidth: String::from(computed_style.BorderLeftWidth()), borderBottomWidth: String::from(computed_style.BorderBottomWidth()),
paddingTop: String::from(computed_style.PaddingTop()), borderLeftWidth: String::from(computed_style.BorderLeftWidth()),
paddingRight: String::from(computed_style.PaddingRight()), paddingTop: String::from(computed_style.PaddingTop()),
paddingBottom: String::from(computed_style.PaddingBottom()), paddingRight: String::from(computed_style.PaddingRight()),
paddingLeft: String::from(computed_style.PaddingLeft()), paddingBottom: String::from(computed_style.PaddingBottom()),
width: width, paddingLeft: String::from(computed_style.PaddingLeft()),
height: height, width: width,
})).unwrap(); height: height,
})).unwrap();
} }
fn determine_auto_margins(window: &Window, node: &Node) -> AutoMargins { fn determine_auto_margins(window: &Window, node: &Node) -> AutoMargins {
@ -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(
message_types: CachedConsoleMessageTypes, _pipeline_id: PipelineId,
reply: IpcSender<Vec<CachedConsoleMessage>>) { message_types: CachedConsoleMessageTypes,
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(
pipeline: PipelineId, documents: &Documents,
node_id: String, pipeline: PipelineId,
modifications: Vec<Modification>) { node_id: String,
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(
pipeline: PipelineId, documents: &Documents,
marker_types: Vec<TimelineMarkerType>, pipeline: PipelineId,
reply: IpcSender<Option<TimelineMarker>>) { marker_types: Vec<TimelineMarkerType>,
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(
pipeline: PipelineId, documents: &Documents,
marker_types: Vec<TimelineMarkerType>) { pipeline: PipelineId,
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(
load: LoadType, &mut self,
request: RequestInit, load: LoadType,
fetch_target: IpcSender<FetchResponseMsg>) { request: RequestInit,
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(
request: RequestInit, &mut self,
fetch_target: IpcSender<FetchResponseMsg>) { request: RequestInit,
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(
ctrl_key: bool, element: &Element,
shift_key: bool, ctrl_key: bool,
alt_key: bool, shift_key: bool,
meta_key: bool, alt_key: bool,
source: ActivationSource) { meta_key: bool,
source: ActivationSource,
) {
// Step 1 // Step 1
if element.click_in_progress() { if element.click_in_progress() {
return; return;
@ -78,23 +80,25 @@ 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(
DOMString::from("click"), &win,
EventBubbles::DoesNotBubble, DOMString::from("click"),
EventCancelable::NotCancelable, EventBubbles::DoesNotBubble,
Some(&win), EventCancelable::NotCancelable,
1, Some(&win),
0, 1,
0, 0,
0, 0,
0, 0,
ctrl_key, 0,
shift_key, ctrl_key,
alt_key, shift_key,
meta_key, alt_key,
0, meta_key,
None, 0,
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(
value: AttrValue, local_name: LocalName,
name: LocalName, value: AttrValue,
namespace: Namespace, name: LocalName,
prefix: Option<Prefix>, namespace: Namespace,
owner: Option<&Element>) prefix: Option<Prefix>,
-> Attr { owner: Option<&Element>,
) -> 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(
local_name: LocalName, window: &Window,
value: AttrValue, local_name: LocalName,
name: LocalName, value: AttrValue,
namespace: Namespace, name: LocalName,
prefix: Option<Prefix>, namespace: Namespace,
owner: Option<&Element>) prefix: Option<Prefix>,
-> DomRoot<Attr> { owner: Option<&Element>,
) -> 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(
@ -90,7 +87,7 @@ impl AudioListener {
node, node,
ParamType::Forward(ParamDir::Z), ParamType::Forward(ParamDir::Z),
AutomationRate::A_rate, AutomationRate::A_rate,
-1., // default value -1., // default value
f32::MIN, // min value f32::MIN, // min value
f32::MAX, // max value f32::MAX, // max value
); );
@ -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,14 +98,16 @@ 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 {
eventtarget: EventTarget::new_inherited(), eventtarget: EventTarget::new_inherited(),
audio_context_impl: ServoMedia::get() audio_context_impl: ServoMedia::get()
.unwrap() .unwrap()
.create_audio_context(options.into()), .create_audio_context(options.into()),
destination: Default::default(), destination: Default::default(),
listener: Default::default(), listener: Default::default(),
in_flight_resume_promises_queue: Default::default(), in_flight_resume_promises_queue: Default::default(),
@ -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(
window, Box::new(BeforeUnloadEvent::new_inherited()),
BeforeUnloadEventBinding::Wrap) window,
BeforeUnloadEventBinding::Wrap,
)
} }
pub fn new(window: &Window, pub fn new(
type_: Atom, window: &Window,
bubbles: EventBubbles, type_: Atom,
cancelable: EventCancelable) -> DomRoot<BeforeUnloadEvent> { bubbles: EventBubbles,
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>(
p: &T, cx: *mut JSContext,
mut rval: MutableHandleObject) { p: &T,
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(
obj, cx,
spec.name.as_ptr() as *const libc::c_char, obj,
value.handle(), spec.name.as_ptr() as *const libc::c_char,
(JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT) as u32)); value.handle(),
(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(
value: HandleValue, cx: *mut JSContext,
option: ()) value: HandleValue,
-> Result<ConversionResult<Finite<T>>, ()> { option: (),
) -> 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(
value: HandleValue, _cx: *mut JSContext,
_config: Self::Config) value: HandleValue,
-> Result<ConversionResult<DomRoot<T>>, ()> { _config: Self::Config,
) -> 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(
value: HandleValue, cx: *mut JSContext,
config: Self::Config) value: HandleValue,
-> Result<ConversionResult<Self>, ()> { config: Self::Config,
) -> 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(
value: HandleValue, cx: *mut JSContext,
null_behavior: StringificationBehavior) value: HandleValue,
-> Result<ConversionResult<DOMString>, ()> { null_behavior: StringificationBehavior,
if null_behavior == StringificationBehavior::Empty && ) -> Result<ConversionResult<DOMString>, ()> {
value.get().is_null() { if null_behavior == StringificationBehavior::Empty && 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(
self.as_ptr() as *const libc::c_char, cx,
self.len() as libc::size_t); self.as_ptr() as *const libc::c_char,
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(
value: HandleValue, cx: *mut JSContext,
_option: ()) value: HandleValue,
-> Result<ConversionResult<ByteString>, ()> { _option: (),
) -> 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(
object: HandleObject, cx: *mut JSContext,
name: &str, object: HandleObject,
mut rval: MutableHandleValue) name: &str,
-> Fallible<()> mut rval: MutableHandleValue,
{ ) -> 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>(
object: HandleObject, cx: *mut JSContext,
name: &str, object: HandleObject,
option: T::Config) name: &str,
-> Fallible<Option<T>> where option: T::Config,
T: FromJSValConvertible ) -> Fallible<Option<T>>
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(
window.get_cx(),
global_object.handle(),
constructor.handle_mut(),
);
} else { } else {
// Step 5 // Step 5
get_constructor_object_from_local_name(definition.local_name.clone(), get_constructor_object_from_local_name(
window.get_cx(), definition.local_name.clone(),
global_object.handle(), window.get_cx(),
constructor.handle_mut()); 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(
cx: *mut JSContext, name: LocalName,
global: HandleObject, cx: *mut JSContext,
rval: MutableHandleObject) global: HandleObject,
-> bool { rval: MutableHandleObject,
) -> 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); }
@ -189,131 +203,131 @@ pub fn get_constructor_object_from_local_name(name: LocalName,
); );
match name { match name {
local_name!("a") => get_constructor!(HTMLAnchorElementBinding), local_name!("a") => get_constructor!(HTMLAnchorElementBinding),
local_name!("abbr") => get_constructor!(HTMLElementBinding), local_name!("abbr") => get_constructor!(HTMLElementBinding),
local_name!("acronym") => get_constructor!(HTMLElementBinding), local_name!("acronym") => get_constructor!(HTMLElementBinding),
local_name!("address") => get_constructor!(HTMLElementBinding), local_name!("address") => get_constructor!(HTMLElementBinding),
local_name!("area") => get_constructor!(HTMLAreaElementBinding), local_name!("area") => get_constructor!(HTMLAreaElementBinding),
local_name!("article") => get_constructor!(HTMLElementBinding), local_name!("article") => get_constructor!(HTMLElementBinding),
local_name!("aside") => get_constructor!(HTMLElementBinding), local_name!("aside") => get_constructor!(HTMLElementBinding),
local_name!("audio") => get_constructor!(HTMLAudioElementBinding), local_name!("audio") => get_constructor!(HTMLAudioElementBinding),
local_name!("b") => get_constructor!(HTMLElementBinding), local_name!("b") => get_constructor!(HTMLElementBinding),
local_name!("base") => get_constructor!(HTMLBaseElementBinding), local_name!("base") => get_constructor!(HTMLBaseElementBinding),
local_name!("bdi") => get_constructor!(HTMLElementBinding), local_name!("bdi") => get_constructor!(HTMLElementBinding),
local_name!("bdo") => get_constructor!(HTMLElementBinding), local_name!("bdo") => get_constructor!(HTMLElementBinding),
local_name!("big") => get_constructor!(HTMLElementBinding), local_name!("big") => get_constructor!(HTMLElementBinding),
local_name!("blockquote") => get_constructor!(HTMLQuoteElementBinding), local_name!("blockquote") => get_constructor!(HTMLQuoteElementBinding),
local_name!("body") => get_constructor!(HTMLBodyElementBinding), local_name!("body") => get_constructor!(HTMLBodyElementBinding),
local_name!("br") => get_constructor!(HTMLBRElementBinding), local_name!("br") => get_constructor!(HTMLBRElementBinding),
local_name!("button") => get_constructor!(HTMLButtonElementBinding), local_name!("button") => get_constructor!(HTMLButtonElementBinding),
local_name!("canvas") => get_constructor!(HTMLCanvasElementBinding), local_name!("canvas") => get_constructor!(HTMLCanvasElementBinding),
local_name!("caption") => get_constructor!(HTMLTableCaptionElementBinding), local_name!("caption") => get_constructor!(HTMLTableCaptionElementBinding),
local_name!("center") => get_constructor!(HTMLElementBinding), local_name!("center") => get_constructor!(HTMLElementBinding),
local_name!("cite") => get_constructor!(HTMLElementBinding), local_name!("cite") => get_constructor!(HTMLElementBinding),
local_name!("code") => get_constructor!(HTMLElementBinding), local_name!("code") => get_constructor!(HTMLElementBinding),
local_name!("col") => get_constructor!(HTMLTableColElementBinding), local_name!("col") => get_constructor!(HTMLTableColElementBinding),
local_name!("colgroup") => get_constructor!(HTMLTableColElementBinding), local_name!("colgroup") => get_constructor!(HTMLTableColElementBinding),
local_name!("data") => get_constructor!(HTMLDataElementBinding), local_name!("data") => get_constructor!(HTMLDataElementBinding),
local_name!("datalist") => get_constructor!(HTMLDataListElementBinding), local_name!("datalist") => get_constructor!(HTMLDataListElementBinding),
local_name!("dd") => get_constructor!(HTMLElementBinding), local_name!("dd") => get_constructor!(HTMLElementBinding),
local_name!("del") => get_constructor!(HTMLModElementBinding), local_name!("del") => get_constructor!(HTMLModElementBinding),
local_name!("details") => get_constructor!(HTMLDetailsElementBinding), local_name!("details") => get_constructor!(HTMLDetailsElementBinding),
local_name!("dfn") => get_constructor!(HTMLElementBinding), local_name!("dfn") => get_constructor!(HTMLElementBinding),
local_name!("dialog") => get_constructor!(HTMLDialogElementBinding), local_name!("dialog") => get_constructor!(HTMLDialogElementBinding),
local_name!("dir") => get_constructor!(HTMLDirectoryElementBinding), local_name!("dir") => get_constructor!(HTMLDirectoryElementBinding),
local_name!("div") => get_constructor!(HTMLDivElementBinding), local_name!("div") => get_constructor!(HTMLDivElementBinding),
local_name!("dl") => get_constructor!(HTMLDListElementBinding), local_name!("dl") => get_constructor!(HTMLDListElementBinding),
local_name!("dt") => get_constructor!(HTMLElementBinding), local_name!("dt") => get_constructor!(HTMLElementBinding),
local_name!("em") => get_constructor!(HTMLElementBinding), local_name!("em") => get_constructor!(HTMLElementBinding),
local_name!("embed") => get_constructor!(HTMLEmbedElementBinding), local_name!("embed") => get_constructor!(HTMLEmbedElementBinding),
local_name!("fieldset") => get_constructor!(HTMLFieldSetElementBinding), local_name!("fieldset") => get_constructor!(HTMLFieldSetElementBinding),
local_name!("figcaption") => get_constructor!(HTMLElementBinding), local_name!("figcaption") => get_constructor!(HTMLElementBinding),
local_name!("figure") => get_constructor!(HTMLElementBinding), local_name!("figure") => get_constructor!(HTMLElementBinding),
local_name!("font") => get_constructor!(HTMLFontElementBinding), local_name!("font") => get_constructor!(HTMLFontElementBinding),
local_name!("footer") => get_constructor!(HTMLElementBinding), local_name!("footer") => get_constructor!(HTMLElementBinding),
local_name!("form") => get_constructor!(HTMLFormElementBinding), local_name!("form") => get_constructor!(HTMLFormElementBinding),
local_name!("frame") => get_constructor!(HTMLFrameElementBinding), local_name!("frame") => get_constructor!(HTMLFrameElementBinding),
local_name!("frameset") => get_constructor!(HTMLFrameSetElementBinding), local_name!("frameset") => get_constructor!(HTMLFrameSetElementBinding),
local_name!("h1") => get_constructor!(HTMLHeadingElementBinding), local_name!("h1") => get_constructor!(HTMLHeadingElementBinding),
local_name!("h2") => get_constructor!(HTMLHeadingElementBinding), local_name!("h2") => get_constructor!(HTMLHeadingElementBinding),
local_name!("h3") => get_constructor!(HTMLHeadingElementBinding), local_name!("h3") => get_constructor!(HTMLHeadingElementBinding),
local_name!("h4") => get_constructor!(HTMLHeadingElementBinding), local_name!("h4") => get_constructor!(HTMLHeadingElementBinding),
local_name!("h5") => get_constructor!(HTMLHeadingElementBinding), local_name!("h5") => get_constructor!(HTMLHeadingElementBinding),
local_name!("h6") => get_constructor!(HTMLHeadingElementBinding), local_name!("h6") => get_constructor!(HTMLHeadingElementBinding),
local_name!("head") => get_constructor!(HTMLHeadElementBinding), local_name!("head") => get_constructor!(HTMLHeadElementBinding),
local_name!("header") => get_constructor!(HTMLElementBinding), local_name!("header") => get_constructor!(HTMLElementBinding),
local_name!("hgroup") => get_constructor!(HTMLElementBinding), local_name!("hgroup") => get_constructor!(HTMLElementBinding),
local_name!("hr") => get_constructor!(HTMLHRElementBinding), local_name!("hr") => get_constructor!(HTMLHRElementBinding),
local_name!("html") => get_constructor!(HTMLHtmlElementBinding), local_name!("html") => get_constructor!(HTMLHtmlElementBinding),
local_name!("i") => get_constructor!(HTMLElementBinding), local_name!("i") => get_constructor!(HTMLElementBinding),
local_name!("iframe") => get_constructor!(HTMLIFrameElementBinding), local_name!("iframe") => get_constructor!(HTMLIFrameElementBinding),
local_name!("img") => get_constructor!(HTMLImageElementBinding), local_name!("img") => get_constructor!(HTMLImageElementBinding),
local_name!("input") => get_constructor!(HTMLInputElementBinding), local_name!("input") => get_constructor!(HTMLInputElementBinding),
local_name!("ins") => get_constructor!(HTMLModElementBinding), local_name!("ins") => get_constructor!(HTMLModElementBinding),
local_name!("kbd") => get_constructor!(HTMLElementBinding), local_name!("kbd") => get_constructor!(HTMLElementBinding),
local_name!("label") => get_constructor!(HTMLLabelElementBinding), local_name!("label") => get_constructor!(HTMLLabelElementBinding),
local_name!("legend") => get_constructor!(HTMLLegendElementBinding), local_name!("legend") => get_constructor!(HTMLLegendElementBinding),
local_name!("li") => get_constructor!(HTMLLIElementBinding), local_name!("li") => get_constructor!(HTMLLIElementBinding),
local_name!("link") => get_constructor!(HTMLLinkElementBinding), local_name!("link") => get_constructor!(HTMLLinkElementBinding),
local_name!("listing") => get_constructor!(HTMLPreElementBinding), local_name!("listing") => get_constructor!(HTMLPreElementBinding),
local_name!("main") => get_constructor!(HTMLElementBinding), local_name!("main") => get_constructor!(HTMLElementBinding),
local_name!("map") => get_constructor!(HTMLMapElementBinding), local_name!("map") => get_constructor!(HTMLMapElementBinding),
local_name!("mark") => get_constructor!(HTMLElementBinding), local_name!("mark") => get_constructor!(HTMLElementBinding),
local_name!("marquee") => get_constructor!(HTMLElementBinding), local_name!("marquee") => get_constructor!(HTMLElementBinding),
local_name!("meta") => get_constructor!(HTMLMetaElementBinding), local_name!("meta") => get_constructor!(HTMLMetaElementBinding),
local_name!("meter") => get_constructor!(HTMLMeterElementBinding), local_name!("meter") => get_constructor!(HTMLMeterElementBinding),
local_name!("nav") => get_constructor!(HTMLElementBinding), local_name!("nav") => get_constructor!(HTMLElementBinding),
local_name!("nobr") => get_constructor!(HTMLElementBinding), local_name!("nobr") => get_constructor!(HTMLElementBinding),
local_name!("noframes") => get_constructor!(HTMLElementBinding), local_name!("noframes") => get_constructor!(HTMLElementBinding),
local_name!("noscript") => get_constructor!(HTMLElementBinding), local_name!("noscript") => get_constructor!(HTMLElementBinding),
local_name!("object") => get_constructor!(HTMLObjectElementBinding), local_name!("object") => get_constructor!(HTMLObjectElementBinding),
local_name!("ol") => get_constructor!(HTMLOListElementBinding), local_name!("ol") => get_constructor!(HTMLOListElementBinding),
local_name!("optgroup") => get_constructor!(HTMLOptGroupElementBinding), local_name!("optgroup") => get_constructor!(HTMLOptGroupElementBinding),
local_name!("option") => get_constructor!(HTMLOptionElementBinding), local_name!("option") => get_constructor!(HTMLOptionElementBinding),
local_name!("output") => get_constructor!(HTMLOutputElementBinding), local_name!("output") => get_constructor!(HTMLOutputElementBinding),
local_name!("p") => get_constructor!(HTMLParagraphElementBinding), local_name!("p") => get_constructor!(HTMLParagraphElementBinding),
local_name!("param") => get_constructor!(HTMLParamElementBinding), local_name!("param") => get_constructor!(HTMLParamElementBinding),
local_name!("plaintext") => get_constructor!(HTMLPreElementBinding), local_name!("plaintext") => get_constructor!(HTMLPreElementBinding),
local_name!("pre") => get_constructor!(HTMLPreElementBinding), local_name!("pre") => get_constructor!(HTMLPreElementBinding),
local_name!("progress") => get_constructor!(HTMLProgressElementBinding), local_name!("progress") => get_constructor!(HTMLProgressElementBinding),
local_name!("q") => get_constructor!(HTMLQuoteElementBinding), local_name!("q") => get_constructor!(HTMLQuoteElementBinding),
local_name!("rp") => get_constructor!(HTMLElementBinding), local_name!("rp") => get_constructor!(HTMLElementBinding),
local_name!("rt") => get_constructor!(HTMLElementBinding), local_name!("rt") => get_constructor!(HTMLElementBinding),
local_name!("ruby") => get_constructor!(HTMLElementBinding), local_name!("ruby") => get_constructor!(HTMLElementBinding),
local_name!("s") => get_constructor!(HTMLElementBinding), local_name!("s") => get_constructor!(HTMLElementBinding),
local_name!("samp") => get_constructor!(HTMLElementBinding), local_name!("samp") => get_constructor!(HTMLElementBinding),
local_name!("script") => get_constructor!(HTMLScriptElementBinding), local_name!("script") => get_constructor!(HTMLScriptElementBinding),
local_name!("section") => get_constructor!(HTMLElementBinding), local_name!("section") => get_constructor!(HTMLElementBinding),
local_name!("select") => get_constructor!(HTMLSelectElementBinding), local_name!("select") => get_constructor!(HTMLSelectElementBinding),
local_name!("small") => get_constructor!(HTMLElementBinding), local_name!("small") => get_constructor!(HTMLElementBinding),
local_name!("source") => get_constructor!(HTMLSourceElementBinding), local_name!("source") => get_constructor!(HTMLSourceElementBinding),
local_name!("span") => get_constructor!(HTMLSpanElementBinding), local_name!("span") => get_constructor!(HTMLSpanElementBinding),
local_name!("strike") => get_constructor!(HTMLElementBinding), local_name!("strike") => get_constructor!(HTMLElementBinding),
local_name!("strong") => get_constructor!(HTMLElementBinding), local_name!("strong") => get_constructor!(HTMLElementBinding),
local_name!("style") => get_constructor!(HTMLStyleElementBinding), local_name!("style") => get_constructor!(HTMLStyleElementBinding),
local_name!("sub") => get_constructor!(HTMLElementBinding), local_name!("sub") => get_constructor!(HTMLElementBinding),
local_name!("summary") => get_constructor!(HTMLElementBinding), local_name!("summary") => get_constructor!(HTMLElementBinding),
local_name!("sup") => get_constructor!(HTMLElementBinding), local_name!("sup") => get_constructor!(HTMLElementBinding),
local_name!("table") => get_constructor!(HTMLTableElementBinding), local_name!("table") => get_constructor!(HTMLTableElementBinding),
local_name!("tbody") => get_constructor!(HTMLTableSectionElementBinding), local_name!("tbody") => get_constructor!(HTMLTableSectionElementBinding),
local_name!("td") => get_constructor!(HTMLTableDataCellElementBinding), local_name!("td") => get_constructor!(HTMLTableDataCellElementBinding),
local_name!("template") => get_constructor!(HTMLTemplateElementBinding), local_name!("template") => get_constructor!(HTMLTemplateElementBinding),
local_name!("textarea") => get_constructor!(HTMLTextAreaElementBinding), local_name!("textarea") => get_constructor!(HTMLTextAreaElementBinding),
local_name!("tfoot") => get_constructor!(HTMLTableSectionElementBinding), local_name!("tfoot") => get_constructor!(HTMLTableSectionElementBinding),
local_name!("th") => get_constructor!(HTMLTableHeaderCellElementBinding), local_name!("th") => get_constructor!(HTMLTableHeaderCellElementBinding),
local_name!("thead") => get_constructor!(HTMLTableSectionElementBinding), local_name!("thead") => get_constructor!(HTMLTableSectionElementBinding),
local_name!("time") => get_constructor!(HTMLTimeElementBinding), local_name!("time") => get_constructor!(HTMLTimeElementBinding),
local_name!("title") => get_constructor!(HTMLTitleElementBinding), local_name!("title") => get_constructor!(HTMLTitleElementBinding),
local_name!("tr") => get_constructor!(HTMLTableRowElementBinding), local_name!("tr") => get_constructor!(HTMLTableRowElementBinding),
local_name!("tt") => get_constructor!(HTMLElementBinding), local_name!("tt") => get_constructor!(HTMLElementBinding),
local_name!("track") => get_constructor!(HTMLTrackElementBinding), local_name!("track") => get_constructor!(HTMLTrackElementBinding),
local_name!("u") => get_constructor!(HTMLElementBinding), local_name!("u") => get_constructor!(HTMLElementBinding),
local_name!("ul") => get_constructor!(HTMLUListElementBinding), local_name!("ul") => get_constructor!(HTMLUListElementBinding),
local_name!("var") => get_constructor!(HTMLElementBinding), local_name!("var") => get_constructor!(HTMLElementBinding),
local_name!("video") => get_constructor!(HTMLVideoElementBinding), local_name!("video") => get_constructor!(HTMLVideoElementBinding),
local_name!("wbr") => get_constructor!(HTMLElementBinding), local_name!("wbr") => get_constructor!(HTMLElementBinding),
local_name!("xmp") => get_constructor!(HTMLPreElementBinding), local_name!("xmp") => get_constructor!(HTMLPreElementBinding),
_ => false, _ => false,
} }
} }

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(
string_rep: &'static [u8], constructor_behavior: &'static InterfaceConstructorBehavior,
proto_id: PrototypeList::ID, string_rep: &'static [u8],
proto_depth: u16) proto_id: PrototypeList::ID,
-> NonCallbackInterfaceObjectClass { proto_depth: u16,
) -> 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,27 +123,29 @@ 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(
cx: *mut JSContext, cx: *mut JSContext,
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(
class, cx,
ptr::null_mut(), class,
OnNewGlobalHookOption::DontFireOnNewGlobalHook, ptr::null_mut(),
&options)); OnNewGlobalHookOption::DontFireOnNewGlobalHook,
&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
@ -162,11 +163,12 @@ pub unsafe fn create_global_object(
/// Create and define the interface object of a callback interface. /// Create and define the interface object of a callback interface.
pub unsafe fn create_callback_interface_object( pub unsafe fn create_callback_interface_object(
cx: *mut JSContext, cx: *mut JSContext,
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());
@ -177,15 +179,24 @@ pub unsafe fn create_callback_interface_object(
/// Create the interface prototype object of a non-callback interface. /// Create the interface prototype object of a non-callback interface.
pub unsafe fn create_interface_prototype_object( pub unsafe fn create_interface_prototype_object(
cx: *mut JSContext, cx: *mut JSContext,
proto: HandleObject, proto: HandleObject,
class: &'static JSClass, class: &'static JSClass,
regular_methods: &[Guard<&'static [JSFunctionSpec]>], regular_methods: &[Guard<&'static [JSFunctionSpec]>],
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,32 +207,43 @@ 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
))
} }
} }
/// Create and define the interface object of a non-callback interface. /// Create and define the interface object of a non-callback interface.
pub unsafe fn create_noncallback_interface_object( pub unsafe fn create_noncallback_interface_object(
cx: *mut JSContext, cx: *mut JSContext,
global: HandleObject, global: HandleObject,
proto: HandleObject, proto: HandleObject,
class: &'static NonCallbackInterfaceObjectClass, class: &'static NonCallbackInterfaceObjectClass,
static_methods: &[Guard<&'static [JSFunctionSpec]>], static_methods: &[Guard<&'static [JSFunctionSpec]>],
static_properties: &[Guard<&'static [JSPropertySpec]>], static_properties: &[Guard<&'static [JSPropertySpec]>],
constants: &[Guard<&[ConstantSpec]>], constants: &[Guard<&[ConstantSpec]>],
interface_prototype_object: HandleObject, interface_prototype_object: HandleObject,
name: &[u8], name: &[u8],
length: u32, length: u32,
rval: MutableHandleObject) { rval: MutableHandleObject,
create_object(cx, ) {
proto, create_object(
class.as_jsclass(), cx,
static_methods, proto,
static_properties, class.as_jsclass(),
constants, static_methods,
rval); static_properties,
assert!(JS_LinkConstructorAndPrototype(cx, rval.handle(), interface_prototype_object)); constants,
rval,
);
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());
@ -229,29 +251,34 @@ pub unsafe fn create_noncallback_interface_object(
/// Create and define the named constructors of a non-callback interface. /// Create and define the named constructors of a non-callback interface.
pub unsafe fn create_named_constructors( 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(
Some(native), cx,
arity, Some(native),
JSFUN_CONSTRUCTOR, arity,
name.as_ptr() as *const libc::c_char); JSFUN_CONSTRUCTOR,
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(
constructor.handle(), cx,
b"prototype\0".as_ptr() as *const libc::c_char, constructor.handle(),
interface_prototype_object, b"prototype\0".as_ptr() as *const libc::c_char,
(JSPROP_PERMANENT | JSPROP_READONLY) as u32)); interface_prototype_object,
(JSPROP_PERMANENT | JSPROP_READONLY) as u32
));
define_on_global_object(cx, global, name, constructor.handle()); define_on_global_object(cx, global, name, constructor.handle());
} }
@ -259,13 +286,14 @@ pub unsafe fn create_named_constructors(
/// Create a new object with a unique type. /// Create a new object with a unique type.
pub unsafe fn create_object( pub unsafe fn create_object(
cx: *mut JSContext, cx: *mut JSContext,
proto: HandleObject, proto: HandleObject,
class: &'static JSClass, class: &'static JSClass,
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);
@ -275,9 +303,10 @@ pub unsafe fn create_object(
/// Conditionally define constants on an object. /// Conditionally define constants on an 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);
@ -287,9 +316,10 @@ pub unsafe fn define_guarded_constants(
/// Conditionally define methods on an object. /// Conditionally define methods on an object.
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();
@ -299,9 +329,10 @@ pub unsafe fn define_guarded_methods(
/// Conditionally define properties on an object. /// Conditionally define properties on an object.
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();
@ -320,16 +351,19 @@ pub unsafe fn is_exposed_in(object: HandleObject, globals: Globals) -> bool {
/// Define a property with a given name on the global object. Should be called /// Define a property with a given name on the global object. Should be called
/// through the resolve hook. /// through the resolve hook.
pub unsafe fn define_on_global_object( 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(
global, cx,
name.as_ptr() as *const libc::c_char, global,
obj, name.as_ptr() as *const libc::c_char,
JSPROP_RESOLVING)); obj,
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(
obj: RawHandleObject, cx: *mut JSContext,
_is_to_source: bool) obj: RawHandleObject,
-> *mut JSString { _is_to_source: bool,
) -> *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(
obj: RawHandleObject, cx: *mut JSContext,
value: RawMutableHandleValue, obj: RawHandleObject,
rval: *mut bool) -> bool { value: RawMutableHandleValue,
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,
} }
} }
@ -376,10 +413,10 @@ unsafe extern "C" fn has_instance_hook(cx: *mut JSContext,
/// Return whether a value is an instance of a given prototype. /// Return whether a value is an instance of a given prototype.
/// <http://heycam.github.io/webidl/#es-interface-hasinstance> /// <http://heycam.github.io/webidl/#es-interface-hasinstance>
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);
@ -422,9 +461,10 @@ 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,35 +485,39 @@ 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(
obj, cx,
b"name\0".as_ptr() as *const libc::c_char, obj,
name.handle().into(), b"name\0".as_ptr() as *const libc::c_char,
JSPROP_READONLY as u32)); name.handle().into(),
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(
obj, cx,
b"length\0".as_ptr() as *const libc::c_char, obj,
length, b"length\0".as_ptr() as *const libc::c_char,
JSPROP_READONLY as u32)); length,
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
} }
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(
type_: IteratorType, iterable: &T,
wrap: unsafe fn(*mut JSContext, &GlobalScope, Box<IterableIterator<T>>) type_: IteratorType,
-> DomRoot<Self>) -> DomRoot<Self> { wrap: unsafe fn(*mut JSContext, &GlobalScope, Box<IterableIterator<T>>) -> 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(
mut result: MutableHandleObject, cx: *mut JSContext,
done: bool, mut result: MutableHandleObject,
value: HandleValue) -> Fallible<()> { done: bool,
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(
mut result: MutableHandleObject, cx: *mut JSContext,
key: HandleValue, mut result: MutableHandleObject,
value: HandleValue) -> Fallible<()> { key: HandleValue,
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(
.into_iter() vec![key, value]
.map(|handle| RootedTraceableBox::from_box(Heap::boxed(handle.get()))) .into_iter()
.collect()); .map(|handle| RootedTraceableBox::from_box(Heap::boxed(handle.get())))
.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
C: Clone, T: FromJSValConvertible<Config = C>,
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(
js_object.handle(), cx,
key.as_ptr(), js_object.handle(),
key.len(), key.as_ptr(),
js_value.handle(), key.len(),
JSPROP_ENUMERATE as u32)); js_value.handle(),
JSPROP_ENUMERATE as u32
));
} }
rval.set(ObjectValue(js_object.handle().get())); rval.set(ObjectValue(js_object.handle().get()));

View file

@ -30,13 +30,14 @@ impl NamespaceObjectClass {
/// Create a new namespace object. /// Create a new namespace object.
pub unsafe fn create_namespace_object( pub unsafe fn create_namespace_object(
cx: *mut JSContext, cx: *mut JSContext,
global: HandleObject, global: HandleObject,
proto: HandleObject, proto: HandleObject,
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(
object: RawHandleObject, cx: *mut JSContext,
id: RawHandleId) object: RawHandleObject,
-> DOMProxyShadowsResult { id: RawHandleId,
) -> 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(
proxy: RawHandleObject, cx: *mut JSContext,
id: RawHandleId, proxy: RawHandleObject,
desc: RawMutableHandle<PropertyDescriptor>) id: RawHandleId,
-> bool { desc: RawMutableHandle<PropertyDescriptor>,
) -> 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(
proxy: RawHandleObject, cx: *mut JSContext,
id: RawHandleId, proxy: RawHandleObject,
desc: RawHandle<PropertyDescriptor>, id: RawHandleId,
result: *mut ObjectOpResult) desc: RawHandle<PropertyDescriptor>,
-> bool { result: *mut ObjectOpResult,
) -> 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(
proxy: RawHandleObject, cx: *mut JSContext,
id: RawHandleId, proxy: RawHandleObject,
bp: *mut ObjectOpResult) id: RawHandleId,
-> bool { bp: *mut ObjectOpResult,
) -> 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(
_proxy: RawHandleObject, _cx: *mut JSContext,
result: *mut ObjectOpResult) _proxy: RawHandleObject,
-> bool { result: *mut ObjectOpResult,
) -> 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(
_proxy: RawHandleObject, _cx: *mut JSContext,
succeeded: *mut bool) _proxy: RawHandleObject,
-> bool { succeeded: *mut 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(
proxy: RawHandleObject, _: *mut JSContext,
is_ordinary: *mut bool, proxy: RawHandleObject,
proto: RawMutableHandleObject) is_ordinary: *mut bool,
-> bool { proto: RawMutableHandleObject,
) -> 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(
obj: *mut JSObject, mut desc: MutableHandle<PropertyDescriptor>,
attrs: u32) { obj: *mut JSObject,
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 {
mod dummy { // Attributes dont apply through the macro. // 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

@ -14,16 +14,16 @@ use std::default::Default;
/// Create the reflector for a new DOM object and yield ownership to the /// Create the reflector for a new DOM object and yield ownership to the
/// reflector. /// reflector.
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()))
}
} }
} }
@ -530,18 +525,14 @@ 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,13 +86,15 @@ 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| {
.iter() stack
.rev() .borrow()
.find(|entry| entry.kind == StackEntryKind::Entry) .iter()
.map(|entry| DomRoot::from_ref(&*entry.global)) .rev()
}).unwrap() .find(|entry| entry.kind == StackEntryKind::Entry)
.map(|entry| DomRoot::from_ref(&*entry.global))
}).unwrap()
} }
/// RAII struct that pushes and pops entries from the script settings stack. /// RAII struct that pushes and pops entries from the script settings stack.
@ -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,8 +174,9 @@ 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
.last() .borrow()
.map(|entry| DomRoot::from_ref(&*entry.global)) .last()
.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)
} }
} }
@ -541,7 +538,7 @@ fn parse_month_component(value: &str) -> Result<(u32, u32), ()> {
// Step 4, 5 // Step 4, 5
let month_int = month.parse::<u32>().map_err(|_| ())?; let month_int = month.parse::<u32>().map_err(|_| ())?;
if month.len() != 2 || month_int > 12 || month_int < 1 { if month.len() != 2 || month_int > 12 || month_int < 1 {
return Err(()); return Err(());
} }
@ -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
@ -624,7 +621,7 @@ fn parse_time_component(value: &str) -> Result<(u32, u32, f32), ()> {
} }
/// https://html.spec.whatwg.org/multipage/#parse-a-local-date-and-time-string /// https://html.spec.whatwg.org/multipage/#parse-a-local-date-and-time-string
fn parse_local_date_and_time_string(value: &str) -> Result<((u32, u32, u32), (u32, u32, f32)), ()> { fn parse_local_date_and_time_string(value: &str) -> Result<((u32, u32, u32), (u32, u32, f32)), ()> {
// Step 1, 2, 4 // Step 1, 2, 4
let mut iterator = if value.contains('T') { let mut iterator = if value.contains('T') {
value.split('T') value.split('T')
@ -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,35 +47,39 @@ 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(
assert!(JS_ReadUint32Pair(r, &mut high as *mut u32, &mut low as *mut u32)); r,
return (low << high) as usize; &mut high as *mut u32,
&mut low as *mut u32
));
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(
assert!(JS_ReadUint32Pair(r, &mut length as *mut u32, &mut zero as *mut u32)); r,
return length as usize; &mut length as *mut u32,
&mut zero as *mut u32
));
return length as usize;
} }
struct StructuredCloneWriter { struct StructuredCloneWriter {
@ -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(
r: *mut JSStructuredCloneReader, cx: *mut JSContext,
sc_holder: &mut StructuredCloneHolder) r: *mut JSStructuredCloneReader,
-> *mut JSObject { sc_holder: &mut StructuredCloneHolder,
) -> *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(
r: *mut JSStructuredCloneReader, cx: *mut JSContext,
tag: u32, r: *mut JSStructuredCloneReader,
_data: u32, tag: u32,
closure: *mut raw::c_void) _data: u32,
-> *mut JSObject { closure: *mut raw::c_void,
assert!(tag < StructuredCloneTags::Max as u32, "tag should be lower than StructuredCloneTags::Max"); ) -> *mut JSObject {
assert!(tag > StructuredCloneTags::Min as u32, "tag should be higher than StructuredCloneTags::Min"); assert!(
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(
w: *mut JSStructuredCloneWriter, _cx: *mut JSContext,
obj: RawHandleObject, w: *mut JSStructuredCloneWriter,
_closure: *mut raw::c_void) obj: RawHandleObject,
-> bool { _closure: *mut raw::c_void,
) -> 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(
_r: *mut JSStructuredCloneReader, _cx: *mut JSContext,
_tag: u32, _r: *mut JSStructuredCloneReader,
_content: *mut raw::c_void, _tag: u32,
_extra_data: u64, _content: *mut raw::c_void,
_closure: *mut raw::c_void, _extra_data: u64,
_return_object: RawMutableHandleObject) _closure: *mut raw::c_void,
-> bool { _return_object: RawMutableHandleObject,
) -> bool {
false false
} }
unsafe extern "C" fn write_transfer_callback(_cx: *mut JSContext, unsafe extern "C" fn write_transfer_callback(
_obj: RawHandleObject, _cx: *mut JSContext,
_closure: *mut raw::c_void, _obj: RawHandleObject,
_tag: *mut u32, _closure: *mut raw::c_void,
_ownership: *mut TransferableOwnership, _tag: *mut u32,
_content: *mut *mut raw::c_void, _ownership: *mut TransferableOwnership,
_extra_data: *mut u64) _content: *mut *mut raw::c_void,
-> bool { _extra_data: *mut u64,
) -> bool {
false false
} }
unsafe extern "C" fn free_transfer_callback(_tag: u32, unsafe extern "C" fn free_transfer_callback(
_ownership: TransferableOwnership, _tag: u32,
_content: *mut raw::c_void, _ownership: TransferableOwnership,
_extra_data: u64, _content: *mut raw::c_void,
_closure: *mut raw::c_void) { _extra_data: u64,
_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(
message, cx,
scdata, message,
StructuredCloneScope::DifferentProcess, scdata,
policy, StructuredCloneScope::DifferentProcess,
&STRUCTURED_CLONE_CALLBACKS, policy,
ptr::null_mut(), &STRUCTURED_CLONE_CALLBACKS,
HandleValue::undefined()); ptr::null_mut(),
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(
scdata, cx,
JS_STRUCTURED_CLONE_VERSION, scdata,
StructuredCloneScope::DifferentProcess, JS_STRUCTURED_CLONE_VERSION,
rval, StructuredCloneScope::DifferentProcess,
&STRUCTURED_CLONE_CALLBACKS, rval,
sc_holder_ptr as *mut raw::c_void)); &STRUCTURED_CLONE_CALLBACKS,
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(
val.ptr.get() as *mut _, tracer,
GCTraceKindToAscii(val.get().trace_kind())); val.ptr.get() as *mut _,
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(
obj.ptr.get() as *mut _, tracer,
GCTraceKindToAscii(TraceKind::Object)); obj.ptr.get() as *mut _,
GCTraceKindToAscii(TraceKind::Object),
);
} }
} }
@ -295,9 +299,10 @@ 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
V: JSTraceable, K: Hash + Eq + JSTraceable,
S: BuildHasher, V: JSTraceable,
S: BuildHasher,
{ {
#[inline] #[inline]
unsafe fn trace(&self, trc: *mut JSTracer) { unsafe fn trace(&self, trc: *mut JSTracer) {
@ -309,8 +314,9 @@ 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
S: BuildHasher, T: Hash + Eq + JSTraceable,
S: BuildHasher,
{ {
#[inline] #[inline]
unsafe fn trace(&self, trc: *mut JSTracer) { unsafe fn trace(&self, trc: *mut JSTracer) {
@ -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,34 +708,26 @@ 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() Some(idx) => idx,
.rposition(|x| *x == traceable) { None => unreachable!(),
Some(idx) => idx, };
None => unreachable!(),
};
traceables.set.remove(idx); traceables.set.remove(idx);
}); });
} }
@ -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,16 +803,14 @@ 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,
{ {
pub fn handle(&self) -> Handle<T> { pub fn handle(&self) -> Handle<T> {
unsafe { Handle::from_raw((*self.ptr).handle()) } unsafe { Handle::from_raw((*self.ptr).handle()) }
@ -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(
proxy: HandleObject, cx: *mut JSContext,
receiver: HandleValue, proxy: HandleObject,
id: HandleId, receiver: HandleValue,
found: *mut bool, id: HandleId,
vp: MutableHandleValue) found: *mut bool,
-> bool { vp: MutableHandleValue,
) -> 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>(
v: HandleValue, cx: *mut JSContext,
pairs: &'a [(&'static str, T)]) v: HandleValue,
-> Result<(Option<&'a T>, DOMString), ()> { pairs: &'a [(&'static str, T)],
) -> 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(
object: HandleObject, cx: *mut JSContext,
property: &str, object: HandleObject,
rval: MutableHandleValue) property: &str,
-> Result<bool, ()> { rval: MutableHandleValue,
fn has_property(cx: *mut JSContext, ) -> Result<bool, ()> {
object: HandleObject, fn has_property(
property: &CString, cx: *mut JSContext,
found: &mut bool) object: HandleObject,
-> bool { property: &CString,
found: &mut 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(
object: HandleObject, cx: *mut JSContext,
property: &CString, object: HandleObject,
value: MutableHandleValue) property: &CString,
-> bool { value: MutableHandleValue,
) -> 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(
object: HandleObject, cx: *mut JSContext,
property: &str, object: HandleObject,
value: HandleValue) property: &str,
-> Result<(), ()> { value: HandleValue,
) -> 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(
proxy: HandleObject, cx: *mut JSContext,
id: HandleId, proxy: HandleObject,
found: &mut bool) id: HandleId,
-> bool { found: &mut 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(
"prototype", tracer,
&*(proto as *const *mut JSObject as *const Heap<*mut JSObject>)); "prototype",
&*(proto as *const *mut JSObject as *const Heap<*mut JSObject>),
);
} }
} }
} }
@ -343,11 +356,11 @@ pub unsafe extern "C" fn enumerate_global(cx: *mut JSContext, obj: RawHandleObje
/// Resolve a lazy global property, for interface objects and named constructors. /// Resolve a lazy global property, for interface objects and named constructors.
pub unsafe extern "C" fn resolve_global( 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(
_existing: RawHandleObject, cx: *mut JSContext,
obj: RawHandleObject) _existing: RawHandleObject,
-> *mut JSObject { obj: RawHandleObject,
) -> *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(
_scope: RawHandleObject, cx: *mut JSContext,
obj: RawHandleObject, _scope: RawHandleObject,
_object_passed_to_wrap: RawHandleObject, obj: RawHandleObject,
rval: RawMutableHandleObject) { _object_passed_to_wrap: RawHandleObject,
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(
object: HandleObject, cx: *mut JSContext,
id: HandleId, object: HandleObject,
bp: *mut ObjectOpResult) id: HandleId,
-> bool { bp: *mut ObjectOpResult,
) -> bool {
JS_DeletePropertyById(cx, object, id, bp) JS_DeletePropertyById(cx, object, id, bp)
} }
unsafe fn generic_call(cx: *mut JSContext, unsafe fn generic_call(
argc: libc::c_uint, cx: *mut JSContext,
vp: *mut JSVal, argc: libc::c_uint,
is_lenient: bool, vp: *mut JSVal,
call: unsafe extern fn(*const JSJitInfo, *mut JSContext, is_lenient: bool,
RawHandleObject, *mut libc::c_void, u32, call: unsafe extern "C" fn(
*mut JSVal) *const JSJitInfo,
-> bool) *mut JSContext,
-> bool { RawHandleObject,
*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(
argc: libc::c_uint, cx: *mut JSContext,
vp: *mut JSVal) argc: libc::c_uint,
-> bool { vp: *mut JSVal,
) -> 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(
argc: libc::c_uint, cx: *mut JSContext,
vp: *mut JSVal) argc: libc::c_uint,
-> bool { vp: *mut JSVal,
) -> 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(
argc: libc::c_uint, cx: *mut JSContext,
vp: *mut JSVal) argc: libc::c_uint,
-> bool { vp: *mut JSVal,
) -> 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(
cx: *mut JSContext, info: *const JSJitInfo,
handle: RawHandleObject, cx: *mut JSContext,
this: *mut libc::c_void, handle: RawHandleObject,
argc: u32, this: *mut libc::c_void,
vp: *mut JSVal) argc: u32,
-> bool { vp: *mut JSVal,
) -> bool {
if !CallJitSetterOp(info, cx, handle, this, argc, vp) { if !CallJitSetterOp(info, cx, handle, this, argc, vp) {
return false; return false;
} }
@ -499,31 +531,34 @@ 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(
argc: libc::c_uint, cx: *mut JSContext,
vp: *mut JSVal) argc: libc::c_uint,
-> bool { vp: *mut JSVal,
) -> 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(
argc: libc::c_uint, cx: *mut JSContext,
vp: *mut JSVal) argc: libc::c_uint,
-> bool { vp: *mut JSVal,
) -> 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(
proto_id: u32, clasp: *const js::jsapi::Class,
depth: u32) proto_id: u32,
-> bool { depth: u32,
) -> 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
} }
#[allow(missing_docs)] // FIXME #[allow(missing_docs)] // FIXME
pub const DOM_CALLBACKS: DOMCallbacks = DOMCallbacks { pub const DOM_CALLBACKS: DOMCallbacks = DOMCallbacks {
instanceClassMatchesProto: Some(instance_class_has_proto_at_depth), instanceClassMatchesProto: Some(instance_class_has_proto_at_depth),
}; };

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!(
self, "Incrementing WeakBox refcount for {:p} to {}.",
new_count); self,
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,
}
} }
} }
} }
@ -122,10 +123,10 @@ impl<T: WeakReferenceable> MallocSizeOf for WeakRef<T> {
} }
impl<T: WeakReferenceable> PartialEq for WeakRef<T> { impl<T: WeakReferenceable> PartialEq for WeakRef<T> {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
unsafe { unsafe {
(*self.ptr.as_ptr()).value.get().map(ptr::NonNull::as_ptr) == (*self.ptr.as_ptr()).value.get().map(ptr::NonNull::as_ptr) ==
(*other.ptr.as_ptr()).value.get().map(ptr::NonNull::as_ptr) (*other.ptr.as_ptr()).value.get().map(ptr::NonNull::as_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(
blobParts: Option<Vec<ArrayBufferOrArrayBufferViewOrBlobOrString>>, global: &GlobalScope,
blobPropertyBag: &BlobBinding::BlobPropertyBag) blobParts: Option<Vec<ArrayBufferOrArrayBufferViewOrBlobOrString>>,
-> Fallible<DomRoot<Blob>> { blobPropertyBag: &BlobBinding::BlobPropertyBag,
) -> 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(
rel_pos.clone(), parent_id.clone(),
tx, origin.clone()); rel_pos.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);
} },
} }
} }
@ -359,10 +379,11 @@ impl BlobMethods for Blob {
// https://w3c.github.io/FileAPI/#dfn-size // https://w3c.github.io/FileAPI/#dfn-size
fn Size(&self) -> u64 { fn Size(&self) -> u64 {
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(
start: Option<i64>, &self,
end: Option<i64>, start: Option<i64>,
content_type: Option<DOMString>) end: Option<i64>,
-> DomRoot<Blob> { content_type: Option<DOMString>,
) -> 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("")))
} }
@ -391,8 +413,8 @@ fn normalize_type_string(s: &str) -> String {
if is_ascii_printable(s) { if is_ascii_printable(s) {
let s_lower = s.to_ascii_lowercase(); let s_lower = s.to_ascii_lowercase();
// match s_lower.parse() as Result<Mime, ()> { // match s_lower.parse() as Result<Mime, ()> {
// Ok(_) => s_lower, // Ok(_) => s_lower,
// Err(_) => "".to_string() // Err(_) => "".to_string()
s_lower s_lower
} else { } else {
"".to_string() "".to_string()

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(
global, Box::new(Bluetooth::new_inherited()),
BluetoothBinding::Wrap) global,
BluetoothBinding::Wrap,
)
} }
fn get_bluetooth_thread(&self) -> IpcSender<BluetoothRequest> { fn get_bluetooth_thread(&self) -> IpcSender<BluetoothRequest> {
@ -146,19 +157,21 @@ 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(
p: &Rc<Promise>, &self,
filters: &Option<Vec<BluetoothLEScanFilterInit>>, p: &Rc<Promise>,
optional_services: &Option<Vec<BluetoothServiceUUID>>, filters: &Option<Vec<BluetoothLEScanFilterInit>>,
sender: IpcSender<BluetoothResponseResult>) { optional_services: &Option<Vec<BluetoothServiceUUID>>,
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.
if filters.is_empty() { if filters.is_empty() {
p.reject_error(Type(FILTER_EMPTY_ERROR.to_owned())); p.reject_error(Type(FILTER_EMPTY_ERROR.to_owned()));
return; return;
} }
@ -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,71 +214,83 @@ 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(
struct ListenerTask<T: AsyncBluetoothListener + DomObject> { action_receiver.to_opaque(),
context: Arc<Mutex<BluetoothContext<T>>>, Box::new(move |message| {
action: BluetoothResponseResult, struct ListenerTask<T: AsyncBluetoothListener + DomObject> {
} context: Arc<Mutex<BluetoothContext<T>>>,
action: BluetoothResponseResult,
impl<T> TaskOnce for ListenerTask<T>
where
T: AsyncBluetoothListener + DomObject,
{
fn run_once(self) {
let mut context = self.context.lock().unwrap();
context.response(self.action);
} }
}
let task = ListenerTask { impl<T> TaskOnce for ListenerTask<T>
context: context.clone(), where
action: message.to().unwrap(), T: AsyncBluetoothListener + DomObject,
}; {
fn run_once(self) {
let mut context = self.context.lock().unwrap();
context.response(self.action);
}
}
let result = task_source.queue_unconditionally(task); let task = ListenerTask {
if let Err(err) = result { context: context.clone(),
warn!("failed to deliver network data: {:?}", err); action: message.to().unwrap(),
} };
}));
let result = task_source.queue_unconditionally(task);
if let Err(err) = result {
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;
} }
@ -307,11 +341,12 @@ pub fn get_gatt_children<T, F> (
fn canonicalize_filter(filter: &BluetoothLEScanFilterInit) -> Fallible<BluetoothScanfilter> { fn canonicalize_filter(filter: &BluetoothLEScanFilterInit) -> Fallible<BluetoothScanfilter> {
// Step 1. // Step 1.
if filter.services.is_none() && if filter.services.is_none() &&
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()));
} }
// Step 2: There is no empty canonicalizedFilter member, // Step 2: There is no empty canonicalizedFilter member,
@ -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(
DOMString::from(device.id.clone()), &self.global(),
device.name.map(DOMString::from), DOMString::from(device.id.clone()),
&self); device.name.map(DOMString::from),
&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
BluetoothScanfilterSequence::new(scan_filters), .get_bluetooth_thread()
sender)).unwrap(); .send(BluetoothRequest::MatchesFilter(
device_id.clone(),
BluetoothScanfilterSequence::new(scan_filters),
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(
name: Option<DOMString>, device: &BluetoothDevice,
appearance: Option<u16>, name: Option<DOMString>,
tx_power: Option<i8>, appearance: Option<u16>,
rssi: Option<i8>) tx_power: Option<i8>,
-> BluetoothAdvertisingEvent { rssi: Option<i8>,
) -> BluetoothAdvertisingEvent {
BluetoothAdvertisingEvent { BluetoothAdvertisingEvent {
event: Event::new_inherited(), event: Event::new_inherited(),
device: Dom::from_ref(device), device: Dom::from_ref(device),
@ -45,26 +46,23 @@ impl BluetoothAdvertisingEvent {
} }
} }
pub fn new(global: &GlobalScope, pub fn new(
type_: Atom, global: &GlobalScope,
bubbles: EventBubbles, type_: Atom,
cancelable: EventCancelable, bubbles: EventBubbles,
device: &BluetoothDevice, cancelable: EventCancelable,
name: Option<DOMString>, device: &BluetoothDevice,
appearance: Option<u16>, name: Option<DOMString>,
txPower: Option<i8>, appearance: Option<u16>,
rssi: Option<i8>) txPower: Option<i8>,
-> DomRoot<BluetoothAdvertisingEvent> { rssi: Option<i8>,
) -> 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(
type_: DOMString, window: &Window,
init: &BluetoothAdvertisingEventInit) type_: DOMString,
-> Fallible<DomRoot<BluetoothAdvertisingEvent>> { init: &BluetoothAdvertisingEventInit,
) -> 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,15 +85,17 @@ 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(
Atom::from(type_), global,
bubbles, Atom::from(type_),
cancelable, bubbles,
device, cancelable,
name, device,
appearance, name,
txPower, appearance,
rssi)) txPower,
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,16 +26,17 @@ pub struct BluetoothCharacteristicProperties {
} }
impl BluetoothCharacteristicProperties { impl BluetoothCharacteristicProperties {
pub fn new_inherited(broadcast: bool, pub fn new_inherited(
read: bool, broadcast: bool,
write_without_response: bool, read: bool,
write: bool, write_without_response: bool,
notify: bool, write: bool,
indicate: bool, notify: bool,
authenticated_signed_writes: bool, indicate: bool,
reliable_write: bool, authenticated_signed_writes: bool,
writable_auxiliaries: bool) reliable_write: bool,
-> BluetoothCharacteristicProperties { writable_auxiliaries: bool,
) -> BluetoothCharacteristicProperties {
BluetoothCharacteristicProperties { BluetoothCharacteristicProperties {
reflector_: Reflector::new(), reflector_: Reflector::new(),
broadcast: broadcast, broadcast: broadcast,
@ -50,17 +51,18 @@ impl BluetoothCharacteristicProperties {
} }
} }
pub fn new(global: &GlobalScope, pub fn new(
broadcast: bool, global: &GlobalScope,
read: bool, broadcast: bool,
writeWithoutResponse: bool, read: bool,
write: bool, writeWithoutResponse: bool,
notify: bool, write: bool,
indicate: bool, notify: bool,
authenticatedSignedWrites: bool, indicate: bool,
reliableWrite: bool, authenticatedSignedWrites: bool,
writableAuxiliaries: bool) reliableWrite: bool,
-> DomRoot<BluetoothCharacteristicProperties> { writableAuxiliaries: bool,
) -> 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,118 +38,144 @@ 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<BluetoothRemoteGATTCharacteristic>>>, DomRefCell<HashMap<String, Dom<BluetoothRemoteGATTService>>>,
DomRefCell<HashMap<String, Dom<BluetoothRemoteGATTDescriptor>>>), DomRefCell<HashMap<String, Dom<BluetoothRemoteGATTCharacteristic>>>,
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(
name: Option<DOMString>, id: DOMString,
context: &Bluetooth) name: Option<DOMString>,
-> BluetoothDevice { context: &Bluetooth,
) -> 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(
id: DOMString, global: &GlobalScope,
name: Option<DOMString>, id: DOMString,
context: &Bluetooth) name: Option<DOMString>,
-> DomRoot<BluetoothDevice> { context: &Bluetooth,
reflect_dom_object(Box::new(BluetoothDevice::new_inherited(id, name, context)), ) -> DomRoot<BluetoothDevice> {
global, reflect_dom_object(
BluetoothDeviceBinding::Wrap) Box::new(BluetoothDevice::new_inherited(id, name, context)),
global,
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(
service: &BluetoothServiceMsg, &self,
server: &BluetoothRemoteGATTServer) service: &BluetoothServiceMsg,
-> DomRoot<BluetoothRemoteGATTService> { server: &BluetoothRemoteGATTServer,
) -> 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.Device(), &server.global(),
DOMString::from(service.uuid.clone()), &server.Device(),
service.is_primary, DOMString::from(service.uuid.clone()),
service.instance_id.clone()); service.is_primary,
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(
characteristic: &BluetoothCharacteristicMsg, &self,
service: &BluetoothRemoteGATTService) characteristic: &BluetoothCharacteristicMsg,
-> DomRoot<BluetoothRemoteGATTCharacteristic> { service: &BluetoothRemoteGATTService,
) -> 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,
characteristic.write, characteristic.write,
characteristic.notify, characteristic.notify,
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(), );
service, let bt_characteristic = BluetoothRemoteGATTCharacteristic::new(
DOMString::from(characteristic.uuid.clone()), &service.global(),
&properties, service,
characteristic.instance_id.clone()); DOMString::from(characteristic.uuid.clone()),
characteristic_map.insert(characteristic.instance_id.clone(), Dom::from_ref(&bt_characteristic)); &properties,
characteristic.instance_id.clone(),
);
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(
descriptor: &BluetoothDescriptorMsg, &self,
characteristic: &BluetoothRemoteGATTCharacteristic) descriptor: &BluetoothDescriptorMsg,
-> DomRoot<BluetoothRemoteGATTDescriptor> { characteristic: &BluetoothRemoteGATTCharacteristic,
) -> 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, &characteristic.global(),
DOMString::from(descriptor.uuid.clone()), characteristic,
descriptor.instance_id.clone()); DOMString::from(descriptor.uuid.clone()),
descriptor_map.insert(descriptor.instance_id.clone(), Dom::from_ref(&bt_descriptor)); descriptor.instance_id.clone(),
);
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,14 +238,17 @@ 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)
} }
} }
impl BluetoothDeviceMethods for BluetoothDevice { impl BluetoothDeviceMethods for BluetoothDevice {
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdevice-id // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdevice-id
fn Id(&self) -> DOMString { fn Id(&self) -> DOMString {
self.id.clone() self.id.clone()
} }
@ -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,
global, status: &PermissionStatus,
BluetoothPermissionResultBinding::Wrap) ) -> DomRoot<BluetoothPermissionResult> {
reflect_dom_object(
Box::new(BluetoothPermissionResult::new_inherited(status)),
global,
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(
DOMString::from(device.id.clone()), &self.global(),
device.name.map(DOMString::from), DOMString::from(device.id.clone()),
&bluetooth); device.name.map(DOMString::from),
&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(
uuid: DOMString, service: &BluetoothRemoteGATTService,
properties: &BluetoothCharacteristicProperties, uuid: DOMString,
instance_id: String) properties: &BluetoothCharacteristicProperties,
-> BluetoothRemoteGATTCharacteristic { instance_id: String,
) -> 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(
service: &BluetoothRemoteGATTService, global: &GlobalScope,
uuid: DOMString, service: &BluetoothRemoteGATTService,
properties: &BluetoothCharacteristicProperties, uuid: DOMString,
instanceID: String) properties: &BluetoothCharacteristicProperties,
-> DomRoot<BluetoothRemoteGATTCharacteristic> { instanceID: String,
) -> 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;
} }
@ -186,8 +201,9 @@ 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(
true, self.get_instance_id(),
sender)).unwrap(); true,
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(
false, self.get_instance_id(),
sender)).unwrap(); false,
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(
uuid: DOMString, characteristic: &BluetoothRemoteGATTCharacteristic,
instance_id: String) uuid: DOMString,
-> BluetoothRemoteGATTDescriptor { instance_id: String,
) -> 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(
characteristic: &BluetoothRemoteGATTCharacteristic, global: &GlobalScope,
uuid: DOMString, characteristic: &BluetoothRemoteGATTCharacteristic,
instanceID: String) uuid: DOMString,
-> DomRoot<BluetoothRemoteGATTDescriptor>{ instanceID: String,
) -> 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,
) )
} }
@ -74,7 +78,7 @@ impl BluetoothRemoteGATTDescriptor {
impl BluetoothRemoteGATTDescriptorMethods for BluetoothRemoteGATTDescriptor { impl BluetoothRemoteGATTDescriptorMethods for BluetoothRemoteGATTDescriptor {
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattdescriptor-characteristic // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattdescriptor-characteristic
fn Characteristic(&self) -> DomRoot<BluetoothRemoteGATTCharacteristic> { fn Characteristic(&self) -> DomRoot<BluetoothRemoteGATTCharacteristic> {
DomRoot::from_ref(&self.characteristic) DomRoot::from_ref(&self.characteristic)
} }
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattdescriptor-uuid // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattdescriptor-uuid
@ -82,7 +86,7 @@ impl BluetoothRemoteGATTDescriptorMethods for BluetoothRemoteGATTDescriptor {
self.uuid.clone() self.uuid.clone()
} }
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattdescriptor-value // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattdescriptor-value
fn GetValue(&self) -> Option<ByteString> { fn GetValue(&self) -> Option<ByteString> {
self.value.borrow().clone() self.value.borrow().clone()
} }
@ -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,
global, device: &BluetoothDevice,
BluetoothRemoteGATTServerBinding::Wrap) ) -> DomRoot<BluetoothRemoteGATTServer> {
reflect_dom_object(
Box::new(BluetoothRemoteGATTServer::new_inherited(device)),
global,
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(
uuid: DOMString, device: &BluetoothDevice,
is_primary: bool, uuid: DOMString,
instance_id: String) is_primary: bool,
-> BluetoothRemoteGATTService { instance_id: String,
) -> 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(
device: &BluetoothDevice, global: &GlobalScope,
uuid: DOMString, device: &BluetoothDevice,
isPrimary: bool, uuid: DOMString,
instanceID: String) isPrimary: bool,
-> DomRoot<BluetoothRemoteGATTService> { instanceID: String,
) -> 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,19 +565,23 @@ 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 =
\ne.g. 'alert_notification'."; "https://developer.bluetooth.org/gatt/services/Pages/ServicesHome.aspx\
\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 =
CharacteristicsHome.aspx\ne.g. 'aerobic_heart_rate_lower_limit'."; "https://developer.bluetooth.org/gatt/characteristics/Pages/\
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 =
DescriptorsHomePage.aspx\ne.g. 'gatt.characteristic_presentation_format'."; "https://developer.bluetooth.org/gatt/descriptors/Pages/\
DescriptorsHomePage.aspx\ne.g. 'gatt.characteristic_presentation_format'.";
impl BluetoothUUID { impl BluetoothUUID {
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothuuid-canonicaluuid // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothuuid-canonicaluuid
@ -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> {
@ -333,22 +638,20 @@ fn canonical_uuid(alias: u32) -> UUID {
// https://webbluetoothcg.github.io/web-bluetooth/#resolveuuidname // https://webbluetoothcg.github.io/web-bluetooth/#resolveuuidname
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();
if regex.is_match(&*dstring) { if regex.is_match(&*dstring) {
Ok(dstring) Ok(dstring)
} else { } else {
// Step 3. // Step 3.
let concatenated = format!("{}.{}", prefix, dstring); let concatenated = format!("{}.{}", prefix, dstring);
let is_in_table = assigned_numbers_table.iter().find(|p| p.0 == concatenated); let is_in_table = assigned_numbers_table.iter().find(|p| p.0 == concatenated);
match is_in_table { match is_in_table {
@ -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(
global, Box::new(CanvasGradient::new_inherited(style)),
CanvasGradientBinding::Wrap) global,
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.y0, gradient.x0,
gradient.x1, gradient.y0,
gradient.y1, gradient.x1,
gradient_stops)) gradient.y1,
} gradient_stops,
))
},
CanvasGradientStyle::Radial(ref gradient) => { CanvasGradientStyle::Radial(ref gradient) => {
FillOrStrokeStyle::RadialGradient(RadialGradientStyle::new(gradient.x0, FillOrStrokeStyle::RadialGradient(RadialGradientStyle::new(
gradient.y0, gradient.x0,
gradient.r0, gradient.y0,
gradient.x1, gradient.r0,
gradient.y1, gradient.x1,
gradient.r1, gradient.y1,
gradient_stops)) gradient.r1,
} 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_size: Size2D<i32>, surface_data: Vec<u8>,
repeat: RepetitionStyle, surface_size: Size2D<i32>,
origin_clean: bool) repeat: RepetitionStyle,
-> CanvasPattern { origin_clean: bool,
) -> 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,30 +45,36 @@ impl CanvasPattern {
origin_clean: origin_clean, origin_clean: origin_clean,
} }
} }
pub fn new(global: &GlobalScope, pub fn new(
surface_data: Vec<u8>, global: &GlobalScope,
surface_size: Size2D<i32>, surface_data: Vec<u8>,
repeat: RepetitionStyle, surface_size: Size2D<i32>,
origin_clean: bool) repeat: RepetitionStyle,
-> DomRoot<CanvasPattern> { origin_clean: bool,
) -> 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 {
self.origin_clean self.origin_clean
} }
} }
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_size, self.surface_data.clone(),
self.repeat_x, self.surface_size,
self.repeat_y)) self.repeat_x,
self.repeat_y,
))
} }
} }

File diff suppressed because it is too large Load diff

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(
@ -43,11 +45,9 @@ impl ChannelMergerNode {
context, context,
node_options, node_options,
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();
@ -209,10 +210,11 @@ impl CharacterDataMethods for CharacterData {
// Step 5 to 7. // Step 5 to 7.
new_data = String::with_capacity( new_data = String::with_capacity(
prefix.len() + prefix.len() +
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!(
Would split a surrogate pair in CharacterData API.\n\ "\n\n\
If you see this in real content, please comment with the URL\n\ Would split a surrogate pair in CharacterData API.\n\
on https://github.com/servo/servo/issues/6873\n\ If you see this in real content, please comment with the URL\n\
\n"); on https://github.com/servo/servo/issues/6873\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(
window, Box::new(Client::new_inherited(window.get_url())),
Wrap) window,
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(
global, Box::new(CloseEvent::new_inherited(false, 0, DOMString::new())),
CloseEventBinding::Wrap) global,
CloseEventBinding::Wrap,
)
} }
pub fn new(global: &GlobalScope, pub fn new(
type_: Atom, global: &GlobalScope,
bubbles: EventBubbles, type_: Atom,
cancelable: EventCancelable, bubbles: EventBubbles,
wasClean: bool, cancelable: EventCancelable,
code: u16, wasClean: bool,
reason: DOMString) code: u16,
-> DomRoot<CloseEvent> { reason: DOMString,
) -> 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(
type_: DOMString, global: &GlobalScope,
init: &CloseEventBinding::CloseEventInit) type_: DOMString,
-> Fallible<DomRoot<CloseEvent>> { init: &CloseEventBinding::CloseEventInit,
) -> 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(
Atom::from(type_), global,
bubbles, Atom::from(type_),
cancelable, bubbles,
init.wasClean, cancelable,
init.code, init.wasClean,
init.reason.clone())) init.code,
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(
document, Box::new(Comment::new_inherited(text, document)),
CommentBinding::Wrap) document,
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(
type_: DOMString, window: &Window,
can_bubble: bool, type_: DOMString,
cancelable: bool, can_bubble: bool,
view: Option<&Window>, cancelable: bool,
detail: i32, view: Option<&Window>,
data: DOMString) -> DomRoot<CompositionEvent> { detail: i32,
let ev = reflect_dom_object(Box::new(CompositionEvent { data: DOMString,
uievent: UIEvent::new_inherited(), ) -> DomRoot<CompositionEvent> {
data: data, let ev = reflect_dom_object(
}), Box::new(CompositionEvent {
window, uievent: UIEvent::new_inherited(),
CompositionEventBinding::Wrap); data: data,
ev.uievent.InitUIEvent(type_, can_bubble, cancelable, view, detail); }),
window,
CompositionEventBinding::Wrap,
);
ev.uievent
.InitUIEvent(type_, can_bubble, cancelable, view, detail);
ev ev
} }
pub fn Constructor(window: &Window, pub fn Constructor(
type_: DOMString, window: &Window,
init: &CompositionEventBinding::CompositionEventInit) type_: DOMString,
-> Fallible<DomRoot<CompositionEvent>> { init: &CompositionEventBinding::CompositionEventInit,
let event = CompositionEvent::new(window, ) -> Fallible<DomRoot<CompositionEvent>> {
type_, let event = CompositionEvent::new(
init.parent.parent.bubbles, window,
init.parent.parent.cancelable, type_,
init.parent.view.r(), init.parent.parent.bubbles,
init.parent.detail, init.parent.parent.cancelable,
init.data.clone()); init.parent.view.r(),
init.parent.detail,
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(
prefix: Option<Prefix>, name: QualName,
document: &Document) prefix: Option<Prefix>,
-> DomRoot<Element> { document: &Document,
) -> DomRoot<Element> {
assert_eq!(name.ns, ns!(svg)); assert_eq!(name.ns, ns!(svg));
macro_rules! make( macro_rules! make(
@ -106,20 +107,21 @@ fn create_svg_element(name: QualName,
} }
match name.local { match name.local {
local_name!("svg") => make!(SVGSVGElement), local_name!("svg") => make!(SVGSVGElement),
_ => Element::new(name.local, name.ns, prefix, document), _ => Element::new(name.local, name.ns, prefix, document),
} }
} }
// 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(
prefix: Option<Prefix>, name: QualName,
is: Option<LocalName>, prefix: Option<Prefix>,
document: &Document, is: Option<LocalName>,
creator: ElementCreator, document: &Document,
mode: CustomElementCreationMode) creator: ElementCreator,
-> DomRoot<Element> { mode: CustomElementCreationMode,
) -> 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;
} }
@ -214,162 +224,163 @@ pub fn create_native_html_element(
// Perhaps we should build a perfect hash from those IDs instead. // Perhaps we should build a perfect hash from those IDs instead.
// https://html.spec.whatwg.org/multipage/#elements-in-the-dom // https://html.spec.whatwg.org/multipage/#elements-in-the-dom
match name.local { match name.local {
local_name!("a") => make!(HTMLAnchorElement), local_name!("a") => make!(HTMLAnchorElement),
local_name!("abbr") => make!(HTMLElement), local_name!("abbr") => make!(HTMLElement),
local_name!("acronym") => make!(HTMLElement), local_name!("acronym") => make!(HTMLElement),
local_name!("address") => make!(HTMLElement), local_name!("address") => make!(HTMLElement),
local_name!("area") => make!(HTMLAreaElement), local_name!("area") => make!(HTMLAreaElement),
local_name!("article") => make!(HTMLElement), local_name!("article") => make!(HTMLElement),
local_name!("aside") => make!(HTMLElement), local_name!("aside") => make!(HTMLElement),
local_name!("audio") => make!(HTMLAudioElement), local_name!("audio") => make!(HTMLAudioElement),
local_name!("b") => make!(HTMLElement), local_name!("b") => make!(HTMLElement),
local_name!("base") => make!(HTMLBaseElement), local_name!("base") => make!(HTMLBaseElement),
local_name!("bdi") => make!(HTMLElement), local_name!("bdi") => make!(HTMLElement),
local_name!("bdo") => make!(HTMLElement), local_name!("bdo") => make!(HTMLElement),
// https://html.spec.whatwg.org/multipage/#other-elements,-attributes-and-apis:bgsound // https://html.spec.whatwg.org/multipage/#other-elements,-attributes-and-apis:bgsound
local_name!("bgsound") => make!(HTMLUnknownElement), local_name!("bgsound") => make!(HTMLUnknownElement),
local_name!("big") => make!(HTMLElement), local_name!("big") => make!(HTMLElement),
// https://html.spec.whatwg.org/multipage/#other-elements,-attributes-and-apis:blink // https://html.spec.whatwg.org/multipage/#other-elements,-attributes-and-apis:blink
local_name!("blink") => make!(HTMLUnknownElement), local_name!("blink") => make!(HTMLUnknownElement),
// https://html.spec.whatwg.org/multipage/#the-blockquote-element // https://html.spec.whatwg.org/multipage/#the-blockquote-element
local_name!("blockquote") => make!(HTMLQuoteElement), local_name!("blockquote") => make!(HTMLQuoteElement),
local_name!("body") => make!(HTMLBodyElement), local_name!("body") => make!(HTMLBodyElement),
local_name!("br") => make!(HTMLBRElement), local_name!("br") => make!(HTMLBRElement),
local_name!("button") => make!(HTMLButtonElement), local_name!("button") => make!(HTMLButtonElement),
local_name!("canvas") => make!(HTMLCanvasElement), local_name!("canvas") => make!(HTMLCanvasElement),
local_name!("caption") => make!(HTMLTableCaptionElement), local_name!("caption") => make!(HTMLTableCaptionElement),
local_name!("center") => make!(HTMLElement), local_name!("center") => make!(HTMLElement),
local_name!("cite") => make!(HTMLElement), local_name!("cite") => make!(HTMLElement),
local_name!("code") => make!(HTMLElement), local_name!("code") => make!(HTMLElement),
local_name!("col") => make!(HTMLTableColElement), local_name!("col") => make!(HTMLTableColElement),
local_name!("colgroup") => make!(HTMLTableColElement), local_name!("colgroup") => make!(HTMLTableColElement),
local_name!("data") => make!(HTMLDataElement), local_name!("data") => make!(HTMLDataElement),
local_name!("datalist") => make!(HTMLDataListElement), local_name!("datalist") => make!(HTMLDataListElement),
local_name!("dd") => make!(HTMLElement), local_name!("dd") => make!(HTMLElement),
local_name!("del") => make!(HTMLModElement), local_name!("del") => make!(HTMLModElement),
local_name!("details") => make!(HTMLDetailsElement), local_name!("details") => make!(HTMLDetailsElement),
local_name!("dfn") => make!(HTMLElement), local_name!("dfn") => make!(HTMLElement),
local_name!("dialog") => make!(HTMLDialogElement), local_name!("dialog") => make!(HTMLDialogElement),
local_name!("dir") => make!(HTMLDirectoryElement), local_name!("dir") => make!(HTMLDirectoryElement),
local_name!("div") => make!(HTMLDivElement), local_name!("div") => make!(HTMLDivElement),
local_name!("dl") => make!(HTMLDListElement), local_name!("dl") => make!(HTMLDListElement),
local_name!("dt") => make!(HTMLElement), local_name!("dt") => make!(HTMLElement),
local_name!("em") => make!(HTMLElement), local_name!("em") => make!(HTMLElement),
local_name!("embed") => make!(HTMLEmbedElement), local_name!("embed") => make!(HTMLEmbedElement),
local_name!("fieldset") => make!(HTMLFieldSetElement), local_name!("fieldset") => make!(HTMLFieldSetElement),
local_name!("figcaption") => make!(HTMLElement), local_name!("figcaption") => make!(HTMLElement),
local_name!("figure") => make!(HTMLElement), local_name!("figure") => make!(HTMLElement),
local_name!("font") => make!(HTMLFontElement), local_name!("font") => make!(HTMLFontElement),
local_name!("footer") => make!(HTMLElement), local_name!("footer") => make!(HTMLElement),
local_name!("form") => make!(HTMLFormElement), local_name!("form") => make!(HTMLFormElement),
local_name!("frame") => make!(HTMLFrameElement), local_name!("frame") => make!(HTMLFrameElement),
local_name!("frameset") => make!(HTMLFrameSetElement), local_name!("frameset") => make!(HTMLFrameSetElement),
local_name!("h1") => make!(HTMLHeadingElement, HeadingLevel::Heading1), local_name!("h1") => make!(HTMLHeadingElement, HeadingLevel::Heading1),
local_name!("h2") => make!(HTMLHeadingElement, HeadingLevel::Heading2), local_name!("h2") => make!(HTMLHeadingElement, HeadingLevel::Heading2),
local_name!("h3") => make!(HTMLHeadingElement, HeadingLevel::Heading3), local_name!("h3") => make!(HTMLHeadingElement, HeadingLevel::Heading3),
local_name!("h4") => make!(HTMLHeadingElement, HeadingLevel::Heading4), local_name!("h4") => make!(HTMLHeadingElement, HeadingLevel::Heading4),
local_name!("h5") => make!(HTMLHeadingElement, HeadingLevel::Heading5), local_name!("h5") => make!(HTMLHeadingElement, HeadingLevel::Heading5),
local_name!("h6") => make!(HTMLHeadingElement, HeadingLevel::Heading6), local_name!("h6") => make!(HTMLHeadingElement, HeadingLevel::Heading6),
local_name!("head") => make!(HTMLHeadElement), local_name!("head") => make!(HTMLHeadElement),
local_name!("header") => make!(HTMLElement), local_name!("header") => make!(HTMLElement),
local_name!("hgroup") => make!(HTMLElement), local_name!("hgroup") => make!(HTMLElement),
local_name!("hr") => make!(HTMLHRElement), local_name!("hr") => make!(HTMLHRElement),
local_name!("html") => make!(HTMLHtmlElement), local_name!("html") => make!(HTMLHtmlElement),
local_name!("i") => make!(HTMLElement), local_name!("i") => make!(HTMLElement),
local_name!("iframe") => make!(HTMLIFrameElement), local_name!("iframe") => make!(HTMLIFrameElement),
local_name!("img") => make!(HTMLImageElement), local_name!("img") => make!(HTMLImageElement),
local_name!("input") => make!(HTMLInputElement), local_name!("input") => make!(HTMLInputElement),
local_name!("ins") => make!(HTMLModElement), local_name!("ins") => make!(HTMLModElement),
// https://html.spec.whatwg.org/multipage/#other-elements,-attributes-and-apis:isindex-2 // https://html.spec.whatwg.org/multipage/#other-elements,-attributes-and-apis:isindex-2
local_name!("isindex") => make!(HTMLUnknownElement), local_name!("isindex") => make!(HTMLUnknownElement),
local_name!("kbd") => make!(HTMLElement), local_name!("kbd") => make!(HTMLElement),
local_name!("label") => make!(HTMLLabelElement), local_name!("label") => make!(HTMLLabelElement),
local_name!("legend") => make!(HTMLLegendElement), local_name!("legend") => make!(HTMLLegendElement),
local_name!("li") => make!(HTMLLIElement), local_name!("li") => make!(HTMLLIElement),
local_name!("link") => make!(HTMLLinkElement, creator), local_name!("link") => make!(HTMLLinkElement, creator),
// https://html.spec.whatwg.org/multipage/#other-elements,-attributes-and-apis:listing // https://html.spec.whatwg.org/multipage/#other-elements,-attributes-and-apis:listing
local_name!("listing") => make!(HTMLPreElement), local_name!("listing") => make!(HTMLPreElement),
local_name!("main") => make!(HTMLElement), local_name!("main") => make!(HTMLElement),
local_name!("map") => make!(HTMLMapElement), local_name!("map") => make!(HTMLMapElement),
local_name!("mark") => make!(HTMLElement), local_name!("mark") => make!(HTMLElement),
local_name!("marquee") => make!(HTMLElement), local_name!("marquee") => make!(HTMLElement),
local_name!("meta") => make!(HTMLMetaElement), local_name!("meta") => make!(HTMLMetaElement),
local_name!("meter") => make!(HTMLMeterElement), local_name!("meter") => make!(HTMLMeterElement),
// https://html.spec.whatwg.org/multipage/#other-elements,-attributes-and-apis:multicol // https://html.spec.whatwg.org/multipage/#other-elements,-attributes-and-apis:multicol
local_name!("multicol") => make!(HTMLUnknownElement), local_name!("multicol") => make!(HTMLUnknownElement),
local_name!("nav") => make!(HTMLElement), local_name!("nav") => make!(HTMLElement),
// https://html.spec.whatwg.org/multipage/#other-elements,-attributes-and-apis:nextid // https://html.spec.whatwg.org/multipage/#other-elements,-attributes-and-apis:nextid
local_name!("nextid") => make!(HTMLUnknownElement), local_name!("nextid") => make!(HTMLUnknownElement),
local_name!("nobr") => make!(HTMLElement), local_name!("nobr") => make!(HTMLElement),
local_name!("noframes") => make!(HTMLElement), local_name!("noframes") => make!(HTMLElement),
local_name!("noscript") => make!(HTMLElement), local_name!("noscript") => make!(HTMLElement),
local_name!("object") => make!(HTMLObjectElement), local_name!("object") => make!(HTMLObjectElement),
local_name!("ol") => make!(HTMLOListElement), local_name!("ol") => make!(HTMLOListElement),
local_name!("optgroup") => make!(HTMLOptGroupElement), local_name!("optgroup") => make!(HTMLOptGroupElement),
local_name!("option") => make!(HTMLOptionElement), local_name!("option") => make!(HTMLOptionElement),
local_name!("output") => make!(HTMLOutputElement), local_name!("output") => make!(HTMLOutputElement),
local_name!("p") => make!(HTMLParagraphElement), local_name!("p") => make!(HTMLParagraphElement),
local_name!("param") => make!(HTMLParamElement), local_name!("param") => make!(HTMLParamElement),
local_name!("picture") => make!(HTMLPictureElement), local_name!("picture") => make!(HTMLPictureElement),
local_name!("plaintext") => make!(HTMLPreElement), local_name!("plaintext") => make!(HTMLPreElement),
local_name!("pre") => make!(HTMLPreElement), local_name!("pre") => make!(HTMLPreElement),
local_name!("progress") => make!(HTMLProgressElement), local_name!("progress") => make!(HTMLProgressElement),
local_name!("q") => make!(HTMLQuoteElement), local_name!("q") => make!(HTMLQuoteElement),
local_name!("rp") => make!(HTMLElement), local_name!("rp") => make!(HTMLElement),
local_name!("rt") => make!(HTMLElement), local_name!("rt") => make!(HTMLElement),
local_name!("ruby") => make!(HTMLElement), local_name!("ruby") => make!(HTMLElement),
local_name!("s") => make!(HTMLElement), local_name!("s") => make!(HTMLElement),
local_name!("samp") => make!(HTMLElement), local_name!("samp") => make!(HTMLElement),
local_name!("script") => make!(HTMLScriptElement, creator), local_name!("script") => make!(HTMLScriptElement, creator),
local_name!("section") => make!(HTMLElement), local_name!("section") => make!(HTMLElement),
local_name!("select") => make!(HTMLSelectElement), local_name!("select") => make!(HTMLSelectElement),
local_name!("small") => make!(HTMLElement), local_name!("small") => make!(HTMLElement),
local_name!("source") => make!(HTMLSourceElement), local_name!("source") => make!(HTMLSourceElement),
// https://html.spec.whatwg.org/multipage/#other-elements,-attributes-and-apis:spacer // https://html.spec.whatwg.org/multipage/#other-elements,-attributes-and-apis:spacer
local_name!("spacer") => make!(HTMLUnknownElement), local_name!("spacer") => make!(HTMLUnknownElement),
local_name!("span") => make!(HTMLSpanElement), local_name!("span") => make!(HTMLSpanElement),
local_name!("strike") => make!(HTMLElement), local_name!("strike") => make!(HTMLElement),
local_name!("strong") => make!(HTMLElement), local_name!("strong") => make!(HTMLElement),
local_name!("style") => make!(HTMLStyleElement, creator), local_name!("style") => make!(HTMLStyleElement, creator),
local_name!("sub") => make!(HTMLElement), local_name!("sub") => make!(HTMLElement),
local_name!("summary") => make!(HTMLElement), local_name!("summary") => make!(HTMLElement),
local_name!("sup") => make!(HTMLElement), local_name!("sup") => make!(HTMLElement),
local_name!("table") => make!(HTMLTableElement), local_name!("table") => make!(HTMLTableElement),
local_name!("tbody") => make!(HTMLTableSectionElement), local_name!("tbody") => make!(HTMLTableSectionElement),
local_name!("td") => make!(HTMLTableDataCellElement), local_name!("td") => make!(HTMLTableDataCellElement),
local_name!("template") => make!(HTMLTemplateElement), local_name!("template") => make!(HTMLTemplateElement),
local_name!("textarea") => make!(HTMLTextAreaElement), local_name!("textarea") => make!(HTMLTextAreaElement),
// https://html.spec.whatwg.org/multipage/#the-tfoot-element:concept-element-dom // https://html.spec.whatwg.org/multipage/#the-tfoot-element:concept-element-dom
local_name!("tfoot") => make!(HTMLTableSectionElement), local_name!("tfoot") => make!(HTMLTableSectionElement),
local_name!("th") => make!(HTMLTableHeaderCellElement), local_name!("th") => make!(HTMLTableHeaderCellElement),
// https://html.spec.whatwg.org/multipage/#the-thead-element:concept-element-dom // https://html.spec.whatwg.org/multipage/#the-thead-element:concept-element-dom
local_name!("thead") => make!(HTMLTableSectionElement), local_name!("thead") => make!(HTMLTableSectionElement),
local_name!("time") => make!(HTMLTimeElement), local_name!("time") => make!(HTMLTimeElement),
local_name!("title") => make!(HTMLTitleElement), local_name!("title") => make!(HTMLTitleElement),
local_name!("tr") => make!(HTMLTableRowElement), local_name!("tr") => make!(HTMLTableRowElement),
local_name!("tt") => make!(HTMLElement), local_name!("tt") => make!(HTMLElement),
local_name!("track") => make!(HTMLTrackElement), local_name!("track") => make!(HTMLTrackElement),
local_name!("u") => make!(HTMLElement), local_name!("u") => make!(HTMLElement),
local_name!("ul") => make!(HTMLUListElement), local_name!("ul") => make!(HTMLUListElement),
local_name!("var") => make!(HTMLElement), local_name!("var") => make!(HTMLElement),
local_name!("video") => make!(HTMLVideoElement), local_name!("video") => make!(HTMLVideoElement),
local_name!("wbr") => make!(HTMLElement), local_name!("wbr") => make!(HTMLElement),
local_name!("xmp") => make!(HTMLPreElement), local_name!("xmp") => make!(HTMLPreElement),
_ if is_valid_custom_element_name(&*name.local) => make!(HTMLElement), _ if is_valid_custom_element_name(&*name.local) => make!(HTMLElement),
_ => make!(HTMLUnknownElement), _ => make!(HTMLUnknownElement),
} }
} }
pub fn create_element(name: QualName, pub fn create_element(
is: Option<LocalName>, name: QualName,
document: &Document, is: Option<LocalName>,
creator: ElementCreator, document: &Document,
mode: CustomElementCreationMode) creator: ElementCreator,
-> DomRoot<Element> { mode: CustomElementCreationMode,
) -> 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(
_cx: *mut JSContext, &self,
mut input: CustomAutoRooterGuard<ArrayBufferView>) _cx: *mut JSContext,
-> Fallible<NonNull<JSObject>> { mut input: CustomAutoRooterGuard<ArrayBufferView>,
) -> 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,
window, fontfacerule: Arc<Locked<FontFaceRule>>,
CSSFontFaceRuleBinding::Wrap) ) -> DomRoot<CSSFontFaceRule> {
reflect_dom_object(
Box::new(CSSFontFaceRule::new_inherited(
parent_stylesheet,
fontfacerule,
)),
window,
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(|| {
parent_stylesheet, CSSRuleList::new(
RulesSource::Rules(self.rules.clone()))) self.global().as_window(),
parent_stylesheet,
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(
parent_stylesheet: &CSSStyleSheet, window: &Window,
import_rule: Arc<Locked<ImportRule>>) -> DomRoot<Self> { parent_stylesheet: &CSSStyleSheet,
reflect_dom_object(Box::new(Self::new_inherited(parent_stylesheet, import_rule)), import_rule: Arc<Locked<ImportRule>>,
window, ) -> DomRoot<Self> {
CSSImportRuleBinding::Wrap) reflect_dom_object(
Box::new(Self::new_inherited(parent_stylesheet, import_rule)),
window,
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,
window, keyframerule: Arc<Locked<Keyframe>>,
CSSKeyframeRuleBinding::Wrap) ) -> DomRoot<CSSKeyframeRule> {
reflect_dom_object(
Box::new(CSSKeyframeRule::new_inherited(
parent_stylesheet,
keyframerule,
)),
window,
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,
window, keyframesrule: Arc<Locked<KeyframesRule>>,
CSSKeyframesRuleBinding::Wrap) ) -> DomRoot<CSSKeyframesRule> {
reflect_dom_object(
Box::new(CSSKeyframesRule::new_inherited(
parent_stylesheet,
keyframesrule,
)),
window,
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(
parent_stylesheet, self.global().as_window(),
RulesSource::Keyframes(self.keyframesrule.clone())) parent_stylesheet,
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,
window, mediarule: Arc<Locked<MediaRule>>,
CSSMediaRuleBinding::Wrap) ) -> DomRoot<CSSMediaRule> {
reflect_dom_object(
Box::new(CSSMediaRule::new_inherited(parent_stylesheet, mediarule)),
window,
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.cssconditionrule.parent_stylesheet(), self.global().as_window(),
self.mediarule.read_with(&guard).media_queries.clone()) self.cssconditionrule.parent_stylesheet(),
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,
window, namespacerule: Arc<Locked<NamespaceRule>>,
CSSNamespaceRuleBinding::Wrap) ) -> DomRoot<CSSNamespaceRule> {
reflect_dom_object(
Box::new(CSSNamespaceRule::new_inherited(
parent_stylesheet,
namespacerule,
)),
window,
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,
window, rules: RulesSource,
CSSRuleListBinding::Wrap) ) -> DomRoot<CSSRuleList> {
reflect_dom_object(
Box::new(CSSRuleList::new_inherited(parent_stylesheet, rules)),
window,
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(
rule, &parent_stylesheet.shared_lock,
&parent_stylesheet.contents, rule,
index, &parent_stylesheet.contents,
nested, index,
None) nested,
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(
pseudo: Option<PseudoElement>, owner: CSSStyleOwner,
modification_access: CSSModificationAccess) pseudo: Option<PseudoElement>,
-> CSSStyleDeclaration { modification_access: CSSModificationAccess,
) -> 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(
owner: CSSStyleOwner, global: &Window,
pseudo: Option<PseudoElement>, owner: CSSStyleOwner,
modification_access: CSSModificationAccess) pseudo: Option<PseudoElement>,
-> DomRoot<CSSStyleDeclaration> { modification_access: CSSModificationAccess,
) -> 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(
property: DOMString, &self,
value: DOMString, property: DOMString,
priority: DOMString) value: DOMString,
-> ErrorResult { priority: DOMString,
) -> 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(
&self.owner.base_url(), &value,
window.css_error_reporter(), &self.owner.base_url(),
quirks_mode); window.css_error_reporter(),
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,
window, stylerule: Arc<Locked<StyleRule>>,
CSSStyleRuleBinding::Wrap) ) -> DomRoot<CSSStyleRule> {
reflect_dom_object(
Box::new(CSSStyleRule::new_inherited(parent_stylesheet, stylerule)),
window,
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(
type_: DOMString, owner: &Element,
href: Option<DOMString>, type_: DOMString,
title: Option<DOMString>, href: Option<DOMString>,
stylesheet: Arc<StyleStyleSheet>) -> CSSStyleSheet { title: Option<DOMString>,
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(
owner: &Element, window: &Window,
type_: DOMString, owner: &Element,
href: Option<DOMString>, type_: DOMString,
title: Option<DOMString>, href: Option<DOMString>,
stylesheet: Arc<StyleStyleSheet>) -> DomRoot<CSSStyleSheet> { title: Option<DOMString>,
reflect_dom_object(Box::new(CSSStyleSheet::new_inherited(owner, type_, href, title, stylesheet)), stylesheet: Arc<StyleStyleSheet>,
window, ) -> DomRoot<CSSStyleSheet> {
CSSStyleSheetBinding::Wrap) reflect_dom_object(
Box::new(CSSStyleSheet::new_inherited(
owner, type_, href, title, stylesheet,
)),
window,
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,
window, supportsrule: Arc<Locked<SupportsRule>>,
CSSSupportsRuleBinding::Wrap) ) -> DomRoot<CSSSupportsRule> {
reflect_dom_object(
Box::new(CSSSupportsRule::new_inherited(
parent_stylesheet,
supportsrule,
)),
window,
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,
window, viewportrule: Arc<Locked<ViewportRule>>,
CSSViewportRuleBinding::Wrap) ) -> DomRoot<CSSViewportRule> {
reflect_dom_object(
Box::new(CSSViewportRule::new_inherited(
parent_stylesheet,
viewportrule,
)),
window,
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(
window, Box::new(CustomElementRegistry::new_inherited(window)),
CustomElementRegistryBinding::Wrap) window,
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(
local_name: &LocalName, &self,
is: Option<&LocalName>) local_name: &LocalName,
-> Option<Rc<CustomElementDefinition>> { is: Option<&LocalName>,
self.definitions.borrow().values().find(|definition| { ) -> Option<Rc<CustomElementDefinition>> {
// Step 4-5 self.definitions
definition.local_name == *local_name && .borrow()
(definition.name == *local_name || Some(&definition.name) == is) .values()
}).cloned() .find(|definition| {
// Step 4-5
definition.local_name == *local_name &&
(definition.name == *local_name || Some(&definition.name) == is)
}).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(
constructor, global_scope.get_cx(),
b"prototype\0".as_ptr() as *const _, constructor,
prototype) { b"prototype\0".as_ptr() as *const _,
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 {
constructor, !JS_GetProperty(
b"observedAttributes\0".as_ptr() as *const _, cx,
observed_attributes.handle_mut()) } { constructor,
b"observedAttributes\0".as_ptr() as *const _,
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(
local_name.clone(), name.clone(),
constructor_, local_name.clone(),
observed_attributes, constructor_,
callbacks)); observed_attributes,
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(
local_name: LocalName, name: LocalName,
constructor: Rc<CustomElementConstructor>, local_name: LocalName,
observed_attributes: Vec<DOMString>, constructor: Rc<CustomElementConstructor>,
callbacks: LifecycleCallbacks) observed_attributes: Vec<DOMString>,
-> CustomElementDefinition { callbacks: LifecycleCallbacks,
) -> 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> =
Ok(ConversionResult::Success(element)) => element, match unsafe { DomRoot::from_jsval(cx, element_val.handle(), ()) } {
Ok(ConversionResult::Failure(..)) => Ok(ConversionResult::Success(element)) => element,
return Err(Error::Type("Constructor did not return a DOM node".to_owned())), Ok(ConversionResult::Failure(..)) => {
_ => return Err(Error::JSFailed), return Err(Error::Type(
}; "Constructor did not return a DOM node".to_owned(),
))
},
_ => 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(
element: &Element, &self,
reaction: CallbackReaction, element: &Element,
definition: Option<Rc<CustomElementDefinition>>) { reaction: CallbackReaction,
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,145 +990,148 @@ 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 >= '0' && c <= '9') || c == '.' ||
(c >= 'a' && c <= 'z') || c == '_' ||
(c >= '\u{C0}' && c <= '\u{D6}') || c == '\u{B7}' ||
(c >= '\u{D8}' && c <= '\u{F6}') || (c >= '0' && c <= '9') ||
(c >= '\u{F8}' && c <= '\u{37D}') || (c >= 'a' && c <= 'z') ||
(c >= '\u{37F}' && c <= '\u{1FFF}') || (c >= '\u{C0}' && c <= '\u{D6}') ||
(c >= '\u{200C}' && c <= '\u{200D}') || (c >= '\u{D8}' && c <= '\u{F6}') ||
(c >= '\u{203F}' && c <= '\u{2040}') || (c >= '\u{F8}' && c <= '\u{37D}') ||
(c >= '\u{2070}' && c <= '\u{2FEF}') || (c >= '\u{37F}' && c <= '\u{1FFF}') ||
(c >= '\u{3001}' && c <= '\u{D7FF}') || (c >= '\u{200C}' && c <= '\u{200D}') ||
(c >= '\u{F900}' && c <= '\u{FDCF}') || (c >= '\u{203F}' && c <= '\u{2040}') ||
(c >= '\u{FDF0}' && c <= '\u{FFFD}') || (c >= '\u{2070}' && c <= '\u{2FEF}') ||
(c >= '\u{10000}' && c <= '\u{EFFFF}') (c >= '\u{3001}' && c <= '\u{D7FF}') ||
(c >= '\u{F900}' && c <= '\u{FDCF}') ||
(c >= '\u{FDF0}' && c <= '\u{FFFD}') ||
(c >= '\u{10000}' && c <= '\u{EFFFF}')
} }
fn is_extendable_element_interface(element: &str) -> bool { fn is_extendable_element_interface(element: &str) -> bool {
element == "a" || element == "a" ||
element == "abbr" || element == "abbr" ||
element == "acronym" || element == "acronym" ||
element == "address" || element == "address" ||
element == "area" || element == "area" ||
element == "article" || element == "article" ||
element == "aside" || element == "aside" ||
element == "audio" || element == "audio" ||
element == "b" || element == "b" ||
element == "base" || element == "base" ||
element == "bdi" || element == "bdi" ||
element == "bdo" || element == "bdo" ||
element == "big" || element == "big" ||
element == "blockquote" || element == "blockquote" ||
element == "body" || element == "body" ||
element == "br" || element == "br" ||
element == "button" || element == "button" ||
element == "canvas" || element == "canvas" ||
element == "caption" || element == "caption" ||
element == "center" || element == "center" ||
element == "cite" || element == "cite" ||
element == "code" || element == "code" ||
element == "col" || element == "col" ||
element == "colgroup" || element == "colgroup" ||
element == "data" || element == "data" ||
element == "datalist" || element == "datalist" ||
element == "dd" || element == "dd" ||
element == "del" || element == "del" ||
element == "details" || element == "details" ||
element == "dfn" || element == "dfn" ||
element == "dialog" || element == "dialog" ||
element == "dir" || element == "dir" ||
element == "div" || element == "div" ||
element == "dl" || element == "dl" ||
element == "dt" || element == "dt" ||
element == "em" || element == "em" ||
element == "embed" || element == "embed" ||
element == "fieldset" || element == "fieldset" ||
element == "figcaption" || element == "figcaption" ||
element == "figure" || element == "figure" ||
element == "font" || element == "font" ||
element == "footer" || element == "footer" ||
element == "form" || element == "form" ||
element == "frame" || element == "frame" ||
element == "frameset" || element == "frameset" ||
element == "h1" || element == "h1" ||
element == "h2" || element == "h2" ||
element == "h3" || element == "h3" ||
element == "h4" || element == "h4" ||
element == "h5" || element == "h5" ||
element == "h6" || element == "h6" ||
element == "head" || element == "head" ||
element == "header" || element == "header" ||
element == "hgroup" || element == "hgroup" ||
element == "hr" || element == "hr" ||
element == "html" || element == "html" ||
element == "i" || element == "i" ||
element == "iframe" || element == "iframe" ||
element == "img" || element == "img" ||
element == "input" || element == "input" ||
element == "ins" || element == "ins" ||
element == "kbd" || element == "kbd" ||
element == "label" || element == "label" ||
element == "legend" || element == "legend" ||
element == "li" || element == "li" ||
element == "link" || element == "link" ||
element == "listing" || element == "listing" ||
element == "main" || element == "main" ||
element == "map" || element == "map" ||
element == "mark" || element == "mark" ||
element == "marquee" || element == "marquee" ||
element == "meta" || element == "meta" ||
element == "meter" || element == "meter" ||
element == "nav" || element == "nav" ||
element == "nobr" || element == "nobr" ||
element == "noframes" || element == "noframes" ||
element == "noscript" || element == "noscript" ||
element == "object" || element == "object" ||
element == "ol" || element == "ol" ||
element == "optgroup" || element == "optgroup" ||
element == "option" || element == "option" ||
element == "output" || element == "output" ||
element == "p" || element == "p" ||
element == "param" || element == "param" ||
element == "plaintext" || element == "plaintext" ||
element == "pre" || element == "pre" ||
element == "progress" || element == "progress" ||
element == "q" || element == "q" ||
element == "rp" || element == "rp" ||
element == "rt" || element == "rt" ||
element == "ruby" || element == "ruby" ||
element == "s" || element == "s" ||
element == "samp" || element == "samp" ||
element == "script" || element == "script" ||
element == "section" || element == "section" ||
element == "select" || element == "select" ||
element == "small" || element == "small" ||
element == "source" || element == "source" ||
element == "span" || element == "span" ||
element == "strike" || element == "strike" ||
element == "strong" || element == "strong" ||
element == "style" || element == "style" ||
element == "sub" || element == "sub" ||
element == "summary" || element == "summary" ||
element == "sup" || element == "sup" ||
element == "table" || element == "table" ||
element == "tbody" || element == "tbody" ||
element == "td" || element == "td" ||
element == "template" || element == "template" ||
element == "textarea" || element == "textarea" ||
element == "tfoot" || element == "tfoot" ||
element == "th" || element == "th" ||
element == "thead" || element == "thead" ||
element == "time" || element == "time" ||
element == "title" || element == "title" ||
element == "tr" || element == "tr" ||
element == "tt" || element == "tt" ||
element == "track" || element == "track" ||
element == "u" || element == "u" ||
element == "ul" || element == "ul" ||
element == "var" || element == "var" ||
element == "video" || element == "video" ||
element == "wbr" || element == "wbr" ||
element == "xmp" element == "xmp"
} }

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(
global, Box::new(CustomEvent::new_inherited()),
CustomEventBinding::Wrap) global,
CustomEventBinding::Wrap,
)
} }
pub fn new(global: &GlobalScope, pub fn new(
type_: Atom, global: &GlobalScope,
bubbles: bool, type_: Atom,
cancelable: bool, bubbles: bool,
detail: HandleValue) cancelable: bool,
-> DomRoot<CustomEvent> { detail: HandleValue,
) -> 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(
type_: DOMString, global: &GlobalScope,
init: RootedTraceableBox<CustomEventBinding::CustomEventInit>) type_: DOMString,
-> Fallible<DomRoot<CustomEvent>> { init: RootedTraceableBox<CustomEventBinding::CustomEventInit>,
Ok(CustomEvent::new(global, ) -> Fallible<DomRoot<CustomEvent>> {
Atom::from(type_), Ok(CustomEvent::new(
init.parent.bubbles, global,
init.parent.cancelable, Atom::from(type_),
init.detail.handle())) init.parent.bubbles,
init.parent.cancelable,
init.detail.handle(),
))
} }
fn init_custom_event(&self, fn init_custom_event(
type_: Atom, &self,
can_bubble: bool, type_: Atom,
cancelable: bool, can_bubble: bool,
detail: HandleValue) { cancelable: bool,
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(
_cx: *mut JSContext, &self,
type_: DOMString, _cx: *mut JSContext,
can_bubble: bool, type_: DOMString,
cancelable: bool, can_bubble: bool,
detail: HandleValue) { cancelable: bool,
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,24 +198,27 @@ impl WorkerEventLoopMethods for DedicatedWorkerGlobalScope {
} }
impl DedicatedWorkerGlobalScope { impl DedicatedWorkerGlobalScope {
fn new_inherited(init: WorkerGlobalScopeInit, fn new_inherited(
worker_url: ServoUrl, init: WorkerGlobalScopeInit,
from_devtools_receiver: Receiver<DevtoolScriptControlMsg>, worker_url: ServoUrl,
runtime: Runtime, from_devtools_receiver: Receiver<DevtoolScriptControlMsg>,
parent_sender: Box<ScriptChan + Send>, runtime: Runtime,
own_sender: Sender<DedicatedWorkerScriptMsg>, parent_sender: Box<ScriptChan + Send>,
receiver: Receiver<DedicatedWorkerScriptMsg>, own_sender: Sender<DedicatedWorkerScriptMsg>,
timer_event_chan: IpcSender<TimerEvent>, receiver: Receiver<DedicatedWorkerScriptMsg>,
timer_event_port: Receiver<(TrustedWorkerAddress, TimerEvent)>, timer_event_chan: IpcSender<TimerEvent>,
closing: Arc<AtomicBool>) timer_event_port: Receiver<(TrustedWorkerAddress, TimerEvent)>,
-> DedicatedWorkerGlobalScope { closing: Arc<AtomicBool>,
) -> DedicatedWorkerGlobalScope {
DedicatedWorkerGlobalScope { DedicatedWorkerGlobalScope {
workerglobalscope: WorkerGlobalScope::new_inherited(init, workerglobalscope: WorkerGlobalScope::new_inherited(
worker_url, init,
runtime, worker_url,
from_devtools_receiver, runtime,
timer_event_chan, from_devtools_receiver,
Some(closing)), timer_event_chan,
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,17 +228,18 @@ impl DedicatedWorkerGlobalScope {
} }
#[allow(unsafe_code)] #[allow(unsafe_code)]
pub fn new(init: WorkerGlobalScopeInit, pub fn new(
worker_url: ServoUrl, init: WorkerGlobalScopeInit,
from_devtools_receiver: Receiver<DevtoolScriptControlMsg>, worker_url: ServoUrl,
runtime: Runtime, from_devtools_receiver: Receiver<DevtoolScriptControlMsg>,
parent_sender: Box<ScriptChan + Send>, runtime: Runtime,
own_sender: Sender<DedicatedWorkerScriptMsg>, parent_sender: Box<ScriptChan + Send>,
receiver: Receiver<DedicatedWorkerScriptMsg>, own_sender: Sender<DedicatedWorkerScriptMsg>,
timer_event_chan: IpcSender<TimerEvent>, receiver: Receiver<DedicatedWorkerScriptMsg>,
timer_event_port: Receiver<(TrustedWorkerAddress, TimerEvent)>, timer_event_chan: IpcSender<TimerEvent>,
closing: Arc<AtomicBool>) timer_event_port: Receiver<(TrustedWorkerAddress, TimerEvent)>,
-> DomRoot<DedicatedWorkerGlobalScope> { closing: Arc<AtomicBool>,
) -> 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,115 +251,147 @@ 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(
worker_url: ServoUrl, init: WorkerGlobalScopeInit,
from_devtools_receiver: IpcReceiver<DevtoolScriptControlMsg>, worker_url: ServoUrl,
worker: TrustedWorkerAddress, from_devtools_receiver: IpcReceiver<DevtoolScriptControlMsg>,
parent_sender: Box<ScriptChan + Send>, worker: TrustedWorkerAddress,
own_sender: Sender<DedicatedWorkerScriptMsg>, parent_sender: Box<ScriptChan + Send>,
receiver: Receiver<DedicatedWorkerScriptMsg>, own_sender: Sender<DedicatedWorkerScriptMsg>,
worker_load_origin: WorkerScriptLoadOrigin, receiver: Receiver<DedicatedWorkerScriptMsg>,
closing: Arc<AtomicBool>) { worker_load_origin: WorkerScriptLoadOrigin,
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()
thread_state::initialize(ThreadState::SCRIPT | ThreadState::IN_WORKER); .name(name)
.spawn(move || {
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 {
TopLevelBrowsingContextId::install(top_level_browsing_context_id); TopLevelBrowsingContextId::install(top_level_browsing_context_id);
} }
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(),
destination: Destination::Worker, destination: Destination::Worker,
credentials_mode: CredentialsMode::Include, credentials_mode: CredentialsMode::Include,
use_url_credentials: true, use_url_credentials: true,
pipeline_id: pipeline_id, pipeline_id: pipeline_id,
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
WorkerEvent, .send(CommonScriptMsg::Task(
Box::new(SimpleWorkerErrorHandler::new(worker)), WorkerEvent,
pipeline_id, Box::new(SimpleWorkerErrorHandler::new(worker)),
TaskSourceName::DOMManipulation, pipeline_id,
)).unwrap(); TaskSourceName::DOMManipulation,
)).unwrap();
return;
},
Ok((metadata, bytes)) => (metadata, bytes),
};
let url = metadata.final_url;
let source = String::from_utf8_lossy(&bytes);
let runtime = unsafe { new_rt_and_cx() };
let (devtools_mpsc_chan, devtools_mpsc_port) = channel();
route_ipc_receiver_to_new_servo_sender(from_devtools_receiver, devtools_mpsc_chan);
let (timer_tx, timer_rx) = channel();
let (timer_ipc_chan, timer_ipc_port) = ipc::channel().unwrap();
let worker_for_route = worker.clone();
ROUTER.add_route(
timer_ipc_port.to_opaque(),
Box::new(move |message| {
let event = message.to().unwrap();
timer_tx.send((worker_for_route.clone(), event)).unwrap();
}),
);
let global = DedicatedWorkerGlobalScope::new(
init,
url,
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
// registration (#6631), so we instead use a random number and cross our fingers.
let scope = global.upcast::<WorkerGlobalScope>();
unsafe {
// Handle interrupt requests
JS_AddInterruptCallback(scope.get_cx(), Some(interrupt_callback));
}
if scope.is_closing() {
return; return;
} }
Ok((metadata, bytes)) => (metadata, bytes)
};
let url = metadata.final_url;
let source = String::from_utf8_lossy(&bytes);
let runtime = unsafe { new_rt_and_cx() }; {
let _ar = AutoWorkerReset::new(&global, worker.clone());
let (devtools_mpsc_chan, devtools_mpsc_port) = channel(); scope.execute_script(DOMString::from(source));
route_ipc_receiver_to_new_servo_sender(from_devtools_receiver, devtools_mpsc_chan);
let (timer_tx, timer_rx) = channel();
let (timer_ipc_chan, timer_ipc_port) = ipc::channel().unwrap();
let worker_for_route = worker.clone();
ROUTER.add_route(timer_ipc_port.to_opaque(), Box::new(move |message| {
let event = message.to().unwrap();
timer_tx.send((worker_for_route.clone(), event)).unwrap();
}));
let global = DedicatedWorkerGlobalScope::new(
init, url, 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
// registration (#6631), so we instead use a random number and cross our fingers.
let scope = global.upcast::<WorkerGlobalScope>();
unsafe {
// Handle interrupt requests
JS_AddInterruptCallback(scope.get_cx(), Some(interrupt_callback));
}
if scope.is_closing() {
return;
}
{
let _ar = AutoWorkerReset::new(&global, worker.clone());
scope.execute_script(DOMString::from(source));
}
let reporter_name = format!("dedicated-worker-reporter-{}", random::<u64>());
scope.upcast::<GlobalScope>().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.
while !scope.is_closing() {
run_worker_event_loop(&*global, Some(&worker));
} }
}, reporter_name, parent_sender, CommonScriptMsg::CollectReports);
}).expect("Thread spawning failed"); let reporter_name = format!("dedicated-worker-reporter-{}", random::<u64>());
scope
.upcast::<GlobalScope>()
.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.
while !scope.is_closing() {
run_worker_event_loop(&*global, Some(&worker));
}
},
reporter_name,
parent_sender,
CommonScriptMsg::CollectReports,
);
}).expect("Thread spawning failed");
} }
pub fn script_chan(&self) -> Box<ScriptChan + Send> { pub fn script_chan(&self) -> Box<ScriptChan + Send> {
@ -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) => DevtoolScriptControlMsg::GetCachedMessages(pipe_id, message_types, sender) => {
devtools::handle_get_cached_messages(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), DevtoolScriptControlMsg::WantsLiveNotifications(_pipe_id, bool_val) => {
_ => debug!("got an unusable devtools control message inside the worker!"), 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)) => { MixedMessage::FromScheduler((linked_worker, timer_event)) => match 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(_, _) => panic!("A worker received a TimerEvent from a window."),
TimerEvent(_, _) => { },
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,20 +489,20 @@ 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
WorkerEvent, .send(CommonScriptMsg::Task(
task, WorkerEvent,
Some(pipeline_id), task,
TaskSourceName::DOMManipulation, Some(pipeline_id),
TaskSourceName::DOMManipulation,
)).unwrap(); )).unwrap();
} }
} }
#[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>());
// A false response causes the script to terminate // A false response causes the script to terminate
@ -483,12 +520,13 @@ 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
WorkerEvent, .send(CommonScriptMsg::Task(
task, WorkerEvent,
Some(pipeline_id), task,
TaskSourceName::DOMManipulation, Some(pipeline_id),
)).unwrap(); TaskSourceName::DOMManipulation,
)).unwrap();
Ok(()) Ok(())
} }

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(
window, Box::new(DissimilarOriginLocation::new_inherited(window)),
DissimilarOriginLocationBinding::Wrap) window,
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(
origin, self.window_proxy.browsing_context_id(),
data.move_to_arraybuffer()); origin,
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(
document, Box::new(DocumentFragment::new_inherited(document)),
DocumentFragmentBinding::Wrap) document,
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>)
None => false, .find(
Some(attr) => *attr.value().as_atom() == id, |descendant| match descendant.get_attribute(&ns!(), &local_name!("id")) {
} None => false,
}) 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(
public_id: Option<DOMString>, name: DOMString,
system_id: Option<DOMString>, public_id: Option<DOMString>,
document: &Document) system_id: Option<DOMString>,
-> DocumentType { document: &Document,
) -> 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(
public_id: Option<DOMString>, name: DOMString,
system_id: Option<DOMString>, public_id: Option<DOMString>,
document: &Document) system_id: Option<DOMString>,
-> DomRoot<DocumentType> { document: &Document,
Node::reflect_node(Box::new(DocumentType::new_inherited(name, public_id, system_id, document)), ) -> DomRoot<DocumentType> {
document, Node::reflect_node(
DocumentTypeBinding::Wrap) Box::new(DocumentType::new_inherited(
name, public_id, system_id, document,
)),
document,
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(
global, Box::new(DOMException::new_inherited(code)),
DOMExceptionBinding::Wrap) global,
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,57 +44,79 @@ 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(
window, Box::new(DOMImplementation::new_inherited(document)),
DOMImplementationBinding::Wrap) window,
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(
qualified_name: DOMString, &self,
pubid: DOMString, qualified_name: DOMString,
sysid: DOMString) pubid: DOMString,
-> Fallible<DomRoot<DocumentType>> { sysid: DOMString,
) -> 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(
maybe_namespace: Option<DOMString>, &self,
qname: DOMString, maybe_namespace: Option<DOMString>,
maybe_doctype: Option<&DocumentType>) qname: DOMString,
-> Fallible<DomRoot<XMLDocument>> { maybe_doctype: Option<&DocumentType>,
) -> 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(
HasBrowsingContext::No, win,
None, HasBrowsingContext::No,
self.document.origin().clone(), None,
IsHTMLDocument::NonHTMLDocument, self.document.origin().clone(),
Some(content_type), IsHTMLDocument::NonHTMLDocument,
None, Some(content_type),
DocumentActivity::Inactive, None,
DocumentSource::NotFromParser, DocumentActivity::Inactive,
loader); DocumentSource::NotFromParser,
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,19 +149,21 @@ 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(
HasBrowsingContext::No, win,
None, HasBrowsingContext::No,
self.document.origin().clone(), None,
IsHTMLDocument::HTMLDocument, self.document.origin().clone(),
None, IsHTMLDocument::HTMLDocument,
None, None,
DocumentActivity::Inactive, None,
DocumentSource::NotFromParser, DocumentActivity::Inactive,
loader, DocumentSource::NotFromParser,
None, loader,
None, None,
Default::default()); None,
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,21 +684,29 @@ 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.
if dict.a.is_some() && dict.m11.is_some() && dict.a.unwrap() != dict.m11.unwrap() || if dict.a.is_some() && dict.m11.is_some() && dict.a.unwrap() != dict.m11.unwrap() ||
dict.b.is_some() && dict.m12.is_some() && dict.b.unwrap() != dict.m12.unwrap() || dict.b.is_some() && dict.m12.is_some() && dict.b.unwrap() != dict.m12.unwrap() ||
dict.c.is_some() && dict.m21.is_some() && dict.c.unwrap() != dict.m21.unwrap() || dict.c.is_some() && dict.m21.is_some() && dict.c.unwrap() != dict.m21.unwrap() ||
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 ||
Err(error::Error::Type("Invalid matrix initializer.".to_owned())) 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()))
} else { } else {
let mut is2D = dict.is2D; let mut is2D = dict.is2D;
// Step 2. // Step 2.
@ -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 ||
is2D = Some(false); 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);
} }
// 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(
window, Box::new(DOMParser::new_inherited(window)),
DOMParserBinding::Wrap) window,
DOMParserBinding::Wrap,
)
} }
pub fn Constructor(window: &Window) -> Fallible<DomRoot<DOMParser>> { pub fn Constructor(window: &Window) -> Fallible<DomRoot<DOMParser>> {
@ -49,51 +51,59 @@ 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(
s: DOMString, &self,
ty: DOMParserBinding::SupportedType) s: DOMString,
-> Fallible<DomRoot<Document>> { ty: DOMParserBinding::SupportedType,
) -> 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(
HasBrowsingContext::No, &self.window,
Some(url.clone()), HasBrowsingContext::No,
doc.origin().clone(), Some(url.clone()),
IsHTMLDocument::HTMLDocument, doc.origin().clone(),
Some(content_type), IsHTMLDocument::HTMLDocument,
None, Some(content_type),
DocumentActivity::Inactive, None,
DocumentSource::FromParser, DocumentActivity::Inactive,
loader, DocumentSource::FromParser,
None, loader,
None, None,
Default::default()); None,
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(
HasBrowsingContext::No, &self.window,
Some(url.clone()), HasBrowsingContext::No,
doc.origin().clone(), Some(url.clone()),
IsHTMLDocument::NonHTMLDocument, doc.origin().clone(),
Some(content_type), IsHTMLDocument::NonHTMLDocument,
None, Some(content_type),
DocumentActivity::Inactive, None,
DocumentSource::FromParser, DocumentActivity::Inactive,
loader, DocumentSource::FromParser,
None, loader,
None, None,
Default::default()); None,
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(
x: f64, global: &GlobalScope,
y: f64, x: f64,
z: f64, y: f64,
w: f64) z: f64,
-> Fallible<DomRoot<DOMPoint>> { w: f64,
) -> 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(
global, Box::new(DOMPointReadOnly::new_inherited(x, y, z, w)),
Wrap) global,
Wrap,
)
} }
pub fn Constructor(global: &GlobalScope, pub fn Constructor(
x: f64, global: &GlobalScope,
y: f64, x: f64,
z: f64, y: f64,
w: f64) z: f64,
-> Fallible<DomRoot<DOMPointReadOnly>> { w: f64,
) -> 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(
p1: &DOMPoint, global: &GlobalScope,
p2: &DOMPoint, p1: &DOMPoint,
p3: &DOMPoint, p2: &DOMPoint,
p4: &DOMPoint) -> DomRoot<DOMQuad> { p3: &DOMPoint,
reflect_dom_object(Box::new(DOMQuad::new_inherited(p1, p2, p3, p4)), p4: &DOMPoint,
global, ) -> DomRoot<DOMQuad> {
Wrap) reflect_dom_object(
Box::new(DOMQuad::new_inherited(p1, p2, p3, p4)),
global,
Wrap,
)
} }
pub fn Constructor(global: &GlobalScope, pub fn Constructor(
p1: &DOMPointInit, global: &GlobalScope,
p2: &DOMPointInit, p1: &DOMPointInit,
p3: &DOMPointInit, p2: &DOMPointInit,
p4: &DOMPointInit) p3: &DOMPointInit,
-> Fallible<DomRoot<DOMQuad>> { p4: &DOMPointInit,
Ok(DOMQuad::new(global, ) -> Fallible<DomRoot<DOMQuad>> {
&*DOMPoint::new_from_init(global, p1), Ok(DOMQuad::new(
&*DOMPoint::new_from_init(global, p2), global,
&*DOMPoint::new_from_init(global, p3), &*DOMPoint::new_from_init(global, p1),
&*DOMPoint::new_from_init(global, p4))) &*DOMPoint::new_from_init(global, p2),
&*DOMPoint::new_from_init(global, p3),
&*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(
&*DOMPoint::new(global, other.x, other.y, 0f64, 1f64), global,
&*DOMPoint::new(global, other.x + other.width, other.y, 0f64, 1f64), &*DOMPoint::new(global, other.x, other.y, 0f64, 1f64),
&*DOMPoint::new(global, other.x + other.width, other.y + other.height, 0f64, 1f64), &*DOMPoint::new(global, other.x + other.width, other.y, 0f64, 1f64),
&*DOMPoint::new(global, other.x, other.y + other.height, 0f64, 1f64)) &*DOMPoint::new(
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(
&DOMPoint::new_from_init(global, &other.p1), global,
&DOMPoint::new_from_init(global, &other.p2), &DOMPoint::new_from_init(global, &other.p1),
&DOMPoint::new_from_init(global, &other.p3), &DOMPoint::new_from_init(global, &other.p2),
&DOMPoint::new_from_init(global, &other.p4)) &DOMPoint::new_from_init(global, &other.p3),
&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(
global, Box::new(DOMRect::new_inherited(x, y, width, height)),
DOMRectBinding::Wrap) global,
DOMRectBinding::Wrap,
)
} }
pub fn Constructor(global: &GlobalScope, pub fn Constructor(
x: f64, global: &GlobalScope,
y: f64, x: f64,
width: f64, y: f64,
height: f64) width: f64,
-> Fallible<DomRoot<DOMRect>> { height: f64,
) -> 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(
x: f64, global: &GlobalScope,
y: f64, x: f64,
width: f64, y: f64,
height: f64) width: f64,
-> DomRoot<DOMRectReadOnly> { height: f64,
reflect_dom_object(Box::new(DOMRectReadOnly::new_inherited(x, y, width, height)), ) -> DomRoot<DOMRectReadOnly> {
global, reflect_dom_object(
Wrap) Box::new(DOMRectReadOnly::new_inherited(x, y, width, height)),
global,
Wrap,
)
} }
pub fn Constructor(global: &GlobalScope, pub fn Constructor(
x: f64, global: &GlobalScope,
y: f64, x: f64,
width: f64, y: f64,
height: f64) width: f64,
-> Fallible<DomRoot<DOMRectReadOnly>> { height: f64,
) -> 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(
&*window, Box::new(DOMStringMap::new_inherited(element)),
DOMStringMapBinding::Wrap) &*window,
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(
&*window, Box::new(DOMTokenList::new_inherited(element, local_name.clone())),
DOMTokenListBinding::Wrap) &*window,
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