mirror of
https://github.com/servo/servo.git
synced 2025-06-13 02:44:29 +00:00
Format script component
This commit is contained in:
parent
2ca7a13473
commit
c37a345dc9
357 changed files with 25485 additions and 18076 deletions
|
@ -35,7 +35,7 @@ pub enum BodyType {
|
||||||
FormData,
|
FormData,
|
||||||
Json,
|
Json,
|
||||||
Text,
|
Text,
|
||||||
ArrayBuffer
|
ArrayBuffer,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum FetchedData {
|
pub enum FetchedData {
|
||||||
|
@ -44,7 +44,7 @@ pub enum FetchedData {
|
||||||
BlobData(DomRoot<Blob>),
|
BlobData(DomRoot<Blob>),
|
||||||
FormData(DomRoot<FormData>),
|
FormData(DomRoot<FormData>),
|
||||||
ArrayBuffer(RootedTraceableBox<Heap<*mut JSObject>>),
|
ArrayBuffer(RootedTraceableBox<Heap<*mut JSObject>>),
|
||||||
JSException(RootedTraceableBox<Heap<JSVal>>)
|
JSException(RootedTraceableBox<Heap<JSVal>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://fetch.spec.whatwg.org/#concept-body-consume-body
|
// https://fetch.spec.whatwg.org/#concept-body-consume-body
|
||||||
|
@ -72,19 +72,19 @@ pub fn consume_body<T: BodyOperations + DomObject>(object: &T, body_type: BodyTy
|
||||||
|
|
||||||
// https://fetch.spec.whatwg.org/#concept-body-consume-body
|
// https://fetch.spec.whatwg.org/#concept-body-consume-body
|
||||||
#[allow(unrooted_must_root)]
|
#[allow(unrooted_must_root)]
|
||||||
pub fn consume_body_with_promise<T: BodyOperations + DomObject>(object: &T,
|
pub fn consume_body_with_promise<T: BodyOperations + DomObject>(
|
||||||
|
object: &T,
|
||||||
body_type: BodyType,
|
body_type: BodyType,
|
||||||
promise: &Promise) {
|
promise: &Promise,
|
||||||
|
) {
|
||||||
// Step 5
|
// Step 5
|
||||||
let body = match object.take_body() {
|
let body = match object.take_body() {
|
||||||
Some(body) => body,
|
Some(body) => body,
|
||||||
None => return,
|
None => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
let pkg_data_results = run_package_data_algorithm(object,
|
let pkg_data_results =
|
||||||
body,
|
run_package_data_algorithm(object, body, body_type, object.get_mime_type());
|
||||||
body_type,
|
|
||||||
object.get_mime_type());
|
|
||||||
|
|
||||||
match pkg_data_results {
|
match pkg_data_results {
|
||||||
Ok(results) => {
|
Ok(results) => {
|
||||||
|
@ -103,11 +103,12 @@ pub fn consume_body_with_promise<T: BodyOperations + DomObject>(object: &T,
|
||||||
|
|
||||||
// https://fetch.spec.whatwg.org/#concept-body-package-data
|
// https://fetch.spec.whatwg.org/#concept-body-package-data
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
fn run_package_data_algorithm<T: BodyOperations + DomObject>(object: &T,
|
fn run_package_data_algorithm<T: BodyOperations + DomObject>(
|
||||||
|
object: &T,
|
||||||
bytes: Vec<u8>,
|
bytes: Vec<u8>,
|
||||||
body_type: BodyType,
|
body_type: BodyType,
|
||||||
mime_type: Ref<Vec<u8>>)
|
mime_type: Ref<Vec<u8>>,
|
||||||
-> Fallible<FetchedData> {
|
) -> Fallible<FetchedData> {
|
||||||
let global = object.global();
|
let global = object.global();
|
||||||
let cx = global.get_cx();
|
let cx = global.get_cx();
|
||||||
let mime = &*mime_type;
|
let mime = &*mime_type;
|
||||||
|
@ -116,40 +117,45 @@ fn run_package_data_algorithm<T: BodyOperations + DomObject>(object: &T,
|
||||||
BodyType::Json => run_json_data_algorithm(cx, bytes),
|
BodyType::Json => run_json_data_algorithm(cx, bytes),
|
||||||
BodyType::Blob => run_blob_data_algorithm(&global, bytes, mime),
|
BodyType::Blob => run_blob_data_algorithm(&global, bytes, mime),
|
||||||
BodyType::FormData => run_form_data_algorithm(&global, bytes, mime),
|
BodyType::FormData => run_form_data_algorithm(&global, bytes, mime),
|
||||||
BodyType::ArrayBuffer => unsafe {
|
BodyType::ArrayBuffer => unsafe { run_array_buffer_data_algorithm(cx, bytes) },
|
||||||
run_array_buffer_data_algorithm(cx, bytes)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_text_data_algorithm(bytes: Vec<u8>) -> Fallible<FetchedData> {
|
fn run_text_data_algorithm(bytes: Vec<u8>) -> Fallible<FetchedData> {
|
||||||
Ok(FetchedData::Text(String::from_utf8_lossy(&bytes).into_owned()))
|
Ok(FetchedData::Text(
|
||||||
|
String::from_utf8_lossy(&bytes).into_owned(),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
fn run_json_data_algorithm(cx: *mut JSContext,
|
fn run_json_data_algorithm(cx: *mut JSContext, bytes: Vec<u8>) -> Fallible<FetchedData> {
|
||||||
bytes: Vec<u8>) -> Fallible<FetchedData> {
|
|
||||||
let json_text = String::from_utf8_lossy(&bytes);
|
let json_text = String::from_utf8_lossy(&bytes);
|
||||||
let json_text: Vec<u16> = json_text.encode_utf16().collect();
|
let json_text: Vec<u16> = json_text.encode_utf16().collect();
|
||||||
rooted!(in(cx) let mut rval = UndefinedValue());
|
rooted!(in(cx) let mut rval = UndefinedValue());
|
||||||
unsafe {
|
unsafe {
|
||||||
if !JS_ParseJSON(cx,
|
if !JS_ParseJSON(
|
||||||
|
cx,
|
||||||
json_text.as_ptr(),
|
json_text.as_ptr(),
|
||||||
json_text.len() as u32,
|
json_text.len() as u32,
|
||||||
rval.handle_mut()) {
|
rval.handle_mut(),
|
||||||
|
) {
|
||||||
rooted!(in(cx) let mut exception = UndefinedValue());
|
rooted!(in(cx) let mut exception = UndefinedValue());
|
||||||
assert!(JS_GetPendingException(cx, exception.handle_mut()));
|
assert!(JS_GetPendingException(cx, exception.handle_mut()));
|
||||||
JS_ClearPendingException(cx);
|
JS_ClearPendingException(cx);
|
||||||
return Ok(FetchedData::JSException(RootedTraceableBox::from_box(Heap::boxed(exception.get()))));
|
return Ok(FetchedData::JSException(RootedTraceableBox::from_box(
|
||||||
|
Heap::boxed(exception.get()),
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
let rooted_heap = RootedTraceableBox::from_box(Heap::boxed(rval.get()));
|
let rooted_heap = RootedTraceableBox::from_box(Heap::boxed(rval.get()));
|
||||||
Ok(FetchedData::Json(rooted_heap))
|
Ok(FetchedData::Json(rooted_heap))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_blob_data_algorithm(root: &GlobalScope,
|
fn run_blob_data_algorithm(
|
||||||
|
root: &GlobalScope,
|
||||||
bytes: Vec<u8>,
|
bytes: Vec<u8>,
|
||||||
mime: &[u8]) -> Fallible<FetchedData> {
|
mime: &[u8],
|
||||||
|
) -> Fallible<FetchedData> {
|
||||||
let mime_string = if let Ok(s) = String::from_utf8(mime.to_vec()) {
|
let mime_string = if let Ok(s) = String::from_utf8(mime.to_vec()) {
|
||||||
s
|
s
|
||||||
} else {
|
} else {
|
||||||
|
@ -159,14 +165,19 @@ fn run_blob_data_algorithm(root: &GlobalScope,
|
||||||
Ok(FetchedData::BlobData(blob))
|
Ok(FetchedData::BlobData(blob))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_form_data_algorithm(root: &GlobalScope, bytes: Vec<u8>, mime: &[u8]) -> Fallible<FetchedData> {
|
fn run_form_data_algorithm(
|
||||||
|
root: &GlobalScope,
|
||||||
|
bytes: Vec<u8>,
|
||||||
|
mime: &[u8],
|
||||||
|
) -> Fallible<FetchedData> {
|
||||||
let mime_str = if let Ok(s) = str::from_utf8(mime) {
|
let mime_str = if let Ok(s) = str::from_utf8(mime) {
|
||||||
s
|
s
|
||||||
} else {
|
} else {
|
||||||
""
|
""
|
||||||
};
|
};
|
||||||
let mime: Mime = mime_str.parse().map_err(
|
let mime: Mime = mime_str
|
||||||
|_| Error::Type("Inappropriate MIME-type for Body".to_string()))?;
|
.parse()
|
||||||
|
.map_err(|_| Error::Type("Inappropriate MIME-type for Body".to_string()))?;
|
||||||
match mime {
|
match mime {
|
||||||
// TODO
|
// TODO
|
||||||
// ... Parser for Mime(TopLevel::Multipart, SubLevel::FormData, _)
|
// ... Parser for Mime(TopLevel::Multipart, SubLevel::FormData, _)
|
||||||
|
@ -184,9 +195,13 @@ fn run_form_data_algorithm(root: &GlobalScope, bytes: Vec<u8>, mime: &[u8]) -> F
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
unsafe fn run_array_buffer_data_algorithm(cx: *mut JSContext, bytes: Vec<u8>) -> Fallible<FetchedData> {
|
unsafe fn run_array_buffer_data_algorithm(
|
||||||
|
cx: *mut JSContext,
|
||||||
|
bytes: Vec<u8>,
|
||||||
|
) -> Fallible<FetchedData> {
|
||||||
rooted!(in(cx) let mut array_buffer_ptr = ptr::null_mut::<JSObject>());
|
rooted!(in(cx) let mut array_buffer_ptr = ptr::null_mut::<JSObject>());
|
||||||
let arraybuffer = ArrayBuffer::create(cx, CreateWith::Slice(&bytes), array_buffer_ptr.handle_mut());
|
let arraybuffer =
|
||||||
|
ArrayBuffer::create(cx, CreateWith::Slice(&bytes), array_buffer_ptr.handle_mut());
|
||||||
if arraybuffer.is_err() {
|
if arraybuffer.is_err() {
|
||||||
return Err(Error::JSFailed);
|
return Err(Error::JSFailed);
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,22 +31,34 @@ fn main() {
|
||||||
build.generator("Ninja");
|
build.generator("Ninja");
|
||||||
// because we're using ninja, we need to explicitly set these
|
// because we're using ninja, we need to explicitly set these
|
||||||
// to VC++, otherwise it'll try to use cc
|
// to VC++, otherwise it'll try to use cc
|
||||||
build.define("CMAKE_C_COMPILER", "cl.exe")
|
build
|
||||||
|
.define("CMAKE_C_COMPILER", "cl.exe")
|
||||||
.define("CMAKE_CXX_COMPILER", "cl.exe");
|
.define("CMAKE_CXX_COMPILER", "cl.exe");
|
||||||
// We have to explicitly specify the full path to link.exe,
|
// We have to explicitly specify the full path to link.exe,
|
||||||
// for reasons that I don't understand. If we just give
|
// for reasons that I don't understand. If we just give
|
||||||
// link.exe, it tries to use script-*/out/link.exe, which of
|
// link.exe, it tries to use script-*/out/link.exe, which of
|
||||||
// course does not exist.
|
// course does not exist.
|
||||||
let link = std::process::Command::new("where").arg("link.exe").output().unwrap();
|
let link = std::process::Command::new("where")
|
||||||
let link_path: Vec<&str> = std::str::from_utf8(&link.stdout).unwrap().split("\r\n").collect();
|
.arg("link.exe")
|
||||||
|
.output()
|
||||||
|
.unwrap();
|
||||||
|
let link_path: Vec<&str> = std::str::from_utf8(&link.stdout)
|
||||||
|
.unwrap()
|
||||||
|
.split("\r\n")
|
||||||
|
.collect();
|
||||||
build.define("CMAKE_LINKER", link_path[0]);
|
build.define("CMAKE_LINKER", link_path[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
build.build();
|
build.build();
|
||||||
|
|
||||||
println!("Binding generation completed in {}s", start.elapsed().as_secs());
|
println!(
|
||||||
|
"Binding generation completed in {}s",
|
||||||
|
start.elapsed().as_secs()
|
||||||
|
);
|
||||||
|
|
||||||
let json = PathBuf::from(env::var_os("OUT_DIR").unwrap()).join("build").join("InterfaceObjectMapData.json");
|
let json = PathBuf::from(env::var_os("OUT_DIR").unwrap())
|
||||||
|
.join("build")
|
||||||
|
.join("InterfaceObjectMapData.json");
|
||||||
let json: Value = serde_json::from_reader(File::open(&json).unwrap()).unwrap();
|
let json: Value = serde_json::from_reader(File::open(&json).unwrap()).unwrap();
|
||||||
let mut map = phf_codegen::Map::new();
|
let mut map = phf_codegen::Map::new();
|
||||||
for (key, value) in json.as_object().unwrap() {
|
for (key, value) in json.as_object().unwrap() {
|
||||||
|
@ -54,7 +66,10 @@ fn main() {
|
||||||
}
|
}
|
||||||
let phf = PathBuf::from(env::var_os("OUT_DIR").unwrap()).join("InterfaceObjectMapPhf.rs");
|
let phf = PathBuf::from(env::var_os("OUT_DIR").unwrap()).join("InterfaceObjectMapPhf.rs");
|
||||||
let mut phf = File::create(&phf).unwrap();
|
let mut phf = File::create(&phf).unwrap();
|
||||||
write!(&mut phf, "pub static MAP: phf::Map<&'static [u8], unsafe fn(*mut JSContext, HandleObject)> = ").unwrap();
|
write!(
|
||||||
|
&mut phf,
|
||||||
|
"pub static MAP: phf::Map<&'static [u8], unsafe fn(*mut JSContext, HandleObject)> = "
|
||||||
|
).unwrap();
|
||||||
map.build(&mut phf).unwrap();
|
map.build(&mut phf).unwrap();
|
||||||
write!(&mut phf, ";\n").unwrap();
|
write!(&mut phf, ";\n").unwrap();
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,6 @@ use std::str;
|
||||||
use style::properties::longhands::{margin_bottom, margin_left, margin_right, margin_top};
|
use style::properties::longhands::{margin_bottom, margin_left, margin_right, margin_top};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
pub fn handle_evaluate_js(global: &GlobalScope, eval: String, reply: IpcSender<EvaluateJSReply>) {
|
pub fn handle_evaluate_js(global: &GlobalScope, eval: String, reply: IpcSender<EvaluateJSReply>) {
|
||||||
// global.get_cx() returns a valid `JSContext` pointer, so this is safe.
|
// global.get_cx() returns a valid `JSContext` pointer, so this is safe.
|
||||||
|
@ -48,8 +47,11 @@ pub fn handle_evaluate_js(global: &GlobalScope, eval: String, reply: IpcSender<E
|
||||||
} else if rval.is_boolean() {
|
} else if rval.is_boolean() {
|
||||||
EvaluateJSReply::BooleanValue(rval.to_boolean())
|
EvaluateJSReply::BooleanValue(rval.to_boolean())
|
||||||
} else if rval.is_double() || rval.is_int32() {
|
} else if rval.is_double() || rval.is_int32() {
|
||||||
EvaluateJSReply::NumberValue(
|
EvaluateJSReply::NumberValue(match FromJSValConvertible::from_jsval(
|
||||||
match FromJSValConvertible::from_jsval(cx, rval.handle(), ()) {
|
cx,
|
||||||
|
rval.handle(),
|
||||||
|
(),
|
||||||
|
) {
|
||||||
Ok(ConversionResult::Success(v)) => v,
|
Ok(ConversionResult::Success(v)) => v,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
})
|
})
|
||||||
|
@ -73,65 +75,84 @@ pub fn handle_evaluate_js(global: &GlobalScope, eval: String, reply: IpcSender<E
|
||||||
reply.send(result).unwrap();
|
reply.send(result).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_get_root_node(documents: &Documents, pipeline: PipelineId, reply: IpcSender<Option<NodeInfo>>) {
|
pub fn handle_get_root_node(
|
||||||
let info = documents.find_document(pipeline)
|
documents: &Documents,
|
||||||
|
pipeline: PipelineId,
|
||||||
|
reply: IpcSender<Option<NodeInfo>>,
|
||||||
|
) {
|
||||||
|
let info = documents
|
||||||
|
.find_document(pipeline)
|
||||||
.map(|document| document.upcast::<Node>().summarize());
|
.map(|document| document.upcast::<Node>().summarize());
|
||||||
reply.send(info).unwrap();
|
reply.send(info).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_get_document_element(documents: &Documents,
|
pub fn handle_get_document_element(
|
||||||
|
documents: &Documents,
|
||||||
pipeline: PipelineId,
|
pipeline: PipelineId,
|
||||||
reply: IpcSender<Option<NodeInfo>>) {
|
reply: IpcSender<Option<NodeInfo>>,
|
||||||
let info = documents.find_document(pipeline)
|
) {
|
||||||
|
let info = documents
|
||||||
|
.find_document(pipeline)
|
||||||
.and_then(|document| document.GetDocumentElement())
|
.and_then(|document| document.GetDocumentElement())
|
||||||
.map(|element| element.upcast::<Node>().summarize());
|
.map(|element| element.upcast::<Node>().summarize());
|
||||||
reply.send(info).unwrap();
|
reply.send(info).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_node_by_unique_id(documents: &Documents,
|
fn find_node_by_unique_id(
|
||||||
|
documents: &Documents,
|
||||||
pipeline: PipelineId,
|
pipeline: PipelineId,
|
||||||
node_id: &str)
|
node_id: &str,
|
||||||
-> Option<DomRoot<Node>> {
|
) -> Option<DomRoot<Node>> {
|
||||||
documents.find_document(pipeline).and_then(|document|
|
documents.find_document(pipeline).and_then(|document| {
|
||||||
document.upcast::<Node>().traverse_preorder().find(|candidate| candidate.unique_id() == node_id)
|
document
|
||||||
)
|
.upcast::<Node>()
|
||||||
|
.traverse_preorder()
|
||||||
|
.find(|candidate| candidate.unique_id() == node_id)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_get_children(documents: &Documents,
|
pub fn handle_get_children(
|
||||||
|
documents: &Documents,
|
||||||
pipeline: PipelineId,
|
pipeline: PipelineId,
|
||||||
node_id: String,
|
node_id: String,
|
||||||
reply: IpcSender<Option<Vec<NodeInfo>>>) {
|
reply: IpcSender<Option<Vec<NodeInfo>>>,
|
||||||
|
) {
|
||||||
match find_node_by_unique_id(documents, pipeline, &*node_id) {
|
match find_node_by_unique_id(documents, pipeline, &*node_id) {
|
||||||
None => return reply.send(None).unwrap(),
|
None => return reply.send(None).unwrap(),
|
||||||
Some(parent) => {
|
Some(parent) => {
|
||||||
let children = parent.children()
|
let children = parent.children().map(|child| child.summarize()).collect();
|
||||||
.map(|child| child.summarize())
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
reply.send(Some(children)).unwrap();
|
reply.send(Some(children)).unwrap();
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_get_layout(documents: &Documents,
|
pub fn handle_get_layout(
|
||||||
|
documents: &Documents,
|
||||||
pipeline: PipelineId,
|
pipeline: PipelineId,
|
||||||
node_id: String,
|
node_id: String,
|
||||||
reply: IpcSender<Option<ComputedNodeLayout>>) {
|
reply: IpcSender<Option<ComputedNodeLayout>>,
|
||||||
|
) {
|
||||||
let node = match find_node_by_unique_id(documents, pipeline, &*node_id) {
|
let node = match find_node_by_unique_id(documents, pipeline, &*node_id) {
|
||||||
None => return reply.send(None).unwrap(),
|
None => return reply.send(None).unwrap(),
|
||||||
Some(found_node) => found_node
|
Some(found_node) => found_node,
|
||||||
};
|
};
|
||||||
|
|
||||||
let elem = node.downcast::<Element>().expect("should be getting layout of element");
|
let elem = node
|
||||||
|
.downcast::<Element>()
|
||||||
|
.expect("should be getting layout of element");
|
||||||
let rect = elem.GetBoundingClientRect();
|
let rect = elem.GetBoundingClientRect();
|
||||||
let width = rect.Width() as f32;
|
let width = rect.Width() as f32;
|
||||||
let height = rect.Height() as f32;
|
let height = rect.Height() as f32;
|
||||||
|
|
||||||
let window = window_from_node(&*node);
|
let window = window_from_node(&*node);
|
||||||
let elem = node.downcast::<Element>().expect("should be getting layout of element");
|
let elem = node
|
||||||
|
.downcast::<Element>()
|
||||||
|
.expect("should be getting layout of element");
|
||||||
let computed_style = window.GetComputedStyle(elem, None);
|
let computed_style = window.GetComputedStyle(elem, None);
|
||||||
|
|
||||||
reply.send(Some(ComputedNodeLayout {
|
reply
|
||||||
|
.send(Some(ComputedNodeLayout {
|
||||||
display: String::from(computed_style.Display()),
|
display: String::from(computed_style.Display()),
|
||||||
position: String::from(computed_style.Position()),
|
position: String::from(computed_style.Position()),
|
||||||
zIndex: String::from(computed_style.ZIndex()),
|
zIndex: String::from(computed_style.ZIndex()),
|
||||||
|
@ -165,9 +186,11 @@ fn determine_auto_margins(window: &Window, node: &Node) -> AutoMargins {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_get_cached_messages(_pipeline_id: PipelineId,
|
pub fn handle_get_cached_messages(
|
||||||
|
_pipeline_id: PipelineId,
|
||||||
message_types: CachedConsoleMessageTypes,
|
message_types: CachedConsoleMessageTypes,
|
||||||
reply: IpcSender<Vec<CachedConsoleMessage>>) {
|
reply: IpcSender<Vec<CachedConsoleMessage>>,
|
||||||
|
) {
|
||||||
// TODO: check the messageTypes against a global Cache for console messages and page exceptions
|
// TODO: check the messageTypes against a global Cache for console messages and page exceptions
|
||||||
let mut messages = Vec::new();
|
let mut messages = Vec::new();
|
||||||
if message_types.contains(CachedConsoleMessageTypes::PAGE_ERROR) {
|
if message_types.contains(CachedConsoleMessageTypes::PAGE_ERROR) {
|
||||||
|
@ -207,22 +230,33 @@ pub fn handle_get_cached_messages(_pipeline_id: PipelineId,
|
||||||
reply.send(messages).unwrap();
|
reply.send(messages).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_modify_attribute(documents: &Documents,
|
pub fn handle_modify_attribute(
|
||||||
|
documents: &Documents,
|
||||||
pipeline: PipelineId,
|
pipeline: PipelineId,
|
||||||
node_id: String,
|
node_id: String,
|
||||||
modifications: Vec<Modification>) {
|
modifications: Vec<Modification>,
|
||||||
|
) {
|
||||||
let node = match find_node_by_unique_id(documents, pipeline, &*node_id) {
|
let node = match find_node_by_unique_id(documents, pipeline, &*node_id) {
|
||||||
None => return warn!("node id {} for pipeline id {} is not found", &node_id, &pipeline),
|
None => {
|
||||||
Some(found_node) => found_node
|
return warn!(
|
||||||
|
"node id {} for pipeline id {} is not found",
|
||||||
|
&node_id, &pipeline
|
||||||
|
)
|
||||||
|
},
|
||||||
|
Some(found_node) => found_node,
|
||||||
};
|
};
|
||||||
|
|
||||||
let elem = node.downcast::<Element>().expect("should be getting layout of element");
|
let elem = node
|
||||||
|
.downcast::<Element>()
|
||||||
|
.expect("should be getting layout of element");
|
||||||
|
|
||||||
for modification in modifications {
|
for modification in modifications {
|
||||||
match modification.newValue {
|
match modification.newValue {
|
||||||
Some(string) => {
|
Some(string) => {
|
||||||
let _ = elem.SetAttribute(DOMString::from(modification.attributeName),
|
let _ = elem.SetAttribute(
|
||||||
DOMString::from(string));
|
DOMString::from(modification.attributeName),
|
||||||
|
DOMString::from(string),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
None => elem.RemoveAttribute(DOMString::from(modification.attributeName)),
|
None => elem.RemoveAttribute(DOMString::from(modification.attributeName)),
|
||||||
}
|
}
|
||||||
|
@ -233,34 +267,35 @@ pub fn handle_wants_live_notifications(global: &GlobalScope, send_notifications:
|
||||||
global.set_devtools_wants_updates(send_notifications);
|
global.set_devtools_wants_updates(send_notifications);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_set_timeline_markers(documents: &Documents,
|
pub fn handle_set_timeline_markers(
|
||||||
|
documents: &Documents,
|
||||||
pipeline: PipelineId,
|
pipeline: PipelineId,
|
||||||
marker_types: Vec<TimelineMarkerType>,
|
marker_types: Vec<TimelineMarkerType>,
|
||||||
reply: IpcSender<Option<TimelineMarker>>) {
|
reply: IpcSender<Option<TimelineMarker>>,
|
||||||
|
) {
|
||||||
match documents.find_window(pipeline) {
|
match documents.find_window(pipeline) {
|
||||||
None => reply.send(None).unwrap(),
|
None => reply.send(None).unwrap(),
|
||||||
Some(window) => window.set_devtools_timeline_markers(marker_types, reply),
|
Some(window) => window.set_devtools_timeline_markers(marker_types, reply),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_drop_timeline_markers(documents: &Documents,
|
pub fn handle_drop_timeline_markers(
|
||||||
|
documents: &Documents,
|
||||||
pipeline: PipelineId,
|
pipeline: PipelineId,
|
||||||
marker_types: Vec<TimelineMarkerType>) {
|
marker_types: Vec<TimelineMarkerType>,
|
||||||
|
) {
|
||||||
if let Some(window) = documents.find_window(pipeline) {
|
if let Some(window) = documents.find_window(pipeline) {
|
||||||
window.drop_devtools_timeline_markers(marker_types);
|
window.drop_devtools_timeline_markers(marker_types);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_request_animation_frame(documents: &Documents,
|
pub fn handle_request_animation_frame(documents: &Documents, id: PipelineId, actor_name: String) {
|
||||||
id: PipelineId,
|
|
||||||
actor_name: String) {
|
|
||||||
if let Some(doc) = documents.find_document(id) {
|
if let Some(doc) = documents.find_document(id) {
|
||||||
doc.request_animation_frame(AnimationFrameCallback::DevtoolsFramerateTick { actor_name });
|
doc.request_animation_frame(AnimationFrameCallback::DevtoolsFramerateTick { actor_name });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_reload(documents: &Documents,
|
pub fn handle_reload(documents: &Documents, id: PipelineId) {
|
||||||
id: PipelineId) {
|
|
||||||
if let Some(win) = documents.find_window(id) {
|
if let Some(win) = documents.find_window(id) {
|
||||||
win.Location().reload_without_origin_check();
|
win.Location().reload_without_origin_check();
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,8 +96,10 @@ impl DocumentLoader {
|
||||||
DocumentLoader::new_with_threads(existing.resource_threads.clone(), None)
|
DocumentLoader::new_with_threads(existing.resource_threads.clone(), None)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_with_threads(resource_threads: ResourceThreads,
|
pub fn new_with_threads(
|
||||||
initial_load: Option<ServoUrl>) -> DocumentLoader {
|
resource_threads: ResourceThreads,
|
||||||
|
initial_load: Option<ServoUrl>,
|
||||||
|
) -> DocumentLoader {
|
||||||
debug!("Initial blocking load {:?}.", initial_load);
|
debug!("Initial blocking load {:?}.", initial_load);
|
||||||
let initial_loads = initial_load.into_iter().map(LoadType::PageSource).collect();
|
let initial_loads = initial_load.into_iter().map(LoadType::PageSource).collect();
|
||||||
|
|
||||||
|
@ -105,7 +107,7 @@ impl DocumentLoader {
|
||||||
resource_threads: resource_threads,
|
resource_threads: resource_threads,
|
||||||
blocking_loads: initial_loads,
|
blocking_loads: initial_loads,
|
||||||
events_inhibited: false,
|
events_inhibited: false,
|
||||||
cancellers: Vec::new()
|
cancellers: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,35 +120,55 @@ impl DocumentLoader {
|
||||||
|
|
||||||
/// Add a load to the list of blocking loads.
|
/// Add a load to the list of blocking loads.
|
||||||
fn add_blocking_load(&mut self, load: LoadType) {
|
fn add_blocking_load(&mut self, load: LoadType) {
|
||||||
debug!("Adding blocking load {:?} ({}).", load, self.blocking_loads.len());
|
debug!(
|
||||||
|
"Adding blocking load {:?} ({}).",
|
||||||
|
load,
|
||||||
|
self.blocking_loads.len()
|
||||||
|
);
|
||||||
self.blocking_loads.push(load);
|
self.blocking_loads.push(load);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initiate a new fetch.
|
/// Initiate a new fetch.
|
||||||
pub fn fetch_async(&mut self,
|
pub fn fetch_async(
|
||||||
|
&mut self,
|
||||||
load: LoadType,
|
load: LoadType,
|
||||||
request: RequestInit,
|
request: RequestInit,
|
||||||
fetch_target: IpcSender<FetchResponseMsg>) {
|
fetch_target: IpcSender<FetchResponseMsg>,
|
||||||
|
) {
|
||||||
self.add_blocking_load(load);
|
self.add_blocking_load(load);
|
||||||
self.fetch_async_background(request, fetch_target);
|
self.fetch_async_background(request, fetch_target);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initiate a new fetch that does not block the document load event.
|
/// Initiate a new fetch that does not block the document load event.
|
||||||
pub fn fetch_async_background(&mut self,
|
pub fn fetch_async_background(
|
||||||
|
&mut self,
|
||||||
request: RequestInit,
|
request: RequestInit,
|
||||||
fetch_target: IpcSender<FetchResponseMsg>) {
|
fetch_target: IpcSender<FetchResponseMsg>,
|
||||||
|
) {
|
||||||
let mut canceller = FetchCanceller::new();
|
let mut canceller = FetchCanceller::new();
|
||||||
let cancel_receiver = canceller.initialize();
|
let cancel_receiver = canceller.initialize();
|
||||||
self.cancellers.push(canceller);
|
self.cancellers.push(canceller);
|
||||||
self.resource_threads.sender().send(
|
self.resource_threads
|
||||||
CoreResourceMsg::Fetch(request, FetchChannels::ResponseMsg(fetch_target, Some(cancel_receiver)))).unwrap();
|
.sender()
|
||||||
|
.send(CoreResourceMsg::Fetch(
|
||||||
|
request,
|
||||||
|
FetchChannels::ResponseMsg(fetch_target, Some(cancel_receiver)),
|
||||||
|
)).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Mark an in-progress network request complete.
|
/// Mark an in-progress network request complete.
|
||||||
pub fn finish_load(&mut self, load: &LoadType) {
|
pub fn finish_load(&mut self, load: &LoadType) {
|
||||||
debug!("Removing blocking load {:?} ({}).", load, self.blocking_loads.len());
|
debug!(
|
||||||
let idx = self.blocking_loads.iter().position(|unfinished| *unfinished == *load);
|
"Removing blocking load {:?} ({}).",
|
||||||
self.blocking_loads.remove(idx.unwrap_or_else(|| panic!("unknown completed load {:?}", load)));
|
load,
|
||||||
|
self.blocking_loads.len()
|
||||||
|
);
|
||||||
|
let idx = self
|
||||||
|
.blocking_loads
|
||||||
|
.iter()
|
||||||
|
.position(|unfinished| *unfinished == *load);
|
||||||
|
self.blocking_loads
|
||||||
|
.remove(idx.unwrap_or_else(|| panic!("unknown completed load {:?}", load)));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_blocked(&self) -> bool {
|
pub fn is_blocked(&self) -> bool {
|
||||||
|
@ -157,7 +179,7 @@ impl DocumentLoader {
|
||||||
pub fn is_only_blocked_by_iframes(&self) -> bool {
|
pub fn is_only_blocked_by_iframes(&self) -> bool {
|
||||||
self.blocking_loads.iter().all(|load| match *load {
|
self.blocking_loads.iter().all(|load| match *load {
|
||||||
LoadType::Subframe(_) => true,
|
LoadType::Subframe(_) => true,
|
||||||
_ => false
|
_ => false,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,12 +56,14 @@ pub enum ActivationSource {
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#run-synthetic-click-activation-steps
|
// https://html.spec.whatwg.org/multipage/#run-synthetic-click-activation-steps
|
||||||
pub fn synthetic_click_activation(element: &Element,
|
pub fn synthetic_click_activation(
|
||||||
|
element: &Element,
|
||||||
ctrl_key: bool,
|
ctrl_key: bool,
|
||||||
shift_key: bool,
|
shift_key: bool,
|
||||||
alt_key: bool,
|
alt_key: bool,
|
||||||
meta_key: bool,
|
meta_key: bool,
|
||||||
source: ActivationSource) {
|
source: ActivationSource,
|
||||||
|
) {
|
||||||
// Step 1
|
// Step 1
|
||||||
if element.click_in_progress() {
|
if element.click_in_progress() {
|
||||||
return;
|
return;
|
||||||
|
@ -78,7 +80,8 @@ pub fn synthetic_click_activation(element: &Element,
|
||||||
// https://html.spec.whatwg.org/multipage/#fire-a-synthetic-mouse-event
|
// https://html.spec.whatwg.org/multipage/#fire-a-synthetic-mouse-event
|
||||||
let win = window_from_node(element);
|
let win = window_from_node(element);
|
||||||
let target = element.upcast::<EventTarget>();
|
let target = element.upcast::<EventTarget>();
|
||||||
let mouse = MouseEvent::new(&win,
|
let mouse = MouseEvent::new(
|
||||||
|
&win,
|
||||||
DOMString::from("click"),
|
DOMString::from("click"),
|
||||||
EventBubbles::DoesNotBubble,
|
EventBubbles::DoesNotBubble,
|
||||||
EventCancelable::NotCancelable,
|
EventCancelable::NotCancelable,
|
||||||
|
@ -94,7 +97,8 @@ pub fn synthetic_click_activation(element: &Element,
|
||||||
meta_key,
|
meta_key,
|
||||||
0,
|
0,
|
||||||
None,
|
None,
|
||||||
None);
|
None,
|
||||||
|
);
|
||||||
let event = mouse.upcast::<Event>();
|
let event = mouse.upcast::<Event>();
|
||||||
if source == ActivationSource::FromClick {
|
if source == ActivationSource::FromClick {
|
||||||
event.set_trusted(false);
|
event.set_trusted(false);
|
||||||
|
|
|
@ -36,13 +36,14 @@ pub struct Attr {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Attr {
|
impl Attr {
|
||||||
fn new_inherited(local_name: LocalName,
|
fn new_inherited(
|
||||||
|
local_name: LocalName,
|
||||||
value: AttrValue,
|
value: AttrValue,
|
||||||
name: LocalName,
|
name: LocalName,
|
||||||
namespace: Namespace,
|
namespace: Namespace,
|
||||||
prefix: Option<Prefix>,
|
prefix: Option<Prefix>,
|
||||||
owner: Option<&Element>)
|
owner: Option<&Element>,
|
||||||
-> Attr {
|
) -> Attr {
|
||||||
Attr {
|
Attr {
|
||||||
reflector_: Reflector::new(),
|
reflector_: Reflector::new(),
|
||||||
identifier: AttrIdentifier {
|
identifier: AttrIdentifier {
|
||||||
|
@ -56,25 +57,21 @@ impl Attr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(window: &Window,
|
pub fn new(
|
||||||
|
window: &Window,
|
||||||
local_name: LocalName,
|
local_name: LocalName,
|
||||||
value: AttrValue,
|
value: AttrValue,
|
||||||
name: LocalName,
|
name: LocalName,
|
||||||
namespace: Namespace,
|
namespace: Namespace,
|
||||||
prefix: Option<Prefix>,
|
prefix: Option<Prefix>,
|
||||||
owner: Option<&Element>)
|
owner: Option<&Element>,
|
||||||
-> DomRoot<Attr> {
|
) -> DomRoot<Attr> {
|
||||||
reflect_dom_object(
|
reflect_dom_object(
|
||||||
Box::new(Attr::new_inherited(
|
Box::new(Attr::new_inherited(
|
||||||
local_name,
|
local_name, value, name, namespace, prefix, owner,
|
||||||
value,
|
|
||||||
name,
|
|
||||||
namespace,
|
|
||||||
prefix,
|
|
||||||
owner
|
|
||||||
)),
|
)),
|
||||||
window,
|
window,
|
||||||
AttrBinding::Wrap
|
AttrBinding::Wrap,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,9 +107,7 @@ impl AttrMethods for Attr {
|
||||||
// https://dom.spec.whatwg.org/#dom-attr-value
|
// https://dom.spec.whatwg.org/#dom-attr-value
|
||||||
fn SetValue(&self, value: DOMString) {
|
fn SetValue(&self, value: DOMString) {
|
||||||
if let Some(owner) = self.owner() {
|
if let Some(owner) = self.owner() {
|
||||||
let value = owner.parse_attribute(&self.identifier.namespace,
|
let value = owner.parse_attribute(&self.identifier.namespace, self.local_name(), value);
|
||||||
self.local_name(),
|
|
||||||
value);
|
|
||||||
self.set_value(value, &owner);
|
self.set_value(value, &owner);
|
||||||
} else {
|
} else {
|
||||||
*self.value.borrow_mut() = AttrValue::String(value.into());
|
*self.value.borrow_mut() = AttrValue::String(value.into());
|
||||||
|
@ -175,7 +170,6 @@ impl AttrMethods for Attr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl Attr {
|
impl Attr {
|
||||||
pub fn set_value(&self, mut value: AttrValue, owner: &Element) {
|
pub fn set_value(&self, mut value: AttrValue, owner: &Element) {
|
||||||
let name = self.local_name().clone();
|
let name = self.local_name().clone();
|
||||||
|
@ -191,7 +185,12 @@ impl Attr {
|
||||||
MutationObserver::queue_a_mutation_record(owner.upcast::<Node>(), mutation);
|
MutationObserver::queue_a_mutation_record(owner.upcast::<Node>(), mutation);
|
||||||
|
|
||||||
if owner.get_custom_element_definition().is_some() {
|
if owner.get_custom_element_definition().is_some() {
|
||||||
let reaction = CallbackReaction::AttributeChanged(name, Some(old_value), Some(new_value), namespace);
|
let reaction = CallbackReaction::AttributeChanged(
|
||||||
|
name,
|
||||||
|
Some(old_value),
|
||||||
|
Some(new_value),
|
||||||
|
namespace,
|
||||||
|
);
|
||||||
ScriptThread::enqueue_callback_reaction(owner, reaction, None);
|
ScriptThread::enqueue_callback_reaction(owner, reaction, None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -229,7 +228,7 @@ impl Attr {
|
||||||
(Some(old), None) => {
|
(Some(old), None) => {
|
||||||
// Already gone from the list of attributes of old owner.
|
// Already gone from the list of attributes of old owner.
|
||||||
assert!(old.get_attribute(&ns, &self.identifier.local_name).r() != Some(self))
|
assert!(old.get_attribute(&ns, &self.identifier.local_name).r() != Some(self))
|
||||||
}
|
},
|
||||||
(Some(old), Some(new)) => assert_eq!(&*old, new),
|
(Some(old), Some(new)) => assert_eq!(&*old, new),
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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(),
|
||||||
|
|
|
@ -28,10 +28,7 @@ pub struct AudioListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AudioListener {
|
impl AudioListener {
|
||||||
fn new_inherited(
|
fn new_inherited(window: &Window, context: &BaseAudioContext) -> AudioListener {
|
||||||
window: &Window,
|
|
||||||
context: &BaseAudioContext,
|
|
||||||
) -> AudioListener {
|
|
||||||
let node = context.listener();
|
let node = context.listener();
|
||||||
|
|
||||||
let position_x = AudioParam::new(
|
let position_x = AudioParam::new(
|
||||||
|
@ -139,10 +136,7 @@ impl AudioListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unrooted_must_root)]
|
#[allow(unrooted_must_root)]
|
||||||
pub fn new(
|
pub fn new(window: &Window, context: &BaseAudioContext) -> DomRoot<AudioListener> {
|
||||||
window: &Window,
|
|
||||||
context: &BaseAudioContext,
|
|
||||||
) -> DomRoot<AudioListener> {
|
|
||||||
let node = AudioListener::new_inherited(window, context);
|
let node = AudioListener::new_inherited(window, context);
|
||||||
reflect_dom_object(Box::new(node), window, AudioListenerBinding::Wrap)
|
reflect_dom_object(Box::new(node), window, AudioListenerBinding::Wrap)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -98,7 +98,9 @@ impl BaseAudioContext {
|
||||||
pub fn new_inherited(options: BaseAudioContextOptions) -> BaseAudioContext {
|
pub fn new_inherited(options: BaseAudioContextOptions) -> BaseAudioContext {
|
||||||
let (sample_rate, channel_count) = match options {
|
let (sample_rate, channel_count) = match options {
|
||||||
BaseAudioContextOptions::AudioContext(ref opt) => (opt.sample_rate, 2),
|
BaseAudioContextOptions::AudioContext(ref opt) => (opt.sample_rate, 2),
|
||||||
BaseAudioContextOptions::OfflineAudioContext(ref opt) => (opt.sample_rate, opt.channels),
|
BaseAudioContextOptions::OfflineAudioContext(ref opt) => {
|
||||||
|
(opt.sample_rate, opt.channels)
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
let context = BaseAudioContext {
|
let context = BaseAudioContext {
|
||||||
|
@ -312,9 +314,7 @@ impl BaseAudioContextMethods for BaseAudioContext {
|
||||||
fn Listener(&self) -> DomRoot<AudioListener> {
|
fn Listener(&self) -> DomRoot<AudioListener> {
|
||||||
let global = self.global();
|
let global = self.global();
|
||||||
let window = global.as_window();
|
let window = global.as_window();
|
||||||
self.listener.or_init(|| {
|
self.listener.or_init(|| AudioListener::new(&window, self))
|
||||||
AudioListener::new(&window, self)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-onstatechange
|
/// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-onstatechange
|
||||||
|
@ -425,12 +425,10 @@ impl BaseAudioContextMethods for BaseAudioContext {
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.resize(channel_count as usize, Vec::new());
|
.resize(channel_count as usize, Vec::new());
|
||||||
})
|
}).progress(move |buffer, channel| {
|
||||||
.progress(move |buffer, channel| {
|
|
||||||
let mut decoded_audio = decoded_audio_.lock().unwrap();
|
let mut decoded_audio = decoded_audio_.lock().unwrap();
|
||||||
decoded_audio[(channel - 1) as usize].extend_from_slice((*buffer).as_ref());
|
decoded_audio[(channel - 1) as usize].extend_from_slice((*buffer).as_ref());
|
||||||
})
|
}).eos(move || {
|
||||||
.eos(move || {
|
|
||||||
let _ = task_source.queue_with_canceller(
|
let _ = task_source.queue_with_canceller(
|
||||||
task!(audio_decode_eos: move || {
|
task!(audio_decode_eos: move || {
|
||||||
let this = this.root();
|
let this = this.root();
|
||||||
|
@ -456,8 +454,7 @@ impl BaseAudioContextMethods for BaseAudioContext {
|
||||||
}),
|
}),
|
||||||
&canceller,
|
&canceller,
|
||||||
);
|
);
|
||||||
})
|
}).error(move || {
|
||||||
.error(move || {
|
|
||||||
let _ = task_source_.queue_with_canceller(
|
let _ = task_source_.queue_with_canceller(
|
||||||
task!(audio_decode_eos: move || {
|
task!(audio_decode_eos: move || {
|
||||||
let this = this_.root();
|
let this = this_.root();
|
||||||
|
@ -473,8 +470,7 @@ impl BaseAudioContextMethods for BaseAudioContext {
|
||||||
}),
|
}),
|
||||||
&canceller_,
|
&canceller_,
|
||||||
);
|
);
|
||||||
})
|
}).build();
|
||||||
.build();
|
|
||||||
self.audio_context_impl
|
self.audio_context_impl
|
||||||
.decode_audio_data(audio_data, callbacks);
|
.decode_audio_data(audio_data, callbacks);
|
||||||
} else {
|
} else {
|
||||||
|
@ -491,10 +487,12 @@ impl BaseAudioContextMethods for BaseAudioContext {
|
||||||
impl From<BaseAudioContextOptions> for AudioContextOptions {
|
impl From<BaseAudioContextOptions> for AudioContextOptions {
|
||||||
fn from(options: BaseAudioContextOptions) -> Self {
|
fn from(options: BaseAudioContextOptions) -> Self {
|
||||||
match options {
|
match options {
|
||||||
BaseAudioContextOptions::AudioContext(options) =>
|
BaseAudioContextOptions::AudioContext(options) => {
|
||||||
AudioContextOptions::RealTimeAudioContext(options),
|
AudioContextOptions::RealTimeAudioContext(options)
|
||||||
BaseAudioContextOptions::OfflineAudioContext(options) =>
|
},
|
||||||
AudioContextOptions::OfflineAudioContext(options),
|
BaseAudioContextOptions::OfflineAudioContext(options) => {
|
||||||
|
AudioContextOptions::OfflineAudioContext(options)
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,20 +33,23 @@ impl BeforeUnloadEvent {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_uninitialized(window: &Window) -> DomRoot<BeforeUnloadEvent> {
|
pub fn new_uninitialized(window: &Window) -> DomRoot<BeforeUnloadEvent> {
|
||||||
reflect_dom_object(Box::new(BeforeUnloadEvent::new_inherited()),
|
reflect_dom_object(
|
||||||
|
Box::new(BeforeUnloadEvent::new_inherited()),
|
||||||
window,
|
window,
|
||||||
BeforeUnloadEventBinding::Wrap)
|
BeforeUnloadEventBinding::Wrap,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(window: &Window,
|
pub fn new(
|
||||||
|
window: &Window,
|
||||||
type_: Atom,
|
type_: Atom,
|
||||||
bubbles: EventBubbles,
|
bubbles: EventBubbles,
|
||||||
cancelable: EventCancelable) -> DomRoot<BeforeUnloadEvent> {
|
cancelable: EventCancelable,
|
||||||
|
) -> DomRoot<BeforeUnloadEvent> {
|
||||||
let ev = BeforeUnloadEvent::new_uninitialized(window);
|
let ev = BeforeUnloadEvent::new_uninitialized(window);
|
||||||
{
|
{
|
||||||
let event = ev.upcast::<Event>();
|
let event = ev.upcast::<Event>();
|
||||||
event.init_event(type_, bool::from(bubbles),
|
event.init_event(type_, bool::from(bubbles), bool::from(cancelable));
|
||||||
bool::from(cancelable));
|
|
||||||
}
|
}
|
||||||
ev
|
ev
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,7 +53,7 @@ pub struct CallbackObject {
|
||||||
///
|
///
|
||||||
/// ["callback context"]: https://heycam.github.io/webidl/#dfn-callback-context
|
/// ["callback context"]: https://heycam.github.io/webidl/#dfn-callback-context
|
||||||
/// [sometimes]: https://github.com/whatwg/html/issues/2248
|
/// [sometimes]: https://github.com/whatwg/html/issues/2248
|
||||||
incumbent: Option<Dom<GlobalScope>>
|
incumbent: Option<Dom<GlobalScope>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for CallbackObject {
|
impl Default for CallbackObject {
|
||||||
|
@ -81,8 +81,11 @@ impl CallbackObject {
|
||||||
unsafe fn init(&mut self, cx: *mut JSContext, callback: *mut JSObject) {
|
unsafe fn init(&mut self, cx: *mut JSContext, callback: *mut JSObject) {
|
||||||
self.callback.set(callback);
|
self.callback.set(callback);
|
||||||
self.permanent_js_root.set(ObjectValue(callback));
|
self.permanent_js_root.set(ObjectValue(callback));
|
||||||
assert!(AddRawValueRoot(cx, self.permanent_js_root.get_unsafe(),
|
assert!(AddRawValueRoot(
|
||||||
b"CallbackObject::root\n".as_c_char_ptr()));
|
cx,
|
||||||
|
self.permanent_js_root.get_unsafe(),
|
||||||
|
b"CallbackObject::root\n".as_c_char_ptr()
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,7 +97,6 @@ impl Drop for CallbackObject {
|
||||||
RemoveRawValueRoot(cx, self.permanent_js_root.get_unsafe());
|
RemoveRawValueRoot(cx, self.permanent_js_root.get_unsafe());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for CallbackObject {
|
impl PartialEq for CallbackObject {
|
||||||
|
@ -103,7 +105,6 @@ impl PartialEq for CallbackObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// A trait to be implemented by concrete IDL callback function and
|
/// A trait to be implemented by concrete IDL callback function and
|
||||||
/// callback interface types.
|
/// callback interface types.
|
||||||
pub trait CallbackContainer {
|
pub trait CallbackContainer {
|
||||||
|
@ -124,7 +125,6 @@ pub trait CallbackContainer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// A common base class for representing IDL callback function types.
|
/// A common base class for representing IDL callback function types.
|
||||||
#[derive(JSTraceable, PartialEq)]
|
#[derive(JSTraceable, PartialEq)]
|
||||||
#[must_root]
|
#[must_root]
|
||||||
|
@ -153,9 +153,6 @@ impl CallbackFunction {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// A common base class for representing IDL callback interface types.
|
/// A common base class for representing IDL callback interface types.
|
||||||
#[derive(JSTraceable, PartialEq)]
|
#[derive(JSTraceable, PartialEq)]
|
||||||
#[must_root]
|
#[must_root]
|
||||||
|
@ -194,19 +191,22 @@ impl CallbackInterface {
|
||||||
}
|
}
|
||||||
|
|
||||||
if !callable.is_object() || !IsCallable(callable.to_object()) {
|
if !callable.is_object() || !IsCallable(callable.to_object()) {
|
||||||
return Err(Error::Type(format!("The value of the {} property is not callable",
|
return Err(Error::Type(format!(
|
||||||
name)));
|
"The value of the {} property is not callable",
|
||||||
|
name
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(callable.get())
|
Ok(callable.get())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Wraps the reflector for `p` into the compartment of `cx`.
|
/// Wraps the reflector for `p` into the compartment of `cx`.
|
||||||
pub fn wrap_call_this_object<T: DomObject>(cx: *mut JSContext,
|
pub fn wrap_call_this_object<T: DomObject>(
|
||||||
|
cx: *mut JSContext,
|
||||||
p: &T,
|
p: &T,
|
||||||
mut rval: MutableHandleObject) {
|
mut rval: MutableHandleObject,
|
||||||
|
) {
|
||||||
rval.set(p.reflector().get_jsobject().get());
|
rval.set(p.reflector().get_jsobject().get());
|
||||||
assert!(!rval.get().is_null());
|
assert!(!rval.get().is_null());
|
||||||
|
|
||||||
|
@ -217,7 +217,6 @@ pub fn wrap_call_this_object<T: DomObject>(cx: *mut JSContext,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// A class that performs whatever setup we need to safely make a call while
|
/// A class that performs whatever setup we need to safely make a call while
|
||||||
/// this class is on the stack. After `new` returns, the call is safe to make.
|
/// this class is on the stack. After `new` returns, the call is safe to make.
|
||||||
pub struct CallSetup {
|
pub struct CallSetup {
|
||||||
|
@ -241,9 +240,7 @@ pub struct CallSetup {
|
||||||
impl CallSetup {
|
impl CallSetup {
|
||||||
/// Performs the setup needed to make a call.
|
/// Performs the setup needed to make a call.
|
||||||
#[allow(unrooted_must_root)]
|
#[allow(unrooted_must_root)]
|
||||||
pub fn new<T: CallbackContainer>(callback: &T,
|
pub fn new<T: CallbackContainer>(callback: &T, handling: ExceptionHandling) -> CallSetup {
|
||||||
handling: ExceptionHandling)
|
|
||||||
-> CallSetup {
|
|
||||||
let global = unsafe { GlobalScope::from_object(callback.callback()) };
|
let global = unsafe { GlobalScope::from_object(callback.callback()) };
|
||||||
let cx = global.get_cx();
|
let cx = global.get_cx();
|
||||||
|
|
||||||
|
@ -270,8 +267,10 @@ impl Drop for CallSetup {
|
||||||
unsafe {
|
unsafe {
|
||||||
JS_LeaveCompartment(self.cx, self.old_compartment);
|
JS_LeaveCompartment(self.cx, self.old_compartment);
|
||||||
if self.handling == ExceptionHandling::Report {
|
if self.handling == ExceptionHandling::Report {
|
||||||
let _ac = JSAutoCompartment::new(self.cx,
|
let _ac = JSAutoCompartment::new(
|
||||||
self.exception_global.reflector().get_jsobject().get());
|
self.cx,
|
||||||
|
self.exception_global.reflector().get_jsobject().get(),
|
||||||
|
);
|
||||||
report_pending_exception(self.cx, true);
|
report_pending_exception(self.cx, true);
|
||||||
}
|
}
|
||||||
drop(self.incumbent_script.take());
|
drop(self.incumbent_script.take());
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -51,16 +51,15 @@ impl ConstantSpec {
|
||||||
|
|
||||||
/// Defines constants on `obj`.
|
/// Defines constants on `obj`.
|
||||||
/// Fails on JSAPI failure.
|
/// Fails on JSAPI failure.
|
||||||
pub unsafe fn define_constants(
|
pub unsafe fn define_constants(cx: *mut JSContext, obj: HandleObject, constants: &[ConstantSpec]) {
|
||||||
cx: *mut JSContext,
|
|
||||||
obj: HandleObject,
|
|
||||||
constants: &[ConstantSpec]) {
|
|
||||||
for spec in constants {
|
for spec in constants {
|
||||||
rooted!(in(cx) let value = spec.get_value());
|
rooted!(in(cx) let value = spec.get_value());
|
||||||
assert!(JS_DefineProperty(cx,
|
assert!(JS_DefineProperty(
|
||||||
|
cx,
|
||||||
obj,
|
obj,
|
||||||
spec.name.as_ptr() as *const libc::c_char,
|
spec.name.as_ptr() as *const libc::c_char,
|
||||||
value.handle(),
|
value.handle(),
|
||||||
(JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT) as u32));
|
(JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT) as u32
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,8 +69,10 @@ pub trait IDLInterface {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A trait to mark an IDL interface as deriving from another one.
|
/// A trait to mark an IDL interface as deriving from another one.
|
||||||
#[cfg_attr(feature = "unstable",
|
#[cfg_attr(
|
||||||
rustc_on_unimplemented = "The IDL interface `{Self}` is not derived from `{T}`.")]
|
feature = "unstable",
|
||||||
|
rustc_on_unimplemented = "The IDL interface `{Self}` is not derived from `{T}`."
|
||||||
|
)]
|
||||||
pub trait DerivedFrom<T: Castable>: Castable {}
|
pub trait DerivedFrom<T: Castable>: Castable {}
|
||||||
|
|
||||||
impl<T: Float + ToJSValConvertible> ToJSValConvertible for Finite<T> {
|
impl<T: Float + ToJSValConvertible> ToJSValConvertible for Finite<T> {
|
||||||
|
@ -81,20 +83,21 @@ impl<T: Float + ToJSValConvertible> ToJSValConvertible for Finite<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Float + FromJSValConvertible<Config=()>> FromJSValConvertible for Finite<T> {
|
impl<T: Float + FromJSValConvertible<Config = ()>> FromJSValConvertible for Finite<T> {
|
||||||
type Config = ();
|
type Config = ();
|
||||||
|
|
||||||
unsafe fn from_jsval(cx: *mut JSContext,
|
unsafe fn from_jsval(
|
||||||
|
cx: *mut JSContext,
|
||||||
value: HandleValue,
|
value: HandleValue,
|
||||||
option: ())
|
option: (),
|
||||||
-> Result<ConversionResult<Finite<T>>, ()> {
|
) -> Result<ConversionResult<Finite<T>>, ()> {
|
||||||
let result = match FromJSValConvertible::from_jsval(cx, value, option)? {
|
let result = match FromJSValConvertible::from_jsval(cx, value, option)? {
|
||||||
ConversionResult::Success(v) => v,
|
ConversionResult::Success(v) => v,
|
||||||
ConversionResult::Failure(error) => {
|
ConversionResult::Failure(error) => {
|
||||||
// FIXME(emilio): Why throwing instead of propagating the error?
|
// FIXME(emilio): Why throwing instead of propagating the error?
|
||||||
throw_type_error(cx, &error);
|
throw_type_error(cx, &error);
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
match Finite::new(result) {
|
match Finite::new(result) {
|
||||||
Some(v) => Ok(ConversionResult::Success(v)),
|
Some(v) => Ok(ConversionResult::Success(v)),
|
||||||
|
@ -106,13 +109,14 @@ impl<T: Float + FromJSValConvertible<Config=()>> FromJSValConvertible for Finite
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <T: DomObject + IDLInterface> FromJSValConvertible for DomRoot<T> {
|
impl<T: DomObject + IDLInterface> FromJSValConvertible for DomRoot<T> {
|
||||||
type Config = ();
|
type Config = ();
|
||||||
|
|
||||||
unsafe fn from_jsval(_cx: *mut JSContext,
|
unsafe fn from_jsval(
|
||||||
|
_cx: *mut JSContext,
|
||||||
value: HandleValue,
|
value: HandleValue,
|
||||||
_config: Self::Config)
|
_config: Self::Config,
|
||||||
-> Result<ConversionResult<DomRoot<T>>, ()> {
|
) -> Result<ConversionResult<DomRoot<T>>, ()> {
|
||||||
Ok(match root_from_handlevalue(value) {
|
Ok(match root_from_handlevalue(value) {
|
||||||
Ok(result) => ConversionResult::Success(result),
|
Ok(result) => ConversionResult::Success(result),
|
||||||
Err(()) => ConversionResult::Failure("value is not an object".into()),
|
Err(()) => ConversionResult::Failure("value is not an object".into()),
|
||||||
|
@ -129,19 +133,21 @@ impl<T: ToJSValConvertible + JSTraceable> ToJSValConvertible for RootedTraceable
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> FromJSValConvertible for RootedTraceableBox<Heap<T>>
|
impl<T> FromJSValConvertible for RootedTraceableBox<Heap<T>>
|
||||||
where
|
where
|
||||||
T: FromJSValConvertible + js::rust::GCMethods + Copy,
|
T: FromJSValConvertible + js::rust::GCMethods + Copy,
|
||||||
Heap<T>: JSTraceable + Default
|
Heap<T>: JSTraceable + Default,
|
||||||
{
|
{
|
||||||
type Config = T::Config;
|
type Config = T::Config;
|
||||||
|
|
||||||
unsafe fn from_jsval(cx: *mut JSContext,
|
unsafe fn from_jsval(
|
||||||
|
cx: *mut JSContext,
|
||||||
value: HandleValue,
|
value: HandleValue,
|
||||||
config: Self::Config)
|
config: Self::Config,
|
||||||
-> Result<ConversionResult<Self>, ()> {
|
) -> Result<ConversionResult<Self>, ()> {
|
||||||
T::from_jsval(cx, value, config).map(|result| match result {
|
T::from_jsval(cx, value, config).map(|result| match result {
|
||||||
ConversionResult::Success(inner) =>
|
ConversionResult::Success(inner) => {
|
||||||
ConversionResult::Success(RootedTraceableBox::from_box(Heap::boxed(inner))),
|
ConversionResult::Success(RootedTraceableBox::from_box(Heap::boxed(inner)))
|
||||||
|
},
|
||||||
ConversionResult::Failure(msg) => ConversionResult::Failure(msg),
|
ConversionResult::Failure(msg) => ConversionResult::Failure(msg),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -190,12 +196,12 @@ impl ToJSValConvertible for DOMString {
|
||||||
// https://heycam.github.io/webidl/#es-DOMString
|
// https://heycam.github.io/webidl/#es-DOMString
|
||||||
impl FromJSValConvertible for DOMString {
|
impl FromJSValConvertible for DOMString {
|
||||||
type Config = StringificationBehavior;
|
type Config = StringificationBehavior;
|
||||||
unsafe fn from_jsval(cx: *mut JSContext,
|
unsafe fn from_jsval(
|
||||||
|
cx: *mut JSContext,
|
||||||
value: HandleValue,
|
value: HandleValue,
|
||||||
null_behavior: StringificationBehavior)
|
null_behavior: StringificationBehavior,
|
||||||
-> Result<ConversionResult<DOMString>, ()> {
|
) -> Result<ConversionResult<DOMString>, ()> {
|
||||||
if null_behavior == StringificationBehavior::Empty &&
|
if null_behavior == StringificationBehavior::Empty && value.get().is_null() {
|
||||||
value.get().is_null() {
|
|
||||||
Ok(ConversionResult::Success(DOMString::new()))
|
Ok(ConversionResult::Success(DOMString::new()))
|
||||||
} else {
|
} else {
|
||||||
let jsstr = ToString(cx, value);
|
let jsstr = ToString(cx, value);
|
||||||
|
@ -231,16 +237,19 @@ pub unsafe fn jsstring_to_str(cx: *mut JSContext, s: *mut JSString) -> DOMString
|
||||||
"Found an unpaired surrogate in a DOM string. \
|
"Found an unpaired surrogate in a DOM string. \
|
||||||
If you see this in real web content, \
|
If you see this in real web content, \
|
||||||
please comment on https://github.com/servo/servo/issues/6564"
|
please comment on https://github.com/servo/servo/issues/6564"
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
if opts::get().replace_surrogates {
|
if opts::get().replace_surrogates {
|
||||||
error!(message!());
|
error!(message!());
|
||||||
s.push('\u{FFFD}');
|
s.push('\u{FFFD}');
|
||||||
} else {
|
} else {
|
||||||
panic!(concat!(message!(), " Use `-Z replace-surrogates` \
|
panic!(concat!(
|
||||||
on the command line to make this non-fatal."));
|
message!(),
|
||||||
}
|
" Use `-Z replace-surrogates` \
|
||||||
|
on the command line to make this non-fatal."
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s
|
s
|
||||||
|
@ -250,8 +259,11 @@ pub unsafe fn jsstring_to_str(cx: *mut JSContext, s: *mut JSString) -> DOMString
|
||||||
// http://heycam.github.io/webidl/#es-USVString
|
// http://heycam.github.io/webidl/#es-USVString
|
||||||
impl FromJSValConvertible for USVString {
|
impl FromJSValConvertible for USVString {
|
||||||
type Config = ();
|
type Config = ();
|
||||||
unsafe fn from_jsval(cx: *mut JSContext, value: HandleValue, _: ())
|
unsafe fn from_jsval(
|
||||||
-> Result<ConversionResult<USVString>, ()> {
|
cx: *mut JSContext,
|
||||||
|
value: HandleValue,
|
||||||
|
_: (),
|
||||||
|
) -> Result<ConversionResult<USVString>, ()> {
|
||||||
let jsstr = ToString(cx, value);
|
let jsstr = ToString(cx, value);
|
||||||
if jsstr.is_null() {
|
if jsstr.is_null() {
|
||||||
debug!("ToString failed");
|
debug!("ToString failed");
|
||||||
|
@ -260,23 +272,28 @@ impl FromJSValConvertible for USVString {
|
||||||
let latin1 = JS_StringHasLatin1Chars(jsstr);
|
let latin1 = JS_StringHasLatin1Chars(jsstr);
|
||||||
if latin1 {
|
if latin1 {
|
||||||
// FIXME(ajeffrey): Convert directly from DOMString to USVString
|
// FIXME(ajeffrey): Convert directly from DOMString to USVString
|
||||||
return Ok(ConversionResult::Success(
|
return Ok(ConversionResult::Success(USVString(String::from(
|
||||||
USVString(String::from(jsstring_to_str(cx, jsstr)))));
|
jsstring_to_str(cx, jsstr),
|
||||||
|
))));
|
||||||
}
|
}
|
||||||
let mut length = 0;
|
let mut length = 0;
|
||||||
let chars = JS_GetTwoByteStringCharsAndLength(cx, ptr::null(), jsstr, &mut length);
|
let chars = JS_GetTwoByteStringCharsAndLength(cx, ptr::null(), jsstr, &mut length);
|
||||||
assert!(!chars.is_null());
|
assert!(!chars.is_null());
|
||||||
let char_vec = slice::from_raw_parts(chars as *const u16, length as usize);
|
let char_vec = slice::from_raw_parts(chars as *const u16, length as usize);
|
||||||
Ok(ConversionResult::Success(USVString(String::from_utf16_lossy(char_vec))))
|
Ok(ConversionResult::Success(USVString(
|
||||||
|
String::from_utf16_lossy(char_vec),
|
||||||
|
)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// http://heycam.github.io/webidl/#es-ByteString
|
// http://heycam.github.io/webidl/#es-ByteString
|
||||||
impl ToJSValConvertible for ByteString {
|
impl ToJSValConvertible for ByteString {
|
||||||
unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {
|
unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {
|
||||||
let jsstr = JS_NewStringCopyN(cx,
|
let jsstr = JS_NewStringCopyN(
|
||||||
|
cx,
|
||||||
self.as_ptr() as *const libc::c_char,
|
self.as_ptr() as *const libc::c_char,
|
||||||
self.len() as libc::size_t);
|
self.len() as libc::size_t,
|
||||||
|
);
|
||||||
if jsstr.is_null() {
|
if jsstr.is_null() {
|
||||||
panic!("JS_NewStringCopyN failed");
|
panic!("JS_NewStringCopyN failed");
|
||||||
}
|
}
|
||||||
|
@ -287,10 +304,11 @@ impl ToJSValConvertible for ByteString {
|
||||||
// http://heycam.github.io/webidl/#es-ByteString
|
// http://heycam.github.io/webidl/#es-ByteString
|
||||||
impl FromJSValConvertible for ByteString {
|
impl FromJSValConvertible for ByteString {
|
||||||
type Config = ();
|
type Config = ();
|
||||||
unsafe fn from_jsval(cx: *mut JSContext,
|
unsafe fn from_jsval(
|
||||||
|
cx: *mut JSContext,
|
||||||
value: HandleValue,
|
value: HandleValue,
|
||||||
_option: ())
|
_option: (),
|
||||||
-> Result<ConversionResult<ByteString>, ()> {
|
) -> Result<ConversionResult<ByteString>, ()> {
|
||||||
let string = ToString(cx, value);
|
let string = ToString(cx, value);
|
||||||
if string.is_null() {
|
if string.is_null() {
|
||||||
debug!("ToString failed");
|
debug!("ToString failed");
|
||||||
|
@ -304,7 +322,9 @@ impl FromJSValConvertible for ByteString {
|
||||||
assert!(!chars.is_null());
|
assert!(!chars.is_null());
|
||||||
|
|
||||||
let char_slice = slice::from_raw_parts(chars as *mut u8, length as usize);
|
let char_slice = slice::from_raw_parts(chars as *mut u8, length as usize);
|
||||||
return Ok(ConversionResult::Success(ByteString::new(char_slice.to_vec())));
|
return Ok(ConversionResult::Success(ByteString::new(
|
||||||
|
char_slice.to_vec(),
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut length = 0;
|
let mut length = 0;
|
||||||
|
@ -315,13 +335,13 @@ impl FromJSValConvertible for ByteString {
|
||||||
throw_type_error(cx, "Invalid ByteString");
|
throw_type_error(cx, "Invalid ByteString");
|
||||||
Err(())
|
Err(())
|
||||||
} else {
|
} else {
|
||||||
Ok(ConversionResult::Success(
|
Ok(ConversionResult::Success(ByteString::new(
|
||||||
ByteString::new(char_vec.iter().map(|&c| c as u8).collect())))
|
char_vec.iter().map(|&c| c as u8).collect(),
|
||||||
|
)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl ToJSValConvertible for Reflector {
|
impl ToJSValConvertible for Reflector {
|
||||||
unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {
|
unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {
|
||||||
let obj = self.get_jsobject().get();
|
let obj = self.get_jsobject().get();
|
||||||
|
@ -389,10 +409,12 @@ pub unsafe fn get_dom_class(obj: *mut JSObject) -> Result<&'static DOMClass, ()>
|
||||||
/// not an object for a DOM object of the given type (as defined by the
|
/// not an object for a DOM object of the given type (as defined by the
|
||||||
/// proto_id and proto_depth).
|
/// proto_id and proto_depth).
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn private_from_proto_check<F>(mut obj: *mut JSObject,
|
pub unsafe fn private_from_proto_check<F>(
|
||||||
proto_check: F)
|
mut obj: *mut JSObject,
|
||||||
-> Result<*const libc::c_void, ()>
|
proto_check: F,
|
||||||
where F: Fn(&'static DOMClass) -> bool
|
) -> Result<*const libc::c_void, ()>
|
||||||
|
where
|
||||||
|
F: Fn(&'static DOMClass) -> bool,
|
||||||
{
|
{
|
||||||
let dom_class = get_dom_class(obj).or_else(|_| {
|
let dom_class = get_dom_class(obj).or_else(|_| {
|
||||||
if IsWrapper(obj) {
|
if IsWrapper(obj) {
|
||||||
|
@ -423,11 +445,10 @@ pub unsafe fn private_from_proto_check<F>(mut obj: *mut JSObject,
|
||||||
|
|
||||||
/// Get a `*const T` for a DOM object accessible from a `JSObject`.
|
/// Get a `*const T` for a DOM object accessible from a `JSObject`.
|
||||||
pub fn native_from_object<T>(obj: *mut JSObject) -> Result<*const T, ()>
|
pub fn native_from_object<T>(obj: *mut JSObject) -> Result<*const T, ()>
|
||||||
where T: DomObject + IDLInterface
|
where
|
||||||
|
T: DomObject + IDLInterface,
|
||||||
{
|
{
|
||||||
unsafe {
|
unsafe { private_from_proto_check(obj, T::derives).map(|ptr| ptr as *const T) }
|
||||||
private_from_proto_check(obj, T::derives).map(|ptr| ptr as *const T)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a `DomRoot<T>` for the given DOM object, unwrapping any wrapper
|
/// Get a `DomRoot<T>` for the given DOM object, unwrapping any wrapper
|
||||||
|
@ -437,7 +458,8 @@ pub fn native_from_object<T>(obj: *mut JSObject) -> Result<*const T, ()>
|
||||||
/// not a reflector for a DOM object of the given type (as defined by the
|
/// not a reflector for a DOM object of the given type (as defined by the
|
||||||
/// proto_id and proto_depth).
|
/// proto_id and proto_depth).
|
||||||
pub fn root_from_object<T>(obj: *mut JSObject) -> Result<DomRoot<T>, ()>
|
pub fn root_from_object<T>(obj: *mut JSObject) -> Result<DomRoot<T>, ()>
|
||||||
where T: DomObject + IDLInterface
|
where
|
||||||
|
T: DomObject + IDLInterface,
|
||||||
{
|
{
|
||||||
native_from_object(obj).map(|ptr| unsafe { DomRoot::from_ref(&*ptr) })
|
native_from_object(obj).map(|ptr| unsafe { DomRoot::from_ref(&*ptr) })
|
||||||
}
|
}
|
||||||
|
@ -445,7 +467,8 @@ pub fn root_from_object<T>(obj: *mut JSObject) -> Result<DomRoot<T>, ()>
|
||||||
/// Get a `*const T` for a DOM object accessible from a `HandleValue`.
|
/// Get a `*const T` for a DOM object accessible from a `HandleValue`.
|
||||||
/// Caller is responsible for throwing a JS exception if needed in case of error.
|
/// Caller is responsible for throwing a JS exception if needed in case of error.
|
||||||
pub fn native_from_handlevalue<T>(v: HandleValue) -> Result<*const T, ()>
|
pub fn native_from_handlevalue<T>(v: HandleValue) -> Result<*const T, ()>
|
||||||
where T: DomObject + IDLInterface
|
where
|
||||||
|
T: DomObject + IDLInterface,
|
||||||
{
|
{
|
||||||
if !v.get().is_object() {
|
if !v.get().is_object() {
|
||||||
return Err(());
|
return Err(());
|
||||||
|
@ -456,7 +479,8 @@ pub fn native_from_handlevalue<T>(v: HandleValue) -> Result<*const T, ()>
|
||||||
/// Get a `DomRoot<T>` for a DOM object accessible from a `HandleValue`.
|
/// Get a `DomRoot<T>` for a DOM object accessible from a `HandleValue`.
|
||||||
/// Caller is responsible for throwing a JS exception if needed in case of error.
|
/// Caller is responsible for throwing a JS exception if needed in case of error.
|
||||||
pub fn root_from_handlevalue<T>(v: HandleValue) -> Result<DomRoot<T>, ()>
|
pub fn root_from_handlevalue<T>(v: HandleValue) -> Result<DomRoot<T>, ()>
|
||||||
where T: DomObject + IDLInterface
|
where
|
||||||
|
T: DomObject + IDLInterface,
|
||||||
{
|
{
|
||||||
if !v.get().is_object() {
|
if !v.get().is_object() {
|
||||||
return Err(());
|
return Err(());
|
||||||
|
@ -466,7 +490,8 @@ pub fn root_from_handlevalue<T>(v: HandleValue) -> Result<DomRoot<T>, ()>
|
||||||
|
|
||||||
/// Get a `DomRoot<T>` for a DOM object accessible from a `HandleObject`.
|
/// Get a `DomRoot<T>` for a DOM object accessible from a `HandleObject`.
|
||||||
pub fn root_from_handleobject<T>(obj: HandleObject) -> Result<DomRoot<T>, ()>
|
pub fn root_from_handleobject<T>(obj: HandleObject) -> Result<DomRoot<T>, ()>
|
||||||
where T: DomObject + IDLInterface
|
where
|
||||||
|
T: DomObject + IDLInterface,
|
||||||
{
|
{
|
||||||
root_from_object(obj.get())
|
root_from_object(obj.get())
|
||||||
}
|
}
|
||||||
|
@ -487,12 +512,12 @@ pub unsafe fn is_array_like(cx: *mut JSContext, value: HandleValue) -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a property from a JS object.
|
/// Get a property from a JS object.
|
||||||
pub unsafe fn get_property_jsval(cx: *mut JSContext,
|
pub unsafe fn get_property_jsval(
|
||||||
|
cx: *mut JSContext,
|
||||||
object: HandleObject,
|
object: HandleObject,
|
||||||
name: &str,
|
name: &str,
|
||||||
mut rval: MutableHandleValue)
|
mut rval: MutableHandleValue,
|
||||||
-> Fallible<()>
|
) -> Fallible<()> {
|
||||||
{
|
|
||||||
rval.set(UndefinedValue());
|
rval.set(UndefinedValue());
|
||||||
let cname = match ffi::CString::new(name) {
|
let cname = match ffi::CString::new(name) {
|
||||||
Ok(cname) => cname,
|
Ok(cname) => cname,
|
||||||
|
@ -506,12 +531,14 @@ pub unsafe fn get_property_jsval(cx: *mut JSContext,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a property from a JS object, and convert it to a Rust value.
|
/// Get a property from a JS object, and convert it to a Rust value.
|
||||||
pub unsafe fn get_property<T>(cx: *mut JSContext,
|
pub unsafe fn get_property<T>(
|
||||||
|
cx: *mut JSContext,
|
||||||
object: HandleObject,
|
object: HandleObject,
|
||||||
name: &str,
|
name: &str,
|
||||||
option: T::Config)
|
option: T::Config,
|
||||||
-> Fallible<Option<T>> where
|
) -> Fallible<Option<T>>
|
||||||
T: FromJSValConvertible
|
where
|
||||||
|
T: FromJSValConvertible,
|
||||||
{
|
{
|
||||||
debug!("Getting property {}.", name);
|
debug!("Getting property {}.", name);
|
||||||
rooted!(in(cx) let mut result = UndefinedValue());
|
rooted!(in(cx) let mut result = UndefinedValue());
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -89,7 +89,9 @@ use std::ptr;
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#htmlconstructor
|
// https://html.spec.whatwg.org/multipage/#htmlconstructor
|
||||||
pub unsafe fn html_constructor<T>(window: &Window, call_args: &CallArgs) -> Fallible<DomRoot<T>>
|
pub unsafe fn html_constructor<T>(window: &Window, call_args: &CallArgs) -> Fallible<DomRoot<T>>
|
||||||
where T: DerivedFrom<Element> {
|
where
|
||||||
|
T: DerivedFrom<Element>,
|
||||||
|
{
|
||||||
let document = window.Document();
|
let document = window.Document();
|
||||||
|
|
||||||
// Step 1
|
// Step 1
|
||||||
|
@ -101,7 +103,11 @@ pub unsafe fn html_constructor<T>(window: &Window, call_args: &CallArgs) -> Fall
|
||||||
rooted!(in(window.get_cx()) let new_target = call_args.new_target().to_object());
|
rooted!(in(window.get_cx()) let new_target = call_args.new_target().to_object());
|
||||||
let definition = match registry.lookup_definition_by_constructor(new_target.handle()) {
|
let definition = match registry.lookup_definition_by_constructor(new_target.handle()) {
|
||||||
Some(definition) => definition,
|
Some(definition) => definition,
|
||||||
None => return Err(Error::Type("No custom element definition found for new.target".to_owned())),
|
None => {
|
||||||
|
return Err(Error::Type(
|
||||||
|
"No custom element definition found for new.target".to_owned(),
|
||||||
|
))
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
rooted!(in(window.get_cx()) let callee = UnwrapObject(call_args.callee(), 1));
|
rooted!(in(window.get_cx()) let callee = UnwrapObject(call_args.callee(), 1));
|
||||||
|
@ -119,18 +125,25 @@ pub unsafe fn html_constructor<T>(window: &Window, call_args: &CallArgs) -> Fall
|
||||||
// Since this element is autonomous, its active function object must be the HTMLElement
|
// Since this element is autonomous, its active function object must be the HTMLElement
|
||||||
|
|
||||||
// Retrieve the constructor object for HTMLElement
|
// Retrieve the constructor object for HTMLElement
|
||||||
HTMLElementBinding::GetConstructorObject(window.get_cx(), global_object.handle(), constructor.handle_mut());
|
HTMLElementBinding::GetConstructorObject(
|
||||||
|
|
||||||
} else {
|
|
||||||
// Step 5
|
|
||||||
get_constructor_object_from_local_name(definition.local_name.clone(),
|
|
||||||
window.get_cx(),
|
window.get_cx(),
|
||||||
global_object.handle(),
|
global_object.handle(),
|
||||||
constructor.handle_mut());
|
constructor.handle_mut(),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// Step 5
|
||||||
|
get_constructor_object_from_local_name(
|
||||||
|
definition.local_name.clone(),
|
||||||
|
window.get_cx(),
|
||||||
|
global_object.handle(),
|
||||||
|
constructor.handle_mut(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
// Callee must be the same as the element interface's constructor object.
|
// Callee must be the same as the element interface's constructor object.
|
||||||
if constructor.get() != callee.get() {
|
if constructor.get() != callee.get() {
|
||||||
return Err(Error::Type("Custom element does not extend the proper interface".to_owned()));
|
return Err(Error::Type(
|
||||||
|
"Custom element does not extend the proper interface".to_owned(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,11 +189,12 @@ pub unsafe fn html_constructor<T>(window: &Window, call_args: &CallArgs) -> Fall
|
||||||
|
|
||||||
/// Returns the constructor object for the element associated with the given local name.
|
/// Returns the constructor object for the element associated with the given local name.
|
||||||
/// This list should only include elements marked with the [HTMLConstructor] extended attribute.
|
/// This list should only include elements marked with the [HTMLConstructor] extended attribute.
|
||||||
pub fn get_constructor_object_from_local_name(name: LocalName,
|
pub fn get_constructor_object_from_local_name(
|
||||||
|
name: LocalName,
|
||||||
cx: *mut JSContext,
|
cx: *mut JSContext,
|
||||||
global: HandleObject,
|
global: HandleObject,
|
||||||
rval: MutableHandleObject)
|
rval: MutableHandleObject,
|
||||||
-> bool {
|
) -> bool {
|
||||||
macro_rules! get_constructor(
|
macro_rules! get_constructor(
|
||||||
($binding:ident) => ({
|
($binding:ident) => ({
|
||||||
unsafe { $binding::GetConstructorObject(cx, global, rval); }
|
unsafe { $binding::GetConstructorObject(cx, global, rval); }
|
||||||
|
|
|
@ -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) })
|
||||||
|
|
|
@ -52,11 +52,12 @@ unsafe impl Sync for NonCallbackInterfaceObjectClass {}
|
||||||
|
|
||||||
impl NonCallbackInterfaceObjectClass {
|
impl NonCallbackInterfaceObjectClass {
|
||||||
/// Create a new `NonCallbackInterfaceObjectClass` structure.
|
/// Create a new `NonCallbackInterfaceObjectClass` structure.
|
||||||
pub const fn new(constructor_behavior: &'static InterfaceConstructorBehavior,
|
pub const fn new(
|
||||||
|
constructor_behavior: &'static InterfaceConstructorBehavior,
|
||||||
string_rep: &'static [u8],
|
string_rep: &'static [u8],
|
||||||
proto_id: PrototypeList::ID,
|
proto_id: PrototypeList::ID,
|
||||||
proto_depth: u16)
|
proto_depth: u16,
|
||||||
-> NonCallbackInterfaceObjectClass {
|
) -> NonCallbackInterfaceObjectClass {
|
||||||
NonCallbackInterfaceObjectClass {
|
NonCallbackInterfaceObjectClass {
|
||||||
class: Class {
|
class: Class {
|
||||||
name: b"Function\0" as *const _ as *const libc::c_char,
|
name: b"Function\0" as *const _ as *const libc::c_char,
|
||||||
|
@ -74,9 +75,7 @@ impl NonCallbackInterfaceObjectClass {
|
||||||
|
|
||||||
/// cast own reference to `JSClass` reference
|
/// cast own reference to `JSClass` reference
|
||||||
pub fn as_jsclass(&self) -> &JSClass {
|
pub fn as_jsclass(&self) -> &JSClass {
|
||||||
unsafe {
|
unsafe { &*(self as *const _ as *const JSClass) }
|
||||||
&*(self as *const _ as *const JSClass)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,8 +123,7 @@ impl InterfaceConstructorBehavior {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A trace hook.
|
/// A trace hook.
|
||||||
pub type TraceHook =
|
pub type TraceHook = unsafe extern "C" fn(trc: *mut JSTracer, obj: *mut JSObject);
|
||||||
unsafe extern "C" fn(trc: *mut JSTracer, obj: *mut JSObject);
|
|
||||||
|
|
||||||
/// Create a global object with the given class.
|
/// Create a global object with the given class.
|
||||||
pub unsafe fn create_global_object(
|
pub unsafe fn create_global_object(
|
||||||
|
@ -133,18 +131,21 @@ pub unsafe fn create_global_object(
|
||||||
class: &'static JSClass,
|
class: &'static JSClass,
|
||||||
private: *const libc::c_void,
|
private: *const libc::c_void,
|
||||||
trace: TraceHook,
|
trace: TraceHook,
|
||||||
mut rval: MutableHandleObject) {
|
mut rval: MutableHandleObject,
|
||||||
|
) {
|
||||||
assert!(rval.is_null());
|
assert!(rval.is_null());
|
||||||
|
|
||||||
let mut options = CompartmentOptions::default();
|
let mut options = CompartmentOptions::default();
|
||||||
options.creationOptions_.traceGlobal_ = Some(trace);
|
options.creationOptions_.traceGlobal_ = Some(trace);
|
||||||
options.creationOptions_.sharedMemoryAndAtomics_ = true;
|
options.creationOptions_.sharedMemoryAndAtomics_ = true;
|
||||||
|
|
||||||
rval.set(JS_NewGlobalObject(cx,
|
rval.set(JS_NewGlobalObject(
|
||||||
|
cx,
|
||||||
class,
|
class,
|
||||||
ptr::null_mut(),
|
ptr::null_mut(),
|
||||||
OnNewGlobalHookOption::DontFireOnNewGlobalHook,
|
OnNewGlobalHookOption::DontFireOnNewGlobalHook,
|
||||||
&options));
|
&options,
|
||||||
|
));
|
||||||
assert!(!rval.is_null());
|
assert!(!rval.is_null());
|
||||||
|
|
||||||
// Initialize the reserved slots before doing anything that can GC, to
|
// Initialize the reserved slots before doing anything that can GC, to
|
||||||
|
@ -166,7 +167,8 @@ pub unsafe fn create_callback_interface_object(
|
||||||
global: HandleObject,
|
global: HandleObject,
|
||||||
constants: &[Guard<&[ConstantSpec]>],
|
constants: &[Guard<&[ConstantSpec]>],
|
||||||
name: &[u8],
|
name: &[u8],
|
||||||
mut rval: MutableHandleObject) {
|
mut rval: MutableHandleObject,
|
||||||
|
) {
|
||||||
assert!(!constants.is_empty());
|
assert!(!constants.is_empty());
|
||||||
rval.set(JS_NewObject(cx, ptr::null()));
|
rval.set(JS_NewObject(cx, ptr::null()));
|
||||||
assert!(!rval.is_null());
|
assert!(!rval.is_null());
|
||||||
|
@ -184,8 +186,17 @@ pub unsafe fn create_interface_prototype_object(
|
||||||
regular_properties: &[Guard<&'static [JSPropertySpec]>],
|
regular_properties: &[Guard<&'static [JSPropertySpec]>],
|
||||||
constants: &[Guard<&[ConstantSpec]>],
|
constants: &[Guard<&[ConstantSpec]>],
|
||||||
unscopable_names: &[&[u8]],
|
unscopable_names: &[&[u8]],
|
||||||
rval: MutableHandleObject) {
|
rval: MutableHandleObject,
|
||||||
create_object(cx, proto, class, regular_methods, regular_properties, constants, rval);
|
) {
|
||||||
|
create_object(
|
||||||
|
cx,
|
||||||
|
proto,
|
||||||
|
class,
|
||||||
|
regular_methods,
|
||||||
|
regular_properties,
|
||||||
|
constants,
|
||||||
|
rval,
|
||||||
|
);
|
||||||
|
|
||||||
if !unscopable_names.is_empty() {
|
if !unscopable_names.is_empty() {
|
||||||
rooted!(in(cx) let mut unscopable_obj = ptr::null_mut::<JSObject>());
|
rooted!(in(cx) let mut unscopable_obj = ptr::null_mut::<JSObject>());
|
||||||
|
@ -196,8 +207,12 @@ pub unsafe fn create_interface_prototype_object(
|
||||||
|
|
||||||
rooted!(in(cx) let unscopable_id = RUST_SYMBOL_TO_JSID(unscopable_symbol));
|
rooted!(in(cx) let unscopable_id = RUST_SYMBOL_TO_JSID(unscopable_symbol));
|
||||||
assert!(JS_DefinePropertyById4(
|
assert!(JS_DefinePropertyById4(
|
||||||
cx, rval.handle(), unscopable_id.handle(), unscopable_obj.handle(),
|
cx,
|
||||||
JSPROP_READONLY as u32))
|
rval.handle(),
|
||||||
|
unscopable_id.handle(),
|
||||||
|
unscopable_obj.handle(),
|
||||||
|
JSPROP_READONLY as u32
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,15 +228,22 @@ pub unsafe fn create_noncallback_interface_object(
|
||||||
interface_prototype_object: HandleObject,
|
interface_prototype_object: HandleObject,
|
||||||
name: &[u8],
|
name: &[u8],
|
||||||
length: u32,
|
length: u32,
|
||||||
rval: MutableHandleObject) {
|
rval: MutableHandleObject,
|
||||||
create_object(cx,
|
) {
|
||||||
|
create_object(
|
||||||
|
cx,
|
||||||
proto,
|
proto,
|
||||||
class.as_jsclass(),
|
class.as_jsclass(),
|
||||||
static_methods,
|
static_methods,
|
||||||
static_properties,
|
static_properties,
|
||||||
constants,
|
constants,
|
||||||
rval);
|
rval,
|
||||||
assert!(JS_LinkConstructorAndPrototype(cx, rval.handle(), interface_prototype_object));
|
);
|
||||||
|
assert!(JS_LinkConstructorAndPrototype(
|
||||||
|
cx,
|
||||||
|
rval.handle(),
|
||||||
|
interface_prototype_object
|
||||||
|
));
|
||||||
define_name(cx, rval.handle(), name);
|
define_name(cx, rval.handle(), name);
|
||||||
define_length(cx, rval.handle(), i32::try_from(length).expect("overflow"));
|
define_length(cx, rval.handle(), i32::try_from(length).expect("overflow"));
|
||||||
define_on_global_object(cx, global, name, rval.handle());
|
define_on_global_object(cx, global, name, rval.handle());
|
||||||
|
@ -232,26 +254,31 @@ pub unsafe fn create_named_constructors(
|
||||||
cx: *mut JSContext,
|
cx: *mut JSContext,
|
||||||
global: HandleObject,
|
global: HandleObject,
|
||||||
named_constructors: &[(ConstructorClassHook, &[u8], u32)],
|
named_constructors: &[(ConstructorClassHook, &[u8], u32)],
|
||||||
interface_prototype_object: HandleObject) {
|
interface_prototype_object: HandleObject,
|
||||||
|
) {
|
||||||
rooted!(in(cx) let mut constructor = ptr::null_mut::<JSObject>());
|
rooted!(in(cx) let mut constructor = ptr::null_mut::<JSObject>());
|
||||||
|
|
||||||
for &(native, name, arity) in named_constructors {
|
for &(native, name, arity) in named_constructors {
|
||||||
assert_eq!(*name.last().unwrap(), b'\0');
|
assert_eq!(*name.last().unwrap(), b'\0');
|
||||||
|
|
||||||
let fun = JS_NewFunction(cx,
|
let fun = JS_NewFunction(
|
||||||
|
cx,
|
||||||
Some(native),
|
Some(native),
|
||||||
arity,
|
arity,
|
||||||
JSFUN_CONSTRUCTOR,
|
JSFUN_CONSTRUCTOR,
|
||||||
name.as_ptr() as *const libc::c_char);
|
name.as_ptr() as *const libc::c_char,
|
||||||
|
);
|
||||||
assert!(!fun.is_null());
|
assert!(!fun.is_null());
|
||||||
constructor.set(JS_GetFunctionObject(fun));
|
constructor.set(JS_GetFunctionObject(fun));
|
||||||
assert!(!constructor.is_null());
|
assert!(!constructor.is_null());
|
||||||
|
|
||||||
assert!(JS_DefineProperty2(cx,
|
assert!(JS_DefineProperty2(
|
||||||
|
cx,
|
||||||
constructor.handle(),
|
constructor.handle(),
|
||||||
b"prototype\0".as_ptr() as *const libc::c_char,
|
b"prototype\0".as_ptr() as *const libc::c_char,
|
||||||
interface_prototype_object,
|
interface_prototype_object,
|
||||||
(JSPROP_PERMANENT | JSPROP_READONLY) as u32));
|
(JSPROP_PERMANENT | JSPROP_READONLY) as u32
|
||||||
|
));
|
||||||
|
|
||||||
define_on_global_object(cx, global, name, constructor.handle());
|
define_on_global_object(cx, global, name, constructor.handle());
|
||||||
}
|
}
|
||||||
|
@ -265,7 +292,8 @@ pub unsafe fn create_object(
|
||||||
methods: &[Guard<&'static [JSFunctionSpec]>],
|
methods: &[Guard<&'static [JSFunctionSpec]>],
|
||||||
properties: &[Guard<&'static [JSPropertySpec]>],
|
properties: &[Guard<&'static [JSPropertySpec]>],
|
||||||
constants: &[Guard<&[ConstantSpec]>],
|
constants: &[Guard<&[ConstantSpec]>],
|
||||||
mut rval: MutableHandleObject) {
|
mut rval: MutableHandleObject,
|
||||||
|
) {
|
||||||
rval.set(JS_NewObjectWithUniqueType(cx, class, proto));
|
rval.set(JS_NewObjectWithUniqueType(cx, class, proto));
|
||||||
assert!(!rval.is_null());
|
assert!(!rval.is_null());
|
||||||
define_guarded_methods(cx, rval.handle(), methods);
|
define_guarded_methods(cx, rval.handle(), methods);
|
||||||
|
@ -277,7 +305,8 @@ pub unsafe fn create_object(
|
||||||
pub unsafe fn define_guarded_constants(
|
pub unsafe fn define_guarded_constants(
|
||||||
cx: *mut JSContext,
|
cx: *mut JSContext,
|
||||||
obj: HandleObject,
|
obj: HandleObject,
|
||||||
constants: &[Guard<&[ConstantSpec]>]) {
|
constants: &[Guard<&[ConstantSpec]>],
|
||||||
|
) {
|
||||||
for guard in constants {
|
for guard in constants {
|
||||||
if let Some(specs) = guard.expose(cx, obj) {
|
if let Some(specs) = guard.expose(cx, obj) {
|
||||||
define_constants(cx, obj, specs);
|
define_constants(cx, obj, specs);
|
||||||
|
@ -289,7 +318,8 @@ pub unsafe fn define_guarded_constants(
|
||||||
pub unsafe fn define_guarded_methods(
|
pub unsafe fn define_guarded_methods(
|
||||||
cx: *mut JSContext,
|
cx: *mut JSContext,
|
||||||
obj: HandleObject,
|
obj: HandleObject,
|
||||||
methods: &[Guard<&'static [JSFunctionSpec]>]) {
|
methods: &[Guard<&'static [JSFunctionSpec]>],
|
||||||
|
) {
|
||||||
for guard in methods {
|
for guard in methods {
|
||||||
if let Some(specs) = guard.expose(cx, obj) {
|
if let Some(specs) = guard.expose(cx, obj) {
|
||||||
define_methods(cx, obj, specs).unwrap();
|
define_methods(cx, obj, specs).unwrap();
|
||||||
|
@ -301,7 +331,8 @@ pub unsafe fn define_guarded_methods(
|
||||||
pub unsafe fn define_guarded_properties(
|
pub unsafe fn define_guarded_properties(
|
||||||
cx: *mut JSContext,
|
cx: *mut JSContext,
|
||||||
obj: HandleObject,
|
obj: HandleObject,
|
||||||
properties: &[Guard<&'static [JSPropertySpec]>]) {
|
properties: &[Guard<&'static [JSPropertySpec]>],
|
||||||
|
) {
|
||||||
for guard in properties {
|
for guard in properties {
|
||||||
if let Some(specs) = guard.expose(cx, obj) {
|
if let Some(specs) = guard.expose(cx, obj) {
|
||||||
define_properties(cx, obj, specs).unwrap();
|
define_properties(cx, obj, specs).unwrap();
|
||||||
|
@ -323,13 +354,16 @@ pub unsafe fn define_on_global_object(
|
||||||
cx: *mut JSContext,
|
cx: *mut JSContext,
|
||||||
global: HandleObject,
|
global: HandleObject,
|
||||||
name: &[u8],
|
name: &[u8],
|
||||||
obj: HandleObject) {
|
obj: HandleObject,
|
||||||
|
) {
|
||||||
assert_eq!(*name.last().unwrap(), b'\0');
|
assert_eq!(*name.last().unwrap(), b'\0');
|
||||||
assert!(JS_DefineProperty2(cx,
|
assert!(JS_DefineProperty2(
|
||||||
|
cx,
|
||||||
global,
|
global,
|
||||||
name.as_ptr() as *const libc::c_char,
|
name.as_ptr() as *const libc::c_char,
|
||||||
obj,
|
obj,
|
||||||
JSPROP_RESOLVING));
|
JSPROP_RESOLVING
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
const OBJECT_OPS: ObjectOps = ObjectOps {
|
const OBJECT_OPS: ObjectOps = ObjectOps {
|
||||||
|
@ -344,10 +378,11 @@ const OBJECT_OPS: ObjectOps = ObjectOps {
|
||||||
funToString: Some(fun_to_string_hook),
|
funToString: Some(fun_to_string_hook),
|
||||||
};
|
};
|
||||||
|
|
||||||
unsafe extern "C" fn fun_to_string_hook(cx: *mut JSContext,
|
unsafe extern "C" fn fun_to_string_hook(
|
||||||
|
cx: *mut JSContext,
|
||||||
obj: RawHandleObject,
|
obj: RawHandleObject,
|
||||||
_is_to_source: bool)
|
_is_to_source: bool,
|
||||||
-> *mut JSString {
|
) -> *mut JSString {
|
||||||
let js_class = get_object_class(obj.get());
|
let js_class = get_object_class(obj.get());
|
||||||
assert!(!js_class.is_null());
|
assert!(!js_class.is_null());
|
||||||
let repr = (*(js_class as *const NonCallbackInterfaceObjectClass)).representation;
|
let repr = (*(js_class as *const NonCallbackInterfaceObjectClass)).representation;
|
||||||
|
@ -358,17 +393,19 @@ unsafe extern "C" fn fun_to_string_hook(cx: *mut JSContext,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Hook for instanceof on interface objects.
|
/// Hook for instanceof on interface objects.
|
||||||
unsafe extern "C" fn has_instance_hook(cx: *mut JSContext,
|
unsafe extern "C" fn has_instance_hook(
|
||||||
|
cx: *mut JSContext,
|
||||||
obj: RawHandleObject,
|
obj: RawHandleObject,
|
||||||
value: RawMutableHandleValue,
|
value: RawMutableHandleValue,
|
||||||
rval: *mut bool) -> bool {
|
rval: *mut bool,
|
||||||
|
) -> bool {
|
||||||
let obj_raw = HandleObject::from_raw(obj);
|
let obj_raw = HandleObject::from_raw(obj);
|
||||||
let val_raw = HandleValue::from_raw(value.handle());
|
let val_raw = HandleValue::from_raw(value.handle());
|
||||||
match has_instance(cx, obj_raw, val_raw) {
|
match has_instance(cx, obj_raw, val_raw) {
|
||||||
Ok(result) => {
|
Ok(result) => {
|
||||||
*rval = result;
|
*rval = result;
|
||||||
true
|
true
|
||||||
}
|
},
|
||||||
Err(()) => false,
|
Err(()) => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -378,8 +415,8 @@ unsafe extern "C" fn has_instance_hook(cx: *mut JSContext,
|
||||||
unsafe fn has_instance(
|
unsafe fn has_instance(
|
||||||
cx: *mut JSContext,
|
cx: *mut JSContext,
|
||||||
interface_object: HandleObject,
|
interface_object: HandleObject,
|
||||||
value: HandleValue)
|
value: HandleValue,
|
||||||
-> Result<bool, ()> {
|
) -> Result<bool, ()> {
|
||||||
if !value.is_object() {
|
if !value.is_object() {
|
||||||
// Step 1.
|
// Step 1.
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
|
@ -391,8 +428,10 @@ unsafe fn has_instance(
|
||||||
let js_class = get_object_class(interface_object.get());
|
let js_class = get_object_class(interface_object.get());
|
||||||
let object_class = &*(js_class as *const NonCallbackInterfaceObjectClass);
|
let object_class = &*(js_class as *const NonCallbackInterfaceObjectClass);
|
||||||
|
|
||||||
if let Ok(dom_class) = get_dom_class(UncheckedUnwrapObject(value.get(),
|
if let Ok(dom_class) = get_dom_class(UncheckedUnwrapObject(
|
||||||
/* stopAtWindowProxy = */ 0)) {
|
value.get(),
|
||||||
|
/* stopAtWindowProxy = */ 0,
|
||||||
|
)) {
|
||||||
if dom_class.interface_chain[object_class.proto_depth as usize] == object_class.proto_id {
|
if dom_class.interface_chain[object_class.proto_depth as usize] == object_class.proto_id {
|
||||||
// Step 4.
|
// Step 4.
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
|
@ -424,7 +463,8 @@ unsafe fn has_instance(
|
||||||
unsafe fn create_unscopable_object(
|
unsafe fn create_unscopable_object(
|
||||||
cx: *mut JSContext,
|
cx: *mut JSContext,
|
||||||
names: &[&[u8]],
|
names: &[&[u8]],
|
||||||
mut rval: MutableHandleObject) {
|
mut rval: MutableHandleObject,
|
||||||
|
) {
|
||||||
assert!(!names.is_empty());
|
assert!(!names.is_empty());
|
||||||
assert!(rval.is_null());
|
assert!(rval.is_null());
|
||||||
rval.set(JS_NewPlainObject(cx));
|
rval.set(JS_NewPlainObject(cx));
|
||||||
|
@ -445,26 +485,30 @@ unsafe fn define_name(cx: *mut JSContext, obj: HandleObject, name: &[u8]) {
|
||||||
assert_eq!(*name.last().unwrap(), b'\0');
|
assert_eq!(*name.last().unwrap(), b'\0');
|
||||||
rooted!(in(cx) let name = JS_AtomizeAndPinString(cx, name.as_ptr() as *const libc::c_char));
|
rooted!(in(cx) let name = JS_AtomizeAndPinString(cx, name.as_ptr() as *const libc::c_char));
|
||||||
assert!(!name.is_null());
|
assert!(!name.is_null());
|
||||||
assert!(JS_DefineProperty3(cx,
|
assert!(JS_DefineProperty3(
|
||||||
|
cx,
|
||||||
obj,
|
obj,
|
||||||
b"name\0".as_ptr() as *const libc::c_char,
|
b"name\0".as_ptr() as *const libc::c_char,
|
||||||
name.handle().into(),
|
name.handle().into(),
|
||||||
JSPROP_READONLY as u32));
|
JSPROP_READONLY as u32
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn define_length(cx: *mut JSContext, obj: HandleObject, length: i32) {
|
unsafe fn define_length(cx: *mut JSContext, obj: HandleObject, length: i32) {
|
||||||
assert!(JS_DefineProperty4(cx,
|
assert!(JS_DefineProperty4(
|
||||||
|
cx,
|
||||||
obj,
|
obj,
|
||||||
b"length\0".as_ptr() as *const libc::c_char,
|
b"length\0".as_ptr() as *const libc::c_char,
|
||||||
length,
|
length,
|
||||||
JSPROP_READONLY as u32));
|
JSPROP_READONLY as u32
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe extern "C" fn invalid_constructor(
|
unsafe extern "C" fn invalid_constructor(
|
||||||
cx: *mut JSContext,
|
cx: *mut JSContext,
|
||||||
_argc: libc::c_uint,
|
_argc: libc::c_uint,
|
||||||
_vp: *mut JSVal)
|
_vp: *mut JSVal,
|
||||||
-> bool {
|
) -> bool {
|
||||||
throw_type_error(cx, "Illegal constructor.");
|
throw_type_error(cx, "Illegal constructor.");
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
@ -472,8 +516,8 @@ unsafe extern "C" fn invalid_constructor(
|
||||||
unsafe extern "C" fn non_new_constructor(
|
unsafe extern "C" fn non_new_constructor(
|
||||||
cx: *mut JSContext,
|
cx: *mut JSContext,
|
||||||
_argc: libc::c_uint,
|
_argc: libc::c_uint,
|
||||||
_vp: *mut JSVal)
|
_vp: *mut JSVal,
|
||||||
-> bool {
|
) -> bool {
|
||||||
throw_type_error(cx, "This constructor needs to be called with `new`.");
|
throw_type_error(cx, "This constructor needs to be called with `new`.");
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,10 +59,11 @@ pub struct IterableIterator<T: DomObject + JSTraceable + Iterable> {
|
||||||
|
|
||||||
impl<T: DomObject + JSTraceable + Iterable> IterableIterator<T> {
|
impl<T: DomObject + JSTraceable + Iterable> IterableIterator<T> {
|
||||||
/// Create a new iterator instance for the provided iterable DOM interface.
|
/// Create a new iterator instance for the provided iterable DOM interface.
|
||||||
pub fn new(iterable: &T,
|
pub fn new(
|
||||||
|
iterable: &T,
|
||||||
type_: IteratorType,
|
type_: IteratorType,
|
||||||
wrap: unsafe fn(*mut JSContext, &GlobalScope, Box<IterableIterator<T>>)
|
wrap: unsafe fn(*mut JSContext, &GlobalScope, Box<IterableIterator<T>>) -> DomRoot<Self>,
|
||||||
-> DomRoot<Self>) -> DomRoot<Self> {
|
) -> DomRoot<Self> {
|
||||||
let iterator = Box::new(IterableIterator {
|
let iterator = Box::new(IterableIterator {
|
||||||
reflector: Reflector::new(),
|
reflector: Reflector::new(),
|
||||||
type_: type_,
|
type_: type_,
|
||||||
|
@ -84,37 +85,45 @@ impl<T: DomObject + JSTraceable + Iterable> IterableIterator<T> {
|
||||||
match self.type_ {
|
match self.type_ {
|
||||||
IteratorType::Keys => {
|
IteratorType::Keys => {
|
||||||
unsafe {
|
unsafe {
|
||||||
self.iterable.get_key_at_index(index).to_jsval(cx, value.handle_mut());
|
self.iterable
|
||||||
|
.get_key_at_index(index)
|
||||||
|
.to_jsval(cx, value.handle_mut());
|
||||||
}
|
}
|
||||||
dict_return(cx, rval.handle_mut(), false, value.handle())
|
dict_return(cx, rval.handle_mut(), false, value.handle())
|
||||||
}
|
},
|
||||||
IteratorType::Values => {
|
IteratorType::Values => {
|
||||||
unsafe {
|
unsafe {
|
||||||
self.iterable.get_value_at_index(index).to_jsval(cx, value.handle_mut());
|
self.iterable
|
||||||
|
.get_value_at_index(index)
|
||||||
|
.to_jsval(cx, value.handle_mut());
|
||||||
}
|
}
|
||||||
dict_return(cx, rval.handle_mut(), false, value.handle())
|
dict_return(cx, rval.handle_mut(), false, value.handle())
|
||||||
}
|
},
|
||||||
IteratorType::Entries => {
|
IteratorType::Entries => {
|
||||||
rooted!(in(cx) let mut key = UndefinedValue());
|
rooted!(in(cx) let mut key = UndefinedValue());
|
||||||
unsafe {
|
unsafe {
|
||||||
self.iterable.get_key_at_index(index).to_jsval(cx, key.handle_mut());
|
self.iterable
|
||||||
self.iterable.get_value_at_index(index).to_jsval(cx, value.handle_mut());
|
.get_key_at_index(index)
|
||||||
|
.to_jsval(cx, key.handle_mut());
|
||||||
|
self.iterable
|
||||||
|
.get_value_at_index(index)
|
||||||
|
.to_jsval(cx, value.handle_mut());
|
||||||
}
|
}
|
||||||
key_and_value_return(cx, rval.handle_mut(), key.handle(), value.handle())
|
key_and_value_return(cx, rval.handle_mut(), key.handle(), value.handle())
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
self.index.set(index + 1);
|
self.index.set(index + 1);
|
||||||
result.map(|_| {
|
result.map(|_| NonNull::new(rval.get()).expect("got a null pointer"))
|
||||||
NonNull::new(rval.get()).expect("got a null pointer")
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dict_return(cx: *mut JSContext,
|
fn dict_return(
|
||||||
|
cx: *mut JSContext,
|
||||||
mut result: MutableHandleObject,
|
mut result: MutableHandleObject,
|
||||||
done: bool,
|
done: bool,
|
||||||
value: HandleValue) -> Fallible<()> {
|
value: HandleValue,
|
||||||
|
) -> Fallible<()> {
|
||||||
let mut dict = IterableKeyOrValueResult::empty();
|
let mut dict = IterableKeyOrValueResult::empty();
|
||||||
dict.done = done;
|
dict.done = done;
|
||||||
dict.value.set(value.get());
|
dict.value.set(value.get());
|
||||||
|
@ -126,16 +135,20 @@ fn dict_return(cx: *mut JSContext,
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn key_and_value_return(cx: *mut JSContext,
|
fn key_and_value_return(
|
||||||
|
cx: *mut JSContext,
|
||||||
mut result: MutableHandleObject,
|
mut result: MutableHandleObject,
|
||||||
key: HandleValue,
|
key: HandleValue,
|
||||||
value: HandleValue) -> Fallible<()> {
|
value: HandleValue,
|
||||||
|
) -> Fallible<()> {
|
||||||
let mut dict = IterableKeyAndValueResult::empty();
|
let mut dict = IterableKeyAndValueResult::empty();
|
||||||
dict.done = false;
|
dict.done = false;
|
||||||
dict.value = Some(vec![key, value]
|
dict.value = Some(
|
||||||
|
vec![key, value]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|handle| RootedTraceableBox::from_box(Heap::boxed(handle.get())))
|
.map(|handle| RootedTraceableBox::from_box(Heap::boxed(handle.get())))
|
||||||
.collect());
|
.collect(),
|
||||||
|
);
|
||||||
rooted!(in(cx) let mut dict_value = UndefinedValue());
|
rooted!(in(cx) let mut dict_value = UndefinedValue());
|
||||||
unsafe {
|
unsafe {
|
||||||
dict.to_jsval(cx, dict_value.handle_mut());
|
dict.to_jsval(cx, dict_value.handle_mut());
|
||||||
|
|
|
@ -49,24 +49,37 @@ impl<T> Deref for MozMap<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, C> FromJSValConvertible for MozMap<T>
|
impl<T, C> FromJSValConvertible for MozMap<T>
|
||||||
where T: FromJSValConvertible<Config=C>,
|
where
|
||||||
|
T: FromJSValConvertible<Config = C>,
|
||||||
C: Clone,
|
C: Clone,
|
||||||
{
|
{
|
||||||
type Config = C;
|
type Config = C;
|
||||||
unsafe fn from_jsval(cx: *mut JSContext, value: HandleValue, config: C)
|
unsafe fn from_jsval(
|
||||||
-> Result<ConversionResult<Self>, ()> {
|
cx: *mut JSContext,
|
||||||
|
value: HandleValue,
|
||||||
|
config: C,
|
||||||
|
) -> Result<ConversionResult<Self>, ()> {
|
||||||
if !value.is_object() {
|
if !value.is_object() {
|
||||||
return Ok(ConversionResult::Failure("MozMap value was not an object".into()));
|
return Ok(ConversionResult::Failure(
|
||||||
|
"MozMap value was not an object".into(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
rooted!(in(cx) let object = value.to_object());
|
rooted!(in(cx) let object = value.to_object());
|
||||||
let ids = IdVector::new(cx);
|
let ids = IdVector::new(cx);
|
||||||
if !GetPropertyKeys(cx, object.handle(), JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, ids.get()) {
|
if !GetPropertyKeys(
|
||||||
|
cx,
|
||||||
|
object.handle(),
|
||||||
|
JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS,
|
||||||
|
ids.get(),
|
||||||
|
) {
|
||||||
// TODO: can GetPropertyKeys fail?
|
// TODO: can GetPropertyKeys fail?
|
||||||
// (it does so if the object has duplicate keys)
|
// (it does so if the object has duplicate keys)
|
||||||
// https://github.com/servo/servo/issues/21462
|
// https://github.com/servo/servo/issues/21462
|
||||||
report_pending_exception(cx, false);
|
report_pending_exception(cx, false);
|
||||||
return Ok(ConversionResult::Failure("Getting MozMap value property keys failed".into()));
|
return Ok(ConversionResult::Failure(
|
||||||
|
"Getting MozMap value property keys failed".into(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut map = HashMap::new();
|
let mut map = HashMap::new();
|
||||||
|
@ -90,9 +103,7 @@ impl<T, C> FromJSValConvertible for MozMap<T>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(ConversionResult::Success(MozMap {
|
Ok(ConversionResult::Success(MozMap { map: map }))
|
||||||
map: map,
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,12 +118,14 @@ impl<T: ToJSValConvertible> ToJSValConvertible for MozMap<T> {
|
||||||
let key = key.encode_utf16().collect::<Vec<_>>();
|
let key = key.encode_utf16().collect::<Vec<_>>();
|
||||||
value.to_jsval(cx, js_value.handle_mut());
|
value.to_jsval(cx, js_value.handle_mut());
|
||||||
|
|
||||||
assert!(JS_DefineUCProperty2(cx,
|
assert!(JS_DefineUCProperty2(
|
||||||
|
cx,
|
||||||
js_object.handle(),
|
js_object.handle(),
|
||||||
key.as_ptr(),
|
key.as_ptr(),
|
||||||
key.len(),
|
key.len(),
|
||||||
js_value.handle(),
|
js_value.handle(),
|
||||||
JSPROP_ENUMERATE as u32));
|
JSPROP_ENUMERATE as u32
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
rval.set(ObjectValue(js_object.handle().get()));
|
rval.set(ObjectValue(js_object.handle().get()));
|
||||||
|
|
|
@ -36,7 +36,8 @@ pub unsafe fn create_namespace_object(
|
||||||
class: &'static NamespaceObjectClass,
|
class: &'static NamespaceObjectClass,
|
||||||
methods: &[Guard<&'static [JSFunctionSpec]>],
|
methods: &[Guard<&'static [JSFunctionSpec]>],
|
||||||
name: &[u8],
|
name: &[u8],
|
||||||
rval: MutableHandleObject) {
|
rval: MutableHandleObject,
|
||||||
|
) {
|
||||||
create_object(cx, proto, &class.0, methods, &[], &[], rval);
|
create_object(cx, proto, &class.0, methods, &[], &[], rval);
|
||||||
define_on_global_object(cx, global, name, rval.handle());
|
define_on_global_object(cx, global, name, rval.handle());
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,12 +30,12 @@ use js::rust::wrappers::JS_AlreadyHasOwnPropertyById;
|
||||||
use js::rust::wrappers::JS_NewObjectWithGivenProto;
|
use js::rust::wrappers::JS_NewObjectWithGivenProto;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
|
|
||||||
/// Determine if this id shadows any existing properties for this proxy.
|
/// Determine if this id shadows any existing properties for this proxy.
|
||||||
pub unsafe extern "C" fn shadow_check_callback(cx: *mut JSContext,
|
pub unsafe extern "C" fn shadow_check_callback(
|
||||||
|
cx: *mut JSContext,
|
||||||
object: RawHandleObject,
|
object: RawHandleObject,
|
||||||
id: RawHandleId)
|
id: RawHandleId,
|
||||||
-> DOMProxyShadowsResult {
|
) -> DOMProxyShadowsResult {
|
||||||
// TODO: support OverrideBuiltins when #12978 is fixed.
|
// TODO: support OverrideBuiltins when #12978 is fixed.
|
||||||
|
|
||||||
rooted!(in(cx) let mut expando = ptr::null_mut::<JSObject>());
|
rooted!(in(cx) let mut expando = ptr::null_mut::<JSObject>());
|
||||||
|
@ -59,19 +59,19 @@ pub unsafe extern "C" fn shadow_check_callback(cx: *mut JSContext,
|
||||||
|
|
||||||
/// Initialize the infrastructure for DOM proxy objects.
|
/// Initialize the infrastructure for DOM proxy objects.
|
||||||
pub unsafe fn init() {
|
pub unsafe fn init() {
|
||||||
SetDOMProxyInformation(GetProxyHandlerFamily(),
|
SetDOMProxyInformation(GetProxyHandlerFamily(), Some(shadow_check_callback));
|
||||||
Some(shadow_check_callback));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Invoke the [[GetOwnProperty]] trap (`getOwnPropertyDescriptor`) on `proxy`,
|
/// Invoke the [[GetOwnProperty]] trap (`getOwnPropertyDescriptor`) on `proxy`,
|
||||||
/// with argument `id` and return the result, if it is not `undefined`.
|
/// with argument `id` and return the result, if it is not `undefined`.
|
||||||
/// Otherwise, walk along the prototype chain to find a property with that
|
/// Otherwise, walk along the prototype chain to find a property with that
|
||||||
/// name.
|
/// name.
|
||||||
pub unsafe extern "C" fn get_property_descriptor(cx: *mut JSContext,
|
pub unsafe extern "C" fn get_property_descriptor(
|
||||||
|
cx: *mut JSContext,
|
||||||
proxy: RawHandleObject,
|
proxy: RawHandleObject,
|
||||||
id: RawHandleId,
|
id: RawHandleId,
|
||||||
desc: RawMutableHandle<PropertyDescriptor>)
|
desc: RawMutableHandle<PropertyDescriptor>,
|
||||||
-> bool {
|
) -> bool {
|
||||||
let handler = GetProxyHandler(proxy.get());
|
let handler = GetProxyHandler(proxy.get());
|
||||||
if !InvokeGetOwnPropertyDescriptor(handler, cx, proxy, id, desc) {
|
if !InvokeGetOwnPropertyDescriptor(handler, cx, proxy, id, desc) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -91,23 +91,25 @@ pub unsafe extern "C" fn get_property_descriptor(cx: *mut JSContext,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Defines an expando on the given `proxy`.
|
/// Defines an expando on the given `proxy`.
|
||||||
pub unsafe extern "C" fn define_property(cx: *mut JSContext,
|
pub unsafe extern "C" fn define_property(
|
||||||
|
cx: *mut JSContext,
|
||||||
proxy: RawHandleObject,
|
proxy: RawHandleObject,
|
||||||
id: RawHandleId,
|
id: RawHandleId,
|
||||||
desc: RawHandle<PropertyDescriptor>,
|
desc: RawHandle<PropertyDescriptor>,
|
||||||
result: *mut ObjectOpResult)
|
result: *mut ObjectOpResult,
|
||||||
-> bool {
|
) -> bool {
|
||||||
rooted!(in(cx) let mut expando = ptr::null_mut::<JSObject>());
|
rooted!(in(cx) let mut expando = ptr::null_mut::<JSObject>());
|
||||||
ensure_expando_object(cx, proxy, expando.handle_mut());
|
ensure_expando_object(cx, proxy, expando.handle_mut());
|
||||||
JS_DefinePropertyById(cx, expando.handle().into(), id, desc, result)
|
JS_DefinePropertyById(cx, expando.handle().into(), id, desc, result)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deletes an expando off the given `proxy`.
|
/// Deletes an expando off the given `proxy`.
|
||||||
pub unsafe extern "C" fn delete(cx: *mut JSContext,
|
pub unsafe extern "C" fn delete(
|
||||||
|
cx: *mut JSContext,
|
||||||
proxy: RawHandleObject,
|
proxy: RawHandleObject,
|
||||||
id: RawHandleId,
|
id: RawHandleId,
|
||||||
bp: *mut ObjectOpResult)
|
bp: *mut ObjectOpResult,
|
||||||
-> bool {
|
) -> bool {
|
||||||
rooted!(in(cx) let mut expando = ptr::null_mut::<JSObject>());
|
rooted!(in(cx) let mut expando = ptr::null_mut::<JSObject>());
|
||||||
get_expando_object(proxy, expando.handle_mut());
|
get_expando_object(proxy, expando.handle_mut());
|
||||||
if expando.is_null() {
|
if expando.is_null() {
|
||||||
|
@ -119,19 +121,21 @@ pub unsafe extern "C" fn delete(cx: *mut JSContext,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Controls whether the Extensible bit can be changed
|
/// Controls whether the Extensible bit can be changed
|
||||||
pub unsafe extern "C" fn prevent_extensions(_cx: *mut JSContext,
|
pub unsafe extern "C" fn prevent_extensions(
|
||||||
|
_cx: *mut JSContext,
|
||||||
_proxy: RawHandleObject,
|
_proxy: RawHandleObject,
|
||||||
result: *mut ObjectOpResult)
|
result: *mut ObjectOpResult,
|
||||||
-> bool {
|
) -> bool {
|
||||||
(*result).code_ = JSErrNum::JSMSG_CANT_PREVENT_EXTENSIONS as ::libc::uintptr_t;
|
(*result).code_ = JSErrNum::JSMSG_CANT_PREVENT_EXTENSIONS as ::libc::uintptr_t;
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reports whether the object is Extensible
|
/// Reports whether the object is Extensible
|
||||||
pub unsafe extern "C" fn is_extensible(_cx: *mut JSContext,
|
pub unsafe extern "C" fn is_extensible(
|
||||||
|
_cx: *mut JSContext,
|
||||||
_proxy: RawHandleObject,
|
_proxy: RawHandleObject,
|
||||||
succeeded: *mut bool)
|
succeeded: *mut bool,
|
||||||
-> bool {
|
) -> bool {
|
||||||
*succeeded = true;
|
*succeeded = true;
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
@ -145,11 +149,12 @@ pub unsafe extern "C" fn is_extensible(_cx: *mut JSContext,
|
||||||
/// This implementation always handles the case of the ordinary
|
/// This implementation always handles the case of the ordinary
|
||||||
/// `[[GetPrototypeOf]]` behavior. An alternative implementation will be
|
/// `[[GetPrototypeOf]]` behavior. An alternative implementation will be
|
||||||
/// necessary for the Location object.
|
/// necessary for the Location object.
|
||||||
pub unsafe extern "C" fn get_prototype_if_ordinary(_: *mut JSContext,
|
pub unsafe extern "C" fn get_prototype_if_ordinary(
|
||||||
|
_: *mut JSContext,
|
||||||
proxy: RawHandleObject,
|
proxy: RawHandleObject,
|
||||||
is_ordinary: *mut bool,
|
is_ordinary: *mut bool,
|
||||||
proto: RawMutableHandleObject)
|
proto: RawMutableHandleObject,
|
||||||
-> bool {
|
) -> bool {
|
||||||
*is_ordinary = true;
|
*is_ordinary = true;
|
||||||
proto.set(GetStaticPrototype(proxy.get()));
|
proto.set(GetStaticPrototype(proxy.get()));
|
||||||
true
|
true
|
||||||
|
@ -169,11 +174,19 @@ pub unsafe fn get_expando_object(obj: RawHandleObject, mut expando: MutableHandl
|
||||||
|
|
||||||
/// Get the expando object, or create it if it doesn't exist yet.
|
/// Get the expando object, or create it if it doesn't exist yet.
|
||||||
/// Fails on JSAPI failure.
|
/// Fails on JSAPI failure.
|
||||||
pub unsafe fn ensure_expando_object(cx: *mut JSContext, obj: RawHandleObject, mut expando: MutableHandleObject) {
|
pub unsafe fn ensure_expando_object(
|
||||||
|
cx: *mut JSContext,
|
||||||
|
obj: RawHandleObject,
|
||||||
|
mut expando: MutableHandleObject,
|
||||||
|
) {
|
||||||
assert!(is_dom_proxy(obj.get()));
|
assert!(is_dom_proxy(obj.get()));
|
||||||
get_expando_object(obj, expando);
|
get_expando_object(obj, expando);
|
||||||
if expando.is_null() {
|
if expando.is_null() {
|
||||||
expando.set(JS_NewObjectWithGivenProto(cx, ptr::null_mut(), HandleObject::null()));
|
expando.set(JS_NewObjectWithGivenProto(
|
||||||
|
cx,
|
||||||
|
ptr::null_mut(),
|
||||||
|
HandleObject::null(),
|
||||||
|
));
|
||||||
assert!(!expando.is_null());
|
assert!(!expando.is_null());
|
||||||
|
|
||||||
SetProxyPrivate(obj.get(), &ObjectValue(expando.get()));
|
SetProxyPrivate(obj.get(), &ObjectValue(expando.get()));
|
||||||
|
@ -182,9 +195,11 @@ pub unsafe fn ensure_expando_object(cx: *mut JSContext, obj: RawHandleObject, mu
|
||||||
|
|
||||||
/// Set the property descriptor's object to `obj` and set it to enumerable,
|
/// Set the property descriptor's object to `obj` and set it to enumerable,
|
||||||
/// and writable if `readonly` is true.
|
/// and writable if `readonly` is true.
|
||||||
pub fn fill_property_descriptor(mut desc: MutableHandle<PropertyDescriptor>,
|
pub fn fill_property_descriptor(
|
||||||
|
mut desc: MutableHandle<PropertyDescriptor>,
|
||||||
obj: *mut JSObject,
|
obj: *mut JSObject,
|
||||||
attrs: u32) {
|
attrs: u32,
|
||||||
|
) {
|
||||||
desc.obj = obj;
|
desc.obj = obj;
|
||||||
desc.attrs = attrs;
|
desc.attrs = attrs;
|
||||||
desc.getter = None;
|
desc.getter = None;
|
||||||
|
|
|
@ -39,9 +39,9 @@ use std::rc::Rc;
|
||||||
use std::sync::{Arc, Weak};
|
use std::sync::{Arc, Weak};
|
||||||
use task::TaskOnce;
|
use task::TaskOnce;
|
||||||
|
|
||||||
|
|
||||||
#[allow(missing_docs)] // FIXME
|
#[allow(missing_docs)] // FIXME
|
||||||
mod dummy { // Attributes don’t apply through the macro.
|
mod dummy {
|
||||||
|
// Attributes don’t 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 don’t 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();
|
||||||
|
|
|
@ -16,14 +16,14 @@ use std::default::Default;
|
||||||
pub fn reflect_dom_object<T, U>(
|
pub fn reflect_dom_object<T, U>(
|
||||||
obj: Box<T>,
|
obj: Box<T>,
|
||||||
global: &U,
|
global: &U,
|
||||||
wrap_fn: unsafe fn(*mut JSContext, &GlobalScope, Box<T>) -> DomRoot<T>)
|
wrap_fn: unsafe fn(*mut JSContext, &GlobalScope, Box<T>) -> DomRoot<T>,
|
||||||
-> DomRoot<T>
|
) -> DomRoot<T>
|
||||||
where T: DomObject, U: DerivedFrom<GlobalScope>
|
where
|
||||||
|
T: DomObject,
|
||||||
|
U: DerivedFrom<GlobalScope>,
|
||||||
{
|
{
|
||||||
let global_scope = global.upcast();
|
let global_scope = global.upcast();
|
||||||
unsafe {
|
unsafe { wrap_fn(global_scope.get_cx(), global_scope, obj) }
|
||||||
wrap_fn(global_scope.get_cx(), global_scope, obj)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A struct to store a reference to the reflector of a DOM object.
|
/// A struct to store a reference to the reflector of a DOM object.
|
||||||
|
@ -79,7 +79,10 @@ pub trait DomObject: 'static {
|
||||||
fn reflector(&self) -> &Reflector;
|
fn reflector(&self) -> &Reflector;
|
||||||
|
|
||||||
/// Returns the global scope of the realm that the DomObject was created in.
|
/// Returns the global scope of the realm that the DomObject was created in.
|
||||||
fn global(&self) -> DomRoot<GlobalScope> where Self: Sized {
|
fn global(&self) -> DomRoot<GlobalScope>
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
GlobalScope::from_reflector(self)
|
GlobalScope::from_reflector(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,9 +96,7 @@ where
|
||||||
trace_reflector(tracer, "on stack", &self.0);
|
trace_reflector(tracer, "on stack", &self.0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unsafe {
|
unsafe { &*(self.reflector() as *const Reflector as *const ReflectorStackRoot) }
|
||||||
&*(self.reflector() as *const Reflector as *const ReflectorStackRoot)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,15 +129,17 @@ pub type DomRoot<T> = Root<Dom<T>>;
|
||||||
impl<T: Castable> DomRoot<T> {
|
impl<T: Castable> DomRoot<T> {
|
||||||
/// Cast a DOM object root upwards to one of the interfaces it derives from.
|
/// Cast a DOM object root upwards to one of the interfaces it derives from.
|
||||||
pub fn upcast<U>(root: DomRoot<T>) -> DomRoot<U>
|
pub fn upcast<U>(root: DomRoot<T>) -> DomRoot<U>
|
||||||
where U: Castable,
|
where
|
||||||
T: DerivedFrom<U>
|
U: Castable,
|
||||||
|
T: DerivedFrom<U>,
|
||||||
{
|
{
|
||||||
unsafe { mem::transmute(root) }
|
unsafe { mem::transmute(root) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Cast a DOM object root downwards to one of the interfaces it might implement.
|
/// Cast a DOM object root downwards to one of the interfaces it might implement.
|
||||||
pub fn downcast<U>(root: DomRoot<T>) -> Option<DomRoot<U>>
|
pub fn downcast<U>(root: DomRoot<T>) -> Option<DomRoot<U>>
|
||||||
where U: DerivedFrom<T>
|
where
|
||||||
|
U: DerivedFrom<T>,
|
||||||
{
|
{
|
||||||
if root.is::<U>() {
|
if root.is::<U>() {
|
||||||
Some(unsafe { mem::transmute(root) })
|
Some(unsafe { mem::transmute(root) })
|
||||||
|
@ -207,9 +207,7 @@ pub struct ThreadLocalStackRoots<'a>(PhantomData<&'a u32>);
|
||||||
|
|
||||||
impl<'a> ThreadLocalStackRoots<'a> {
|
impl<'a> ThreadLocalStackRoots<'a> {
|
||||||
pub fn new(roots: &'a RootCollection) -> Self {
|
pub fn new(roots: &'a RootCollection) -> Self {
|
||||||
STACK_ROOTS.with(|ref r| {
|
STACK_ROOTS.with(|ref r| r.set(Some(roots)));
|
||||||
r.set(Some(roots))
|
|
||||||
});
|
|
||||||
ThreadLocalStackRoots(PhantomData)
|
ThreadLocalStackRoots(PhantomData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -363,9 +361,7 @@ unsafe impl<T: DomObject> JSTraceable for Dom<T> {
|
||||||
#[cfg(not(all(feature = "unstable", debug_assertions)))]
|
#[cfg(not(all(feature = "unstable", debug_assertions)))]
|
||||||
let trace_info = "for DOM object on heap";
|
let trace_info = "for DOM object on heap";
|
||||||
|
|
||||||
trace_reflector(trc,
|
trace_reflector(trc, trace_info, (*self.ptr.as_ptr()).reflector());
|
||||||
trace_info,
|
|
||||||
(*self.ptr.as_ptr()).reflector());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -379,8 +375,9 @@ pub struct LayoutDom<T> {
|
||||||
impl<T: Castable> LayoutDom<T> {
|
impl<T: Castable> LayoutDom<T> {
|
||||||
/// Cast a DOM object root upwards to one of the interfaces it derives from.
|
/// Cast a DOM object root upwards to one of the interfaces it derives from.
|
||||||
pub fn upcast<U>(&self) -> LayoutDom<U>
|
pub fn upcast<U>(&self) -> LayoutDom<U>
|
||||||
where U: Castable,
|
where
|
||||||
T: DerivedFrom<U>
|
U: Castable,
|
||||||
|
T: DerivedFrom<U>,
|
||||||
{
|
{
|
||||||
debug_assert!(thread_state::get().is_layout());
|
debug_assert!(thread_state::get().is_layout());
|
||||||
let ptr: *mut T = self.ptr.as_ptr();
|
let ptr: *mut T = self.ptr.as_ptr();
|
||||||
|
@ -391,7 +388,8 @@ impl<T: Castable> LayoutDom<T> {
|
||||||
|
|
||||||
/// Cast a DOM object downwards to one of the interfaces it might implement.
|
/// Cast a DOM object downwards to one of the interfaces it might implement.
|
||||||
pub fn downcast<U>(&self) -> Option<LayoutDom<U>>
|
pub fn downcast<U>(&self) -> Option<LayoutDom<U>>
|
||||||
where U: DerivedFrom<T>
|
where
|
||||||
|
U: DerivedFrom<T>,
|
||||||
{
|
{
|
||||||
debug_assert!(thread_state::get().is_layout());
|
debug_assert!(thread_state::get().is_layout());
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -429,7 +427,6 @@ impl<'a, T: DomObject> PartialEq<&'a T> for Dom<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl<T> Eq for Dom<T> {}
|
impl<T> Eq for Dom<T> {}
|
||||||
|
|
||||||
impl<T> PartialEq for LayoutDom<T> {
|
impl<T> PartialEq for LayoutDom<T> {
|
||||||
|
@ -452,7 +449,7 @@ impl<T> Hash for LayoutDom<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <T> Clone for Dom<T> {
|
impl<T> Clone for Dom<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
#[allow(unrooted_must_root)]
|
#[allow(unrooted_must_root)]
|
||||||
fn clone(&self) -> Dom<T> {
|
fn clone(&self) -> Dom<T> {
|
||||||
|
@ -463,7 +460,7 @@ impl <T> Clone for Dom<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <T> Clone for LayoutDom<T> {
|
impl<T> Clone for LayoutDom<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn clone(&self) -> LayoutDom<T> {
|
fn clone(&self) -> LayoutDom<T> {
|
||||||
debug_assert!(thread_state::get().is_layout());
|
debug_assert!(thread_state::get().is_layout());
|
||||||
|
@ -516,9 +513,7 @@ impl<T: DomObject> MutDom<T> {
|
||||||
/// Get the value in this `MutDom`.
|
/// Get the value in this `MutDom`.
|
||||||
pub fn get(&self) -> DomRoot<T> {
|
pub fn get(&self) -> DomRoot<T> {
|
||||||
debug_assert!(thread_state::get().is_script());
|
debug_assert!(thread_state::get().is_script());
|
||||||
unsafe {
|
unsafe { DomRoot::from_ref(&*ptr::read(self.val.get())) }
|
||||||
DomRoot::from_ref(&*ptr::read(self.val.get()))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -531,17 +526,13 @@ impl<T: DomObject> MallocSizeOf for MutDom<T> {
|
||||||
|
|
||||||
impl<T: DomObject> PartialEq for MutDom<T> {
|
impl<T: DomObject> PartialEq for MutDom<T> {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
unsafe {
|
unsafe { *self.val.get() == *other.val.get() }
|
||||||
*self.val.get() == *other.val.get()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: DomObject + PartialEq> PartialEq<T> for MutDom<T> {
|
impl<T: DomObject + PartialEq> PartialEq<T> for MutDom<T> {
|
||||||
fn eq(&self, other: &T) -> bool {
|
fn eq(&self, other: &T) -> bool {
|
||||||
unsafe {
|
unsafe { **self.val.get() == *other }
|
||||||
**self.val.get() == *other
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -569,7 +560,8 @@ impl<T: DomObject> MutNullableDom<T> {
|
||||||
/// Retrieve a copy of the current inner value. If it is `None`, it is
|
/// Retrieve a copy of the current inner value. If it is `None`, it is
|
||||||
/// initialized with the result of `cb` first.
|
/// initialized with the result of `cb` first.
|
||||||
pub fn or_init<F>(&self, cb: F) -> DomRoot<T>
|
pub fn or_init<F>(&self, cb: F) -> DomRoot<T>
|
||||||
where F: FnOnce() -> DomRoot<T>
|
where
|
||||||
|
F: FnOnce() -> DomRoot<T>,
|
||||||
{
|
{
|
||||||
debug_assert!(thread_state::get().is_script());
|
debug_assert!(thread_state::get().is_script());
|
||||||
match self.get() {
|
match self.get() {
|
||||||
|
@ -594,9 +586,7 @@ impl<T: DomObject> MutNullableDom<T> {
|
||||||
#[allow(unrooted_must_root)]
|
#[allow(unrooted_must_root)]
|
||||||
pub fn get(&self) -> Option<DomRoot<T>> {
|
pub fn get(&self) -> Option<DomRoot<T>> {
|
||||||
debug_assert!(thread_state::get().is_script());
|
debug_assert!(thread_state::get().is_script());
|
||||||
unsafe {
|
unsafe { ptr::read(self.ptr.get()).map(|o| DomRoot::from_ref(&*o)) }
|
||||||
ptr::read(self.ptr.get()).map(|o| DomRoot::from_ref(&*o))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set this `MutNullableDom` to the given value.
|
/// Set this `MutNullableDom` to the given value.
|
||||||
|
@ -617,17 +607,13 @@ impl<T: DomObject> MutNullableDom<T> {
|
||||||
|
|
||||||
impl<T: DomObject> PartialEq for MutNullableDom<T> {
|
impl<T: DomObject> PartialEq for MutNullableDom<T> {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
unsafe {
|
unsafe { *self.ptr.get() == *other.ptr.get() }
|
||||||
*self.ptr.get() == *other.ptr.get()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T: DomObject> PartialEq<Option<&'a T>> for MutNullableDom<T> {
|
impl<'a, T: DomObject> PartialEq<Option<&'a T>> for MutNullableDom<T> {
|
||||||
fn eq(&self, other: &Option<&T>) -> bool {
|
fn eq(&self, other: &Option<&T>) -> bool {
|
||||||
unsafe {
|
unsafe { *self.ptr.get() == other.map(Dom::from_ref) }
|
||||||
*self.ptr.get() == other.map(Dom::from_ref)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -661,13 +647,14 @@ pub struct DomOnceCell<T: DomObject> {
|
||||||
|
|
||||||
impl<T> DomOnceCell<T>
|
impl<T> DomOnceCell<T>
|
||||||
where
|
where
|
||||||
T: DomObject
|
T: DomObject,
|
||||||
{
|
{
|
||||||
/// Retrieve a copy of the current inner value. If it is `None`, it is
|
/// Retrieve a copy of the current inner value. If it is `None`, it is
|
||||||
/// initialized with the result of `cb` first.
|
/// initialized with the result of `cb` first.
|
||||||
#[allow(unrooted_must_root)]
|
#[allow(unrooted_must_root)]
|
||||||
pub fn init_once<F>(&self, cb: F) -> &T
|
pub fn init_once<F>(&self, cb: F) -> &T
|
||||||
where F: FnOnce() -> DomRoot<T>
|
where
|
||||||
|
F: FnOnce() -> DomRoot<T>,
|
||||||
{
|
{
|
||||||
debug_assert!(thread_state::get().is_script());
|
debug_assert!(thread_state::get().is_script());
|
||||||
&self.ptr.init_once(|| Dom::from_ref(&cb()))
|
&self.ptr.init_once(|| Dom::from_ref(&cb()))
|
||||||
|
@ -725,14 +712,17 @@ pub trait OptionalHeapSetter {
|
||||||
fn set(&mut self, v: Option<Self::Value>);
|
fn set(&mut self, v: Option<Self::Value>);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: GCMethods + Copy> OptionalHeapSetter for Option<Heap<T>> where Heap<T>: Default {
|
impl<T: GCMethods + Copy> OptionalHeapSetter for Option<Heap<T>>
|
||||||
|
where
|
||||||
|
Heap<T>: Default,
|
||||||
|
{
|
||||||
type Value = T;
|
type Value = T;
|
||||||
fn set(&mut self, v: Option<T>) {
|
fn set(&mut self, v: Option<T>) {
|
||||||
let v = match v {
|
let v = match v {
|
||||||
None => {
|
None => {
|
||||||
*self = None;
|
*self = None;
|
||||||
return;
|
return;
|
||||||
}
|
},
|
||||||
Some(v) => v,
|
Some(v) => v,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -36,9 +36,7 @@ pub unsafe fn trace(tracer: *mut JSTracer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_execution_stack_empty() -> bool {
|
pub fn is_execution_stack_empty() -> bool {
|
||||||
STACK.with(|stack| {
|
STACK.with(|stack| stack.borrow().is_empty())
|
||||||
stack.borrow().is_empty()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// RAII struct that pushes and pops entries from the script settings stack.
|
/// RAII struct that pushes and pops entries from the script settings stack.
|
||||||
|
@ -69,9 +67,10 @@ impl Drop for AutoEntryScript {
|
||||||
STACK.with(|stack| {
|
STACK.with(|stack| {
|
||||||
let mut stack = stack.borrow_mut();
|
let mut stack = stack.borrow_mut();
|
||||||
let entry = stack.pop().unwrap();
|
let entry = stack.pop().unwrap();
|
||||||
assert_eq!(&*entry.global as *const GlobalScope,
|
assert_eq!(
|
||||||
&*self.global as *const GlobalScope,
|
&*entry.global as *const GlobalScope, &*self.global as *const GlobalScope,
|
||||||
"Dropped AutoEntryScript out of order.");
|
"Dropped AutoEntryScript out of order."
|
||||||
|
);
|
||||||
assert_eq!(entry.kind, StackEntryKind::Entry);
|
assert_eq!(entry.kind, StackEntryKind::Entry);
|
||||||
trace!("Clean up after running script with {:p}", &*entry.global);
|
trace!("Clean up after running script with {:p}", &*entry.global);
|
||||||
});
|
});
|
||||||
|
@ -87,8 +86,10 @@ impl Drop for AutoEntryScript {
|
||||||
///
|
///
|
||||||
/// ["entry"]: https://html.spec.whatwg.org/multipage/#entry
|
/// ["entry"]: https://html.spec.whatwg.org/multipage/#entry
|
||||||
pub fn entry_global() -> DomRoot<GlobalScope> {
|
pub fn entry_global() -> DomRoot<GlobalScope> {
|
||||||
STACK.with(|stack| {
|
STACK
|
||||||
stack.borrow()
|
.with(|stack| {
|
||||||
|
stack
|
||||||
|
.borrow()
|
||||||
.iter()
|
.iter()
|
||||||
.rev()
|
.rev()
|
||||||
.find(|entry| entry.kind == StackEntryKind::Entry)
|
.find(|entry| entry.kind == StackEntryKind::Entry)
|
||||||
|
@ -133,11 +134,15 @@ impl Drop for AutoIncumbentScript {
|
||||||
let mut stack = stack.borrow_mut();
|
let mut stack = stack.borrow_mut();
|
||||||
let entry = stack.pop().unwrap();
|
let entry = stack.pop().unwrap();
|
||||||
// Step 3.
|
// Step 3.
|
||||||
assert_eq!(&*entry.global as *const GlobalScope as usize,
|
assert_eq!(
|
||||||
self.global,
|
&*entry.global as *const GlobalScope as usize, self.global,
|
||||||
"Dropped AutoIncumbentScript out of order.");
|
"Dropped AutoIncumbentScript out of order."
|
||||||
|
);
|
||||||
assert_eq!(entry.kind, StackEntryKind::Incumbent);
|
assert_eq!(entry.kind, StackEntryKind::Incumbent);
|
||||||
trace!("Clean up after running a callback with {:p}", &*entry.global);
|
trace!(
|
||||||
|
"Clean up after running a callback with {:p}",
|
||||||
|
&*entry.global
|
||||||
|
);
|
||||||
});
|
});
|
||||||
unsafe {
|
unsafe {
|
||||||
// Step 1-2.
|
// Step 1-2.
|
||||||
|
@ -169,7 +174,8 @@ pub fn incumbent_global() -> Option<DomRoot<GlobalScope>> {
|
||||||
|
|
||||||
// Step 2: nothing from the JS engine. Let's use whatever's on the explicit stack.
|
// Step 2: nothing from the JS engine. Let's use whatever's on the explicit stack.
|
||||||
STACK.with(|stack| {
|
STACK.with(|stack| {
|
||||||
stack.borrow()
|
stack
|
||||||
|
.borrow()
|
||||||
.last()
|
.last()
|
||||||
.map(|entry| DomRoot::from_ref(&*entry.global))
|
.map(|entry| DomRoot::from_ref(&*entry.global))
|
||||||
})
|
})
|
||||||
|
|
|
@ -82,7 +82,6 @@ impl ops::Deref for ByteString {
|
||||||
#[derive(Clone, Default, MallocSizeOf)]
|
#[derive(Clone, Default, MallocSizeOf)]
|
||||||
pub struct USVString(pub String);
|
pub struct USVString(pub String);
|
||||||
|
|
||||||
|
|
||||||
/// Returns whether `s` is a `token`, as defined by
|
/// Returns whether `s` is a `token`, as defined by
|
||||||
/// [RFC 2616](http://tools.ietf.org/html/rfc2616#page-17).
|
/// [RFC 2616](http://tools.ietf.org/html/rfc2616#page-17).
|
||||||
pub fn is_token(s: &[u8]) -> bool {
|
pub fn is_token(s: &[u8]) -> bool {
|
||||||
|
@ -93,31 +92,14 @@ pub fn is_token(s: &[u8]) -> bool {
|
||||||
// http://tools.ietf.org/html/rfc2616#section-2.2
|
// http://tools.ietf.org/html/rfc2616#section-2.2
|
||||||
match x {
|
match x {
|
||||||
0...31 | 127 => false, // CTLs
|
0...31 | 127 => false, // CTLs
|
||||||
40 |
|
40 | 41 | 60 | 62 | 64 | 44 | 59 | 58 | 92 | 34 | 47 | 91 | 93 | 63 | 61 | 123 |
|
||||||
41 |
|
125 | 32 => false, // separators
|
||||||
60 |
|
|
||||||
62 |
|
|
||||||
64 |
|
|
||||||
44 |
|
|
||||||
59 |
|
|
||||||
58 |
|
|
||||||
92 |
|
|
||||||
34 |
|
|
||||||
47 |
|
|
||||||
91 |
|
|
||||||
93 |
|
|
||||||
63 |
|
|
||||||
61 |
|
|
||||||
123 |
|
|
||||||
125 |
|
|
||||||
32 => false, // separators
|
|
||||||
x if x > 127 => false, // non-CHARs
|
x if x > 127 => false, // non-CHARs
|
||||||
_ => true,
|
_ => true,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// A DOMString.
|
/// A DOMString.
|
||||||
///
|
///
|
||||||
/// This type corresponds to the [`DOMString`](idl) type in WebIDL.
|
/// This type corresponds to the [`DOMString`](idl) type in WebIDL.
|
||||||
|
@ -196,14 +178,16 @@ impl DOMString {
|
||||||
/// Removes leading and trailing ASCII whitespaces according to
|
/// Removes leading and trailing ASCII whitespaces according to
|
||||||
/// <https://infra.spec.whatwg.org/#strip-leading-and-trailing-ascii-whitespace>.
|
/// <https://infra.spec.whatwg.org/#strip-leading-and-trailing-ascii-whitespace>.
|
||||||
pub fn strip_leading_and_trailing_ascii_whitespace(&mut self) {
|
pub fn strip_leading_and_trailing_ascii_whitespace(&mut self) {
|
||||||
if self.0.len() == 0 { return; }
|
if self.0.len() == 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let last_non_whitespace = match self.0.rfind(|ref c| !char::is_ascii_whitespace(c)) {
|
let last_non_whitespace = match self.0.rfind(|ref c| !char::is_ascii_whitespace(c)) {
|
||||||
Some(idx) => idx + 1,
|
Some(idx) => idx + 1,
|
||||||
None => {
|
None => {
|
||||||
self.0.clear();
|
self.0.clear();
|
||||||
return;
|
return;
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
let first_non_whitespace = self.0.find(|ref c| !char::is_ascii_whitespace(c)).unwrap();
|
let first_non_whitespace = self.0.find(|ref c| !char::is_ascii_whitespace(c)).unwrap();
|
||||||
|
|
||||||
|
@ -231,17 +215,21 @@ impl DOMString {
|
||||||
Done,
|
Done,
|
||||||
Error,
|
Error,
|
||||||
}
|
}
|
||||||
let next_state = |valid: bool, next: State| -> State { if valid { next } else { State::Error } };
|
let next_state = |valid: bool, next: State| -> State {
|
||||||
|
if valid {
|
||||||
|
next
|
||||||
|
} else {
|
||||||
|
State::Error
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let state = self.chars().fold(State::HourHigh, |state, c| {
|
let state = self.chars().fold(State::HourHigh, |state, c| {
|
||||||
match state {
|
match state {
|
||||||
// Step 1 "HH"
|
// Step 1 "HH"
|
||||||
State::HourHigh => {
|
State::HourHigh => match c {
|
||||||
match c {
|
|
||||||
'0' | '1' => State::HourLow09,
|
'0' | '1' => State::HourLow09,
|
||||||
'2' => State::HourLow03,
|
'2' => State::HourLow03,
|
||||||
_ => State::Error,
|
_ => State::Error,
|
||||||
}
|
|
||||||
},
|
},
|
||||||
State::HourLow09 => next_state(c.is_digit(10), State::MinuteColon),
|
State::HourLow09 => next_state(c.is_digit(10), State::MinuteColon),
|
||||||
State::HourLow03 => next_state(c.is_digit(4), State::MinuteColon),
|
State::HourLow03 => next_state(c.is_digit(4), State::MinuteColon),
|
||||||
|
@ -323,15 +311,21 @@ impl DOMString {
|
||||||
/// where date and time are both valid, and the time string must be as short as possible
|
/// where date and time are both valid, and the time string must be as short as possible
|
||||||
/// https://html.spec.whatwg.org/multipage/#valid-normalised-local-date-and-time-string
|
/// https://html.spec.whatwg.org/multipage/#valid-normalised-local-date-and-time-string
|
||||||
pub fn convert_valid_normalized_local_date_and_time_string(&mut self) -> Result<(), ()> {
|
pub fn convert_valid_normalized_local_date_and_time_string(&mut self) -> Result<(), ()> {
|
||||||
let ((year, month, day), (hour, minute, second)) = parse_local_date_and_time_string(&*self.0)?;
|
let ((year, month, day), (hour, minute, second)) =
|
||||||
|
parse_local_date_and_time_string(&*self.0)?;
|
||||||
if second == 0.0 {
|
if second == 0.0 {
|
||||||
self.0 = format!("{:04}-{:02}-{:02}T{:02}:{:02}", year, month, day, hour, minute);
|
self.0 = format!(
|
||||||
|
"{:04}-{:02}-{:02}T{:02}:{:02}",
|
||||||
|
year, month, day, hour, minute
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
self.0 = format!("{:04}-{:02}-{:02}T{:02}:{:02}:{}", year, month, day, hour, minute, second);
|
self.0 = format!(
|
||||||
|
"{:04}-{:02}-{:02}T{:02}:{:02}:{}",
|
||||||
|
year, month, day, hour, minute, second
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Borrow<str> for DOMString {
|
impl Borrow<str> for DOMString {
|
||||||
|
@ -452,7 +446,10 @@ impl<'a> Into<CowRcStr<'a>> for DOMString {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Extend<char> for DOMString {
|
impl Extend<char> for DOMString {
|
||||||
fn extend<I>(&mut self, iterable: I) where I: IntoIterator<Item=char> {
|
fn extend<I>(&mut self, iterable: I)
|
||||||
|
where
|
||||||
|
I: IntoIterator<Item = char>,
|
||||||
|
{
|
||||||
self.0.extend(iterable)
|
self.0.extend(iterable)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -611,12 +608,12 @@ fn parse_time_component(value: &str) -> Result<(u32, u32, f32), ()> {
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
None => {}
|
None => {},
|
||||||
}
|
}
|
||||||
|
|
||||||
second.parse::<f32>().map_err(|_| ())?
|
second.parse::<f32>().map_err(|_| ())?
|
||||||
},
|
},
|
||||||
None => 0.0
|
None => 0.0,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Step 8
|
// Step 8
|
||||||
|
@ -651,8 +648,8 @@ fn parse_local_date_and_time_string(value: &str) -> Result<((u32, u32, u32), (u
|
||||||
|
|
||||||
fn max_day_in_month(year_num: u32, month_num: u32) -> Result<u32, ()> {
|
fn max_day_in_month(year_num: u32, month_num: u32) -> Result<u32, ()> {
|
||||||
match month_num {
|
match month_num {
|
||||||
1|3|5|7|8|10|12 => Ok(31),
|
1 | 3 | 5 | 7 | 8 | 10 | 12 => Ok(31),
|
||||||
4|6|9|11 => Ok(30),
|
4 | 6 | 9 | 11 => Ok(30),
|
||||||
2 => {
|
2 => {
|
||||||
if is_leap_year(year_num) {
|
if is_leap_year(year_num) {
|
||||||
Ok(29)
|
Ok(29)
|
||||||
|
@ -660,7 +657,7 @@ fn max_day_in_month(year_num: u32, month_num: u32) -> Result<u32, ()> {
|
||||||
Ok(28)
|
Ok(28)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => Err(())
|
_ => Err(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -669,7 +666,7 @@ fn max_week_in_year(year: u32) -> u32 {
|
||||||
match Utc.ymd(year as i32, 1, 1).weekday() {
|
match Utc.ymd(year as i32, 1, 1).weekday() {
|
||||||
Weekday::Thu => 53,
|
Weekday::Thu => 53,
|
||||||
Weekday::Wed if is_leap_year(year) => 53,
|
Weekday::Wed if is_leap_year(year) => 53,
|
||||||
_ => 52
|
_ => 52,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -681,14 +678,16 @@ fn is_leap_year(year: u32) -> bool {
|
||||||
/// https://html.spec.whatwg.org/multipage/#rules-for-parsing-floating-point-number-values
|
/// https://html.spec.whatwg.org/multipage/#rules-for-parsing-floating-point-number-values
|
||||||
fn parse_floating_point_number(input: &str) -> Result<f64, ()> {
|
fn parse_floating_point_number(input: &str) -> Result<f64, ()> {
|
||||||
match input.trim().parse::<f64>() {
|
match input.trim().parse::<f64>() {
|
||||||
Ok(val) if !(
|
Ok(val)
|
||||||
|
if !(
|
||||||
// A valid number is the same as what rust considers to be valid,
|
// A valid number is the same as what rust considers to be valid,
|
||||||
// except for +1., NaN, and Infinity.
|
// except for +1., NaN, and Infinity.
|
||||||
val.is_infinite() || val.is_nan() || input.ends_with(".") || input.starts_with("+")
|
val.is_infinite() || val.is_nan() || input.ends_with(".") || input.starts_with("+")
|
||||||
) => {
|
) =>
|
||||||
|
{
|
||||||
// TODO(#19773): need consider `min`, `max`, `step`, when they are implemented
|
// TODO(#19773): need consider `min`, `max`, `step`, when they are implemented
|
||||||
Ok(val.round())
|
Ok(val.round())
|
||||||
},
|
}
|
||||||
_ => Err(())
|
_ => Err(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,34 +47,38 @@ enum StructuredCloneTags {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_pointer_width = "64")]
|
#[cfg(target_pointer_width = "64")]
|
||||||
unsafe fn write_length(w: *mut JSStructuredCloneWriter,
|
unsafe fn write_length(w: *mut JSStructuredCloneWriter, length: usize) {
|
||||||
length: usize) {
|
|
||||||
let high: u32 = (length >> 32) as u32;
|
let high: u32 = (length >> 32) as u32;
|
||||||
let low: u32 = length as u32;
|
let low: u32 = length as u32;
|
||||||
assert!(JS_WriteUint32Pair(w, high, low));
|
assert!(JS_WriteUint32Pair(w, high, low));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_pointer_width = "32")]
|
#[cfg(target_pointer_width = "32")]
|
||||||
unsafe fn write_length(w: *mut JSStructuredCloneWriter,
|
unsafe fn write_length(w: *mut JSStructuredCloneWriter, length: usize) {
|
||||||
length: usize) {
|
|
||||||
assert!(JS_WriteUint32Pair(w, length as u32, 0));
|
assert!(JS_WriteUint32Pair(w, length as u32, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_pointer_width = "64")]
|
#[cfg(target_pointer_width = "64")]
|
||||||
unsafe fn read_length(r: *mut JSStructuredCloneReader)
|
unsafe fn read_length(r: *mut JSStructuredCloneReader) -> usize {
|
||||||
-> usize {
|
|
||||||
let mut high: u32 = 0;
|
let mut high: u32 = 0;
|
||||||
let mut low: u32 = 0;
|
let mut low: u32 = 0;
|
||||||
assert!(JS_ReadUint32Pair(r, &mut high as *mut u32, &mut low as *mut u32));
|
assert!(JS_ReadUint32Pair(
|
||||||
|
r,
|
||||||
|
&mut high as *mut u32,
|
||||||
|
&mut low as *mut u32
|
||||||
|
));
|
||||||
return (low << high) as usize;
|
return (low << high) as usize;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_pointer_width = "32")]
|
#[cfg(target_pointer_width = "32")]
|
||||||
unsafe fn read_length(r: *mut JSStructuredCloneReader)
|
unsafe fn read_length(r: *mut JSStructuredCloneReader) -> usize {
|
||||||
-> usize {
|
|
||||||
let mut length: u32 = 0;
|
let mut length: u32 = 0;
|
||||||
let mut zero: u32 = 0;
|
let mut zero: u32 = 0;
|
||||||
assert!(JS_ReadUint32Pair(r, &mut length as *mut u32, &mut zero as *mut u32));
|
assert!(JS_ReadUint32Pair(
|
||||||
|
r,
|
||||||
|
&mut length as *mut u32,
|
||||||
|
&mut zero as *mut u32
|
||||||
|
));
|
||||||
return length as usize;
|
return length as usize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,7 +90,11 @@ impl StructuredCloneWriter {
|
||||||
unsafe fn write_slice(&self, v: &[u8]) {
|
unsafe fn write_slice(&self, v: &[u8]) {
|
||||||
let type_length = v.len();
|
let type_length = v.len();
|
||||||
write_length(self.w, type_length);
|
write_length(self.w, type_length);
|
||||||
assert!(JS_WriteBytes(self.w, v.as_ptr() as *const raw::c_void, type_length));
|
assert!(JS_WriteBytes(
|
||||||
|
self.w,
|
||||||
|
v.as_ptr() as *const raw::c_void,
|
||||||
|
type_length
|
||||||
|
));
|
||||||
}
|
}
|
||||||
unsafe fn write_str(&self, s: &str) {
|
unsafe fn write_str(&self, s: &str) {
|
||||||
self.write_slice(s.as_bytes());
|
self.write_slice(s.as_bytes());
|
||||||
|
@ -101,7 +109,11 @@ impl StructuredCloneReader {
|
||||||
unsafe fn read_bytes(&self) -> Vec<u8> {
|
unsafe fn read_bytes(&self) -> Vec<u8> {
|
||||||
let mut bytes = vec![0u8; read_length(self.r)];
|
let mut bytes = vec![0u8; read_length(self.r)];
|
||||||
let blob_length = bytes.len();
|
let blob_length = bytes.len();
|
||||||
assert!(JS_ReadBytes(self.r, bytes.as_mut_ptr() as *mut raw::c_void, blob_length));
|
assert!(JS_ReadBytes(
|
||||||
|
self.r,
|
||||||
|
bytes.as_mut_ptr() as *mut raw::c_void,
|
||||||
|
blob_length
|
||||||
|
));
|
||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
unsafe fn read_str(&self) -> String {
|
unsafe fn read_str(&self) -> String {
|
||||||
|
@ -110,87 +122,105 @@ impl StructuredCloneReader {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn read_blob(cx: *mut JSContext,
|
unsafe fn read_blob(
|
||||||
|
cx: *mut JSContext,
|
||||||
r: *mut JSStructuredCloneReader,
|
r: *mut JSStructuredCloneReader,
|
||||||
sc_holder: &mut StructuredCloneHolder)
|
sc_holder: &mut StructuredCloneHolder,
|
||||||
-> *mut JSObject {
|
) -> *mut JSObject {
|
||||||
let structured_reader = StructuredCloneReader { r: r };
|
let structured_reader = StructuredCloneReader { r: r };
|
||||||
let blob_buffer = structured_reader.read_bytes();
|
let blob_buffer = structured_reader.read_bytes();
|
||||||
let type_str = structured_reader.read_str();
|
let type_str = structured_reader.read_str();
|
||||||
let target_global = GlobalScope::from_context(cx);
|
let target_global = GlobalScope::from_context(cx);
|
||||||
let blob = Blob::new(&target_global, BlobImpl::new_from_bytes(blob_buffer), type_str);
|
let blob = Blob::new(
|
||||||
|
&target_global,
|
||||||
|
BlobImpl::new_from_bytes(blob_buffer),
|
||||||
|
type_str,
|
||||||
|
);
|
||||||
let js_object = blob.reflector().get_jsobject().get();
|
let js_object = blob.reflector().get_jsobject().get();
|
||||||
sc_holder.blob = Some(blob);
|
sc_holder.blob = Some(blob);
|
||||||
js_object
|
js_object
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn write_blob(blob: DomRoot<Blob>,
|
unsafe fn write_blob(blob: DomRoot<Blob>, w: *mut JSStructuredCloneWriter) -> Result<(), ()> {
|
||||||
w: *mut JSStructuredCloneWriter)
|
|
||||||
-> Result<(), ()> {
|
|
||||||
let structured_writer = StructuredCloneWriter { w: w };
|
let structured_writer = StructuredCloneWriter { w: w };
|
||||||
let blob_vec = blob.get_bytes()?;
|
let blob_vec = blob.get_bytes()?;
|
||||||
assert!(JS_WriteUint32Pair(w, StructuredCloneTags::DomBlob as u32, 0));
|
assert!(JS_WriteUint32Pair(
|
||||||
|
w,
|
||||||
|
StructuredCloneTags::DomBlob as u32,
|
||||||
|
0
|
||||||
|
));
|
||||||
structured_writer.write_slice(&blob_vec);
|
structured_writer.write_slice(&blob_vec);
|
||||||
structured_writer.write_str(&blob.type_string());
|
structured_writer.write_str(&blob.type_string());
|
||||||
return Ok(())
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe extern "C" fn read_callback(cx: *mut JSContext,
|
unsafe extern "C" fn read_callback(
|
||||||
|
cx: *mut JSContext,
|
||||||
r: *mut JSStructuredCloneReader,
|
r: *mut JSStructuredCloneReader,
|
||||||
tag: u32,
|
tag: u32,
|
||||||
_data: u32,
|
_data: u32,
|
||||||
closure: *mut raw::c_void)
|
closure: *mut raw::c_void,
|
||||||
-> *mut JSObject {
|
) -> *mut JSObject {
|
||||||
assert!(tag < StructuredCloneTags::Max as u32, "tag should be lower than StructuredCloneTags::Max");
|
assert!(
|
||||||
assert!(tag > StructuredCloneTags::Min as u32, "tag should be higher than StructuredCloneTags::Min");
|
tag < StructuredCloneTags::Max as u32,
|
||||||
|
"tag should be lower than StructuredCloneTags::Max"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
tag > StructuredCloneTags::Min as u32,
|
||||||
|
"tag should be higher than StructuredCloneTags::Min"
|
||||||
|
);
|
||||||
if tag == StructuredCloneTags::DomBlob as u32 {
|
if tag == StructuredCloneTags::DomBlob as u32 {
|
||||||
return read_blob(cx, r, &mut *(closure as *mut StructuredCloneHolder))
|
return read_blob(cx, r, &mut *(closure as *mut StructuredCloneHolder));
|
||||||
}
|
}
|
||||||
return ptr::null_mut()
|
return ptr::null_mut();
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe extern "C" fn write_callback(_cx: *mut JSContext,
|
unsafe extern "C" fn write_callback(
|
||||||
|
_cx: *mut JSContext,
|
||||||
w: *mut JSStructuredCloneWriter,
|
w: *mut JSStructuredCloneWriter,
|
||||||
obj: RawHandleObject,
|
obj: RawHandleObject,
|
||||||
_closure: *mut raw::c_void)
|
_closure: *mut raw::c_void,
|
||||||
-> bool {
|
) -> bool {
|
||||||
if let Ok(blob) = root_from_handleobject::<Blob>(Handle::from_raw(obj)) {
|
if let Ok(blob) = root_from_handleobject::<Blob>(Handle::from_raw(obj)) {
|
||||||
return write_blob(blob, w).is_ok()
|
return write_blob(blob, w).is_ok();
|
||||||
}
|
}
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe extern "C" fn read_transfer_callback(_cx: *mut JSContext,
|
unsafe extern "C" fn read_transfer_callback(
|
||||||
|
_cx: *mut JSContext,
|
||||||
_r: *mut JSStructuredCloneReader,
|
_r: *mut JSStructuredCloneReader,
|
||||||
_tag: u32,
|
_tag: u32,
|
||||||
_content: *mut raw::c_void,
|
_content: *mut raw::c_void,
|
||||||
_extra_data: u64,
|
_extra_data: u64,
|
||||||
_closure: *mut raw::c_void,
|
_closure: *mut raw::c_void,
|
||||||
_return_object: RawMutableHandleObject)
|
_return_object: RawMutableHandleObject,
|
||||||
-> bool {
|
) -> bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe extern "C" fn write_transfer_callback(_cx: *mut JSContext,
|
unsafe extern "C" fn write_transfer_callback(
|
||||||
|
_cx: *mut JSContext,
|
||||||
_obj: RawHandleObject,
|
_obj: RawHandleObject,
|
||||||
_closure: *mut raw::c_void,
|
_closure: *mut raw::c_void,
|
||||||
_tag: *mut u32,
|
_tag: *mut u32,
|
||||||
_ownership: *mut TransferableOwnership,
|
_ownership: *mut TransferableOwnership,
|
||||||
_content: *mut *mut raw::c_void,
|
_content: *mut *mut raw::c_void,
|
||||||
_extra_data: *mut u64)
|
_extra_data: *mut u64,
|
||||||
-> bool {
|
) -> bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe extern "C" fn free_transfer_callback(_tag: u32,
|
unsafe extern "C" fn free_transfer_callback(
|
||||||
|
_tag: u32,
|
||||||
_ownership: TransferableOwnership,
|
_ownership: TransferableOwnership,
|
||||||
_content: *mut raw::c_void,
|
_content: *mut raw::c_void,
|
||||||
_extra_data: u64,
|
_extra_data: u64,
|
||||||
_closure: *mut raw::c_void) {
|
_closure: *mut raw::c_void,
|
||||||
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe extern "C" fn report_error_callback(_cx: *mut JSContext, _errorid: u32) {
|
unsafe extern "C" fn report_error_callback(_cx: *mut JSContext, _errorid: u32) {}
|
||||||
}
|
|
||||||
|
|
||||||
static STRUCTURED_CLONE_CALLBACKS: JSStructuredCloneCallbacks = JSStructuredCloneCallbacks {
|
static STRUCTURED_CLONE_CALLBACKS: JSStructuredCloneCallbacks = JSStructuredCloneCallbacks {
|
||||||
read: Some(read_callback),
|
read: Some(read_callback),
|
||||||
|
@ -202,7 +232,7 @@ static STRUCTURED_CLONE_CALLBACKS: JSStructuredCloneCallbacks = JSStructuredClon
|
||||||
};
|
};
|
||||||
|
|
||||||
struct StructuredCloneHolder {
|
struct StructuredCloneHolder {
|
||||||
blob: Option<DomRoot<Blob>>
|
blob: Option<DomRoot<Blob>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A buffer for a structured clone.
|
/// A buffer for a structured clone.
|
||||||
|
@ -210,7 +240,7 @@ pub enum StructuredCloneData {
|
||||||
/// A non-serializable (default) variant
|
/// A non-serializable (default) variant
|
||||||
Struct(*mut u64, size_t),
|
Struct(*mut u64, size_t),
|
||||||
/// A variant that can be serialized
|
/// A variant that can be serialized
|
||||||
Vector(Vec<u8>)
|
Vector(Vec<u8>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StructuredCloneData {
|
impl StructuredCloneData {
|
||||||
|
@ -218,21 +248,25 @@ impl StructuredCloneData {
|
||||||
/// Writes a structured clone. Returns a `DataClone` error if that fails.
|
/// Writes a structured clone. Returns a `DataClone` error if that fails.
|
||||||
pub fn write(cx: *mut JSContext, message: HandleValue) -> Fallible<StructuredCloneData> {
|
pub fn write(cx: *mut JSContext, message: HandleValue) -> Fallible<StructuredCloneData> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let scbuf = NewJSAutoStructuredCloneBuffer(StructuredCloneScope::DifferentProcess,
|
let scbuf = NewJSAutoStructuredCloneBuffer(
|
||||||
&STRUCTURED_CLONE_CALLBACKS);
|
StructuredCloneScope::DifferentProcess,
|
||||||
|
&STRUCTURED_CLONE_CALLBACKS,
|
||||||
|
);
|
||||||
let scdata = &mut ((*scbuf).data_);
|
let scdata = &mut ((*scbuf).data_);
|
||||||
let policy = CloneDataPolicy {
|
let policy = CloneDataPolicy {
|
||||||
// TODO: SAB?
|
// TODO: SAB?
|
||||||
sharedArrayBuffer_: false,
|
sharedArrayBuffer_: false,
|
||||||
};
|
};
|
||||||
let result = JS_WriteStructuredClone(cx,
|
let result = JS_WriteStructuredClone(
|
||||||
|
cx,
|
||||||
message,
|
message,
|
||||||
scdata,
|
scdata,
|
||||||
StructuredCloneScope::DifferentProcess,
|
StructuredCloneScope::DifferentProcess,
|
||||||
policy,
|
policy,
|
||||||
&STRUCTURED_CLONE_CALLBACKS,
|
&STRUCTURED_CLONE_CALLBACKS,
|
||||||
ptr::null_mut(),
|
ptr::null_mut(),
|
||||||
HandleValue::undefined());
|
HandleValue::undefined(),
|
||||||
|
);
|
||||||
if !result {
|
if !result {
|
||||||
JS_ClearPendingException(cx);
|
JS_ClearPendingException(cx);
|
||||||
return Err(Error::DataClone);
|
return Err(Error::DataClone);
|
||||||
|
@ -252,41 +286,40 @@ impl StructuredCloneData {
|
||||||
/// Converts a StructuredCloneData to Vec<u8> for inter-thread sharing
|
/// Converts a StructuredCloneData to Vec<u8> for inter-thread sharing
|
||||||
pub fn move_to_arraybuffer(self) -> Vec<u8> {
|
pub fn move_to_arraybuffer(self) -> Vec<u8> {
|
||||||
match self {
|
match self {
|
||||||
StructuredCloneData::Struct(data, nbytes) => {
|
StructuredCloneData::Struct(data, nbytes) => unsafe {
|
||||||
unsafe {
|
|
||||||
slice::from_raw_parts(data as *mut u8, nbytes).to_vec()
|
slice::from_raw_parts(data as *mut u8, nbytes).to_vec()
|
||||||
}
|
},
|
||||||
}
|
StructuredCloneData::Vector(msg) => msg,
|
||||||
StructuredCloneData::Vector(msg) => msg
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reads a structured clone.
|
/// Reads a structured clone.
|
||||||
///
|
///
|
||||||
/// Panics if `JS_ReadStructuredClone` fails.
|
/// Panics if `JS_ReadStructuredClone` fails.
|
||||||
fn read_clone(global: &GlobalScope,
|
fn read_clone(global: &GlobalScope, data: *mut u64, nbytes: size_t, rval: MutableHandleValue) {
|
||||||
data: *mut u64,
|
|
||||||
nbytes: size_t,
|
|
||||||
rval: MutableHandleValue) {
|
|
||||||
let cx = global.get_cx();
|
let cx = global.get_cx();
|
||||||
let globalhandle = global.reflector().get_jsobject();
|
let globalhandle = global.reflector().get_jsobject();
|
||||||
let _ac = JSAutoCompartment::new(cx, globalhandle.get());
|
let _ac = JSAutoCompartment::new(cx, globalhandle.get());
|
||||||
let mut sc_holder = StructuredCloneHolder { blob: None };
|
let mut sc_holder = StructuredCloneHolder { blob: None };
|
||||||
let sc_holder_ptr = &mut sc_holder as *mut _;
|
let sc_holder_ptr = &mut sc_holder as *mut _;
|
||||||
unsafe {
|
unsafe {
|
||||||
let scbuf = NewJSAutoStructuredCloneBuffer(StructuredCloneScope::DifferentProcess,
|
let scbuf = NewJSAutoStructuredCloneBuffer(
|
||||||
&STRUCTURED_CLONE_CALLBACKS);
|
StructuredCloneScope::DifferentProcess,
|
||||||
|
&STRUCTURED_CLONE_CALLBACKS,
|
||||||
|
);
|
||||||
let scdata = &mut ((*scbuf).data_);
|
let scdata = &mut ((*scbuf).data_);
|
||||||
|
|
||||||
WriteBytesToJSStructuredCloneData(data as *const u8, nbytes, scdata);
|
WriteBytesToJSStructuredCloneData(data as *const u8, nbytes, scdata);
|
||||||
|
|
||||||
assert!(JS_ReadStructuredClone(cx,
|
assert!(JS_ReadStructuredClone(
|
||||||
|
cx,
|
||||||
scdata,
|
scdata,
|
||||||
JS_STRUCTURED_CLONE_VERSION,
|
JS_STRUCTURED_CLONE_VERSION,
|
||||||
StructuredCloneScope::DifferentProcess,
|
StructuredCloneScope::DifferentProcess,
|
||||||
rval,
|
rval,
|
||||||
&STRUCTURED_CLONE_CALLBACKS,
|
&STRUCTURED_CLONE_CALLBACKS,
|
||||||
sc_holder_ptr as *mut raw::c_void));
|
sc_holder_ptr as *mut raw::c_void
|
||||||
|
));
|
||||||
|
|
||||||
DeleteJSAutoStructuredCloneBuffer(scbuf);
|
DeleteJSAutoStructuredCloneBuffer(scbuf);
|
||||||
}
|
}
|
||||||
|
@ -299,8 +332,10 @@ impl StructuredCloneData {
|
||||||
let nbytes = vec_msg.len();
|
let nbytes = vec_msg.len();
|
||||||
let data = vec_msg.as_mut_ptr() as *mut u64;
|
let data = vec_msg.as_mut_ptr() as *mut u64;
|
||||||
StructuredCloneData::read_clone(global, data, nbytes, rval);
|
StructuredCloneData::read_clone(global, data, nbytes, rval);
|
||||||
}
|
},
|
||||||
StructuredCloneData::Struct(data, nbytes) => StructuredCloneData::read_clone(global, data, nbytes, rval)
|
StructuredCloneData::Struct(data, nbytes) => {
|
||||||
|
StructuredCloneData::read_clone(global, data, nbytes, rval)
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -149,9 +149,11 @@ pub fn trace_jsval(tracer: *mut JSTracer, description: &str, val: &Heap<JSVal>)
|
||||||
}
|
}
|
||||||
|
|
||||||
trace!("tracing value {}", description);
|
trace!("tracing value {}", description);
|
||||||
CallValueTracer(tracer,
|
CallValueTracer(
|
||||||
|
tracer,
|
||||||
val.ptr.get() as *mut _,
|
val.ptr.get() as *mut _,
|
||||||
GCTraceKindToAscii(val.get().trace_kind()));
|
GCTraceKindToAscii(val.get().trace_kind()),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,9 +168,11 @@ pub fn trace_reflector(tracer: *mut JSTracer, description: &str, reflector: &Ref
|
||||||
pub fn trace_object(tracer: *mut JSTracer, description: &str, obj: &Heap<*mut JSObject>) {
|
pub fn trace_object(tracer: *mut JSTracer, description: &str, obj: &Heap<*mut JSObject>) {
|
||||||
unsafe {
|
unsafe {
|
||||||
trace!("tracing {}", description);
|
trace!("tracing {}", description);
|
||||||
CallObjectTracer(tracer,
|
CallObjectTracer(
|
||||||
|
tracer,
|
||||||
obj.ptr.get() as *mut _,
|
obj.ptr.get() as *mut _,
|
||||||
GCTraceKindToAscii(TraceKind::Object));
|
GCTraceKindToAscii(TraceKind::Object),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -295,7 +299,8 @@ unsafe impl<T: JSTraceable, U: JSTraceable> JSTraceable for Result<T, U> {
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<K, V, S> JSTraceable for HashMap<K, V, S>
|
unsafe impl<K, V, S> JSTraceable for HashMap<K, V, S>
|
||||||
where K: Hash + Eq + JSTraceable,
|
where
|
||||||
|
K: Hash + Eq + JSTraceable,
|
||||||
V: JSTraceable,
|
V: JSTraceable,
|
||||||
S: BuildHasher,
|
S: BuildHasher,
|
||||||
{
|
{
|
||||||
|
@ -309,7 +314,8 @@ unsafe impl<K, V, S> JSTraceable for HashMap<K, V, S>
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<T, S> JSTraceable for HashSet<T, S>
|
unsafe impl<T, S> JSTraceable for HashSet<T, S>
|
||||||
where T: Hash + Eq + JSTraceable,
|
where
|
||||||
|
T: Hash + Eq + JSTraceable,
|
||||||
S: BuildHasher,
|
S: BuildHasher,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -365,7 +371,12 @@ unsafe_no_jsmanaged_fields!(PropertyDeclarationBlock);
|
||||||
// These three are interdependent, if you plan to put jsmanaged data
|
// These three are interdependent, if you plan to put jsmanaged data
|
||||||
// in one of these make sure it is propagated properly to containing structs
|
// in one of these make sure it is propagated properly to containing structs
|
||||||
unsafe_no_jsmanaged_fields!(DocumentActivity, WindowSizeData, WindowSizeType);
|
unsafe_no_jsmanaged_fields!(DocumentActivity, WindowSizeData, WindowSizeType);
|
||||||
unsafe_no_jsmanaged_fields!(BrowsingContextId, HistoryStateId, PipelineId, TopLevelBrowsingContextId);
|
unsafe_no_jsmanaged_fields!(
|
||||||
|
BrowsingContextId,
|
||||||
|
HistoryStateId,
|
||||||
|
PipelineId,
|
||||||
|
TopLevelBrowsingContextId
|
||||||
|
);
|
||||||
unsafe_no_jsmanaged_fields!(TimerEventId, TimerSource);
|
unsafe_no_jsmanaged_fields!(TimerEventId, TimerSource);
|
||||||
unsafe_no_jsmanaged_fields!(TimelineMarkerType);
|
unsafe_no_jsmanaged_fields!(TimelineMarkerType);
|
||||||
unsafe_no_jsmanaged_fields!(WorkerId);
|
unsafe_no_jsmanaged_fields!(WorkerId);
|
||||||
|
@ -459,7 +470,10 @@ unsafe impl<'a, A, B> JSTraceable for fn(&A) -> B {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<T> JSTraceable for IpcSender<T> where T: for<'de> Deserialize<'de> + Serialize {
|
unsafe impl<T> JSTraceable for IpcSender<T>
|
||||||
|
where
|
||||||
|
T: for<'de> Deserialize<'de> + Serialize,
|
||||||
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn trace(&self, _: *mut JSTracer) {
|
unsafe fn trace(&self, _: *mut JSTracer) {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
|
@ -481,7 +495,10 @@ unsafe impl JSTraceable for () {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<T> JSTraceable for IpcReceiver<T> where T: for<'de> Deserialize<'de> + Serialize {
|
unsafe impl<T> JSTraceable for IpcReceiver<T>
|
||||||
|
where
|
||||||
|
T: for<'de> Deserialize<'de> + Serialize,
|
||||||
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn trace(&self, _: *mut JSTracer) {
|
unsafe fn trace(&self, _: *mut JSTracer) {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
|
@ -509,14 +526,20 @@ unsafe impl<T: Send> JSTraceable for Sender<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<T: Send> JSTraceable for WebGLReceiver<T> where T: for<'de> Deserialize<'de> + Serialize {
|
unsafe impl<T: Send> JSTraceable for WebGLReceiver<T>
|
||||||
|
where
|
||||||
|
T: for<'de> Deserialize<'de> + Serialize,
|
||||||
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn trace(&self, _: *mut JSTracer) {
|
unsafe fn trace(&self, _: *mut JSTracer) {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<T: Send> JSTraceable for WebGLSender<T> where T: for<'de> Deserialize<'de> + Serialize {
|
unsafe impl<T: Send> JSTraceable for WebGLSender<T>
|
||||||
|
where
|
||||||
|
T: for<'de> Deserialize<'de> + Serialize,
|
||||||
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn trace(&self, _: *mut JSTracer) {
|
unsafe fn trace(&self, _: *mut JSTracer) {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
|
@ -665,7 +688,10 @@ unsafe impl JSTraceable for StyleLocked<MediaList> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<T> JSTraceable for TypedArray<T, Box<Heap<*mut JSObject>>> where T: TypedArrayElement {
|
unsafe impl<T> JSTraceable for TypedArray<T, Box<Heap<*mut JSObject>>>
|
||||||
|
where
|
||||||
|
T: TypedArrayElement,
|
||||||
|
{
|
||||||
unsafe fn trace(&self, trc: *mut JSTracer) {
|
unsafe fn trace(&self, trc: *mut JSTracer) {
|
||||||
self.underlying_object().trace(trc);
|
self.underlying_object().trace(trc);
|
||||||
}
|
}
|
||||||
|
@ -682,31 +708,23 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Holds a set of JSTraceables that need to be rooted
|
/// Holds a set of JSTraceables that need to be rooted
|
||||||
struct RootedTraceableSet {
|
struct RootedTraceableSet {
|
||||||
set: Vec<*const JSTraceable>,
|
set: Vec<*const JSTraceable>,
|
||||||
}
|
}
|
||||||
|
|
||||||
thread_local!(
|
thread_local!(/// TLV Holds a set of JSTraceables that need to be rooted
|
||||||
/// TLV Holds a set of JSTraceables that need to be rooted
|
static ROOTED_TRACEABLES: RefCell<RootedTraceableSet> = RefCell::new(RootedTraceableSet::new()););
|
||||||
static ROOTED_TRACEABLES: RefCell<RootedTraceableSet> =
|
|
||||||
RefCell::new(RootedTraceableSet::new());
|
|
||||||
);
|
|
||||||
|
|
||||||
impl RootedTraceableSet {
|
impl RootedTraceableSet {
|
||||||
fn new() -> RootedTraceableSet {
|
fn new() -> RootedTraceableSet {
|
||||||
RootedTraceableSet {
|
RootedTraceableSet { set: vec![] }
|
||||||
set: vec![],
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn remove(traceable: *const JSTraceable) {
|
unsafe fn remove(traceable: *const JSTraceable) {
|
||||||
ROOTED_TRACEABLES.with(|ref traceables| {
|
ROOTED_TRACEABLES.with(|ref traceables| {
|
||||||
let mut traceables = traceables.borrow_mut();
|
let mut traceables = traceables.borrow_mut();
|
||||||
let idx =
|
let idx = match traceables.set.iter().rposition(|x| *x == traceable) {
|
||||||
match traceables.set.iter()
|
|
||||||
.rposition(|x| *x == traceable) {
|
|
||||||
Some(idx) => idx,
|
Some(idx) => idx,
|
||||||
None => unreachable!(),
|
None => unreachable!(),
|
||||||
};
|
};
|
||||||
|
@ -744,9 +762,7 @@ impl<'a, T: JSTraceable + 'static> RootedTraceable<'a, T> {
|
||||||
unsafe {
|
unsafe {
|
||||||
RootedTraceableSet::add(traceable);
|
RootedTraceableSet::add(traceable);
|
||||||
}
|
}
|
||||||
RootedTraceable {
|
RootedTraceable { ptr: traceable }
|
||||||
ptr: traceable,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -787,14 +803,12 @@ impl<T: JSTraceable + 'static> RootedTraceableBox<T> {
|
||||||
unsafe {
|
unsafe {
|
||||||
RootedTraceableSet::add(traceable);
|
RootedTraceableSet::add(traceable);
|
||||||
}
|
}
|
||||||
RootedTraceableBox {
|
RootedTraceableBox { ptr: traceable }
|
||||||
ptr: traceable,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> RootedTraceableBox<Heap<T>>
|
impl<T> RootedTraceableBox<Heap<T>>
|
||||||
where
|
where
|
||||||
Heap<T>: JSTraceable + 'static,
|
Heap<T>: JSTraceable + 'static,
|
||||||
T: GCMethods + Copy,
|
T: GCMethods + Copy,
|
||||||
{
|
{
|
||||||
|
@ -812,17 +826,13 @@ impl<T: JSTraceable + Default> Default for RootedTraceableBox<T> {
|
||||||
impl<T: JSTraceable> Deref for RootedTraceableBox<T> {
|
impl<T: JSTraceable> Deref for RootedTraceableBox<T> {
|
||||||
type Target = T;
|
type Target = T;
|
||||||
fn deref(&self) -> &T {
|
fn deref(&self) -> &T {
|
||||||
unsafe {
|
unsafe { &*self.ptr }
|
||||||
&*self.ptr
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: JSTraceable> DerefMut for RootedTraceableBox<T> {
|
impl<T: JSTraceable> DerefMut for RootedTraceableBox<T> {
|
||||||
fn deref_mut(&mut self) -> &mut T {
|
fn deref_mut(&mut self) -> &mut T {
|
||||||
unsafe {
|
unsafe { &mut *self.ptr }
|
||||||
&mut *self.ptr
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -849,9 +859,7 @@ pub struct RootableVec<T: JSTraceable> {
|
||||||
impl<T: JSTraceable> RootableVec<T> {
|
impl<T: JSTraceable> RootableVec<T> {
|
||||||
/// Create a vector of items of type T that can be rooted later.
|
/// Create a vector of items of type T that can be rooted later.
|
||||||
pub fn new_unrooted() -> RootableVec<T> {
|
pub fn new_unrooted() -> RootableVec<T> {
|
||||||
RootableVec {
|
RootableVec { v: vec![] }
|
||||||
v: vec![],
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -868,9 +876,7 @@ impl<'a, T: 'static + JSTraceable> RootedVec<'a, T> {
|
||||||
unsafe {
|
unsafe {
|
||||||
RootedTraceableSet::add(root);
|
RootedTraceableSet::add(root);
|
||||||
}
|
}
|
||||||
RootedVec {
|
RootedVec { root: root }
|
||||||
root: root,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -878,15 +884,14 @@ impl<'a, T: 'static + JSTraceable + DomObject> RootedVec<'a, Dom<T>> {
|
||||||
/// Create a vector of items of type Dom<T> that is rooted for
|
/// Create a vector of items of type Dom<T> that is rooted for
|
||||||
/// the lifetime of this struct
|
/// the lifetime of this struct
|
||||||
pub fn from_iter<I>(root: &'a mut RootableVec<Dom<T>>, iter: I) -> Self
|
pub fn from_iter<I>(root: &'a mut RootableVec<Dom<T>>, iter: I) -> Self
|
||||||
where I: Iterator<Item = DomRoot<T>>
|
where
|
||||||
|
I: Iterator<Item = DomRoot<T>>,
|
||||||
{
|
{
|
||||||
unsafe {
|
unsafe {
|
||||||
RootedTraceableSet::add(root);
|
RootedTraceableSet::add(root);
|
||||||
}
|
}
|
||||||
root.v.extend(iter.map(|item| Dom::from_ref(&*item)));
|
root.v.extend(iter.map(|item| Dom::from_ref(&*item)));
|
||||||
RootedVec {
|
RootedVec { root: root }
|
||||||
root: root,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -85,7 +85,6 @@ pub const DOM_PROTOTYPE_SLOT: u32 = js::JSCLASS_GLOBAL_SLOT_COUNT;
|
||||||
// changes.
|
// changes.
|
||||||
pub const JSCLASS_DOM_GLOBAL: u32 = js::JSCLASS_USERBIT1;
|
pub const JSCLASS_DOM_GLOBAL: u32 = js::JSCLASS_USERBIT1;
|
||||||
|
|
||||||
|
|
||||||
/// The struct that holds inheritance information for DOM object reflectors.
|
/// The struct that holds inheritance information for DOM object reflectors.
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct DOMClass {
|
pub struct DOMClass {
|
||||||
|
@ -137,13 +136,14 @@ pub type ProtoOrIfaceArray = [*mut JSObject; PROTO_OR_IFACE_LENGTH];
|
||||||
/// set to true and `*vp` to the value, otherwise `*found` is set to false.
|
/// set to true and `*vp` to the value, otherwise `*found` is set to false.
|
||||||
///
|
///
|
||||||
/// Returns false on JSAPI failure.
|
/// Returns false on JSAPI failure.
|
||||||
pub unsafe fn get_property_on_prototype(cx: *mut JSContext,
|
pub unsafe fn get_property_on_prototype(
|
||||||
|
cx: *mut JSContext,
|
||||||
proxy: HandleObject,
|
proxy: HandleObject,
|
||||||
receiver: HandleValue,
|
receiver: HandleValue,
|
||||||
id: HandleId,
|
id: HandleId,
|
||||||
found: *mut bool,
|
found: *mut bool,
|
||||||
vp: MutableHandleValue)
|
vp: MutableHandleValue,
|
||||||
-> bool {
|
) -> bool {
|
||||||
rooted!(in(cx) let mut proto = ptr::null_mut::<JSObject>());
|
rooted!(in(cx) let mut proto = ptr::null_mut::<JSObject>());
|
||||||
if !JS_GetPrototype(cx, proxy, proto.handle_mut()) || proto.is_null() {
|
if !JS_GetPrototype(cx, proxy, proto.handle_mut()) || proto.is_null() {
|
||||||
*found = false;
|
*found = false;
|
||||||
|
@ -184,23 +184,29 @@ pub fn get_array_index_from_id(_cx: *mut JSContext, id: HandleId) -> Option<u32>
|
||||||
return if StringIsArray(str, &mut i) != 0 { i } else { -1 }
|
return if StringIsArray(str, &mut i) != 0 { i } else { -1 }
|
||||||
} else {
|
} else {
|
||||||
IdToInt32(cx, id);
|
IdToInt32(cx, id);
|
||||||
}*/
|
}*/}
|
||||||
}
|
|
||||||
|
|
||||||
/// Find the enum equivelent of a string given by `v` in `pairs`.
|
/// Find the enum equivelent of a string given by `v` in `pairs`.
|
||||||
/// Returns `Err(())` on JSAPI failure (there is a pending exception), and
|
/// Returns `Err(())` on JSAPI failure (there is a pending exception), and
|
||||||
/// `Ok((None, value))` if there was no matching string.
|
/// `Ok((None, value))` if there was no matching string.
|
||||||
pub unsafe fn find_enum_value<'a, T>(cx: *mut JSContext,
|
pub unsafe fn find_enum_value<'a, T>(
|
||||||
|
cx: *mut JSContext,
|
||||||
v: HandleValue,
|
v: HandleValue,
|
||||||
pairs: &'a [(&'static str, T)])
|
pairs: &'a [(&'static str, T)],
|
||||||
-> Result<(Option<&'a T>, DOMString), ()> {
|
) -> Result<(Option<&'a T>, DOMString), ()> {
|
||||||
let jsstr = ToString(cx, v);
|
let jsstr = ToString(cx, v);
|
||||||
if jsstr.is_null() {
|
if jsstr.is_null() {
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let search = jsstring_to_str(cx, jsstr);
|
let search = jsstring_to_str(cx, jsstr);
|
||||||
Ok((pairs.iter().find(|&&(key, _)| search == *key).map(|&(_, ref ev)| ev), search))
|
Ok((
|
||||||
|
pairs
|
||||||
|
.iter()
|
||||||
|
.find(|&&(key, _)| search == *key)
|
||||||
|
.map(|&(_, ref ev)| ev),
|
||||||
|
search,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns wether `obj` is a platform object
|
/// Returns wether `obj` is a platform object
|
||||||
|
@ -228,23 +234,26 @@ pub fn is_platform_object(obj: *mut JSObject) -> bool {
|
||||||
/// Get the property with name `property` from `object`.
|
/// Get the property with name `property` from `object`.
|
||||||
/// Returns `Err(())` on JSAPI failure (there is a pending exception), and
|
/// Returns `Err(())` on JSAPI failure (there is a pending exception), and
|
||||||
/// `Ok(false)` if there was no property with the given name.
|
/// `Ok(false)` if there was no property with the given name.
|
||||||
pub fn get_dictionary_property(cx: *mut JSContext,
|
pub fn get_dictionary_property(
|
||||||
|
cx: *mut JSContext,
|
||||||
object: HandleObject,
|
object: HandleObject,
|
||||||
property: &str,
|
property: &str,
|
||||||
rval: MutableHandleValue)
|
rval: MutableHandleValue,
|
||||||
-> Result<bool, ()> {
|
) -> Result<bool, ()> {
|
||||||
fn has_property(cx: *mut JSContext,
|
fn has_property(
|
||||||
|
cx: *mut JSContext,
|
||||||
object: HandleObject,
|
object: HandleObject,
|
||||||
property: &CString,
|
property: &CString,
|
||||||
found: &mut bool)
|
found: &mut bool,
|
||||||
-> bool {
|
) -> bool {
|
||||||
unsafe { JS_HasProperty(cx, object, property.as_ptr(), found) }
|
unsafe { JS_HasProperty(cx, object, property.as_ptr(), found) }
|
||||||
}
|
}
|
||||||
fn get_property(cx: *mut JSContext,
|
fn get_property(
|
||||||
|
cx: *mut JSContext,
|
||||||
object: HandleObject,
|
object: HandleObject,
|
||||||
property: &CString,
|
property: &CString,
|
||||||
value: MutableHandleValue)
|
value: MutableHandleValue,
|
||||||
-> bool {
|
) -> bool {
|
||||||
unsafe { JS_GetProperty(cx, object, property.as_ptr(), value) }
|
unsafe { JS_GetProperty(cx, object, property.as_ptr(), value) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -272,11 +281,12 @@ pub fn get_dictionary_property(cx: *mut JSContext,
|
||||||
/// Set the property with name `property` from `object`.
|
/// Set the property with name `property` from `object`.
|
||||||
/// Returns `Err(())` on JSAPI failure, or null object,
|
/// Returns `Err(())` on JSAPI failure, or null object,
|
||||||
/// and Ok(()) otherwise
|
/// and Ok(()) otherwise
|
||||||
pub fn set_dictionary_property(cx: *mut JSContext,
|
pub fn set_dictionary_property(
|
||||||
|
cx: *mut JSContext,
|
||||||
object: HandleObject,
|
object: HandleObject,
|
||||||
property: &str,
|
property: &str,
|
||||||
value: HandleValue)
|
value: HandleValue,
|
||||||
-> Result<(), ()> {
|
) -> Result<(), ()> {
|
||||||
if object.get().is_null() {
|
if object.get().is_null() {
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
|
@ -292,11 +302,12 @@ pub fn set_dictionary_property(cx: *mut JSContext,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns whether `proxy` has a property `id` on its prototype.
|
/// Returns whether `proxy` has a property `id` on its prototype.
|
||||||
pub unsafe fn has_property_on_prototype(cx: *mut JSContext,
|
pub unsafe fn has_property_on_prototype(
|
||||||
|
cx: *mut JSContext,
|
||||||
proxy: HandleObject,
|
proxy: HandleObject,
|
||||||
id: HandleId,
|
id: HandleId,
|
||||||
found: &mut bool)
|
found: &mut bool,
|
||||||
-> bool {
|
) -> bool {
|
||||||
rooted!(in(cx) let mut proto = ptr::null_mut::<JSObject>());
|
rooted!(in(cx) let mut proto = ptr::null_mut::<JSObject>());
|
||||||
if !JS_GetPrototype(cx, proxy, proto.handle_mut()) {
|
if !JS_GetPrototype(cx, proxy, proto.handle_mut()) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -322,9 +333,11 @@ pub unsafe fn trace_global(tracer: *mut JSTracer, obj: *mut JSObject) {
|
||||||
let array = get_proto_or_iface_array(obj);
|
let array = get_proto_or_iface_array(obj);
|
||||||
for proto in (*array).iter() {
|
for proto in (*array).iter() {
|
||||||
if !proto.is_null() {
|
if !proto.is_null() {
|
||||||
trace_object(tracer,
|
trace_object(
|
||||||
|
tracer,
|
||||||
"prototype",
|
"prototype",
|
||||||
&*(proto as *const *mut JSObject as *const Heap<*mut JSObject>));
|
&*(proto as *const *mut JSObject as *const Heap<*mut JSObject>),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -346,8 +359,8 @@ pub unsafe extern "C" fn resolve_global(
|
||||||
cx: *mut JSContext,
|
cx: *mut JSContext,
|
||||||
obj: RawHandleObject,
|
obj: RawHandleObject,
|
||||||
id: RawHandleId,
|
id: RawHandleId,
|
||||||
rval: *mut bool)
|
rval: *mut bool,
|
||||||
-> bool {
|
) -> bool {
|
||||||
assert!(JS_IsGlobalObject(obj.get()));
|
assert!(JS_IsGlobalObject(obj.get()));
|
||||||
if !JS_ResolveStandardClass(cx, obj, id, rval) {
|
if !JS_ResolveStandardClass(cx, obj, id, rval) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -379,20 +392,23 @@ pub unsafe extern "C" fn resolve_global(
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe extern "C" fn wrap(cx: *mut JSContext,
|
unsafe extern "C" fn wrap(
|
||||||
|
cx: *mut JSContext,
|
||||||
_existing: RawHandleObject,
|
_existing: RawHandleObject,
|
||||||
obj: RawHandleObject)
|
obj: RawHandleObject,
|
||||||
-> *mut JSObject {
|
) -> *mut JSObject {
|
||||||
// FIXME terrible idea. need security wrappers
|
// FIXME terrible idea. need security wrappers
|
||||||
// https://github.com/servo/servo/issues/2382
|
// https://github.com/servo/servo/issues/2382
|
||||||
WrapperNew(cx, obj, GetCrossCompartmentWrapper(), ptr::null(), false)
|
WrapperNew(cx, obj, GetCrossCompartmentWrapper(), ptr::null(), false)
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe extern "C" fn pre_wrap(cx: *mut JSContext,
|
unsafe extern "C" fn pre_wrap(
|
||||||
|
cx: *mut JSContext,
|
||||||
_scope: RawHandleObject,
|
_scope: RawHandleObject,
|
||||||
obj: RawHandleObject,
|
obj: RawHandleObject,
|
||||||
_object_passed_to_wrap: RawHandleObject,
|
_object_passed_to_wrap: RawHandleObject,
|
||||||
rval: RawMutableHandleObject) {
|
rval: RawMutableHandleObject,
|
||||||
|
) {
|
||||||
let _ac = JSAutoCompartment::new(cx, obj.get());
|
let _ac = JSAutoCompartment::new(cx, obj.get());
|
||||||
let obj = ToWindowProxyIfWindow(obj.get());
|
let obj = ToWindowProxyIfWindow(obj.get());
|
||||||
assert!(!obj.is_null());
|
assert!(!obj.is_null());
|
||||||
|
@ -406,23 +422,29 @@ pub static WRAP_CALLBACKS: JSWrapObjectCallbacks = JSWrapObjectCallbacks {
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Deletes the property `id` from `object`.
|
/// Deletes the property `id` from `object`.
|
||||||
pub unsafe fn delete_property_by_id(cx: *mut JSContext,
|
pub unsafe fn delete_property_by_id(
|
||||||
|
cx: *mut JSContext,
|
||||||
object: HandleObject,
|
object: HandleObject,
|
||||||
id: HandleId,
|
id: HandleId,
|
||||||
bp: *mut ObjectOpResult)
|
bp: *mut ObjectOpResult,
|
||||||
-> bool {
|
) -> bool {
|
||||||
JS_DeletePropertyById(cx, object, id, bp)
|
JS_DeletePropertyById(cx, object, id, bp)
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn generic_call(cx: *mut JSContext,
|
unsafe fn generic_call(
|
||||||
|
cx: *mut JSContext,
|
||||||
argc: libc::c_uint,
|
argc: libc::c_uint,
|
||||||
vp: *mut JSVal,
|
vp: *mut JSVal,
|
||||||
is_lenient: bool,
|
is_lenient: bool,
|
||||||
call: unsafe extern fn(*const JSJitInfo, *mut JSContext,
|
call: unsafe extern "C" fn(
|
||||||
RawHandleObject, *mut libc::c_void, u32,
|
*const JSJitInfo,
|
||||||
*mut JSVal)
|
*mut JSContext,
|
||||||
-> bool)
|
RawHandleObject,
|
||||||
-> bool {
|
*mut libc::c_void,
|
||||||
|
u32,
|
||||||
|
*mut JSVal,
|
||||||
|
) -> bool,
|
||||||
|
) -> bool {
|
||||||
let args = CallArgs::from_vp(vp, argc);
|
let args = CallArgs::from_vp(vp, argc);
|
||||||
|
|
||||||
let info = RUST_FUNCTION_VALUE_TO_JITINFO(JS_CALLEE(cx, vp));
|
let info = RUST_FUNCTION_VALUE_TO_JITINFO(JS_CALLEE(cx, vp));
|
||||||
|
@ -441,9 +463,8 @@ unsafe fn generic_call(cx: *mut JSContext,
|
||||||
};
|
};
|
||||||
rooted!(in(cx) let obj = obj);
|
rooted!(in(cx) let obj = obj);
|
||||||
let depth = (*info).depth;
|
let depth = (*info).depth;
|
||||||
let proto_check = |class: &'static DOMClass| {
|
let proto_check =
|
||||||
class.interface_chain[depth as usize] as u16 == proto_id
|
|class: &'static DOMClass| class.interface_chain[depth as usize] as u16 == proto_id;
|
||||||
};
|
|
||||||
let this = match private_from_proto_check(obj.get(), proto_check) {
|
let this = match private_from_proto_check(obj.get(), proto_check) {
|
||||||
Ok(val) => val,
|
Ok(val) => val,
|
||||||
Err(()) => {
|
Err(()) => {
|
||||||
|
@ -455,42 +476,53 @@ unsafe fn generic_call(cx: *mut JSContext,
|
||||||
throw_invalid_this(cx, proto_id);
|
throw_invalid_this(cx, proto_id);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
call(info, cx, obj.handle().into(), this as *mut libc::c_void, argc, vp)
|
call(
|
||||||
|
info,
|
||||||
|
cx,
|
||||||
|
obj.handle().into(),
|
||||||
|
this as *mut libc::c_void,
|
||||||
|
argc,
|
||||||
|
vp,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generic method of IDL interface.
|
/// Generic method of IDL interface.
|
||||||
pub unsafe extern "C" fn generic_method(cx: *mut JSContext,
|
pub unsafe extern "C" fn generic_method(
|
||||||
|
cx: *mut JSContext,
|
||||||
argc: libc::c_uint,
|
argc: libc::c_uint,
|
||||||
vp: *mut JSVal)
|
vp: *mut JSVal,
|
||||||
-> bool {
|
) -> bool {
|
||||||
generic_call(cx, argc, vp, false, CallJitMethodOp)
|
generic_call(cx, argc, vp, false, CallJitMethodOp)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generic getter of IDL interface.
|
/// Generic getter of IDL interface.
|
||||||
pub unsafe extern "C" fn generic_getter(cx: *mut JSContext,
|
pub unsafe extern "C" fn generic_getter(
|
||||||
|
cx: *mut JSContext,
|
||||||
argc: libc::c_uint,
|
argc: libc::c_uint,
|
||||||
vp: *mut JSVal)
|
vp: *mut JSVal,
|
||||||
-> bool {
|
) -> bool {
|
||||||
generic_call(cx, argc, vp, false, CallJitGetterOp)
|
generic_call(cx, argc, vp, false, CallJitGetterOp)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generic lenient getter of IDL interface.
|
/// Generic lenient getter of IDL interface.
|
||||||
pub unsafe extern "C" fn generic_lenient_getter(cx: *mut JSContext,
|
pub unsafe extern "C" fn generic_lenient_getter(
|
||||||
|
cx: *mut JSContext,
|
||||||
argc: libc::c_uint,
|
argc: libc::c_uint,
|
||||||
vp: *mut JSVal)
|
vp: *mut JSVal,
|
||||||
-> bool {
|
) -> bool {
|
||||||
generic_call(cx, argc, vp, true, CallJitGetterOp)
|
generic_call(cx, argc, vp, true, CallJitGetterOp)
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe extern "C" fn call_setter(info: *const JSJitInfo,
|
unsafe extern "C" fn call_setter(
|
||||||
|
info: *const JSJitInfo,
|
||||||
cx: *mut JSContext,
|
cx: *mut JSContext,
|
||||||
handle: RawHandleObject,
|
handle: RawHandleObject,
|
||||||
this: *mut libc::c_void,
|
this: *mut libc::c_void,
|
||||||
argc: u32,
|
argc: u32,
|
||||||
vp: *mut JSVal)
|
vp: *mut JSVal,
|
||||||
-> bool {
|
) -> bool {
|
||||||
if !CallJitSetterOp(info, cx, handle, this, argc, vp) {
|
if !CallJitSetterOp(info, cx, handle, this, argc, vp) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -499,25 +531,28 @@ unsafe extern "C" fn call_setter(info: *const JSJitInfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generic setter of IDL interface.
|
/// Generic setter of IDL interface.
|
||||||
pub unsafe extern "C" fn generic_setter(cx: *mut JSContext,
|
pub unsafe extern "C" fn generic_setter(
|
||||||
|
cx: *mut JSContext,
|
||||||
argc: libc::c_uint,
|
argc: libc::c_uint,
|
||||||
vp: *mut JSVal)
|
vp: *mut JSVal,
|
||||||
-> bool {
|
) -> bool {
|
||||||
generic_call(cx, argc, vp, false, call_setter)
|
generic_call(cx, argc, vp, false, call_setter)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generic lenient setter of IDL interface.
|
/// Generic lenient setter of IDL interface.
|
||||||
pub unsafe extern "C" fn generic_lenient_setter(cx: *mut JSContext,
|
pub unsafe extern "C" fn generic_lenient_setter(
|
||||||
|
cx: *mut JSContext,
|
||||||
argc: libc::c_uint,
|
argc: libc::c_uint,
|
||||||
vp: *mut JSVal)
|
vp: *mut JSVal,
|
||||||
-> bool {
|
) -> bool {
|
||||||
generic_call(cx, argc, vp, true, call_setter)
|
generic_call(cx, argc, vp, true, call_setter)
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe extern "C" fn instance_class_has_proto_at_depth(clasp: *const js::jsapi::Class,
|
unsafe extern "C" fn instance_class_has_proto_at_depth(
|
||||||
|
clasp: *const js::jsapi::Class,
|
||||||
proto_id: u32,
|
proto_id: u32,
|
||||||
depth: u32)
|
depth: u32,
|
||||||
-> bool {
|
) -> bool {
|
||||||
let domclass: *const DOMJSClass = clasp as *const _;
|
let domclass: *const DOMJSClass = clasp as *const _;
|
||||||
let domclass = &*domclass;
|
let domclass = &*domclass;
|
||||||
domclass.dom_class.interface_chain[depth as usize] as u32 == proto_id
|
domclass.dom_class.interface_chain[depth as usize] as u32 == proto_id
|
||||||
|
|
|
@ -70,9 +70,11 @@ pub trait WeakReferenceable: DomObject + Sized {
|
||||||
let box_ = &*ptr;
|
let box_ = &*ptr;
|
||||||
assert!(box_.value.get().is_some());
|
assert!(box_.value.get().is_some());
|
||||||
let new_count = box_.count.get() + 1;
|
let new_count = box_.count.get() + 1;
|
||||||
trace!("Incrementing WeakBox refcount for {:p} to {}.",
|
trace!(
|
||||||
|
"Incrementing WeakBox refcount for {:p} to {}.",
|
||||||
self,
|
self,
|
||||||
new_count);
|
new_count
|
||||||
|
);
|
||||||
box_.count.set(new_count);
|
box_.count.set(new_count);
|
||||||
WeakRef {
|
WeakRef {
|
||||||
ptr: ptr::NonNull::new_unchecked(ptr),
|
ptr: ptr::NonNull::new_unchecked(ptr),
|
||||||
|
@ -91,9 +93,10 @@ impl<T: WeakReferenceable> WeakRef<T> {
|
||||||
|
|
||||||
/// DomRoot a weak reference. Returns `None` if the object was already collected.
|
/// DomRoot a weak reference. Returns `None` if the object was already collected.
|
||||||
pub fn root(&self) -> Option<DomRoot<T>> {
|
pub fn root(&self) -> Option<DomRoot<T>> {
|
||||||
unsafe { &*self.ptr.as_ptr() }.value.get().map(|ptr| unsafe {
|
unsafe { &*self.ptr.as_ptr() }
|
||||||
DomRoot::from_ref(&*ptr.as_ptr())
|
.value
|
||||||
})
|
.get()
|
||||||
|
.map(|ptr| unsafe { DomRoot::from_ref(&*ptr.as_ptr()) })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return whether the weakly-referenced object is still alive.
|
/// Return whether the weakly-referenced object is still alive.
|
||||||
|
@ -108,9 +111,7 @@ impl<T: WeakReferenceable> Clone for WeakRef<T> {
|
||||||
let box_ = &*self.ptr.as_ptr();
|
let box_ = &*self.ptr.as_ptr();
|
||||||
let new_count = box_.count.get() + 1;
|
let new_count = box_.count.get() + 1;
|
||||||
box_.count.set(new_count);
|
box_.count.set(new_count);
|
||||||
WeakRef {
|
WeakRef { ptr: self.ptr }
|
||||||
ptr: self.ptr,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -190,7 +191,9 @@ impl<T: WeakReferenceable> MutableWeakRef<T> {
|
||||||
/// DomRoot a mutable weak reference. Returns `None` if the object
|
/// DomRoot a mutable weak reference. Returns `None` if the object
|
||||||
/// was already collected.
|
/// was already collected.
|
||||||
pub fn root(&self) -> Option<DomRoot<T>> {
|
pub fn root(&self) -> Option<DomRoot<T>> {
|
||||||
unsafe { &*self.cell.get() }.as_ref().and_then(WeakRef::root)
|
unsafe { &*self.cell.get() }
|
||||||
|
.as_ref()
|
||||||
|
.and_then(WeakRef::root)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -233,7 +236,10 @@ impl<T: WeakReferenceable> WeakRefVec<T> {
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
while i < self.vec.len() {
|
while i < self.vec.len() {
|
||||||
if self.vec[i].is_alive() {
|
if self.vec[i].is_alive() {
|
||||||
f(WeakRefEntry { vec: self, index: &mut i });
|
f(WeakRefEntry {
|
||||||
|
vec: self,
|
||||||
|
index: &mut i,
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
self.vec.swap_remove(i);
|
self.vec.swap_remove(i);
|
||||||
}
|
}
|
||||||
|
@ -293,13 +299,13 @@ impl<'a, T: WeakReferenceable + 'a> Drop for WeakRefEntry<'a, T> {
|
||||||
|
|
||||||
#[derive(MallocSizeOf)]
|
#[derive(MallocSizeOf)]
|
||||||
pub struct DOMTracker<T: WeakReferenceable> {
|
pub struct DOMTracker<T: WeakReferenceable> {
|
||||||
dom_objects: DomRefCell<WeakRefVec<T>>
|
dom_objects: DomRefCell<WeakRefVec<T>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: WeakReferenceable> DOMTracker<T> {
|
impl<T: WeakReferenceable> DOMTracker<T> {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
dom_objects: DomRefCell::new(WeakRefVec::new())
|
dom_objects: DomRefCell::new(WeakRefVec::new()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -30,7 +30,6 @@ pub struct FileBlob {
|
||||||
size: u64,
|
size: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Different backends of Blob
|
/// Different backends of Blob
|
||||||
#[must_root]
|
#[must_root]
|
||||||
#[derive(JSTraceable)]
|
#[derive(JSTraceable)]
|
||||||
|
@ -43,7 +42,7 @@ pub enum BlobImpl {
|
||||||
/// relative positions of current slicing range,
|
/// relative positions of current slicing range,
|
||||||
/// IMPORTANT: The depth of tree is only two, i.e. the parent Blob must be
|
/// IMPORTANT: The depth of tree is only two, i.e. the parent Blob must be
|
||||||
/// either File-based or Memory-based
|
/// either File-based or Memory-based
|
||||||
Sliced(Dom<Blob>, RelativePos)
|
Sliced(Dom<Blob>, RelativePos),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BlobImpl {
|
impl BlobImpl {
|
||||||
|
@ -76,9 +75,7 @@ pub struct Blob {
|
||||||
|
|
||||||
impl Blob {
|
impl Blob {
|
||||||
#[allow(unrooted_must_root)]
|
#[allow(unrooted_must_root)]
|
||||||
pub fn new(
|
pub fn new(global: &GlobalScope, blob_impl: BlobImpl, typeString: String) -> DomRoot<Blob> {
|
||||||
global: &GlobalScope, blob_impl: BlobImpl, typeString: String)
|
|
||||||
-> DomRoot<Blob> {
|
|
||||||
let boxed_blob = Box::new(Blob::new_inherited(blob_impl, typeString));
|
let boxed_blob = Box::new(Blob::new_inherited(blob_impl, typeString));
|
||||||
reflect_dom_object(boxed_blob, global, BlobBinding::Wrap)
|
reflect_dom_object(boxed_blob, global, BlobBinding::Wrap)
|
||||||
}
|
}
|
||||||
|
@ -95,41 +92,49 @@ impl Blob {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unrooted_must_root)]
|
#[allow(unrooted_must_root)]
|
||||||
fn new_sliced(parent: &Blob, rel_pos: RelativePos,
|
fn new_sliced(
|
||||||
relative_content_type: DOMString) -> DomRoot<Blob> {
|
parent: &Blob,
|
||||||
|
rel_pos: RelativePos,
|
||||||
|
relative_content_type: DOMString,
|
||||||
|
) -> DomRoot<Blob> {
|
||||||
let blob_impl = match *parent.blob_impl.borrow() {
|
let blob_impl = match *parent.blob_impl.borrow() {
|
||||||
BlobImpl::File(_) => {
|
BlobImpl::File(_) => {
|
||||||
// Create new parent node
|
// Create new parent node
|
||||||
BlobImpl::Sliced(Dom::from_ref(parent), rel_pos)
|
BlobImpl::Sliced(Dom::from_ref(parent), rel_pos)
|
||||||
}
|
},
|
||||||
BlobImpl::Memory(_) => {
|
BlobImpl::Memory(_) => {
|
||||||
// Create new parent node
|
// Create new parent node
|
||||||
BlobImpl::Sliced(Dom::from_ref(parent), rel_pos)
|
BlobImpl::Sliced(Dom::from_ref(parent), rel_pos)
|
||||||
}
|
},
|
||||||
BlobImpl::Sliced(ref grandparent, ref old_rel_pos) => {
|
BlobImpl::Sliced(ref grandparent, ref old_rel_pos) => {
|
||||||
// Adjust the slicing position, using same parent
|
// Adjust the slicing position, using same parent
|
||||||
BlobImpl::Sliced(grandparent.clone(), old_rel_pos.slice_inner(&rel_pos))
|
BlobImpl::Sliced(grandparent.clone(), old_rel_pos.slice_inner(&rel_pos))
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
Blob::new(&parent.global(), blob_impl, relative_content_type.into())
|
Blob::new(&parent.global(), blob_impl, relative_content_type.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://w3c.github.io/FileAPI/#constructorBlob
|
// https://w3c.github.io/FileAPI/#constructorBlob
|
||||||
pub fn Constructor(global: &GlobalScope,
|
pub fn Constructor(
|
||||||
|
global: &GlobalScope,
|
||||||
blobParts: Option<Vec<ArrayBufferOrArrayBufferViewOrBlobOrString>>,
|
blobParts: Option<Vec<ArrayBufferOrArrayBufferViewOrBlobOrString>>,
|
||||||
blobPropertyBag: &BlobBinding::BlobPropertyBag)
|
blobPropertyBag: &BlobBinding::BlobPropertyBag,
|
||||||
-> Fallible<DomRoot<Blob>> {
|
) -> Fallible<DomRoot<Blob>> {
|
||||||
// TODO: accept other blobParts types - ArrayBuffer or ArrayBufferView
|
// TODO: accept other blobParts types - ArrayBuffer or ArrayBufferView
|
||||||
let bytes: Vec<u8> = match blobParts {
|
let bytes: Vec<u8> = match blobParts {
|
||||||
None => Vec::new(),
|
None => Vec::new(),
|
||||||
Some(blobparts) => match blob_parts_to_bytes(blobparts) {
|
Some(blobparts) => match blob_parts_to_bytes(blobparts) {
|
||||||
Ok(bytes) => bytes,
|
Ok(bytes) => bytes,
|
||||||
Err(_) => return Err(Error::InvalidCharacter),
|
Err(_) => return Err(Error::InvalidCharacter),
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Blob::new(global, BlobImpl::new_from_bytes(bytes), blobPropertyBag.type_.to_string()))
|
Ok(Blob::new(
|
||||||
|
global,
|
||||||
|
BlobImpl::new_from_bytes(bytes),
|
||||||
|
blobPropertyBag.type_.to_string(),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a slice to inner data, this might incur synchronous read and caching
|
/// Get a slice to inner data, this might incur synchronous read and caching
|
||||||
|
@ -141,7 +146,7 @@ impl Blob {
|
||||||
None => {
|
None => {
|
||||||
let bytes = read_file(&self.global(), f.id.clone())?;
|
let bytes = read_file(&self.global(), f.id.clone())?;
|
||||||
(bytes, true)
|
(bytes, true)
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// Cache
|
// Cache
|
||||||
|
@ -150,14 +155,12 @@ impl Blob {
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(buffer)
|
Ok(buffer)
|
||||||
}
|
},
|
||||||
BlobImpl::Memory(ref s) => Ok(s.clone()),
|
BlobImpl::Memory(ref s) => Ok(s.clone()),
|
||||||
BlobImpl::Sliced(ref parent, ref rel_pos) => {
|
BlobImpl::Sliced(ref parent, ref rel_pos) => parent.get_bytes().map(|v| {
|
||||||
parent.get_bytes().map(|v| {
|
|
||||||
let range = rel_pos.to_abs_range(v.len());
|
let range = rel_pos.to_abs_range(v.len());
|
||||||
v.index(range).to_vec()
|
v.index(range).to_vec()
|
||||||
})
|
}),
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,13 +174,19 @@ impl Blob {
|
||||||
pub fn get_blob_url_id(&self) -> Uuid {
|
pub fn get_blob_url_id(&self) -> Uuid {
|
||||||
let opt_sliced_parent = match *self.blob_impl.borrow() {
|
let opt_sliced_parent = match *self.blob_impl.borrow() {
|
||||||
BlobImpl::Sliced(ref parent, ref rel_pos) => {
|
BlobImpl::Sliced(ref parent, ref rel_pos) => {
|
||||||
Some((parent.promote(/* set_valid is */ false), rel_pos.clone(), parent.Size()))
|
Some((
|
||||||
}
|
parent.promote(/* set_valid is */ false),
|
||||||
_ => None
|
rel_pos.clone(),
|
||||||
|
parent.Size(),
|
||||||
|
))
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
match opt_sliced_parent {
|
match opt_sliced_parent {
|
||||||
Some((parent_id, rel_pos, size)) => self.create_sliced_url_id(&parent_id, &rel_pos, size),
|
Some((parent_id, rel_pos, size)) => {
|
||||||
|
self.create_sliced_url_id(&parent_id, &rel_pos, size)
|
||||||
|
},
|
||||||
None => self.promote(/* set_valid is */ true),
|
None => self.promote(/* set_valid is */ true),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -196,13 +205,15 @@ impl Blob {
|
||||||
debug!("Sliced can't have a sliced parent");
|
debug!("Sliced can't have a sliced parent");
|
||||||
// Return dummy id
|
// Return dummy id
|
||||||
return Uuid::new_v4();
|
return Uuid::new_v4();
|
||||||
}
|
},
|
||||||
BlobImpl::File(ref f) => {
|
BlobImpl::File(ref f) => {
|
||||||
if set_valid {
|
if set_valid {
|
||||||
let origin = get_blob_origin(&global_url);
|
let origin = get_blob_origin(&global_url);
|
||||||
let (tx, rx) = ipc::channel(self.global().time_profiler_chan().clone()).unwrap();
|
let (tx, rx) =
|
||||||
|
ipc::channel(self.global().time_profiler_chan().clone()).unwrap();
|
||||||
|
|
||||||
let msg = FileManagerThreadMsg::ActivateBlobURL(f.id.clone(), tx, origin.clone());
|
let msg =
|
||||||
|
FileManagerThreadMsg::ActivateBlobURL(f.id.clone(), tx, origin.clone());
|
||||||
self.send_to_file_manager(msg);
|
self.send_to_file_manager(msg);
|
||||||
|
|
||||||
match rx.recv().unwrap() {
|
match rx.recv().unwrap() {
|
||||||
|
@ -214,7 +225,7 @@ impl Blob {
|
||||||
// no need to activate
|
// no need to activate
|
||||||
return f.id.clone();
|
return f.id.clone();
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
BlobImpl::Memory(ref mut bytes_in) => mem::swap(bytes_in, &mut bytes),
|
BlobImpl::Memory(ref mut bytes_in) => mem::swap(bytes_in, &mut bytes),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -240,21 +251,28 @@ impl Blob {
|
||||||
size: bytes.len() as u64,
|
size: bytes.len() as u64,
|
||||||
});
|
});
|
||||||
id
|
id
|
||||||
}
|
},
|
||||||
// Dummy id
|
// Dummy id
|
||||||
Err(_) => Uuid::new_v4(),
|
Err(_) => Uuid::new_v4(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a FileID representing sliced parent-blob content
|
/// Get a FileID representing sliced parent-blob content
|
||||||
fn create_sliced_url_id(&self, parent_id: &Uuid,
|
fn create_sliced_url_id(
|
||||||
rel_pos: &RelativePos, parent_len: u64) -> Uuid {
|
&self,
|
||||||
|
parent_id: &Uuid,
|
||||||
|
rel_pos: &RelativePos,
|
||||||
|
parent_len: u64,
|
||||||
|
) -> Uuid {
|
||||||
let origin = get_blob_origin(&self.global().get_url());
|
let origin = get_blob_origin(&self.global().get_url());
|
||||||
|
|
||||||
let (tx, rx) = ipc::channel(self.global().time_profiler_chan().clone()).unwrap();
|
let (tx, rx) = ipc::channel(self.global().time_profiler_chan().clone()).unwrap();
|
||||||
let msg = FileManagerThreadMsg::AddSlicedURLEntry(parent_id.clone(),
|
let msg = FileManagerThreadMsg::AddSlicedURLEntry(
|
||||||
|
parent_id.clone(),
|
||||||
rel_pos.clone(),
|
rel_pos.clone(),
|
||||||
tx, origin.clone());
|
tx,
|
||||||
|
origin.clone(),
|
||||||
|
);
|
||||||
self.send_to_file_manager(msg);
|
self.send_to_file_manager(msg);
|
||||||
match rx.recv().expect("File manager thread is down") {
|
match rx.recv().expect("File manager thread is down") {
|
||||||
Ok(new_id) => {
|
Ok(new_id) => {
|
||||||
|
@ -267,11 +285,11 @@ impl Blob {
|
||||||
|
|
||||||
// Return the indirect id reference
|
// Return the indirect id reference
|
||||||
new_id
|
new_id
|
||||||
}
|
},
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
// Return dummy id
|
// Return dummy id
|
||||||
Uuid::new_v4()
|
Uuid::new_v4()
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -303,7 +321,7 @@ impl Drop for Blob {
|
||||||
|
|
||||||
fn read_file(global: &GlobalScope, id: Uuid) -> Result<Vec<u8>, ()> {
|
fn read_file(global: &GlobalScope, id: Uuid) -> Result<Vec<u8>, ()> {
|
||||||
let resource_threads = global.resource_threads();
|
let resource_threads = global.resource_threads();
|
||||||
let (chan, recv) = ipc::channel(global.time_profiler_chan().clone()).map_err(|_|())?;
|
let (chan, recv) = ipc::channel(global.time_profiler_chan().clone()).map_err(|_| ())?;
|
||||||
let origin = get_blob_origin(&global.get_url());
|
let origin = get_blob_origin(&global.get_url());
|
||||||
let check_url_validity = false;
|
let check_url_validity = false;
|
||||||
let msg = FileManagerThreadMsg::ReadFile(chan, id, check_url_validity, origin);
|
let msg = FileManagerThreadMsg::ReadFile(chan, id, check_url_validity, origin);
|
||||||
|
@ -315,13 +333,13 @@ fn read_file(global: &GlobalScope, id: Uuid) -> Result<Vec<u8>, ()> {
|
||||||
match recv.recv().unwrap() {
|
match recv.recv().unwrap() {
|
||||||
Ok(ReadFileProgress::Meta(mut blob_buf)) => {
|
Ok(ReadFileProgress::Meta(mut blob_buf)) => {
|
||||||
bytes.append(&mut blob_buf.bytes);
|
bytes.append(&mut blob_buf.bytes);
|
||||||
}
|
},
|
||||||
Ok(ReadFileProgress::Partial(mut bytes_in)) => {
|
Ok(ReadFileProgress::Partial(mut bytes_in)) => {
|
||||||
bytes.append(&mut bytes_in);
|
bytes.append(&mut bytes_in);
|
||||||
}
|
},
|
||||||
Ok(ReadFileProgress::EOF) => {
|
Ok(ReadFileProgress::EOF) => {
|
||||||
return Ok(bytes);
|
return Ok(bytes);
|
||||||
}
|
},
|
||||||
Err(_) => return Err(()),
|
Err(_) => return Err(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -330,7 +348,9 @@ fn read_file(global: &GlobalScope, id: Uuid) -> Result<Vec<u8>, ()> {
|
||||||
/// Extract bytes from BlobParts, used by Blob and File constructor
|
/// Extract bytes from BlobParts, used by Blob and File constructor
|
||||||
/// <https://w3c.github.io/FileAPI/#constructorBlob>
|
/// <https://w3c.github.io/FileAPI/#constructorBlob>
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
pub fn blob_parts_to_bytes(mut blobparts: Vec<ArrayBufferOrArrayBufferViewOrBlobOrString>) -> Result<Vec<u8>, ()> {
|
pub fn blob_parts_to_bytes(
|
||||||
|
mut blobparts: Vec<ArrayBufferOrArrayBufferViewOrBlobOrString>,
|
||||||
|
) -> Result<Vec<u8>, ()> {
|
||||||
let mut ret = vec![];
|
let mut ret = vec![];
|
||||||
for blobpart in &mut blobparts {
|
for blobpart in &mut blobparts {
|
||||||
match blobpart {
|
match blobpart {
|
||||||
|
@ -348,7 +368,7 @@ pub fn blob_parts_to_bytes(mut blobparts: Vec<ArrayBufferOrArrayBufferViewOrBlob
|
||||||
&mut ArrayBufferOrArrayBufferViewOrBlobOrString::ArrayBufferView(ref mut a) => unsafe {
|
&mut ArrayBufferOrArrayBufferViewOrBlobOrString::ArrayBufferView(ref mut a) => unsafe {
|
||||||
let bytes = a.as_slice();
|
let bytes = a.as_slice();
|
||||||
ret.extend(bytes);
|
ret.extend(bytes);
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -361,8 +381,9 @@ impl BlobMethods for Blob {
|
||||||
match *self.blob_impl.borrow() {
|
match *self.blob_impl.borrow() {
|
||||||
BlobImpl::File(ref f) => f.size,
|
BlobImpl::File(ref f) => f.size,
|
||||||
BlobImpl::Memory(ref v) => v.len() as u64,
|
BlobImpl::Memory(ref v) => v.len() as u64,
|
||||||
BlobImpl::Sliced(ref parent, ref rel_pos) =>
|
BlobImpl::Sliced(ref parent, ref rel_pos) => {
|
||||||
rel_pos.to_abs_range(parent.Size() as usize).len() as u64,
|
rel_pos.to_abs_range(parent.Size() as usize).len() as u64
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -372,11 +393,12 @@ impl BlobMethods for Blob {
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://w3c.github.io/FileAPI/#slice-method-algo
|
// https://w3c.github.io/FileAPI/#slice-method-algo
|
||||||
fn Slice(&self,
|
fn Slice(
|
||||||
|
&self,
|
||||||
start: Option<i64>,
|
start: Option<i64>,
|
||||||
end: Option<i64>,
|
end: Option<i64>,
|
||||||
content_type: Option<DOMString>)
|
content_type: Option<DOMString>,
|
||||||
-> DomRoot<Blob> {
|
) -> DomRoot<Blob> {
|
||||||
let rel_pos = RelativePos::from_opts(start, end);
|
let rel_pos = RelativePos::from_opts(start, end);
|
||||||
Blob::new_sliced(self, rel_pos, content_type.unwrap_or(DOMString::from("")))
|
Blob::new_sliced(self, rel_pos, content_type.unwrap_or(DOMString::from("")))
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ use dom::bindings::codegen::Bindings::BluetoothBinding::{self, BluetoothDataFilt
|
||||||
use dom::bindings::codegen::Bindings::BluetoothBinding::{BluetoothMethods, RequestDeviceOptions};
|
use dom::bindings::codegen::Bindings::BluetoothBinding::{BluetoothMethods, RequestDeviceOptions};
|
||||||
use dom::bindings::codegen::Bindings::BluetoothPermissionResultBinding::BluetoothPermissionDescriptor;
|
use dom::bindings::codegen::Bindings::BluetoothPermissionResultBinding::BluetoothPermissionDescriptor;
|
||||||
use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServerBinding::BluetoothRemoteGATTServerBinding::
|
use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServerBinding::BluetoothRemoteGATTServerBinding::
|
||||||
BluetoothRemoteGATTServerMethods;
|
BluetoothRemoteGATTServerMethods;
|
||||||
use dom::bindings::codegen::Bindings::PermissionStatusBinding::{PermissionName, PermissionState};
|
use dom::bindings::codegen::Bindings::PermissionStatusBinding::{PermissionName, PermissionState};
|
||||||
use dom::bindings::codegen::UnionTypes::{ArrayBufferViewOrArrayBuffer, StringOrUnsignedLong};
|
use dom::bindings::codegen::UnionTypes::{ArrayBufferViewOrArrayBuffer, StringOrUnsignedLong};
|
||||||
use dom::bindings::error::Error::{self, Network, Security, Type};
|
use dom::bindings::error::Error::{self, Network, Security, Type};
|
||||||
|
@ -42,20 +42,26 @@ use std::str::FromStr;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use task::TaskOnce;
|
use task::TaskOnce;
|
||||||
|
|
||||||
const KEY_CONVERSION_ERROR: &'static str = "This `manufacturerData` key can not be parsed as unsigned short:";
|
const KEY_CONVERSION_ERROR: &'static str =
|
||||||
const FILTER_EMPTY_ERROR: &'static str = "'filters' member, if present, must be nonempty to find any devices.";
|
"This `manufacturerData` key can not be parsed as unsigned short:";
|
||||||
|
const FILTER_EMPTY_ERROR: &'static str =
|
||||||
|
"'filters' member, if present, must be nonempty to find any devices.";
|
||||||
const FILTER_ERROR: &'static str = "A filter must restrict the devices in some way.";
|
const FILTER_ERROR: &'static str = "A filter must restrict the devices in some way.";
|
||||||
const MANUFACTURER_DATA_ERROR: &'static str = "'manufacturerData', if present, must be non-empty to filter devices.";
|
const MANUFACTURER_DATA_ERROR: &'static str =
|
||||||
const MASK_LENGTH_ERROR: &'static str = "`mask`, if present, must have the same length as `dataPrefix`.";
|
"'manufacturerData', if present, must be non-empty to filter devices.";
|
||||||
|
const MASK_LENGTH_ERROR: &'static str =
|
||||||
|
"`mask`, if present, must have the same length as `dataPrefix`.";
|
||||||
// 248 is the maximum number of UTF-8 code units in a Bluetooth Device Name.
|
// 248 is the maximum number of UTF-8 code units in a Bluetooth Device Name.
|
||||||
const MAX_DEVICE_NAME_LENGTH: usize = 248;
|
const MAX_DEVICE_NAME_LENGTH: usize = 248;
|
||||||
const NAME_PREFIX_ERROR: &'static str = "'namePrefix', if present, must be nonempty.";
|
const NAME_PREFIX_ERROR: &'static str = "'namePrefix', if present, must be nonempty.";
|
||||||
const NAME_TOO_LONG_ERROR: &'static str = "A device name can't be longer than 248 bytes.";
|
const NAME_TOO_LONG_ERROR: &'static str = "A device name can't be longer than 248 bytes.";
|
||||||
const SERVICE_DATA_ERROR: &'static str = "'serviceData', if present, must be non-empty to filter devices.";
|
const SERVICE_DATA_ERROR: &'static str =
|
||||||
|
"'serviceData', if present, must be non-empty to filter devices.";
|
||||||
const SERVICE_ERROR: &'static str = "'services', if present, must contain at least one service.";
|
const SERVICE_ERROR: &'static str = "'services', if present, must contain at least one service.";
|
||||||
const OPTIONS_ERROR: &'static str = "Fields of 'options' conflict with each other.
|
const OPTIONS_ERROR: &'static str = "Fields of 'options' conflict with each other.
|
||||||
Either 'acceptAllDevices' member must be true, or 'filters' member must be set to a value.";
|
Either 'acceptAllDevices' member must be true, or 'filters' member must be set to a value.";
|
||||||
const BT_DESC_CONVERSION_ERROR: &'static str = "Can't convert to an IDL value of type BluetoothPermissionDescriptor";
|
const BT_DESC_CONVERSION_ERROR: &'static str =
|
||||||
|
"Can't convert to an IDL value of type BluetoothPermissionDescriptor";
|
||||||
|
|
||||||
#[derive(JSTraceable, MallocSizeOf)]
|
#[derive(JSTraceable, MallocSizeOf)]
|
||||||
pub struct AllowedBluetoothDevice {
|
pub struct AllowedBluetoothDevice {
|
||||||
|
@ -84,7 +90,10 @@ impl BluetoothExtraPermissionData {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn allowed_devices_contains_id(&self, id: DOMString) -> bool {
|
pub fn allowed_devices_contains_id(&self, id: DOMString) -> bool {
|
||||||
self.allowed_devices.borrow().iter().any(|d| d.deviceId == id)
|
self.allowed_devices
|
||||||
|
.borrow()
|
||||||
|
.iter()
|
||||||
|
.any(|d| d.deviceId == id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,9 +141,11 @@ impl Bluetooth {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(global: &GlobalScope) -> DomRoot<Bluetooth> {
|
pub fn new(global: &GlobalScope) -> DomRoot<Bluetooth> {
|
||||||
reflect_dom_object(Box::new(Bluetooth::new_inherited()),
|
reflect_dom_object(
|
||||||
|
Box::new(Bluetooth::new_inherited()),
|
||||||
global,
|
global,
|
||||||
BluetoothBinding::Wrap)
|
BluetoothBinding::Wrap,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_bluetooth_thread(&self) -> IpcSender<BluetoothRequest> {
|
fn get_bluetooth_thread(&self) -> IpcSender<BluetoothRequest> {
|
||||||
|
@ -146,15 +157,17 @@ impl Bluetooth {
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#request-bluetooth-devices
|
// https://webbluetoothcg.github.io/web-bluetooth/#request-bluetooth-devices
|
||||||
fn request_bluetooth_devices(&self,
|
fn request_bluetooth_devices(
|
||||||
|
&self,
|
||||||
p: &Rc<Promise>,
|
p: &Rc<Promise>,
|
||||||
filters: &Option<Vec<BluetoothLEScanFilterInit>>,
|
filters: &Option<Vec<BluetoothLEScanFilterInit>>,
|
||||||
optional_services: &Option<Vec<BluetoothServiceUUID>>,
|
optional_services: &Option<Vec<BluetoothServiceUUID>>,
|
||||||
sender: IpcSender<BluetoothResponseResult>) {
|
sender: IpcSender<BluetoothResponseResult>,
|
||||||
|
) {
|
||||||
// TODO: Step 1: Triggered by user activation.
|
// TODO: Step 1: Triggered by user activation.
|
||||||
|
|
||||||
// Step 2.2: There are no requiredServiceUUIDS, we scan for all devices.
|
// Step 2.2: There are no requiredServiceUUIDS, we scan for all devices.
|
||||||
let mut uuid_filters = vec!();
|
let mut uuid_filters = vec![];
|
||||||
|
|
||||||
if let &Some(ref filters) = filters {
|
if let &Some(ref filters) = filters {
|
||||||
// Step 2.1.
|
// Step 2.1.
|
||||||
|
@ -180,7 +193,7 @@ impl Bluetooth {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut optional_services_uuids = vec!();
|
let mut optional_services_uuids = vec![];
|
||||||
if let &Some(ref opt_services) = optional_services {
|
if let &Some(ref opt_services) = optional_services {
|
||||||
for opt_service in opt_services {
|
for opt_service in opt_services {
|
||||||
// Step 2.5 - 2.6.
|
// Step 2.5 - 2.6.
|
||||||
|
@ -201,30 +214,39 @@ impl Bluetooth {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let option = RequestDeviceoptions::new(BluetoothScanfilterSequence::new(uuid_filters),
|
let option = RequestDeviceoptions::new(
|
||||||
ServiceUUIDSequence::new(optional_services_uuids));
|
BluetoothScanfilterSequence::new(uuid_filters),
|
||||||
|
ServiceUUIDSequence::new(optional_services_uuids),
|
||||||
|
);
|
||||||
|
|
||||||
// Step 4 - 5.
|
// Step 4 - 5.
|
||||||
if let PermissionState::Denied = get_descriptor_permission_state(PermissionName::Bluetooth, None) {
|
if let PermissionState::Denied =
|
||||||
|
get_descriptor_permission_state(PermissionName::Bluetooth, None)
|
||||||
|
{
|
||||||
return p.reject_error(Error::NotFound);
|
return p.reject_error(Error::NotFound);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: Step 3, 6 - 8 are implemented in
|
// Note: Step 3, 6 - 8 are implemented in
|
||||||
// components/net/bluetooth_thread.rs in request_device function.
|
// components/net/bluetooth_thread.rs in request_device function.
|
||||||
self.get_bluetooth_thread().send(BluetoothRequest::RequestDevice(option, sender)).unwrap();
|
self.get_bluetooth_thread()
|
||||||
|
.send(BluetoothRequest::RequestDevice(option, sender))
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn response_async<T: AsyncBluetoothListener + DomObject + 'static>(
|
pub fn response_async<T: AsyncBluetoothListener + DomObject + 'static>(
|
||||||
promise: &Rc<Promise>,
|
promise: &Rc<Promise>,
|
||||||
receiver: &T) -> IpcSender<BluetoothResponseResult> {
|
receiver: &T,
|
||||||
|
) -> IpcSender<BluetoothResponseResult> {
|
||||||
let (action_sender, action_receiver) = ipc::channel().unwrap();
|
let (action_sender, action_receiver) = ipc::channel().unwrap();
|
||||||
let task_source = receiver.global().networking_task_source();
|
let task_source = receiver.global().networking_task_source();
|
||||||
let context = Arc::new(Mutex::new(BluetoothContext {
|
let context = Arc::new(Mutex::new(BluetoothContext {
|
||||||
promise: Some(TrustedPromise::new(promise.clone())),
|
promise: Some(TrustedPromise::new(promise.clone())),
|
||||||
receiver: Trusted::new(receiver),
|
receiver: Trusted::new(receiver),
|
||||||
}));
|
}));
|
||||||
ROUTER.add_route(action_receiver.to_opaque(), Box::new(move |message| {
|
ROUTER.add_route(
|
||||||
|
action_receiver.to_opaque(),
|
||||||
|
Box::new(move |message| {
|
||||||
struct ListenerTask<T: AsyncBluetoothListener + DomObject> {
|
struct ListenerTask<T: AsyncBluetoothListener + DomObject> {
|
||||||
context: Arc<Mutex<BluetoothContext<T>>>,
|
context: Arc<Mutex<BluetoothContext<T>>>,
|
||||||
action: BluetoothResponseResult,
|
action: BluetoothResponseResult,
|
||||||
|
@ -249,23 +271,26 @@ pub fn response_async<T: AsyncBluetoothListener + DomObject + 'static>(
|
||||||
if let Err(err) = result {
|
if let Err(err) = result {
|
||||||
warn!("failed to deliver network data: {:?}", err);
|
warn!("failed to deliver network data: {:?}", err);
|
||||||
}
|
}
|
||||||
}));
|
}),
|
||||||
|
);
|
||||||
action_sender
|
action_sender
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unrooted_must_root)]
|
#[allow(unrooted_must_root)]
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#getgattchildren
|
// https://webbluetoothcg.github.io/web-bluetooth/#getgattchildren
|
||||||
pub fn get_gatt_children<T, F> (
|
pub fn get_gatt_children<T, F>(
|
||||||
attribute: &T,
|
attribute: &T,
|
||||||
single: bool,
|
single: bool,
|
||||||
uuid_canonicalizer: F,
|
uuid_canonicalizer: F,
|
||||||
uuid: Option<StringOrUnsignedLong>,
|
uuid: Option<StringOrUnsignedLong>,
|
||||||
instance_id: String,
|
instance_id: String,
|
||||||
connected: bool,
|
connected: bool,
|
||||||
child_type: GATTType)
|
child_type: GATTType,
|
||||||
-> Rc<Promise>
|
) -> Rc<Promise>
|
||||||
where T: AsyncBluetoothListener + DomObject + 'static,
|
where
|
||||||
F: FnOnce(StringOrUnsignedLong) -> Fallible<UUID> {
|
T: AsyncBluetoothListener + DomObject + 'static,
|
||||||
|
F: FnOnce(StringOrUnsignedLong) -> Fallible<UUID>,
|
||||||
|
{
|
||||||
let p = Promise::new(&attribute.global());
|
let p = Promise::new(&attribute.global());
|
||||||
|
|
||||||
let result_uuid = if let Some(u) = uuid {
|
let result_uuid = if let Some(u) = uuid {
|
||||||
|
@ -275,7 +300,7 @@ pub fn get_gatt_children<T, F> (
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
p.reject_error(e);
|
p.reject_error(e);
|
||||||
return p;
|
return p;
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
// Step 2.
|
// Step 2.
|
||||||
if uuid_is_blocklisted(canonicalized.as_ref(), Blocklist::All) {
|
if uuid_is_blocklisted(canonicalized.as_ref(), Blocklist::All) {
|
||||||
|
@ -298,8 +323,17 @@ pub fn get_gatt_children<T, F> (
|
||||||
// Note: Steps 6 - 7 are implemented in components/bluetooth/lib.rs in get_descriptor function
|
// Note: Steps 6 - 7 are implemented in components/bluetooth/lib.rs in get_descriptor function
|
||||||
// and in handle_response function.
|
// and in handle_response function.
|
||||||
let sender = response_async(&p, attribute);
|
let sender = response_async(&p, attribute);
|
||||||
attribute.global().as_window().bluetooth_thread().send(
|
attribute
|
||||||
BluetoothRequest::GetGATTChildren(instance_id, result_uuid, single, child_type, sender)).unwrap();
|
.global()
|
||||||
|
.as_window()
|
||||||
|
.bluetooth_thread()
|
||||||
|
.send(BluetoothRequest::GetGATTChildren(
|
||||||
|
instance_id,
|
||||||
|
result_uuid,
|
||||||
|
single,
|
||||||
|
child_type,
|
||||||
|
sender,
|
||||||
|
)).unwrap();
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -310,7 +344,8 @@ fn canonicalize_filter(filter: &BluetoothLEScanFilterInit) -> Fallible<Bluetooth
|
||||||
filter.name.is_none() &&
|
filter.name.is_none() &&
|
||||||
filter.namePrefix.is_none() &&
|
filter.namePrefix.is_none() &&
|
||||||
filter.manufacturerData.is_none() &&
|
filter.manufacturerData.is_none() &&
|
||||||
filter.serviceData.is_none() {
|
filter.serviceData.is_none()
|
||||||
|
{
|
||||||
return Err(Type(FILTER_ERROR.to_owned()));
|
return Err(Type(FILTER_ERROR.to_owned()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -325,7 +360,7 @@ fn canonicalize_filter(filter: &BluetoothLEScanFilterInit) -> Fallible<Bluetooth
|
||||||
return Err(Type(SERVICE_ERROR.to_owned()));
|
return Err(Type(SERVICE_ERROR.to_owned()));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut services_vec = vec!();
|
let mut services_vec = vec![];
|
||||||
|
|
||||||
for service in services {
|
for service in services {
|
||||||
// Step 3.2 - 3.3.
|
// Step 3.2 - 3.3.
|
||||||
|
@ -333,7 +368,7 @@ fn canonicalize_filter(filter: &BluetoothLEScanFilterInit) -> Fallible<Bluetooth
|
||||||
|
|
||||||
// Step 3.4.
|
// Step 3.4.
|
||||||
if uuid_is_blocklisted(uuid.as_ref(), Blocklist::All) {
|
if uuid_is_blocklisted(uuid.as_ref(), Blocklist::All) {
|
||||||
return Err(Security)
|
return Err(Security);
|
||||||
}
|
}
|
||||||
|
|
||||||
services_vec.push(uuid);
|
services_vec.push(uuid);
|
||||||
|
@ -341,7 +376,7 @@ fn canonicalize_filter(filter: &BluetoothLEScanFilterInit) -> Fallible<Bluetooth
|
||||||
// Step 3.5.
|
// Step 3.5.
|
||||||
services_vec
|
services_vec
|
||||||
},
|
},
|
||||||
None => vec!(),
|
None => vec![],
|
||||||
};
|
};
|
||||||
|
|
||||||
// Step 4.
|
// Step 4.
|
||||||
|
@ -388,13 +423,18 @@ fn canonicalize_filter(filter: &BluetoothLEScanFilterInit) -> Fallible<Bluetooth
|
||||||
// Step 7.1 - 7.2.
|
// Step 7.1 - 7.2.
|
||||||
let manufacturer_id = match u16::from_str(key.as_ref()) {
|
let manufacturer_id = match u16::from_str(key.as_ref()) {
|
||||||
Ok(id) => id,
|
Ok(id) => id,
|
||||||
Err(err) => return Err(Type(format!("{} {} {}", KEY_CONVERSION_ERROR, key, err))),
|
Err(err) => {
|
||||||
|
return Err(Type(format!("{} {} {}", KEY_CONVERSION_ERROR, key, err)))
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// Step 7.3: No need to convert to IDL values since this is only used by native code.
|
// Step 7.3: No need to convert to IDL values since this is only used by native code.
|
||||||
|
|
||||||
// Step 7.4 - 7.5.
|
// Step 7.4 - 7.5.
|
||||||
map.insert(manufacturer_id, canonicalize_bluetooth_data_filter_init(bdfi)?);
|
map.insert(
|
||||||
|
manufacturer_id,
|
||||||
|
canonicalize_bluetooth_data_filter_init(bdfi)?,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Some(map)
|
Some(map)
|
||||||
},
|
},
|
||||||
|
@ -414,7 +454,7 @@ fn canonicalize_filter(filter: &BluetoothLEScanFilterInit) -> Fallible<Bluetooth
|
||||||
// Step 9.1.
|
// Step 9.1.
|
||||||
Ok(number) => StringOrUnsignedLong::UnsignedLong(number),
|
Ok(number) => StringOrUnsignedLong::UnsignedLong(number),
|
||||||
// Step 9.2.
|
// Step 9.2.
|
||||||
_ => StringOrUnsignedLong::String(key.clone())
|
_ => StringOrUnsignedLong::String(key.clone()),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Step 9.3 - 9.4.
|
// Step 9.3 - 9.4.
|
||||||
|
@ -436,16 +476,24 @@ fn canonicalize_filter(filter: &BluetoothLEScanFilterInit) -> Fallible<Bluetooth
|
||||||
};
|
};
|
||||||
|
|
||||||
// Step 10.
|
// Step 10.
|
||||||
Ok(BluetoothScanfilter::new(name, name_prefix, services_vec, manufacturer_data, service_data))
|
Ok(BluetoothScanfilter::new(
|
||||||
|
name,
|
||||||
|
name_prefix,
|
||||||
|
services_vec,
|
||||||
|
manufacturer_data,
|
||||||
|
service_data,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#bluetoothdatafilterinit-canonicalizing
|
// https://webbluetoothcg.github.io/web-bluetooth/#bluetoothdatafilterinit-canonicalizing
|
||||||
fn canonicalize_bluetooth_data_filter_init(bdfi: &BluetoothDataFilterInit) -> Fallible<(Vec<u8>, Vec<u8>)> {
|
fn canonicalize_bluetooth_data_filter_init(
|
||||||
|
bdfi: &BluetoothDataFilterInit,
|
||||||
|
) -> Fallible<(Vec<u8>, Vec<u8>)> {
|
||||||
// Step 1.
|
// Step 1.
|
||||||
let data_prefix = match bdfi.dataPrefix {
|
let data_prefix = match bdfi.dataPrefix {
|
||||||
Some(ArrayBufferViewOrArrayBuffer::ArrayBufferView(ref avb)) => avb.to_vec(),
|
Some(ArrayBufferViewOrArrayBuffer::ArrayBufferView(ref avb)) => avb.to_vec(),
|
||||||
Some(ArrayBufferViewOrArrayBuffer::ArrayBuffer(ref ab)) => ab.to_vec(),
|
Some(ArrayBufferViewOrArrayBuffer::ArrayBuffer(ref ab)) => ab.to_vec(),
|
||||||
None => vec![]
|
None => vec![],
|
||||||
};
|
};
|
||||||
|
|
||||||
// Step 2.
|
// Step 2.
|
||||||
|
@ -454,7 +502,7 @@ fn canonicalize_bluetooth_data_filter_init(bdfi: &BluetoothDataFilterInit) -> Fa
|
||||||
let mask = match bdfi.mask {
|
let mask = match bdfi.mask {
|
||||||
Some(ArrayBufferViewOrArrayBuffer::ArrayBufferView(ref avb)) => avb.to_vec(),
|
Some(ArrayBufferViewOrArrayBuffer::ArrayBufferView(ref avb)) => avb.to_vec(),
|
||||||
Some(ArrayBufferViewOrArrayBuffer::ArrayBuffer(ref ab)) => ab.to_vec(),
|
Some(ArrayBufferViewOrArrayBuffer::ArrayBuffer(ref ab)) => ab.to_vec(),
|
||||||
None => vec![0xFF; data_prefix.len()]
|
None => vec![0xFF; data_prefix.len()],
|
||||||
};
|
};
|
||||||
|
|
||||||
// Step 3.
|
// Step 3.
|
||||||
|
@ -486,7 +534,8 @@ impl BluetoothMethods for Bluetooth {
|
||||||
let p = Promise::new(&self.global());
|
let p = Promise::new(&self.global());
|
||||||
// Step 1.
|
// Step 1.
|
||||||
if (option.filters.is_some() && option.acceptAllDevices) ||
|
if (option.filters.is_some() && option.acceptAllDevices) ||
|
||||||
(option.filters.is_none() && !option.acceptAllDevices) {
|
(option.filters.is_none() && !option.acceptAllDevices)
|
||||||
|
{
|
||||||
p.reject_error(Error::Type(OPTIONS_ERROR.to_owned()));
|
p.reject_error(Error::Type(OPTIONS_ERROR.to_owned()));
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
@ -505,13 +554,18 @@ impl BluetoothMethods for Bluetooth {
|
||||||
// Step 1. We did not override the method
|
// Step 1. We did not override the method
|
||||||
// Step 2 - 3. in handle_response
|
// Step 2 - 3. in handle_response
|
||||||
let sender = response_async(&p, self);
|
let sender = response_async(&p, self);
|
||||||
self.get_bluetooth_thread().send(
|
self.get_bluetooth_thread()
|
||||||
BluetoothRequest::GetAvailability(sender)).unwrap();
|
.send(BluetoothRequest::GetAvailability(sender))
|
||||||
|
.unwrap();
|
||||||
p
|
p
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetooth-onavailabilitychanged
|
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetooth-onavailabilitychanged
|
||||||
event_handler!(availabilitychanged, GetOnavailabilitychanged, SetOnavailabilitychanged);
|
event_handler!(
|
||||||
|
availabilitychanged,
|
||||||
|
GetOnavailabilitychanged,
|
||||||
|
SetOnavailabilitychanged
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsyncBluetoothListener for Bluetooth {
|
impl AsyncBluetoothListener for Bluetooth {
|
||||||
|
@ -524,18 +578,21 @@ impl AsyncBluetoothListener for Bluetooth {
|
||||||
if let Some(existing_device) = device_instance_map.get(&device.id.clone()) {
|
if let Some(existing_device) = device_instance_map.get(&device.id.clone()) {
|
||||||
return promise.resolve_native(&**existing_device);
|
return promise.resolve_native(&**existing_device);
|
||||||
}
|
}
|
||||||
let bt_device = BluetoothDevice::new(&self.global(),
|
let bt_device = BluetoothDevice::new(
|
||||||
|
&self.global(),
|
||||||
DOMString::from(device.id.clone()),
|
DOMString::from(device.id.clone()),
|
||||||
device.name.map(DOMString::from),
|
device.name.map(DOMString::from),
|
||||||
&self);
|
&self,
|
||||||
|
);
|
||||||
device_instance_map.insert(device.id.clone(), Dom::from_ref(&bt_device));
|
device_instance_map.insert(device.id.clone(), Dom::from_ref(&bt_device));
|
||||||
|
|
||||||
self.global().as_window().bluetooth_extra_permission_data().add_new_allowed_device(
|
self.global()
|
||||||
AllowedBluetoothDevice {
|
.as_window()
|
||||||
|
.bluetooth_extra_permission_data()
|
||||||
|
.add_new_allowed_device(AllowedBluetoothDevice {
|
||||||
deviceId: DOMString::from(device.id),
|
deviceId: DOMString::from(device.id),
|
||||||
mayUseGATT: true,
|
mayUseGATT: true,
|
||||||
}
|
});
|
||||||
);
|
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetooth-requestdevice
|
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetooth-requestdevice
|
||||||
// Step 5.
|
// Step 5.
|
||||||
promise.resolve_native(&bt_device);
|
promise.resolve_native(&bt_device);
|
||||||
|
@ -544,7 +601,7 @@ impl AsyncBluetoothListener for Bluetooth {
|
||||||
// Step 2 - 3.
|
// Step 2 - 3.
|
||||||
BluetoothResponse::GetAvailability(is_available) => {
|
BluetoothResponse::GetAvailability(is_available) => {
|
||||||
promise.resolve_native(&is_available);
|
promise.resolve_native(&is_available);
|
||||||
}
|
},
|
||||||
_ => promise.reject_error(Error::Type("Something went wrong...".to_owned())),
|
_ => promise.reject_error(Error::Type("Something went wrong...".to_owned())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -555,11 +612,14 @@ impl PermissionAlgorithm for Bluetooth {
|
||||||
type Status = BluetoothPermissionResult;
|
type Status = BluetoothPermissionResult;
|
||||||
|
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
fn create_descriptor(cx: *mut JSContext,
|
fn create_descriptor(
|
||||||
permission_descriptor_obj: *mut JSObject)
|
cx: *mut JSContext,
|
||||||
-> Result<BluetoothPermissionDescriptor, Error> {
|
permission_descriptor_obj: *mut JSObject,
|
||||||
|
) -> Result<BluetoothPermissionDescriptor, Error> {
|
||||||
rooted!(in(cx) let mut property = UndefinedValue());
|
rooted!(in(cx) let mut property = UndefinedValue());
|
||||||
property.handle_mut().set(ObjectValue(permission_descriptor_obj));
|
property
|
||||||
|
.handle_mut()
|
||||||
|
.set(ObjectValue(permission_descriptor_obj));
|
||||||
unsafe {
|
unsafe {
|
||||||
match BluetoothPermissionDescriptor::new(cx, property.handle()) {
|
match BluetoothPermissionDescriptor::new(cx, property.handle()) {
|
||||||
Ok(ConversionResult::Success(descriptor)) => Ok(descriptor),
|
Ok(ConversionResult::Success(descriptor)) => Ok(descriptor),
|
||||||
|
@ -592,7 +652,10 @@ impl PermissionAlgorithm for Bluetooth {
|
||||||
|
|
||||||
// Step 5.
|
// Step 5.
|
||||||
let global = status.global();
|
let global = status.global();
|
||||||
let allowed_devices = global.as_window().bluetooth_extra_permission_data().get_allowed_devices();
|
let allowed_devices = global
|
||||||
|
.as_window()
|
||||||
|
.bluetooth_extra_permission_data()
|
||||||
|
.get_allowed_devices();
|
||||||
|
|
||||||
let bluetooth = status.get_bluetooth();
|
let bluetooth = status.get_bluetooth();
|
||||||
let device_map = bluetooth.get_device_map().borrow();
|
let device_map = bluetooth.get_device_map().borrow();
|
||||||
|
@ -622,11 +685,15 @@ impl PermissionAlgorithm for Bluetooth {
|
||||||
// Step 6.2.2.
|
// Step 6.2.2.
|
||||||
// Instead of creating an internal slot we send an ipc message to the Bluetooth thread
|
// Instead of creating an internal slot we send an ipc message to the Bluetooth thread
|
||||||
// to check if one of the filters matches.
|
// to check if one of the filters matches.
|
||||||
let (sender, receiver) = ProfiledIpc::channel(global.time_profiler_chan().clone()).unwrap();
|
let (sender, receiver) =
|
||||||
status.get_bluetooth_thread()
|
ProfiledIpc::channel(global.time_profiler_chan().clone()).unwrap();
|
||||||
.send(BluetoothRequest::MatchesFilter(device_id.clone(),
|
status
|
||||||
|
.get_bluetooth_thread()
|
||||||
|
.send(BluetoothRequest::MatchesFilter(
|
||||||
|
device_id.clone(),
|
||||||
BluetoothScanfilterSequence::new(scan_filters),
|
BluetoothScanfilterSequence::new(scan_filters),
|
||||||
sender)).unwrap();
|
sender,
|
||||||
|
)).unwrap();
|
||||||
|
|
||||||
match receiver.recv().unwrap() {
|
match receiver.recv().unwrap() {
|
||||||
Ok(true) => (),
|
Ok(true) => (),
|
||||||
|
@ -666,17 +733,28 @@ impl PermissionAlgorithm for Bluetooth {
|
||||||
// Step 2.
|
// Step 2.
|
||||||
let sender = response_async(promise, status);
|
let sender = response_async(promise, status);
|
||||||
let bluetooth = status.get_bluetooth();
|
let bluetooth = status.get_bluetooth();
|
||||||
bluetooth.request_bluetooth_devices(promise, &descriptor.filters, &descriptor.optionalServices, sender);
|
bluetooth.request_bluetooth_devices(
|
||||||
|
promise,
|
||||||
|
&descriptor.filters,
|
||||||
|
&descriptor.optionalServices,
|
||||||
|
sender,
|
||||||
|
);
|
||||||
|
|
||||||
// NOTE: Step 3. is in BluetoothPermissionResult's `handle_response` function.
|
// NOTE: Step 3. is in BluetoothPermissionResult's `handle_response` function.
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unrooted_must_root)]
|
#[allow(unrooted_must_root)]
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#revoke-bluetooth-access
|
// https://webbluetoothcg.github.io/web-bluetooth/#revoke-bluetooth-access
|
||||||
fn permission_revoke(_descriptor: &BluetoothPermissionDescriptor, status: &BluetoothPermissionResult) {
|
fn permission_revoke(
|
||||||
|
_descriptor: &BluetoothPermissionDescriptor,
|
||||||
|
status: &BluetoothPermissionResult,
|
||||||
|
) {
|
||||||
// Step 1.
|
// Step 1.
|
||||||
let global = status.global();
|
let global = status.global();
|
||||||
let allowed_devices = global.as_window().bluetooth_extra_permission_data().get_allowed_devices();
|
let allowed_devices = global
|
||||||
|
.as_window()
|
||||||
|
.bluetooth_extra_permission_data()
|
||||||
|
.get_allowed_devices();
|
||||||
// Step 2.
|
// Step 2.
|
||||||
let bluetooth = status.get_bluetooth();
|
let bluetooth = status.get_bluetooth();
|
||||||
let device_map = bluetooth.get_device_map().borrow();
|
let device_map = bluetooth.get_device_map().borrow();
|
||||||
|
@ -684,7 +762,8 @@ impl PermissionAlgorithm for Bluetooth {
|
||||||
let id = DOMString::from(id.clone());
|
let id = DOMString::from(id.clone());
|
||||||
// Step 2.1.
|
// Step 2.1.
|
||||||
if allowed_devices.iter().any(|d| d.deviceId == id) &&
|
if allowed_devices.iter().any(|d| d.deviceId == id) &&
|
||||||
!device.is_represented_device_null() {
|
!device.is_represented_device_null()
|
||||||
|
{
|
||||||
// Note: We don't need to update the allowed_services,
|
// Note: We don't need to update the allowed_services,
|
||||||
// because we store it in the lower level
|
// because we store it in the lower level
|
||||||
// where it is already up-to-date
|
// where it is already up-to-date
|
||||||
|
|
|
@ -29,12 +29,13 @@ pub struct BluetoothAdvertisingEvent {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BluetoothAdvertisingEvent {
|
impl BluetoothAdvertisingEvent {
|
||||||
pub fn new_inherited(device: &BluetoothDevice,
|
pub fn new_inherited(
|
||||||
|
device: &BluetoothDevice,
|
||||||
name: Option<DOMString>,
|
name: Option<DOMString>,
|
||||||
appearance: Option<u16>,
|
appearance: Option<u16>,
|
||||||
tx_power: Option<i8>,
|
tx_power: Option<i8>,
|
||||||
rssi: Option<i8>)
|
rssi: Option<i8>,
|
||||||
-> BluetoothAdvertisingEvent {
|
) -> BluetoothAdvertisingEvent {
|
||||||
BluetoothAdvertisingEvent {
|
BluetoothAdvertisingEvent {
|
||||||
event: Event::new_inherited(),
|
event: Event::new_inherited(),
|
||||||
device: Dom::from_ref(device),
|
device: Dom::from_ref(device),
|
||||||
|
@ -45,7 +46,8 @@ impl BluetoothAdvertisingEvent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(global: &GlobalScope,
|
pub fn new(
|
||||||
|
global: &GlobalScope,
|
||||||
type_: Atom,
|
type_: Atom,
|
||||||
bubbles: EventBubbles,
|
bubbles: EventBubbles,
|
||||||
cancelable: EventCancelable,
|
cancelable: EventCancelable,
|
||||||
|
@ -53,18 +55,14 @@ impl BluetoothAdvertisingEvent {
|
||||||
name: Option<DOMString>,
|
name: Option<DOMString>,
|
||||||
appearance: Option<u16>,
|
appearance: Option<u16>,
|
||||||
txPower: Option<i8>,
|
txPower: Option<i8>,
|
||||||
rssi: Option<i8>)
|
rssi: Option<i8>,
|
||||||
-> DomRoot<BluetoothAdvertisingEvent> {
|
) -> DomRoot<BluetoothAdvertisingEvent> {
|
||||||
let ev = reflect_dom_object(
|
let ev = reflect_dom_object(
|
||||||
Box::new(BluetoothAdvertisingEvent::new_inherited(
|
Box::new(BluetoothAdvertisingEvent::new_inherited(
|
||||||
device,
|
device, name, appearance, txPower, rssi,
|
||||||
name,
|
|
||||||
appearance,
|
|
||||||
txPower,
|
|
||||||
rssi
|
|
||||||
)),
|
)),
|
||||||
global,
|
global,
|
||||||
BluetoothAdvertisingEventBinding::Wrap
|
BluetoothAdvertisingEventBinding::Wrap,
|
||||||
);
|
);
|
||||||
{
|
{
|
||||||
let event = ev.upcast::<Event>();
|
let event = ev.upcast::<Event>();
|
||||||
|
@ -74,10 +72,11 @@ impl BluetoothAdvertisingEvent {
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothadvertisingevent-bluetoothadvertisingevent
|
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothadvertisingevent-bluetoothadvertisingevent
|
||||||
pub fn Constructor(window: &Window,
|
pub fn Constructor(
|
||||||
|
window: &Window,
|
||||||
type_: DOMString,
|
type_: DOMString,
|
||||||
init: &BluetoothAdvertisingEventInit)
|
init: &BluetoothAdvertisingEventInit,
|
||||||
-> Fallible<DomRoot<BluetoothAdvertisingEvent>> {
|
) -> Fallible<DomRoot<BluetoothAdvertisingEvent>> {
|
||||||
let global = window.upcast::<GlobalScope>();
|
let global = window.upcast::<GlobalScope>();
|
||||||
let device = init.device.r();
|
let device = init.device.r();
|
||||||
let name = init.name.clone();
|
let name = init.name.clone();
|
||||||
|
@ -86,7 +85,8 @@ impl BluetoothAdvertisingEvent {
|
||||||
let rssi = init.rssi.clone();
|
let rssi = init.rssi.clone();
|
||||||
let bubbles = EventBubbles::from(init.parent.bubbles);
|
let bubbles = EventBubbles::from(init.parent.bubbles);
|
||||||
let cancelable = EventCancelable::from(init.parent.cancelable);
|
let cancelable = EventCancelable::from(init.parent.cancelable);
|
||||||
Ok(BluetoothAdvertisingEvent::new(global,
|
Ok(BluetoothAdvertisingEvent::new(
|
||||||
|
global,
|
||||||
Atom::from(type_),
|
Atom::from(type_),
|
||||||
bubbles,
|
bubbles,
|
||||||
cancelable,
|
cancelable,
|
||||||
|
@ -94,7 +94,8 @@ impl BluetoothAdvertisingEvent {
|
||||||
name,
|
name,
|
||||||
appearance,
|
appearance,
|
||||||
txPower,
|
txPower,
|
||||||
rssi))
|
rssi,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,14 +4,14 @@
|
||||||
|
|
||||||
use dom::bindings::codegen::Bindings::BluetoothCharacteristicPropertiesBinding;
|
use dom::bindings::codegen::Bindings::BluetoothCharacteristicPropertiesBinding;
|
||||||
use dom::bindings::codegen::Bindings::BluetoothCharacteristicPropertiesBinding::
|
use dom::bindings::codegen::Bindings::BluetoothCharacteristicPropertiesBinding::
|
||||||
BluetoothCharacteristicPropertiesMethods;
|
BluetoothCharacteristicPropertiesMethods;
|
||||||
use dom::bindings::reflector::{Reflector, reflect_dom_object};
|
use dom::bindings::reflector::{Reflector, reflect_dom_object};
|
||||||
use dom::bindings::root::DomRoot;
|
use dom::bindings::root::DomRoot;
|
||||||
use dom::globalscope::GlobalScope;
|
use dom::globalscope::GlobalScope;
|
||||||
use dom_struct::dom_struct;
|
use dom_struct::dom_struct;
|
||||||
|
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#characteristicproperties
|
// https://webbluetoothcg.github.io/web-bluetooth/#characteristicproperties
|
||||||
#[dom_struct]
|
#[dom_struct]
|
||||||
pub struct BluetoothCharacteristicProperties {
|
pub struct BluetoothCharacteristicProperties {
|
||||||
reflector_: Reflector,
|
reflector_: Reflector,
|
||||||
broadcast: bool,
|
broadcast: bool,
|
||||||
|
@ -26,7 +26,8 @@ pub struct BluetoothCharacteristicProperties {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BluetoothCharacteristicProperties {
|
impl BluetoothCharacteristicProperties {
|
||||||
pub fn new_inherited(broadcast: bool,
|
pub fn new_inherited(
|
||||||
|
broadcast: bool,
|
||||||
read: bool,
|
read: bool,
|
||||||
write_without_response: bool,
|
write_without_response: bool,
|
||||||
write: bool,
|
write: bool,
|
||||||
|
@ -34,8 +35,8 @@ impl BluetoothCharacteristicProperties {
|
||||||
indicate: bool,
|
indicate: bool,
|
||||||
authenticated_signed_writes: bool,
|
authenticated_signed_writes: bool,
|
||||||
reliable_write: bool,
|
reliable_write: bool,
|
||||||
writable_auxiliaries: bool)
|
writable_auxiliaries: bool,
|
||||||
-> BluetoothCharacteristicProperties {
|
) -> BluetoothCharacteristicProperties {
|
||||||
BluetoothCharacteristicProperties {
|
BluetoothCharacteristicProperties {
|
||||||
reflector_: Reflector::new(),
|
reflector_: Reflector::new(),
|
||||||
broadcast: broadcast,
|
broadcast: broadcast,
|
||||||
|
@ -50,7 +51,8 @@ impl BluetoothCharacteristicProperties {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(global: &GlobalScope,
|
pub fn new(
|
||||||
|
global: &GlobalScope,
|
||||||
broadcast: bool,
|
broadcast: bool,
|
||||||
read: bool,
|
read: bool,
|
||||||
writeWithoutResponse: bool,
|
writeWithoutResponse: bool,
|
||||||
|
@ -59,8 +61,8 @@ impl BluetoothCharacteristicProperties {
|
||||||
indicate: bool,
|
indicate: bool,
|
||||||
authenticatedSignedWrites: bool,
|
authenticatedSignedWrites: bool,
|
||||||
reliableWrite: bool,
|
reliableWrite: bool,
|
||||||
writableAuxiliaries: bool)
|
writableAuxiliaries: bool,
|
||||||
-> DomRoot<BluetoothCharacteristicProperties> {
|
) -> DomRoot<BluetoothCharacteristicProperties> {
|
||||||
reflect_dom_object(
|
reflect_dom_object(
|
||||||
Box::new(BluetoothCharacteristicProperties::new_inherited(
|
Box::new(BluetoothCharacteristicProperties::new_inherited(
|
||||||
broadcast,
|
broadcast,
|
||||||
|
@ -71,10 +73,10 @@ impl BluetoothCharacteristicProperties {
|
||||||
indicate,
|
indicate,
|
||||||
authenticatedSignedWrites,
|
authenticatedSignedWrites,
|
||||||
reliableWrite,
|
reliableWrite,
|
||||||
writableAuxiliaries
|
writableAuxiliaries,
|
||||||
)),
|
)),
|
||||||
global,
|
global,
|
||||||
BluetoothCharacteristicPropertiesBinding::Wrap
|
BluetoothCharacteristicPropertiesBinding::Wrap,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,79 +38,90 @@ pub struct BluetoothDevice {
|
||||||
name: Option<DOMString>,
|
name: Option<DOMString>,
|
||||||
gatt: MutNullableDom<BluetoothRemoteGATTServer>,
|
gatt: MutNullableDom<BluetoothRemoteGATTServer>,
|
||||||
context: Dom<Bluetooth>,
|
context: Dom<Bluetooth>,
|
||||||
attribute_instance_map: (DomRefCell<HashMap<String, Dom<BluetoothRemoteGATTService>>>,
|
attribute_instance_map: (
|
||||||
|
DomRefCell<HashMap<String, Dom<BluetoothRemoteGATTService>>>,
|
||||||
DomRefCell<HashMap<String, Dom<BluetoothRemoteGATTCharacteristic>>>,
|
DomRefCell<HashMap<String, Dom<BluetoothRemoteGATTCharacteristic>>>,
|
||||||
DomRefCell<HashMap<String, Dom<BluetoothRemoteGATTDescriptor>>>),
|
DomRefCell<HashMap<String, Dom<BluetoothRemoteGATTDescriptor>>>,
|
||||||
|
),
|
||||||
watching_advertisements: Cell<bool>,
|
watching_advertisements: Cell<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BluetoothDevice {
|
impl BluetoothDevice {
|
||||||
pub fn new_inherited(id: DOMString,
|
pub fn new_inherited(
|
||||||
|
id: DOMString,
|
||||||
name: Option<DOMString>,
|
name: Option<DOMString>,
|
||||||
context: &Bluetooth)
|
context: &Bluetooth,
|
||||||
-> BluetoothDevice {
|
) -> BluetoothDevice {
|
||||||
BluetoothDevice {
|
BluetoothDevice {
|
||||||
eventtarget: EventTarget::new_inherited(),
|
eventtarget: EventTarget::new_inherited(),
|
||||||
id: id,
|
id: id,
|
||||||
name: name,
|
name: name,
|
||||||
gatt: Default::default(),
|
gatt: Default::default(),
|
||||||
context: Dom::from_ref(context),
|
context: Dom::from_ref(context),
|
||||||
attribute_instance_map: (DomRefCell::new(HashMap::new()),
|
attribute_instance_map: (
|
||||||
DomRefCell::new(HashMap::new()),
|
DomRefCell::new(HashMap::new()),
|
||||||
DomRefCell::new(HashMap::new())),
|
DomRefCell::new(HashMap::new()),
|
||||||
|
DomRefCell::new(HashMap::new()),
|
||||||
|
),
|
||||||
watching_advertisements: Cell::new(false),
|
watching_advertisements: Cell::new(false),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(global: &GlobalScope,
|
pub fn new(
|
||||||
|
global: &GlobalScope,
|
||||||
id: DOMString,
|
id: DOMString,
|
||||||
name: Option<DOMString>,
|
name: Option<DOMString>,
|
||||||
context: &Bluetooth)
|
context: &Bluetooth,
|
||||||
-> DomRoot<BluetoothDevice> {
|
) -> DomRoot<BluetoothDevice> {
|
||||||
reflect_dom_object(Box::new(BluetoothDevice::new_inherited(id, name, context)),
|
reflect_dom_object(
|
||||||
|
Box::new(BluetoothDevice::new_inherited(id, name, context)),
|
||||||
global,
|
global,
|
||||||
BluetoothDeviceBinding::Wrap)
|
BluetoothDeviceBinding::Wrap,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_gatt(&self) -> DomRoot<BluetoothRemoteGATTServer> {
|
pub fn get_gatt(&self) -> DomRoot<BluetoothRemoteGATTServer> {
|
||||||
self.gatt.or_init(|| {
|
self.gatt
|
||||||
BluetoothRemoteGATTServer::new(&self.global(), self)
|
.or_init(|| BluetoothRemoteGATTServer::new(&self.global(), self))
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_context(&self) -> DomRoot<Bluetooth> {
|
fn get_context(&self) -> DomRoot<Bluetooth> {
|
||||||
DomRoot::from_ref(&self.context)
|
DomRoot::from_ref(&self.context)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_or_create_service(&self,
|
pub fn get_or_create_service(
|
||||||
|
&self,
|
||||||
service: &BluetoothServiceMsg,
|
service: &BluetoothServiceMsg,
|
||||||
server: &BluetoothRemoteGATTServer)
|
server: &BluetoothRemoteGATTServer,
|
||||||
-> DomRoot<BluetoothRemoteGATTService> {
|
) -> DomRoot<BluetoothRemoteGATTService> {
|
||||||
let (ref service_map_ref, _, _) = self.attribute_instance_map;
|
let (ref service_map_ref, _, _) = self.attribute_instance_map;
|
||||||
let mut service_map = service_map_ref.borrow_mut();
|
let mut service_map = service_map_ref.borrow_mut();
|
||||||
if let Some(existing_service) = service_map.get(&service.instance_id) {
|
if let Some(existing_service) = service_map.get(&service.instance_id) {
|
||||||
return DomRoot::from_ref(&existing_service);
|
return DomRoot::from_ref(&existing_service);
|
||||||
}
|
}
|
||||||
let bt_service = BluetoothRemoteGATTService::new(&server.global(),
|
let bt_service = BluetoothRemoteGATTService::new(
|
||||||
|
&server.global(),
|
||||||
&server.Device(),
|
&server.Device(),
|
||||||
DOMString::from(service.uuid.clone()),
|
DOMString::from(service.uuid.clone()),
|
||||||
service.is_primary,
|
service.is_primary,
|
||||||
service.instance_id.clone());
|
service.instance_id.clone(),
|
||||||
|
);
|
||||||
service_map.insert(service.instance_id.clone(), Dom::from_ref(&bt_service));
|
service_map.insert(service.instance_id.clone(), Dom::from_ref(&bt_service));
|
||||||
return bt_service;
|
return bt_service;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_or_create_characteristic(&self,
|
pub fn get_or_create_characteristic(
|
||||||
|
&self,
|
||||||
characteristic: &BluetoothCharacteristicMsg,
|
characteristic: &BluetoothCharacteristicMsg,
|
||||||
service: &BluetoothRemoteGATTService)
|
service: &BluetoothRemoteGATTService,
|
||||||
-> DomRoot<BluetoothRemoteGATTCharacteristic> {
|
) -> DomRoot<BluetoothRemoteGATTCharacteristic> {
|
||||||
let (_, ref characteristic_map_ref, _) = self.attribute_instance_map;
|
let (_, ref characteristic_map_ref, _) = self.attribute_instance_map;
|
||||||
let mut characteristic_map = characteristic_map_ref.borrow_mut();
|
let mut characteristic_map = characteristic_map_ref.borrow_mut();
|
||||||
if let Some(existing_characteristic) = characteristic_map.get(&characteristic.instance_id) {
|
if let Some(existing_characteristic) = characteristic_map.get(&characteristic.instance_id) {
|
||||||
return DomRoot::from_ref(&existing_characteristic);
|
return DomRoot::from_ref(&existing_characteristic);
|
||||||
}
|
}
|
||||||
let properties =
|
let properties = BluetoothCharacteristicProperties::new(
|
||||||
BluetoothCharacteristicProperties::new(&service.global(),
|
&service.global(),
|
||||||
characteristic.broadcast,
|
characteristic.broadcast,
|
||||||
characteristic.read,
|
characteristic.read,
|
||||||
characteristic.write_without_response,
|
characteristic.write_without_response,
|
||||||
|
@ -119,37 +130,52 @@ impl BluetoothDevice {
|
||||||
characteristic.indicate,
|
characteristic.indicate,
|
||||||
characteristic.authenticated_signed_writes,
|
characteristic.authenticated_signed_writes,
|
||||||
characteristic.reliable_write,
|
characteristic.reliable_write,
|
||||||
characteristic.writable_auxiliaries);
|
characteristic.writable_auxiliaries,
|
||||||
let bt_characteristic = BluetoothRemoteGATTCharacteristic::new(&service.global(),
|
);
|
||||||
|
let bt_characteristic = BluetoothRemoteGATTCharacteristic::new(
|
||||||
|
&service.global(),
|
||||||
service,
|
service,
|
||||||
DOMString::from(characteristic.uuid.clone()),
|
DOMString::from(characteristic.uuid.clone()),
|
||||||
&properties,
|
&properties,
|
||||||
characteristic.instance_id.clone());
|
characteristic.instance_id.clone(),
|
||||||
characteristic_map.insert(characteristic.instance_id.clone(), Dom::from_ref(&bt_characteristic));
|
);
|
||||||
|
characteristic_map.insert(
|
||||||
|
characteristic.instance_id.clone(),
|
||||||
|
Dom::from_ref(&bt_characteristic),
|
||||||
|
);
|
||||||
return bt_characteristic;
|
return bt_characteristic;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_represented_device_null(&self) -> bool {
|
pub fn is_represented_device_null(&self) -> bool {
|
||||||
let (sender, receiver) = ipc::channel(self.global().time_profiler_chan().clone()).unwrap();
|
let (sender, receiver) = ipc::channel(self.global().time_profiler_chan().clone()).unwrap();
|
||||||
self.get_bluetooth_thread().send(
|
self.get_bluetooth_thread()
|
||||||
BluetoothRequest::IsRepresentedDeviceNull(self.Id().to_string(), sender)).unwrap();
|
.send(BluetoothRequest::IsRepresentedDeviceNull(
|
||||||
|
self.Id().to_string(),
|
||||||
|
sender,
|
||||||
|
)).unwrap();
|
||||||
receiver.recv().unwrap()
|
receiver.recv().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_or_create_descriptor(&self,
|
pub fn get_or_create_descriptor(
|
||||||
|
&self,
|
||||||
descriptor: &BluetoothDescriptorMsg,
|
descriptor: &BluetoothDescriptorMsg,
|
||||||
characteristic: &BluetoothRemoteGATTCharacteristic)
|
characteristic: &BluetoothRemoteGATTCharacteristic,
|
||||||
-> DomRoot<BluetoothRemoteGATTDescriptor> {
|
) -> DomRoot<BluetoothRemoteGATTDescriptor> {
|
||||||
let (_, _, ref descriptor_map_ref) = self.attribute_instance_map;
|
let (_, _, ref descriptor_map_ref) = self.attribute_instance_map;
|
||||||
let mut descriptor_map = descriptor_map_ref.borrow_mut();
|
let mut descriptor_map = descriptor_map_ref.borrow_mut();
|
||||||
if let Some(existing_descriptor) = descriptor_map.get(&descriptor.instance_id) {
|
if let Some(existing_descriptor) = descriptor_map.get(&descriptor.instance_id) {
|
||||||
return DomRoot::from_ref(&existing_descriptor);
|
return DomRoot::from_ref(&existing_descriptor);
|
||||||
}
|
}
|
||||||
let bt_descriptor = BluetoothRemoteGATTDescriptor::new(&characteristic.global(),
|
let bt_descriptor = BluetoothRemoteGATTDescriptor::new(
|
||||||
|
&characteristic.global(),
|
||||||
characteristic,
|
characteristic,
|
||||||
DOMString::from(descriptor.uuid.clone()),
|
DOMString::from(descriptor.uuid.clone()),
|
||||||
descriptor.instance_id.clone());
|
descriptor.instance_id.clone(),
|
||||||
descriptor_map.insert(descriptor.instance_id.clone(), Dom::from_ref(&bt_descriptor));
|
);
|
||||||
|
descriptor_map.insert(
|
||||||
|
descriptor.instance_id.clone(),
|
||||||
|
Dom::from_ref(&bt_descriptor),
|
||||||
|
);
|
||||||
return bt_descriptor;
|
return bt_descriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,11 +206,17 @@ impl BluetoothDevice {
|
||||||
|
|
||||||
// Step 5, 6.4, 7.
|
// Step 5, 6.4, 7.
|
||||||
// TODO: Step 6: Implement `active notification context set` for BluetoothRemoteGATTCharacteristic.
|
// TODO: Step 6: Implement `active notification context set` for BluetoothRemoteGATTCharacteristic.
|
||||||
let _ = self.get_bluetooth_thread().send(
|
let _ = self
|
||||||
BluetoothRequest::SetRepresentedToNull(service_ids, characteristic_ids, descriptor_ids));
|
.get_bluetooth_thread()
|
||||||
|
.send(BluetoothRequest::SetRepresentedToNull(
|
||||||
|
service_ids,
|
||||||
|
characteristic_ids,
|
||||||
|
descriptor_ids,
|
||||||
|
));
|
||||||
|
|
||||||
// Step 8.
|
// Step 8.
|
||||||
self.upcast::<EventTarget>().fire_bubbling_event(atom!("gattserverdisconnected"));
|
self.upcast::<EventTarget>()
|
||||||
|
.fire_bubbling_event(atom!("gattserverdisconnected"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#garbage-collect-the-connection
|
// https://webbluetoothcg.github.io/web-bluetooth/#garbage-collect-the-connection
|
||||||
|
@ -206,8 +238,11 @@ impl BluetoothDevice {
|
||||||
|
|
||||||
// Step 3.
|
// Step 3.
|
||||||
let (sender, receiver) = ipc::channel(self.global().time_profiler_chan().clone()).unwrap();
|
let (sender, receiver) = ipc::channel(self.global().time_profiler_chan().clone()).unwrap();
|
||||||
self.get_bluetooth_thread().send(
|
self.get_bluetooth_thread()
|
||||||
BluetoothRequest::GATTServerDisconnect(String::from(self.Id()), sender)).unwrap();
|
.send(BluetoothRequest::GATTServerDisconnect(
|
||||||
|
String::from(self.Id()),
|
||||||
|
sender,
|
||||||
|
)).unwrap();
|
||||||
receiver.recv().unwrap().map_err(Error::from)
|
receiver.recv().unwrap().map_err(Error::from)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -226,9 +261,14 @@ impl BluetoothDeviceMethods for BluetoothDevice {
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdevice-gatt
|
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdevice-gatt
|
||||||
fn GetGatt(&self) -> Option<DomRoot<BluetoothRemoteGATTServer>> {
|
fn GetGatt(&self) -> Option<DomRoot<BluetoothRemoteGATTServer>> {
|
||||||
// Step 1.
|
// Step 1.
|
||||||
if self.global().as_window().bluetooth_extra_permission_data()
|
if self
|
||||||
.allowed_devices_contains_id(self.id.clone()) && !self.is_represented_device_null() {
|
.global()
|
||||||
return Some(self.get_gatt())
|
.as_window()
|
||||||
|
.bluetooth_extra_permission_data()
|
||||||
|
.allowed_devices_contains_id(self.id.clone()) &&
|
||||||
|
!self.is_represented_device_null()
|
||||||
|
{
|
||||||
|
return Some(self.get_gatt());
|
||||||
}
|
}
|
||||||
// Step 2.
|
// Step 2.
|
||||||
None
|
None
|
||||||
|
@ -242,8 +282,11 @@ impl BluetoothDeviceMethods for BluetoothDevice {
|
||||||
// TODO: Step 1.
|
// TODO: Step 1.
|
||||||
// Note: Steps 2 - 3 are implemented in components/bluetooth/lib.rs in watch_advertisements function
|
// Note: Steps 2 - 3 are implemented in components/bluetooth/lib.rs in watch_advertisements function
|
||||||
// and in handle_response function.
|
// and in handle_response function.
|
||||||
self.get_bluetooth_thread().send(
|
self.get_bluetooth_thread()
|
||||||
BluetoothRequest::WatchAdvertisements(String::from(self.Id()), sender)).unwrap();
|
.send(BluetoothRequest::WatchAdvertisements(
|
||||||
|
String::from(self.Id()),
|
||||||
|
sender,
|
||||||
|
)).unwrap();
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -260,7 +303,11 @@ impl BluetoothDeviceMethods for BluetoothDevice {
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdeviceeventhandlers-ongattserverdisconnected
|
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdeviceeventhandlers-ongattserverdisconnected
|
||||||
event_handler!(gattserverdisconnected, GetOngattserverdisconnected, SetOngattserverdisconnected);
|
event_handler!(
|
||||||
|
gattserverdisconnected,
|
||||||
|
GetOngattserverdisconnected,
|
||||||
|
SetOngattserverdisconnected
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsyncBluetoothListener for BluetoothDevice {
|
impl AsyncBluetoothListener for BluetoothDevice {
|
||||||
|
|
|
@ -40,10 +40,15 @@ impl BluetoothPermissionResult {
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(global: &GlobalScope, status: &PermissionStatus) -> DomRoot<BluetoothPermissionResult> {
|
pub fn new(
|
||||||
reflect_dom_object(Box::new(BluetoothPermissionResult::new_inherited(status)),
|
global: &GlobalScope,
|
||||||
|
status: &PermissionStatus,
|
||||||
|
) -> DomRoot<BluetoothPermissionResult> {
|
||||||
|
reflect_dom_object(
|
||||||
|
Box::new(BluetoothPermissionResult::new_inherited(status)),
|
||||||
global,
|
global,
|
||||||
BluetoothPermissionResultBinding::Wrap)
|
BluetoothPermissionResultBinding::Wrap,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_bluetooth(&self) -> DomRoot<Bluetooth> {
|
pub fn get_bluetooth(&self) -> DomRoot<Bluetooth> {
|
||||||
|
@ -75,8 +80,12 @@ impl BluetoothPermissionResult {
|
||||||
impl BluetoothPermissionResultMethods for BluetoothPermissionResult {
|
impl BluetoothPermissionResultMethods for BluetoothPermissionResult {
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothpermissionresult-devices
|
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothpermissionresult-devices
|
||||||
fn Devices(&self) -> Vec<DomRoot<BluetoothDevice>> {
|
fn Devices(&self) -> Vec<DomRoot<BluetoothDevice>> {
|
||||||
let device_vec: Vec<DomRoot<BluetoothDevice>> =
|
let device_vec: Vec<DomRoot<BluetoothDevice>> = self
|
||||||
self.devices.borrow().iter().map(|d| DomRoot::from_ref(&**d)).collect();
|
.devices
|
||||||
|
.borrow()
|
||||||
|
.iter()
|
||||||
|
.map(|d| DomRoot::from_ref(&**d))
|
||||||
|
.collect();
|
||||||
device_vec
|
device_vec
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -93,26 +102,29 @@ impl AsyncBluetoothListener for BluetoothPermissionResult {
|
||||||
if let Some(ref existing_device) = device_instance_map.get(&device.id) {
|
if let Some(ref existing_device) = device_instance_map.get(&device.id) {
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#request-the-bluetooth-permission
|
// https://webbluetoothcg.github.io/web-bluetooth/#request-the-bluetooth-permission
|
||||||
// Step 3.
|
// Step 3.
|
||||||
self.set_devices(vec!(Dom::from_ref(&*existing_device)));
|
self.set_devices(vec![Dom::from_ref(&*existing_device)]);
|
||||||
|
|
||||||
// https://w3c.github.io/permissions/#dom-permissions-request
|
// https://w3c.github.io/permissions/#dom-permissions-request
|
||||||
// Step 8.
|
// Step 8.
|
||||||
return promise.resolve_native(self);
|
return promise.resolve_native(self);
|
||||||
}
|
}
|
||||||
let bt_device = BluetoothDevice::new(&self.global(),
|
let bt_device = BluetoothDevice::new(
|
||||||
|
&self.global(),
|
||||||
DOMString::from(device.id.clone()),
|
DOMString::from(device.id.clone()),
|
||||||
device.name.map(DOMString::from),
|
device.name.map(DOMString::from),
|
||||||
&bluetooth);
|
&bluetooth,
|
||||||
|
);
|
||||||
device_instance_map.insert(device.id.clone(), Dom::from_ref(&bt_device));
|
device_instance_map.insert(device.id.clone(), Dom::from_ref(&bt_device));
|
||||||
self.global().as_window().bluetooth_extra_permission_data().add_new_allowed_device(
|
self.global()
|
||||||
AllowedBluetoothDevice {
|
.as_window()
|
||||||
|
.bluetooth_extra_permission_data()
|
||||||
|
.add_new_allowed_device(AllowedBluetoothDevice {
|
||||||
deviceId: DOMString::from(device.id),
|
deviceId: DOMString::from(device.id),
|
||||||
mayUseGATT: true,
|
mayUseGATT: true,
|
||||||
}
|
});
|
||||||
);
|
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#request-the-bluetooth-permission
|
// https://webbluetoothcg.github.io/web-bluetooth/#request-the-bluetooth-permission
|
||||||
// Step 3.
|
// Step 3.
|
||||||
self.set_devices(vec!(Dom::from_ref(&bt_device)));
|
self.set_devices(vec![Dom::from_ref(&bt_device)]);
|
||||||
|
|
||||||
// https://w3c.github.io/permissions/#dom-permissions-request
|
// https://w3c.github.io/permissions/#dom-permissions-request
|
||||||
// Step 8.
|
// Step 8.
|
||||||
|
|
|
@ -6,10 +6,10 @@ use bluetooth_traits::{BluetoothRequest, BluetoothResponse, GATTType};
|
||||||
use bluetooth_traits::blocklist::{Blocklist, uuid_is_blocklisted};
|
use bluetooth_traits::blocklist::{Blocklist, uuid_is_blocklisted};
|
||||||
use dom::bindings::cell::DomRefCell;
|
use dom::bindings::cell::DomRefCell;
|
||||||
use dom::bindings::codegen::Bindings::BluetoothCharacteristicPropertiesBinding::
|
use dom::bindings::codegen::Bindings::BluetoothCharacteristicPropertiesBinding::
|
||||||
BluetoothCharacteristicPropertiesMethods;
|
BluetoothCharacteristicPropertiesMethods;
|
||||||
use dom::bindings::codegen::Bindings::BluetoothRemoteGATTCharacteristicBinding;
|
use dom::bindings::codegen::Bindings::BluetoothRemoteGATTCharacteristicBinding;
|
||||||
use dom::bindings::codegen::Bindings::BluetoothRemoteGATTCharacteristicBinding::
|
use dom::bindings::codegen::Bindings::BluetoothRemoteGATTCharacteristicBinding::
|
||||||
BluetoothRemoteGATTCharacteristicMethods;
|
BluetoothRemoteGATTCharacteristicMethods;
|
||||||
use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServerBinding::BluetoothRemoteGATTServerMethods;
|
use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServerBinding::BluetoothRemoteGATTServerMethods;
|
||||||
use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServiceBinding::BluetoothRemoteGATTServiceMethods;
|
use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServiceBinding::BluetoothRemoteGATTServiceMethods;
|
||||||
use dom::bindings::codegen::UnionTypes::ArrayBufferViewOrArrayBuffer;
|
use dom::bindings::codegen::UnionTypes::ArrayBufferViewOrArrayBuffer;
|
||||||
|
@ -45,11 +45,12 @@ pub struct BluetoothRemoteGATTCharacteristic {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BluetoothRemoteGATTCharacteristic {
|
impl BluetoothRemoteGATTCharacteristic {
|
||||||
pub fn new_inherited(service: &BluetoothRemoteGATTService,
|
pub fn new_inherited(
|
||||||
|
service: &BluetoothRemoteGATTService,
|
||||||
uuid: DOMString,
|
uuid: DOMString,
|
||||||
properties: &BluetoothCharacteristicProperties,
|
properties: &BluetoothCharacteristicProperties,
|
||||||
instance_id: String)
|
instance_id: String,
|
||||||
-> BluetoothRemoteGATTCharacteristic {
|
) -> BluetoothRemoteGATTCharacteristic {
|
||||||
BluetoothRemoteGATTCharacteristic {
|
BluetoothRemoteGATTCharacteristic {
|
||||||
eventtarget: EventTarget::new_inherited(),
|
eventtarget: EventTarget::new_inherited(),
|
||||||
service: Dom::from_ref(service),
|
service: Dom::from_ref(service),
|
||||||
|
@ -60,18 +61,19 @@ impl BluetoothRemoteGATTCharacteristic {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(global: &GlobalScope,
|
pub fn new(
|
||||||
|
global: &GlobalScope,
|
||||||
service: &BluetoothRemoteGATTService,
|
service: &BluetoothRemoteGATTService,
|
||||||
uuid: DOMString,
|
uuid: DOMString,
|
||||||
properties: &BluetoothCharacteristicProperties,
|
properties: &BluetoothCharacteristicProperties,
|
||||||
instanceID: String)
|
instanceID: String,
|
||||||
-> DomRoot<BluetoothRemoteGATTCharacteristic> {
|
) -> DomRoot<BluetoothRemoteGATTCharacteristic> {
|
||||||
reflect_dom_object(
|
reflect_dom_object(
|
||||||
Box::new(BluetoothRemoteGATTCharacteristic::new_inherited(
|
Box::new(BluetoothRemoteGATTCharacteristic::new_inherited(
|
||||||
service, uuid, properties, instanceID
|
service, uuid, properties, instanceID,
|
||||||
)),
|
)),
|
||||||
global,
|
global,
|
||||||
BluetoothRemoteGATTCharacteristicBinding::Wrap
|
BluetoothRemoteGATTCharacteristicBinding::Wrap,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,17 +105,29 @@ impl BluetoothRemoteGATTCharacteristicMethods for BluetoothRemoteGATTCharacteris
|
||||||
#[allow(unrooted_must_root)]
|
#[allow(unrooted_must_root)]
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-getdescriptor
|
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-getdescriptor
|
||||||
fn GetDescriptor(&self, descriptor: BluetoothDescriptorUUID) -> Rc<Promise> {
|
fn GetDescriptor(&self, descriptor: BluetoothDescriptorUUID) -> Rc<Promise> {
|
||||||
get_gatt_children(self, true, BluetoothUUID::descriptor, Some(descriptor), self.get_instance_id(),
|
get_gatt_children(
|
||||||
self.Service().Device().get_gatt().Connected(), GATTType::Descriptor)
|
self,
|
||||||
|
true,
|
||||||
|
BluetoothUUID::descriptor,
|
||||||
|
Some(descriptor),
|
||||||
|
self.get_instance_id(),
|
||||||
|
self.Service().Device().get_gatt().Connected(),
|
||||||
|
GATTType::Descriptor,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unrooted_must_root)]
|
#[allow(unrooted_must_root)]
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-getdescriptors
|
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-getdescriptors
|
||||||
fn GetDescriptors(&self,
|
fn GetDescriptors(&self, descriptor: Option<BluetoothDescriptorUUID>) -> Rc<Promise> {
|
||||||
descriptor: Option<BluetoothDescriptorUUID>)
|
get_gatt_children(
|
||||||
-> Rc<Promise> {
|
self,
|
||||||
get_gatt_children(self, false, BluetoothUUID::descriptor, descriptor, self.get_instance_id(),
|
false,
|
||||||
self.Service().Device().get_gatt().Connected(), GATTType::Descriptor)
|
BluetoothUUID::descriptor,
|
||||||
|
descriptor,
|
||||||
|
self.get_instance_id(),
|
||||||
|
self.Service().Device().get_gatt().Connected(),
|
||||||
|
GATTType::Descriptor,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-value
|
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-value
|
||||||
|
@ -149,8 +163,9 @@ impl BluetoothRemoteGATTCharacteristicMethods for BluetoothRemoteGATTCharacteris
|
||||||
// Note: Steps 3 - 4 and the remaining substeps of Step 5 are implemented in components/bluetooth/lib.rs
|
// Note: Steps 3 - 4 and the remaining substeps of Step 5 are implemented in components/bluetooth/lib.rs
|
||||||
// in readValue function and in handle_response function.
|
// in readValue function and in handle_response function.
|
||||||
let sender = response_async(&p, self);
|
let sender = response_async(&p, self);
|
||||||
self.get_bluetooth_thread().send(
|
self.get_bluetooth_thread()
|
||||||
BluetoothRequest::ReadValue(self.get_instance_id(), sender)).unwrap();
|
.send(BluetoothRequest::ReadValue(self.get_instance_id(), sender))
|
||||||
|
.unwrap();
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,7 +202,8 @@ impl BluetoothRemoteGATTCharacteristicMethods for BluetoothRemoteGATTCharacteris
|
||||||
// Step 7.1.
|
// Step 7.1.
|
||||||
if !(self.Properties().Write() ||
|
if !(self.Properties().Write() ||
|
||||||
self.Properties().WriteWithoutResponse() ||
|
self.Properties().WriteWithoutResponse() ||
|
||||||
self.Properties().AuthenticatedSignedWrites()) {
|
self.Properties().AuthenticatedSignedWrites())
|
||||||
|
{
|
||||||
p.reject_error(NotSupported);
|
p.reject_error(NotSupported);
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
@ -195,8 +211,12 @@ impl BluetoothRemoteGATTCharacteristicMethods for BluetoothRemoteGATTCharacteris
|
||||||
// Note: Steps 5 - 6 and the remaining substeps of Step 7 are implemented in components/bluetooth/lib.rs
|
// Note: Steps 5 - 6 and the remaining substeps of Step 7 are implemented in components/bluetooth/lib.rs
|
||||||
// in writeValue function and in handle_response function.
|
// in writeValue function and in handle_response function.
|
||||||
let sender = response_async(&p, self);
|
let sender = response_async(&p, self);
|
||||||
self.get_bluetooth_thread().send(
|
self.get_bluetooth_thread()
|
||||||
BluetoothRequest::WriteValue(self.get_instance_id(), vec, sender)).unwrap();
|
.send(BluetoothRequest::WriteValue(
|
||||||
|
self.get_instance_id(),
|
||||||
|
vec,
|
||||||
|
sender,
|
||||||
|
)).unwrap();
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -218,8 +238,7 @@ impl BluetoothRemoteGATTCharacteristicMethods for BluetoothRemoteGATTCharacteris
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 5.
|
// Step 5.
|
||||||
if !(self.Properties().Notify() ||
|
if !(self.Properties().Notify() || self.Properties().Indicate()) {
|
||||||
self.Properties().Indicate()) {
|
|
||||||
p.reject_error(NotSupported);
|
p.reject_error(NotSupported);
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
@ -229,10 +248,12 @@ impl BluetoothRemoteGATTCharacteristicMethods for BluetoothRemoteGATTCharacteris
|
||||||
// Note: Steps 3 - 4, 7 - 11 are implemented in components/bluetooth/lib.rs in enable_notification function
|
// Note: Steps 3 - 4, 7 - 11 are implemented in components/bluetooth/lib.rs in enable_notification function
|
||||||
// and in handle_response function.
|
// and in handle_response function.
|
||||||
let sender = response_async(&p, self);
|
let sender = response_async(&p, self);
|
||||||
self.get_bluetooth_thread().send(
|
self.get_bluetooth_thread()
|
||||||
BluetoothRequest::EnableNotification(self.get_instance_id(),
|
.send(BluetoothRequest::EnableNotification(
|
||||||
|
self.get_instance_id(),
|
||||||
true,
|
true,
|
||||||
sender)).unwrap();
|
sender,
|
||||||
|
)).unwrap();
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -246,15 +267,21 @@ impl BluetoothRemoteGATTCharacteristicMethods for BluetoothRemoteGATTCharacteris
|
||||||
|
|
||||||
// Note: Steps 1 - 2, and part of Step 4 and Step 5 are implemented in components/bluetooth/lib.rs
|
// Note: Steps 1 - 2, and part of Step 4 and Step 5 are implemented in components/bluetooth/lib.rs
|
||||||
// in enable_notification function and in handle_response function.
|
// in enable_notification function and in handle_response function.
|
||||||
self.get_bluetooth_thread().send(
|
self.get_bluetooth_thread()
|
||||||
BluetoothRequest::EnableNotification(self.get_instance_id(),
|
.send(BluetoothRequest::EnableNotification(
|
||||||
|
self.get_instance_id(),
|
||||||
false,
|
false,
|
||||||
sender)).unwrap();
|
sender,
|
||||||
|
)).unwrap();
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-characteristiceventhandlers-oncharacteristicvaluechanged
|
// https://webbluetoothcg.github.io/web-bluetooth/#dom-characteristiceventhandlers-oncharacteristicvaluechanged
|
||||||
event_handler!(characteristicvaluechanged, GetOncharacteristicvaluechanged, SetOncharacteristicvaluechanged);
|
event_handler!(
|
||||||
|
characteristicvaluechanged,
|
||||||
|
GetOncharacteristicvaluechanged,
|
||||||
|
SetOncharacteristicvaluechanged
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsyncBluetoothListener for BluetoothRemoteGATTCharacteristic {
|
impl AsyncBluetoothListener for BluetoothRemoteGATTCharacteristic {
|
||||||
|
@ -265,10 +292,12 @@ impl AsyncBluetoothListener for BluetoothRemoteGATTCharacteristic {
|
||||||
// Step 7.
|
// Step 7.
|
||||||
BluetoothResponse::GetDescriptors(descriptors_vec, single) => {
|
BluetoothResponse::GetDescriptors(descriptors_vec, single) => {
|
||||||
if single {
|
if single {
|
||||||
promise.resolve_native(&device.get_or_create_descriptor(&descriptors_vec[0], &self));
|
promise.resolve_native(
|
||||||
|
&device.get_or_create_descriptor(&descriptors_vec[0], &self),
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let mut descriptors = vec!();
|
let mut descriptors = vec![];
|
||||||
for descriptor in descriptors_vec {
|
for descriptor in descriptors_vec {
|
||||||
let bt_descriptor = device.get_or_create_descriptor(&descriptor, &self);
|
let bt_descriptor = device.get_or_create_descriptor(&descriptor, &self);
|
||||||
descriptors.push(bt_descriptor);
|
descriptors.push(bt_descriptor);
|
||||||
|
@ -285,7 +314,8 @@ impl AsyncBluetoothListener for BluetoothRemoteGATTCharacteristic {
|
||||||
*self.value.borrow_mut() = Some(value.clone());
|
*self.value.borrow_mut() = Some(value.clone());
|
||||||
|
|
||||||
// Step 5.5.3.
|
// Step 5.5.3.
|
||||||
self.upcast::<EventTarget>().fire_bubbling_event(atom!("characteristicvaluechanged"));
|
self.upcast::<EventTarget>()
|
||||||
|
.fire_bubbling_event(atom!("characteristicvaluechanged"));
|
||||||
|
|
||||||
// Step 5.5.4.
|
// Step 5.5.4.
|
||||||
promise.resolve_native(&value);
|
promise.resolve_native(&value);
|
||||||
|
|
|
@ -6,7 +6,7 @@ use bluetooth_traits::{BluetoothRequest, BluetoothResponse};
|
||||||
use bluetooth_traits::blocklist::{Blocklist, uuid_is_blocklisted};
|
use bluetooth_traits::blocklist::{Blocklist, uuid_is_blocklisted};
|
||||||
use dom::bindings::cell::DomRefCell;
|
use dom::bindings::cell::DomRefCell;
|
||||||
use dom::bindings::codegen::Bindings::BluetoothRemoteGATTCharacteristicBinding::
|
use dom::bindings::codegen::Bindings::BluetoothRemoteGATTCharacteristicBinding::
|
||||||
BluetoothRemoteGATTCharacteristicMethods;
|
BluetoothRemoteGATTCharacteristicMethods;
|
||||||
use dom::bindings::codegen::Bindings::BluetoothRemoteGATTDescriptorBinding;
|
use dom::bindings::codegen::Bindings::BluetoothRemoteGATTDescriptorBinding;
|
||||||
use dom::bindings::codegen::Bindings::BluetoothRemoteGATTDescriptorBinding::BluetoothRemoteGATTDescriptorMethods;
|
use dom::bindings::codegen::Bindings::BluetoothRemoteGATTDescriptorBinding::BluetoothRemoteGATTDescriptorMethods;
|
||||||
use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServerBinding::BluetoothRemoteGATTServerMethods;
|
use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServerBinding::BluetoothRemoteGATTServerMethods;
|
||||||
|
@ -35,10 +35,11 @@ pub struct BluetoothRemoteGATTDescriptor {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BluetoothRemoteGATTDescriptor {
|
impl BluetoothRemoteGATTDescriptor {
|
||||||
pub fn new_inherited(characteristic: &BluetoothRemoteGATTCharacteristic,
|
pub fn new_inherited(
|
||||||
|
characteristic: &BluetoothRemoteGATTCharacteristic,
|
||||||
uuid: DOMString,
|
uuid: DOMString,
|
||||||
instance_id: String)
|
instance_id: String,
|
||||||
-> BluetoothRemoteGATTDescriptor {
|
) -> BluetoothRemoteGATTDescriptor {
|
||||||
BluetoothRemoteGATTDescriptor {
|
BluetoothRemoteGATTDescriptor {
|
||||||
reflector_: Reflector::new(),
|
reflector_: Reflector::new(),
|
||||||
characteristic: Dom::from_ref(characteristic),
|
characteristic: Dom::from_ref(characteristic),
|
||||||
|
@ -48,17 +49,20 @@ impl BluetoothRemoteGATTDescriptor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(global: &GlobalScope,
|
pub fn new(
|
||||||
|
global: &GlobalScope,
|
||||||
characteristic: &BluetoothRemoteGATTCharacteristic,
|
characteristic: &BluetoothRemoteGATTCharacteristic,
|
||||||
uuid: DOMString,
|
uuid: DOMString,
|
||||||
instanceID: String)
|
instanceID: String,
|
||||||
-> DomRoot<BluetoothRemoteGATTDescriptor>{
|
) -> DomRoot<BluetoothRemoteGATTDescriptor> {
|
||||||
reflect_dom_object(
|
reflect_dom_object(
|
||||||
Box::new(BluetoothRemoteGATTDescriptor::new_inherited(
|
Box::new(BluetoothRemoteGATTDescriptor::new_inherited(
|
||||||
characteristic, uuid, instanceID
|
characteristic,
|
||||||
|
uuid,
|
||||||
|
instanceID,
|
||||||
)),
|
)),
|
||||||
global,
|
global,
|
||||||
BluetoothRemoteGATTDescriptorBinding::Wrap
|
BluetoothRemoteGATTDescriptorBinding::Wrap,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,7 +103,13 @@ impl BluetoothRemoteGATTDescriptorMethods for BluetoothRemoteGATTDescriptor {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 2.
|
// Step 2.
|
||||||
if !self.Characteristic().Service().Device().get_gatt().Connected() {
|
if !self
|
||||||
|
.Characteristic()
|
||||||
|
.Service()
|
||||||
|
.Device()
|
||||||
|
.get_gatt()
|
||||||
|
.Connected()
|
||||||
|
{
|
||||||
p.reject_error(Network);
|
p.reject_error(Network);
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
@ -108,8 +118,9 @@ impl BluetoothRemoteGATTDescriptorMethods for BluetoothRemoteGATTDescriptor {
|
||||||
// Note: Steps 3 - 4 and substeps of Step 5 are implemented in components/bluetooth/lib.rs
|
// Note: Steps 3 - 4 and substeps of Step 5 are implemented in components/bluetooth/lib.rs
|
||||||
// in readValue function and in handle_response function.
|
// in readValue function and in handle_response function.
|
||||||
let sender = response_async(&p, self);
|
let sender = response_async(&p, self);
|
||||||
self.get_bluetooth_thread().send(
|
self.get_bluetooth_thread()
|
||||||
BluetoothRequest::ReadValue(self.get_instance_id(), sender)).unwrap();
|
.send(BluetoothRequest::ReadValue(self.get_instance_id(), sender))
|
||||||
|
.unwrap();
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,7 +146,13 @@ impl BluetoothRemoteGATTDescriptorMethods for BluetoothRemoteGATTDescriptor {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 4.
|
// Step 4.
|
||||||
if !self.Characteristic().Service().Device().get_gatt().Connected() {
|
if !self
|
||||||
|
.Characteristic()
|
||||||
|
.Service()
|
||||||
|
.Device()
|
||||||
|
.get_gatt()
|
||||||
|
.Connected()
|
||||||
|
{
|
||||||
p.reject_error(Network);
|
p.reject_error(Network);
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
@ -144,8 +161,12 @@ impl BluetoothRemoteGATTDescriptorMethods for BluetoothRemoteGATTDescriptor {
|
||||||
// Note: Steps 5 - 6 and substeps of Step 7 are implemented in components/bluetooth/lib.rs
|
// Note: Steps 5 - 6 and substeps of Step 7 are implemented in components/bluetooth/lib.rs
|
||||||
// in writeValue function and in handle_response function.
|
// in writeValue function and in handle_response function.
|
||||||
let sender = response_async(&p, self);
|
let sender = response_async(&p, self);
|
||||||
self.get_bluetooth_thread().send(
|
self.get_bluetooth_thread()
|
||||||
BluetoothRequest::WriteValue(self.get_instance_id(), vec, sender)).unwrap();
|
.send(BluetoothRequest::WriteValue(
|
||||||
|
self.get_instance_id(),
|
||||||
|
vec,
|
||||||
|
sender,
|
||||||
|
)).unwrap();
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,10 +37,15 @@ impl BluetoothRemoteGATTServer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(global: &GlobalScope, device: &BluetoothDevice) -> DomRoot<BluetoothRemoteGATTServer> {
|
pub fn new(
|
||||||
reflect_dom_object(Box::new(BluetoothRemoteGATTServer::new_inherited(device)),
|
global: &GlobalScope,
|
||||||
|
device: &BluetoothDevice,
|
||||||
|
) -> DomRoot<BluetoothRemoteGATTServer> {
|
||||||
|
reflect_dom_object(
|
||||||
|
Box::new(BluetoothRemoteGATTServer::new_inherited(device)),
|
||||||
global,
|
global,
|
||||||
BluetoothRemoteGATTServerBinding::Wrap)
|
BluetoothRemoteGATTServerBinding::Wrap,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_bluetooth_thread(&self) -> IpcSender<BluetoothRequest> {
|
fn get_bluetooth_thread(&self) -> IpcSender<BluetoothRequest> {
|
||||||
|
@ -78,8 +83,11 @@ impl BluetoothRemoteGATTServerMethods for BluetoothRemoteGATTServer {
|
||||||
|
|
||||||
// Note: Steps 2, 5.1.1 and 5.1.3 are in components/bluetooth/lib.rs in the gatt_server_connect function.
|
// Note: Steps 2, 5.1.1 and 5.1.3 are in components/bluetooth/lib.rs in the gatt_server_connect function.
|
||||||
// Steps 5.2.3 - 5.2.5 are in response function.
|
// Steps 5.2.3 - 5.2.5 are in response function.
|
||||||
self.get_bluetooth_thread().send(
|
self.get_bluetooth_thread()
|
||||||
BluetoothRequest::GATTServerConnect(String::from(self.Device().Id()), sender)).unwrap();
|
.send(BluetoothRequest::GATTServerConnect(
|
||||||
|
String::from(self.Device().Id()),
|
||||||
|
sender,
|
||||||
|
)).unwrap();
|
||||||
// Step 5: return promise.
|
// Step 5: return promise.
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
@ -90,7 +98,7 @@ impl BluetoothRemoteGATTServerMethods for BluetoothRemoteGATTServer {
|
||||||
|
|
||||||
// Step 2.
|
// Step 2.
|
||||||
if !self.Connected() {
|
if !self.Connected() {
|
||||||
return Ok(())
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 3.
|
// Step 3.
|
||||||
|
@ -104,17 +112,30 @@ impl BluetoothRemoteGATTServerMethods for BluetoothRemoteGATTServer {
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-getprimaryservice
|
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-getprimaryservice
|
||||||
fn GetPrimaryService(&self, service: BluetoothServiceUUID) -> Rc<Promise> {
|
fn GetPrimaryService(&self, service: BluetoothServiceUUID) -> Rc<Promise> {
|
||||||
// Step 1 - 2.
|
// Step 1 - 2.
|
||||||
get_gatt_children(self, true, BluetoothUUID::service, Some(service), String::from(self.Device().Id()),
|
get_gatt_children(
|
||||||
self.Device().get_gatt().Connected(), GATTType::PrimaryService)
|
self,
|
||||||
|
true,
|
||||||
|
BluetoothUUID::service,
|
||||||
|
Some(service),
|
||||||
|
String::from(self.Device().Id()),
|
||||||
|
self.Device().get_gatt().Connected(),
|
||||||
|
GATTType::PrimaryService,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unrooted_must_root)]
|
#[allow(unrooted_must_root)]
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-getprimaryservices
|
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-getprimaryservices
|
||||||
fn GetPrimaryServices(&self, service: Option<BluetoothServiceUUID>) -> Rc<Promise> {
|
fn GetPrimaryServices(&self, service: Option<BluetoothServiceUUID>) -> Rc<Promise> {
|
||||||
// Step 1 - 2.
|
// Step 1 - 2.
|
||||||
get_gatt_children(self, false, BluetoothUUID::service, service, String::from(self.Device().Id()),
|
get_gatt_children(
|
||||||
self.Connected(), GATTType::PrimaryService)
|
self,
|
||||||
|
false,
|
||||||
|
BluetoothUUID::service,
|
||||||
|
service,
|
||||||
|
String::from(self.Device().Id()),
|
||||||
|
self.Connected(),
|
||||||
|
GATTType::PrimaryService,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,7 +166,7 @@ impl AsyncBluetoothListener for BluetoothRemoteGATTServer {
|
||||||
promise.resolve_native(&device.get_or_create_service(&services_vec[0], &self));
|
promise.resolve_native(&device.get_or_create_service(&services_vec[0], &self));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let mut services = vec!();
|
let mut services = vec![];
|
||||||
for service in services_vec {
|
for service in services_vec {
|
||||||
let bt_service = device.get_or_create_service(&service, &self);
|
let bt_service = device.get_or_create_service(&service, &self);
|
||||||
services.push(bt_service);
|
services.push(bt_service);
|
||||||
|
|
|
@ -30,11 +30,12 @@ pub struct BluetoothRemoteGATTService {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BluetoothRemoteGATTService {
|
impl BluetoothRemoteGATTService {
|
||||||
pub fn new_inherited(device: &BluetoothDevice,
|
pub fn new_inherited(
|
||||||
|
device: &BluetoothDevice,
|
||||||
uuid: DOMString,
|
uuid: DOMString,
|
||||||
is_primary: bool,
|
is_primary: bool,
|
||||||
instance_id: String)
|
instance_id: String,
|
||||||
-> BluetoothRemoteGATTService {
|
) -> BluetoothRemoteGATTService {
|
||||||
BluetoothRemoteGATTService {
|
BluetoothRemoteGATTService {
|
||||||
eventtarget: EventTarget::new_inherited(),
|
eventtarget: EventTarget::new_inherited(),
|
||||||
device: Dom::from_ref(device),
|
device: Dom::from_ref(device),
|
||||||
|
@ -44,18 +45,19 @@ impl BluetoothRemoteGATTService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(global: &GlobalScope,
|
pub fn new(
|
||||||
|
global: &GlobalScope,
|
||||||
device: &BluetoothDevice,
|
device: &BluetoothDevice,
|
||||||
uuid: DOMString,
|
uuid: DOMString,
|
||||||
isPrimary: bool,
|
isPrimary: bool,
|
||||||
instanceID: String)
|
instanceID: String,
|
||||||
-> DomRoot<BluetoothRemoteGATTService> {
|
) -> DomRoot<BluetoothRemoteGATTService> {
|
||||||
reflect_dom_object(
|
reflect_dom_object(
|
||||||
Box::new(BluetoothRemoteGATTService::new_inherited(
|
Box::new(BluetoothRemoteGATTService::new_inherited(
|
||||||
device, uuid, isPrimary, instanceID
|
device, uuid, isPrimary, instanceID,
|
||||||
)),
|
)),
|
||||||
global,
|
global,
|
||||||
BluetoothRemoteGATTServiceBinding::Wrap
|
BluetoothRemoteGATTServiceBinding::Wrap,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,39 +84,61 @@ impl BluetoothRemoteGATTServiceMethods for BluetoothRemoteGATTService {
|
||||||
|
|
||||||
#[allow(unrooted_must_root)]
|
#[allow(unrooted_must_root)]
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getcharacteristic
|
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getcharacteristic
|
||||||
fn GetCharacteristic(&self,
|
fn GetCharacteristic(&self, characteristic: BluetoothCharacteristicUUID) -> Rc<Promise> {
|
||||||
characteristic: BluetoothCharacteristicUUID)
|
get_gatt_children(
|
||||||
-> Rc<Promise> {
|
self,
|
||||||
get_gatt_children(self, true, BluetoothUUID::characteristic, Some(characteristic), self.get_instance_id(),
|
true,
|
||||||
self.Device().get_gatt().Connected(), GATTType::Characteristic)
|
BluetoothUUID::characteristic,
|
||||||
|
Some(characteristic),
|
||||||
|
self.get_instance_id(),
|
||||||
|
self.Device().get_gatt().Connected(),
|
||||||
|
GATTType::Characteristic,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unrooted_must_root)]
|
#[allow(unrooted_must_root)]
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getcharacteristics
|
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getcharacteristics
|
||||||
fn GetCharacteristics(&self,
|
fn GetCharacteristics(
|
||||||
characteristic: Option<BluetoothCharacteristicUUID>)
|
&self,
|
||||||
-> Rc<Promise> {
|
characteristic: Option<BluetoothCharacteristicUUID>,
|
||||||
get_gatt_children(self, false, BluetoothUUID::characteristic, characteristic, self.get_instance_id(),
|
) -> Rc<Promise> {
|
||||||
self.Device().get_gatt().Connected(), GATTType::Characteristic)
|
get_gatt_children(
|
||||||
|
self,
|
||||||
|
false,
|
||||||
|
BluetoothUUID::characteristic,
|
||||||
|
characteristic,
|
||||||
|
self.get_instance_id(),
|
||||||
|
self.Device().get_gatt().Connected(),
|
||||||
|
GATTType::Characteristic,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unrooted_must_root)]
|
#[allow(unrooted_must_root)]
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getincludedservice
|
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getincludedservice
|
||||||
fn GetIncludedService(&self,
|
fn GetIncludedService(&self, service: BluetoothServiceUUID) -> Rc<Promise> {
|
||||||
service: BluetoothServiceUUID)
|
get_gatt_children(
|
||||||
-> Rc<Promise> {
|
self,
|
||||||
get_gatt_children(self, false, BluetoothUUID::service, Some(service), self.get_instance_id(),
|
false,
|
||||||
self.Device().get_gatt().Connected(), GATTType::IncludedService)
|
BluetoothUUID::service,
|
||||||
|
Some(service),
|
||||||
|
self.get_instance_id(),
|
||||||
|
self.Device().get_gatt().Connected(),
|
||||||
|
GATTType::IncludedService,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[allow(unrooted_must_root)]
|
#[allow(unrooted_must_root)]
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getincludedservices
|
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getincludedservices
|
||||||
fn GetIncludedServices(&self,
|
fn GetIncludedServices(&self, service: Option<BluetoothServiceUUID>) -> Rc<Promise> {
|
||||||
service: Option<BluetoothServiceUUID>)
|
get_gatt_children(
|
||||||
-> Rc<Promise> {
|
self,
|
||||||
get_gatt_children(self, false, BluetoothUUID::service, service, self.get_instance_id(),
|
false,
|
||||||
self.Device().get_gatt().Connected(), GATTType::IncludedService)
|
BluetoothUUID::service,
|
||||||
|
service,
|
||||||
|
self.get_instance_id(),
|
||||||
|
self.Device().get_gatt().Connected(),
|
||||||
|
GATTType::IncludedService,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-serviceeventhandlers-onserviceadded
|
// https://webbluetoothcg.github.io/web-bluetooth/#dom-serviceeventhandlers-onserviceadded
|
||||||
|
@ -135,12 +159,15 @@ impl AsyncBluetoothListener for BluetoothRemoteGATTService {
|
||||||
// Step 7.
|
// Step 7.
|
||||||
BluetoothResponse::GetCharacteristics(characteristics_vec, single) => {
|
BluetoothResponse::GetCharacteristics(characteristics_vec, single) => {
|
||||||
if single {
|
if single {
|
||||||
promise.resolve_native(&device.get_or_create_characteristic(&characteristics_vec[0], &self));
|
promise.resolve_native(
|
||||||
|
&device.get_or_create_characteristic(&characteristics_vec[0], &self),
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let mut characteristics = vec!();
|
let mut characteristics = vec![];
|
||||||
for characteristic in characteristics_vec {
|
for characteristic in characteristics_vec {
|
||||||
let bt_characteristic = device.get_or_create_characteristic(&characteristic, &self);
|
let bt_characteristic =
|
||||||
|
device.get_or_create_characteristic(&characteristic, &self);
|
||||||
characteristics.push(bt_characteristic);
|
characteristics.push(bt_characteristic);
|
||||||
}
|
}
|
||||||
promise.resolve_native(&characteristics);
|
promise.resolve_native(&characteristics);
|
||||||
|
@ -149,9 +176,11 @@ impl AsyncBluetoothListener for BluetoothRemoteGATTService {
|
||||||
// Step 7.
|
// Step 7.
|
||||||
BluetoothResponse::GetIncludedServices(services_vec, single) => {
|
BluetoothResponse::GetIncludedServices(services_vec, single) => {
|
||||||
if single {
|
if single {
|
||||||
return promise.resolve_native(&device.get_or_create_service(&services_vec[0], &device.get_gatt()));
|
return promise.resolve_native(
|
||||||
|
&device.get_or_create_service(&services_vec[0], &device.get_gatt()),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
let mut services = vec!();
|
let mut services = vec![];
|
||||||
for service in services_vec {
|
for service in services_vec {
|
||||||
let bt_service = device.get_or_create_service(&service, &device.get_gatt());
|
let bt_service = device.get_or_create_service(&service, &device.get_gatt());
|
||||||
services.push(bt_service);
|
services.push(bt_service);
|
||||||
|
|
|
@ -17,7 +17,7 @@ pub type BluetoothCharacteristicUUID = StringOrUnsignedLong;
|
||||||
pub type BluetoothDescriptorUUID = StringOrUnsignedLong;
|
pub type BluetoothDescriptorUUID = StringOrUnsignedLong;
|
||||||
|
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#bluetoothuuid
|
// https://webbluetoothcg.github.io/web-bluetooth/#bluetoothuuid
|
||||||
#[dom_struct]
|
#[dom_struct]
|
||||||
pub struct BluetoothUUID {
|
pub struct BluetoothUUID {
|
||||||
reflector_: Reflector,
|
reflector_: Reflector,
|
||||||
}
|
}
|
||||||
|
@ -30,10 +30,16 @@ const BLUETOOTH_ASSIGNED_SERVICES: &'static [(&'static str, u32)] = &[
|
||||||
("org.bluetooth.service.blood_pressure", 0x1810_u32),
|
("org.bluetooth.service.blood_pressure", 0x1810_u32),
|
||||||
("org.bluetooth.service.body_composition", 0x181b_u32),
|
("org.bluetooth.service.body_composition", 0x181b_u32),
|
||||||
("org.bluetooth.service.bond_management", 0x181e_u32),
|
("org.bluetooth.service.bond_management", 0x181e_u32),
|
||||||
("org.bluetooth.service.continuous_glucose_monitoring", 0x181f_u32),
|
(
|
||||||
|
"org.bluetooth.service.continuous_glucose_monitoring",
|
||||||
|
0x181f_u32,
|
||||||
|
),
|
||||||
("org.bluetooth.service.current_time", 0x1805_u32),
|
("org.bluetooth.service.current_time", 0x1805_u32),
|
||||||
("org.bluetooth.service.cycling_power", 0x1818_u32),
|
("org.bluetooth.service.cycling_power", 0x1818_u32),
|
||||||
("org.bluetooth.service.cycling_speed_and_cadence", 0x1816_u32),
|
(
|
||||||
|
"org.bluetooth.service.cycling_speed_and_cadence",
|
||||||
|
0x1816_u32,
|
||||||
|
),
|
||||||
("org.bluetooth.service.device_information", 0x180a_u32),
|
("org.bluetooth.service.device_information", 0x180a_u32),
|
||||||
("org.bluetooth.service.environmental_sensing", 0x181a_u32),
|
("org.bluetooth.service.environmental_sensing", 0x181a_u32),
|
||||||
("org.bluetooth.service.generic_access", 0x1800_u32),
|
("org.bluetooth.service.generic_access", 0x1800_u32),
|
||||||
|
@ -45,7 +51,10 @@ const BLUETOOTH_ASSIGNED_SERVICES: &'static [(&'static str, u32)] = &[
|
||||||
("org.bluetooth.service.human_interface_device", 0x1812_u32),
|
("org.bluetooth.service.human_interface_device", 0x1812_u32),
|
||||||
("org.bluetooth.service.immediate_alert", 0x1802_u32),
|
("org.bluetooth.service.immediate_alert", 0x1802_u32),
|
||||||
("org.bluetooth.service.indoor_positioning", 0x1821_u32),
|
("org.bluetooth.service.indoor_positioning", 0x1821_u32),
|
||||||
("org.bluetooth.service.internet_protocol_support", 0x1820_u32),
|
(
|
||||||
|
"org.bluetooth.service.internet_protocol_support",
|
||||||
|
0x1820_u32,
|
||||||
|
),
|
||||||
("org.bluetooth.service.link_loss", 0x1803_u32),
|
("org.bluetooth.service.link_loss", 0x1803_u32),
|
||||||
("org.bluetooth.service.location_and_navigation", 0x1819_u32),
|
("org.bluetooth.service.location_and_navigation", 0x1819_u32),
|
||||||
("org.bluetooth.service.next_dst_change", 0x1807_u32),
|
("org.bluetooth.service.next_dst_change", 0x1807_u32),
|
||||||
|
@ -53,7 +62,10 @@ const BLUETOOTH_ASSIGNED_SERVICES: &'static [(&'static str, u32)] = &[
|
||||||
("org.bluetooth.service.phone_alert_status", 0x180e_u32),
|
("org.bluetooth.service.phone_alert_status", 0x180e_u32),
|
||||||
("org.bluetooth.service.pulse_oximeter", 0x1822_u32),
|
("org.bluetooth.service.pulse_oximeter", 0x1822_u32),
|
||||||
("org.bluetooth.service.reference_time_update", 0x1806_u32),
|
("org.bluetooth.service.reference_time_update", 0x1806_u32),
|
||||||
("org.bluetooth.service.running_speed_and_cadence", 0x1814_u32),
|
(
|
||||||
|
"org.bluetooth.service.running_speed_and_cadence",
|
||||||
|
0x1814_u32,
|
||||||
|
),
|
||||||
("org.bluetooth.service.scan_parameters", 0x1813_u32),
|
("org.bluetooth.service.scan_parameters", 0x1813_u32),
|
||||||
("org.bluetooth.service.transport_discovery", 0x1824),
|
("org.bluetooth.service.transport_discovery", 0x1824),
|
||||||
("org.bluetooth.service.tx_power", 0x1804_u32),
|
("org.bluetooth.service.tx_power", 0x1804_u32),
|
||||||
|
@ -63,57 +75,150 @@ const BLUETOOTH_ASSIGNED_SERVICES: &'static [(&'static str, u32)] = &[
|
||||||
|
|
||||||
//https://developer.bluetooth.org/gatt/services/Pages/ServicesHome.aspx
|
//https://developer.bluetooth.org/gatt/services/Pages/ServicesHome.aspx
|
||||||
const BLUETOOTH_ASSIGNED_CHARCTERISTICS: &'static [(&'static str, u32)] = &[
|
const BLUETOOTH_ASSIGNED_CHARCTERISTICS: &'static [(&'static str, u32)] = &[
|
||||||
("org.bluetooth.characteristic.aerobic_heart_rate_lower_limit", 0x2a7e_u32),
|
(
|
||||||
("org.bluetooth.characteristic.aerobic_heart_rate_upper_limit", 0x2a84_u32),
|
"org.bluetooth.characteristic.aerobic_heart_rate_lower_limit",
|
||||||
|
0x2a7e_u32,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"org.bluetooth.characteristic.aerobic_heart_rate_upper_limit",
|
||||||
|
0x2a84_u32,
|
||||||
|
),
|
||||||
("org.bluetooth.characteristic.aerobic_threshold", 0x2a7f_u32),
|
("org.bluetooth.characteristic.aerobic_threshold", 0x2a7f_u32),
|
||||||
("org.bluetooth.characteristic.age", 0x2a80_u32),
|
("org.bluetooth.characteristic.age", 0x2a80_u32),
|
||||||
("org.bluetooth.characteristic.aggregate", 0x2a5a_u32),
|
("org.bluetooth.characteristic.aggregate", 0x2a5a_u32),
|
||||||
("org.bluetooth.characteristic.alert_category_id", 0x2a43_u32),
|
("org.bluetooth.characteristic.alert_category_id", 0x2a43_u32),
|
||||||
("org.bluetooth.characteristic.alert_category_id_bit_mask", 0x2a42_u32),
|
(
|
||||||
|
"org.bluetooth.characteristic.alert_category_id_bit_mask",
|
||||||
|
0x2a42_u32,
|
||||||
|
),
|
||||||
("org.bluetooth.characteristic.alert_level", 0x2a06_u32),
|
("org.bluetooth.characteristic.alert_level", 0x2a06_u32),
|
||||||
("org.bluetooth.characteristic.alert_notification_control_point", 0x2a44_u32),
|
(
|
||||||
|
"org.bluetooth.characteristic.alert_notification_control_point",
|
||||||
|
0x2a44_u32,
|
||||||
|
),
|
||||||
("org.bluetooth.characteristic.alert_status", 0x2a3f_u32),
|
("org.bluetooth.characteristic.alert_status", 0x2a3f_u32),
|
||||||
("org.bluetooth.characteristic.altitude", 0x2ab3_u32),
|
("org.bluetooth.characteristic.altitude", 0x2ab3_u32),
|
||||||
("org.bluetooth.characteristic.anaerobic_heart_rate_lower_limit", 0x2a81_u32),
|
(
|
||||||
("org.bluetooth.characteristic.anaerobic_heart_rate_upper_limit", 0x2a82_u32),
|
"org.bluetooth.characteristic.anaerobic_heart_rate_lower_limit",
|
||||||
("org.bluetooth.characteristic.anaerobic_threshold", 0x2a83_u32),
|
0x2a81_u32,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"org.bluetooth.characteristic.anaerobic_heart_rate_upper_limit",
|
||||||
|
0x2a82_u32,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"org.bluetooth.characteristic.anaerobic_threshold",
|
||||||
|
0x2a83_u32,
|
||||||
|
),
|
||||||
("org.bluetooth.characteristic.analog", 0x2a58_u32),
|
("org.bluetooth.characteristic.analog", 0x2a58_u32),
|
||||||
("org.bluetooth.characteristic.apparent_wind_direction", 0x2a73_u32),
|
(
|
||||||
("org.bluetooth.characteristic.apparent_wind_speed", 0x2a72_u32),
|
"org.bluetooth.characteristic.apparent_wind_direction",
|
||||||
|
0x2a73_u32,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"org.bluetooth.characteristic.apparent_wind_speed",
|
||||||
|
0x2a72_u32,
|
||||||
|
),
|
||||||
("org.bluetooth.characteristic.gap.appearance", 0x2a01_u32),
|
("org.bluetooth.characteristic.gap.appearance", 0x2a01_u32),
|
||||||
("org.bluetooth.characteristic.barometric_pressure_trend", 0x2aa3_u32),
|
(
|
||||||
|
"org.bluetooth.characteristic.barometric_pressure_trend",
|
||||||
|
0x2aa3_u32,
|
||||||
|
),
|
||||||
("org.bluetooth.characteristic.battery_level", 0x2a19_u32),
|
("org.bluetooth.characteristic.battery_level", 0x2a19_u32),
|
||||||
("org.bluetooth.characteristic.blood_pressure_feature", 0x2a49_u32),
|
(
|
||||||
("org.bluetooth.characteristic.blood_pressure_measurement", 0x2a35_u32),
|
"org.bluetooth.characteristic.blood_pressure_feature",
|
||||||
("org.bluetooth.characteristic.body_composition_feature", 0x2a9b_u32),
|
0x2a49_u32,
|
||||||
("org.bluetooth.characteristic.body_composition_measurement", 0x2a9c_u32),
|
),
|
||||||
("org.bluetooth.characteristic.body_sensor_location", 0x2a38_u32),
|
(
|
||||||
("org.bluetooth.characteristic.bond_management_control_point", 0x2aa4_u32),
|
"org.bluetooth.characteristic.blood_pressure_measurement",
|
||||||
("org.bluetooth.characteristic.bond_management_feature", 0x2aa5_u32),
|
0x2a35_u32,
|
||||||
("org.bluetooth.characteristic.boot_keyboard_input_report", 0x2a22_u32),
|
),
|
||||||
("org.bluetooth.characteristic.boot_keyboard_output_report", 0x2a32_u32),
|
(
|
||||||
("org.bluetooth.characteristic.boot_mouse_input_report", 0x2a33_u32),
|
"org.bluetooth.characteristic.body_composition_feature",
|
||||||
("org.bluetooth.characteristic.gap.central_address_resolution_support", 0x2aa6_u32),
|
0x2a9b_u32,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"org.bluetooth.characteristic.body_composition_measurement",
|
||||||
|
0x2a9c_u32,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"org.bluetooth.characteristic.body_sensor_location",
|
||||||
|
0x2a38_u32,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"org.bluetooth.characteristic.bond_management_control_point",
|
||||||
|
0x2aa4_u32,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"org.bluetooth.characteristic.bond_management_feature",
|
||||||
|
0x2aa5_u32,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"org.bluetooth.characteristic.boot_keyboard_input_report",
|
||||||
|
0x2a22_u32,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"org.bluetooth.characteristic.boot_keyboard_output_report",
|
||||||
|
0x2a32_u32,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"org.bluetooth.characteristic.boot_mouse_input_report",
|
||||||
|
0x2a33_u32,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"org.bluetooth.characteristic.gap.central_address_resolution_support",
|
||||||
|
0x2aa6_u32,
|
||||||
|
),
|
||||||
("org.bluetooth.characteristic.cgm_feature", 0x2aa8_u32),
|
("org.bluetooth.characteristic.cgm_feature", 0x2aa8_u32),
|
||||||
("org.bluetooth.characteristic.cgm_measurement", 0x2aa7_u32),
|
("org.bluetooth.characteristic.cgm_measurement", 0x2aa7_u32),
|
||||||
("org.bluetooth.characteristic.cgm_session_run_time", 0x2aab_u32),
|
(
|
||||||
("org.bluetooth.characteristic.cgm_session_start_time", 0x2aaa_u32),
|
"org.bluetooth.characteristic.cgm_session_run_time",
|
||||||
("org.bluetooth.characteristic.cgm_specific_ops_control_point", 0x2aac_u32),
|
0x2aab_u32,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"org.bluetooth.characteristic.cgm_session_start_time",
|
||||||
|
0x2aaa_u32,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"org.bluetooth.characteristic.cgm_specific_ops_control_point",
|
||||||
|
0x2aac_u32,
|
||||||
|
),
|
||||||
("org.bluetooth.characteristic.cgm_status", 0x2aa9_u32),
|
("org.bluetooth.characteristic.cgm_status", 0x2aa9_u32),
|
||||||
("org.bluetooth.characteristic.csc_feature", 0x2a5c_u32),
|
("org.bluetooth.characteristic.csc_feature", 0x2a5c_u32),
|
||||||
("org.bluetooth.characteristic.csc_measurement", 0x2a5b_u32),
|
("org.bluetooth.characteristic.csc_measurement", 0x2a5b_u32),
|
||||||
("org.bluetooth.characteristic.current_time", 0x2a2b_u32),
|
("org.bluetooth.characteristic.current_time", 0x2a2b_u32),
|
||||||
("org.bluetooth.characteristic.cycling_power_control_point", 0x2a66_u32),
|
(
|
||||||
("org.bluetooth.characteristic.cycling_power_feature", 0x2a65_u32),
|
"org.bluetooth.characteristic.cycling_power_control_point",
|
||||||
("org.bluetooth.characteristic.cycling_power_measurement", 0x2a63_u32),
|
0x2a66_u32,
|
||||||
("org.bluetooth.characteristic.cycling_power_vector", 0x2a64_u32),
|
),
|
||||||
("org.bluetooth.characteristic.database_change_increment", 0x2a99_u32),
|
(
|
||||||
|
"org.bluetooth.characteristic.cycling_power_feature",
|
||||||
|
0x2a65_u32,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"org.bluetooth.characteristic.cycling_power_measurement",
|
||||||
|
0x2a63_u32,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"org.bluetooth.characteristic.cycling_power_vector",
|
||||||
|
0x2a64_u32,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"org.bluetooth.characteristic.database_change_increment",
|
||||||
|
0x2a99_u32,
|
||||||
|
),
|
||||||
("org.bluetooth.characteristic.date_of_birth", 0x2a85_u32),
|
("org.bluetooth.characteristic.date_of_birth", 0x2a85_u32),
|
||||||
("org.bluetooth.characteristic.date_of_threshold_assessment", 0x2a86_u32),
|
(
|
||||||
|
"org.bluetooth.characteristic.date_of_threshold_assessment",
|
||||||
|
0x2a86_u32,
|
||||||
|
),
|
||||||
("org.bluetooth.characteristic.date_time", 0x2a08_u32),
|
("org.bluetooth.characteristic.date_time", 0x2a08_u32),
|
||||||
("org.bluetooth.characteristic.day_date_time", 0x2a0a_u32),
|
("org.bluetooth.characteristic.day_date_time", 0x2a0a_u32),
|
||||||
("org.bluetooth.characteristic.day_of_week", 0x2a09_u32),
|
("org.bluetooth.characteristic.day_of_week", 0x2a09_u32),
|
||||||
("org.bluetooth.characteristic.descriptor_value_changed", 0x2a7d_u32),
|
(
|
||||||
|
"org.bluetooth.characteristic.descriptor_value_changed",
|
||||||
|
0x2a7d_u32,
|
||||||
|
),
|
||||||
("org.bluetooth.characteristic.gap.device_name", 0x2a00_u32),
|
("org.bluetooth.characteristic.gap.device_name", 0x2a00_u32),
|
||||||
("org.bluetooth.characteristic.dew_point", 0x2a7b_u32),
|
("org.bluetooth.characteristic.dew_point", 0x2a7b_u32),
|
||||||
("org.bluetooth.characteristic.digital", 0x2a56_u32),
|
("org.bluetooth.characteristic.digital", 0x2a56_u32),
|
||||||
|
@ -121,140 +226,332 @@ const BLUETOOTH_ASSIGNED_CHARCTERISTICS: &'static [(&'static str, u32)] = &[
|
||||||
("org.bluetooth.characteristic.elevation", 0x2a6c_u32),
|
("org.bluetooth.characteristic.elevation", 0x2a6c_u32),
|
||||||
("org.bluetooth.characteristic.email_address", 0x2a87_u32),
|
("org.bluetooth.characteristic.email_address", 0x2a87_u32),
|
||||||
("org.bluetooth.characteristic.exact_time_256", 0x2a0c_u32),
|
("org.bluetooth.characteristic.exact_time_256", 0x2a0c_u32),
|
||||||
("org.bluetooth.characteristic.fat_burn_heart_rate_lower_limit", 0x2a88_u32),
|
(
|
||||||
("org.bluetooth.characteristic.fat_burn_heart_rate_upper_limit", 0x2a89_u32),
|
"org.bluetooth.characteristic.fat_burn_heart_rate_lower_limit",
|
||||||
("org.bluetooth.characteristic.firmware_revision_string", 0x2a26_u32),
|
0x2a88_u32,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"org.bluetooth.characteristic.fat_burn_heart_rate_upper_limit",
|
||||||
|
0x2a89_u32,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"org.bluetooth.characteristic.firmware_revision_string",
|
||||||
|
0x2a26_u32,
|
||||||
|
),
|
||||||
("org.bluetooth.characteristic.first_name", 0x2a8a_u32),
|
("org.bluetooth.characteristic.first_name", 0x2a8a_u32),
|
||||||
("org.bluetooth.characteristic.five_zone_heart_rate_limits", 0x2a8b_u32),
|
(
|
||||||
|
"org.bluetooth.characteristic.five_zone_heart_rate_limits",
|
||||||
|
0x2a8b_u32,
|
||||||
|
),
|
||||||
("org.bluetooth.characteristic.floor_number", 0x2ab2_u32),
|
("org.bluetooth.characteristic.floor_number", 0x2ab2_u32),
|
||||||
("org.bluetooth.characteristic.gender", 0x2a8c_u32),
|
("org.bluetooth.characteristic.gender", 0x2a8c_u32),
|
||||||
("org.bluetooth.characteristic.glucose_feature", 0x2a51_u32),
|
("org.bluetooth.characteristic.glucose_feature", 0x2a51_u32),
|
||||||
("org.bluetooth.characteristic.glucose_measurement", 0x2a18_u32),
|
(
|
||||||
("org.bluetooth.characteristic.glucose_measurement_context", 0x2a34_u32),
|
"org.bluetooth.characteristic.glucose_measurement",
|
||||||
|
0x2a18_u32,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"org.bluetooth.characteristic.glucose_measurement_context",
|
||||||
|
0x2a34_u32,
|
||||||
|
),
|
||||||
("org.bluetooth.characteristic.gust_factor", 0x2a74_u32),
|
("org.bluetooth.characteristic.gust_factor", 0x2a74_u32),
|
||||||
("org.bluetooth.characteristic.hardware_revision_string", 0x2a27_u32),
|
(
|
||||||
("org.bluetooth.characteristic.heart_rate_control_point", 0x2a39_u32),
|
"org.bluetooth.characteristic.hardware_revision_string",
|
||||||
|
0x2a27_u32,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"org.bluetooth.characteristic.heart_rate_control_point",
|
||||||
|
0x2a39_u32,
|
||||||
|
),
|
||||||
("org.bluetooth.characteristic.heart_rate_max", 0x2a8d_u32),
|
("org.bluetooth.characteristic.heart_rate_max", 0x2a8d_u32),
|
||||||
("org.bluetooth.characteristic.heart_rate_measurement", 0x2a37_u32),
|
(
|
||||||
|
"org.bluetooth.characteristic.heart_rate_measurement",
|
||||||
|
0x2a37_u32,
|
||||||
|
),
|
||||||
("org.bluetooth.characteristic.heat_index", 0x2a7a_u32),
|
("org.bluetooth.characteristic.heat_index", 0x2a7a_u32),
|
||||||
("org.bluetooth.characteristic.height", 0x2a8e_u32),
|
("org.bluetooth.characteristic.height", 0x2a8e_u32),
|
||||||
("org.bluetooth.characteristic.hid_control_point", 0x2a4c_u32),
|
("org.bluetooth.characteristic.hid_control_point", 0x2a4c_u32),
|
||||||
("org.bluetooth.characteristic.hid_information", 0x2a4a_u32),
|
("org.bluetooth.characteristic.hid_information", 0x2a4a_u32),
|
||||||
("org.bluetooth.characteristic.hip_circumference", 0x2a8f_u32),
|
("org.bluetooth.characteristic.hip_circumference", 0x2a8f_u32),
|
||||||
("org.bluetooth.characteristic.http_control_point", 0x2aba_u32),
|
(
|
||||||
|
"org.bluetooth.characteristic.http_control_point",
|
||||||
|
0x2aba_u32,
|
||||||
|
),
|
||||||
("org.bluetooth.characteristic.http_entity_body", 0x2ab9_u32),
|
("org.bluetooth.characteristic.http_entity_body", 0x2ab9_u32),
|
||||||
("org.bluetooth.characteristic.http_headers", 0x2ab7_u32),
|
("org.bluetooth.characteristic.http_headers", 0x2ab7_u32),
|
||||||
("org.bluetooth.characteristic.http_status_code", 0x2ab8_u32),
|
("org.bluetooth.characteristic.http_status_code", 0x2ab8_u32),
|
||||||
("org.bluetooth.characteristic.https_security", 0x2abb_u32),
|
("org.bluetooth.characteristic.https_security", 0x2abb_u32),
|
||||||
("org.bluetooth.characteristic.humidity", 0x2a6f_u32),
|
("org.bluetooth.characteristic.humidity", 0x2a6f_u32),
|
||||||
("org.bluetooth.characteristic.ieee_11073-20601_regulatory_certification_data_list", 0x2a2a_u32),
|
(
|
||||||
("org.bluetooth.characteristic.indoor_positioning_configuration", 0x2aad_u32),
|
"org.bluetooth.characteristic.ieee_11073-20601_regulatory_certification_data_list",
|
||||||
("org.bluetooth.characteristic.intermediate_cuff_pressure", 0x2a36_u32),
|
0x2a2a_u32,
|
||||||
("org.bluetooth.characteristic.intermediate_temperature", 0x2a1e_u32),
|
),
|
||||||
|
(
|
||||||
|
"org.bluetooth.characteristic.indoor_positioning_configuration",
|
||||||
|
0x2aad_u32,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"org.bluetooth.characteristic.intermediate_cuff_pressure",
|
||||||
|
0x2a36_u32,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"org.bluetooth.characteristic.intermediate_temperature",
|
||||||
|
0x2a1e_u32,
|
||||||
|
),
|
||||||
("org.bluetooth.characteristic.irradiance", 0x2a77_u32),
|
("org.bluetooth.characteristic.irradiance", 0x2a77_u32),
|
||||||
("org.bluetooth.characteristic.language", 0x2aa2_u32),
|
("org.bluetooth.characteristic.language", 0x2aa2_u32),
|
||||||
("org.bluetooth.characteristic.last_name", 0x2a90_u32),
|
("org.bluetooth.characteristic.last_name", 0x2a90_u32),
|
||||||
("org.bluetooth.characteristic.latitude", 0x2aae_u32),
|
("org.bluetooth.characteristic.latitude", 0x2aae_u32),
|
||||||
("org.bluetooth.characteristic.ln_control_point", 0x2a6b_u32),
|
("org.bluetooth.characteristic.ln_control_point", 0x2a6b_u32),
|
||||||
("org.bluetooth.characteristic.ln_feature", 0x2a6a_u32),
|
("org.bluetooth.characteristic.ln_feature", 0x2a6a_u32),
|
||||||
("org.bluetooth.characteristic.local_east_coordinate.xml", 0x2ab1_u32),
|
(
|
||||||
("org.bluetooth.characteristic.local_north_coordinate", 0x2ab0_u32),
|
"org.bluetooth.characteristic.local_east_coordinate.xml",
|
||||||
("org.bluetooth.characteristic.local_time_information", 0x2a0f_u32),
|
0x2ab1_u32,
|
||||||
("org.bluetooth.characteristic.location_and_speed", 0x2a67_u32),
|
),
|
||||||
|
(
|
||||||
|
"org.bluetooth.characteristic.local_north_coordinate",
|
||||||
|
0x2ab0_u32,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"org.bluetooth.characteristic.local_time_information",
|
||||||
|
0x2a0f_u32,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"org.bluetooth.characteristic.location_and_speed",
|
||||||
|
0x2a67_u32,
|
||||||
|
),
|
||||||
("org.bluetooth.characteristic.location_name", 0x2ab5_u32),
|
("org.bluetooth.characteristic.location_name", 0x2ab5_u32),
|
||||||
("org.bluetooth.characteristic.longitude", 0x2aaf_u32),
|
("org.bluetooth.characteristic.longitude", 0x2aaf_u32),
|
||||||
("org.bluetooth.characteristic.magnetic_declination", 0x2a2c_u32),
|
(
|
||||||
("org.bluetooth.characteristic.magnetic_flux_density_2d", 0x2aa0_u32),
|
"org.bluetooth.characteristic.magnetic_declination",
|
||||||
("org.bluetooth.characteristic.magnetic_flux_density_3d", 0x2aa1_u32),
|
0x2a2c_u32,
|
||||||
("org.bluetooth.characteristic.manufacturer_name_string", 0x2a29_u32),
|
),
|
||||||
("org.bluetooth.characteristic.maximum_recommended_heart_rate", 0x2a91_u32),
|
(
|
||||||
("org.bluetooth.characteristic.measurement_interval", 0x2a21_u32),
|
"org.bluetooth.characteristic.magnetic_flux_density_2d",
|
||||||
("org.bluetooth.characteristic.model_number_string", 0x2a24_u32),
|
0x2aa0_u32,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"org.bluetooth.characteristic.magnetic_flux_density_3d",
|
||||||
|
0x2aa1_u32,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"org.bluetooth.characteristic.manufacturer_name_string",
|
||||||
|
0x2a29_u32,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"org.bluetooth.characteristic.maximum_recommended_heart_rate",
|
||||||
|
0x2a91_u32,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"org.bluetooth.characteristic.measurement_interval",
|
||||||
|
0x2a21_u32,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"org.bluetooth.characteristic.model_number_string",
|
||||||
|
0x2a24_u32,
|
||||||
|
),
|
||||||
("org.bluetooth.characteristic.navigation", 0x2a68_u32),
|
("org.bluetooth.characteristic.navigation", 0x2a68_u32),
|
||||||
("org.bluetooth.characteristic.new_alert", 0x2a46_u32),
|
("org.bluetooth.characteristic.new_alert", 0x2a46_u32),
|
||||||
("org.bluetooth.characteristic.object_action_control_point", 0x2ac5_u32),
|
(
|
||||||
|
"org.bluetooth.characteristic.object_action_control_point",
|
||||||
|
0x2ac5_u32,
|
||||||
|
),
|
||||||
("org.bluetooth.characteristic.object_changed", 0x2ac8_u32),
|
("org.bluetooth.characteristic.object_changed", 0x2ac8_u32),
|
||||||
("org.bluetooth.characteristic.object_first_created", 0x2ac1_u32),
|
(
|
||||||
|
"org.bluetooth.characteristic.object_first_created",
|
||||||
|
0x2ac1_u32,
|
||||||
|
),
|
||||||
("org.bluetooth.characteristic.object_id", 0x2ac3_u32),
|
("org.bluetooth.characteristic.object_id", 0x2ac3_u32),
|
||||||
("org.bluetooth.characteristic.object_last_modified", 0x2ac2_u32),
|
(
|
||||||
("org.bluetooth.characteristic.object_list_control_point", 0x2ac6_u32),
|
"org.bluetooth.characteristic.object_last_modified",
|
||||||
("org.bluetooth.characteristic.object_list_filter", 0x2ac7_u32),
|
0x2ac2_u32,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"org.bluetooth.characteristic.object_list_control_point",
|
||||||
|
0x2ac6_u32,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"org.bluetooth.characteristic.object_list_filter",
|
||||||
|
0x2ac7_u32,
|
||||||
|
),
|
||||||
("org.bluetooth.characteristic.object_name", 0x2abe_u32),
|
("org.bluetooth.characteristic.object_name", 0x2abe_u32),
|
||||||
("org.bluetooth.characteristic.object_properties", 0x2ac4_u32),
|
("org.bluetooth.characteristic.object_properties", 0x2ac4_u32),
|
||||||
("org.bluetooth.characteristic.object_size", 0x2ac0_u32),
|
("org.bluetooth.characteristic.object_size", 0x2ac0_u32),
|
||||||
("org.bluetooth.characteristic.object_type", 0x2abf_u32),
|
("org.bluetooth.characteristic.object_type", 0x2abf_u32),
|
||||||
("org.bluetooth.characteristic.ots_feature", 0x2abd_u32),
|
("org.bluetooth.characteristic.ots_feature", 0x2abd_u32),
|
||||||
("org.bluetooth.characteristic.gap.peripheral_preferred_connection_parameters", 0x2a04_u32),
|
(
|
||||||
("org.bluetooth.characteristic.gap.peripheral_privacy_flag", 0x2a02_u32),
|
"org.bluetooth.characteristic.gap.peripheral_preferred_connection_parameters",
|
||||||
("org.bluetooth.characteristic.plx_continuous_measurement", 0x2a5f_u32),
|
0x2a04_u32,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"org.bluetooth.characteristic.gap.peripheral_privacy_flag",
|
||||||
|
0x2a02_u32,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"org.bluetooth.characteristic.plx_continuous_measurement",
|
||||||
|
0x2a5f_u32,
|
||||||
|
),
|
||||||
("org.bluetooth.characteristic.plx_features", 0x2a60_u32),
|
("org.bluetooth.characteristic.plx_features", 0x2a60_u32),
|
||||||
("org.bluetooth.characteristic.plx_spot_check_measurement", 0x2a5e_u32),
|
(
|
||||||
|
"org.bluetooth.characteristic.plx_spot_check_measurement",
|
||||||
|
0x2a5e_u32,
|
||||||
|
),
|
||||||
("org.bluetooth.characteristic.pnp_id", 0x2a50_u32),
|
("org.bluetooth.characteristic.pnp_id", 0x2a50_u32),
|
||||||
("org.bluetooth.characteristic.pollen_concentration", 0x2a75_u32),
|
(
|
||||||
|
"org.bluetooth.characteristic.pollen_concentration",
|
||||||
|
0x2a75_u32,
|
||||||
|
),
|
||||||
("org.bluetooth.characteristic.position_quality", 0x2a69_u32),
|
("org.bluetooth.characteristic.position_quality", 0x2a69_u32),
|
||||||
("org.bluetooth.characteristic.pressure", 0x2a6d_u32),
|
("org.bluetooth.characteristic.pressure", 0x2a6d_u32),
|
||||||
("org.bluetooth.characteristic.protocol_mode", 0x2a4e_u32),
|
("org.bluetooth.characteristic.protocol_mode", 0x2a4e_u32),
|
||||||
("org.bluetooth.characteristic.rainfall", 0x2a78_u32),
|
("org.bluetooth.characteristic.rainfall", 0x2a78_u32),
|
||||||
("org.bluetooth.characteristic.gap.reconnection_address", 0x2a03_u32),
|
(
|
||||||
("org.bluetooth.characteristic.record_access_control_point", 0x2a52_u32),
|
"org.bluetooth.characteristic.gap.reconnection_address",
|
||||||
("org.bluetooth.characteristic.reference_time_information", 0x2a14_u32),
|
0x2a03_u32,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"org.bluetooth.characteristic.record_access_control_point",
|
||||||
|
0x2a52_u32,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"org.bluetooth.characteristic.reference_time_information",
|
||||||
|
0x2a14_u32,
|
||||||
|
),
|
||||||
("org.bluetooth.characteristic.report", 0x2a4d_u32),
|
("org.bluetooth.characteristic.report", 0x2a4d_u32),
|
||||||
("org.bluetooth.characteristic.report_map", 0x2a4b_u32),
|
("org.bluetooth.characteristic.report_map", 0x2a4b_u32),
|
||||||
("org.bluetooth.characteristic.resting_heart_rate", 0x2a92_u32),
|
(
|
||||||
("org.bluetooth.characteristic.ringer_control_point", 0x2a40_u32),
|
"org.bluetooth.characteristic.resting_heart_rate",
|
||||||
|
0x2a92_u32,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"org.bluetooth.characteristic.ringer_control_point",
|
||||||
|
0x2a40_u32,
|
||||||
|
),
|
||||||
("org.bluetooth.characteristic.ringer_setting", 0x2a41_u32),
|
("org.bluetooth.characteristic.ringer_setting", 0x2a41_u32),
|
||||||
("org.bluetooth.characteristic.rsc_feature", 0x2a54_u32),
|
("org.bluetooth.characteristic.rsc_feature", 0x2a54_u32),
|
||||||
("org.bluetooth.characteristic.rsc_measurement", 0x2a53_u32),
|
("org.bluetooth.characteristic.rsc_measurement", 0x2a53_u32),
|
||||||
("org.bluetooth.characteristic.sc_control_point", 0x2a55_u32),
|
("org.bluetooth.characteristic.sc_control_point", 0x2a55_u32),
|
||||||
("org.bluetooth.characteristic.scan_interval_window", 0x2a4f_u32),
|
(
|
||||||
|
"org.bluetooth.characteristic.scan_interval_window",
|
||||||
|
0x2a4f_u32,
|
||||||
|
),
|
||||||
("org.bluetooth.characteristic.scan_refresh", 0x2a31_u32),
|
("org.bluetooth.characteristic.scan_refresh", 0x2a31_u32),
|
||||||
("org.bluetooth.characteristic.sensor_location", 0x2a5d_u32),
|
("org.bluetooth.characteristic.sensor_location", 0x2a5d_u32),
|
||||||
("org.bluetooth.characteristic.serial_number_string", 0x2a25_u32),
|
(
|
||||||
("org.bluetooth.characteristic.gatt.service_changed", 0x2a05_u32),
|
"org.bluetooth.characteristic.serial_number_string",
|
||||||
("org.bluetooth.characteristic.software_revision_string", 0x2a28_u32),
|
0x2a25_u32,
|
||||||
("org.bluetooth.characteristic.sport_type_for_aerobic_and_anaerobic_thresholds", 0x2a93_u32),
|
),
|
||||||
("org.bluetooth.characteristic.supported_new_alert_category", 0x2a47_u32),
|
(
|
||||||
("org.bluetooth.characteristic.supported_unread_alert_category", 0x2a48_u32),
|
"org.bluetooth.characteristic.gatt.service_changed",
|
||||||
|
0x2a05_u32,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"org.bluetooth.characteristic.software_revision_string",
|
||||||
|
0x2a28_u32,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"org.bluetooth.characteristic.sport_type_for_aerobic_and_anaerobic_thresholds",
|
||||||
|
0x2a93_u32,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"org.bluetooth.characteristic.supported_new_alert_category",
|
||||||
|
0x2a47_u32,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"org.bluetooth.characteristic.supported_unread_alert_category",
|
||||||
|
0x2a48_u32,
|
||||||
|
),
|
||||||
("org.bluetooth.characteristic.system_id", 0x2a23_u32),
|
("org.bluetooth.characteristic.system_id", 0x2a23_u32),
|
||||||
("org.bluetooth.characteristic.tds_control_point", 0x2abc_u32),
|
("org.bluetooth.characteristic.tds_control_point", 0x2abc_u32),
|
||||||
("org.bluetooth.characteristic.temperature", 0x2a6e_u32),
|
("org.bluetooth.characteristic.temperature", 0x2a6e_u32),
|
||||||
("org.bluetooth.characteristic.temperature_measurement", 0x2a1c_u32),
|
(
|
||||||
|
"org.bluetooth.characteristic.temperature_measurement",
|
||||||
|
0x2a1c_u32,
|
||||||
|
),
|
||||||
("org.bluetooth.characteristic.temperature_type", 0x2a1d_u32),
|
("org.bluetooth.characteristic.temperature_type", 0x2a1d_u32),
|
||||||
("org.bluetooth.characteristic.three_zone_heart_rate_limits", 0x2a94_u32),
|
(
|
||||||
|
"org.bluetooth.characteristic.three_zone_heart_rate_limits",
|
||||||
|
0x2a94_u32,
|
||||||
|
),
|
||||||
("org.bluetooth.characteristic.time_accuracy", 0x2a12_u32),
|
("org.bluetooth.characteristic.time_accuracy", 0x2a12_u32),
|
||||||
("org.bluetooth.characteristic.time_source", 0x2a13_u32),
|
("org.bluetooth.characteristic.time_source", 0x2a13_u32),
|
||||||
("org.bluetooth.characteristic.time_update_control_point", 0x2a16_u32),
|
(
|
||||||
|
"org.bluetooth.characteristic.time_update_control_point",
|
||||||
|
0x2a16_u32,
|
||||||
|
),
|
||||||
("org.bluetooth.characteristic.time_update_state", 0x2a17_u32),
|
("org.bluetooth.characteristic.time_update_state", 0x2a17_u32),
|
||||||
("org.bluetooth.characteristic.time_with_dst", 0x2a11_u32),
|
("org.bluetooth.characteristic.time_with_dst", 0x2a11_u32),
|
||||||
("org.bluetooth.characteristic.time_zone", 0x2a0e_u32),
|
("org.bluetooth.characteristic.time_zone", 0x2a0e_u32),
|
||||||
("org.bluetooth.characteristic.true_wind_direction", 0x2a71_u32),
|
(
|
||||||
|
"org.bluetooth.characteristic.true_wind_direction",
|
||||||
|
0x2a71_u32,
|
||||||
|
),
|
||||||
("org.bluetooth.characteristic.true_wind_speed", 0x2a70_u32),
|
("org.bluetooth.characteristic.true_wind_speed", 0x2a70_u32),
|
||||||
("org.bluetooth.characteristic.two_zone_heart_rate_limit", 0x2a95_u32),
|
(
|
||||||
|
"org.bluetooth.characteristic.two_zone_heart_rate_limit",
|
||||||
|
0x2a95_u32,
|
||||||
|
),
|
||||||
("org.bluetooth.characteristic.tx_power_level", 0x2a07_u32),
|
("org.bluetooth.characteristic.tx_power_level", 0x2a07_u32),
|
||||||
("org.bluetooth.characteristic.uncertainty", 0x2ab4_u32),
|
("org.bluetooth.characteristic.uncertainty", 0x2ab4_u32),
|
||||||
("org.bluetooth.characteristic.unread_alert_status", 0x2a45_u32),
|
(
|
||||||
|
"org.bluetooth.characteristic.unread_alert_status",
|
||||||
|
0x2a45_u32,
|
||||||
|
),
|
||||||
("org.bluetooth.characteristic.uri", 0x2ab6_u32),
|
("org.bluetooth.characteristic.uri", 0x2ab6_u32),
|
||||||
("org.bluetooth.characteristic.user_control_point", 0x2a9f_u32),
|
(
|
||||||
|
"org.bluetooth.characteristic.user_control_point",
|
||||||
|
0x2a9f_u32,
|
||||||
|
),
|
||||||
("org.bluetooth.characteristic.user_index", 0x2a9a_u32),
|
("org.bluetooth.characteristic.user_index", 0x2a9a_u32),
|
||||||
("org.bluetooth.characteristic.uv_index", 0x2a76_u32),
|
("org.bluetooth.characteristic.uv_index", 0x2a76_u32),
|
||||||
("org.bluetooth.characteristic.vo2_max", 0x2a96_u32),
|
("org.bluetooth.characteristic.vo2_max", 0x2a96_u32),
|
||||||
("org.bluetooth.characteristic.waist_circumference", 0x2a97_u32),
|
(
|
||||||
|
"org.bluetooth.characteristic.waist_circumference",
|
||||||
|
0x2a97_u32,
|
||||||
|
),
|
||||||
("org.bluetooth.characteristic.weight", 0x2a98_u32),
|
("org.bluetooth.characteristic.weight", 0x2a98_u32),
|
||||||
("org.bluetooth.characteristic.weight_measurement", 0x2a9d_u32),
|
(
|
||||||
("org.bluetooth.characteristic.weight_scale_feature", 0x2a9e_u32),
|
"org.bluetooth.characteristic.weight_measurement",
|
||||||
|
0x2a9d_u32,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"org.bluetooth.characteristic.weight_scale_feature",
|
||||||
|
0x2a9e_u32,
|
||||||
|
),
|
||||||
("org.bluetooth.characteristic.wind_chill", 0x2a79_u32),
|
("org.bluetooth.characteristic.wind_chill", 0x2a79_u32),
|
||||||
];
|
];
|
||||||
|
|
||||||
//https://developer.bluetooth.org/gatt/services/Pages/ServicesHome.aspx
|
//https://developer.bluetooth.org/gatt/services/Pages/ServicesHome.aspx
|
||||||
const BLUETOOTH_ASSIGNED_DESCRIPTORS: &'static [(&'static str, u32)] = &[
|
const BLUETOOTH_ASSIGNED_DESCRIPTORS: &'static [(&'static str, u32)] = &[
|
||||||
("org.bluetooth.descriptor.gatt.characteristic_extended_properties", 0x2900_u32),
|
(
|
||||||
("org.bluetooth.descriptor.gatt.characteristic_user_description", 0x2901_u32),
|
"org.bluetooth.descriptor.gatt.characteristic_extended_properties",
|
||||||
("org.bluetooth.descriptor.gatt.client_characteristic_configuration", 0x2902_u32),
|
0x2900_u32,
|
||||||
("org.bluetooth.descriptor.gatt.server_characteristic_configuration", 0x2903_u32),
|
),
|
||||||
("org.bluetooth.descriptor.gatt.characteristic_presentation_format", 0x2904_u32),
|
(
|
||||||
("org.bluetooth.descriptor.gatt.characteristic_aggregate_format", 0x2905_u32),
|
"org.bluetooth.descriptor.gatt.characteristic_user_description",
|
||||||
|
0x2901_u32,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"org.bluetooth.descriptor.gatt.client_characteristic_configuration",
|
||||||
|
0x2902_u32,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"org.bluetooth.descriptor.gatt.server_characteristic_configuration",
|
||||||
|
0x2903_u32,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"org.bluetooth.descriptor.gatt.characteristic_presentation_format",
|
||||||
|
0x2904_u32,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"org.bluetooth.descriptor.gatt.characteristic_aggregate_format",
|
||||||
|
0x2905_u32,
|
||||||
|
),
|
||||||
("org.bluetooth.descriptor.valid_range", 0x2906_u32),
|
("org.bluetooth.descriptor.valid_range", 0x2906_u32),
|
||||||
("org.bluetooth.descriptor.external_report_reference", 0x2907_u32),
|
(
|
||||||
|
"org.bluetooth.descriptor.external_report_reference",
|
||||||
|
0x2907_u32,
|
||||||
|
),
|
||||||
("org.bluetooth.descriptor.report_reference", 0x2908_u32),
|
("org.bluetooth.descriptor.report_reference", 0x2908_u32),
|
||||||
("org.bluetooth.descriptor.number_of_digitals", 0x2909_u32),
|
("org.bluetooth.descriptor.number_of_digitals", 0x2909_u32),
|
||||||
("org.bluetooth.descriptor.value_trigger_setting", 0x290a_u32),
|
("org.bluetooth.descriptor.value_trigger_setting", 0x290a_u32),
|
||||||
|
@ -268,18 +565,22 @@ const BASE_UUID: &'static str = "-0000-1000-8000-00805f9b34fb";
|
||||||
const SERVICE_PREFIX: &'static str = "org.bluetooth.service";
|
const SERVICE_PREFIX: &'static str = "org.bluetooth.service";
|
||||||
const CHARACTERISTIC_PREFIX: &'static str = "org.bluetooth.characteristic";
|
const CHARACTERISTIC_PREFIX: &'static str = "org.bluetooth.characteristic";
|
||||||
const DESCRIPTOR_PREFIX: &'static str = "org.bluetooth.descriptor";
|
const DESCRIPTOR_PREFIX: &'static str = "org.bluetooth.descriptor";
|
||||||
const VALID_UUID_REGEX: &'static str = "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$";
|
const VALID_UUID_REGEX: &'static str =
|
||||||
|
"^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$";
|
||||||
// https://cs.chromium.org/chromium/src/third_party/WebKit/Source/modules/bluetooth/BluetoothUUID.cpp?l=314
|
// https://cs.chromium.org/chromium/src/third_party/WebKit/Source/modules/bluetooth/BluetoothUUID.cpp?l=314
|
||||||
const UUID_ERROR_MESSAGE: &'static str = "It must be a valid UUID alias (e.g. 0x1234), \
|
const UUID_ERROR_MESSAGE: &'static str = "It must be a valid UUID alias (e.g. 0x1234), \
|
||||||
UUID (lowercase hex characters e.g. '00001234-0000-1000-8000-00805f9b34fb'),\nor recognized standard name from";
|
UUID (lowercase hex characters e.g. '00001234-0000-1000-8000-00805f9b34fb'),\nor recognized standard name from";
|
||||||
// https://cs.chromium.org/chromium/src/third_party/WebKit/Source/modules/bluetooth/BluetoothUUID.cpp?l=321
|
// https://cs.chromium.org/chromium/src/third_party/WebKit/Source/modules/bluetooth/BluetoothUUID.cpp?l=321
|
||||||
const SERVICES_ERROR_MESSAGE: &'static str = "https://developer.bluetooth.org/gatt/services/Pages/ServicesHome.aspx\
|
const SERVICES_ERROR_MESSAGE: &'static str =
|
||||||
|
"https://developer.bluetooth.org/gatt/services/Pages/ServicesHome.aspx\
|
||||||
\ne.g. 'alert_notification'.";
|
\ne.g. 'alert_notification'.";
|
||||||
// https://cs.chromium.org/chromium/src/third_party/WebKit/Source/modules/bluetooth/BluetoothUUID.cpp?l=327
|
// https://cs.chromium.org/chromium/src/third_party/WebKit/Source/modules/bluetooth/BluetoothUUID.cpp?l=327
|
||||||
const CHARACTERISTIC_ERROR_MESSAGE: &'static str = "https://developer.bluetooth.org/gatt/characteristics/Pages/\
|
const CHARACTERISTIC_ERROR_MESSAGE: &'static str =
|
||||||
|
"https://developer.bluetooth.org/gatt/characteristics/Pages/\
|
||||||
CharacteristicsHome.aspx\ne.g. 'aerobic_heart_rate_lower_limit'.";
|
CharacteristicsHome.aspx\ne.g. 'aerobic_heart_rate_lower_limit'.";
|
||||||
// https://cs.chromium.org/chromium/src/third_party/WebKit/Source/modules/bluetooth/BluetoothUUID.cpp?l=333
|
// https://cs.chromium.org/chromium/src/third_party/WebKit/Source/modules/bluetooth/BluetoothUUID.cpp?l=333
|
||||||
const DESCRIPTOR_ERROR_MESSAGE: &'static str = "https://developer.bluetooth.org/gatt/descriptors/Pages/\
|
const DESCRIPTOR_ERROR_MESSAGE: &'static str =
|
||||||
|
"https://developer.bluetooth.org/gatt/descriptors/Pages/\
|
||||||
DescriptorsHomePage.aspx\ne.g. 'gatt.characteristic_presentation_format'.";
|
DescriptorsHomePage.aspx\ne.g. 'gatt.characteristic_presentation_format'.";
|
||||||
|
|
||||||
impl BluetoothUUID {
|
impl BluetoothUUID {
|
||||||
|
@ -310,7 +611,11 @@ impl BluetoothUUID {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn characteristic(name: BluetoothCharacteristicUUID) -> Fallible<UUID> {
|
pub fn characteristic(name: BluetoothCharacteristicUUID) -> Fallible<UUID> {
|
||||||
resolve_uuid_name(name, BLUETOOTH_ASSIGNED_CHARCTERISTICS, CHARACTERISTIC_PREFIX)
|
resolve_uuid_name(
|
||||||
|
name,
|
||||||
|
BLUETOOTH_ASSIGNED_CHARCTERISTICS,
|
||||||
|
CHARACTERISTIC_PREFIX,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn descriptor(name: BluetoothDescriptorUUID) -> Fallible<UUID> {
|
pub fn descriptor(name: BluetoothDescriptorUUID) -> Fallible<UUID> {
|
||||||
|
@ -335,13 +640,11 @@ fn canonical_uuid(alias: u32) -> UUID {
|
||||||
fn resolve_uuid_name(
|
fn resolve_uuid_name(
|
||||||
name: StringOrUnsignedLong,
|
name: StringOrUnsignedLong,
|
||||||
assigned_numbers_table: &'static [(&'static str, u32)],
|
assigned_numbers_table: &'static [(&'static str, u32)],
|
||||||
prefix: &str)
|
prefix: &str,
|
||||||
-> Fallible<DOMString> {
|
) -> Fallible<DOMString> {
|
||||||
match name {
|
match name {
|
||||||
// Step 1.
|
// Step 1.
|
||||||
StringOrUnsignedLong::UnsignedLong(unsigned32) => {
|
StringOrUnsignedLong::UnsignedLong(unsigned32) => Ok(canonical_uuid(unsigned32)),
|
||||||
Ok(canonical_uuid(unsigned32))
|
|
||||||
},
|
|
||||||
StringOrUnsignedLong::String(dstring) => {
|
StringOrUnsignedLong::String(dstring) => {
|
||||||
// Step 2.
|
// Step 2.
|
||||||
let regex = Regex::new(VALID_UUID_REGEX).unwrap();
|
let regex = Regex::new(VALID_UUID_REGEX).unwrap();
|
||||||
|
@ -356,16 +659,17 @@ fn resolve_uuid_name(
|
||||||
None => {
|
None => {
|
||||||
let (attribute_type, error_url_message) = match prefix {
|
let (attribute_type, error_url_message) = match prefix {
|
||||||
SERVICE_PREFIX => ("Service", SERVICES_ERROR_MESSAGE),
|
SERVICE_PREFIX => ("Service", SERVICES_ERROR_MESSAGE),
|
||||||
CHARACTERISTIC_PREFIX => ("Characteristic", CHARACTERISTIC_ERROR_MESSAGE),
|
CHARACTERISTIC_PREFIX => {
|
||||||
|
("Characteristic", CHARACTERISTIC_ERROR_MESSAGE)
|
||||||
|
},
|
||||||
DESCRIPTOR_PREFIX => ("Descriptor", DESCRIPTOR_ERROR_MESSAGE),
|
DESCRIPTOR_PREFIX => ("Descriptor", DESCRIPTOR_ERROR_MESSAGE),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
// Step 4.
|
// Step 4.
|
||||||
return Err(Type(format!("Invalid {} name : '{}'.\n{} {}",
|
return Err(Type(format!(
|
||||||
attribute_type,
|
"Invalid {} name : '{}'.\n{} {}",
|
||||||
dstring,
|
attribute_type, dstring, UUID_ERROR_MESSAGE, error_url_message
|
||||||
UUID_ERROR_MESSAGE,
|
)));
|
||||||
error_url_message)));
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,9 +40,11 @@ impl CanvasGradient {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(global: &GlobalScope, style: CanvasGradientStyle) -> DomRoot<CanvasGradient> {
|
pub fn new(global: &GlobalScope, style: CanvasGradientStyle) -> DomRoot<CanvasGradient> {
|
||||||
reflect_dom_object(Box::new(CanvasGradient::new_inherited(style)),
|
reflect_dom_object(
|
||||||
|
Box::new(CanvasGradient::new_inherited(style)),
|
||||||
global,
|
global,
|
||||||
CanvasGradientBinding::Wrap)
|
CanvasGradientBinding::Wrap,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,10 +62,10 @@ impl CanvasGradientMethods for CanvasGradient {
|
||||||
match color {
|
match color {
|
||||||
Ok(CSSColor::RGBA(rgba)) => rgba,
|
Ok(CSSColor::RGBA(rgba)) => rgba,
|
||||||
Ok(CSSColor::CurrentColor) => RGBA::new(0, 0, 0, 255),
|
Ok(CSSColor::CurrentColor) => RGBA::new(0, 0, 0, 255),
|
||||||
_ => return Err(Error::Syntax)
|
_ => return Err(Error::Syntax),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(Error::Syntax)
|
return Err(Error::Syntax);
|
||||||
};
|
};
|
||||||
|
|
||||||
self.stops.borrow_mut().push(CanvasGradientStop {
|
self.stops.borrow_mut().push(CanvasGradientStop {
|
||||||
|
@ -83,21 +85,25 @@ impl<'a> ToFillOrStrokeStyle for &'a CanvasGradient {
|
||||||
let gradient_stops = self.stops.borrow().clone();
|
let gradient_stops = self.stops.borrow().clone();
|
||||||
match self.style {
|
match self.style {
|
||||||
CanvasGradientStyle::Linear(ref gradient) => {
|
CanvasGradientStyle::Linear(ref gradient) => {
|
||||||
FillOrStrokeStyle::LinearGradient(LinearGradientStyle::new(gradient.x0,
|
FillOrStrokeStyle::LinearGradient(LinearGradientStyle::new(
|
||||||
|
gradient.x0,
|
||||||
gradient.y0,
|
gradient.y0,
|
||||||
gradient.x1,
|
gradient.x1,
|
||||||
gradient.y1,
|
gradient.y1,
|
||||||
gradient_stops))
|
gradient_stops,
|
||||||
}
|
))
|
||||||
|
},
|
||||||
CanvasGradientStyle::Radial(ref gradient) => {
|
CanvasGradientStyle::Radial(ref gradient) => {
|
||||||
FillOrStrokeStyle::RadialGradient(RadialGradientStyle::new(gradient.x0,
|
FillOrStrokeStyle::RadialGradient(RadialGradientStyle::new(
|
||||||
|
gradient.x0,
|
||||||
gradient.y0,
|
gradient.y0,
|
||||||
gradient.r0,
|
gradient.r0,
|
||||||
gradient.x1,
|
gradient.x1,
|
||||||
gradient.y1,
|
gradient.y1,
|
||||||
gradient.r1,
|
gradient.r1,
|
||||||
gradient_stops))
|
gradient_stops,
|
||||||
}
|
))
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,11 +23,12 @@ pub struct CanvasPattern {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CanvasPattern {
|
impl CanvasPattern {
|
||||||
fn new_inherited(surface_data: Vec<u8>,
|
fn new_inherited(
|
||||||
|
surface_data: Vec<u8>,
|
||||||
surface_size: Size2D<i32>,
|
surface_size: Size2D<i32>,
|
||||||
repeat: RepetitionStyle,
|
repeat: RepetitionStyle,
|
||||||
origin_clean: bool)
|
origin_clean: bool,
|
||||||
-> CanvasPattern {
|
) -> CanvasPattern {
|
||||||
let (x, y) = match repeat {
|
let (x, y) = match repeat {
|
||||||
RepetitionStyle::Repeat => (true, true),
|
RepetitionStyle::Repeat => (true, true),
|
||||||
RepetitionStyle::RepeatX => (true, false),
|
RepetitionStyle::RepeatX => (true, false),
|
||||||
|
@ -44,18 +45,22 @@ impl CanvasPattern {
|
||||||
origin_clean: origin_clean,
|
origin_clean: origin_clean,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn new(global: &GlobalScope,
|
pub fn new(
|
||||||
|
global: &GlobalScope,
|
||||||
surface_data: Vec<u8>,
|
surface_data: Vec<u8>,
|
||||||
surface_size: Size2D<i32>,
|
surface_size: Size2D<i32>,
|
||||||
repeat: RepetitionStyle,
|
repeat: RepetitionStyle,
|
||||||
origin_clean: bool)
|
origin_clean: bool,
|
||||||
-> DomRoot<CanvasPattern> {
|
) -> DomRoot<CanvasPattern> {
|
||||||
reflect_dom_object(
|
reflect_dom_object(
|
||||||
Box::new(CanvasPattern::new_inherited(
|
Box::new(CanvasPattern::new_inherited(
|
||||||
surface_data, surface_size, repeat, origin_clean
|
surface_data,
|
||||||
|
surface_size,
|
||||||
|
repeat,
|
||||||
|
origin_clean,
|
||||||
)),
|
)),
|
||||||
global,
|
global,
|
||||||
CanvasPatternBinding::Wrap
|
CanvasPatternBinding::Wrap,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
pub fn origin_is_clean(&self) -> bool {
|
pub fn origin_is_clean(&self) -> bool {
|
||||||
|
@ -65,9 +70,11 @@ impl CanvasPattern {
|
||||||
|
|
||||||
impl<'a> ToFillOrStrokeStyle for &'a CanvasPattern {
|
impl<'a> ToFillOrStrokeStyle for &'a CanvasPattern {
|
||||||
fn to_fill_or_stroke_style(self) -> FillOrStrokeStyle {
|
fn to_fill_or_stroke_style(self) -> FillOrStrokeStyle {
|
||||||
FillOrStrokeStyle::Surface(SurfaceStyle::new(self.surface_data.clone(),
|
FillOrStrokeStyle::Surface(SurfaceStyle::new(
|
||||||
|
self.surface_data.clone(),
|
||||||
self.surface_size,
|
self.surface_size,
|
||||||
self.repeat_x,
|
self.repeat_x,
|
||||||
self.repeat_y))
|
self.repeat_y,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -123,17 +123,21 @@ impl CanvasContextState {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CanvasRenderingContext2D {
|
impl CanvasRenderingContext2D {
|
||||||
pub fn new_inherited(global: &GlobalScope,
|
pub fn new_inherited(
|
||||||
|
global: &GlobalScope,
|
||||||
canvas: Option<&HTMLCanvasElement>,
|
canvas: Option<&HTMLCanvasElement>,
|
||||||
image_cache: Arc<ImageCache>,
|
image_cache: Arc<ImageCache>,
|
||||||
base_url: ServoUrl,
|
base_url: ServoUrl,
|
||||||
size: Size2D<i32>)
|
size: Size2D<i32>,
|
||||||
-> CanvasRenderingContext2D {
|
) -> CanvasRenderingContext2D {
|
||||||
debug!("Creating new canvas rendering context.");
|
debug!("Creating new canvas rendering context.");
|
||||||
let (sender, receiver) = profiled_ipc::channel(global.time_profiler_chan().clone()).unwrap();
|
let (sender, receiver) =
|
||||||
|
profiled_ipc::channel(global.time_profiler_chan().clone()).unwrap();
|
||||||
let script_to_constellation_chan = global.script_to_constellation_chan();
|
let script_to_constellation_chan = global.script_to_constellation_chan();
|
||||||
debug!("Asking constellation to create new canvas thread.");
|
debug!("Asking constellation to create new canvas thread.");
|
||||||
script_to_constellation_chan.send(ScriptMsg::CreateCanvasPaintThread(size, sender)).unwrap();
|
script_to_constellation_chan
|
||||||
|
.send(ScriptMsg::CreateCanvasPaintThread(size, sender))
|
||||||
|
.unwrap();
|
||||||
let (ipc_renderer, canvas_id) = receiver.recv().unwrap();
|
let (ipc_renderer, canvas_id) = receiver.recv().unwrap();
|
||||||
debug!("Done.");
|
debug!("Done.");
|
||||||
CanvasRenderingContext2D {
|
CanvasRenderingContext2D {
|
||||||
|
@ -150,15 +154,20 @@ impl CanvasRenderingContext2D {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(global: &GlobalScope,
|
pub fn new(
|
||||||
|
global: &GlobalScope,
|
||||||
canvas: &HTMLCanvasElement,
|
canvas: &HTMLCanvasElement,
|
||||||
size: Size2D<i32>)
|
size: Size2D<i32>,
|
||||||
-> DomRoot<CanvasRenderingContext2D> {
|
) -> DomRoot<CanvasRenderingContext2D> {
|
||||||
let window = window_from_node(canvas);
|
let window = window_from_node(canvas);
|
||||||
let image_cache = window.image_cache();
|
let image_cache = window.image_cache();
|
||||||
let base_url = window.get_url();
|
let base_url = window.get_url();
|
||||||
let boxed = Box::new(CanvasRenderingContext2D::new_inherited(
|
let boxed = Box::new(CanvasRenderingContext2D::new_inherited(
|
||||||
global, Some(canvas), image_cache, base_url, size
|
global,
|
||||||
|
Some(canvas),
|
||||||
|
image_cache,
|
||||||
|
base_url,
|
||||||
|
size,
|
||||||
));
|
));
|
||||||
reflect_dom_object(boxed, global, CanvasRenderingContext2DBinding::Wrap)
|
reflect_dom_object(boxed, global, CanvasRenderingContext2DBinding::Wrap)
|
||||||
}
|
}
|
||||||
|
@ -191,7 +200,8 @@ impl CanvasRenderingContext2D {
|
||||||
// on the drawImage call arguments
|
// on the drawImage call arguments
|
||||||
// source rectangle = area of the original image to be copied
|
// source rectangle = area of the original image to be copied
|
||||||
// destination rectangle = area of the destination canvas where the source image is going to be drawn
|
// destination rectangle = area of the destination canvas where the source image is going to be drawn
|
||||||
fn adjust_source_dest_rects(&self,
|
fn adjust_source_dest_rects(
|
||||||
|
&self,
|
||||||
image_size: Size2D<f64>,
|
image_size: Size2D<f64>,
|
||||||
sx: f64,
|
sx: f64,
|
||||||
sy: f64,
|
sy: f64,
|
||||||
|
@ -200,19 +210,25 @@ impl CanvasRenderingContext2D {
|
||||||
dx: f64,
|
dx: f64,
|
||||||
dy: f64,
|
dy: f64,
|
||||||
dw: f64,
|
dw: f64,
|
||||||
dh: f64)
|
dh: f64,
|
||||||
-> (Rect<f64>, Rect<f64>) {
|
) -> (Rect<f64>, Rect<f64>) {
|
||||||
let image_rect = Rect::new(Point2D::new(0f64, 0f64),
|
let image_rect = Rect::new(
|
||||||
Size2D::new(image_size.width as f64, image_size.height as f64));
|
Point2D::new(0f64, 0f64),
|
||||||
|
Size2D::new(image_size.width as f64, image_size.height as f64),
|
||||||
|
);
|
||||||
|
|
||||||
// The source rectangle is the rectangle whose corners are the four points (sx, sy),
|
// The source rectangle is the rectangle whose corners are the four points (sx, sy),
|
||||||
// (sx+sw, sy), (sx+sw, sy+sh), (sx, sy+sh).
|
// (sx+sw, sy), (sx+sw, sy+sh), (sx, sy+sh).
|
||||||
let source_rect = Rect::new(Point2D::new(sx.min(sx + sw), sy.min(sy + sh)),
|
let source_rect = Rect::new(
|
||||||
Size2D::new(sw.abs(), sh.abs()));
|
Point2D::new(sx.min(sx + sw), sy.min(sy + sh)),
|
||||||
|
Size2D::new(sw.abs(), sh.abs()),
|
||||||
|
);
|
||||||
|
|
||||||
// When the source rectangle is outside the source image,
|
// When the source rectangle is outside the source image,
|
||||||
// the source rectangle must be clipped to the source image
|
// the source rectangle must be clipped to the source image
|
||||||
let source_rect_clipped = source_rect.intersection(&image_rect).unwrap_or(Rect::zero());
|
let source_rect_clipped = source_rect
|
||||||
|
.intersection(&image_rect)
|
||||||
|
.unwrap_or(Rect::zero());
|
||||||
|
|
||||||
// Width and height ratios between the non clipped and clipped source rectangles
|
// Width and height ratios between the non clipped and clipped source rectangles
|
||||||
let width_ratio: f64 = source_rect_clipped.size.width / source_rect.size.width;
|
let width_ratio: f64 = source_rect_clipped.size.width / source_rect.size.width;
|
||||||
|
@ -225,27 +241,29 @@ impl CanvasRenderingContext2D {
|
||||||
|
|
||||||
// The destination rectangle is the rectangle whose corners are the four points (dx, dy),
|
// The destination rectangle is the rectangle whose corners are the four points (dx, dy),
|
||||||
// (dx+dw, dy), (dx+dw, dy+dh), (dx, dy+dh).
|
// (dx+dw, dy), (dx+dw, dy+dh), (dx, dy+dh).
|
||||||
let dest_rect = Rect::new(Point2D::new(dx.min(dx + dest_rect_width_scaled),
|
let dest_rect = Rect::new(
|
||||||
dy.min(dy + dest_rect_height_scaled)),
|
Point2D::new(
|
||||||
Size2D::new(dest_rect_width_scaled.abs(),
|
dx.min(dx + dest_rect_width_scaled),
|
||||||
dest_rect_height_scaled.abs()));
|
dy.min(dy + dest_rect_height_scaled),
|
||||||
|
),
|
||||||
|
Size2D::new(dest_rect_width_scaled.abs(), dest_rect_height_scaled.abs()),
|
||||||
|
);
|
||||||
|
|
||||||
let source_rect = Rect::new(Point2D::new(source_rect_clipped.origin.x,
|
let source_rect = Rect::new(
|
||||||
source_rect_clipped.origin.y),
|
Point2D::new(source_rect_clipped.origin.x, source_rect_clipped.origin.y),
|
||||||
Size2D::new(source_rect_clipped.size.width,
|
Size2D::new(
|
||||||
source_rect_clipped.size.height));
|
source_rect_clipped.size.width,
|
||||||
|
source_rect_clipped.size.height,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
(source_rect, dest_rect)
|
(source_rect, dest_rect)
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#the-image-argument-is-not-origin-clean
|
// https://html.spec.whatwg.org/multipage/#the-image-argument-is-not-origin-clean
|
||||||
fn is_origin_clean(&self,
|
fn is_origin_clean(&self, image: CanvasImageSource) -> bool {
|
||||||
image: CanvasImageSource)
|
|
||||||
-> bool {
|
|
||||||
match image {
|
match image {
|
||||||
CanvasImageSource::HTMLCanvasElement(canvas) => {
|
CanvasImageSource::HTMLCanvasElement(canvas) => canvas.origin_is_clean(),
|
||||||
canvas.origin_is_clean()
|
|
||||||
}
|
|
||||||
CanvasImageSource::HTMLImageElement(image) => {
|
CanvasImageSource::HTMLImageElement(image) => {
|
||||||
image.same_origin(GlobalScope::entry().origin())
|
image.same_origin(GlobalScope::entry().origin())
|
||||||
}
|
}
|
||||||
|
@ -274,7 +292,8 @@ impl CanvasRenderingContext2D {
|
||||||
// is copied on the rectangle (dx, dy, dh, dw) of the destination canvas
|
// is copied on the rectangle (dx, dy, dh, dw) of the destination canvas
|
||||||
//
|
//
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-drawimage
|
// https://html.spec.whatwg.org/multipage/#dom-context-2d-drawimage
|
||||||
fn draw_image(&self,
|
fn draw_image(
|
||||||
|
&self,
|
||||||
image: CanvasImageSource,
|
image: CanvasImageSource,
|
||||||
sx: f64,
|
sx: f64,
|
||||||
sy: f64,
|
sy: f64,
|
||||||
|
@ -283,29 +302,25 @@ impl CanvasRenderingContext2D {
|
||||||
dx: f64,
|
dx: f64,
|
||||||
dy: f64,
|
dy: f64,
|
||||||
dw: Option<f64>,
|
dw: Option<f64>,
|
||||||
dh: Option<f64>)
|
dh: Option<f64>,
|
||||||
-> ErrorResult {
|
) -> ErrorResult {
|
||||||
let result = match image {
|
let result = match image {
|
||||||
CanvasImageSource::HTMLCanvasElement(ref canvas) => {
|
CanvasImageSource::HTMLCanvasElement(ref canvas) => {
|
||||||
self.draw_html_canvas_element(&canvas,
|
self.draw_html_canvas_element(&canvas, sx, sy, sw, sh, dx, dy, dw, dh)
|
||||||
sx, sy, sw, sh,
|
},
|
||||||
dx, dy, dw, dh)
|
|
||||||
}
|
|
||||||
CanvasImageSource::HTMLImageElement(ref image) => {
|
CanvasImageSource::HTMLImageElement(ref image) => {
|
||||||
// https://html.spec.whatwg.org/multipage/#img-error
|
// https://html.spec.whatwg.org/multipage/#img-error
|
||||||
// If the image argument is an HTMLImageElement object that is in the broken state,
|
// If the image argument is an HTMLImageElement object that is in the broken state,
|
||||||
// then throw an InvalidStateError exception
|
// then throw an InvalidStateError exception
|
||||||
let url = image.get_url().ok_or(Error::InvalidState)?;
|
let url = image.get_url().ok_or(Error::InvalidState)?;
|
||||||
self.fetch_and_draw_image_data(url,
|
self.fetch_and_draw_image_data(url, sx, sy, sw, sh, dx, dy, dw, dh)
|
||||||
sx, sy, sw, sh,
|
},
|
||||||
dx, dy, dw, dh)
|
|
||||||
}
|
|
||||||
CanvasImageSource::CSSStyleValue(ref value) => {
|
CanvasImageSource::CSSStyleValue(ref value) => {
|
||||||
let url = value.get_url(self.base_url.clone()).ok_or(Error::InvalidState)?;
|
let url = value
|
||||||
self.fetch_and_draw_image_data(url,
|
.get_url(self.base_url.clone())
|
||||||
sx, sy, sw, sh,
|
.ok_or(Error::InvalidState)?;
|
||||||
dx, dy, dw, dh)
|
self.fetch_and_draw_image_data(url, sx, sy, sw, sh, dx, dy, dw, dh)
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
if result.is_ok() && !self.is_origin_clean(image) {
|
if result.is_ok() && !self.is_origin_clean(image) {
|
||||||
|
@ -339,17 +354,8 @@ impl CanvasRenderingContext2D {
|
||||||
|
|
||||||
let image_size = Size2D::new(canvas_size.width as f64, canvas_size.height as f64);
|
let image_size = Size2D::new(canvas_size.width as f64, canvas_size.height as f64);
|
||||||
// 2. Establish the source and destination rectangles
|
// 2. Establish the source and destination rectangles
|
||||||
let (source_rect, dest_rect) = self.adjust_source_dest_rects(
|
let (source_rect, dest_rect) =
|
||||||
image_size,
|
self.adjust_source_dest_rects(image_size, sx, sy, sw, sh, dx, dy, dw, dh);
|
||||||
sx,
|
|
||||||
sy,
|
|
||||||
sw,
|
|
||||||
sh,
|
|
||||||
dx,
|
|
||||||
dy,
|
|
||||||
dw,
|
|
||||||
dh,
|
|
||||||
);
|
|
||||||
|
|
||||||
if !is_rect_valid(source_rect) || !is_rect_valid(dest_rect) {
|
if !is_rect_valid(source_rect) || !is_rect_valid(dest_rect) {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
@ -384,7 +390,8 @@ impl CanvasRenderingContext2D {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fetch_and_draw_image_data(&self,
|
fn fetch_and_draw_image_data(
|
||||||
|
&self,
|
||||||
url: ServoUrl,
|
url: ServoUrl,
|
||||||
sx: f64,
|
sx: f64,
|
||||||
sy: f64,
|
sy: f64,
|
||||||
|
@ -393,8 +400,8 @@ impl CanvasRenderingContext2D {
|
||||||
dx: f64,
|
dx: f64,
|
||||||
dy: f64,
|
dy: f64,
|
||||||
dw: Option<f64>,
|
dw: Option<f64>,
|
||||||
dh: Option<f64>)
|
dh: Option<f64>,
|
||||||
-> ErrorResult {
|
) -> ErrorResult {
|
||||||
debug!("Fetching image {}.", url);
|
debug!("Fetching image {}.", url);
|
||||||
// https://html.spec.whatwg.org/multipage/#img-error
|
// https://html.spec.whatwg.org/multipage/#img-error
|
||||||
// If the image argument is an HTMLImageElement object that is in the broken state,
|
// If the image argument is an HTMLImageElement object that is in the broken state,
|
||||||
|
@ -413,13 +420,11 @@ impl CanvasRenderingContext2D {
|
||||||
let dh = dh.unwrap_or(image_size.height);
|
let dh = dh.unwrap_or(image_size.height);
|
||||||
let sw = sw.unwrap_or(image_size.width);
|
let sw = sw.unwrap_or(image_size.width);
|
||||||
let sh = sh.unwrap_or(image_size.height);
|
let sh = sh.unwrap_or(image_size.height);
|
||||||
self.draw_image_data(image_data,
|
self.draw_image_data(image_data, image_size, sx, sy, sw, sh, dx, dy, dw, dh)
|
||||||
image_size,
|
|
||||||
sx, sy, sw, sh,
|
|
||||||
dx, dy, dw, dh)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_image_data(&self,
|
fn draw_image_data(
|
||||||
|
&self,
|
||||||
image_data: Vec<u8>,
|
image_data: Vec<u8>,
|
||||||
image_size: Size2D<f64>,
|
image_size: Size2D<f64>,
|
||||||
sx: f64,
|
sx: f64,
|
||||||
|
@ -429,18 +434,11 @@ impl CanvasRenderingContext2D {
|
||||||
dx: f64,
|
dx: f64,
|
||||||
dy: f64,
|
dy: f64,
|
||||||
dw: f64,
|
dw: f64,
|
||||||
dh: f64)
|
dh: f64,
|
||||||
-> ErrorResult {
|
) -> ErrorResult {
|
||||||
// Establish the source and destination rectangles
|
// Establish the source and destination rectangles
|
||||||
let (source_rect, dest_rect) = self.adjust_source_dest_rects(image_size,
|
let (source_rect, dest_rect) =
|
||||||
sx,
|
self.adjust_source_dest_rects(image_size, sx, sy, sw, sh, dx, dy, dw, dh);
|
||||||
sy,
|
|
||||||
sw,
|
|
||||||
sh,
|
|
||||||
dx,
|
|
||||||
dy,
|
|
||||||
dw,
|
|
||||||
dh);
|
|
||||||
|
|
||||||
if !is_rect_valid(source_rect) || !is_rect_valid(dest_rect) {
|
if !is_rect_valid(source_rect) || !is_rect_valid(dest_rect) {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
@ -465,7 +463,7 @@ impl CanvasRenderingContext2D {
|
||||||
ImageResponse::None |
|
ImageResponse::None |
|
||||||
ImageResponse::MetadataLoaded(_) => {
|
ImageResponse::MetadataLoaded(_) => {
|
||||||
return None;
|
return None;
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
let image_size = Size2D::new(img.width as i32, img.height as i32);
|
let image_size = Size2D::new(img.width as i32, img.height as i32);
|
||||||
|
@ -481,15 +479,16 @@ impl CanvasRenderingContext2D {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn request_image_from_cache(&self, url: ServoUrl) -> ImageResponse {
|
fn request_image_from_cache(&self, url: ServoUrl) -> ImageResponse {
|
||||||
let response = self.image_cache
|
let response = self.image_cache.find_image_or_metadata(
|
||||||
.find_image_or_metadata(url.clone(),
|
url.clone(),
|
||||||
UsePlaceholder::No,
|
UsePlaceholder::No,
|
||||||
CanRequestImages::No);
|
CanRequestImages::No,
|
||||||
|
);
|
||||||
match response {
|
match response {
|
||||||
Ok(ImageOrMetadataAvailable::ImageAvailable(image, url)) =>
|
Ok(ImageOrMetadataAvailable::ImageAvailable(image, url)) => {
|
||||||
ImageResponse::Loaded(image, url),
|
ImageResponse::Loaded(image, url)
|
||||||
Err(ImageState::Pending(_)) =>
|
},
|
||||||
ImageResponse::None,
|
Err(ImageState::Pending(_)) => ImageResponse::None,
|
||||||
_ => {
|
_ => {
|
||||||
// Rather annoyingly, we get the same response back from
|
// Rather annoyingly, we get the same response back from
|
||||||
// A load which really failed and from a load which hasn't started yet.
|
// A load which really failed and from a load which hasn't started yet.
|
||||||
|
@ -512,8 +511,10 @@ impl CanvasRenderingContext2D {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(Rect::new(Point2D::new(x as f32, y as f32),
|
Some(Rect::new(
|
||||||
Size2D::new(w as f32, h as f32)))
|
Point2D::new(x as f32, y as f32),
|
||||||
|
Size2D::new(w as f32, h as f32),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_color(&self, string: &str) -> Result<RGBA, ()> {
|
fn parse_color(&self, string: &str) -> Result<RGBA, ()> {
|
||||||
|
@ -540,11 +541,13 @@ impl CanvasRenderingContext2D {
|
||||||
let canvas_element = canvas.upcast::<Element>();
|
let canvas_element = canvas.upcast::<Element>();
|
||||||
|
|
||||||
match canvas_element.style() {
|
match canvas_element.style() {
|
||||||
Some(ref s) if canvas_element.has_css_layout_box() => Ok(s.get_color().color),
|
Some(ref s) if canvas_element.has_css_layout_box() => {
|
||||||
_ => Ok(RGBA::new(0, 0, 0, 255))
|
Ok(s.get_color().color)
|
||||||
|
},
|
||||||
|
_ => Ok(RGBA::new(0, 0, 0, 255)),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => Err(())
|
_ => Err(()),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(())
|
Err(())
|
||||||
|
@ -556,7 +559,9 @@ impl CanvasRenderingContext2D {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_canvas_2d_msg(&self, msg: Canvas2dMsg) {
|
pub fn send_canvas_2d_msg(&self, msg: Canvas2dMsg) {
|
||||||
self.ipc_renderer.send(CanvasMsg::Canvas2d(msg, self.get_canvas_id())).unwrap()
|
self.ipc_renderer
|
||||||
|
.send(CanvasMsg::Canvas2d(msg, self.get_canvas_id()))
|
||||||
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_ipc_renderer(&self) -> IpcSender<CanvasMsg> {
|
pub fn get_ipc_renderer(&self) -> IpcSender<CanvasMsg> {
|
||||||
|
@ -610,7 +615,9 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-save
|
// https://html.spec.whatwg.org/multipage/#dom-context-2d-save
|
||||||
fn Save(&self) {
|
fn Save(&self) {
|
||||||
self.saved_states.borrow_mut().push(self.state.borrow().clone());
|
self.saved_states
|
||||||
|
.borrow_mut()
|
||||||
|
.push(self.state.borrow().clone());
|
||||||
self.send_canvas_2d_msg(Canvas2dMsg::SaveContext);
|
self.send_canvas_2d_msg(Canvas2dMsg::SaveContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -643,10 +650,14 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
|
||||||
|
|
||||||
let (sin, cos) = (angle.sin(), angle.cos());
|
let (sin, cos) = (angle.sin(), angle.cos());
|
||||||
let transform = self.state.borrow().transform;
|
let transform = self.state.borrow().transform;
|
||||||
self.state.borrow_mut().transform = transform.pre_mul(
|
self.state.borrow_mut().transform = transform.pre_mul(&Transform2D::row_major(
|
||||||
&Transform2D::row_major(cos as f32, sin as f32,
|
cos as f32,
|
||||||
-sin as f32, cos as f32,
|
sin as f32,
|
||||||
0.0, 0.0));
|
-sin as f32,
|
||||||
|
cos as f32,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
));
|
||||||
self.update_transform()
|
self.update_transform()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -663,21 +674,32 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-transform
|
// https://html.spec.whatwg.org/multipage/#dom-context-2d-transform
|
||||||
fn Transform(&self, a: f64, b: f64, c: f64, d: f64, e: f64, f: f64) {
|
fn Transform(&self, a: f64, b: f64, c: f64, d: f64, e: f64, f: f64) {
|
||||||
if !(a.is_finite() && b.is_finite() && c.is_finite() &&
|
if !(a.is_finite() &&
|
||||||
d.is_finite() && e.is_finite() && f.is_finite()) {
|
b.is_finite() &&
|
||||||
|
c.is_finite() &&
|
||||||
|
d.is_finite() &&
|
||||||
|
e.is_finite() &&
|
||||||
|
f.is_finite())
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let transform = self.state.borrow().transform;
|
let transform = self.state.borrow().transform;
|
||||||
self.state.borrow_mut().transform = transform.pre_mul(
|
self.state.borrow_mut().transform = transform.pre_mul(&Transform2D::row_major(
|
||||||
&Transform2D::row_major(a as f32, b as f32, c as f32, d as f32, e as f32, f as f32));
|
a as f32, b as f32, c as f32, d as f32, e as f32, f as f32,
|
||||||
|
));
|
||||||
self.update_transform()
|
self.update_transform()
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-settransform
|
// https://html.spec.whatwg.org/multipage/#dom-context-2d-settransform
|
||||||
fn SetTransform(&self, a: f64, b: f64, c: f64, d: f64, e: f64, f: f64) {
|
fn SetTransform(&self, a: f64, b: f64, c: f64, d: f64, e: f64, f: f64) {
|
||||||
if !(a.is_finite() && b.is_finite() && c.is_finite() &&
|
if !(a.is_finite() &&
|
||||||
d.is_finite() && e.is_finite() && f.is_finite()) {
|
b.is_finite() &&
|
||||||
|
c.is_finite() &&
|
||||||
|
d.is_finite() &&
|
||||||
|
e.is_finite() &&
|
||||||
|
f.is_finite())
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -784,7 +806,8 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
|
||||||
CanvasFillRule::Nonzero => FillRule::Nonzero,
|
CanvasFillRule::Nonzero => FillRule::Nonzero,
|
||||||
CanvasFillRule::Evenodd => FillRule::Evenodd,
|
CanvasFillRule::Evenodd => FillRule::Evenodd,
|
||||||
};
|
};
|
||||||
let (sender, receiver) = profiled_ipc::channel::<bool>(self.global().time_profiler_chan().clone()).unwrap();
|
let (sender, receiver) =
|
||||||
|
profiled_ipc::channel::<bool>(self.global().time_profiler_chan().clone()).unwrap();
|
||||||
self.send_canvas_2d_msg(Canvas2dMsg::IsPointInPath(x, y, fill_rule, sender));
|
self.send_canvas_2d_msg(Canvas2dMsg::IsPointInPath(x, y, fill_rule, sender));
|
||||||
receiver.recv().unwrap()
|
receiver.recv().unwrap()
|
||||||
}
|
}
|
||||||
|
@ -797,11 +820,7 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-drawimage
|
// https://html.spec.whatwg.org/multipage/#dom-context-2d-drawimage
|
||||||
fn DrawImage(&self,
|
fn DrawImage(&self, image: CanvasImageSource, dx: f64, dy: f64) -> ErrorResult {
|
||||||
image: CanvasImageSource,
|
|
||||||
dx: f64,
|
|
||||||
dy: f64)
|
|
||||||
-> ErrorResult {
|
|
||||||
if !(dx.is_finite() && dy.is_finite()) {
|
if !(dx.is_finite() && dy.is_finite()) {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
@ -810,13 +829,14 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-drawimage
|
// https://html.spec.whatwg.org/multipage/#dom-context-2d-drawimage
|
||||||
fn DrawImage_(&self,
|
fn DrawImage_(
|
||||||
|
&self,
|
||||||
image: CanvasImageSource,
|
image: CanvasImageSource,
|
||||||
dx: f64,
|
dx: f64,
|
||||||
dy: f64,
|
dy: f64,
|
||||||
dw: f64,
|
dw: f64,
|
||||||
dh: f64)
|
dh: f64,
|
||||||
-> ErrorResult {
|
) -> ErrorResult {
|
||||||
if !(dx.is_finite() && dy.is_finite() && dw.is_finite() && dh.is_finite()) {
|
if !(dx.is_finite() && dy.is_finite() && dw.is_finite() && dh.is_finite()) {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
@ -825,7 +845,8 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-drawimage
|
// https://html.spec.whatwg.org/multipage/#dom-context-2d-drawimage
|
||||||
fn DrawImage__(&self,
|
fn DrawImage__(
|
||||||
|
&self,
|
||||||
image: CanvasImageSource,
|
image: CanvasImageSource,
|
||||||
sx: f64,
|
sx: f64,
|
||||||
sy: f64,
|
sy: f64,
|
||||||
|
@ -834,14 +855,22 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
|
||||||
dx: f64,
|
dx: f64,
|
||||||
dy: f64,
|
dy: f64,
|
||||||
dw: f64,
|
dw: f64,
|
||||||
dh: f64)
|
dh: f64,
|
||||||
-> ErrorResult {
|
) -> ErrorResult {
|
||||||
if !(sx.is_finite() && sy.is_finite() && sw.is_finite() && sh.is_finite() &&
|
if !(sx.is_finite() &&
|
||||||
dx.is_finite() && dy.is_finite() && dw.is_finite() && dh.is_finite()) {
|
sy.is_finite() &&
|
||||||
|
sw.is_finite() &&
|
||||||
|
sh.is_finite() &&
|
||||||
|
dx.is_finite() &&
|
||||||
|
dy.is_finite() &&
|
||||||
|
dw.is_finite() &&
|
||||||
|
dh.is_finite())
|
||||||
|
{
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
self.draw_image(image,
|
self.draw_image(
|
||||||
|
image,
|
||||||
sx,
|
sx,
|
||||||
sy,
|
sy,
|
||||||
Some(sw),
|
Some(sw),
|
||||||
|
@ -849,7 +878,8 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
|
||||||
dx,
|
dx,
|
||||||
dy,
|
dy,
|
||||||
Some(dw),
|
Some(dw),
|
||||||
Some(dh))
|
Some(dh),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-moveto
|
// https://html.spec.whatwg.org/multipage/#dom-context-2d-moveto
|
||||||
|
@ -871,8 +901,10 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-rect
|
// https://html.spec.whatwg.org/multipage/#dom-context-2d-rect
|
||||||
fn Rect(&self, x: f64, y: f64, width: f64, height: f64) {
|
fn Rect(&self, x: f64, y: f64, width: f64, height: f64) {
|
||||||
if [x, y, width, height].iter().all(|val| val.is_finite()) {
|
if [x, y, width, height].iter().all(|val| val.is_finite()) {
|
||||||
let rect = Rect::new(Point2D::new(x as f32, y as f32),
|
let rect = Rect::new(
|
||||||
Size2D::new(width as f32, height as f32));
|
Point2D::new(x as f32, y as f32),
|
||||||
|
Size2D::new(width as f32, height as f32),
|
||||||
|
);
|
||||||
self.send_canvas_2d_msg(Canvas2dMsg::Rect(rect));
|
self.send_canvas_2d_msg(Canvas2dMsg::Rect(rect));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -882,23 +914,28 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
|
||||||
if !(cpx.is_finite() && cpy.is_finite() && x.is_finite() && y.is_finite()) {
|
if !(cpx.is_finite() && cpy.is_finite() && x.is_finite() && y.is_finite()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
self.send_canvas_2d_msg(Canvas2dMsg::QuadraticCurveTo(Point2D::new(cpx as f32,
|
self.send_canvas_2d_msg(Canvas2dMsg::QuadraticCurveTo(
|
||||||
cpy as f32),
|
Point2D::new(cpx as f32, cpy as f32),
|
||||||
Point2D::new(x as f32,
|
Point2D::new(x as f32, y as f32),
|
||||||
y as f32)));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-beziercurveto
|
// https://html.spec.whatwg.org/multipage/#dom-context-2d-beziercurveto
|
||||||
fn BezierCurveTo(&self, cp1x: f64, cp1y: f64, cp2x: f64, cp2y: f64, x: f64, y: f64) {
|
fn BezierCurveTo(&self, cp1x: f64, cp1y: f64, cp2x: f64, cp2y: f64, x: f64, y: f64) {
|
||||||
if !(cp1x.is_finite() && cp1y.is_finite() && cp2x.is_finite() && cp2y.is_finite() &&
|
if !(cp1x.is_finite() &&
|
||||||
x.is_finite() && y.is_finite()) {
|
cp1y.is_finite() &&
|
||||||
|
cp2x.is_finite() &&
|
||||||
|
cp2y.is_finite() &&
|
||||||
|
x.is_finite() &&
|
||||||
|
y.is_finite())
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
self.send_canvas_2d_msg(Canvas2dMsg::BezierCurveTo(Point2D::new(cp1x as f32,
|
self.send_canvas_2d_msg(Canvas2dMsg::BezierCurveTo(
|
||||||
cp1y as f32),
|
Point2D::new(cp1x as f32, cp1y as f32),
|
||||||
Point2D::new(cp2x as f32,
|
Point2D::new(cp2x as f32, cp2y as f32),
|
||||||
cp2y as f32),
|
Point2D::new(x as f32, y as f32),
|
||||||
Point2D::new(x as f32, y as f32)));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-arc
|
// https://html.spec.whatwg.org/multipage/#dom-context-2d-arc
|
||||||
|
@ -911,11 +948,13 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
|
||||||
return Err(Error::IndexSize);
|
return Err(Error::IndexSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.send_canvas_2d_msg(Canvas2dMsg::Arc(Point2D::new(x as f32, y as f32),
|
self.send_canvas_2d_msg(Canvas2dMsg::Arc(
|
||||||
|
Point2D::new(x as f32, y as f32),
|
||||||
r as f32,
|
r as f32,
|
||||||
start as f32,
|
start as f32,
|
||||||
end as f32,
|
end as f32,
|
||||||
ccw));
|
ccw,
|
||||||
|
));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -928,28 +967,45 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
|
||||||
return Err(Error::IndexSize);
|
return Err(Error::IndexSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.send_canvas_2d_msg(Canvas2dMsg::ArcTo(Point2D::new(cp1x as f32, cp1y as f32),
|
self.send_canvas_2d_msg(Canvas2dMsg::ArcTo(
|
||||||
|
Point2D::new(cp1x as f32, cp1y as f32),
|
||||||
Point2D::new(cp2x as f32, cp2y as f32),
|
Point2D::new(cp2x as f32, cp2y as f32),
|
||||||
r as f32));
|
r as f32,
|
||||||
|
));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-ellipse
|
// https://html.spec.whatwg.org/multipage/#dom-context-2d-ellipse
|
||||||
fn Ellipse(&self, x: f64, y: f64, rx: f64, ry: f64, rotation: f64, start: f64, end: f64, ccw: bool) -> ErrorResult {
|
fn Ellipse(
|
||||||
if !([x, y, rx, ry, rotation, start, end].iter().all(|x| x.is_finite())) {
|
&self,
|
||||||
|
x: f64,
|
||||||
|
y: f64,
|
||||||
|
rx: f64,
|
||||||
|
ry: f64,
|
||||||
|
rotation: f64,
|
||||||
|
start: f64,
|
||||||
|
end: f64,
|
||||||
|
ccw: bool,
|
||||||
|
) -> ErrorResult {
|
||||||
|
if !([x, y, rx, ry, rotation, start, end]
|
||||||
|
.iter()
|
||||||
|
.all(|x| x.is_finite()))
|
||||||
|
{
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
if rx < 0.0 || ry < 0.0 {
|
if rx < 0.0 || ry < 0.0 {
|
||||||
return Err(Error::IndexSize);
|
return Err(Error::IndexSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.send_canvas_2d_msg(Canvas2dMsg::Ellipse(Point2D::new(x as f32, y as f32),
|
self.send_canvas_2d_msg(Canvas2dMsg::Ellipse(
|
||||||
|
Point2D::new(x as f32, y as f32),
|
||||||
rx as f32,
|
rx as f32,
|
||||||
ry as f32,
|
ry as f32,
|
||||||
rotation as f32,
|
rotation as f32,
|
||||||
start as f32,
|
start as f32,
|
||||||
end as f32,
|
end as f32,
|
||||||
ccw));
|
ccw,
|
||||||
|
));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -977,7 +1033,7 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
|
||||||
},
|
},
|
||||||
CanvasFillOrStrokeStyle::Pattern(ref pattern) => {
|
CanvasFillOrStrokeStyle::Pattern(ref pattern) => {
|
||||||
StringOrCanvasGradientOrCanvasPattern::CanvasPattern(DomRoot::from_ref(&*pattern))
|
StringOrCanvasGradientOrCanvasPattern::CanvasPattern(DomRoot::from_ref(&*pattern))
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -987,23 +1043,28 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
|
||||||
StringOrCanvasGradientOrCanvasPattern::String(string) => {
|
StringOrCanvasGradientOrCanvasPattern::String(string) => {
|
||||||
if let Ok(rgba) = self.parse_color(&string) {
|
if let Ok(rgba) = self.parse_color(&string) {
|
||||||
self.state.borrow_mut().stroke_style = CanvasFillOrStrokeStyle::Color(rgba);
|
self.state.borrow_mut().stroke_style = CanvasFillOrStrokeStyle::Color(rgba);
|
||||||
self.send_canvas_2d_msg(Canvas2dMsg::SetStrokeStyle(
|
self.send_canvas_2d_msg(Canvas2dMsg::SetStrokeStyle(FillOrStrokeStyle::Color(
|
||||||
FillOrStrokeStyle::Color(rgba)));
|
rgba,
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
StringOrCanvasGradientOrCanvasPattern::CanvasGradient(gradient) => {
|
StringOrCanvasGradientOrCanvasPattern::CanvasGradient(gradient) => {
|
||||||
self.state.borrow_mut().stroke_style =
|
self.state.borrow_mut().stroke_style =
|
||||||
CanvasFillOrStrokeStyle::Gradient(Dom::from_ref(&*gradient));
|
CanvasFillOrStrokeStyle::Gradient(Dom::from_ref(&*gradient));
|
||||||
self.send_canvas_2d_msg(Canvas2dMsg::SetStrokeStyle(gradient.to_fill_or_stroke_style()));
|
self.send_canvas_2d_msg(Canvas2dMsg::SetStrokeStyle(
|
||||||
|
gradient.to_fill_or_stroke_style(),
|
||||||
|
));
|
||||||
},
|
},
|
||||||
StringOrCanvasGradientOrCanvasPattern::CanvasPattern(pattern) => {
|
StringOrCanvasGradientOrCanvasPattern::CanvasPattern(pattern) => {
|
||||||
self.state.borrow_mut().stroke_style =
|
self.state.borrow_mut().stroke_style =
|
||||||
CanvasFillOrStrokeStyle::Pattern(Dom::from_ref(&*pattern));
|
CanvasFillOrStrokeStyle::Pattern(Dom::from_ref(&*pattern));
|
||||||
self.send_canvas_2d_msg(Canvas2dMsg::SetStrokeStyle(pattern.to_fill_or_stroke_style()));
|
self.send_canvas_2d_msg(Canvas2dMsg::SetStrokeStyle(
|
||||||
|
pattern.to_fill_or_stroke_style(),
|
||||||
|
));
|
||||||
if !pattern.origin_is_clean() {
|
if !pattern.origin_is_clean() {
|
||||||
self.set_origin_unclean();
|
self.set_origin_unclean();
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1020,7 +1081,7 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
|
||||||
},
|
},
|
||||||
CanvasFillOrStrokeStyle::Pattern(ref pattern) => {
|
CanvasFillOrStrokeStyle::Pattern(ref pattern) => {
|
||||||
StringOrCanvasGradientOrCanvasPattern::CanvasPattern(DomRoot::from_ref(&*pattern))
|
StringOrCanvasGradientOrCanvasPattern::CanvasPattern(DomRoot::from_ref(&*pattern))
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1030,23 +1091,28 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
|
||||||
StringOrCanvasGradientOrCanvasPattern::String(string) => {
|
StringOrCanvasGradientOrCanvasPattern::String(string) => {
|
||||||
if let Ok(rgba) = self.parse_color(&string) {
|
if let Ok(rgba) = self.parse_color(&string) {
|
||||||
self.state.borrow_mut().fill_style = CanvasFillOrStrokeStyle::Color(rgba);
|
self.state.borrow_mut().fill_style = CanvasFillOrStrokeStyle::Color(rgba);
|
||||||
self.send_canvas_2d_msg(Canvas2dMsg::SetFillStyle(
|
self.send_canvas_2d_msg(Canvas2dMsg::SetFillStyle(FillOrStrokeStyle::Color(
|
||||||
FillOrStrokeStyle::Color(rgba)))
|
rgba,
|
||||||
}
|
)))
|
||||||
}
|
}
|
||||||
|
},
|
||||||
StringOrCanvasGradientOrCanvasPattern::CanvasGradient(gradient) => {
|
StringOrCanvasGradientOrCanvasPattern::CanvasGradient(gradient) => {
|
||||||
self.state.borrow_mut().fill_style =
|
self.state.borrow_mut().fill_style =
|
||||||
CanvasFillOrStrokeStyle::Gradient(Dom::from_ref(&*gradient));
|
CanvasFillOrStrokeStyle::Gradient(Dom::from_ref(&*gradient));
|
||||||
self.send_canvas_2d_msg(Canvas2dMsg::SetFillStyle(gradient.to_fill_or_stroke_style()));
|
self.send_canvas_2d_msg(Canvas2dMsg::SetFillStyle(
|
||||||
}
|
gradient.to_fill_or_stroke_style(),
|
||||||
|
));
|
||||||
|
},
|
||||||
StringOrCanvasGradientOrCanvasPattern::CanvasPattern(pattern) => {
|
StringOrCanvasGradientOrCanvasPattern::CanvasPattern(pattern) => {
|
||||||
self.state.borrow_mut().fill_style =
|
self.state.borrow_mut().fill_style =
|
||||||
CanvasFillOrStrokeStyle::Pattern(Dom::from_ref(&*pattern));
|
CanvasFillOrStrokeStyle::Pattern(Dom::from_ref(&*pattern));
|
||||||
self.send_canvas_2d_msg(Canvas2dMsg::SetFillStyle(pattern.to_fill_or_stroke_style()));
|
self.send_canvas_2d_msg(Canvas2dMsg::SetFillStyle(
|
||||||
|
pattern.to_fill_or_stroke_style(),
|
||||||
|
));
|
||||||
if !pattern.origin_is_clean() {
|
if !pattern.origin_is_clean() {
|
||||||
self.set_origin_unclean();
|
self.set_origin_unclean();
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1063,21 +1129,19 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-createimagedata
|
// https://html.spec.whatwg.org/multipage/#dom-context-2d-createimagedata
|
||||||
fn CreateImageData_(&self, imagedata: &ImageData) -> Fallible<DomRoot<ImageData>> {
|
fn CreateImageData_(&self, imagedata: &ImageData) -> Fallible<DomRoot<ImageData>> {
|
||||||
ImageData::new(&self.global(),
|
ImageData::new(&self.global(), imagedata.Width(), imagedata.Height(), None)
|
||||||
imagedata.Width(),
|
|
||||||
imagedata.Height(),
|
|
||||||
None)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-getimagedata
|
// https://html.spec.whatwg.org/multipage/#dom-context-2d-getimagedata
|
||||||
fn GetImageData(&self,
|
fn GetImageData(
|
||||||
|
&self,
|
||||||
sx: Finite<f64>,
|
sx: Finite<f64>,
|
||||||
sy: Finite<f64>,
|
sy: Finite<f64>,
|
||||||
sw: Finite<f64>,
|
sw: Finite<f64>,
|
||||||
sh: Finite<f64>)
|
sh: Finite<f64>,
|
||||||
-> Fallible<DomRoot<ImageData>> {
|
) -> Fallible<DomRoot<ImageData>> {
|
||||||
if !self.origin_is_clean() {
|
if !self.origin_is_clean() {
|
||||||
return Err(Error::Security)
|
return Err(Error::Security);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut sx = *sx;
|
let mut sx = *sx;
|
||||||
|
@ -1102,9 +1166,15 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
|
||||||
let sw = cmp::max(1, sw.to_u32().unwrap());
|
let sw = cmp::max(1, sw.to_u32().unwrap());
|
||||||
|
|
||||||
let (sender, receiver) = ipc::bytes_channel().unwrap();
|
let (sender, receiver) = ipc::bytes_channel().unwrap();
|
||||||
let dest_rect = Rect::new(Point2D::new(sx.to_i32().unwrap(), sy.to_i32().unwrap()),
|
let dest_rect = Rect::new(
|
||||||
Size2D::new(sw as i32, sh as i32));
|
Point2D::new(sx.to_i32().unwrap(), sy.to_i32().unwrap()),
|
||||||
let canvas_size = self.canvas.as_ref().map(|c| c.get_size()).unwrap_or(Size2D::zero());
|
Size2D::new(sw as i32, sh as i32),
|
||||||
|
);
|
||||||
|
let canvas_size = self
|
||||||
|
.canvas
|
||||||
|
.as_ref()
|
||||||
|
.map(|c| c.get_size())
|
||||||
|
.unwrap_or(Size2D::zero());
|
||||||
let canvas_size = Size2D::new(canvas_size.width as f64, canvas_size.height as f64);
|
let canvas_size = Size2D::new(canvas_size.width as f64, canvas_size.height as f64);
|
||||||
self.send_canvas_2d_msg(Canvas2dMsg::GetImageData(dest_rect, canvas_size, sender));
|
self.send_canvas_2d_msg(Canvas2dMsg::GetImageData(dest_rect, canvas_size, sender));
|
||||||
let mut data = receiver.recv().unwrap();
|
let mut data = receiver.recv().unwrap();
|
||||||
|
@ -1122,97 +1192,110 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-putimagedata
|
// https://html.spec.whatwg.org/multipage/#dom-context-2d-putimagedata
|
||||||
fn PutImageData(&self, imagedata: &ImageData, dx: Finite<f64>, dy: Finite<f64>) {
|
fn PutImageData(&self, imagedata: &ImageData, dx: Finite<f64>, dy: Finite<f64>) {
|
||||||
self.PutImageData_(imagedata,
|
self.PutImageData_(
|
||||||
|
imagedata,
|
||||||
dx,
|
dx,
|
||||||
dy,
|
dy,
|
||||||
Finite::wrap(0f64),
|
Finite::wrap(0f64),
|
||||||
Finite::wrap(0f64),
|
Finite::wrap(0f64),
|
||||||
Finite::wrap(imagedata.Width() as f64),
|
Finite::wrap(imagedata.Width() as f64),
|
||||||
Finite::wrap(imagedata.Height() as f64))
|
Finite::wrap(imagedata.Height() as f64),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-putimagedata
|
// https://html.spec.whatwg.org/multipage/#dom-context-2d-putimagedata
|
||||||
fn PutImageData_(&self,
|
fn PutImageData_(
|
||||||
|
&self,
|
||||||
imagedata: &ImageData,
|
imagedata: &ImageData,
|
||||||
dx: Finite<f64>,
|
dx: Finite<f64>,
|
||||||
dy: Finite<f64>,
|
dy: Finite<f64>,
|
||||||
dirty_x: Finite<f64>,
|
dirty_x: Finite<f64>,
|
||||||
dirty_y: Finite<f64>,
|
dirty_y: Finite<f64>,
|
||||||
dirty_width: Finite<f64>,
|
dirty_width: Finite<f64>,
|
||||||
dirty_height: Finite<f64>) {
|
dirty_height: Finite<f64>,
|
||||||
|
) {
|
||||||
let data = imagedata.get_data_array();
|
let data = imagedata.get_data_array();
|
||||||
let offset = Vector2D::new(*dx, *dy);
|
let offset = Vector2D::new(*dx, *dy);
|
||||||
let image_data_size = Size2D::new(imagedata.Width() as f64, imagedata.Height() as f64);
|
let image_data_size = Size2D::new(imagedata.Width() as f64, imagedata.Height() as f64);
|
||||||
|
|
||||||
let dirty_rect = Rect::new(Point2D::new(*dirty_x, *dirty_y),
|
let dirty_rect = Rect::new(
|
||||||
Size2D::new(*dirty_width, *dirty_height));
|
Point2D::new(*dirty_x, *dirty_y),
|
||||||
self.send_canvas_2d_msg(Canvas2dMsg::PutImageData(data.into(),
|
Size2D::new(*dirty_width, *dirty_height),
|
||||||
|
);
|
||||||
|
self.send_canvas_2d_msg(Canvas2dMsg::PutImageData(
|
||||||
|
data.into(),
|
||||||
offset,
|
offset,
|
||||||
image_data_size,
|
image_data_size,
|
||||||
dirty_rect));
|
dirty_rect,
|
||||||
|
));
|
||||||
self.mark_as_dirty();
|
self.mark_as_dirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-createlineargradient
|
// https://html.spec.whatwg.org/multipage/#dom-context-2d-createlineargradient
|
||||||
fn CreateLinearGradient(&self,
|
fn CreateLinearGradient(
|
||||||
|
&self,
|
||||||
x0: Finite<f64>,
|
x0: Finite<f64>,
|
||||||
y0: Finite<f64>,
|
y0: Finite<f64>,
|
||||||
x1: Finite<f64>,
|
x1: Finite<f64>,
|
||||||
y1: Finite<f64>)
|
y1: Finite<f64>,
|
||||||
-> DomRoot<CanvasGradient> {
|
) -> DomRoot<CanvasGradient> {
|
||||||
CanvasGradient::new(&self.global(),
|
CanvasGradient::new(
|
||||||
CanvasGradientStyle::Linear(LinearGradientStyle::new(*x0,
|
&self.global(),
|
||||||
*y0,
|
CanvasGradientStyle::Linear(LinearGradientStyle::new(*x0, *y0, *x1, *y1, Vec::new())),
|
||||||
*x1,
|
)
|
||||||
*y1,
|
|
||||||
Vec::new())))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-createradialgradient
|
// https://html.spec.whatwg.org/multipage/#dom-context-2d-createradialgradient
|
||||||
fn CreateRadialGradient(&self,
|
fn CreateRadialGradient(
|
||||||
|
&self,
|
||||||
x0: Finite<f64>,
|
x0: Finite<f64>,
|
||||||
y0: Finite<f64>,
|
y0: Finite<f64>,
|
||||||
r0: Finite<f64>,
|
r0: Finite<f64>,
|
||||||
x1: Finite<f64>,
|
x1: Finite<f64>,
|
||||||
y1: Finite<f64>,
|
y1: Finite<f64>,
|
||||||
r1: Finite<f64>)
|
r1: Finite<f64>,
|
||||||
-> Fallible<DomRoot<CanvasGradient>> {
|
) -> Fallible<DomRoot<CanvasGradient>> {
|
||||||
if *r0 < 0. || *r1 < 0. {
|
if *r0 < 0. || *r1 < 0. {
|
||||||
return Err(Error::IndexSize);
|
return Err(Error::IndexSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(CanvasGradient::new(&self.global(),
|
Ok(CanvasGradient::new(
|
||||||
CanvasGradientStyle::Radial(RadialGradientStyle::new(*x0,
|
&self.global(),
|
||||||
|
CanvasGradientStyle::Radial(RadialGradientStyle::new(
|
||||||
|
*x0,
|
||||||
*y0,
|
*y0,
|
||||||
*r0,
|
*r0,
|
||||||
*x1,
|
*x1,
|
||||||
*y1,
|
*y1,
|
||||||
*r1,
|
*r1,
|
||||||
Vec::new()))))
|
Vec::new(),
|
||||||
|
)),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-createpattern
|
// https://html.spec.whatwg.org/multipage/#dom-context-2d-createpattern
|
||||||
fn CreatePattern(&self,
|
fn CreatePattern(
|
||||||
|
&self,
|
||||||
image: CanvasImageSource,
|
image: CanvasImageSource,
|
||||||
mut repetition: DOMString)
|
mut repetition: DOMString,
|
||||||
-> Fallible<DomRoot<CanvasPattern>> {
|
) -> Fallible<DomRoot<CanvasPattern>> {
|
||||||
let (image_data, image_size) = match image {
|
let (image_data, image_size) = match image {
|
||||||
CanvasImageSource::HTMLImageElement(ref image) => {
|
CanvasImageSource::HTMLImageElement(ref image) => {
|
||||||
// https://html.spec.whatwg.org/multipage/#img-error
|
// https://html.spec.whatwg.org/multipage/#img-error
|
||||||
// If the image argument is an HTMLImageElement object that is in the broken state,
|
// If the image argument is an HTMLImageElement object that is in the broken state,
|
||||||
// then throw an InvalidStateError exception
|
// then throw an InvalidStateError exception
|
||||||
image.get_url()
|
image
|
||||||
|
.get_url()
|
||||||
.and_then(|url| self.fetch_image_data(url))
|
.and_then(|url| self.fetch_image_data(url))
|
||||||
.ok_or(Error::InvalidState)?
|
.ok_or(Error::InvalidState)?
|
||||||
},
|
},
|
||||||
CanvasImageSource::HTMLCanvasElement(ref canvas) => {
|
CanvasImageSource::HTMLCanvasElement(ref canvas) => {
|
||||||
canvas.fetch_all_data().ok_or(Error::InvalidState)?
|
canvas.fetch_all_data().ok_or(Error::InvalidState)?
|
||||||
},
|
},
|
||||||
CanvasImageSource::CSSStyleValue(ref value) => {
|
CanvasImageSource::CSSStyleValue(ref value) => value
|
||||||
value.get_url(self.base_url.clone())
|
.get_url(self.base_url.clone())
|
||||||
.and_then(|url| self.fetch_image_data(url))
|
.and_then(|url| self.fetch_image_data(url))
|
||||||
.ok_or(Error::InvalidState)?
|
.ok_or(Error::InvalidState)?,
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if repetition.is_empty() {
|
if repetition.is_empty() {
|
||||||
|
@ -1220,11 +1303,13 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Ok(rep) = RepetitionStyle::from_str(&repetition) {
|
if let Ok(rep) = RepetitionStyle::from_str(&repetition) {
|
||||||
Ok(CanvasPattern::new(&self.global(),
|
Ok(CanvasPattern::new(
|
||||||
|
&self.global(),
|
||||||
image_data,
|
image_data,
|
||||||
image_size,
|
image_size,
|
||||||
rep,
|
rep,
|
||||||
self.is_origin_clean(image)))
|
self.is_origin_clean(image),
|
||||||
|
))
|
||||||
} else {
|
} else {
|
||||||
Err(Error::Syntax)
|
Err(Error::Syntax)
|
||||||
}
|
}
|
||||||
|
@ -1362,7 +1447,10 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
|
||||||
|
|
||||||
impl Drop for CanvasRenderingContext2D {
|
impl Drop for CanvasRenderingContext2D {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
if let Err(err) = self.ipc_renderer.send(CanvasMsg::Close(self.get_canvas_id())) {
|
if let Err(err) = self
|
||||||
|
.ipc_renderer
|
||||||
|
.send(CanvasMsg::Close(self.get_canvas_id()))
|
||||||
|
{
|
||||||
warn!("Could not close canvas: {}", err)
|
warn!("Could not close canvas: {}", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1391,22 +1479,32 @@ fn is_rect_valid(rect: Rect<f64>) -> bool {
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#serialisation-of-a-colour
|
// https://html.spec.whatwg.org/multipage/#serialisation-of-a-colour
|
||||||
fn serialize<W>(color: &RGBA, dest: &mut W) -> fmt::Result
|
fn serialize<W>(color: &RGBA, dest: &mut W) -> fmt::Result
|
||||||
where W: fmt::Write
|
where
|
||||||
|
W: fmt::Write,
|
||||||
{
|
{
|
||||||
let red = color.red;
|
let red = color.red;
|
||||||
let green = color.green;
|
let green = color.green;
|
||||||
let blue = color.blue;
|
let blue = color.blue;
|
||||||
|
|
||||||
if color.alpha == 255 {
|
if color.alpha == 255 {
|
||||||
write!(dest,
|
write!(
|
||||||
|
dest,
|
||||||
"#{:x}{:x}{:x}{:x}{:x}{:x}",
|
"#{:x}{:x}{:x}{:x}{:x}{:x}",
|
||||||
red >> 4,
|
red >> 4,
|
||||||
red & 0xF,
|
red & 0xF,
|
||||||
green >> 4,
|
green >> 4,
|
||||||
green & 0xF,
|
green & 0xF,
|
||||||
blue >> 4,
|
blue >> 4,
|
||||||
blue & 0xF)
|
blue & 0xF
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
write!(dest, "rgba({}, {}, {}, {})", red, green, blue, color.alpha_f32())
|
write!(
|
||||||
|
dest,
|
||||||
|
"rgba({}, {}, {}, {})",
|
||||||
|
red,
|
||||||
|
green,
|
||||||
|
blue,
|
||||||
|
color.alpha_f32()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,16 +26,18 @@ impl ChannelMergerNode {
|
||||||
context: &BaseAudioContext,
|
context: &BaseAudioContext,
|
||||||
options: &ChannelMergerOptions,
|
options: &ChannelMergerOptions,
|
||||||
) -> Fallible<ChannelMergerNode> {
|
) -> Fallible<ChannelMergerNode> {
|
||||||
let node_options = options.parent
|
let node_options = options.parent.unwrap_or(
|
||||||
.unwrap_or(1, ChannelCountMode::Explicit,
|
1,
|
||||||
ChannelInterpretation::Speakers);
|
ChannelCountMode::Explicit,
|
||||||
|
ChannelInterpretation::Speakers,
|
||||||
|
);
|
||||||
|
|
||||||
if node_options.count != 1 || node_options.mode != ChannelCountMode::Explicit {
|
if node_options.count != 1 || node_options.mode != ChannelCountMode::Explicit {
|
||||||
return Err(Error::InvalidState)
|
return Err(Error::InvalidState);
|
||||||
}
|
}
|
||||||
|
|
||||||
if options.numberOfInputs < 1 || options.numberOfInputs > MAX_CHANNEL_COUNT {
|
if options.numberOfInputs < 1 || options.numberOfInputs > MAX_CHANNEL_COUNT {
|
||||||
return Err(Error::IndexSize)
|
return Err(Error::IndexSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
let node = AudioNode::new_inherited(
|
let node = AudioNode::new_inherited(
|
||||||
|
@ -45,9 +47,7 @@ impl ChannelMergerNode {
|
||||||
options.numberOfInputs, // inputs
|
options.numberOfInputs, // inputs
|
||||||
1, // outputs
|
1, // outputs
|
||||||
)?;
|
)?;
|
||||||
Ok(ChannelMergerNode {
|
Ok(ChannelMergerNode { node })
|
||||||
node,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unrooted_must_root)]
|
#[allow(unrooted_must_root)]
|
||||||
|
@ -57,7 +57,11 @@ impl ChannelMergerNode {
|
||||||
options: &ChannelMergerOptions,
|
options: &ChannelMergerOptions,
|
||||||
) -> Fallible<DomRoot<ChannelMergerNode>> {
|
) -> Fallible<DomRoot<ChannelMergerNode>> {
|
||||||
let node = ChannelMergerNode::new_inherited(window, context, options)?;
|
let node = ChannelMergerNode::new_inherited(window, context, options)?;
|
||||||
Ok(reflect_dom_object(Box::new(node), window, ChannelMergerNodeBinding::Wrap))
|
Ok(reflect_dom_object(
|
||||||
|
Box::new(node),
|
||||||
|
window,
|
||||||
|
ChannelMergerNodeBinding::Wrap,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn Constructor(
|
pub fn Constructor(
|
||||||
|
|
|
@ -45,7 +45,7 @@ impl CharacterData {
|
||||||
match self.upcast::<Node>().type_id() {
|
match self.upcast::<Node>().type_id() {
|
||||||
NodeTypeId::CharacterData(CharacterDataTypeId::Comment) => {
|
NodeTypeId::CharacterData(CharacterDataTypeId::Comment) => {
|
||||||
DomRoot::upcast(Comment::new(data, &document))
|
DomRoot::upcast(Comment::new(data, &document))
|
||||||
}
|
},
|
||||||
NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) => {
|
NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) => {
|
||||||
let pi = self.downcast::<ProcessingInstruction>().unwrap();
|
let pi = self.downcast::<ProcessingInstruction>().unwrap();
|
||||||
DomRoot::upcast(ProcessingInstruction::new(pi.Target(), data, &document))
|
DomRoot::upcast(ProcessingInstruction::new(pi.Target(), data, &document))
|
||||||
|
@ -107,7 +107,8 @@ impl CharacterDataMethods for CharacterData {
|
||||||
*self.data.borrow_mut() = data;
|
*self.data.borrow_mut() = data;
|
||||||
self.content_changed();
|
self.content_changed();
|
||||||
let node = self.upcast::<Node>();
|
let node = self.upcast::<Node>();
|
||||||
node.ranges().replace_code_units(node, 0, old_length, new_length);
|
node.ranges()
|
||||||
|
.replace_code_units(node, 0, old_length, new_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://dom.spec.whatwg.org/#dom-characterdata-length
|
// https://dom.spec.whatwg.org/#dom-characterdata-length
|
||||||
|
@ -130,7 +131,7 @@ impl CharacterDataMethods for CharacterData {
|
||||||
substring = substring + "\u{FFFD}";
|
substring = substring + "\u{FFFD}";
|
||||||
}
|
}
|
||||||
remaining = s;
|
remaining = s;
|
||||||
}
|
},
|
||||||
// Step 2.
|
// Step 2.
|
||||||
Err(()) => return Err(Error::IndexSize),
|
Err(()) => return Err(Error::IndexSize),
|
||||||
}
|
}
|
||||||
|
@ -146,7 +147,7 @@ impl CharacterDataMethods for CharacterData {
|
||||||
if astral.is_some() {
|
if astral.is_some() {
|
||||||
substring = substring + "\u{FFFD}";
|
substring = substring + "\u{FFFD}";
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
Ok(DOMString::from(substring))
|
Ok(DOMString::from(substring))
|
||||||
}
|
}
|
||||||
|
@ -183,7 +184,7 @@ impl CharacterDataMethods for CharacterData {
|
||||||
// since our DOMString is currently strict UTF-8.
|
// since our DOMString is currently strict UTF-8.
|
||||||
replacement_before = if astral.is_some() { "\u{FFFD}" } else { "" };
|
replacement_before = if astral.is_some() { "\u{FFFD}" } else { "" };
|
||||||
remaining = r;
|
remaining = r;
|
||||||
}
|
},
|
||||||
// Step 2.
|
// Step 2.
|
||||||
Err(()) => return Err(Error::IndexSize),
|
Err(()) => return Err(Error::IndexSize),
|
||||||
};
|
};
|
||||||
|
@ -194,14 +195,14 @@ impl CharacterDataMethods for CharacterData {
|
||||||
Err(()) => {
|
Err(()) => {
|
||||||
replacement_after = "";
|
replacement_after = "";
|
||||||
suffix = "";
|
suffix = "";
|
||||||
}
|
},
|
||||||
Ok((_, astral, s)) => {
|
Ok((_, astral, s)) => {
|
||||||
// As if we had split the UTF-16 surrogate pair in half
|
// As if we had split the UTF-16 surrogate pair in half
|
||||||
// and then transcoded that to UTF-8 lossily,
|
// and then transcoded that to UTF-8 lossily,
|
||||||
// since our DOMString is currently strict UTF-8.
|
// since our DOMString is currently strict UTF-8.
|
||||||
replacement_after = if astral.is_some() { "\u{FFFD}" } else { "" };
|
replacement_after = if astral.is_some() { "\u{FFFD}" } else { "" };
|
||||||
suffix = s;
|
suffix = s;
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
// Step 4: Mutation observers.
|
// Step 4: Mutation observers.
|
||||||
self.queue_mutation_record();
|
self.queue_mutation_record();
|
||||||
|
@ -212,7 +213,8 @@ impl CharacterDataMethods for CharacterData {
|
||||||
replacement_before.len() +
|
replacement_before.len() +
|
||||||
arg.len() +
|
arg.len() +
|
||||||
replacement_after.len() +
|
replacement_after.len() +
|
||||||
suffix.len());
|
suffix.len(),
|
||||||
|
);
|
||||||
new_data.push_str(prefix);
|
new_data.push_str(prefix);
|
||||||
new_data.push_str(replacement_before);
|
new_data.push_str(replacement_before);
|
||||||
new_data.push_str(&arg);
|
new_data.push_str(&arg);
|
||||||
|
@ -223,8 +225,8 @@ impl CharacterDataMethods for CharacterData {
|
||||||
self.content_changed();
|
self.content_changed();
|
||||||
// Steps 8-11.
|
// Steps 8-11.
|
||||||
let node = self.upcast::<Node>();
|
let node = self.upcast::<Node>();
|
||||||
node.ranges().replace_code_units(
|
node.ranges()
|
||||||
node, offset, count, arg.encode_utf16().count() as u32);
|
.replace_code_units(node, offset, count, arg.encode_utf16().count() as u32);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -251,12 +253,18 @@ impl CharacterDataMethods for CharacterData {
|
||||||
|
|
||||||
// https://dom.spec.whatwg.org/#dom-nondocumenttypechildnode-previouselementsibling
|
// https://dom.spec.whatwg.org/#dom-nondocumenttypechildnode-previouselementsibling
|
||||||
fn GetPreviousElementSibling(&self) -> Option<DomRoot<Element>> {
|
fn GetPreviousElementSibling(&self) -> Option<DomRoot<Element>> {
|
||||||
self.upcast::<Node>().preceding_siblings().filter_map(DomRoot::downcast).next()
|
self.upcast::<Node>()
|
||||||
|
.preceding_siblings()
|
||||||
|
.filter_map(DomRoot::downcast)
|
||||||
|
.next()
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://dom.spec.whatwg.org/#dom-nondocumenttypechildnode-nextelementsibling
|
// https://dom.spec.whatwg.org/#dom-nondocumenttypechildnode-nextelementsibling
|
||||||
fn GetNextElementSibling(&self) -> Option<DomRoot<Element>> {
|
fn GetNextElementSibling(&self) -> Option<DomRoot<Element>> {
|
||||||
self.upcast::<Node>().following_siblings().filter_map(DomRoot::downcast).next()
|
self.upcast::<Node>()
|
||||||
|
.following_siblings()
|
||||||
|
.filter_map(DomRoot::downcast)
|
||||||
|
.next()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -305,13 +313,15 @@ fn split_at_utf16_code_unit_offset(s: &str, offset: u32) -> Result<(&str, Option
|
||||||
if code_units == offset {
|
if code_units == offset {
|
||||||
if opts::get().replace_surrogates {
|
if opts::get().replace_surrogates {
|
||||||
debug_assert_eq!(c.len_utf8(), 4);
|
debug_assert_eq!(c.len_utf8(), 4);
|
||||||
return Ok((&s[..i], Some(c), &s[i + c.len_utf8()..]))
|
return Ok((&s[..i], Some(c), &s[i + c.len_utf8()..]));
|
||||||
}
|
}
|
||||||
panic!("\n\n\
|
panic!(
|
||||||
|
"\n\n\
|
||||||
Would split a surrogate pair in CharacterData API.\n\
|
Would split a surrogate pair in CharacterData API.\n\
|
||||||
If you see this in real content, please comment with the URL\n\
|
If you see this in real content, please comment with the URL\n\
|
||||||
on https://github.com/servo/servo/issues/6873\n\
|
on https://github.com/servo/servo/issues/6873\n\
|
||||||
\n");
|
\n"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
code_units += 1;
|
code_units += 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ pub struct Client {
|
||||||
url: ServoUrl,
|
url: ServoUrl,
|
||||||
frame_type: FrameType,
|
frame_type: FrameType,
|
||||||
#[ignore_malloc_size_of = "Defined in uuid"]
|
#[ignore_malloc_size_of = "Defined in uuid"]
|
||||||
id: Uuid
|
id: Uuid,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Client {
|
impl Client {
|
||||||
|
@ -31,14 +31,16 @@ impl Client {
|
||||||
active_worker: Default::default(),
|
active_worker: Default::default(),
|
||||||
url: url,
|
url: url,
|
||||||
frame_type: FrameType::None,
|
frame_type: FrameType::None,
|
||||||
id: Uuid::new_v4()
|
id: Uuid::new_v4(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(window: &Window) -> DomRoot<Client> {
|
pub fn new(window: &Window) -> DomRoot<Client> {
|
||||||
reflect_dom_object(Box::new(Client::new_inherited(window.get_url())),
|
reflect_dom_object(
|
||||||
|
Box::new(Client::new_inherited(window.get_url())),
|
||||||
window,
|
window,
|
||||||
Wrap)
|
Wrap,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn creation_url(&self) -> ServoUrl {
|
pub fn creation_url(&self) -> ServoUrl {
|
||||||
|
|
|
@ -34,45 +34,48 @@ impl CloseEvent {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_uninitialized(global: &GlobalScope) -> DomRoot<CloseEvent> {
|
pub fn new_uninitialized(global: &GlobalScope) -> DomRoot<CloseEvent> {
|
||||||
reflect_dom_object(Box::new(CloseEvent::new_inherited(false, 0, DOMString::new())),
|
reflect_dom_object(
|
||||||
|
Box::new(CloseEvent::new_inherited(false, 0, DOMString::new())),
|
||||||
global,
|
global,
|
||||||
CloseEventBinding::Wrap)
|
CloseEventBinding::Wrap,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(global: &GlobalScope,
|
pub fn new(
|
||||||
|
global: &GlobalScope,
|
||||||
type_: Atom,
|
type_: Atom,
|
||||||
bubbles: EventBubbles,
|
bubbles: EventBubbles,
|
||||||
cancelable: EventCancelable,
|
cancelable: EventCancelable,
|
||||||
wasClean: bool,
|
wasClean: bool,
|
||||||
code: u16,
|
code: u16,
|
||||||
reason: DOMString)
|
reason: DOMString,
|
||||||
-> DomRoot<CloseEvent> {
|
) -> DomRoot<CloseEvent> {
|
||||||
let event = Box::new(CloseEvent::new_inherited(wasClean, code, reason));
|
let event = Box::new(CloseEvent::new_inherited(wasClean, code, reason));
|
||||||
let ev = reflect_dom_object(event, global, CloseEventBinding::Wrap);
|
let ev = reflect_dom_object(event, global, CloseEventBinding::Wrap);
|
||||||
{
|
{
|
||||||
let event = ev.upcast::<Event>();
|
let event = ev.upcast::<Event>();
|
||||||
event.init_event(type_,
|
event.init_event(type_, bool::from(bubbles), bool::from(cancelable));
|
||||||
bool::from(bubbles),
|
|
||||||
bool::from(cancelable));
|
|
||||||
}
|
}
|
||||||
ev
|
ev
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn Constructor(global: &GlobalScope,
|
pub fn Constructor(
|
||||||
|
global: &GlobalScope,
|
||||||
type_: DOMString,
|
type_: DOMString,
|
||||||
init: &CloseEventBinding::CloseEventInit)
|
init: &CloseEventBinding::CloseEventInit,
|
||||||
-> Fallible<DomRoot<CloseEvent>> {
|
) -> Fallible<DomRoot<CloseEvent>> {
|
||||||
let bubbles = EventBubbles::from(init.parent.bubbles);
|
let bubbles = EventBubbles::from(init.parent.bubbles);
|
||||||
let cancelable = EventCancelable::from(init.parent.cancelable);
|
let cancelable = EventCancelable::from(init.parent.cancelable);
|
||||||
Ok(CloseEvent::new(global,
|
Ok(CloseEvent::new(
|
||||||
|
global,
|
||||||
Atom::from(type_),
|
Atom::from(type_),
|
||||||
bubbles,
|
bubbles,
|
||||||
cancelable,
|
cancelable,
|
||||||
init.wasClean,
|
init.wasClean,
|
||||||
init.code,
|
init.code,
|
||||||
init.reason.clone()))
|
init.reason.clone(),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CloseEventMethods for CloseEvent {
|
impl CloseEventMethods for CloseEvent {
|
||||||
|
|
|
@ -27,9 +27,11 @@ impl Comment {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(text: DOMString, document: &Document) -> DomRoot<Comment> {
|
pub fn new(text: DOMString, document: &Document) -> DomRoot<Comment> {
|
||||||
Node::reflect_node(Box::new(Comment::new_inherited(text, document)),
|
Node::reflect_node(
|
||||||
|
Box::new(Comment::new_inherited(text, document)),
|
||||||
document,
|
document,
|
||||||
CommentBinding::Wrap)
|
CommentBinding::Wrap,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn Constructor(window: &Window, data: DOMString) -> Fallible<DomRoot<Comment>> {
|
pub fn Constructor(window: &Window, data: DOMString) -> Fallible<DomRoot<Comment>> {
|
||||||
|
|
|
@ -19,34 +19,42 @@ pub struct CompositionEvent {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CompositionEvent {
|
impl CompositionEvent {
|
||||||
pub fn new(window: &Window,
|
pub fn new(
|
||||||
|
window: &Window,
|
||||||
type_: DOMString,
|
type_: DOMString,
|
||||||
can_bubble: bool,
|
can_bubble: bool,
|
||||||
cancelable: bool,
|
cancelable: bool,
|
||||||
view: Option<&Window>,
|
view: Option<&Window>,
|
||||||
detail: i32,
|
detail: i32,
|
||||||
data: DOMString) -> DomRoot<CompositionEvent> {
|
data: DOMString,
|
||||||
let ev = reflect_dom_object(Box::new(CompositionEvent {
|
) -> DomRoot<CompositionEvent> {
|
||||||
|
let ev = reflect_dom_object(
|
||||||
|
Box::new(CompositionEvent {
|
||||||
uievent: UIEvent::new_inherited(),
|
uievent: UIEvent::new_inherited(),
|
||||||
data: data,
|
data: data,
|
||||||
}),
|
}),
|
||||||
window,
|
window,
|
||||||
CompositionEventBinding::Wrap);
|
CompositionEventBinding::Wrap,
|
||||||
ev.uievent.InitUIEvent(type_, can_bubble, cancelable, view, detail);
|
);
|
||||||
|
ev.uievent
|
||||||
|
.InitUIEvent(type_, can_bubble, cancelable, view, detail);
|
||||||
ev
|
ev
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn Constructor(window: &Window,
|
pub fn Constructor(
|
||||||
|
window: &Window,
|
||||||
type_: DOMString,
|
type_: DOMString,
|
||||||
init: &CompositionEventBinding::CompositionEventInit)
|
init: &CompositionEventBinding::CompositionEventInit,
|
||||||
-> Fallible<DomRoot<CompositionEvent>> {
|
) -> Fallible<DomRoot<CompositionEvent>> {
|
||||||
let event = CompositionEvent::new(window,
|
let event = CompositionEvent::new(
|
||||||
|
window,
|
||||||
type_,
|
type_,
|
||||||
init.parent.parent.bubbles,
|
init.parent.parent.bubbles,
|
||||||
init.parent.parent.cancelable,
|
init.parent.parent.cancelable,
|
||||||
init.parent.view.r(),
|
init.parent.view.r(),
|
||||||
init.parent.detail,
|
init.parent.detail,
|
||||||
init.data.clone());
|
init.data.clone(),
|
||||||
|
);
|
||||||
Ok(event)
|
Ok(event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
|
@ -84,10 +84,11 @@ use js::jsapi::JSAutoCompartment;
|
||||||
use script_thread::ScriptThread;
|
use script_thread::ScriptThread;
|
||||||
use servo_config::prefs::PREFS;
|
use servo_config::prefs::PREFS;
|
||||||
|
|
||||||
fn create_svg_element(name: QualName,
|
fn create_svg_element(
|
||||||
|
name: QualName,
|
||||||
prefix: Option<Prefix>,
|
prefix: Option<Prefix>,
|
||||||
document: &Document)
|
document: &Document,
|
||||||
-> DomRoot<Element> {
|
) -> DomRoot<Element> {
|
||||||
assert_eq!(name.ns, ns!(svg));
|
assert_eq!(name.ns, ns!(svg));
|
||||||
|
|
||||||
macro_rules! make(
|
macro_rules! make(
|
||||||
|
@ -113,13 +114,14 @@ fn create_svg_element(name: QualName,
|
||||||
|
|
||||||
// https://dom.spec.whatwg.org/#concept-create-element
|
// https://dom.spec.whatwg.org/#concept-create-element
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
fn create_html_element(name: QualName,
|
fn create_html_element(
|
||||||
|
name: QualName,
|
||||||
prefix: Option<Prefix>,
|
prefix: Option<Prefix>,
|
||||||
is: Option<LocalName>,
|
is: Option<LocalName>,
|
||||||
document: &Document,
|
document: &Document,
|
||||||
creator: ElementCreator,
|
creator: ElementCreator,
|
||||||
mode: CustomElementCreationMode)
|
mode: CustomElementCreationMode,
|
||||||
-> DomRoot<Element> {
|
) -> DomRoot<Element> {
|
||||||
assert_eq!(name.ns, ns!(html));
|
assert_eq!(name.ns, ns!(html));
|
||||||
|
|
||||||
// Step 4
|
// Step 4
|
||||||
|
@ -129,8 +131,11 @@ fn create_html_element(name: QualName,
|
||||||
if definition.is_autonomous() {
|
if definition.is_autonomous() {
|
||||||
match mode {
|
match mode {
|
||||||
CustomElementCreationMode::Asynchronous => {
|
CustomElementCreationMode::Asynchronous => {
|
||||||
let result = DomRoot::upcast::<Element>(
|
let result = DomRoot::upcast::<Element>(HTMLElement::new(
|
||||||
HTMLElement::new(name.local.clone(), prefix.clone(), document));
|
name.local.clone(),
|
||||||
|
prefix.clone(),
|
||||||
|
document,
|
||||||
|
));
|
||||||
result.set_custom_element_state(CustomElementState::Undefined);
|
result.set_custom_element_state(CustomElementState::Undefined);
|
||||||
ScriptThread::enqueue_upgrade_reaction(&*result, definition);
|
ScriptThread::enqueue_upgrade_reaction(&*result, definition);
|
||||||
return result;
|
return result;
|
||||||
|
@ -144,19 +149,24 @@ fn create_html_element(name: QualName,
|
||||||
},
|
},
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
// Step 6. Recovering from exception.
|
// Step 6. Recovering from exception.
|
||||||
let global = GlobalScope::current().unwrap_or_else(|| document.global());
|
let global =
|
||||||
|
GlobalScope::current().unwrap_or_else(|| document.global());
|
||||||
let cx = global.get_cx();
|
let cx = global.get_cx();
|
||||||
|
|
||||||
// Step 6.1.1
|
// Step 6.1.1
|
||||||
unsafe {
|
unsafe {
|
||||||
let _ac = JSAutoCompartment::new(cx, global.reflector().get_jsobject().get());
|
let _ac = JSAutoCompartment::new(
|
||||||
|
cx,
|
||||||
|
global.reflector().get_jsobject().get(),
|
||||||
|
);
|
||||||
throw_dom_exception(cx, &global, error);
|
throw_dom_exception(cx, &global, error);
|
||||||
report_pending_exception(cx, true);
|
report_pending_exception(cx, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 6.1.2
|
// Step 6.1.2
|
||||||
let element = DomRoot::upcast::<Element>(
|
let element = DomRoot::upcast::<Element>(HTMLUnknownElement::new(
|
||||||
HTMLUnknownElement::new(local_name, prefix, document));
|
local_name, prefix, document,
|
||||||
|
));
|
||||||
element.set_custom_element_state(CustomElementState::Failed);
|
element.set_custom_element_state(CustomElementState::Failed);
|
||||||
element
|
element
|
||||||
},
|
},
|
||||||
|
@ -170,11 +180,11 @@ fn create_html_element(name: QualName,
|
||||||
element.set_custom_element_state(CustomElementState::Undefined);
|
element.set_custom_element_state(CustomElementState::Undefined);
|
||||||
match mode {
|
match mode {
|
||||||
// Step 5.3
|
// Step 5.3
|
||||||
CustomElementCreationMode::Synchronous =>
|
CustomElementCreationMode::Synchronous => upgrade_element(definition, &*element),
|
||||||
upgrade_element(definition, &*element),
|
|
||||||
// Step 5.4
|
// Step 5.4
|
||||||
CustomElementCreationMode::Asynchronous =>
|
CustomElementCreationMode::Asynchronous => {
|
||||||
ScriptThread::enqueue_upgrade_reaction(&*element, definition),
|
ScriptThread::enqueue_upgrade_reaction(&*element, definition)
|
||||||
|
},
|
||||||
}
|
}
|
||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
|
@ -360,16 +370,17 @@ pub fn create_native_html_element(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_element(name: QualName,
|
pub fn create_element(
|
||||||
|
name: QualName,
|
||||||
is: Option<LocalName>,
|
is: Option<LocalName>,
|
||||||
document: &Document,
|
document: &Document,
|
||||||
creator: ElementCreator,
|
creator: ElementCreator,
|
||||||
mode: CustomElementCreationMode)
|
mode: CustomElementCreationMode,
|
||||||
-> DomRoot<Element> {
|
) -> DomRoot<Element> {
|
||||||
let prefix = name.prefix.clone();
|
let prefix = name.prefix.clone();
|
||||||
match name.ns {
|
match name.ns {
|
||||||
ns!(html) => create_html_element(name, prefix, is, document, creator, mode),
|
ns!(html) => create_html_element(name, prefix, is, document, creator, mode),
|
||||||
ns!(svg) => create_svg_element(name, prefix, document),
|
ns!(svg) => create_svg_element(name, prefix, document),
|
||||||
_ => Element::new(name.local, name.ns, prefix, document)
|
_ => Element::new(name.local, name.ns, prefix, document),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,17 +36,22 @@ impl Crypto {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(global: &GlobalScope) -> DomRoot<Crypto> {
|
pub fn new(global: &GlobalScope) -> DomRoot<Crypto> {
|
||||||
reflect_dom_object(Box::new(Crypto::new_inherited()), global, CryptoBinding::Wrap)
|
reflect_dom_object(
|
||||||
|
Box::new(Crypto::new_inherited()),
|
||||||
|
global,
|
||||||
|
CryptoBinding::Wrap,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CryptoMethods for Crypto {
|
impl CryptoMethods for Crypto {
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
// https://dvcs.w3.org/hg/webcrypto-api/raw-file/tip/spec/Overview.html#Crypto-method-getRandomValues
|
// https://dvcs.w3.org/hg/webcrypto-api/raw-file/tip/spec/Overview.html#Crypto-method-getRandomValues
|
||||||
unsafe fn GetRandomValues(&self,
|
unsafe fn GetRandomValues(
|
||||||
|
&self,
|
||||||
_cx: *mut JSContext,
|
_cx: *mut JSContext,
|
||||||
mut input: CustomAutoRooterGuard<ArrayBufferView>)
|
mut input: CustomAutoRooterGuard<ArrayBufferView>,
|
||||||
-> Fallible<NonNull<JSObject>> {
|
) -> Fallible<NonNull<JSObject>> {
|
||||||
let array_type = input.get_array_type();
|
let array_type = input.get_array_type();
|
||||||
|
|
||||||
if !is_integer_buffer(array_type) {
|
if !is_integer_buffer(array_type) {
|
||||||
|
|
|
@ -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),
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,8 +22,10 @@ pub struct CSSFontFaceRule {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CSSFontFaceRule {
|
impl CSSFontFaceRule {
|
||||||
fn new_inherited(parent_stylesheet: &CSSStyleSheet, fontfacerule: Arc<Locked<FontFaceRule>>)
|
fn new_inherited(
|
||||||
-> CSSFontFaceRule {
|
parent_stylesheet: &CSSStyleSheet,
|
||||||
|
fontfacerule: Arc<Locked<FontFaceRule>>,
|
||||||
|
) -> CSSFontFaceRule {
|
||||||
CSSFontFaceRule {
|
CSSFontFaceRule {
|
||||||
cssrule: CSSRule::new_inherited(parent_stylesheet),
|
cssrule: CSSRule::new_inherited(parent_stylesheet),
|
||||||
fontfacerule: fontfacerule,
|
fontfacerule: fontfacerule,
|
||||||
|
@ -31,11 +33,19 @@ impl CSSFontFaceRule {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unrooted_must_root)]
|
#[allow(unrooted_must_root)]
|
||||||
pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet,
|
pub fn new(
|
||||||
fontfacerule: Arc<Locked<FontFaceRule>>) -> DomRoot<CSSFontFaceRule> {
|
window: &Window,
|
||||||
reflect_dom_object(Box::new(CSSFontFaceRule::new_inherited(parent_stylesheet, fontfacerule)),
|
parent_stylesheet: &CSSStyleSheet,
|
||||||
|
fontfacerule: Arc<Locked<FontFaceRule>>,
|
||||||
|
) -> DomRoot<CSSFontFaceRule> {
|
||||||
|
reflect_dom_object(
|
||||||
|
Box::new(CSSFontFaceRule::new_inherited(
|
||||||
|
parent_stylesheet,
|
||||||
|
fontfacerule,
|
||||||
|
)),
|
||||||
window,
|
window,
|
||||||
CSSFontFaceRuleBinding::Wrap)
|
CSSFontFaceRuleBinding::Wrap,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,6 +57,9 @@ impl SpecificCSSRule for CSSFontFaceRule {
|
||||||
|
|
||||||
fn get_css(&self) -> DOMString {
|
fn get_css(&self) -> DOMString {
|
||||||
let guard = self.cssrule.shared_lock().read();
|
let guard = self.cssrule.shared_lock().read();
|
||||||
self.fontfacerule.read_with(&guard).to_css_string(&guard).into()
|
self.fontfacerule
|
||||||
|
.read_with(&guard)
|
||||||
|
.to_css_string(&guard)
|
||||||
|
.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,8 +25,10 @@ pub struct CSSGroupingRule {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CSSGroupingRule {
|
impl CSSGroupingRule {
|
||||||
pub fn new_inherited(parent_stylesheet: &CSSStyleSheet,
|
pub fn new_inherited(
|
||||||
rules: Arc<Locked<StyleCssRules>>) -> CSSGroupingRule {
|
parent_stylesheet: &CSSStyleSheet,
|
||||||
|
rules: Arc<Locked<StyleCssRules>>,
|
||||||
|
) -> CSSGroupingRule {
|
||||||
CSSGroupingRule {
|
CSSGroupingRule {
|
||||||
cssrule: CSSRule::new_inherited(parent_stylesheet),
|
cssrule: CSSRule::new_inherited(parent_stylesheet),
|
||||||
rules: rules,
|
rules: rules,
|
||||||
|
@ -36,9 +38,13 @@ impl CSSGroupingRule {
|
||||||
|
|
||||||
fn rulelist(&self) -> DomRoot<CSSRuleList> {
|
fn rulelist(&self) -> DomRoot<CSSRuleList> {
|
||||||
let parent_stylesheet = self.upcast::<CSSRule>().parent_stylesheet();
|
let parent_stylesheet = self.upcast::<CSSRule>().parent_stylesheet();
|
||||||
self.rulelist.or_init(|| CSSRuleList::new(self.global().as_window(),
|
self.rulelist.or_init(|| {
|
||||||
|
CSSRuleList::new(
|
||||||
|
self.global().as_window(),
|
||||||
parent_stylesheet,
|
parent_stylesheet,
|
||||||
RulesSource::Rules(self.rules.clone())))
|
RulesSource::Rules(self.rules.clone()),
|
||||||
|
)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parent_stylesheet(&self) -> &CSSStyleSheet {
|
pub fn parent_stylesheet(&self) -> &CSSStyleSheet {
|
||||||
|
|
|
@ -22,9 +22,10 @@ pub struct CSSImportRule {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CSSImportRule {
|
impl CSSImportRule {
|
||||||
fn new_inherited(parent_stylesheet: &CSSStyleSheet,
|
fn new_inherited(
|
||||||
import_rule: Arc<Locked<ImportRule>>)
|
parent_stylesheet: &CSSStyleSheet,
|
||||||
-> Self {
|
import_rule: Arc<Locked<ImportRule>>,
|
||||||
|
) -> Self {
|
||||||
CSSImportRule {
|
CSSImportRule {
|
||||||
cssrule: CSSRule::new_inherited(parent_stylesheet),
|
cssrule: CSSRule::new_inherited(parent_stylesheet),
|
||||||
import_rule: import_rule,
|
import_rule: import_rule,
|
||||||
|
@ -32,12 +33,16 @@ impl CSSImportRule {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unrooted_must_root)]
|
#[allow(unrooted_must_root)]
|
||||||
pub fn new(window: &Window,
|
pub fn new(
|
||||||
|
window: &Window,
|
||||||
parent_stylesheet: &CSSStyleSheet,
|
parent_stylesheet: &CSSStyleSheet,
|
||||||
import_rule: Arc<Locked<ImportRule>>) -> DomRoot<Self> {
|
import_rule: Arc<Locked<ImportRule>>,
|
||||||
reflect_dom_object(Box::new(Self::new_inherited(parent_stylesheet, import_rule)),
|
) -> DomRoot<Self> {
|
||||||
|
reflect_dom_object(
|
||||||
|
Box::new(Self::new_inherited(parent_stylesheet, import_rule)),
|
||||||
window,
|
window,
|
||||||
CSSImportRuleBinding::Wrap)
|
CSSImportRuleBinding::Wrap,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,6 +54,9 @@ impl SpecificCSSRule for CSSImportRule {
|
||||||
|
|
||||||
fn get_css(&self) -> DOMString {
|
fn get_css(&self) -> DOMString {
|
||||||
let guard = self.cssrule.shared_lock().read();
|
let guard = self.cssrule.shared_lock().read();
|
||||||
self.import_rule.read_with(&guard).to_css_string(&guard).into()
|
self.import_rule
|
||||||
|
.read_with(&guard)
|
||||||
|
.to_css_string(&guard)
|
||||||
|
.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,8 +25,10 @@ pub struct CSSKeyframeRule {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CSSKeyframeRule {
|
impl CSSKeyframeRule {
|
||||||
fn new_inherited(parent_stylesheet: &CSSStyleSheet, keyframerule: Arc<Locked<Keyframe>>)
|
fn new_inherited(
|
||||||
-> CSSKeyframeRule {
|
parent_stylesheet: &CSSStyleSheet,
|
||||||
|
keyframerule: Arc<Locked<Keyframe>>,
|
||||||
|
) -> CSSKeyframeRule {
|
||||||
CSSKeyframeRule {
|
CSSKeyframeRule {
|
||||||
cssrule: CSSRule::new_inherited(parent_stylesheet),
|
cssrule: CSSRule::new_inherited(parent_stylesheet),
|
||||||
keyframerule: keyframerule,
|
keyframerule: keyframerule,
|
||||||
|
@ -35,11 +37,19 @@ impl CSSKeyframeRule {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unrooted_must_root)]
|
#[allow(unrooted_must_root)]
|
||||||
pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet,
|
pub fn new(
|
||||||
keyframerule: Arc<Locked<Keyframe>>) -> DomRoot<CSSKeyframeRule> {
|
window: &Window,
|
||||||
reflect_dom_object(Box::new(CSSKeyframeRule::new_inherited(parent_stylesheet, keyframerule)),
|
parent_stylesheet: &CSSStyleSheet,
|
||||||
|
keyframerule: Arc<Locked<Keyframe>>,
|
||||||
|
) -> DomRoot<CSSKeyframeRule> {
|
||||||
|
reflect_dom_object(
|
||||||
|
Box::new(CSSKeyframeRule::new_inherited(
|
||||||
|
parent_stylesheet,
|
||||||
|
keyframerule,
|
||||||
|
)),
|
||||||
window,
|
window,
|
||||||
CSSKeyframeRuleBinding::Wrap)
|
CSSKeyframeRuleBinding::Wrap,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,6 +79,9 @@ impl SpecificCSSRule for CSSKeyframeRule {
|
||||||
|
|
||||||
fn get_css(&self) -> DOMString {
|
fn get_css(&self) -> DOMString {
|
||||||
let guard = self.cssrule.shared_lock().read();
|
let guard = self.cssrule.shared_lock().read();
|
||||||
self.keyframerule.read_with(&guard).to_css_string(&guard).into()
|
self.keyframerule
|
||||||
|
.read_with(&guard)
|
||||||
|
.to_css_string(&guard)
|
||||||
|
.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,8 +30,10 @@ pub struct CSSKeyframesRule {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CSSKeyframesRule {
|
impl CSSKeyframesRule {
|
||||||
fn new_inherited(parent_stylesheet: &CSSStyleSheet, keyframesrule: Arc<Locked<KeyframesRule>>)
|
fn new_inherited(
|
||||||
-> CSSKeyframesRule {
|
parent_stylesheet: &CSSStyleSheet,
|
||||||
|
keyframesrule: Arc<Locked<KeyframesRule>>,
|
||||||
|
) -> CSSKeyframesRule {
|
||||||
CSSKeyframesRule {
|
CSSKeyframesRule {
|
||||||
cssrule: CSSRule::new_inherited(parent_stylesheet),
|
cssrule: CSSRule::new_inherited(parent_stylesheet),
|
||||||
keyframesrule: keyframesrule,
|
keyframesrule: keyframesrule,
|
||||||
|
@ -40,19 +42,29 @@ impl CSSKeyframesRule {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unrooted_must_root)]
|
#[allow(unrooted_must_root)]
|
||||||
pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet,
|
pub fn new(
|
||||||
keyframesrule: Arc<Locked<KeyframesRule>>) -> DomRoot<CSSKeyframesRule> {
|
window: &Window,
|
||||||
reflect_dom_object(Box::new(CSSKeyframesRule::new_inherited(parent_stylesheet, keyframesrule)),
|
parent_stylesheet: &CSSStyleSheet,
|
||||||
|
keyframesrule: Arc<Locked<KeyframesRule>>,
|
||||||
|
) -> DomRoot<CSSKeyframesRule> {
|
||||||
|
reflect_dom_object(
|
||||||
|
Box::new(CSSKeyframesRule::new_inherited(
|
||||||
|
parent_stylesheet,
|
||||||
|
keyframesrule,
|
||||||
|
)),
|
||||||
window,
|
window,
|
||||||
CSSKeyframesRuleBinding::Wrap)
|
CSSKeyframesRuleBinding::Wrap,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rulelist(&self) -> DomRoot<CSSRuleList> {
|
fn rulelist(&self) -> DomRoot<CSSRuleList> {
|
||||||
self.rulelist.or_init(|| {
|
self.rulelist.or_init(|| {
|
||||||
let parent_stylesheet = &self.upcast::<CSSRule>().parent_stylesheet();
|
let parent_stylesheet = &self.upcast::<CSSRule>().parent_stylesheet();
|
||||||
CSSRuleList::new(self.global().as_window(),
|
CSSRuleList::new(
|
||||||
|
self.global().as_window(),
|
||||||
parent_stylesheet,
|
parent_stylesheet,
|
||||||
RulesSource::Keyframes(self.keyframesrule.clone()))
|
RulesSource::Keyframes(self.keyframesrule.clone()),
|
||||||
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,10 +76,11 @@ impl CSSKeyframesRule {
|
||||||
let guard = self.cssrule.shared_lock().read();
|
let guard = self.cssrule.shared_lock().read();
|
||||||
// This finds the *last* element matching a selector
|
// This finds the *last* element matching a selector
|
||||||
// because that's the rule that applies. Thus, rposition
|
// because that's the rule that applies. Thus, rposition
|
||||||
self.keyframesrule.read_with(&guard)
|
self.keyframesrule
|
||||||
.keyframes.iter().rposition(|frame| {
|
.read_with(&guard)
|
||||||
frame.read_with(&guard).selector == sel
|
.keyframes
|
||||||
})
|
.iter()
|
||||||
|
.rposition(|frame| frame.read_with(&guard).selector == sel)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -86,12 +99,15 @@ impl CSSKeyframesRuleMethods for CSSKeyframesRule {
|
||||||
let rule = Keyframe::parse(
|
let rule = Keyframe::parse(
|
||||||
&rule,
|
&rule,
|
||||||
&style_stylesheet.contents,
|
&style_stylesheet.contents,
|
||||||
&style_stylesheet.shared_lock
|
&style_stylesheet.shared_lock,
|
||||||
);
|
);
|
||||||
|
|
||||||
if let Ok(rule) = rule {
|
if let Ok(rule) = rule {
|
||||||
let mut guard = self.cssrule.shared_lock().write();
|
let mut guard = self.cssrule.shared_lock().write();
|
||||||
self.keyframesrule.write_with(&mut guard).keyframes.push(rule);
|
self.keyframesrule
|
||||||
|
.write_with(&mut guard)
|
||||||
|
.keyframes
|
||||||
|
.push(rule);
|
||||||
self.rulelist().append_lazy_dom_rule();
|
self.rulelist().append_lazy_dom_rule();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -105,9 +121,9 @@ impl CSSKeyframesRuleMethods for CSSKeyframesRule {
|
||||||
|
|
||||||
// https://drafts.csswg.org/css-animations/#dom-csskeyframesrule-findrule
|
// https://drafts.csswg.org/css-animations/#dom-csskeyframesrule-findrule
|
||||||
fn FindRule(&self, selector: DOMString) -> Option<DomRoot<CSSKeyframeRule>> {
|
fn FindRule(&self, selector: DOMString) -> Option<DomRoot<CSSKeyframeRule>> {
|
||||||
self.find_rule(&selector).and_then(|idx| {
|
self.find_rule(&selector)
|
||||||
self.rulelist().item(idx as u32)
|
.and_then(|idx| self.rulelist().item(idx as u32))
|
||||||
}).and_then(DomRoot::downcast)
|
.and_then(DomRoot::downcast)
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://drafts.csswg.org/css-animations/#dom-csskeyframesrule-name
|
// https://drafts.csswg.org/css-animations/#dom-csskeyframesrule-name
|
||||||
|
@ -136,7 +152,10 @@ impl SpecificCSSRule for CSSKeyframesRule {
|
||||||
|
|
||||||
fn get_css(&self) -> DOMString {
|
fn get_css(&self) -> DOMString {
|
||||||
let guard = self.cssrule.shared_lock().read();
|
let guard = self.cssrule.shared_lock().read();
|
||||||
self.keyframesrule.read_with(&guard).to_css_string(&guard).into()
|
self.keyframesrule
|
||||||
|
.read_with(&guard)
|
||||||
|
.to_css_string(&guard)
|
||||||
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deparent_children(&self) {
|
fn deparent_children(&self) {
|
||||||
|
|
|
@ -31,8 +31,10 @@ pub struct CSSMediaRule {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CSSMediaRule {
|
impl CSSMediaRule {
|
||||||
fn new_inherited(parent_stylesheet: &CSSStyleSheet, mediarule: Arc<Locked<MediaRule>>)
|
fn new_inherited(
|
||||||
-> CSSMediaRule {
|
parent_stylesheet: &CSSStyleSheet,
|
||||||
|
mediarule: Arc<Locked<MediaRule>>,
|
||||||
|
) -> CSSMediaRule {
|
||||||
let guard = parent_stylesheet.shared_lock().read();
|
let guard = parent_stylesheet.shared_lock().read();
|
||||||
let list = mediarule.read_with(&guard).rules.clone();
|
let list = mediarule.read_with(&guard).rules.clone();
|
||||||
CSSMediaRule {
|
CSSMediaRule {
|
||||||
|
@ -43,19 +45,26 @@ impl CSSMediaRule {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unrooted_must_root)]
|
#[allow(unrooted_must_root)]
|
||||||
pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet,
|
pub fn new(
|
||||||
mediarule: Arc<Locked<MediaRule>>) -> DomRoot<CSSMediaRule> {
|
window: &Window,
|
||||||
reflect_dom_object(Box::new(CSSMediaRule::new_inherited(parent_stylesheet, mediarule)),
|
parent_stylesheet: &CSSStyleSheet,
|
||||||
|
mediarule: Arc<Locked<MediaRule>>,
|
||||||
|
) -> DomRoot<CSSMediaRule> {
|
||||||
|
reflect_dom_object(
|
||||||
|
Box::new(CSSMediaRule::new_inherited(parent_stylesheet, mediarule)),
|
||||||
window,
|
window,
|
||||||
CSSMediaRuleBinding::Wrap)
|
CSSMediaRuleBinding::Wrap,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn medialist(&self) -> DomRoot<MediaList> {
|
fn medialist(&self) -> DomRoot<MediaList> {
|
||||||
self.medialist.or_init(|| {
|
self.medialist.or_init(|| {
|
||||||
let guard = self.cssconditionrule.shared_lock().read();
|
let guard = self.cssconditionrule.shared_lock().read();
|
||||||
MediaList::new(self.global().as_window(),
|
MediaList::new(
|
||||||
|
self.global().as_window(),
|
||||||
self.cssconditionrule.parent_stylesheet(),
|
self.cssconditionrule.parent_stylesheet(),
|
||||||
self.mediarule.read_with(&guard).media_queries.clone())
|
self.mediarule.read_with(&guard).media_queries.clone(),
|
||||||
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,7 +115,10 @@ impl SpecificCSSRule for CSSMediaRule {
|
||||||
|
|
||||||
fn get_css(&self) -> DOMString {
|
fn get_css(&self) -> DOMString {
|
||||||
let guard = self.cssconditionrule.shared_lock().read();
|
let guard = self.cssconditionrule.shared_lock().read();
|
||||||
self.mediarule.read_with(&guard).to_css_string(&guard).into()
|
self.mediarule
|
||||||
|
.read_with(&guard)
|
||||||
|
.to_css_string(&guard)
|
||||||
|
.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,8 +23,10 @@ pub struct CSSNamespaceRule {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CSSNamespaceRule {
|
impl CSSNamespaceRule {
|
||||||
fn new_inherited(parent_stylesheet: &CSSStyleSheet, namespacerule: Arc<Locked<NamespaceRule>>)
|
fn new_inherited(
|
||||||
-> CSSNamespaceRule {
|
parent_stylesheet: &CSSStyleSheet,
|
||||||
|
namespacerule: Arc<Locked<NamespaceRule>>,
|
||||||
|
) -> CSSNamespaceRule {
|
||||||
CSSNamespaceRule {
|
CSSNamespaceRule {
|
||||||
cssrule: CSSRule::new_inherited(parent_stylesheet),
|
cssrule: CSSRule::new_inherited(parent_stylesheet),
|
||||||
namespacerule: namespacerule,
|
namespacerule: namespacerule,
|
||||||
|
@ -32,11 +34,19 @@ impl CSSNamespaceRule {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unrooted_must_root)]
|
#[allow(unrooted_must_root)]
|
||||||
pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet,
|
pub fn new(
|
||||||
namespacerule: Arc<Locked<NamespaceRule>>) -> DomRoot<CSSNamespaceRule> {
|
window: &Window,
|
||||||
reflect_dom_object(Box::new(CSSNamespaceRule::new_inherited(parent_stylesheet, namespacerule)),
|
parent_stylesheet: &CSSStyleSheet,
|
||||||
|
namespacerule: Arc<Locked<NamespaceRule>>,
|
||||||
|
) -> DomRoot<CSSNamespaceRule> {
|
||||||
|
reflect_dom_object(
|
||||||
|
Box::new(CSSNamespaceRule::new_inherited(
|
||||||
|
parent_stylesheet,
|
||||||
|
namespacerule,
|
||||||
|
)),
|
||||||
window,
|
window,
|
||||||
CSSNamespaceRuleBinding::Wrap)
|
CSSNamespaceRuleBinding::Wrap,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,8 +54,11 @@ impl CSSNamespaceRuleMethods for CSSNamespaceRule {
|
||||||
// https://drafts.csswg.org/cssom/#dom-cssnamespacerule-prefix
|
// https://drafts.csswg.org/cssom/#dom-cssnamespacerule-prefix
|
||||||
fn Prefix(&self) -> DOMString {
|
fn Prefix(&self) -> DOMString {
|
||||||
let guard = self.cssrule.shared_lock().read();
|
let guard = self.cssrule.shared_lock().read();
|
||||||
self.namespacerule.read_with(&guard).prefix
|
self.namespacerule
|
||||||
.as_ref().map(|s| s.to_string().into())
|
.read_with(&guard)
|
||||||
|
.prefix
|
||||||
|
.as_ref()
|
||||||
|
.map(|s| s.to_string().into())
|
||||||
.unwrap_or(DOMString::new())
|
.unwrap_or(DOMString::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,6 +77,9 @@ impl SpecificCSSRule for CSSNamespaceRule {
|
||||||
|
|
||||||
fn get_css(&self) -> DOMString {
|
fn get_css(&self) -> DOMString {
|
||||||
let guard = self.cssrule.shared_lock().read();
|
let guard = self.cssrule.shared_lock().read();
|
||||||
self.namespacerule.read_with(&guard).to_css_string(&guard).into()
|
self.namespacerule
|
||||||
|
.read_with(&guard)
|
||||||
|
.to_css_string(&guard)
|
||||||
|
.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ pub struct CSSRuleList {
|
||||||
parent_stylesheet: Dom<CSSStyleSheet>,
|
parent_stylesheet: Dom<CSSStyleSheet>,
|
||||||
#[ignore_malloc_size_of = "Arc"]
|
#[ignore_malloc_size_of = "Arc"]
|
||||||
rules: RulesSource,
|
rules: RulesSource,
|
||||||
dom_rules: DomRefCell<Vec<MutNullableDom<CSSRule>>>
|
dom_rules: DomRefCell<Vec<MutNullableDom<CSSRule>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum RulesSource {
|
pub enum RulesSource {
|
||||||
|
@ -52,12 +52,18 @@ impl CSSRuleList {
|
||||||
pub fn new_inherited(parent_stylesheet: &CSSStyleSheet, rules: RulesSource) -> CSSRuleList {
|
pub fn new_inherited(parent_stylesheet: &CSSStyleSheet, rules: RulesSource) -> CSSRuleList {
|
||||||
let guard = parent_stylesheet.shared_lock().read();
|
let guard = parent_stylesheet.shared_lock().read();
|
||||||
let dom_rules = match rules {
|
let dom_rules = match rules {
|
||||||
RulesSource::Rules(ref rules) => {
|
RulesSource::Rules(ref rules) => rules
|
||||||
rules.read_with(&guard).0.iter().map(|_| MutNullableDom::new(None)).collect()
|
.read_with(&guard)
|
||||||
}
|
.0
|
||||||
RulesSource::Keyframes(ref rules) => {
|
.iter()
|
||||||
rules.read_with(&guard).keyframes.iter().map(|_| MutNullableDom::new(None)).collect()
|
.map(|_| MutNullableDom::new(None))
|
||||||
}
|
.collect(),
|
||||||
|
RulesSource::Keyframes(ref rules) => rules
|
||||||
|
.read_with(&guard)
|
||||||
|
.keyframes
|
||||||
|
.iter()
|
||||||
|
.map(|_| MutNullableDom::new(None))
|
||||||
|
.collect(),
|
||||||
};
|
};
|
||||||
|
|
||||||
CSSRuleList {
|
CSSRuleList {
|
||||||
|
@ -69,11 +75,16 @@ impl CSSRuleList {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unrooted_must_root)]
|
#[allow(unrooted_must_root)]
|
||||||
pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet,
|
pub fn new(
|
||||||
rules: RulesSource) -> DomRoot<CSSRuleList> {
|
window: &Window,
|
||||||
reflect_dom_object(Box::new(CSSRuleList::new_inherited(parent_stylesheet, rules)),
|
parent_stylesheet: &CSSStyleSheet,
|
||||||
|
rules: RulesSource,
|
||||||
|
) -> DomRoot<CSSRuleList> {
|
||||||
|
reflect_dom_object(
|
||||||
|
Box::new(CSSRuleList::new_inherited(parent_stylesheet, rules)),
|
||||||
window,
|
window,
|
||||||
CSSRuleListBinding::Wrap)
|
CSSRuleListBinding::Wrap,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Should only be called for CssRules-backed rules. Use append_lazy_rule
|
/// Should only be called for CssRules-backed rules. Use append_lazy_rule
|
||||||
|
@ -91,18 +102,21 @@ impl CSSRuleList {
|
||||||
|
|
||||||
let parent_stylesheet = self.parent_stylesheet.style_stylesheet();
|
let parent_stylesheet = self.parent_stylesheet.style_stylesheet();
|
||||||
let new_rule = css_rules.with_raw_offset_arc(|arc| {
|
let new_rule = css_rules.with_raw_offset_arc(|arc| {
|
||||||
arc.insert_rule(&parent_stylesheet.shared_lock,
|
arc.insert_rule(
|
||||||
|
&parent_stylesheet.shared_lock,
|
||||||
rule,
|
rule,
|
||||||
&parent_stylesheet.contents,
|
&parent_stylesheet.contents,
|
||||||
index,
|
index,
|
||||||
nested,
|
nested,
|
||||||
None)
|
None,
|
||||||
|
)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
|
||||||
let parent_stylesheet = &*self.parent_stylesheet;
|
let parent_stylesheet = &*self.parent_stylesheet;
|
||||||
let dom_rule = CSSRule::new_specific(&window, parent_stylesheet, new_rule);
|
let dom_rule = CSSRule::new_specific(&window, parent_stylesheet, new_rule);
|
||||||
self.dom_rules.borrow_mut().insert(index, MutNullableDom::new(Some(&*dom_rule)));
|
self.dom_rules
|
||||||
|
.borrow_mut()
|
||||||
|
.insert(index, MutNullableDom::new(Some(&*dom_rule)));
|
||||||
Ok(idx)
|
Ok(idx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,7 +132,7 @@ impl CSSRuleList {
|
||||||
dom_rules[index].get().map(|r| r.detach());
|
dom_rules[index].get().map(|r| r.detach());
|
||||||
dom_rules.remove(index);
|
dom_rules.remove(index);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
},
|
||||||
RulesSource::Keyframes(ref kf) => {
|
RulesSource::Keyframes(ref kf) => {
|
||||||
// https://drafts.csswg.org/css-animations/#dom-csskeyframesrule-deleterule
|
// https://drafts.csswg.org/css-animations/#dom-csskeyframesrule-deleterule
|
||||||
let mut dom_rules = self.dom_rules.borrow_mut();
|
let mut dom_rules = self.dom_rules.borrow_mut();
|
||||||
|
@ -126,7 +140,7 @@ impl CSSRuleList {
|
||||||
dom_rules.remove(index);
|
dom_rules.remove(index);
|
||||||
kf.write_with(&mut guard).keyframes.remove(index);
|
kf.write_with(&mut guard).keyframes.remove(index);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,20 +157,17 @@ impl CSSRuleList {
|
||||||
let parent_stylesheet = &self.parent_stylesheet;
|
let parent_stylesheet = &self.parent_stylesheet;
|
||||||
let guard = parent_stylesheet.shared_lock().read();
|
let guard = parent_stylesheet.shared_lock().read();
|
||||||
match self.rules {
|
match self.rules {
|
||||||
RulesSource::Rules(ref rules) => {
|
RulesSource::Rules(ref rules) => CSSRule::new_specific(
|
||||||
CSSRule::new_specific(self.global().as_window(),
|
self.global().as_window(),
|
||||||
parent_stylesheet,
|
parent_stylesheet,
|
||||||
rules.read_with(&guard).0[idx as usize].clone())
|
rules.read_with(&guard).0[idx as usize].clone(),
|
||||||
}
|
),
|
||||||
RulesSource::Keyframes(ref rules) => {
|
RulesSource::Keyframes(ref rules) => DomRoot::upcast(CSSKeyframeRule::new(
|
||||||
DomRoot::upcast(CSSKeyframeRule::new(self.global().as_window(),
|
self.global().as_window(),
|
||||||
parent_stylesheet,
|
parent_stylesheet,
|
||||||
rules.read_with(&guard)
|
rules.read_with(&guard).keyframes[idx as usize].clone(),
|
||||||
.keyframes[idx as usize]
|
)),
|
||||||
.clone()))
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -190,4 +201,3 @@ impl CSSRuleListMethods for CSSRuleList {
|
||||||
self.Item(index)
|
self.Item(index)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,16 +36,18 @@ pub struct CSSStyleDeclaration {
|
||||||
#[must_root]
|
#[must_root]
|
||||||
pub enum CSSStyleOwner {
|
pub enum CSSStyleOwner {
|
||||||
Element(Dom<Element>),
|
Element(Dom<Element>),
|
||||||
CSSRule(Dom<CSSRule>,
|
CSSRule(
|
||||||
#[ignore_malloc_size_of = "Arc"]
|
Dom<CSSRule>,
|
||||||
Arc<Locked<PropertyDeclarationBlock>>),
|
#[ignore_malloc_size_of = "Arc"] Arc<Locked<PropertyDeclarationBlock>>,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CSSStyleOwner {
|
impl CSSStyleOwner {
|
||||||
// Mutate the declaration block associated to this style owner, and
|
// Mutate the declaration block associated to this style owner, and
|
||||||
// optionally indicate if it has changed (assumed to be true).
|
// optionally indicate if it has changed (assumed to be true).
|
||||||
fn mutate_associated_block<F, R>(&self, f: F) -> R
|
fn mutate_associated_block<F, R>(&self, f: F) -> R
|
||||||
where F: FnOnce(&mut PropertyDeclarationBlock, &mut bool) -> R,
|
where
|
||||||
|
F: FnOnce(&mut PropertyDeclarationBlock, &mut bool) -> R,
|
||||||
{
|
{
|
||||||
// TODO(emilio): This has some duplication just to avoid dummy clones.
|
// TODO(emilio): This has some duplication just to avoid dummy clones.
|
||||||
//
|
//
|
||||||
|
@ -87,9 +89,10 @@ impl CSSStyleOwner {
|
||||||
let guard = shared_lock.read();
|
let guard = shared_lock.read();
|
||||||
let mut serialization = String::new();
|
let mut serialization = String::new();
|
||||||
pdb.read_with(&guard).to_css(&mut serialization).unwrap();
|
pdb.read_with(&guard).to_css(&mut serialization).unwrap();
|
||||||
el.set_attribute(&local_name!("style"),
|
el.set_attribute(
|
||||||
AttrValue::Declaration(serialization,
|
&local_name!("style"),
|
||||||
pdb));
|
AttrValue::Declaration(serialization, pdb),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Remember to put it back.
|
// Remember to put it back.
|
||||||
|
@ -97,7 +100,7 @@ impl CSSStyleOwner {
|
||||||
}
|
}
|
||||||
|
|
||||||
result
|
result
|
||||||
}
|
},
|
||||||
CSSStyleOwner::CSSRule(ref rule, ref pdb) => {
|
CSSStyleOwner::CSSRule(ref rule, ref pdb) => {
|
||||||
let result = {
|
let result = {
|
||||||
let mut guard = rule.shared_lock().write();
|
let mut guard = rule.shared_lock().write();
|
||||||
|
@ -106,34 +109,36 @@ impl CSSStyleOwner {
|
||||||
if changed {
|
if changed {
|
||||||
// If this is changed, see also
|
// If this is changed, see also
|
||||||
// CSSStyleRule::SetSelectorText, which does the same thing.
|
// CSSStyleRule::SetSelectorText, which does the same thing.
|
||||||
rule.global().as_window().Document().invalidate_stylesheets();
|
rule.global()
|
||||||
|
.as_window()
|
||||||
|
.Document()
|
||||||
|
.invalidate_stylesheets();
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_block<F, R>(&self, f: F) -> R
|
fn with_block<F, R>(&self, f: F) -> R
|
||||||
where F: FnOnce(&PropertyDeclarationBlock) -> R,
|
where
|
||||||
|
F: FnOnce(&PropertyDeclarationBlock) -> R,
|
||||||
{
|
{
|
||||||
match *self {
|
match *self {
|
||||||
CSSStyleOwner::Element(ref el) => {
|
CSSStyleOwner::Element(ref el) => match *el.style_attribute().borrow() {
|
||||||
match *el.style_attribute().borrow() {
|
|
||||||
Some(ref pdb) => {
|
Some(ref pdb) => {
|
||||||
let document = document_from_node(&**el);
|
let document = document_from_node(&**el);
|
||||||
let guard = document.style_shared_lock().read();
|
let guard = document.style_shared_lock().read();
|
||||||
f(pdb.read_with(&guard))
|
f(pdb.read_with(&guard))
|
||||||
}
|
},
|
||||||
None => {
|
None => {
|
||||||
let pdb = PropertyDeclarationBlock::new();
|
let pdb = PropertyDeclarationBlock::new();
|
||||||
f(&pdb)
|
f(&pdb)
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
|
||||||
CSSStyleOwner::CSSRule(ref rule, ref pdb) => {
|
CSSStyleOwner::CSSRule(ref rule, ref pdb) => {
|
||||||
let guard = rule.shared_lock().read();
|
let guard = rule.shared_lock().read();
|
||||||
f(pdb.read_with(&guard))
|
f(pdb.read_with(&guard))
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,9 +152,12 @@ impl CSSStyleOwner {
|
||||||
fn base_url(&self) -> ServoUrl {
|
fn base_url(&self) -> ServoUrl {
|
||||||
match *self {
|
match *self {
|
||||||
CSSStyleOwner::Element(ref el) => window_from_node(&**el).Document().base_url(),
|
CSSStyleOwner::Element(ref el) => window_from_node(&**el).Document().base_url(),
|
||||||
CSSStyleOwner::CSSRule(ref rule, _) => {
|
CSSStyleOwner::CSSRule(ref rule, _) => (*rule
|
||||||
(*rule.parent_stylesheet().style_stylesheet().contents.url_data.read()).clone()
|
.parent_stylesheet()
|
||||||
}
|
.style_stylesheet()
|
||||||
|
.contents
|
||||||
|
.url_data
|
||||||
|
.read()).clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -181,10 +189,7 @@ macro_rules! css_properties(
|
||||||
);
|
);
|
||||||
);
|
);
|
||||||
|
|
||||||
fn remove_property(
|
fn remove_property(decls: &mut PropertyDeclarationBlock, id: &PropertyId) -> bool {
|
||||||
decls: &mut PropertyDeclarationBlock,
|
|
||||||
id: &PropertyId,
|
|
||||||
) -> bool {
|
|
||||||
let first_declaration = decls.first_declaration_to_remove(id);
|
let first_declaration = decls.first_declaration_to_remove(id);
|
||||||
let first_declaration = match first_declaration {
|
let first_declaration = match first_declaration {
|
||||||
Some(i) => i,
|
Some(i) => i,
|
||||||
|
@ -196,10 +201,11 @@ fn remove_property(
|
||||||
|
|
||||||
impl CSSStyleDeclaration {
|
impl CSSStyleDeclaration {
|
||||||
#[allow(unrooted_must_root)]
|
#[allow(unrooted_must_root)]
|
||||||
pub fn new_inherited(owner: CSSStyleOwner,
|
pub fn new_inherited(
|
||||||
|
owner: CSSStyleOwner,
|
||||||
pseudo: Option<PseudoElement>,
|
pseudo: Option<PseudoElement>,
|
||||||
modification_access: CSSModificationAccess)
|
modification_access: CSSModificationAccess,
|
||||||
-> CSSStyleDeclaration {
|
) -> CSSStyleDeclaration {
|
||||||
CSSStyleDeclaration {
|
CSSStyleDeclaration {
|
||||||
reflector_: Reflector::new(),
|
reflector_: Reflector::new(),
|
||||||
owner: owner,
|
owner: owner,
|
||||||
|
@ -209,22 +215,28 @@ impl CSSStyleDeclaration {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unrooted_must_root)]
|
#[allow(unrooted_must_root)]
|
||||||
pub fn new(global: &Window,
|
pub fn new(
|
||||||
|
global: &Window,
|
||||||
owner: CSSStyleOwner,
|
owner: CSSStyleOwner,
|
||||||
pseudo: Option<PseudoElement>,
|
pseudo: Option<PseudoElement>,
|
||||||
modification_access: CSSModificationAccess)
|
modification_access: CSSModificationAccess,
|
||||||
-> DomRoot<CSSStyleDeclaration> {
|
) -> DomRoot<CSSStyleDeclaration> {
|
||||||
reflect_dom_object(
|
reflect_dom_object(
|
||||||
Box::new(CSSStyleDeclaration::new_inherited(owner, pseudo, modification_access)),
|
Box::new(CSSStyleDeclaration::new_inherited(
|
||||||
|
owner,
|
||||||
|
pseudo,
|
||||||
|
modification_access,
|
||||||
|
)),
|
||||||
global,
|
global,
|
||||||
CSSStyleDeclarationBinding::Wrap
|
CSSStyleDeclarationBinding::Wrap,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_computed_style(&self, property: PropertyId) -> DOMString {
|
fn get_computed_style(&self, property: PropertyId) -> DOMString {
|
||||||
match self.owner {
|
match self.owner {
|
||||||
CSSStyleOwner::CSSRule(..) =>
|
CSSStyleOwner::CSSRule(..) => {
|
||||||
panic!("get_computed_style called on CSSStyleDeclaration with a CSSRule owner"),
|
panic!("get_computed_style called on CSSStyleDeclaration with a CSSRule owner")
|
||||||
|
},
|
||||||
CSSStyleOwner::Element(ref el) => {
|
CSSStyleOwner::Element(ref el) => {
|
||||||
let node = el.upcast::<Node>();
|
let node = el.upcast::<Node>();
|
||||||
if !node.is_in_doc() {
|
if !node.is_in_doc() {
|
||||||
|
@ -234,7 +246,7 @@ impl CSSStyleDeclaration {
|
||||||
}
|
}
|
||||||
let addr = node.to_trusted_node_address();
|
let addr = node.to_trusted_node_address();
|
||||||
window_from_node(node).resolved_style_query(addr, self.pseudo.clone(), property)
|
window_from_node(node).resolved_style_query(addr, self.pseudo.clone(), property)
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -277,7 +289,7 @@ impl CSSStyleDeclaration {
|
||||||
_ => {
|
_ => {
|
||||||
*changed = false;
|
*changed = false;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// Step 5
|
// Step 5
|
||||||
|
@ -300,12 +312,11 @@ impl CSSStyleDeclaration {
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
*changed = false;
|
*changed = false;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut updates = Default::default();
|
let mut updates = Default::default();
|
||||||
*changed =
|
*changed = pdb.prepare_for_update(&declarations, importance, &mut updates);
|
||||||
pdb.prepare_for_update(&declarations, importance, &mut updates);
|
|
||||||
|
|
||||||
if !*changed {
|
if !*changed {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
@ -323,9 +334,7 @@ impl CSSStyleDeclaration {
|
||||||
impl CSSStyleDeclarationMethods for CSSStyleDeclaration {
|
impl CSSStyleDeclarationMethods for CSSStyleDeclaration {
|
||||||
// https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-length
|
// https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-length
|
||||||
fn Length(&self) -> u32 {
|
fn Length(&self) -> u32 {
|
||||||
self.owner.with_block(|pdb| {
|
self.owner.with_block(|pdb| pdb.declarations().len() as u32)
|
||||||
pdb.declarations().len() as u32
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-item
|
// https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-item
|
||||||
|
@ -360,11 +369,12 @@ impl CSSStyleDeclarationMethods for CSSStyleDeclaration {
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-setproperty
|
// https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-setproperty
|
||||||
fn SetProperty(&self,
|
fn SetProperty(
|
||||||
|
&self,
|
||||||
property: DOMString,
|
property: DOMString,
|
||||||
value: DOMString,
|
value: DOMString,
|
||||||
priority: DOMString)
|
priority: DOMString,
|
||||||
-> ErrorResult {
|
) -> ErrorResult {
|
||||||
// Step 3
|
// Step 3
|
||||||
let id = match PropertyId::parse_enabled_for_all_content(&property) {
|
let id = match PropertyId::parse_enabled_for_all_content(&property) {
|
||||||
Ok(id) => id,
|
Ok(id) => id,
|
||||||
|
@ -444,10 +454,12 @@ impl CSSStyleDeclarationMethods for CSSStyleDeclaration {
|
||||||
let quirks_mode = window.Document().quirks_mode();
|
let quirks_mode = window.Document().quirks_mode();
|
||||||
self.owner.mutate_associated_block(|pdb, _changed| {
|
self.owner.mutate_associated_block(|pdb, _changed| {
|
||||||
// Step 3
|
// Step 3
|
||||||
*pdb = parse_style_attribute(&value,
|
*pdb = parse_style_attribute(
|
||||||
|
&value,
|
||||||
&self.owner.base_url(),
|
&self.owner.base_url(),
|
||||||
window.css_error_reporter(),
|
window.css_error_reporter(),
|
||||||
quirks_mode);
|
quirks_mode,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -31,8 +31,10 @@ pub struct CSSStyleRule {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CSSStyleRule {
|
impl CSSStyleRule {
|
||||||
fn new_inherited(parent_stylesheet: &CSSStyleSheet, stylerule: Arc<Locked<StyleRule>>)
|
fn new_inherited(
|
||||||
-> CSSStyleRule {
|
parent_stylesheet: &CSSStyleSheet,
|
||||||
|
stylerule: Arc<Locked<StyleRule>>,
|
||||||
|
) -> CSSStyleRule {
|
||||||
CSSStyleRule {
|
CSSStyleRule {
|
||||||
cssrule: CSSRule::new_inherited(parent_stylesheet),
|
cssrule: CSSRule::new_inherited(parent_stylesheet),
|
||||||
stylerule: stylerule,
|
stylerule: stylerule,
|
||||||
|
@ -41,11 +43,16 @@ impl CSSStyleRule {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unrooted_must_root)]
|
#[allow(unrooted_must_root)]
|
||||||
pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet,
|
pub fn new(
|
||||||
stylerule: Arc<Locked<StyleRule>>) -> DomRoot<CSSStyleRule> {
|
window: &Window,
|
||||||
reflect_dom_object(Box::new(CSSStyleRule::new_inherited(parent_stylesheet, stylerule)),
|
parent_stylesheet: &CSSStyleSheet,
|
||||||
|
stylerule: Arc<Locked<StyleRule>>,
|
||||||
|
) -> DomRoot<CSSStyleRule> {
|
||||||
|
reflect_dom_object(
|
||||||
|
Box::new(CSSStyleRule::new_inherited(parent_stylesheet, stylerule)),
|
||||||
window,
|
window,
|
||||||
CSSStyleRuleBinding::Wrap)
|
CSSStyleRuleBinding::Wrap,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,7 +64,10 @@ impl SpecificCSSRule for CSSStyleRule {
|
||||||
|
|
||||||
fn get_css(&self) -> DOMString {
|
fn get_css(&self) -> DOMString {
|
||||||
let guard = self.cssrule.shared_lock().read();
|
let guard = self.cssrule.shared_lock().read();
|
||||||
self.stylerule.read_with(&guard).to_css_string(&guard).into()
|
self.stylerule
|
||||||
|
.read_with(&guard)
|
||||||
|
.to_css_string(&guard)
|
||||||
|
.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,10 +80,10 @@ impl CSSStyleRuleMethods for CSSStyleRule {
|
||||||
self.global().as_window(),
|
self.global().as_window(),
|
||||||
CSSStyleOwner::CSSRule(
|
CSSStyleOwner::CSSRule(
|
||||||
Dom::from_ref(self.upcast()),
|
Dom::from_ref(self.upcast()),
|
||||||
self.stylerule.read_with(&guard).block.clone()
|
self.stylerule.read_with(&guard).block.clone(),
|
||||||
),
|
),
|
||||||
None,
|
None,
|
||||||
CSSModificationAccess::ReadWrite
|
CSSModificationAccess::ReadWrite,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -89,7 +99,13 @@ impl CSSStyleRuleMethods for CSSStyleRule {
|
||||||
fn SetSelectorText(&self, value: DOMString) {
|
fn SetSelectorText(&self, value: DOMString) {
|
||||||
// It's not clear from the spec if we should use the stylesheet's namespaces.
|
// It's not clear from the spec if we should use the stylesheet's namespaces.
|
||||||
// https://github.com/w3c/csswg-drafts/issues/1511
|
// https://github.com/w3c/csswg-drafts/issues/1511
|
||||||
let namespaces = self.cssrule.parent_stylesheet().style_stylesheet().contents.namespaces.read();
|
let namespaces = self
|
||||||
|
.cssrule
|
||||||
|
.parent_stylesheet()
|
||||||
|
.style_stylesheet()
|
||||||
|
.contents
|
||||||
|
.namespaces
|
||||||
|
.read();
|
||||||
let parser = SelectorParser {
|
let parser = SelectorParser {
|
||||||
stylesheet_origin: Origin::Author,
|
stylesheet_origin: Origin::Author,
|
||||||
namespaces: &namespaces,
|
namespaces: &namespaces,
|
||||||
|
@ -104,7 +120,10 @@ impl CSSStyleRuleMethods for CSSStyleRule {
|
||||||
mem::swap(&mut stylerule.selectors, &mut s);
|
mem::swap(&mut stylerule.selectors, &mut s);
|
||||||
// It seems like we will want to avoid having to invalidate all
|
// It seems like we will want to avoid having to invalidate all
|
||||||
// stylesheets eventually!
|
// stylesheets eventually!
|
||||||
self.global().as_window().Document().invalidate_stylesheets();
|
self.global()
|
||||||
|
.as_window()
|
||||||
|
.Document()
|
||||||
|
.invalidate_stylesheets();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,11 +30,13 @@ pub struct CSSStyleSheet {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CSSStyleSheet {
|
impl CSSStyleSheet {
|
||||||
fn new_inherited(owner: &Element,
|
fn new_inherited(
|
||||||
|
owner: &Element,
|
||||||
type_: DOMString,
|
type_: DOMString,
|
||||||
href: Option<DOMString>,
|
href: Option<DOMString>,
|
||||||
title: Option<DOMString>,
|
title: Option<DOMString>,
|
||||||
stylesheet: Arc<StyleStyleSheet>) -> CSSStyleSheet {
|
stylesheet: Arc<StyleStyleSheet>,
|
||||||
|
) -> CSSStyleSheet {
|
||||||
CSSStyleSheet {
|
CSSStyleSheet {
|
||||||
stylesheet: StyleSheet::new_inherited(type_, href, title),
|
stylesheet: StyleSheet::new_inherited(type_, href, title),
|
||||||
owner: Dom::from_ref(owner),
|
owner: Dom::from_ref(owner),
|
||||||
|
@ -45,25 +47,27 @@ impl CSSStyleSheet {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unrooted_must_root)]
|
#[allow(unrooted_must_root)]
|
||||||
pub fn new(window: &Window,
|
pub fn new(
|
||||||
|
window: &Window,
|
||||||
owner: &Element,
|
owner: &Element,
|
||||||
type_: DOMString,
|
type_: DOMString,
|
||||||
href: Option<DOMString>,
|
href: Option<DOMString>,
|
||||||
title: Option<DOMString>,
|
title: Option<DOMString>,
|
||||||
stylesheet: Arc<StyleStyleSheet>) -> DomRoot<CSSStyleSheet> {
|
stylesheet: Arc<StyleStyleSheet>,
|
||||||
reflect_dom_object(Box::new(CSSStyleSheet::new_inherited(owner, type_, href, title, stylesheet)),
|
) -> DomRoot<CSSStyleSheet> {
|
||||||
|
reflect_dom_object(
|
||||||
|
Box::new(CSSStyleSheet::new_inherited(
|
||||||
|
owner, type_, href, title, stylesheet,
|
||||||
|
)),
|
||||||
window,
|
window,
|
||||||
CSSStyleSheetBinding::Wrap)
|
CSSStyleSheetBinding::Wrap,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rulelist(&self) -> DomRoot<CSSRuleList> {
|
fn rulelist(&self) -> DomRoot<CSSRuleList> {
|
||||||
self.rulelist.or_init(|| {
|
self.rulelist.or_init(|| {
|
||||||
let rules = self.style_stylesheet.contents.rules.clone();
|
let rules = self.style_stylesheet.contents.rules.clone();
|
||||||
CSSRuleList::new(
|
CSSRuleList::new(self.global().as_window(), self, RulesSource::Rules(rules))
|
||||||
self.global().as_window(),
|
|
||||||
self,
|
|
||||||
RulesSource::Rules(rules)
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,7 +77,10 @@ impl CSSStyleSheet {
|
||||||
|
|
||||||
pub fn set_disabled(&self, disabled: bool) {
|
pub fn set_disabled(&self, disabled: bool) {
|
||||||
if self.style_stylesheet.set_disabled(disabled) {
|
if self.style_stylesheet.set_disabled(disabled) {
|
||||||
self.global().as_window().Document().invalidate_stylesheets();
|
self.global()
|
||||||
|
.as_window()
|
||||||
|
.Document()
|
||||||
|
.invalidate_stylesheets();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,7 +111,8 @@ impl CSSStyleSheetMethods for CSSStyleSheet {
|
||||||
if !self.origin_clean.get() {
|
if !self.origin_clean.get() {
|
||||||
return Err(Error::Security);
|
return Err(Error::Security);
|
||||||
}
|
}
|
||||||
self.rulelist().insert_rule(&rule, index, /* nested */ false)
|
self.rulelist()
|
||||||
|
.insert_rule(&rule, index, /* nested */ false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://drafts.csswg.org/cssom/#dom-cssstylesheet-deleterule
|
// https://drafts.csswg.org/cssom/#dom-cssstylesheet-deleterule
|
||||||
|
@ -115,4 +123,3 @@ impl CSSStyleSheetMethods for CSSStyleSheet {
|
||||||
self.rulelist().remove_rule(index)
|
self.rulelist().remove_rule(index)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,8 +28,10 @@ pub struct CSSSupportsRule {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CSSSupportsRule {
|
impl CSSSupportsRule {
|
||||||
fn new_inherited(parent_stylesheet: &CSSStyleSheet, supportsrule: Arc<Locked<SupportsRule>>)
|
fn new_inherited(
|
||||||
-> CSSSupportsRule {
|
parent_stylesheet: &CSSStyleSheet,
|
||||||
|
supportsrule: Arc<Locked<SupportsRule>>,
|
||||||
|
) -> CSSSupportsRule {
|
||||||
let guard = parent_stylesheet.shared_lock().read();
|
let guard = parent_stylesheet.shared_lock().read();
|
||||||
let list = supportsrule.read_with(&guard).rules.clone();
|
let list = supportsrule.read_with(&guard).rules.clone();
|
||||||
CSSSupportsRule {
|
CSSSupportsRule {
|
||||||
|
@ -39,11 +41,19 @@ impl CSSSupportsRule {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unrooted_must_root)]
|
#[allow(unrooted_must_root)]
|
||||||
pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet,
|
pub fn new(
|
||||||
supportsrule: Arc<Locked<SupportsRule>>) -> DomRoot<CSSSupportsRule> {
|
window: &Window,
|
||||||
reflect_dom_object(Box::new(CSSSupportsRule::new_inherited(parent_stylesheet, supportsrule)),
|
parent_stylesheet: &CSSStyleSheet,
|
||||||
|
supportsrule: Arc<Locked<SupportsRule>>,
|
||||||
|
) -> DomRoot<CSSSupportsRule> {
|
||||||
|
reflect_dom_object(
|
||||||
|
Box::new(CSSSupportsRule::new_inherited(
|
||||||
|
parent_stylesheet,
|
||||||
|
supportsrule,
|
||||||
|
)),
|
||||||
window,
|
window,
|
||||||
CSSSupportsRuleBinding::Wrap)
|
CSSSupportsRuleBinding::Wrap,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <https://drafts.csswg.org/css-conditional-3/#the-csssupportsrule-interface>
|
/// <https://drafts.csswg.org/css-conditional-3/#the-csssupportsrule-interface>
|
||||||
|
@ -88,6 +98,9 @@ impl SpecificCSSRule for CSSSupportsRule {
|
||||||
|
|
||||||
fn get_css(&self) -> DOMString {
|
fn get_css(&self) -> DOMString {
|
||||||
let guard = self.cssconditionrule.shared_lock().read();
|
let guard = self.cssconditionrule.shared_lock().read();
|
||||||
self.supportsrule.read_with(&guard).to_css_string(&guard).into()
|
self.supportsrule
|
||||||
|
.read_with(&guard)
|
||||||
|
.to_css_string(&guard)
|
||||||
|
.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,10 @@ pub struct CSSViewportRule {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CSSViewportRule {
|
impl CSSViewportRule {
|
||||||
fn new_inherited(parent_stylesheet: &CSSStyleSheet, viewportrule: Arc<Locked<ViewportRule>>) -> CSSViewportRule {
|
fn new_inherited(
|
||||||
|
parent_stylesheet: &CSSStyleSheet,
|
||||||
|
viewportrule: Arc<Locked<ViewportRule>>,
|
||||||
|
) -> CSSViewportRule {
|
||||||
CSSViewportRule {
|
CSSViewportRule {
|
||||||
cssrule: CSSRule::new_inherited(parent_stylesheet),
|
cssrule: CSSRule::new_inherited(parent_stylesheet),
|
||||||
viewportrule: viewportrule,
|
viewportrule: viewportrule,
|
||||||
|
@ -30,11 +33,19 @@ impl CSSViewportRule {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unrooted_must_root)]
|
#[allow(unrooted_must_root)]
|
||||||
pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet,
|
pub fn new(
|
||||||
viewportrule: Arc<Locked<ViewportRule>>) -> DomRoot<CSSViewportRule> {
|
window: &Window,
|
||||||
reflect_dom_object(Box::new(CSSViewportRule::new_inherited(parent_stylesheet, viewportrule)),
|
parent_stylesheet: &CSSStyleSheet,
|
||||||
|
viewportrule: Arc<Locked<ViewportRule>>,
|
||||||
|
) -> DomRoot<CSSViewportRule> {
|
||||||
|
reflect_dom_object(
|
||||||
|
Box::new(CSSViewportRule::new_inherited(
|
||||||
|
parent_stylesheet,
|
||||||
|
viewportrule,
|
||||||
|
)),
|
||||||
window,
|
window,
|
||||||
CSSViewportRuleBinding::Wrap)
|
CSSViewportRuleBinding::Wrap,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,6 +57,9 @@ impl SpecificCSSRule for CSSViewportRule {
|
||||||
|
|
||||||
fn get_css(&self) -> DOMString {
|
fn get_css(&self) -> DOMString {
|
||||||
let guard = self.cssrule.shared_lock().read();
|
let guard = self.cssrule.shared_lock().read();
|
||||||
self.viewportrule.read_with(&guard).to_css_string(&guard).into()
|
self.viewportrule
|
||||||
|
.read_with(&guard)
|
||||||
|
.to_css_string(&guard)
|
||||||
|
.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,9 +71,11 @@ impl CustomElementRegistry {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(window: &Window) -> DomRoot<CustomElementRegistry> {
|
pub fn new(window: &Window) -> DomRoot<CustomElementRegistry> {
|
||||||
reflect_dom_object(Box::new(CustomElementRegistry::new_inherited(window)),
|
reflect_dom_object(
|
||||||
|
Box::new(CustomElementRegistry::new_inherited(window)),
|
||||||
window,
|
window,
|
||||||
CustomElementRegistryBinding::Wrap)
|
CustomElementRegistryBinding::Wrap,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Cleans up any active promises
|
/// Cleans up any active promises
|
||||||
|
@ -83,40 +85,57 @@ impl CustomElementRegistry {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <https://html.spec.whatwg.org/multipage/#look-up-a-custom-element-definition>
|
/// <https://html.spec.whatwg.org/multipage/#look-up-a-custom-element-definition>
|
||||||
pub fn lookup_definition(&self,
|
pub fn lookup_definition(
|
||||||
|
&self,
|
||||||
local_name: &LocalName,
|
local_name: &LocalName,
|
||||||
is: Option<&LocalName>)
|
is: Option<&LocalName>,
|
||||||
-> Option<Rc<CustomElementDefinition>> {
|
) -> Option<Rc<CustomElementDefinition>> {
|
||||||
self.definitions.borrow().values().find(|definition| {
|
self.definitions
|
||||||
|
.borrow()
|
||||||
|
.values()
|
||||||
|
.find(|definition| {
|
||||||
// Step 4-5
|
// Step 4-5
|
||||||
definition.local_name == *local_name &&
|
definition.local_name == *local_name &&
|
||||||
(definition.name == *local_name || Some(&definition.name) == is)
|
(definition.name == *local_name || Some(&definition.name) == is)
|
||||||
}).cloned()
|
}).cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lookup_definition_by_constructor(&self, constructor: HandleObject) -> Option<Rc<CustomElementDefinition>> {
|
pub fn lookup_definition_by_constructor(
|
||||||
self.definitions.borrow().values().find(|definition| {
|
&self,
|
||||||
definition.constructor.callback() == constructor.get()
|
constructor: HandleObject,
|
||||||
}).cloned()
|
) -> Option<Rc<CustomElementDefinition>> {
|
||||||
|
self.definitions
|
||||||
|
.borrow()
|
||||||
|
.values()
|
||||||
|
.find(|definition| definition.constructor.callback() == constructor.get())
|
||||||
|
.cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <https://html.spec.whatwg.org/multipage/#dom-customelementregistry-define>
|
/// <https://html.spec.whatwg.org/multipage/#dom-customelementregistry-define>
|
||||||
/// Steps 10.1, 10.2
|
/// Steps 10.1, 10.2
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
fn check_prototype(&self, constructor: HandleObject, prototype: MutableHandleValue) -> ErrorResult {
|
fn check_prototype(
|
||||||
|
&self,
|
||||||
|
constructor: HandleObject,
|
||||||
|
prototype: MutableHandleValue,
|
||||||
|
) -> ErrorResult {
|
||||||
let global_scope = self.window.upcast::<GlobalScope>();
|
let global_scope = self.window.upcast::<GlobalScope>();
|
||||||
unsafe {
|
unsafe {
|
||||||
// Step 10.1
|
// Step 10.1
|
||||||
if !JS_GetProperty(global_scope.get_cx(),
|
if !JS_GetProperty(
|
||||||
|
global_scope.get_cx(),
|
||||||
constructor,
|
constructor,
|
||||||
b"prototype\0".as_ptr() as *const _,
|
b"prototype\0".as_ptr() as *const _,
|
||||||
prototype) {
|
prototype,
|
||||||
|
) {
|
||||||
return Err(Error::JSFailed);
|
return Err(Error::JSFailed);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 10.2
|
// Step 10.2
|
||||||
if !prototype.is_object() {
|
if !prototype.is_object() {
|
||||||
return Err(Error::Type("constructor.prototype is not an object".to_owned()));
|
return Err(Error::Type(
|
||||||
|
"constructor.prototype is not an object".to_owned(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -143,10 +162,14 @@ impl CustomElementRegistry {
|
||||||
fn get_observed_attributes(&self, constructor: HandleObject) -> Fallible<Vec<DOMString>> {
|
fn get_observed_attributes(&self, constructor: HandleObject) -> Fallible<Vec<DOMString>> {
|
||||||
let cx = self.window.get_cx();
|
let cx = self.window.get_cx();
|
||||||
rooted!(in(cx) let mut observed_attributes = UndefinedValue());
|
rooted!(in(cx) let mut observed_attributes = UndefinedValue());
|
||||||
if unsafe { !JS_GetProperty(cx,
|
if unsafe {
|
||||||
|
!JS_GetProperty(
|
||||||
|
cx,
|
||||||
constructor,
|
constructor,
|
||||||
b"observedAttributes\0".as_ptr() as *const _,
|
b"observedAttributes\0".as_ptr() as *const _,
|
||||||
observed_attributes.handle_mut()) } {
|
observed_attributes.handle_mut(),
|
||||||
|
)
|
||||||
|
} {
|
||||||
return Err(Error::JSFailed);
|
return Err(Error::JSFailed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,7 +178,11 @@ impl CustomElementRegistry {
|
||||||
}
|
}
|
||||||
|
|
||||||
let conversion = unsafe {
|
let conversion = unsafe {
|
||||||
FromJSValConvertible::from_jsval(cx, observed_attributes.handle(), StringificationBehavior::Default)
|
FromJSValConvertible::from_jsval(
|
||||||
|
cx,
|
||||||
|
observed_attributes.handle(),
|
||||||
|
StringificationBehavior::Default,
|
||||||
|
)
|
||||||
};
|
};
|
||||||
match conversion {
|
match conversion {
|
||||||
Ok(ConversionResult::Success(attributes)) => Ok(attributes),
|
Ok(ConversionResult::Success(attributes)) => Ok(attributes),
|
||||||
|
@ -176,7 +203,12 @@ unsafe fn get_callback(
|
||||||
rooted!(in(cx) let mut callback = UndefinedValue());
|
rooted!(in(cx) let mut callback = UndefinedValue());
|
||||||
|
|
||||||
// Step 10.4.1
|
// Step 10.4.1
|
||||||
if !JS_GetProperty(cx, prototype, name.as_ptr() as *const _, callback.handle_mut()) {
|
if !JS_GetProperty(
|
||||||
|
cx,
|
||||||
|
prototype,
|
||||||
|
name.as_ptr() as *const _,
|
||||||
|
callback.handle_mut(),
|
||||||
|
) {
|
||||||
return Err(Error::JSFailed);
|
return Err(Error::JSFailed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,9 +227,10 @@ impl CustomElementRegistryMethods for CustomElementRegistry {
|
||||||
#[allow(unsafe_code, unrooted_must_root)]
|
#[allow(unsafe_code, unrooted_must_root)]
|
||||||
/// <https://html.spec.whatwg.org/multipage/#dom-customelementregistry-define>
|
/// <https://html.spec.whatwg.org/multipage/#dom-customelementregistry-define>
|
||||||
fn Define(
|
fn Define(
|
||||||
&self, name: DOMString,
|
&self,
|
||||||
|
name: DOMString,
|
||||||
constructor_: Rc<CustomElementConstructor>,
|
constructor_: Rc<CustomElementConstructor>,
|
||||||
options: &ElementDefinitionOptions
|
options: &ElementDefinitionOptions,
|
||||||
) -> ErrorResult {
|
) -> ErrorResult {
|
||||||
let cx = self.window.get_cx();
|
let cx = self.window.get_cx();
|
||||||
rooted!(in(cx) let constructor = constructor_.callback());
|
rooted!(in(cx) let constructor = constructor_.callback());
|
||||||
|
@ -213,12 +246,14 @@ impl CustomElementRegistryMethods for CustomElementRegistry {
|
||||||
}
|
}
|
||||||
|
|
||||||
if unsafe { !IsConstructor(unwrapped_constructor.get()) } {
|
if unsafe { !IsConstructor(unwrapped_constructor.get()) } {
|
||||||
return Err(Error::Type("Second argument of CustomElementRegistry.define is not a constructor".to_owned()));
|
return Err(Error::Type(
|
||||||
|
"Second argument of CustomElementRegistry.define is not a constructor".to_owned(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 2
|
// Step 2
|
||||||
if !is_valid_custom_element_name(&name) {
|
if !is_valid_custom_element_name(&name) {
|
||||||
return Err(Error::Syntax)
|
return Err(Error::Syntax);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 3
|
// Step 3
|
||||||
|
@ -227,7 +262,12 @@ impl CustomElementRegistryMethods for CustomElementRegistry {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 4
|
// Step 4
|
||||||
if self.definitions.borrow().iter().any(|(_, ref def)| def.constructor == constructor_) {
|
if self
|
||||||
|
.definitions
|
||||||
|
.borrow()
|
||||||
|
.iter()
|
||||||
|
.any(|(_, ref def)| def.constructor == constructor_)
|
||||||
|
{
|
||||||
return Err(Error::NotSupported);
|
return Err(Error::NotSupported);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -238,12 +278,12 @@ impl CustomElementRegistryMethods for CustomElementRegistry {
|
||||||
let local_name = if let Some(ref extended_name) = *extends {
|
let local_name = if let Some(ref extended_name) = *extends {
|
||||||
// Step 7.1
|
// Step 7.1
|
||||||
if is_valid_custom_element_name(extended_name) {
|
if is_valid_custom_element_name(extended_name) {
|
||||||
return Err(Error::NotSupported)
|
return Err(Error::NotSupported);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 7.2
|
// Step 7.2
|
||||||
if !is_extendable_element_interface(extended_name) {
|
if !is_extendable_element_interface(extended_name) {
|
||||||
return Err(Error::NotSupported)
|
return Err(Error::NotSupported);
|
||||||
}
|
}
|
||||||
|
|
||||||
LocalName::from(&**extended_name)
|
LocalName::from(&**extended_name)
|
||||||
|
@ -300,20 +340,28 @@ impl CustomElementRegistryMethods for CustomElementRegistry {
|
||||||
self.element_definition_is_running.set(false);
|
self.element_definition_is_running.set(false);
|
||||||
|
|
||||||
// Step 11
|
// Step 11
|
||||||
let definition = Rc::new(CustomElementDefinition::new(name.clone(),
|
let definition = Rc::new(CustomElementDefinition::new(
|
||||||
|
name.clone(),
|
||||||
local_name.clone(),
|
local_name.clone(),
|
||||||
constructor_,
|
constructor_,
|
||||||
observed_attributes,
|
observed_attributes,
|
||||||
callbacks));
|
callbacks,
|
||||||
|
));
|
||||||
|
|
||||||
// Step 12
|
// Step 12
|
||||||
self.definitions.borrow_mut().insert(name.clone(), definition.clone());
|
self.definitions
|
||||||
|
.borrow_mut()
|
||||||
|
.insert(name.clone(), definition.clone());
|
||||||
|
|
||||||
// Step 13
|
// Step 13
|
||||||
let document = self.window.Document();
|
let document = self.window.Document();
|
||||||
|
|
||||||
// Steps 14-15
|
// Steps 14-15
|
||||||
for candidate in document.upcast::<Node>().traverse_preorder().filter_map(DomRoot::downcast::<Element>) {
|
for candidate in document
|
||||||
|
.upcast::<Node>()
|
||||||
|
.traverse_preorder()
|
||||||
|
.filter_map(DomRoot::downcast::<Element>)
|
||||||
|
{
|
||||||
let is = candidate.get_is();
|
let is = candidate.get_is();
|
||||||
if *candidate.local_name() == local_name &&
|
if *candidate.local_name() == local_name &&
|
||||||
*candidate.namespace() == ns!(html) &&
|
*candidate.namespace() == ns!(html) &&
|
||||||
|
@ -336,7 +384,9 @@ impl CustomElementRegistryMethods for CustomElementRegistry {
|
||||||
match self.definitions.borrow().get(&LocalName::from(&*name)) {
|
match self.definitions.borrow().get(&LocalName::from(&*name)) {
|
||||||
Some(definition) => {
|
Some(definition) => {
|
||||||
rooted!(in(cx) let mut constructor = UndefinedValue());
|
rooted!(in(cx) let mut constructor = UndefinedValue());
|
||||||
definition.constructor.to_jsval(cx, constructor.handle_mut());
|
definition
|
||||||
|
.constructor
|
||||||
|
.to_jsval(cx, constructor.handle_mut());
|
||||||
constructor.get()
|
constructor.get()
|
||||||
},
|
},
|
||||||
None => UndefinedValue(),
|
None => UndefinedValue(),
|
||||||
|
@ -353,14 +403,14 @@ impl CustomElementRegistryMethods for CustomElementRegistry {
|
||||||
if !is_valid_custom_element_name(&name) {
|
if !is_valid_custom_element_name(&name) {
|
||||||
let promise = Promise::new(global_scope);
|
let promise = Promise::new(global_scope);
|
||||||
promise.reject_native(&DOMException::new(global_scope, DOMErrorName::SyntaxError));
|
promise.reject_native(&DOMException::new(global_scope, DOMErrorName::SyntaxError));
|
||||||
return promise
|
return promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 2
|
// Step 2
|
||||||
if self.definitions.borrow().contains_key(&name) {
|
if self.definitions.borrow().contains_key(&name) {
|
||||||
let promise = Promise::new(global_scope);
|
let promise = Promise::new(global_scope);
|
||||||
promise.resolve_native(&UndefinedValue());
|
promise.resolve_native(&UndefinedValue());
|
||||||
return promise
|
return promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 3
|
// Step 3
|
||||||
|
@ -417,12 +467,13 @@ pub struct CustomElementDefinition {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CustomElementDefinition {
|
impl CustomElementDefinition {
|
||||||
fn new(name: LocalName,
|
fn new(
|
||||||
|
name: LocalName,
|
||||||
local_name: LocalName,
|
local_name: LocalName,
|
||||||
constructor: Rc<CustomElementConstructor>,
|
constructor: Rc<CustomElementConstructor>,
|
||||||
observed_attributes: Vec<DOMString>,
|
observed_attributes: Vec<DOMString>,
|
||||||
callbacks: LifecycleCallbacks)
|
callbacks: LifecycleCallbacks,
|
||||||
-> CustomElementDefinition {
|
) -> CustomElementDefinition {
|
||||||
CustomElementDefinition {
|
CustomElementDefinition {
|
||||||
name: name,
|
name: name,
|
||||||
local_name: local_name,
|
local_name: local_name,
|
||||||
|
@ -440,7 +491,11 @@ impl CustomElementDefinition {
|
||||||
|
|
||||||
/// https://dom.spec.whatwg.org/#concept-create-element Step 6.1
|
/// https://dom.spec.whatwg.org/#concept-create-element Step 6.1
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
pub fn create_element(&self, document: &Document, prefix: Option<Prefix>) -> Fallible<DomRoot<Element>> {
|
pub fn create_element(
|
||||||
|
&self,
|
||||||
|
document: &Document,
|
||||||
|
prefix: Option<Prefix>,
|
||||||
|
) -> Fallible<DomRoot<Element>> {
|
||||||
let window = document.window();
|
let window = document.window();
|
||||||
let cx = window.get_cx();
|
let cx = window.get_cx();
|
||||||
// Step 2
|
// Step 2
|
||||||
|
@ -456,16 +511,22 @@ impl CustomElementDefinition {
|
||||||
}
|
}
|
||||||
|
|
||||||
rooted!(in(cx) let element_val = ObjectValue(element.get()));
|
rooted!(in(cx) let element_val = ObjectValue(element.get()));
|
||||||
let element: DomRoot<Element> = match unsafe { DomRoot::from_jsval(cx, element_val.handle(), ()) } {
|
let element: DomRoot<Element> =
|
||||||
|
match unsafe { DomRoot::from_jsval(cx, element_val.handle(), ()) } {
|
||||||
Ok(ConversionResult::Success(element)) => element,
|
Ok(ConversionResult::Success(element)) => element,
|
||||||
Ok(ConversionResult::Failure(..)) =>
|
Ok(ConversionResult::Failure(..)) => {
|
||||||
return Err(Error::Type("Constructor did not return a DOM node".to_owned())),
|
return Err(Error::Type(
|
||||||
|
"Constructor did not return a DOM node".to_owned(),
|
||||||
|
))
|
||||||
|
},
|
||||||
_ => return Err(Error::JSFailed),
|
_ => return Err(Error::JSFailed),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Step 3
|
// Step 3
|
||||||
if !element.is::<HTMLElement>() {
|
if !element.is::<HTMLElement>() {
|
||||||
return Err(Error::Type("Constructor did not return a DOM node".to_owned()));
|
return Err(Error::Type(
|
||||||
|
"Constructor did not return a DOM node".to_owned(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Steps 4-9
|
// Steps 4-9
|
||||||
|
@ -503,17 +564,27 @@ pub fn upgrade_element(definition: Rc<CustomElementDefinition>, element: &Elemen
|
||||||
let local_name = attr.local_name().clone();
|
let local_name = attr.local_name().clone();
|
||||||
let value = DOMString::from(&**attr.value());
|
let value = DOMString::from(&**attr.value());
|
||||||
let namespace = attr.namespace().clone();
|
let namespace = attr.namespace().clone();
|
||||||
ScriptThread::enqueue_callback_reaction(element,
|
ScriptThread::enqueue_callback_reaction(
|
||||||
CallbackReaction::AttributeChanged(local_name, None, Some(value), namespace), Some(definition.clone()));
|
element,
|
||||||
|
CallbackReaction::AttributeChanged(local_name, None, Some(value), namespace),
|
||||||
|
Some(definition.clone()),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 4
|
// Step 4
|
||||||
if element.is_connected() {
|
if element.is_connected() {
|
||||||
ScriptThread::enqueue_callback_reaction(element, CallbackReaction::Connected, Some(definition.clone()));
|
ScriptThread::enqueue_callback_reaction(
|
||||||
|
element,
|
||||||
|
CallbackReaction::Connected,
|
||||||
|
Some(definition.clone()),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 5
|
// Step 5
|
||||||
definition.construction_stack.borrow_mut().push(ConstructionStackEntry::Element(DomRoot::from_ref(element)));
|
definition
|
||||||
|
.construction_stack
|
||||||
|
.borrow_mut()
|
||||||
|
.push(ConstructionStackEntry::Element(DomRoot::from_ref(element)));
|
||||||
|
|
||||||
// Step 7
|
// Step 7
|
||||||
let result = run_upgrade_constructor(&definition.constructor, element);
|
let result = run_upgrade_constructor(&definition.constructor, element);
|
||||||
|
@ -548,25 +619,44 @@ pub fn upgrade_element(definition: Rc<CustomElementDefinition>, element: &Elemen
|
||||||
/// <https://html.spec.whatwg.org/multipage/#concept-upgrade-an-element>
|
/// <https://html.spec.whatwg.org/multipage/#concept-upgrade-an-element>
|
||||||
/// Steps 7.1-7.2
|
/// Steps 7.1-7.2
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
fn run_upgrade_constructor(constructor: &Rc<CustomElementConstructor>, element: &Element) -> ErrorResult {
|
fn run_upgrade_constructor(
|
||||||
|
constructor: &Rc<CustomElementConstructor>,
|
||||||
|
element: &Element,
|
||||||
|
) -> ErrorResult {
|
||||||
let window = window_from_node(element);
|
let window = window_from_node(element);
|
||||||
let cx = window.get_cx();
|
let cx = window.get_cx();
|
||||||
rooted!(in(cx) let constructor_val = ObjectValue(constructor.callback()));
|
rooted!(in(cx) let constructor_val = ObjectValue(constructor.callback()));
|
||||||
rooted!(in(cx) let mut element_val = UndefinedValue());
|
rooted!(in(cx) let mut element_val = UndefinedValue());
|
||||||
unsafe { element.to_jsval(cx, element_val.handle_mut()); }
|
unsafe {
|
||||||
|
element.to_jsval(cx, element_val.handle_mut());
|
||||||
|
}
|
||||||
rooted!(in(cx) let mut construct_result = ptr::null_mut::<JSObject>());
|
rooted!(in(cx) let mut construct_result = ptr::null_mut::<JSObject>());
|
||||||
{
|
{
|
||||||
// Go into the constructor's compartment
|
// Go into the constructor's compartment
|
||||||
let _ac = JSAutoCompartment::new(cx, constructor.callback());
|
let _ac = JSAutoCompartment::new(cx, constructor.callback());
|
||||||
let args = HandleValueArray::new();
|
let args = HandleValueArray::new();
|
||||||
// Step 7.1
|
// Step 7.1
|
||||||
if unsafe { !Construct1(cx, constructor_val.handle(), &args, construct_result.handle_mut()) } {
|
if unsafe {
|
||||||
|
!Construct1(
|
||||||
|
cx,
|
||||||
|
constructor_val.handle(),
|
||||||
|
&args,
|
||||||
|
construct_result.handle_mut(),
|
||||||
|
)
|
||||||
|
} {
|
||||||
return Err(Error::JSFailed);
|
return Err(Error::JSFailed);
|
||||||
}
|
}
|
||||||
// Step 7.2
|
// Step 7.2
|
||||||
let mut same = false;
|
let mut same = false;
|
||||||
rooted!(in(cx) let construct_result_val = ObjectValue(construct_result.get()));
|
rooted!(in(cx) let construct_result_val = ObjectValue(construct_result.get()));
|
||||||
if unsafe { !JS_SameValue(cx, construct_result_val.handle(), element_val.handle(), &mut same) } {
|
if unsafe {
|
||||||
|
!JS_SameValue(
|
||||||
|
cx,
|
||||||
|
construct_result_val.handle(),
|
||||||
|
element_val.handle(),
|
||||||
|
&mut same,
|
||||||
|
)
|
||||||
|
} {
|
||||||
return Err(Error::JSFailed);
|
return Err(Error::JSFailed);
|
||||||
}
|
}
|
||||||
if !same {
|
if !same {
|
||||||
|
@ -583,7 +673,9 @@ pub fn try_upgrade_element(element: &Element) {
|
||||||
let namespace = element.namespace();
|
let namespace = element.namespace();
|
||||||
let local_name = element.local_name();
|
let local_name = element.local_name();
|
||||||
let is = element.get_is();
|
let is = element.get_is();
|
||||||
if let Some(definition) = document.lookup_custom_element_definition(namespace, local_name, is.as_ref()) {
|
if let Some(definition) =
|
||||||
|
document.lookup_custom_element_definition(namespace, local_name, is.as_ref())
|
||||||
|
{
|
||||||
// Step 2
|
// Step 2
|
||||||
ScriptThread::enqueue_upgrade_reaction(element, definition);
|
ScriptThread::enqueue_upgrade_reaction(element, definition);
|
||||||
}
|
}
|
||||||
|
@ -592,14 +684,10 @@ pub fn try_upgrade_element(element: &Element) {
|
||||||
#[derive(JSTraceable, MallocSizeOf)]
|
#[derive(JSTraceable, MallocSizeOf)]
|
||||||
#[must_root]
|
#[must_root]
|
||||||
pub enum CustomElementReaction {
|
pub enum CustomElementReaction {
|
||||||
Upgrade(
|
Upgrade(#[ignore_malloc_size_of = "Rc"] Rc<CustomElementDefinition>),
|
||||||
#[ignore_malloc_size_of = "Rc"]
|
|
||||||
Rc<CustomElementDefinition>
|
|
||||||
),
|
|
||||||
Callback(
|
Callback(
|
||||||
#[ignore_malloc_size_of = "Rc"]
|
#[ignore_malloc_size_of = "Rc"] Rc<Function>,
|
||||||
Rc<Function>,
|
Box<[Heap<JSVal>]>,
|
||||||
Box<[Heap<JSVal>]>
|
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -609,12 +697,17 @@ impl CustomElementReaction {
|
||||||
pub fn invoke(&self, element: &Element) {
|
pub fn invoke(&self, element: &Element) {
|
||||||
// Step 2.1
|
// Step 2.1
|
||||||
match *self {
|
match *self {
|
||||||
CustomElementReaction::Upgrade(ref definition) => upgrade_element(definition.clone(), element),
|
CustomElementReaction::Upgrade(ref definition) => {
|
||||||
|
upgrade_element(definition.clone(), element)
|
||||||
|
},
|
||||||
CustomElementReaction::Callback(ref callback, ref arguments) => {
|
CustomElementReaction::Callback(ref callback, ref arguments) => {
|
||||||
// We're rooted, so it's safe to hand out a handle to objects in Heap
|
// We're rooted, so it's safe to hand out a handle to objects in Heap
|
||||||
let arguments = arguments.iter().map(|arg| unsafe { HandleValue::from_raw(arg.handle()) }).collect();
|
let arguments = arguments
|
||||||
|
.iter()
|
||||||
|
.map(|arg| unsafe { HandleValue::from_raw(arg.handle()) })
|
||||||
|
.collect();
|
||||||
let _ = callback.Call_(&*element, arguments, ExceptionHandling::Report);
|
let _ = callback.Call_(&*element, arguments, ExceptionHandling::Report);
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -675,7 +768,8 @@ impl CustomElementReactionStack {
|
||||||
self.backup_queue.invoke_reactions();
|
self.backup_queue.invoke_reactions();
|
||||||
|
|
||||||
// Step 4.2
|
// Step 4.2
|
||||||
self.processing_backup_element_queue.set(BackupElementQueueFlag::NotProcessing);
|
self.processing_backup_element_queue
|
||||||
|
.set(BackupElementQueueFlag::NotProcessing);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <https://html.spec.whatwg.org/multipage/#enqueue-an-element-on-the-appropriate-element-queue>
|
/// <https://html.spec.whatwg.org/multipage/#enqueue-an-element-on-the-appropriate-element-queue>
|
||||||
|
@ -693,7 +787,8 @@ impl CustomElementReactionStack {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 1.3
|
// Step 1.3
|
||||||
self.processing_backup_element_queue.set(BackupElementQueueFlag::Processing);
|
self.processing_backup_element_queue
|
||||||
|
.set(BackupElementQueueFlag::Processing);
|
||||||
|
|
||||||
// Step 4
|
// Step 4
|
||||||
ScriptThread::enqueue_microtask(Microtask::CustomElementReaction);
|
ScriptThread::enqueue_microtask(Microtask::CustomElementReaction);
|
||||||
|
@ -702,10 +797,12 @@ impl CustomElementReactionStack {
|
||||||
|
|
||||||
/// <https://html.spec.whatwg.org/multipage/#enqueue-a-custom-element-callback-reaction>
|
/// <https://html.spec.whatwg.org/multipage/#enqueue-a-custom-element-callback-reaction>
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
pub fn enqueue_callback_reaction(&self,
|
pub fn enqueue_callback_reaction(
|
||||||
|
&self,
|
||||||
element: &Element,
|
element: &Element,
|
||||||
reaction: CallbackReaction,
|
reaction: CallbackReaction,
|
||||||
definition: Option<Rc<CustomElementDefinition>>) {
|
definition: Option<Rc<CustomElementDefinition>>,
|
||||||
|
) {
|
||||||
// Step 1
|
// Step 1
|
||||||
let definition = match definition.or_else(|| element.get_custom_element_definition()) {
|
let definition = match definition.or_else(|| element.get_custom_element_definition()) {
|
||||||
Some(definition) => definition,
|
Some(definition) => definition,
|
||||||
|
@ -714,8 +811,13 @@ impl CustomElementReactionStack {
|
||||||
|
|
||||||
// Step 2
|
// Step 2
|
||||||
let (callback, args) = match reaction {
|
let (callback, args) = match reaction {
|
||||||
CallbackReaction::Connected => (definition.callbacks.connected_callback.clone(), Vec::new()),
|
CallbackReaction::Connected => {
|
||||||
CallbackReaction::Disconnected => (definition.callbacks.disconnected_callback.clone(), Vec::new()),
|
(definition.callbacks.connected_callback.clone(), Vec::new())
|
||||||
|
},
|
||||||
|
CallbackReaction::Disconnected => (
|
||||||
|
definition.callbacks.disconnected_callback.clone(),
|
||||||
|
Vec::new(),
|
||||||
|
),
|
||||||
CallbackReaction::Adopted(ref old_doc, ref new_doc) => {
|
CallbackReaction::Adopted(ref old_doc, ref new_doc) => {
|
||||||
let args = vec![Heap::default(), Heap::default()];
|
let args = vec![Heap::default(), Heap::default()];
|
||||||
args[0].set(ObjectValue(old_doc.reflector().get_jsobject().get()));
|
args[0].set(ObjectValue(old_doc.reflector().get_jsobject().get()));
|
||||||
|
@ -724,7 +826,11 @@ impl CustomElementReactionStack {
|
||||||
},
|
},
|
||||||
CallbackReaction::AttributeChanged(local_name, old_val, val, namespace) => {
|
CallbackReaction::AttributeChanged(local_name, old_val, val, namespace) => {
|
||||||
// Step 4
|
// Step 4
|
||||||
if !definition.observed_attributes.iter().any(|attr| *attr == *local_name) {
|
if !definition
|
||||||
|
.observed_attributes
|
||||||
|
.iter()
|
||||||
|
.any(|attr| *attr == *local_name)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -732,31 +838,47 @@ impl CustomElementReactionStack {
|
||||||
|
|
||||||
let local_name = DOMString::from(&*local_name);
|
let local_name = DOMString::from(&*local_name);
|
||||||
rooted!(in(cx) let mut name_value = UndefinedValue());
|
rooted!(in(cx) let mut name_value = UndefinedValue());
|
||||||
unsafe { local_name.to_jsval(cx, name_value.handle_mut()); }
|
unsafe {
|
||||||
|
local_name.to_jsval(cx, name_value.handle_mut());
|
||||||
|
}
|
||||||
|
|
||||||
rooted!(in(cx) let mut old_value = NullValue());
|
rooted!(in(cx) let mut old_value = NullValue());
|
||||||
if let Some(old_val) = old_val {
|
if let Some(old_val) = old_val {
|
||||||
unsafe { old_val.to_jsval(cx, old_value.handle_mut()); }
|
unsafe {
|
||||||
|
old_val.to_jsval(cx, old_value.handle_mut());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rooted!(in(cx) let mut value = NullValue());
|
rooted!(in(cx) let mut value = NullValue());
|
||||||
if let Some(val) = val {
|
if let Some(val) = val {
|
||||||
unsafe { val.to_jsval(cx, value.handle_mut()); }
|
unsafe {
|
||||||
|
val.to_jsval(cx, value.handle_mut());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rooted!(in(cx) let mut namespace_value = NullValue());
|
rooted!(in(cx) let mut namespace_value = NullValue());
|
||||||
if namespace != ns!() {
|
if namespace != ns!() {
|
||||||
let namespace = DOMString::from(&*namespace);
|
let namespace = DOMString::from(&*namespace);
|
||||||
unsafe { namespace.to_jsval(cx, namespace_value.handle_mut()); }
|
unsafe {
|
||||||
|
namespace.to_jsval(cx, namespace_value.handle_mut());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let args = vec![Heap::default(), Heap::default(), Heap::default(), Heap::default()];
|
let args = vec![
|
||||||
|
Heap::default(),
|
||||||
|
Heap::default(),
|
||||||
|
Heap::default(),
|
||||||
|
Heap::default(),
|
||||||
|
];
|
||||||
args[0].set(name_value.get());
|
args[0].set(name_value.get());
|
||||||
args[1].set(old_value.get());
|
args[1].set(old_value.get());
|
||||||
args[2].set(value.get());
|
args[2].set(value.get());
|
||||||
args[3].set(namespace_value.get());
|
args[3].set(namespace_value.get());
|
||||||
|
|
||||||
(definition.callbacks.attribute_changed_callback.clone(), args)
|
(
|
||||||
|
definition.callbacks.attribute_changed_callback.clone(),
|
||||||
|
args,
|
||||||
|
)
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -774,7 +896,11 @@ impl CustomElementReactionStack {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <https://html.spec.whatwg.org/multipage/#enqueue-a-custom-element-upgrade-reaction>
|
/// <https://html.spec.whatwg.org/multipage/#enqueue-a-custom-element-upgrade-reaction>
|
||||||
pub fn enqueue_upgrade_reaction(&self, element: &Element, definition: Rc<CustomElementDefinition>) {
|
pub fn enqueue_upgrade_reaction(
|
||||||
|
&self,
|
||||||
|
element: &Element,
|
||||||
|
definition: Rc<CustomElementDefinition>,
|
||||||
|
) {
|
||||||
// Step 1
|
// Step 1
|
||||||
element.push_upgrade_reaction(definition);
|
element.push_upgrade_reaction(definition);
|
||||||
// Step 2
|
// Step 2
|
||||||
|
@ -806,7 +932,12 @@ impl ElementQueue {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next_element(&self) -> Option<DomRoot<Element>> {
|
fn next_element(&self) -> Option<DomRoot<Element>> {
|
||||||
self.queue.borrow_mut().pop_front().as_ref().map(Dom::deref).map(DomRoot::from_ref)
|
self.queue
|
||||||
|
.borrow_mut()
|
||||||
|
.pop_front()
|
||||||
|
.as_ref()
|
||||||
|
.map(Dom::deref)
|
||||||
|
.map(DomRoot::from_ref)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn append_element(&self, element: &Element) {
|
fn append_element(&self, element: &Element) {
|
||||||
|
@ -859,7 +990,10 @@ pub fn is_valid_custom_element_name(name: &str) -> bool {
|
||||||
/// Check if this character is a PCENChar
|
/// Check if this character is a PCENChar
|
||||||
/// <https://html.spec.whatwg.org/multipage/#prod-pcenchar>
|
/// <https://html.spec.whatwg.org/multipage/#prod-pcenchar>
|
||||||
fn is_potential_custom_element_char(c: char) -> bool {
|
fn is_potential_custom_element_char(c: char) -> bool {
|
||||||
c == '-' || c == '.' || c == '_' || c == '\u{B7}' ||
|
c == '-' ||
|
||||||
|
c == '.' ||
|
||||||
|
c == '_' ||
|
||||||
|
c == '\u{B7}' ||
|
||||||
(c >= '0' && c <= '9') ||
|
(c >= '0' && c <= '9') ||
|
||||||
(c >= 'a' && c <= 'z') ||
|
(c >= 'a' && c <= 'z') ||
|
||||||
(c >= '\u{C0}' && c <= '\u{D6}') ||
|
(c >= '\u{C0}' && c <= '\u{D6}') ||
|
||||||
|
|
|
@ -36,38 +36,46 @@ impl CustomEvent {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_uninitialized(global: &GlobalScope) -> DomRoot<CustomEvent> {
|
pub fn new_uninitialized(global: &GlobalScope) -> DomRoot<CustomEvent> {
|
||||||
reflect_dom_object(Box::new(CustomEvent::new_inherited()),
|
reflect_dom_object(
|
||||||
|
Box::new(CustomEvent::new_inherited()),
|
||||||
global,
|
global,
|
||||||
CustomEventBinding::Wrap)
|
CustomEventBinding::Wrap,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
pub fn new(global: &GlobalScope,
|
pub fn new(
|
||||||
|
global: &GlobalScope,
|
||||||
type_: Atom,
|
type_: Atom,
|
||||||
bubbles: bool,
|
bubbles: bool,
|
||||||
cancelable: bool,
|
cancelable: bool,
|
||||||
detail: HandleValue)
|
detail: HandleValue,
|
||||||
-> DomRoot<CustomEvent> {
|
) -> DomRoot<CustomEvent> {
|
||||||
let ev = CustomEvent::new_uninitialized(global);
|
let ev = CustomEvent::new_uninitialized(global);
|
||||||
ev.init_custom_event(type_, bubbles, cancelable, detail);
|
ev.init_custom_event(type_, bubbles, cancelable, detail);
|
||||||
ev
|
ev
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
pub fn Constructor(global: &GlobalScope,
|
pub fn Constructor(
|
||||||
|
global: &GlobalScope,
|
||||||
type_: DOMString,
|
type_: DOMString,
|
||||||
init: RootedTraceableBox<CustomEventBinding::CustomEventInit>)
|
init: RootedTraceableBox<CustomEventBinding::CustomEventInit>,
|
||||||
-> Fallible<DomRoot<CustomEvent>> {
|
) -> Fallible<DomRoot<CustomEvent>> {
|
||||||
Ok(CustomEvent::new(global,
|
Ok(CustomEvent::new(
|
||||||
|
global,
|
||||||
Atom::from(type_),
|
Atom::from(type_),
|
||||||
init.parent.bubbles,
|
init.parent.bubbles,
|
||||||
init.parent.cancelable,
|
init.parent.cancelable,
|
||||||
init.detail.handle()))
|
init.detail.handle(),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_custom_event(&self,
|
fn init_custom_event(
|
||||||
|
&self,
|
||||||
type_: Atom,
|
type_: Atom,
|
||||||
can_bubble: bool,
|
can_bubble: bool,
|
||||||
cancelable: bool,
|
cancelable: bool,
|
||||||
detail: HandleValue) {
|
detail: HandleValue,
|
||||||
|
) {
|
||||||
let event = self.upcast::<Event>();
|
let event = self.upcast::<Event>();
|
||||||
if event.dispatching() {
|
if event.dispatching() {
|
||||||
return;
|
return;
|
||||||
|
@ -87,12 +95,14 @@ impl CustomEventMethods for CustomEvent {
|
||||||
|
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
// https://dom.spec.whatwg.org/#dom-customevent-initcustomevent
|
// https://dom.spec.whatwg.org/#dom-customevent-initcustomevent
|
||||||
unsafe fn InitCustomEvent(&self,
|
unsafe fn InitCustomEvent(
|
||||||
|
&self,
|
||||||
_cx: *mut JSContext,
|
_cx: *mut JSContext,
|
||||||
type_: DOMString,
|
type_: DOMString,
|
||||||
can_bubble: bool,
|
can_bubble: bool,
|
||||||
cancelable: bool,
|
cancelable: bool,
|
||||||
detail: HandleValue) {
|
detail: HandleValue,
|
||||||
|
) {
|
||||||
self.init_custom_event(Atom::from(type_), can_bubble, cancelable, detail)
|
self.init_custom_event(Atom::from(type_), can_bubble, cancelable, detail)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -57,9 +57,10 @@ pub struct AutoWorkerReset<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> AutoWorkerReset<'a> {
|
impl<'a> AutoWorkerReset<'a> {
|
||||||
fn new(workerscope: &'a DedicatedWorkerGlobalScope,
|
fn new(
|
||||||
worker: TrustedWorkerAddress)
|
workerscope: &'a DedicatedWorkerGlobalScope,
|
||||||
-> AutoWorkerReset<'a> {
|
worker: TrustedWorkerAddress,
|
||||||
|
) -> AutoWorkerReset<'a> {
|
||||||
AutoWorkerReset {
|
AutoWorkerReset {
|
||||||
workerscope: workerscope,
|
workerscope: workerscope,
|
||||||
old_worker: replace(&mut *workerscope.worker.borrow_mut(), Some(worker)),
|
old_worker: replace(&mut *workerscope.worker.borrow_mut(), Some(worker)),
|
||||||
|
@ -83,7 +84,7 @@ pub enum DedicatedWorkerScriptMsg {
|
||||||
pub enum MixedMessage {
|
pub enum MixedMessage {
|
||||||
FromWorker(DedicatedWorkerScriptMsg),
|
FromWorker(DedicatedWorkerScriptMsg),
|
||||||
FromScheduler((TrustedWorkerAddress, TimerEvent)),
|
FromScheduler((TrustedWorkerAddress, TimerEvent)),
|
||||||
FromDevtools(DevtoolScriptControlMsg)
|
FromDevtools(DevtoolScriptControlMsg),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl QueuedTaskConversion for DedicatedWorkerScriptMsg {
|
impl QueuedTaskConversion for DedicatedWorkerScriptMsg {
|
||||||
|
@ -97,14 +98,18 @@ impl QueuedTaskConversion for DedicatedWorkerScriptMsg {
|
||||||
_ => return None,
|
_ => return None,
|
||||||
};
|
};
|
||||||
match script_msg {
|
match script_msg {
|
||||||
CommonScriptMsg::Task(_category, _boxed, _pipeline_id, source_name) => Some(&source_name),
|
CommonScriptMsg::Task(_category, _boxed, _pipeline_id, source_name) => {
|
||||||
|
Some(&source_name)
|
||||||
|
},
|
||||||
_ => return None,
|
_ => return None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn into_queued_task(self) -> Option<QueuedTask> {
|
fn into_queued_task(self) -> Option<QueuedTask> {
|
||||||
let (worker, common_worker_msg) = match self {
|
let (worker, common_worker_msg) = match self {
|
||||||
DedicatedWorkerScriptMsg::CommonWorker(worker, common_worker_msg) => (worker, common_worker_msg),
|
DedicatedWorkerScriptMsg::CommonWorker(worker, common_worker_msg) => {
|
||||||
|
(worker, common_worker_msg)
|
||||||
|
},
|
||||||
_ => return None,
|
_ => return None,
|
||||||
};
|
};
|
||||||
let script_msg = match common_worker_msg {
|
let script_msg = match common_worker_msg {
|
||||||
|
@ -112,8 +117,9 @@ impl QueuedTaskConversion for DedicatedWorkerScriptMsg {
|
||||||
_ => return None,
|
_ => return None,
|
||||||
};
|
};
|
||||||
let (category, boxed, pipeline_id, task_source) = match script_msg {
|
let (category, boxed, pipeline_id, task_source) = match script_msg {
|
||||||
CommonScriptMsg::Task(category, boxed, pipeline_id, task_source) =>
|
CommonScriptMsg::Task(category, boxed, pipeline_id, task_source) => {
|
||||||
(category, boxed, pipeline_id, task_source),
|
(category, boxed, pipeline_id, task_source)
|
||||||
|
},
|
||||||
_ => return None,
|
_ => return None,
|
||||||
};
|
};
|
||||||
Some((Some(worker), category, boxed, pipeline_id, task_source))
|
Some((Some(worker), category, boxed, pipeline_id, task_source))
|
||||||
|
@ -121,12 +127,7 @@ impl QueuedTaskConversion for DedicatedWorkerScriptMsg {
|
||||||
|
|
||||||
fn from_queued_task(queued_task: QueuedTask) -> Self {
|
fn from_queued_task(queued_task: QueuedTask) -> Self {
|
||||||
let (worker, category, boxed, pipeline_id, task_source) = queued_task;
|
let (worker, category, boxed, pipeline_id, task_source) = queued_task;
|
||||||
let script_msg = CommonScriptMsg::Task(
|
let script_msg = CommonScriptMsg::Task(category, boxed, pipeline_id, task_source);
|
||||||
category,
|
|
||||||
boxed,
|
|
||||||
pipeline_id,
|
|
||||||
task_source
|
|
||||||
);
|
|
||||||
DedicatedWorkerScriptMsg::CommonWorker(worker.unwrap(), WorkerScriptMsg::Common(script_msg))
|
DedicatedWorkerScriptMsg::CommonWorker(worker.unwrap(), WorkerScriptMsg::Common(script_msg))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,7 +198,8 @@ impl WorkerEventLoopMethods for DedicatedWorkerGlobalScope {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DedicatedWorkerGlobalScope {
|
impl DedicatedWorkerGlobalScope {
|
||||||
fn new_inherited(init: WorkerGlobalScopeInit,
|
fn new_inherited(
|
||||||
|
init: WorkerGlobalScopeInit,
|
||||||
worker_url: ServoUrl,
|
worker_url: ServoUrl,
|
||||||
from_devtools_receiver: Receiver<DevtoolScriptControlMsg>,
|
from_devtools_receiver: Receiver<DevtoolScriptControlMsg>,
|
||||||
runtime: Runtime,
|
runtime: Runtime,
|
||||||
|
@ -206,15 +208,17 @@ impl DedicatedWorkerGlobalScope {
|
||||||
receiver: Receiver<DedicatedWorkerScriptMsg>,
|
receiver: Receiver<DedicatedWorkerScriptMsg>,
|
||||||
timer_event_chan: IpcSender<TimerEvent>,
|
timer_event_chan: IpcSender<TimerEvent>,
|
||||||
timer_event_port: Receiver<(TrustedWorkerAddress, TimerEvent)>,
|
timer_event_port: Receiver<(TrustedWorkerAddress, TimerEvent)>,
|
||||||
closing: Arc<AtomicBool>)
|
closing: Arc<AtomicBool>,
|
||||||
-> DedicatedWorkerGlobalScope {
|
) -> DedicatedWorkerGlobalScope {
|
||||||
DedicatedWorkerGlobalScope {
|
DedicatedWorkerGlobalScope {
|
||||||
workerglobalscope: WorkerGlobalScope::new_inherited(init,
|
workerglobalscope: WorkerGlobalScope::new_inherited(
|
||||||
|
init,
|
||||||
worker_url,
|
worker_url,
|
||||||
runtime,
|
runtime,
|
||||||
from_devtools_receiver,
|
from_devtools_receiver,
|
||||||
timer_event_chan,
|
timer_event_chan,
|
||||||
Some(closing)),
|
Some(closing),
|
||||||
|
),
|
||||||
task_queue: TaskQueue::new(receiver, own_sender.clone()),
|
task_queue: TaskQueue::new(receiver, own_sender.clone()),
|
||||||
own_sender: own_sender,
|
own_sender: own_sender,
|
||||||
timer_event_port: timer_event_port,
|
timer_event_port: timer_event_port,
|
||||||
|
@ -224,7 +228,8 @@ impl DedicatedWorkerGlobalScope {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
pub fn new(init: WorkerGlobalScopeInit,
|
pub fn new(
|
||||||
|
init: WorkerGlobalScopeInit,
|
||||||
worker_url: ServoUrl,
|
worker_url: ServoUrl,
|
||||||
from_devtools_receiver: Receiver<DevtoolScriptControlMsg>,
|
from_devtools_receiver: Receiver<DevtoolScriptControlMsg>,
|
||||||
runtime: Runtime,
|
runtime: Runtime,
|
||||||
|
@ -233,8 +238,8 @@ impl DedicatedWorkerGlobalScope {
|
||||||
receiver: Receiver<DedicatedWorkerScriptMsg>,
|
receiver: Receiver<DedicatedWorkerScriptMsg>,
|
||||||
timer_event_chan: IpcSender<TimerEvent>,
|
timer_event_chan: IpcSender<TimerEvent>,
|
||||||
timer_event_port: Receiver<(TrustedWorkerAddress, TimerEvent)>,
|
timer_event_port: Receiver<(TrustedWorkerAddress, TimerEvent)>,
|
||||||
closing: Arc<AtomicBool>)
|
closing: Arc<AtomicBool>,
|
||||||
-> DomRoot<DedicatedWorkerGlobalScope> {
|
) -> DomRoot<DedicatedWorkerGlobalScope> {
|
||||||
let cx = runtime.cx();
|
let cx = runtime.cx();
|
||||||
let scope = Box::new(DedicatedWorkerGlobalScope::new_inherited(
|
let scope = Box::new(DedicatedWorkerGlobalScope::new_inherited(
|
||||||
init,
|
init,
|
||||||
|
@ -246,16 +251,15 @@ impl DedicatedWorkerGlobalScope {
|
||||||
receiver,
|
receiver,
|
||||||
timer_event_chan,
|
timer_event_chan,
|
||||||
timer_event_port,
|
timer_event_port,
|
||||||
closing
|
closing,
|
||||||
));
|
));
|
||||||
unsafe {
|
unsafe { DedicatedWorkerGlobalScopeBinding::Wrap(cx, scope) }
|
||||||
DedicatedWorkerGlobalScopeBinding::Wrap(cx, scope)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
// https://html.spec.whatwg.org/multipage/#run-a-worker
|
// https://html.spec.whatwg.org/multipage/#run-a-worker
|
||||||
pub fn run_worker_scope(init: WorkerGlobalScopeInit,
|
pub fn run_worker_scope(
|
||||||
|
init: WorkerGlobalScopeInit,
|
||||||
worker_url: ServoUrl,
|
worker_url: ServoUrl,
|
||||||
from_devtools_receiver: IpcReceiver<DevtoolScriptControlMsg>,
|
from_devtools_receiver: IpcReceiver<DevtoolScriptControlMsg>,
|
||||||
worker: TrustedWorkerAddress,
|
worker: TrustedWorkerAddress,
|
||||||
|
@ -263,13 +267,20 @@ impl DedicatedWorkerGlobalScope {
|
||||||
own_sender: Sender<DedicatedWorkerScriptMsg>,
|
own_sender: Sender<DedicatedWorkerScriptMsg>,
|
||||||
receiver: Receiver<DedicatedWorkerScriptMsg>,
|
receiver: Receiver<DedicatedWorkerScriptMsg>,
|
||||||
worker_load_origin: WorkerScriptLoadOrigin,
|
worker_load_origin: WorkerScriptLoadOrigin,
|
||||||
closing: Arc<AtomicBool>) {
|
closing: Arc<AtomicBool>,
|
||||||
|
) {
|
||||||
let serialized_worker_url = worker_url.to_string();
|
let serialized_worker_url = worker_url.to_string();
|
||||||
let name = format!("WebWorker for {}", serialized_worker_url);
|
let name = format!("WebWorker for {}", serialized_worker_url);
|
||||||
let top_level_browsing_context_id = TopLevelBrowsingContextId::installed();
|
let top_level_browsing_context_id = TopLevelBrowsingContextId::installed();
|
||||||
let origin = GlobalScope::current().expect("No current global object").origin().immutable().clone();
|
let origin = GlobalScope::current()
|
||||||
|
.expect("No current global object")
|
||||||
|
.origin()
|
||||||
|
.immutable()
|
||||||
|
.clone();
|
||||||
|
|
||||||
thread::Builder::new().name(name).spawn(move || {
|
thread::Builder::new()
|
||||||
|
.name(name)
|
||||||
|
.spawn(move || {
|
||||||
thread_state::initialize(ThreadState::SCRIPT | ThreadState::IN_WORKER);
|
thread_state::initialize(ThreadState::SCRIPT | ThreadState::IN_WORKER);
|
||||||
|
|
||||||
if let Some(top_level_browsing_context_id) = top_level_browsing_context_id {
|
if let Some(top_level_browsing_context_id) = top_level_browsing_context_id {
|
||||||
|
@ -279,7 +290,11 @@ impl DedicatedWorkerGlobalScope {
|
||||||
let roots = RootCollection::new();
|
let roots = RootCollection::new();
|
||||||
let _stack_roots = ThreadLocalStackRoots::new(&roots);
|
let _stack_roots = ThreadLocalStackRoots::new(&roots);
|
||||||
|
|
||||||
let WorkerScriptLoadOrigin { referrer_url, referrer_policy, pipeline_id } = worker_load_origin;
|
let WorkerScriptLoadOrigin {
|
||||||
|
referrer_url,
|
||||||
|
referrer_policy,
|
||||||
|
pipeline_id,
|
||||||
|
} = worker_load_origin;
|
||||||
|
|
||||||
let request = RequestInit {
|
let request = RequestInit {
|
||||||
url: worker_url.clone(),
|
url: worker_url.clone(),
|
||||||
|
@ -290,22 +305,23 @@ impl DedicatedWorkerGlobalScope {
|
||||||
referrer_url: referrer_url,
|
referrer_url: referrer_url,
|
||||||
referrer_policy: referrer_policy,
|
referrer_policy: referrer_policy,
|
||||||
origin,
|
origin,
|
||||||
.. RequestInit::default()
|
..RequestInit::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
let (metadata, bytes) = match load_whole_resource(request,
|
let (metadata, bytes) =
|
||||||
&init.resource_threads.sender()) {
|
match load_whole_resource(request, &init.resource_threads.sender()) {
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
println!("error loading script {}", serialized_worker_url);
|
println!("error loading script {}", serialized_worker_url);
|
||||||
parent_sender.send(CommonScriptMsg::Task(
|
parent_sender
|
||||||
|
.send(CommonScriptMsg::Task(
|
||||||
WorkerEvent,
|
WorkerEvent,
|
||||||
Box::new(SimpleWorkerErrorHandler::new(worker)),
|
Box::new(SimpleWorkerErrorHandler::new(worker)),
|
||||||
pipeline_id,
|
pipeline_id,
|
||||||
TaskSourceName::DOMManipulation,
|
TaskSourceName::DOMManipulation,
|
||||||
)).unwrap();
|
)).unwrap();
|
||||||
return;
|
return;
|
||||||
}
|
},
|
||||||
Ok((metadata, bytes)) => (metadata, bytes)
|
Ok((metadata, bytes)) => (metadata, bytes),
|
||||||
};
|
};
|
||||||
let url = metadata.final_url;
|
let url = metadata.final_url;
|
||||||
let source = String::from_utf8_lossy(&bytes);
|
let source = String::from_utf8_lossy(&bytes);
|
||||||
|
@ -318,15 +334,26 @@ impl DedicatedWorkerGlobalScope {
|
||||||
let (timer_tx, timer_rx) = channel();
|
let (timer_tx, timer_rx) = channel();
|
||||||
let (timer_ipc_chan, timer_ipc_port) = ipc::channel().unwrap();
|
let (timer_ipc_chan, timer_ipc_port) = ipc::channel().unwrap();
|
||||||
let worker_for_route = worker.clone();
|
let worker_for_route = worker.clone();
|
||||||
ROUTER.add_route(timer_ipc_port.to_opaque(), Box::new(move |message| {
|
ROUTER.add_route(
|
||||||
|
timer_ipc_port.to_opaque(),
|
||||||
|
Box::new(move |message| {
|
||||||
let event = message.to().unwrap();
|
let event = message.to().unwrap();
|
||||||
timer_tx.send((worker_for_route.clone(), event)).unwrap();
|
timer_tx.send((worker_for_route.clone(), event)).unwrap();
|
||||||
}));
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
let global = DedicatedWorkerGlobalScope::new(
|
let global = DedicatedWorkerGlobalScope::new(
|
||||||
init, url, devtools_mpsc_port, runtime,
|
init,
|
||||||
parent_sender.clone(), own_sender, receiver,
|
url,
|
||||||
timer_ipc_chan, timer_rx, closing);
|
devtools_mpsc_port,
|
||||||
|
runtime,
|
||||||
|
parent_sender.clone(),
|
||||||
|
own_sender,
|
||||||
|
receiver,
|
||||||
|
timer_ipc_chan,
|
||||||
|
timer_rx,
|
||||||
|
closing,
|
||||||
|
);
|
||||||
// FIXME(njn): workers currently don't have a unique ID suitable for using in reporter
|
// FIXME(njn): workers currently don't have a unique ID suitable for using in reporter
|
||||||
// registration (#6631), so we instead use a random number and cross our fingers.
|
// registration (#6631), so we instead use a random number and cross our fingers.
|
||||||
let scope = global.upcast::<WorkerGlobalScope>();
|
let scope = global.upcast::<WorkerGlobalScope>();
|
||||||
|
@ -346,14 +373,24 @@ impl DedicatedWorkerGlobalScope {
|
||||||
}
|
}
|
||||||
|
|
||||||
let reporter_name = format!("dedicated-worker-reporter-{}", random::<u64>());
|
let reporter_name = format!("dedicated-worker-reporter-{}", random::<u64>());
|
||||||
scope.upcast::<GlobalScope>().mem_profiler_chan().run_with_memory_reporting(|| {
|
scope
|
||||||
// Step 29, Run the responsible event loop specified by inside settings until it is destroyed.
|
.upcast::<GlobalScope>()
|
||||||
// The worker processing model remains on this step until the event loop is destroyed,
|
.mem_profiler_chan()
|
||||||
|
.run_with_memory_reporting(
|
||||||
|
|| {
|
||||||
|
// Step 29, Run the responsible event loop specified
|
||||||
|
// by inside settings until it is destroyed.
|
||||||
|
// The worker processing model remains on this step
|
||||||
|
// until the event loop is destroyed,
|
||||||
// which happens after the closing flag is set to true.
|
// which happens after the closing flag is set to true.
|
||||||
while !scope.is_closing() {
|
while !scope.is_closing() {
|
||||||
run_worker_event_loop(&*global, Some(&worker));
|
run_worker_event_loop(&*global, Some(&worker));
|
||||||
}
|
}
|
||||||
}, reporter_name, parent_sender, CommonScriptMsg::CollectReports);
|
},
|
||||||
|
reporter_name,
|
||||||
|
parent_sender,
|
||||||
|
CommonScriptMsg::CollectReports,
|
||||||
|
);
|
||||||
}).expect("Thread spawning failed");
|
}).expect("Thread spawning failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -378,8 +415,8 @@ impl DedicatedWorkerGlobalScope {
|
||||||
WorkerScriptMsg::DOMMessage(data) => {
|
WorkerScriptMsg::DOMMessage(data) => {
|
||||||
let scope = self.upcast::<WorkerGlobalScope>();
|
let scope = self.upcast::<WorkerGlobalScope>();
|
||||||
let target = self.upcast();
|
let target = self.upcast();
|
||||||
let _ac = JSAutoCompartment::new(scope.get_cx(),
|
let _ac =
|
||||||
scope.reflector().get_jsobject().get());
|
JSAutoCompartment::new(scope.get_cx(), scope.reflector().get_jsobject().get());
|
||||||
rooted!(in(scope.get_cx()) let mut message = UndefinedValue());
|
rooted!(in(scope.get_cx()) let mut message = UndefinedValue());
|
||||||
data.read(scope.upcast(), message.handle_mut());
|
data.read(scope.upcast(), message.handle_mut());
|
||||||
MessageEvent::dispatch_jsval(target, scope.upcast(), message.handle(), None);
|
MessageEvent::dispatch_jsval(target, scope.upcast(), message.handle(), None);
|
||||||
|
@ -392,33 +429,33 @@ impl DedicatedWorkerGlobalScope {
|
||||||
|
|
||||||
fn handle_mixed_message(&self, msg: MixedMessage) {
|
fn handle_mixed_message(&self, msg: MixedMessage) {
|
||||||
match msg {
|
match msg {
|
||||||
MixedMessage::FromDevtools(msg) => {
|
MixedMessage::FromDevtools(msg) => match msg {
|
||||||
match msg {
|
DevtoolScriptControlMsg::EvaluateJS(_pipe_id, string, sender) => {
|
||||||
DevtoolScriptControlMsg::EvaluateJS(_pipe_id, string, sender) =>
|
devtools::handle_evaluate_js(self.upcast(), string, sender)
|
||||||
devtools::handle_evaluate_js(self.upcast(), string, sender),
|
|
||||||
DevtoolScriptControlMsg::GetCachedMessages(pipe_id, message_types, sender) =>
|
|
||||||
devtools::handle_get_cached_messages(pipe_id, message_types, sender),
|
|
||||||
DevtoolScriptControlMsg::WantsLiveNotifications(_pipe_id, bool_val) =>
|
|
||||||
devtools::handle_wants_live_notifications(self.upcast(), bool_val),
|
|
||||||
_ => debug!("got an unusable devtools control message inside the worker!"),
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
MixedMessage::FromScheduler((linked_worker, timer_event)) => {
|
DevtoolScriptControlMsg::GetCachedMessages(pipe_id, message_types, sender) => {
|
||||||
match timer_event {
|
devtools::handle_get_cached_messages(pipe_id, message_types, sender)
|
||||||
|
},
|
||||||
|
DevtoolScriptControlMsg::WantsLiveNotifications(_pipe_id, bool_val) => {
|
||||||
|
devtools::handle_wants_live_notifications(self.upcast(), bool_val)
|
||||||
|
},
|
||||||
|
_ => debug!("got an unusable devtools control message inside the worker!"),
|
||||||
|
},
|
||||||
|
MixedMessage::FromScheduler((linked_worker, timer_event)) => match timer_event {
|
||||||
TimerEvent(TimerSource::FromWorker, id) => {
|
TimerEvent(TimerSource::FromWorker, id) => {
|
||||||
let _ar = AutoWorkerReset::new(self, linked_worker);
|
let _ar = AutoWorkerReset::new(self, linked_worker);
|
||||||
let scope = self.upcast::<WorkerGlobalScope>();
|
let scope = self.upcast::<WorkerGlobalScope>();
|
||||||
scope.handle_fire_timer(id);
|
scope.handle_fire_timer(id);
|
||||||
},
|
},
|
||||||
TimerEvent(_, _) => {
|
TimerEvent(_, _) => panic!("A worker received a TimerEvent from a window."),
|
||||||
panic!("A worker received a TimerEvent from a window.")
|
},
|
||||||
}
|
MixedMessage::FromWorker(DedicatedWorkerScriptMsg::CommonWorker(
|
||||||
}
|
linked_worker,
|
||||||
}
|
msg,
|
||||||
MixedMessage::FromWorker(DedicatedWorkerScriptMsg::CommonWorker(linked_worker, msg)) => {
|
)) => {
|
||||||
let _ar = AutoWorkerReset::new(self, linked_worker);
|
let _ar = AutoWorkerReset::new(self, linked_worker);
|
||||||
self.handle_script_event(msg);
|
self.handle_script_event(msg);
|
||||||
}
|
},
|
||||||
MixedMessage::FromWorker(DedicatedWorkerScriptMsg::WakeUp) => {},
|
MixedMessage::FromWorker(DedicatedWorkerScriptMsg::WakeUp) => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -452,7 +489,8 @@ impl DedicatedWorkerGlobalScope {
|
||||||
global.report_an_error(error_info, HandleValue::null());
|
global.report_an_error(error_info, HandleValue::null());
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
self.parent_sender.send(CommonScriptMsg::Task(
|
self.parent_sender
|
||||||
|
.send(CommonScriptMsg::Task(
|
||||||
WorkerEvent,
|
WorkerEvent,
|
||||||
task,
|
task,
|
||||||
Some(pipeline_id),
|
Some(pipeline_id),
|
||||||
|
@ -463,8 +501,7 @@ impl DedicatedWorkerGlobalScope {
|
||||||
|
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
unsafe extern "C" fn interrupt_callback(cx: *mut JSContext) -> bool {
|
unsafe extern "C" fn interrupt_callback(cx: *mut JSContext) -> bool {
|
||||||
let worker =
|
let worker = DomRoot::downcast::<WorkerGlobalScope>(GlobalScope::from_context(cx))
|
||||||
DomRoot::downcast::<WorkerGlobalScope>(GlobalScope::from_context(cx))
|
|
||||||
.expect("global is not a worker scope");
|
.expect("global is not a worker scope");
|
||||||
assert!(worker.is::<DedicatedWorkerGlobalScope>());
|
assert!(worker.is::<DedicatedWorkerGlobalScope>());
|
||||||
|
|
||||||
|
@ -483,7 +520,8 @@ impl DedicatedWorkerGlobalScopeMethods for DedicatedWorkerGlobalScope {
|
||||||
Worker::handle_message(worker, data);
|
Worker::handle_message(worker, data);
|
||||||
}));
|
}));
|
||||||
// TODO: Change this task source to a new `unshipped-port-message-queue` task source
|
// TODO: Change this task source to a new `unshipped-port-message-queue` task source
|
||||||
self.parent_sender.send(CommonScriptMsg::Task(
|
self.parent_sender
|
||||||
|
.send(CommonScriptMsg::Task(
|
||||||
WorkerEvent,
|
WorkerEvent,
|
||||||
task,
|
task,
|
||||||
Some(pipeline_id),
|
Some(pipeline_id),
|
||||||
|
|
|
@ -40,9 +40,11 @@ impl DissimilarOriginLocation {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(window: &DissimilarOriginWindow) -> DomRoot<DissimilarOriginLocation> {
|
pub fn new(window: &DissimilarOriginWindow) -> DomRoot<DissimilarOriginLocation> {
|
||||||
reflect_dom_object(Box::new(DissimilarOriginLocation::new_inherited(window)),
|
reflect_dom_object(
|
||||||
|
Box::new(DissimilarOriginLocation::new_inherited(window)),
|
||||||
window,
|
window,
|
||||||
DissimilarOriginLocationBinding::Wrap)
|
DissimilarOriginLocationBinding::Wrap,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
|
|
@ -46,10 +46,7 @@ pub struct DissimilarOriginWindow {
|
||||||
|
|
||||||
impl DissimilarOriginWindow {
|
impl DissimilarOriginWindow {
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
pub fn new(
|
pub fn new(global_to_clone_from: &GlobalScope, window_proxy: &WindowProxy) -> DomRoot<Self> {
|
||||||
global_to_clone_from: &GlobalScope,
|
|
||||||
window_proxy: &WindowProxy,
|
|
||||||
) -> DomRoot<Self> {
|
|
||||||
let cx = global_to_clone_from.get_cx();
|
let cx = global_to_clone_from.get_cx();
|
||||||
// Any timer events fired on this window are ignored.
|
// Any timer events fired on this window are ignored.
|
||||||
let (timer_event_chan, _) = ipc::channel().unwrap();
|
let (timer_event_chan, _) = ipc::channel().unwrap();
|
||||||
|
@ -142,7 +139,12 @@ impl DissimilarOriginWindowMethods for DissimilarOriginWindow {
|
||||||
|
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-window-postmessage
|
// https://html.spec.whatwg.org/multipage/#dom-window-postmessage
|
||||||
unsafe fn PostMessage(&self, cx: *mut JSContext, message: HandleValue, origin: DOMString) -> ErrorResult {
|
unsafe fn PostMessage(
|
||||||
|
&self,
|
||||||
|
cx: *mut JSContext,
|
||||||
|
message: HandleValue,
|
||||||
|
origin: DOMString,
|
||||||
|
) -> ErrorResult {
|
||||||
// Step 3-5.
|
// Step 3-5.
|
||||||
let origin = match &origin[..] {
|
let origin = match &origin[..] {
|
||||||
"*" => None,
|
"*" => None,
|
||||||
|
@ -153,7 +155,7 @@ impl DissimilarOriginWindowMethods for DissimilarOriginWindow {
|
||||||
url => match ServoUrl::parse(&url) {
|
url => match ServoUrl::parse(&url) {
|
||||||
Ok(url) => Some(url.origin()),
|
Ok(url) => Some(url.origin()),
|
||||||
Err(_) => return Err(Error::Syntax),
|
Err(_) => return Err(Error::Syntax),
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// Step 1-2, 6-8.
|
// Step 1-2, 6-8.
|
||||||
|
@ -190,7 +192,8 @@ impl DissimilarOriginWindowMethods for DissimilarOriginWindow {
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-location
|
// https://html.spec.whatwg.org/multipage/#dom-location
|
||||||
fn Location(&self) -> DomRoot<DissimilarOriginLocation> {
|
fn Location(&self) -> DomRoot<DissimilarOriginLocation> {
|
||||||
self.location.or_init(|| DissimilarOriginLocation::new(self))
|
self.location
|
||||||
|
.or_init(|| DissimilarOriginLocation::new(self))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,9 +203,11 @@ impl DissimilarOriginWindow {
|
||||||
None => return warn!("postMessage called with no incumbent global"),
|
None => return warn!("postMessage called with no incumbent global"),
|
||||||
Some(incumbent) => incumbent,
|
Some(incumbent) => incumbent,
|
||||||
};
|
};
|
||||||
let msg = ScriptMsg::PostMessage(self.window_proxy.browsing_context_id(),
|
let msg = ScriptMsg::PostMessage(
|
||||||
|
self.window_proxy.browsing_context_id(),
|
||||||
origin,
|
origin,
|
||||||
data.move_to_arraybuffer());
|
data.move_to_arraybuffer(),
|
||||||
|
);
|
||||||
let _ = incumbent.script_to_constellation_chan().send(msg);
|
let _ = incumbent.script_to_constellation_chan().send(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -34,9 +34,11 @@ impl DocumentFragment {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(document: &Document) -> DomRoot<DocumentFragment> {
|
pub fn new(document: &Document) -> DomRoot<DocumentFragment> {
|
||||||
Node::reflect_node(Box::new(DocumentFragment::new_inherited(document)),
|
Node::reflect_node(
|
||||||
|
Box::new(DocumentFragment::new_inherited(document)),
|
||||||
document,
|
document,
|
||||||
DocumentFragmentBinding::Wrap)
|
DocumentFragmentBinding::Wrap,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn Constructor(window: &Window) -> Fallible<DomRoot<DocumentFragment>> {
|
pub fn Constructor(window: &Window) -> Fallible<DomRoot<DocumentFragment>> {
|
||||||
|
@ -57,12 +59,14 @@ impl DocumentFragmentMethods for DocumentFragment {
|
||||||
fn GetElementById(&self, id: DOMString) -> Option<DomRoot<Element>> {
|
fn GetElementById(&self, id: DOMString) -> Option<DomRoot<Element>> {
|
||||||
let node = self.upcast::<Node>();
|
let node = self.upcast::<Node>();
|
||||||
let id = Atom::from(id);
|
let id = Atom::from(id);
|
||||||
node.traverse_preorder().filter_map(DomRoot::downcast::<Element>).find(|descendant| {
|
node.traverse_preorder()
|
||||||
match descendant.get_attribute(&ns!(), &local_name!("id")) {
|
.filter_map(DomRoot::downcast::<Element>)
|
||||||
|
.find(
|
||||||
|
|descendant| match descendant.get_attribute(&ns!(), &local_name!("id")) {
|
||||||
None => false,
|
None => false,
|
||||||
Some(attr) => *attr.value().as_atom() == id,
|
Some(attr) => *attr.value().as_atom() == id,
|
||||||
}
|
},
|
||||||
})
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://dom.spec.whatwg.org/#dom-parentnode-firstelementchild
|
// https://dom.spec.whatwg.org/#dom-parentnode-firstelementchild
|
||||||
|
@ -72,7 +76,10 @@ impl DocumentFragmentMethods for DocumentFragment {
|
||||||
|
|
||||||
// https://dom.spec.whatwg.org/#dom-parentnode-lastelementchild
|
// https://dom.spec.whatwg.org/#dom-parentnode-lastelementchild
|
||||||
fn GetLastElementChild(&self) -> Option<DomRoot<Element>> {
|
fn GetLastElementChild(&self) -> Option<DomRoot<Element>> {
|
||||||
self.upcast::<Node>().rev_children().filter_map(DomRoot::downcast::<Element>).next()
|
self.upcast::<Node>()
|
||||||
|
.rev_children()
|
||||||
|
.filter_map(DomRoot::downcast::<Element>)
|
||||||
|
.next()
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://dom.spec.whatwg.org/#dom-parentnode-childelementcount
|
// https://dom.spec.whatwg.org/#dom-parentnode-childelementcount
|
||||||
|
|
|
@ -24,11 +24,12 @@ pub struct DocumentType {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DocumentType {
|
impl DocumentType {
|
||||||
fn new_inherited(name: DOMString,
|
fn new_inherited(
|
||||||
|
name: DOMString,
|
||||||
public_id: Option<DOMString>,
|
public_id: Option<DOMString>,
|
||||||
system_id: Option<DOMString>,
|
system_id: Option<DOMString>,
|
||||||
document: &Document)
|
document: &Document,
|
||||||
-> DocumentType {
|
) -> DocumentType {
|
||||||
DocumentType {
|
DocumentType {
|
||||||
node: Node::new_inherited(document),
|
node: Node::new_inherited(document),
|
||||||
name: name,
|
name: name,
|
||||||
|
@ -37,14 +38,19 @@ impl DocumentType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[allow(unrooted_must_root)]
|
#[allow(unrooted_must_root)]
|
||||||
pub fn new(name: DOMString,
|
pub fn new(
|
||||||
|
name: DOMString,
|
||||||
public_id: Option<DOMString>,
|
public_id: Option<DOMString>,
|
||||||
system_id: Option<DOMString>,
|
system_id: Option<DOMString>,
|
||||||
document: &Document)
|
document: &Document,
|
||||||
-> DomRoot<DocumentType> {
|
) -> DomRoot<DocumentType> {
|
||||||
Node::reflect_node(Box::new(DocumentType::new_inherited(name, public_id, system_id, document)),
|
Node::reflect_node(
|
||||||
|
Box::new(DocumentType::new_inherited(
|
||||||
|
name, public_id, system_id, document,
|
||||||
|
)),
|
||||||
document,
|
document,
|
||||||
DocumentTypeBinding::Wrap)
|
DocumentTypeBinding::Wrap,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -53,9 +53,11 @@ impl DOMException {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(global: &GlobalScope, code: DOMErrorName) -> DomRoot<DOMException> {
|
pub fn new(global: &GlobalScope, code: DOMErrorName) -> DomRoot<DOMException> {
|
||||||
reflect_dom_object(Box::new(DOMException::new_inherited(code)),
|
reflect_dom_object(
|
||||||
|
Box::new(DOMException::new_inherited(code)),
|
||||||
global,
|
global,
|
||||||
DOMExceptionBinding::Wrap)
|
DOMExceptionBinding::Wrap,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,7 +76,9 @@ impl DOMExceptionMethods for DOMException {
|
||||||
fn Message(&self) -> DOMString {
|
fn Message(&self) -> DOMString {
|
||||||
let message = match self.code {
|
let message = match self.code {
|
||||||
DOMErrorName::IndexSizeError => "The index is not in the allowed range.",
|
DOMErrorName::IndexSizeError => "The index is not in the allowed range.",
|
||||||
DOMErrorName::HierarchyRequestError => "The operation would yield an incorrect node tree.",
|
DOMErrorName::HierarchyRequestError => {
|
||||||
|
"The operation would yield an incorrect node tree."
|
||||||
|
},
|
||||||
DOMErrorName::WrongDocumentError => "The object is in the wrong document.",
|
DOMErrorName::WrongDocumentError => "The object is in the wrong document.",
|
||||||
DOMErrorName::InvalidCharacterError => "The string contains invalid characters.",
|
DOMErrorName::InvalidCharacterError => "The string contains invalid characters.",
|
||||||
DOMErrorName::NoModificationAllowedError => "The object can not be modified.",
|
DOMErrorName::NoModificationAllowedError => "The object can not be modified.",
|
||||||
|
@ -85,17 +89,20 @@ impl DOMExceptionMethods for DOMException {
|
||||||
DOMErrorName::SyntaxError => "The string did not match the expected pattern.",
|
DOMErrorName::SyntaxError => "The string did not match the expected pattern.",
|
||||||
DOMErrorName::InvalidModificationError => "The object can not be modified in this way.",
|
DOMErrorName::InvalidModificationError => "The object can not be modified in this way.",
|
||||||
DOMErrorName::NamespaceError => "The operation is not allowed by Namespaces in XML.",
|
DOMErrorName::NamespaceError => "The operation is not allowed by Namespaces in XML.",
|
||||||
DOMErrorName::InvalidAccessError => "The object does not support the operation or argument.",
|
DOMErrorName::InvalidAccessError => {
|
||||||
|
"The object does not support the operation or argument."
|
||||||
|
},
|
||||||
DOMErrorName::SecurityError => "The operation is insecure.",
|
DOMErrorName::SecurityError => "The operation is insecure.",
|
||||||
DOMErrorName::NetworkError => "A network error occurred.",
|
DOMErrorName::NetworkError => "A network error occurred.",
|
||||||
DOMErrorName::AbortError => "The operation was aborted.",
|
DOMErrorName::AbortError => "The operation was aborted.",
|
||||||
DOMErrorName::TypeMismatchError => "The given type does not match any expected type.",
|
DOMErrorName::TypeMismatchError => "The given type does not match any expected type.",
|
||||||
DOMErrorName::QuotaExceededError => "The quota has been exceeded.",
|
DOMErrorName::QuotaExceededError => "The quota has been exceeded.",
|
||||||
DOMErrorName::TimeoutError => "The operation timed out.",
|
DOMErrorName::TimeoutError => "The operation timed out.",
|
||||||
DOMErrorName::InvalidNodeTypeError =>
|
DOMErrorName::InvalidNodeTypeError => {
|
||||||
"The supplied node is incorrect or has an incorrect ancestor for this operation.",
|
"The supplied node is incorrect or has an incorrect ancestor for this operation."
|
||||||
|
},
|
||||||
DOMErrorName::DataCloneError => "The object can not be cloned.",
|
DOMErrorName::DataCloneError => "The object can not be cloned.",
|
||||||
DOMErrorName::NotReadableError => "The I/O read operation failed."
|
DOMErrorName::NotReadableError => "The I/O read operation failed.",
|
||||||
};
|
};
|
||||||
|
|
||||||
DOMString::from(message)
|
DOMString::from(message)
|
||||||
|
|
|
@ -44,42 +44,60 @@ impl DOMImplementation {
|
||||||
|
|
||||||
pub fn new(document: &Document) -> DomRoot<DOMImplementation> {
|
pub fn new(document: &Document) -> DomRoot<DOMImplementation> {
|
||||||
let window = document.window();
|
let window = document.window();
|
||||||
reflect_dom_object(Box::new(DOMImplementation::new_inherited(document)),
|
reflect_dom_object(
|
||||||
|
Box::new(DOMImplementation::new_inherited(document)),
|
||||||
window,
|
window,
|
||||||
DOMImplementationBinding::Wrap)
|
DOMImplementationBinding::Wrap,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://dom.spec.whatwg.org/#domimplementation
|
// https://dom.spec.whatwg.org/#domimplementation
|
||||||
impl DOMImplementationMethods for DOMImplementation {
|
impl DOMImplementationMethods for DOMImplementation {
|
||||||
// https://dom.spec.whatwg.org/#dom-domimplementation-createdocumenttype
|
// https://dom.spec.whatwg.org/#dom-domimplementation-createdocumenttype
|
||||||
fn CreateDocumentType(&self,
|
fn CreateDocumentType(
|
||||||
|
&self,
|
||||||
qualified_name: DOMString,
|
qualified_name: DOMString,
|
||||||
pubid: DOMString,
|
pubid: DOMString,
|
||||||
sysid: DOMString)
|
sysid: DOMString,
|
||||||
-> Fallible<DomRoot<DocumentType>> {
|
) -> Fallible<DomRoot<DocumentType>> {
|
||||||
validate_qualified_name(&qualified_name)?;
|
validate_qualified_name(&qualified_name)?;
|
||||||
Ok(DocumentType::new(qualified_name, Some(pubid), Some(sysid), &self.document))
|
Ok(DocumentType::new(
|
||||||
|
qualified_name,
|
||||||
|
Some(pubid),
|
||||||
|
Some(sysid),
|
||||||
|
&self.document,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://dom.spec.whatwg.org/#dom-domimplementation-createdocument
|
// https://dom.spec.whatwg.org/#dom-domimplementation-createdocument
|
||||||
fn CreateDocument(&self,
|
fn CreateDocument(
|
||||||
|
&self,
|
||||||
maybe_namespace: Option<DOMString>,
|
maybe_namespace: Option<DOMString>,
|
||||||
qname: DOMString,
|
qname: DOMString,
|
||||||
maybe_doctype: Option<&DocumentType>)
|
maybe_doctype: Option<&DocumentType>,
|
||||||
-> Fallible<DomRoot<XMLDocument>> {
|
) -> Fallible<DomRoot<XMLDocument>> {
|
||||||
let win = self.document.window();
|
let win = self.document.window();
|
||||||
let loader = DocumentLoader::new(&self.document.loader());
|
let loader = DocumentLoader::new(&self.document.loader());
|
||||||
let namespace = namespace_from_domstring(maybe_namespace.to_owned());
|
let namespace = namespace_from_domstring(maybe_namespace.to_owned());
|
||||||
|
|
||||||
let content_type = match namespace {
|
let content_type = match namespace {
|
||||||
ns!(html) => Mime(TopLevel::Application, SubLevel::Ext("xhtml+xml".to_string()), vec![]),
|
ns!(html) => Mime(
|
||||||
ns!(svg) => Mime(TopLevel::Image, SubLevel::Ext("svg+xml".to_string()), vec![]),
|
TopLevel::Application,
|
||||||
_ => Mime(TopLevel::Application, SubLevel::Xml, vec![])
|
SubLevel::Ext("xhtml+xml".to_string()),
|
||||||
|
vec![],
|
||||||
|
),
|
||||||
|
ns!(svg) => Mime(
|
||||||
|
TopLevel::Image,
|
||||||
|
SubLevel::Ext("svg+xml".to_string()),
|
||||||
|
vec![],
|
||||||
|
),
|
||||||
|
_ => Mime(TopLevel::Application, SubLevel::Xml, vec![]),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Step 1.
|
// Step 1.
|
||||||
let doc = XMLDocument::new(win,
|
let doc = XMLDocument::new(
|
||||||
|
win,
|
||||||
HasBrowsingContext::No,
|
HasBrowsingContext::No,
|
||||||
None,
|
None,
|
||||||
self.document.origin().clone(),
|
self.document.origin().clone(),
|
||||||
|
@ -88,13 +106,17 @@ impl DOMImplementationMethods for DOMImplementation {
|
||||||
None,
|
None,
|
||||||
DocumentActivity::Inactive,
|
DocumentActivity::Inactive,
|
||||||
DocumentSource::NotFromParser,
|
DocumentSource::NotFromParser,
|
||||||
loader);
|
loader,
|
||||||
|
);
|
||||||
// Step 2-3.
|
// Step 2-3.
|
||||||
let maybe_elem = if qname.is_empty() {
|
let maybe_elem = if qname.is_empty() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
let options = ElementCreationOptions { is: None };
|
let options = ElementCreationOptions { is: None };
|
||||||
match doc.upcast::<Document>().CreateElementNS(maybe_namespace, qname, &options) {
|
match doc
|
||||||
|
.upcast::<Document>()
|
||||||
|
.CreateElementNS(maybe_namespace, qname, &options)
|
||||||
|
{
|
||||||
Err(error) => return Err(error),
|
Err(error) => return Err(error),
|
||||||
Ok(elem) => Some(elem),
|
Ok(elem) => Some(elem),
|
||||||
}
|
}
|
||||||
|
@ -127,7 +149,8 @@ impl DOMImplementationMethods for DOMImplementation {
|
||||||
let loader = DocumentLoader::new(&self.document.loader());
|
let loader = DocumentLoader::new(&self.document.loader());
|
||||||
|
|
||||||
// Step 1-2.
|
// Step 1-2.
|
||||||
let doc = Document::new(win,
|
let doc = Document::new(
|
||||||
|
win,
|
||||||
HasBrowsingContext::No,
|
HasBrowsingContext::No,
|
||||||
None,
|
None,
|
||||||
self.document.origin().clone(),
|
self.document.origin().clone(),
|
||||||
|
@ -139,7 +162,8 @@ impl DOMImplementationMethods for DOMImplementation {
|
||||||
loader,
|
loader,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
Default::default());
|
Default::default(),
|
||||||
|
);
|
||||||
|
|
||||||
{
|
{
|
||||||
// Step 3.
|
// Step 3.
|
||||||
|
@ -151,25 +175,24 @@ impl DOMImplementationMethods for DOMImplementation {
|
||||||
{
|
{
|
||||||
// Step 4.
|
// Step 4.
|
||||||
let doc_node = doc.upcast::<Node>();
|
let doc_node = doc.upcast::<Node>();
|
||||||
let doc_html = DomRoot::upcast::<Node>(HTMLHtmlElement::new(local_name!("html"),
|
let doc_html =
|
||||||
None,
|
DomRoot::upcast::<Node>(HTMLHtmlElement::new(local_name!("html"), None, &doc));
|
||||||
&doc));
|
|
||||||
doc_node.AppendChild(&doc_html).expect("Appending failed");
|
doc_node.AppendChild(&doc_html).expect("Appending failed");
|
||||||
|
|
||||||
{
|
{
|
||||||
// Step 5.
|
// Step 5.
|
||||||
let doc_head = DomRoot::upcast::<Node>(HTMLHeadElement::new(local_name!("head"),
|
let doc_head =
|
||||||
None,
|
DomRoot::upcast::<Node>(HTMLHeadElement::new(local_name!("head"), None, &doc));
|
||||||
&doc));
|
|
||||||
doc_html.AppendChild(&doc_head).unwrap();
|
doc_html.AppendChild(&doc_head).unwrap();
|
||||||
|
|
||||||
// Step 6.
|
// Step 6.
|
||||||
if let Some(title_str) = title {
|
if let Some(title_str) = title {
|
||||||
// Step 6.1.
|
// Step 6.1.
|
||||||
let doc_title =
|
let doc_title = DomRoot::upcast::<Node>(HTMLTitleElement::new(
|
||||||
DomRoot::upcast::<Node>(HTMLTitleElement::new(local_name!("title"),
|
local_name!("title"),
|
||||||
None,
|
None,
|
||||||
&doc));
|
&doc,
|
||||||
|
));
|
||||||
doc_head.AppendChild(&doc_title).unwrap();
|
doc_head.AppendChild(&doc_title).unwrap();
|
||||||
|
|
||||||
// Step 6.2.
|
// Step 6.2.
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,18 +53,12 @@ impl DOMMatrixReadOnly {
|
||||||
|
|
||||||
// https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-dommatrixreadonly-numbersequence
|
// https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-dommatrixreadonly-numbersequence
|
||||||
pub fn Constructor_(global: &GlobalScope, entries: Vec<f64>) -> Fallible<DomRoot<Self>> {
|
pub fn Constructor_(global: &GlobalScope, entries: Vec<f64>) -> Fallible<DomRoot<Self>> {
|
||||||
entries_to_matrix(&entries[..])
|
entries_to_matrix(&entries[..]).map(|(is2D, matrix)| Self::new(global, is2D, matrix))
|
||||||
.map(|(is2D, matrix)| {
|
|
||||||
Self::new(global, is2D, matrix)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-frommatrix
|
// https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-frommatrix
|
||||||
pub fn FromMatrix(global: &GlobalScope, other: &DOMMatrixInit) -> Fallible<DomRoot<Self>> {
|
pub fn FromMatrix(global: &GlobalScope, other: &DOMMatrixInit) -> Fallible<DomRoot<Self>> {
|
||||||
dommatrixinit_to_matrix(&other)
|
dommatrixinit_to_matrix(&other).map(|(is2D, matrix)| Self::new(global, is2D, matrix))
|
||||||
.map(|(is2D, matrix)| {
|
|
||||||
Self::new(global, is2D, matrix)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn matrix(&self) -> Ref<Transform3D<f64>> {
|
pub fn matrix(&self) -> Ref<Transform3D<f64>> {
|
||||||
|
@ -155,7 +149,6 @@ impl DOMMatrixReadOnly {
|
||||||
self.matrix.borrow_mut().m44 = value;
|
self.matrix.borrow_mut().m44 = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// https://drafts.fxtf.org/geometry-1/#dom-dommatrix-multiplyself
|
// https://drafts.fxtf.org/geometry-1/#dom-dommatrix-multiplyself
|
||||||
pub fn multiply_self(&self, other: &DOMMatrixInit) -> Fallible<()> {
|
pub fn multiply_self(&self, other: &DOMMatrixInit) -> Fallible<()> {
|
||||||
// Step 1.
|
// Step 1.
|
||||||
|
@ -200,8 +193,15 @@ impl DOMMatrixReadOnly {
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://drafts.fxtf.org/geometry-1/#dom-dommatrix-scaleself
|
// https://drafts.fxtf.org/geometry-1/#dom-dommatrix-scaleself
|
||||||
pub fn scale_self(&self, scaleX: f64, scaleY: Option<f64>, scaleZ: f64,
|
pub fn scale_self(
|
||||||
mut originX: f64, mut originY: f64, mut originZ: f64) {
|
&self,
|
||||||
|
scaleX: f64,
|
||||||
|
scaleY: Option<f64>,
|
||||||
|
scaleZ: f64,
|
||||||
|
mut originX: f64,
|
||||||
|
mut originY: f64,
|
||||||
|
mut originZ: f64,
|
||||||
|
) {
|
||||||
// Step 1.
|
// Step 1.
|
||||||
self.translate_self(originX, originY, originZ);
|
self.translate_self(originX, originY, originZ);
|
||||||
// Step 2.
|
// Step 2.
|
||||||
|
@ -262,19 +262,22 @@ impl DOMMatrixReadOnly {
|
||||||
}
|
}
|
||||||
if rotZ != 0.0 {
|
if rotZ != 0.0 {
|
||||||
// Step 5.
|
// Step 5.
|
||||||
let rotation = Transform3D::create_rotation(0.0, 0.0, 1.0, Angle::radians(rotZ.to_radians()));
|
let rotation =
|
||||||
|
Transform3D::create_rotation(0.0, 0.0, 1.0, Angle::radians(rotZ.to_radians()));
|
||||||
let mut matrix = self.matrix.borrow_mut();
|
let mut matrix = self.matrix.borrow_mut();
|
||||||
*matrix = rotation.post_mul(&matrix);
|
*matrix = rotation.post_mul(&matrix);
|
||||||
}
|
}
|
||||||
if rotY != 0.0 {
|
if rotY != 0.0 {
|
||||||
// Step 6.
|
// Step 6.
|
||||||
let rotation = Transform3D::create_rotation(0.0, 1.0, 0.0, Angle::radians(rotY.to_radians()));
|
let rotation =
|
||||||
|
Transform3D::create_rotation(0.0, 1.0, 0.0, Angle::radians(rotY.to_radians()));
|
||||||
let mut matrix = self.matrix.borrow_mut();
|
let mut matrix = self.matrix.borrow_mut();
|
||||||
*matrix = rotation.post_mul(&matrix);
|
*matrix = rotation.post_mul(&matrix);
|
||||||
}
|
}
|
||||||
if rotX != 0.0 {
|
if rotX != 0.0 {
|
||||||
// Step 7.
|
// Step 7.
|
||||||
let rotation = Transform3D::create_rotation(1.0, 0.0, 0.0, Angle::radians(rotX.to_radians()));
|
let rotation =
|
||||||
|
Transform3D::create_rotation(1.0, 0.0, 0.0, Angle::radians(rotX.to_radians()));
|
||||||
let mut matrix = self.matrix.borrow_mut();
|
let mut matrix = self.matrix.borrow_mut();
|
||||||
*matrix = rotation.post_mul(&matrix);
|
*matrix = rotation.post_mul(&matrix);
|
||||||
}
|
}
|
||||||
|
@ -298,7 +301,12 @@ impl DOMMatrixReadOnly {
|
||||||
pub fn rotate_axis_angle_self(&self, x: f64, y: f64, z: f64, angle: f64) {
|
pub fn rotate_axis_angle_self(&self, x: f64, y: f64, z: f64, angle: f64) {
|
||||||
// Step 1.
|
// Step 1.
|
||||||
let (norm_x, norm_y, norm_z) = normalize_point(x, y, z);
|
let (norm_x, norm_y, norm_z) = normalize_point(x, y, z);
|
||||||
let rotation = Transform3D::create_rotation(norm_x, norm_y, norm_z, Angle::radians(angle.to_radians()));
|
let rotation = Transform3D::create_rotation(
|
||||||
|
norm_x,
|
||||||
|
norm_y,
|
||||||
|
norm_z,
|
||||||
|
Angle::radians(angle.to_radians()),
|
||||||
|
);
|
||||||
let mut matrix = self.matrix.borrow_mut();
|
let mut matrix = self.matrix.borrow_mut();
|
||||||
*matrix = rotation.post_mul(&matrix);
|
*matrix = rotation.post_mul(&matrix);
|
||||||
// Step 2.
|
// Step 2.
|
||||||
|
@ -333,10 +341,24 @@ impl DOMMatrixReadOnly {
|
||||||
*matrix = matrix.inverse().unwrap_or_else(|| {
|
*matrix = matrix.inverse().unwrap_or_else(|| {
|
||||||
// Step 2.
|
// Step 2.
|
||||||
self.is2D.set(false);
|
self.is2D.set(false);
|
||||||
Transform3D::row_major(f64::NAN, f64::NAN, f64::NAN, f64::NAN,
|
Transform3D::row_major(
|
||||||
f64::NAN, f64::NAN, f64::NAN, f64::NAN,
|
f64::NAN,
|
||||||
f64::NAN, f64::NAN, f64::NAN, f64::NAN,
|
f64::NAN,
|
||||||
f64::NAN, f64::NAN, f64::NAN, f64::NAN)
|
f64::NAN,
|
||||||
|
f64::NAN,
|
||||||
|
f64::NAN,
|
||||||
|
f64::NAN,
|
||||||
|
f64::NAN,
|
||||||
|
f64::NAN,
|
||||||
|
f64::NAN,
|
||||||
|
f64::NAN,
|
||||||
|
f64::NAN,
|
||||||
|
f64::NAN,
|
||||||
|
f64::NAN,
|
||||||
|
f64::NAN,
|
||||||
|
f64::NAN,
|
||||||
|
f64::NAN,
|
||||||
|
)
|
||||||
})
|
})
|
||||||
// Step 3 in DOMMatrix.InvertSelf
|
// Step 3 in DOMMatrix.InvertSelf
|
||||||
}
|
}
|
||||||
|
@ -362,7 +384,6 @@ impl DOMMatrixReadOnly {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl DOMMatrixReadOnlyMethods for DOMMatrixReadOnly {
|
impl DOMMatrixReadOnlyMethods for DOMMatrixReadOnly {
|
||||||
// https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m11
|
// https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m11
|
||||||
fn M11(&self) -> f64 {
|
fn M11(&self) -> f64 {
|
||||||
|
@ -482,10 +503,22 @@ impl DOMMatrixReadOnlyMethods for DOMMatrixReadOnly {
|
||||||
// https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-isidentity
|
// https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-isidentity
|
||||||
fn IsIdentity(&self) -> bool {
|
fn IsIdentity(&self) -> bool {
|
||||||
let matrix = self.matrix.borrow();
|
let matrix = self.matrix.borrow();
|
||||||
matrix.m12 == 0.0 && matrix.m13 == 0.0 && matrix.m14 == 0.0 && matrix.m21 == 0.0 &&
|
matrix.m12 == 0.0 &&
|
||||||
matrix.m23 == 0.0 && matrix.m24 == 0.0 && matrix.m31 == 0.0 && matrix.m32 == 0.0 &&
|
matrix.m13 == 0.0 &&
|
||||||
matrix.m34 == 0.0 && matrix.m41 == 0.0 && matrix.m42 == 0.0 && matrix.m43 == 0.0 &&
|
matrix.m14 == 0.0 &&
|
||||||
matrix.m11 == 1.0 && matrix.m22 == 1.0 && matrix.m33 == 1.0 && matrix.m44 == 1.0
|
matrix.m21 == 0.0 &&
|
||||||
|
matrix.m23 == 0.0 &&
|
||||||
|
matrix.m24 == 0.0 &&
|
||||||
|
matrix.m31 == 0.0 &&
|
||||||
|
matrix.m32 == 0.0 &&
|
||||||
|
matrix.m34 == 0.0 &&
|
||||||
|
matrix.m41 == 0.0 &&
|
||||||
|
matrix.m42 == 0.0 &&
|
||||||
|
matrix.m43 == 0.0 &&
|
||||||
|
matrix.m11 == 1.0 &&
|
||||||
|
matrix.m22 == 1.0 &&
|
||||||
|
matrix.m33 == 1.0 &&
|
||||||
|
matrix.m44 == 1.0
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-translate
|
// https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-translate
|
||||||
|
@ -494,16 +527,22 @@ impl DOMMatrixReadOnlyMethods for DOMMatrixReadOnly {
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-scale
|
// https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-scale
|
||||||
fn Scale(&self, scaleX: f64, scaleY: Option<f64>, scaleZ: f64,
|
fn Scale(
|
||||||
originX: f64, originY: f64, originZ: f64) -> DomRoot<DOMMatrix> {
|
&self,
|
||||||
|
scaleX: f64,
|
||||||
|
scaleY: Option<f64>,
|
||||||
|
scaleZ: f64,
|
||||||
|
originX: f64,
|
||||||
|
originY: f64,
|
||||||
|
originZ: f64,
|
||||||
|
) -> DomRoot<DOMMatrix> {
|
||||||
DOMMatrix::from_readonly(&self.global(), self)
|
DOMMatrix::from_readonly(&self.global(), self)
|
||||||
.ScaleSelf(scaleX, scaleY, scaleZ, originX, originY, originZ)
|
.ScaleSelf(scaleX, scaleY, scaleZ, originX, originY, originZ)
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-scale3d
|
// https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-scale3d
|
||||||
fn Scale3d(&self, scale: f64, originX: f64, originY: f64, originZ: f64) -> DomRoot<DOMMatrix> {
|
fn Scale3d(&self, scale: f64, originX: f64, originY: f64, originZ: f64) -> DomRoot<DOMMatrix> {
|
||||||
DOMMatrix::from_readonly(&self.global(), self)
|
DOMMatrix::from_readonly(&self.global(), self).Scale3dSelf(scale, originX, originY, originZ)
|
||||||
.Scale3dSelf(scale, originX, originY, originZ)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-rotate
|
// https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-rotate
|
||||||
|
@ -539,10 +578,9 @@ impl DOMMatrixReadOnlyMethods for DOMMatrixReadOnly {
|
||||||
// https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-flipx
|
// https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-flipx
|
||||||
fn FlipX(&self) -> DomRoot<DOMMatrix> {
|
fn FlipX(&self) -> DomRoot<DOMMatrix> {
|
||||||
let is2D = self.is2D.get();
|
let is2D = self.is2D.get();
|
||||||
let flip = Transform3D::row_major(-1.0, 0.0, 0.0, 0.0,
|
let flip = Transform3D::row_major(
|
||||||
0.0, 1.0, 0.0, 0.0,
|
-1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0,
|
||||||
0.0, 0.0, 1.0, 0.0,
|
);
|
||||||
0.0, 0.0, 0.0, 1.0);
|
|
||||||
let matrix = flip.post_mul(&self.matrix.borrow());
|
let matrix = flip.post_mul(&self.matrix.borrow());
|
||||||
DOMMatrix::new(&self.global(), is2D, matrix)
|
DOMMatrix::new(&self.global(), is2D, matrix)
|
||||||
}
|
}
|
||||||
|
@ -550,10 +588,9 @@ impl DOMMatrixReadOnlyMethods for DOMMatrixReadOnly {
|
||||||
// https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-flipy
|
// https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-flipy
|
||||||
fn FlipY(&self) -> DomRoot<DOMMatrix> {
|
fn FlipY(&self) -> DomRoot<DOMMatrix> {
|
||||||
let is2D = self.is2D.get();
|
let is2D = self.is2D.get();
|
||||||
let flip = Transform3D::row_major(1.0, 0.0, 0.0, 0.0,
|
let flip = Transform3D::row_major(
|
||||||
0.0, -1.0, 0.0, 0.0,
|
1.0, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0,
|
||||||
0.0, 0.0, 1.0, 0.0,
|
);
|
||||||
0.0, 0.0, 0.0, 1.0);
|
|
||||||
let matrix = flip.post_mul(&self.matrix.borrow());
|
let matrix = flip.post_mul(&self.matrix.borrow());
|
||||||
DOMMatrix::new(&self.global(), is2D, matrix)
|
DOMMatrix::new(&self.global(), is2D, matrix)
|
||||||
}
|
}
|
||||||
|
@ -583,11 +620,15 @@ impl DOMMatrixReadOnlyMethods for DOMMatrixReadOnly {
|
||||||
// https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-tofloat32array
|
// https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-tofloat32array
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
unsafe fn ToFloat32Array(&self, cx: *mut JSContext) -> NonNull<JSObject> {
|
unsafe fn ToFloat32Array(&self, cx: *mut JSContext) -> NonNull<JSObject> {
|
||||||
let vec: Vec<f32> = self.matrix
|
let vec: Vec<f32> = self
|
||||||
.borrow().to_row_major_array().iter().map(|&x| x as f32).collect();
|
.matrix
|
||||||
|
.borrow()
|
||||||
|
.to_row_major_array()
|
||||||
|
.iter()
|
||||||
|
.map(|&x| x as f32)
|
||||||
|
.collect();
|
||||||
rooted!(in (cx) let mut array = ptr::null_mut::<JSObject>());
|
rooted!(in (cx) let mut array = ptr::null_mut::<JSObject>());
|
||||||
let _ = Float32Array::create(cx, CreateWith::Slice(&vec), array.handle_mut())
|
let _ = Float32Array::create(cx, CreateWith::Slice(&vec), array.handle_mut()).unwrap();
|
||||||
.unwrap();
|
|
||||||
NonNull::new_unchecked(array.get())
|
NonNull::new_unchecked(array.get())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -596,28 +637,39 @@ impl DOMMatrixReadOnlyMethods for DOMMatrixReadOnly {
|
||||||
unsafe fn ToFloat64Array(&self, cx: *mut JSContext) -> NonNull<JSObject> {
|
unsafe fn ToFloat64Array(&self, cx: *mut JSContext) -> NonNull<JSObject> {
|
||||||
let arr = self.matrix.borrow().to_row_major_array();
|
let arr = self.matrix.borrow().to_row_major_array();
|
||||||
rooted!(in (cx) let mut array = ptr::null_mut::<JSObject>());
|
rooted!(in (cx) let mut array = ptr::null_mut::<JSObject>());
|
||||||
let _ = Float64Array::create(cx, CreateWith::Slice(&arr), array.handle_mut())
|
let _ = Float64Array::create(cx, CreateWith::Slice(&arr), array.handle_mut()).unwrap();
|
||||||
.unwrap();
|
|
||||||
NonNull::new_unchecked(array.get())
|
NonNull::new_unchecked(array.get())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// https://drafts.fxtf.org/geometry-1/#create-a-2d-matrix
|
// https://drafts.fxtf.org/geometry-1/#create-a-2d-matrix
|
||||||
fn create_2d_matrix(entries: &[f64]) -> Transform3D<f64> {
|
fn create_2d_matrix(entries: &[f64]) -> Transform3D<f64> {
|
||||||
Transform3D::row_major(entries[0], entries[1], 0.0, 0.0,
|
Transform3D::row_major(
|
||||||
entries[2], entries[3], 0.0, 0.0,
|
entries[0], entries[1], 0.0, 0.0, entries[2], entries[3], 0.0, 0.0, 0.0, 0.0, 1.0, 0.0,
|
||||||
0.0, 0.0, 1.0, 0.0,
|
entries[4], entries[5], 0.0, 1.0,
|
||||||
entries[4], entries[5], 0.0, 1.0)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// https://drafts.fxtf.org/geometry-1/#create-a-3d-matrix
|
// https://drafts.fxtf.org/geometry-1/#create-a-3d-matrix
|
||||||
fn create_3d_matrix(entries: &[f64]) -> Transform3D<f64> {
|
fn create_3d_matrix(entries: &[f64]) -> Transform3D<f64> {
|
||||||
Transform3D::row_major(entries[0], entries[1], entries[2], entries[3],
|
Transform3D::row_major(
|
||||||
entries[4], entries[5], entries[6], entries[7],
|
entries[0],
|
||||||
entries[8], entries[9], entries[10], entries[11],
|
entries[1],
|
||||||
entries[12], entries[13], entries[14], entries[15])
|
entries[2],
|
||||||
|
entries[3],
|
||||||
|
entries[4],
|
||||||
|
entries[5],
|
||||||
|
entries[6],
|
||||||
|
entries[7],
|
||||||
|
entries[8],
|
||||||
|
entries[9],
|
||||||
|
entries[10],
|
||||||
|
entries[11],
|
||||||
|
entries[12],
|
||||||
|
entries[13],
|
||||||
|
entries[14],
|
||||||
|
entries[15],
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-dommatrixreadonly-numbersequence
|
// https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-dommatrixreadonly-numbersequence
|
||||||
|
@ -632,7 +684,6 @@ pub fn entries_to_matrix(entries: &[f64]) -> Fallible<(bool, Transform3D<f64>)>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// https://drafts.fxtf.org/geometry-1/#validate-and-fixup
|
// https://drafts.fxtf.org/geometry-1/#validate-and-fixup
|
||||||
pub fn dommatrixinit_to_matrix(dict: &DOMMatrixInit) -> Fallible<(bool, Transform3D<f64>)> {
|
pub fn dommatrixinit_to_matrix(dict: &DOMMatrixInit) -> Fallible<(bool, Transform3D<f64>)> {
|
||||||
// Step 1.
|
// Step 1.
|
||||||
|
@ -642,10 +693,19 @@ pub fn dommatrixinit_to_matrix(dict: &DOMMatrixInit) -> Fallible<(bool, Transfor
|
||||||
dict.d.is_some() && dict.m22.is_some() && dict.d.unwrap() != dict.m22.unwrap() ||
|
dict.d.is_some() && dict.m22.is_some() && dict.d.unwrap() != dict.m22.unwrap() ||
|
||||||
dict.e.is_some() && dict.m41.is_some() && dict.e.unwrap() != dict.m41.unwrap() ||
|
dict.e.is_some() && dict.m41.is_some() && dict.e.unwrap() != dict.m41.unwrap() ||
|
||||||
dict.f.is_some() && dict.m42.is_some() && dict.f.unwrap() != dict.m42.unwrap() ||
|
dict.f.is_some() && dict.m42.is_some() && dict.f.unwrap() != dict.m42.unwrap() ||
|
||||||
dict.is2D.is_some() && dict.is2D.unwrap() &&
|
dict.is2D.is_some() &&
|
||||||
(dict.m31 != 0.0 || dict.m32 != 0.0 || dict.m13 != 0.0 || dict.m23 != 0.0 ||
|
dict.is2D.unwrap() &&
|
||||||
dict.m43 != 0.0 || dict.m14 != 0.0 || dict.m24 != 0.0 || dict.m34 != 0.0 ||
|
(dict.m31 != 0.0 ||
|
||||||
dict.m33 != 1.0 || dict.m44 != 1.0) {
|
dict.m32 != 0.0 ||
|
||||||
|
dict.m13 != 0.0 ||
|
||||||
|
dict.m23 != 0.0 ||
|
||||||
|
dict.m43 != 0.0 ||
|
||||||
|
dict.m14 != 0.0 ||
|
||||||
|
dict.m24 != 0.0 ||
|
||||||
|
dict.m34 != 0.0 ||
|
||||||
|
dict.m33 != 1.0 ||
|
||||||
|
dict.m44 != 1.0)
|
||||||
|
{
|
||||||
Err(error::Error::Type("Invalid matrix initializer.".to_owned()))
|
Err(error::Error::Type("Invalid matrix initializer.".to_owned()))
|
||||||
} else {
|
} else {
|
||||||
let mut is2D = dict.is2D;
|
let mut is2D = dict.is2D;
|
||||||
|
@ -663,25 +723,31 @@ pub fn dommatrixinit_to_matrix(dict: &DOMMatrixInit) -> Fallible<(bool, Transfor
|
||||||
let m42 = dict.m42.unwrap_or(dict.f.unwrap_or(0.0));
|
let m42 = dict.m42.unwrap_or(dict.f.unwrap_or(0.0));
|
||||||
// Step 8.
|
// Step 8.
|
||||||
if is2D.is_none() &&
|
if is2D.is_none() &&
|
||||||
(dict.m31 != 0.0 || dict.m32 != 0.0 || dict.m13 != 0.0 ||
|
(dict.m31 != 0.0 ||
|
||||||
dict.m23 != 0.0 || dict.m43 != 0.0 || dict.m14 != 0.0 ||
|
dict.m32 != 0.0 ||
|
||||||
dict.m24 != 0.0 || dict.m34 != 0.0 ||
|
dict.m13 != 0.0 ||
|
||||||
dict.m33 != 1.0 || dict.m44 != 1.0) {
|
dict.m23 != 0.0 ||
|
||||||
|
dict.m43 != 0.0 ||
|
||||||
|
dict.m14 != 0.0 ||
|
||||||
|
dict.m24 != 0.0 ||
|
||||||
|
dict.m34 != 0.0 ||
|
||||||
|
dict.m33 != 1.0 ||
|
||||||
|
dict.m44 != 1.0)
|
||||||
|
{
|
||||||
is2D = Some(false);
|
is2D = Some(false);
|
||||||
}
|
}
|
||||||
// Step 9.
|
// Step 9.
|
||||||
if is2D.is_none() {
|
if is2D.is_none() {
|
||||||
is2D = Some(true);
|
is2D = Some(true);
|
||||||
}
|
}
|
||||||
let matrix = Transform3D::row_major(m11, m12, dict.m13, dict.m14,
|
let matrix = Transform3D::row_major(
|
||||||
m21, m22, dict.m23, dict.m24,
|
m11, m12, dict.m13, dict.m14, m21, m22, dict.m23, dict.m24, dict.m31, dict.m32,
|
||||||
dict.m31, dict.m32, dict.m33, dict.m34,
|
dict.m33, dict.m34, m41, m42, dict.m43, dict.m44,
|
||||||
m41, m42, dict.m43, dict.m44);
|
);
|
||||||
Ok((is2D.unwrap(), matrix))
|
Ok((is2D.unwrap(), matrix))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn normalize_point(x: f64, y: f64, z: f64) -> (f64, f64, f64) {
|
fn normalize_point(x: f64, y: f64, z: f64) -> (f64, f64, f64) {
|
||||||
let len = (x * x + y * y + z * z).sqrt();
|
let len = (x * x + y * y + z * z).sqrt();
|
||||||
|
|
|
@ -37,9 +37,11 @@ impl DOMParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(window: &Window) -> DomRoot<DOMParser> {
|
pub fn new(window: &Window) -> DomRoot<DOMParser> {
|
||||||
reflect_dom_object(Box::new(DOMParser::new_inherited(window)),
|
reflect_dom_object(
|
||||||
|
Box::new(DOMParser::new_inherited(window)),
|
||||||
window,
|
window,
|
||||||
DOMParserBinding::Wrap)
|
DOMParserBinding::Wrap,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn Constructor(window: &Window) -> Fallible<DomRoot<DOMParser>> {
|
pub fn Constructor(window: &Window) -> Fallible<DomRoot<DOMParser>> {
|
||||||
|
@ -49,17 +51,22 @@ impl DOMParser {
|
||||||
|
|
||||||
impl DOMParserMethods for DOMParser {
|
impl DOMParserMethods for DOMParser {
|
||||||
// https://w3c.github.io/DOM-Parsing/#the-domparser-interface
|
// https://w3c.github.io/DOM-Parsing/#the-domparser-interface
|
||||||
fn ParseFromString(&self,
|
fn ParseFromString(
|
||||||
|
&self,
|
||||||
s: DOMString,
|
s: DOMString,
|
||||||
ty: DOMParserBinding::SupportedType)
|
ty: DOMParserBinding::SupportedType,
|
||||||
-> Fallible<DomRoot<Document>> {
|
) -> Fallible<DomRoot<Document>> {
|
||||||
let url = self.window.get_url();
|
let url = self.window.get_url();
|
||||||
let content_type = ty.as_str().parse().expect("Supported type is not a MIME type");
|
let content_type = ty
|
||||||
|
.as_str()
|
||||||
|
.parse()
|
||||||
|
.expect("Supported type is not a MIME type");
|
||||||
let doc = self.window.Document();
|
let doc = self.window.Document();
|
||||||
let loader = DocumentLoader::new(&*doc.loader());
|
let loader = DocumentLoader::new(&*doc.loader());
|
||||||
match ty {
|
match ty {
|
||||||
Text_html => {
|
Text_html => {
|
||||||
let document = Document::new(&self.window,
|
let document = Document::new(
|
||||||
|
&self.window,
|
||||||
HasBrowsingContext::No,
|
HasBrowsingContext::No,
|
||||||
Some(url.clone()),
|
Some(url.clone()),
|
||||||
doc.origin().clone(),
|
doc.origin().clone(),
|
||||||
|
@ -71,13 +78,15 @@ impl DOMParserMethods for DOMParser {
|
||||||
loader,
|
loader,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
Default::default());
|
Default::default(),
|
||||||
|
);
|
||||||
ServoParser::parse_html_document(&document, s, url);
|
ServoParser::parse_html_document(&document, s, url);
|
||||||
document.set_ready_state(DocumentReadyState::Complete);
|
document.set_ready_state(DocumentReadyState::Complete);
|
||||||
Ok(document)
|
Ok(document)
|
||||||
}
|
},
|
||||||
Text_xml | Application_xml | Application_xhtml_xml => {
|
Text_xml | Application_xml | Application_xhtml_xml => {
|
||||||
let document = Document::new(&self.window,
|
let document = Document::new(
|
||||||
|
&self.window,
|
||||||
HasBrowsingContext::No,
|
HasBrowsingContext::No,
|
||||||
Some(url.clone()),
|
Some(url.clone()),
|
||||||
doc.origin().clone(),
|
doc.origin().clone(),
|
||||||
|
@ -89,11 +98,12 @@ impl DOMParserMethods for DOMParser {
|
||||||
loader,
|
loader,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
Default::default());
|
Default::default(),
|
||||||
|
);
|
||||||
ServoParser::parse_xml_document(&document, s, url);
|
ServoParser::parse_xml_document(&document, s, url);
|
||||||
document.set_ready_state(DocumentReadyState::Complete);
|
document.set_ready_state(DocumentReadyState::Complete);
|
||||||
Ok(document)
|
Ok(document)
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,12 +28,13 @@ impl DOMPoint {
|
||||||
reflect_dom_object(Box::new(DOMPoint::new_inherited(x, y, z, w)), global, Wrap)
|
reflect_dom_object(Box::new(DOMPoint::new_inherited(x, y, z, w)), global, Wrap)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn Constructor(global: &GlobalScope,
|
pub fn Constructor(
|
||||||
|
global: &GlobalScope,
|
||||||
x: f64,
|
x: f64,
|
||||||
y: f64,
|
y: f64,
|
||||||
z: f64,
|
z: f64,
|
||||||
w: f64)
|
w: f64,
|
||||||
-> Fallible<DomRoot<DOMPoint>> {
|
) -> Fallible<DomRoot<DOMPoint>> {
|
||||||
Ok(DOMPoint::new(global, x, y, z, w))
|
Ok(DOMPoint::new(global, x, y, z, w))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,17 +32,20 @@ impl DOMPointReadOnly {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(global: &GlobalScope, x: f64, y: f64, z: f64, w: f64) -> DomRoot<DOMPointReadOnly> {
|
pub fn new(global: &GlobalScope, x: f64, y: f64, z: f64, w: f64) -> DomRoot<DOMPointReadOnly> {
|
||||||
reflect_dom_object(Box::new(DOMPointReadOnly::new_inherited(x, y, z, w)),
|
reflect_dom_object(
|
||||||
|
Box::new(DOMPointReadOnly::new_inherited(x, y, z, w)),
|
||||||
global,
|
global,
|
||||||
Wrap)
|
Wrap,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn Constructor(global: &GlobalScope,
|
pub fn Constructor(
|
||||||
|
global: &GlobalScope,
|
||||||
x: f64,
|
x: f64,
|
||||||
y: f64,
|
y: f64,
|
||||||
z: f64,
|
z: f64,
|
||||||
w: f64)
|
w: f64,
|
||||||
-> Fallible<DomRoot<DOMPointReadOnly>> {
|
) -> Fallible<DomRoot<DOMPointReadOnly>> {
|
||||||
Ok(DOMPointReadOnly::new(global, x, y, z, w))
|
Ok(DOMPointReadOnly::new(global, x, y, z, w))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,11 +24,7 @@ pub struct DOMQuad {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DOMQuad {
|
impl DOMQuad {
|
||||||
fn new_inherited(p1: &DOMPoint,
|
fn new_inherited(p1: &DOMPoint, p2: &DOMPoint, p3: &DOMPoint, p4: &DOMPoint) -> DOMQuad {
|
||||||
p2: &DOMPoint,
|
|
||||||
p3: &DOMPoint,
|
|
||||||
p4: &DOMPoint)
|
|
||||||
-> DOMQuad {
|
|
||||||
DOMQuad {
|
DOMQuad {
|
||||||
reflector_: Reflector::new(),
|
reflector_: Reflector::new(),
|
||||||
p1: Dom::from_ref(p1),
|
p1: Dom::from_ref(p1),
|
||||||
|
@ -38,45 +34,62 @@ impl DOMQuad {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(global: &GlobalScope,
|
pub fn new(
|
||||||
|
global: &GlobalScope,
|
||||||
p1: &DOMPoint,
|
p1: &DOMPoint,
|
||||||
p2: &DOMPoint,
|
p2: &DOMPoint,
|
||||||
p3: &DOMPoint,
|
p3: &DOMPoint,
|
||||||
p4: &DOMPoint) -> DomRoot<DOMQuad> {
|
p4: &DOMPoint,
|
||||||
reflect_dom_object(Box::new(DOMQuad::new_inherited(p1, p2, p3, p4)),
|
) -> DomRoot<DOMQuad> {
|
||||||
|
reflect_dom_object(
|
||||||
|
Box::new(DOMQuad::new_inherited(p1, p2, p3, p4)),
|
||||||
global,
|
global,
|
||||||
Wrap)
|
Wrap,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn Constructor(global: &GlobalScope,
|
pub fn Constructor(
|
||||||
|
global: &GlobalScope,
|
||||||
p1: &DOMPointInit,
|
p1: &DOMPointInit,
|
||||||
p2: &DOMPointInit,
|
p2: &DOMPointInit,
|
||||||
p3: &DOMPointInit,
|
p3: &DOMPointInit,
|
||||||
p4: &DOMPointInit)
|
p4: &DOMPointInit,
|
||||||
-> Fallible<DomRoot<DOMQuad>> {
|
) -> Fallible<DomRoot<DOMQuad>> {
|
||||||
Ok(DOMQuad::new(global,
|
Ok(DOMQuad::new(
|
||||||
|
global,
|
||||||
&*DOMPoint::new_from_init(global, p1),
|
&*DOMPoint::new_from_init(global, p1),
|
||||||
&*DOMPoint::new_from_init(global, p2),
|
&*DOMPoint::new_from_init(global, p2),
|
||||||
&*DOMPoint::new_from_init(global, p3),
|
&*DOMPoint::new_from_init(global, p3),
|
||||||
&*DOMPoint::new_from_init(global, p4)))
|
&*DOMPoint::new_from_init(global, p4),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://drafts.fxtf.org/geometry/#dom-domquad-fromrect
|
// https://drafts.fxtf.org/geometry/#dom-domquad-fromrect
|
||||||
pub fn FromRect(global: &GlobalScope, other: &DOMRectInit) -> DomRoot<DOMQuad> {
|
pub fn FromRect(global: &GlobalScope, other: &DOMRectInit) -> DomRoot<DOMQuad> {
|
||||||
DOMQuad::new(global,
|
DOMQuad::new(
|
||||||
|
global,
|
||||||
&*DOMPoint::new(global, other.x, other.y, 0f64, 1f64),
|
&*DOMPoint::new(global, other.x, other.y, 0f64, 1f64),
|
||||||
&*DOMPoint::new(global, other.x + other.width, other.y, 0f64, 1f64),
|
&*DOMPoint::new(global, other.x + other.width, other.y, 0f64, 1f64),
|
||||||
&*DOMPoint::new(global, other.x + other.width, other.y + other.height, 0f64, 1f64),
|
&*DOMPoint::new(
|
||||||
&*DOMPoint::new(global, other.x, other.y + other.height, 0f64, 1f64))
|
global,
|
||||||
|
other.x + other.width,
|
||||||
|
other.y + other.height,
|
||||||
|
0f64,
|
||||||
|
1f64,
|
||||||
|
),
|
||||||
|
&*DOMPoint::new(global, other.x, other.y + other.height, 0f64, 1f64),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://drafts.fxtf.org/geometry/#dom-domquad-fromquad
|
// https://drafts.fxtf.org/geometry/#dom-domquad-fromquad
|
||||||
pub fn FromQuad(global: &GlobalScope, other: &DOMQuadInit) -> DomRoot<DOMQuad> {
|
pub fn FromQuad(global: &GlobalScope, other: &DOMQuadInit) -> DomRoot<DOMQuad> {
|
||||||
DOMQuad::new(global,
|
DOMQuad::new(
|
||||||
|
global,
|
||||||
&DOMPoint::new_from_init(global, &other.p1),
|
&DOMPoint::new_from_init(global, &other.p1),
|
||||||
&DOMPoint::new_from_init(global, &other.p2),
|
&DOMPoint::new_from_init(global, &other.p2),
|
||||||
&DOMPoint::new_from_init(global, &other.p3),
|
&DOMPoint::new_from_init(global, &other.p3),
|
||||||
&DOMPoint::new_from_init(global, &other.p4))
|
&DOMPoint::new_from_init(global, &other.p4),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,15 +116,31 @@ impl DOMQuadMethods for DOMQuad {
|
||||||
|
|
||||||
// https://drafts.fxtf.org/geometry/#dom-domquad-getbounds
|
// https://drafts.fxtf.org/geometry/#dom-domquad-getbounds
|
||||||
fn GetBounds(&self) -> DomRoot<DOMRect> {
|
fn GetBounds(&self) -> DomRoot<DOMRect> {
|
||||||
let left = self.p1.X().min(self.p2.X()).min(self.p3.X()).min(self.p4.X());
|
let left = self
|
||||||
let top = self.p1.Y().min(self.p2.Y()).min(self.p3.Y()).min(self.p4.Y());
|
.p1
|
||||||
let right = self.p1.X().max(self.p2.X()).max(self.p3.X()).max(self.p4.X());
|
.X()
|
||||||
let bottom = self.p1.Y().max(self.p2.Y()).max(self.p3.Y()).max(self.p4.Y());
|
.min(self.p2.X())
|
||||||
|
.min(self.p3.X())
|
||||||
|
.min(self.p4.X());
|
||||||
|
let top = self
|
||||||
|
.p1
|
||||||
|
.Y()
|
||||||
|
.min(self.p2.Y())
|
||||||
|
.min(self.p3.Y())
|
||||||
|
.min(self.p4.Y());
|
||||||
|
let right = self
|
||||||
|
.p1
|
||||||
|
.X()
|
||||||
|
.max(self.p2.X())
|
||||||
|
.max(self.p3.X())
|
||||||
|
.max(self.p4.X());
|
||||||
|
let bottom = self
|
||||||
|
.p1
|
||||||
|
.Y()
|
||||||
|
.max(self.p2.Y())
|
||||||
|
.max(self.p3.Y())
|
||||||
|
.max(self.p4.Y());
|
||||||
|
|
||||||
DOMRect::new(&self.global(),
|
DOMRect::new(&self.global(), left, top, right - left, bottom - top)
|
||||||
left,
|
|
||||||
top,
|
|
||||||
right - left,
|
|
||||||
bottom - top)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,17 +25,20 @@ impl DOMRect {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(global: &GlobalScope, x: f64, y: f64, width: f64, height: f64) -> DomRoot<DOMRect> {
|
pub fn new(global: &GlobalScope, x: f64, y: f64, width: f64, height: f64) -> DomRoot<DOMRect> {
|
||||||
reflect_dom_object(Box::new(DOMRect::new_inherited(x, y, width, height)),
|
reflect_dom_object(
|
||||||
|
Box::new(DOMRect::new_inherited(x, y, width, height)),
|
||||||
global,
|
global,
|
||||||
DOMRectBinding::Wrap)
|
DOMRectBinding::Wrap,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn Constructor(global: &GlobalScope,
|
pub fn Constructor(
|
||||||
|
global: &GlobalScope,
|
||||||
x: f64,
|
x: f64,
|
||||||
y: f64,
|
y: f64,
|
||||||
width: f64,
|
width: f64,
|
||||||
height: f64)
|
height: f64,
|
||||||
-> Fallible<DomRoot<DOMRect>> {
|
) -> Fallible<DomRoot<DOMRect>> {
|
||||||
Ok(DOMRect::new(global, x, y, width, height))
|
Ok(DOMRect::new(global, x, y, width, height))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,23 +30,27 @@ impl DOMRectReadOnly {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(global: &GlobalScope,
|
pub fn new(
|
||||||
|
global: &GlobalScope,
|
||||||
x: f64,
|
x: f64,
|
||||||
y: f64,
|
y: f64,
|
||||||
width: f64,
|
width: f64,
|
||||||
height: f64)
|
height: f64,
|
||||||
-> DomRoot<DOMRectReadOnly> {
|
) -> DomRoot<DOMRectReadOnly> {
|
||||||
reflect_dom_object(Box::new(DOMRectReadOnly::new_inherited(x, y, width, height)),
|
reflect_dom_object(
|
||||||
|
Box::new(DOMRectReadOnly::new_inherited(x, y, width, height)),
|
||||||
global,
|
global,
|
||||||
Wrap)
|
Wrap,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn Constructor(global: &GlobalScope,
|
pub fn Constructor(
|
||||||
|
global: &GlobalScope,
|
||||||
x: f64,
|
x: f64,
|
||||||
y: f64,
|
y: f64,
|
||||||
width: f64,
|
width: f64,
|
||||||
height: f64)
|
height: f64,
|
||||||
-> Fallible<DomRoot<DOMRectReadOnly>> {
|
) -> Fallible<DomRoot<DOMRectReadOnly>> {
|
||||||
Ok(DOMRectReadOnly::new(global, x, y, width, height))
|
Ok(DOMRectReadOnly::new(global, x, y, width, height))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,9 +28,11 @@ impl DOMStringMap {
|
||||||
|
|
||||||
pub fn new(element: &HTMLElement) -> DomRoot<DOMStringMap> {
|
pub fn new(element: &HTMLElement) -> DomRoot<DOMStringMap> {
|
||||||
let window = window_from_node(element);
|
let window = window_from_node(element);
|
||||||
reflect_dom_object(Box::new(DOMStringMap::new_inherited(element)),
|
reflect_dom_object(
|
||||||
|
Box::new(DOMStringMap::new_inherited(element)),
|
||||||
&*window,
|
&*window,
|
||||||
DOMStringMapBinding::Wrap)
|
DOMStringMapBinding::Wrap,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,6 +55,10 @@ impl DOMStringMapMethods for DOMStringMap {
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#the-domstringmap-interface:supported-property-names
|
// https://html.spec.whatwg.org/multipage/#the-domstringmap-interface:supported-property-names
|
||||||
fn SupportedPropertyNames(&self) -> Vec<DOMString> {
|
fn SupportedPropertyNames(&self) -> Vec<DOMString> {
|
||||||
self.element.supported_prop_names_custom_attr().iter().cloned().collect()
|
self.element
|
||||||
|
.supported_prop_names_custom_attr()
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,9 +34,11 @@ impl DOMTokenList {
|
||||||
|
|
||||||
pub fn new(element: &Element, local_name: &LocalName) -> DomRoot<DOMTokenList> {
|
pub fn new(element: &Element, local_name: &LocalName) -> DomRoot<DOMTokenList> {
|
||||||
let window = window_from_node(element);
|
let window = window_from_node(element);
|
||||||
reflect_dom_object(Box::new(DOMTokenList::new_inherited(element, local_name.clone())),
|
reflect_dom_object(
|
||||||
|
Box::new(DOMTokenList::new_inherited(element, local_name.clone())),
|
||||||
&*window,
|
&*window,
|
||||||
DOMTokenListBinding::Wrap)
|
DOMTokenListBinding::Wrap,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn attribute(&self) -> Option<DomRoot<Attr>> {
|
fn attribute(&self) -> Option<DomRoot<Attr>> {
|
||||||
|
@ -56,16 +58,18 @@ impl DOMTokenList {
|
||||||
impl DOMTokenListMethods for DOMTokenList {
|
impl DOMTokenListMethods for DOMTokenList {
|
||||||
// https://dom.spec.whatwg.org/#dom-domtokenlist-length
|
// https://dom.spec.whatwg.org/#dom-domtokenlist-length
|
||||||
fn Length(&self) -> u32 {
|
fn Length(&self) -> u32 {
|
||||||
self.attribute().map_or(0, |attr| {
|
self.attribute()
|
||||||
attr.value().as_tokens().len()
|
.map_or(0, |attr| attr.value().as_tokens().len()) as u32
|
||||||
}) as u32
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://dom.spec.whatwg.org/#dom-domtokenlist-item
|
// https://dom.spec.whatwg.org/#dom-domtokenlist-item
|
||||||
fn Item(&self, index: u32) -> Option<DOMString> {
|
fn Item(&self, index: u32) -> Option<DOMString> {
|
||||||
self.attribute().and_then(|attr| {
|
self.attribute().and_then(|attr| {
|
||||||
// FIXME(ajeffrey): Convert directly from Atom to DOMString
|
// FIXME(ajeffrey): Convert directly from Atom to DOMString
|
||||||
attr.value().as_tokens().get(index as usize).map(|token| DOMString::from(&**token))
|
attr.value()
|
||||||
|
.as_tokens()
|
||||||
|
.get(index as usize)
|
||||||
|
.map(|token| DOMString::from(&**token))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,7 +93,8 @@ impl DOMTokenListMethods for DOMTokenList {
|
||||||
atoms.push(token);
|
atoms.push(token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.element.set_atomic_tokenlist_attribute(&self.local_name, atoms);
|
self.element
|
||||||
|
.set_atomic_tokenlist_attribute(&self.local_name, atoms);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,9 +103,13 @@ impl DOMTokenListMethods for DOMTokenList {
|
||||||
let mut atoms = self.element.get_tokenlist_attribute(&self.local_name);
|
let mut atoms = self.element.get_tokenlist_attribute(&self.local_name);
|
||||||
for token in &tokens {
|
for token in &tokens {
|
||||||
let token = self.check_token_exceptions(&token)?;
|
let token = self.check_token_exceptions(&token)?;
|
||||||
atoms.iter().position(|atom| *atom == token).map(|index| atoms.remove(index));
|
atoms
|
||||||
|
.iter()
|
||||||
|
.position(|atom| *atom == token)
|
||||||
|
.map(|index| atoms.remove(index));
|
||||||
}
|
}
|
||||||
self.element.set_atomic_tokenlist_attribute(&self.local_name, atoms);
|
self.element
|
||||||
|
.set_atomic_tokenlist_attribute(&self.local_name, atoms);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,17 +122,19 @@ impl DOMTokenListMethods for DOMTokenList {
|
||||||
Some(true) => Ok(true),
|
Some(true) => Ok(true),
|
||||||
_ => {
|
_ => {
|
||||||
atoms.remove(index);
|
atoms.remove(index);
|
||||||
self.element.set_atomic_tokenlist_attribute(&self.local_name, atoms);
|
self.element
|
||||||
|
.set_atomic_tokenlist_attribute(&self.local_name, atoms);
|
||||||
Ok(false)
|
Ok(false)
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
None => match force {
|
None => match force {
|
||||||
Some(false) => Ok(false),
|
Some(false) => Ok(false),
|
||||||
_ => {
|
_ => {
|
||||||
atoms.push(token);
|
atoms.push(token);
|
||||||
self.element.set_atomic_tokenlist_attribute(&self.local_name, atoms);
|
self.element
|
||||||
|
.set_atomic_tokenlist_attribute(&self.local_name, atoms);
|
||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -135,7 +146,8 @@ impl DOMTokenListMethods for DOMTokenList {
|
||||||
|
|
||||||
// https://dom.spec.whatwg.org/#dom-domtokenlist-value
|
// https://dom.spec.whatwg.org/#dom-domtokenlist-value
|
||||||
fn SetValue(&self, value: DOMString) {
|
fn SetValue(&self, value: DOMString) {
|
||||||
self.element.set_tokenlist_attribute(&self.local_name, value);
|
self.element
|
||||||
|
.set_tokenlist_attribute(&self.local_name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://dom.spec.whatwg.org/#dom-domtokenlist-replace
|
// https://dom.spec.whatwg.org/#dom-domtokenlist-replace
|
||||||
|
@ -159,7 +171,8 @@ impl DOMTokenListMethods for DOMTokenList {
|
||||||
atoms.remove(pos);
|
atoms.remove(pos);
|
||||||
}
|
}
|
||||||
// Step 5.
|
// Step 5.
|
||||||
self.element.set_atomic_tokenlist_attribute(&self.local_name, atoms);
|
self.element
|
||||||
|
.set_atomic_tokenlist_attribute(&self.local_name, atoms);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue