mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +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,
|
||||
Json,
|
||||
Text,
|
||||
ArrayBuffer
|
||||
ArrayBuffer,
|
||||
}
|
||||
|
||||
pub enum FetchedData {
|
||||
|
@ -44,7 +44,7 @@ pub enum FetchedData {
|
|||
BlobData(DomRoot<Blob>),
|
||||
FormData(DomRoot<FormData>),
|
||||
ArrayBuffer(RootedTraceableBox<Heap<*mut JSObject>>),
|
||||
JSException(RootedTraceableBox<Heap<JSVal>>)
|
||||
JSException(RootedTraceableBox<Heap<JSVal>>),
|
||||
}
|
||||
|
||||
// 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
|
||||
#[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,
|
||||
promise: &Promise) {
|
||||
promise: &Promise,
|
||||
) {
|
||||
// Step 5
|
||||
let body = match object.take_body() {
|
||||
Some(body) => body,
|
||||
None => return,
|
||||
};
|
||||
|
||||
let pkg_data_results = run_package_data_algorithm(object,
|
||||
body,
|
||||
body_type,
|
||||
object.get_mime_type());
|
||||
let pkg_data_results =
|
||||
run_package_data_algorithm(object, body, body_type, object.get_mime_type());
|
||||
|
||||
match pkg_data_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
|
||||
#[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>,
|
||||
body_type: BodyType,
|
||||
mime_type: Ref<Vec<u8>>)
|
||||
-> Fallible<FetchedData> {
|
||||
mime_type: Ref<Vec<u8>>,
|
||||
) -> Fallible<FetchedData> {
|
||||
let global = object.global();
|
||||
let cx = global.get_cx();
|
||||
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::Blob => run_blob_data_algorithm(&global, bytes, mime),
|
||||
BodyType::FormData => run_form_data_algorithm(&global, bytes, mime),
|
||||
BodyType::ArrayBuffer => unsafe {
|
||||
run_array_buffer_data_algorithm(cx, bytes)
|
||||
}
|
||||
BodyType::ArrayBuffer => unsafe { run_array_buffer_data_algorithm(cx, bytes) },
|
||||
}
|
||||
}
|
||||
|
||||
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)]
|
||||
fn run_json_data_algorithm(cx: *mut JSContext,
|
||||
bytes: Vec<u8>) -> Fallible<FetchedData> {
|
||||
fn run_json_data_algorithm(cx: *mut JSContext, bytes: Vec<u8>) -> Fallible<FetchedData> {
|
||||
let json_text = String::from_utf8_lossy(&bytes);
|
||||
let json_text: Vec<u16> = json_text.encode_utf16().collect();
|
||||
rooted!(in(cx) let mut rval = UndefinedValue());
|
||||
unsafe {
|
||||
if !JS_ParseJSON(cx,
|
||||
if !JS_ParseJSON(
|
||||
cx,
|
||||
json_text.as_ptr(),
|
||||
json_text.len() as u32,
|
||||
rval.handle_mut()) {
|
||||
rval.handle_mut(),
|
||||
) {
|
||||
rooted!(in(cx) let mut exception = UndefinedValue());
|
||||
assert!(JS_GetPendingException(cx, exception.handle_mut()));
|
||||
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()));
|
||||
Ok(FetchedData::Json(rooted_heap))
|
||||
}
|
||||
}
|
||||
|
||||
fn run_blob_data_algorithm(root: &GlobalScope,
|
||||
fn run_blob_data_algorithm(
|
||||
root: &GlobalScope,
|
||||
bytes: Vec<u8>,
|
||||
mime: &[u8]) -> Fallible<FetchedData> {
|
||||
mime: &[u8],
|
||||
) -> Fallible<FetchedData> {
|
||||
let mime_string = if let Ok(s) = String::from_utf8(mime.to_vec()) {
|
||||
s
|
||||
} else {
|
||||
|
@ -159,14 +165,19 @@ fn run_blob_data_algorithm(root: &GlobalScope,
|
|||
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) {
|
||||
s
|
||||
} else {
|
||||
""
|
||||
};
|
||||
let mime: Mime = mime_str.parse().map_err(
|
||||
|_| Error::Type("Inappropriate MIME-type for Body".to_string()))?;
|
||||
let mime: Mime = mime_str
|
||||
.parse()
|
||||
.map_err(|_| Error::Type("Inappropriate MIME-type for Body".to_string()))?;
|
||||
match mime {
|
||||
// TODO
|
||||
// ... 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)]
|
||||
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>());
|
||||
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() {
|
||||
return Err(Error::JSFailed);
|
||||
}
|
||||
|
|
|
@ -31,22 +31,34 @@ fn main() {
|
|||
build.generator("Ninja");
|
||||
// because we're using ninja, we need to explicitly set these
|
||||
// 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");
|
||||
// We have to explicitly specify the full path to link.exe,
|
||||
// for reasons that I don't understand. If we just give
|
||||
// link.exe, it tries to use script-*/out/link.exe, which of
|
||||
// course does not exist.
|
||||
let link = std::process::Command::new("where").arg("link.exe").output().unwrap();
|
||||
let link_path: Vec<&str> = std::str::from_utf8(&link.stdout).unwrap().split("\r\n").collect();
|
||||
let link = std::process::Command::new("where")
|
||||
.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.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 mut map = phf_codegen::Map::new();
|
||||
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 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();
|
||||
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 uuid::Uuid;
|
||||
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
pub fn handle_evaluate_js(global: &GlobalScope, eval: String, reply: IpcSender<EvaluateJSReply>) {
|
||||
// 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() {
|
||||
EvaluateJSReply::BooleanValue(rval.to_boolean())
|
||||
} else if rval.is_double() || rval.is_int32() {
|
||||
EvaluateJSReply::NumberValue(
|
||||
match FromJSValConvertible::from_jsval(cx, rval.handle(), ()) {
|
||||
EvaluateJSReply::NumberValue(match FromJSValConvertible::from_jsval(
|
||||
cx,
|
||||
rval.handle(),
|
||||
(),
|
||||
) {
|
||||
Ok(ConversionResult::Success(v)) => v,
|
||||
_ => unreachable!(),
|
||||
})
|
||||
|
@ -73,65 +75,84 @@ pub fn handle_evaluate_js(global: &GlobalScope, eval: String, reply: IpcSender<E
|
|||
reply.send(result).unwrap();
|
||||
}
|
||||
|
||||
pub fn handle_get_root_node(documents: &Documents, pipeline: PipelineId, reply: IpcSender<Option<NodeInfo>>) {
|
||||
let info = documents.find_document(pipeline)
|
||||
pub fn handle_get_root_node(
|
||||
documents: &Documents,
|
||||
pipeline: PipelineId,
|
||||
reply: IpcSender<Option<NodeInfo>>,
|
||||
) {
|
||||
let info = documents
|
||||
.find_document(pipeline)
|
||||
.map(|document| document.upcast::<Node>().summarize());
|
||||
reply.send(info).unwrap();
|
||||
}
|
||||
|
||||
pub fn handle_get_document_element(documents: &Documents,
|
||||
pub fn handle_get_document_element(
|
||||
documents: &Documents,
|
||||
pipeline: PipelineId,
|
||||
reply: IpcSender<Option<NodeInfo>>) {
|
||||
let info = documents.find_document(pipeline)
|
||||
reply: IpcSender<Option<NodeInfo>>,
|
||||
) {
|
||||
let info = documents
|
||||
.find_document(pipeline)
|
||||
.and_then(|document| document.GetDocumentElement())
|
||||
.map(|element| element.upcast::<Node>().summarize());
|
||||
reply.send(info).unwrap();
|
||||
}
|
||||
|
||||
fn find_node_by_unique_id(documents: &Documents,
|
||||
fn find_node_by_unique_id(
|
||||
documents: &Documents,
|
||||
pipeline: PipelineId,
|
||||
node_id: &str)
|
||||
-> Option<DomRoot<Node>> {
|
||||
documents.find_document(pipeline).and_then(|document|
|
||||
document.upcast::<Node>().traverse_preorder().find(|candidate| candidate.unique_id() == node_id)
|
||||
)
|
||||
node_id: &str,
|
||||
) -> Option<DomRoot<Node>> {
|
||||
documents.find_document(pipeline).and_then(|document| {
|
||||
document
|
||||
.upcast::<Node>()
|
||||
.traverse_preorder()
|
||||
.find(|candidate| candidate.unique_id() == node_id)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn handle_get_children(documents: &Documents,
|
||||
pub fn handle_get_children(
|
||||
documents: &Documents,
|
||||
pipeline: PipelineId,
|
||||
node_id: String,
|
||||
reply: IpcSender<Option<Vec<NodeInfo>>>) {
|
||||
reply: IpcSender<Option<Vec<NodeInfo>>>,
|
||||
) {
|
||||
match find_node_by_unique_id(documents, pipeline, &*node_id) {
|
||||
None => return reply.send(None).unwrap(),
|
||||
Some(parent) => {
|
||||
let children = parent.children()
|
||||
.map(|child| child.summarize())
|
||||
.collect();
|
||||
let children = parent.children().map(|child| child.summarize()).collect();
|
||||
|
||||
reply.send(Some(children)).unwrap();
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
pub fn handle_get_layout(documents: &Documents,
|
||||
pub fn handle_get_layout(
|
||||
documents: &Documents,
|
||||
pipeline: PipelineId,
|
||||
node_id: String,
|
||||
reply: IpcSender<Option<ComputedNodeLayout>>) {
|
||||
reply: IpcSender<Option<ComputedNodeLayout>>,
|
||||
) {
|
||||
let node = match find_node_by_unique_id(documents, pipeline, &*node_id) {
|
||||
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 width = rect.Width() as f32;
|
||||
let height = rect.Height() as f32;
|
||||
|
||||
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);
|
||||
|
||||
reply.send(Some(ComputedNodeLayout {
|
||||
reply
|
||||
.send(Some(ComputedNodeLayout {
|
||||
display: String::from(computed_style.Display()),
|
||||
position: String::from(computed_style.Position()),
|
||||
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,
|
||||
reply: IpcSender<Vec<CachedConsoleMessage>>) {
|
||||
reply: IpcSender<Vec<CachedConsoleMessage>>,
|
||||
) {
|
||||
// TODO: check the messageTypes against a global Cache for console messages and page exceptions
|
||||
let mut messages = Vec::new();
|
||||
if message_types.contains(CachedConsoleMessageTypes::PAGE_ERROR) {
|
||||
|
@ -207,22 +230,33 @@ pub fn handle_get_cached_messages(_pipeline_id: PipelineId,
|
|||
reply.send(messages).unwrap();
|
||||
}
|
||||
|
||||
pub fn handle_modify_attribute(documents: &Documents,
|
||||
pub fn handle_modify_attribute(
|
||||
documents: &Documents,
|
||||
pipeline: PipelineId,
|
||||
node_id: String,
|
||||
modifications: Vec<Modification>) {
|
||||
modifications: Vec<Modification>,
|
||||
) {
|
||||
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),
|
||||
Some(found_node) => found_node
|
||||
None => {
|
||||
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 {
|
||||
match modification.newValue {
|
||||
Some(string) => {
|
||||
let _ = elem.SetAttribute(DOMString::from(modification.attributeName),
|
||||
DOMString::from(string));
|
||||
let _ = elem.SetAttribute(
|
||||
DOMString::from(modification.attributeName),
|
||||
DOMString::from(string),
|
||||
);
|
||||
},
|
||||
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);
|
||||
}
|
||||
|
||||
pub fn handle_set_timeline_markers(documents: &Documents,
|
||||
pub fn handle_set_timeline_markers(
|
||||
documents: &Documents,
|
||||
pipeline: PipelineId,
|
||||
marker_types: Vec<TimelineMarkerType>,
|
||||
reply: IpcSender<Option<TimelineMarker>>) {
|
||||
reply: IpcSender<Option<TimelineMarker>>,
|
||||
) {
|
||||
match documents.find_window(pipeline) {
|
||||
None => reply.send(None).unwrap(),
|
||||
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,
|
||||
marker_types: Vec<TimelineMarkerType>) {
|
||||
marker_types: Vec<TimelineMarkerType>,
|
||||
) {
|
||||
if let Some(window) = documents.find_window(pipeline) {
|
||||
window.drop_devtools_timeline_markers(marker_types);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_request_animation_frame(documents: &Documents,
|
||||
id: PipelineId,
|
||||
actor_name: String) {
|
||||
pub fn handle_request_animation_frame(documents: &Documents, id: PipelineId, actor_name: String) {
|
||||
if let Some(doc) = documents.find_document(id) {
|
||||
doc.request_animation_frame(AnimationFrameCallback::DevtoolsFramerateTick { actor_name });
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_reload(documents: &Documents,
|
||||
id: PipelineId) {
|
||||
pub fn handle_reload(documents: &Documents, id: PipelineId) {
|
||||
if let Some(win) = documents.find_window(id) {
|
||||
win.Location().reload_without_origin_check();
|
||||
}
|
||||
|
|
|
@ -96,8 +96,10 @@ impl DocumentLoader {
|
|||
DocumentLoader::new_with_threads(existing.resource_threads.clone(), None)
|
||||
}
|
||||
|
||||
pub fn new_with_threads(resource_threads: ResourceThreads,
|
||||
initial_load: Option<ServoUrl>) -> DocumentLoader {
|
||||
pub fn new_with_threads(
|
||||
resource_threads: ResourceThreads,
|
||||
initial_load: Option<ServoUrl>,
|
||||
) -> DocumentLoader {
|
||||
debug!("Initial blocking load {:?}.", initial_load);
|
||||
let initial_loads = initial_load.into_iter().map(LoadType::PageSource).collect();
|
||||
|
||||
|
@ -105,7 +107,7 @@ impl DocumentLoader {
|
|||
resource_threads: resource_threads,
|
||||
blocking_loads: initial_loads,
|
||||
events_inhibited: false,
|
||||
cancellers: Vec::new()
|
||||
cancellers: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -118,35 +120,55 @@ impl DocumentLoader {
|
|||
|
||||
/// Add a load to the list of blocking loads.
|
||||
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);
|
||||
}
|
||||
|
||||
/// Initiate a new fetch.
|
||||
pub fn fetch_async(&mut self,
|
||||
pub fn fetch_async(
|
||||
&mut self,
|
||||
load: LoadType,
|
||||
request: RequestInit,
|
||||
fetch_target: IpcSender<FetchResponseMsg>) {
|
||||
fetch_target: IpcSender<FetchResponseMsg>,
|
||||
) {
|
||||
self.add_blocking_load(load);
|
||||
self.fetch_async_background(request, fetch_target);
|
||||
}
|
||||
|
||||
/// 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,
|
||||
fetch_target: IpcSender<FetchResponseMsg>) {
|
||||
fetch_target: IpcSender<FetchResponseMsg>,
|
||||
) {
|
||||
let mut canceller = FetchCanceller::new();
|
||||
let cancel_receiver = canceller.initialize();
|
||||
self.cancellers.push(canceller);
|
||||
self.resource_threads.sender().send(
|
||||
CoreResourceMsg::Fetch(request, FetchChannels::ResponseMsg(fetch_target, Some(cancel_receiver)))).unwrap();
|
||||
self.resource_threads
|
||||
.sender()
|
||||
.send(CoreResourceMsg::Fetch(
|
||||
request,
|
||||
FetchChannels::ResponseMsg(fetch_target, Some(cancel_receiver)),
|
||||
)).unwrap();
|
||||
}
|
||||
|
||||
/// Mark an in-progress network request complete.
|
||||
pub fn finish_load(&mut self, load: &LoadType) {
|
||||
debug!("Removing blocking 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)));
|
||||
debug!(
|
||||
"Removing blocking 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 {
|
||||
|
@ -157,7 +179,7 @@ impl DocumentLoader {
|
|||
pub fn is_only_blocked_by_iframes(&self) -> bool {
|
||||
self.blocking_loads.iter().all(|load| match *load {
|
||||
LoadType::Subframe(_) => true,
|
||||
_ => false
|
||||
_ => false,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ pub enum WorkerScriptMsg {
|
|||
/// Common variants associated with the script messages
|
||||
Common(CommonScriptMsg),
|
||||
/// Message sent through Worker.postMessage
|
||||
DOMMessage(StructuredCloneData)
|
||||
DOMMessage(StructuredCloneData),
|
||||
}
|
||||
|
||||
pub struct SimpleWorkerErrorHandler<T: DomObject> {
|
||||
|
@ -21,8 +21,6 @@ pub struct SimpleWorkerErrorHandler<T: DomObject> {
|
|||
|
||||
impl<T: DomObject> SimpleWorkerErrorHandler<T> {
|
||||
pub fn new(addr: Trusted<T>) -> SimpleWorkerErrorHandler<T> {
|
||||
SimpleWorkerErrorHandler {
|
||||
addr: addr
|
||||
}
|
||||
SimpleWorkerErrorHandler { addr: addr }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,10 @@ pub struct SendableWorkerScriptChan {
|
|||
|
||||
impl ScriptChan for SendableWorkerScriptChan {
|
||||
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(|_| ())
|
||||
}
|
||||
|
||||
|
@ -48,10 +51,11 @@ pub struct WorkerThreadWorkerChan {
|
|||
|
||||
impl ScriptChan for WorkerThreadWorkerChan {
|
||||
fn send(&self, msg: CommonScriptMsg) -> Result<(), ()> {
|
||||
let msg = DedicatedWorkerScriptMsg::CommonWorker(self.worker.clone(), WorkerScriptMsg::Common(msg));
|
||||
self.sender
|
||||
.send(msg)
|
||||
.map_err(|_| ())
|
||||
let msg = DedicatedWorkerScriptMsg::CommonWorker(
|
||||
self.worker.clone(),
|
||||
WorkerScriptMsg::Common(msg),
|
||||
);
|
||||
self.sender.send(msg).map_err(|_| ())
|
||||
}
|
||||
|
||||
fn clone(&self) -> Box<ScriptChan + Send> {
|
||||
|
@ -67,7 +71,7 @@ impl ScriptPort for Receiver<DedicatedWorkerScriptMsg> {
|
|||
let common_msg = match self.recv() {
|
||||
Some(DedicatedWorkerScriptMsg::CommonWorker(_worker, common_msg)) => common_msg,
|
||||
None => return Err(()),
|
||||
Some(DedicatedWorkerScriptMsg::WakeUp) => panic!("unexpected worker event message!")
|
||||
Some(DedicatedWorkerScriptMsg::WakeUp) => panic!("unexpected worker event message!"),
|
||||
};
|
||||
match common_msg {
|
||||
WorkerScriptMsg::Common(script_msg) => Ok(script_msg),
|
||||
|
@ -90,14 +94,17 @@ pub trait WorkerEventLoopMethods {
|
|||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#worker-event-loop
|
||||
pub fn run_worker_event_loop<T, TimerMsg, WorkerMsg, Event>(worker_scope: &T,
|
||||
worker: Option<&TrustedWorkerAddress>)
|
||||
where
|
||||
pub fn run_worker_event_loop<T, TimerMsg, WorkerMsg, Event>(
|
||||
worker_scope: &T,
|
||||
worker: Option<&TrustedWorkerAddress>,
|
||||
) where
|
||||
TimerMsg: Send,
|
||||
WorkerMsg: QueuedTaskConversion + Send,
|
||||
T: WorkerEventLoopMethods<TimerMsg = TimerMsg, WorkerMsg = WorkerMsg, Event = Event>
|
||||
+ DerivedFrom<WorkerGlobalScope> + DerivedFrom<GlobalScope>
|
||||
+ DomObject {
|
||||
+ DerivedFrom<WorkerGlobalScope>
|
||||
+ DerivedFrom<GlobalScope>
|
||||
+ DomObject,
|
||||
{
|
||||
let scope = worker_scope.upcast::<WorkerGlobalScope>();
|
||||
let timer_event_port = worker_scope.timer_event_port();
|
||||
let devtools_port = match scope.from_devtools_sender() {
|
||||
|
@ -140,8 +147,10 @@ where
|
|||
// Step 6
|
||||
let _ar = match 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
|
||||
pub fn synthetic_click_activation(element: &Element,
|
||||
pub fn synthetic_click_activation(
|
||||
element: &Element,
|
||||
ctrl_key: bool,
|
||||
shift_key: bool,
|
||||
alt_key: bool,
|
||||
meta_key: bool,
|
||||
source: ActivationSource) {
|
||||
source: ActivationSource,
|
||||
) {
|
||||
// Step 1
|
||||
if element.click_in_progress() {
|
||||
return;
|
||||
|
@ -78,7 +80,8 @@ pub fn synthetic_click_activation(element: &Element,
|
|||
// https://html.spec.whatwg.org/multipage/#fire-a-synthetic-mouse-event
|
||||
let win = window_from_node(element);
|
||||
let target = element.upcast::<EventTarget>();
|
||||
let mouse = MouseEvent::new(&win,
|
||||
let mouse = MouseEvent::new(
|
||||
&win,
|
||||
DOMString::from("click"),
|
||||
EventBubbles::DoesNotBubble,
|
||||
EventCancelable::NotCancelable,
|
||||
|
@ -94,7 +97,8 @@ pub fn synthetic_click_activation(element: &Element,
|
|||
meta_key,
|
||||
0,
|
||||
None,
|
||||
None);
|
||||
None,
|
||||
);
|
||||
let event = mouse.upcast::<Event>();
|
||||
if source == ActivationSource::FromClick {
|
||||
event.set_trusted(false);
|
||||
|
|
|
@ -36,13 +36,14 @@ pub struct Attr {
|
|||
}
|
||||
|
||||
impl Attr {
|
||||
fn new_inherited(local_name: LocalName,
|
||||
fn new_inherited(
|
||||
local_name: LocalName,
|
||||
value: AttrValue,
|
||||
name: LocalName,
|
||||
namespace: Namespace,
|
||||
prefix: Option<Prefix>,
|
||||
owner: Option<&Element>)
|
||||
-> Attr {
|
||||
owner: Option<&Element>,
|
||||
) -> Attr {
|
||||
Attr {
|
||||
reflector_: Reflector::new(),
|
||||
identifier: AttrIdentifier {
|
||||
|
@ -56,25 +57,21 @@ impl Attr {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn new(window: &Window,
|
||||
pub fn new(
|
||||
window: &Window,
|
||||
local_name: LocalName,
|
||||
value: AttrValue,
|
||||
name: LocalName,
|
||||
namespace: Namespace,
|
||||
prefix: Option<Prefix>,
|
||||
owner: Option<&Element>)
|
||||
-> DomRoot<Attr> {
|
||||
owner: Option<&Element>,
|
||||
) -> DomRoot<Attr> {
|
||||
reflect_dom_object(
|
||||
Box::new(Attr::new_inherited(
|
||||
local_name,
|
||||
value,
|
||||
name,
|
||||
namespace,
|
||||
prefix,
|
||||
owner
|
||||
local_name, value, name, namespace, prefix, owner,
|
||||
)),
|
||||
window,
|
||||
AttrBinding::Wrap
|
||||
AttrBinding::Wrap,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -110,9 +107,7 @@ impl AttrMethods for Attr {
|
|||
// https://dom.spec.whatwg.org/#dom-attr-value
|
||||
fn SetValue(&self, value: DOMString) {
|
||||
if let Some(owner) = self.owner() {
|
||||
let value = owner.parse_attribute(&self.identifier.namespace,
|
||||
self.local_name(),
|
||||
value);
|
||||
let value = owner.parse_attribute(&self.identifier.namespace, self.local_name(), value);
|
||||
self.set_value(value, &owner);
|
||||
} else {
|
||||
*self.value.borrow_mut() = AttrValue::String(value.into());
|
||||
|
@ -175,7 +170,6 @@ impl AttrMethods for Attr {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
impl Attr {
|
||||
pub fn set_value(&self, mut value: AttrValue, owner: &Element) {
|
||||
let name = self.local_name().clone();
|
||||
|
@ -191,7 +185,12 @@ impl Attr {
|
|||
MutationObserver::queue_a_mutation_record(owner.upcast::<Node>(), mutation);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -229,7 +228,7 @@ impl Attr {
|
|||
(Some(old), None) => {
|
||||
// Already gone from the list of attributes of old owner.
|
||||
assert!(old.get_attribute(&ns, &self.identifier.local_name).r() != Some(self))
|
||||
}
|
||||
},
|
||||
(Some(old), Some(new)) => assert_eq!(&*old, new),
|
||||
_ => {},
|
||||
}
|
||||
|
|
|
@ -98,7 +98,11 @@ impl AudioBufferSourceNode {
|
|||
options: &AudioBufferSourceOptions,
|
||||
) -> Fallible<DomRoot<AudioBufferSourceNode>> {
|
||||
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(
|
||||
|
|
|
@ -36,9 +36,8 @@ impl AudioContext {
|
|||
// https://webaudio.github.io/web-audio-api/#AudioContext-constructors
|
||||
fn new_inherited(options: &AudioContextOptions) -> AudioContext {
|
||||
// Steps 1-3.
|
||||
let context = BaseAudioContext::new_inherited(
|
||||
BaseAudioContextOptions::AudioContext(options.into()),
|
||||
);
|
||||
let context =
|
||||
BaseAudioContext::new_inherited(BaseAudioContextOptions::AudioContext(options.into()));
|
||||
|
||||
// Step 4.1.
|
||||
let latency_hint = options.latencyHint;
|
||||
|
|
|
@ -22,8 +22,8 @@ impl AudioDestinationNode {
|
|||
context: &BaseAudioContext,
|
||||
options: &AudioNodeOptions,
|
||||
) -> AudioDestinationNode {
|
||||
let node_options = options.unwrap_or(2, ChannelCountMode::Max,
|
||||
ChannelInterpretation::Speakers);
|
||||
let node_options =
|
||||
options.unwrap_or(2, ChannelCountMode::Max, ChannelInterpretation::Speakers);
|
||||
AudioDestinationNode {
|
||||
node: AudioNode::new_inherited_for_id(
|
||||
context.destination_node(),
|
||||
|
|
|
@ -28,10 +28,7 @@ pub struct AudioListener {
|
|||
}
|
||||
|
||||
impl AudioListener {
|
||||
fn new_inherited(
|
||||
window: &Window,
|
||||
context: &BaseAudioContext,
|
||||
) -> AudioListener {
|
||||
fn new_inherited(window: &Window, context: &BaseAudioContext) -> AudioListener {
|
||||
let node = context.listener();
|
||||
|
||||
let position_x = AudioParam::new(
|
||||
|
@ -139,10 +136,7 @@ impl AudioListener {
|
|||
}
|
||||
|
||||
#[allow(unrooted_must_root)]
|
||||
pub fn new(
|
||||
window: &Window,
|
||||
context: &BaseAudioContext,
|
||||
) -> DomRoot<AudioListener> {
|
||||
pub fn new(window: &Window, context: &BaseAudioContext) -> DomRoot<AudioListener> {
|
||||
let node = AudioListener::new_inherited(window, context);
|
||||
reflect_dom_object(Box::new(node), window, AudioListenerBinding::Wrap)
|
||||
}
|
||||
|
|
|
@ -36,7 +36,6 @@ pub struct AudioNode {
|
|||
channel_interpretation: Cell<ChannelInterpretation>,
|
||||
}
|
||||
|
||||
|
||||
impl AudioNode {
|
||||
pub fn new_inherited(
|
||||
node_type: AudioNodeInit,
|
||||
|
@ -54,7 +53,13 @@ impl AudioNode {
|
|||
interpretation: options.interpretation.into(),
|
||||
};
|
||||
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(
|
||||
|
@ -177,8 +182,7 @@ impl AudioNodeMethods for AudioNode {
|
|||
fn Disconnect_____(&self, param: &AudioParam) -> ErrorResult {
|
||||
self.context
|
||||
.audio_context_impl()
|
||||
.disconnect_to(self.node_id(),
|
||||
param.node_id().param(param.param_type()));
|
||||
.disconnect_to(self.node_id(), param.node_id().param(param.param_type()));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -186,8 +190,10 @@ impl AudioNodeMethods for AudioNode {
|
|||
fn Disconnect______(&self, param: &AudioParam, out: u32) -> ErrorResult {
|
||||
self.context
|
||||
.audio_context_impl()
|
||||
.disconnect_output_between_to(self.node_id().output(out),
|
||||
param.node_id().param(param.param_type()));
|
||||
.disconnect_output_between_to(
|
||||
self.node_id().output(out),
|
||||
param.node_id().param(param.param_type()),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -223,14 +229,14 @@ impl AudioNodeMethods for AudioNode {
|
|||
},
|
||||
EventTargetTypeId::AudioNode(AudioNodeTypeId::PannerNode) => {
|
||||
if value > 2 {
|
||||
return Err(Error::NotSupported)
|
||||
}
|
||||
return Err(Error::NotSupported);
|
||||
}
|
||||
},
|
||||
EventTargetTypeId::AudioNode(AudioNodeTypeId::ChannelMergerNode) => {
|
||||
if value != 1 {
|
||||
return Err(Error::InvalidState)
|
||||
}
|
||||
return Err(Error::InvalidState);
|
||||
}
|
||||
},
|
||||
// XXX We do not support any of the other AudioNodes with
|
||||
// constraints yet. Add more cases here as we add support
|
||||
// for new AudioNodes.
|
||||
|
@ -266,14 +272,14 @@ impl AudioNodeMethods for AudioNode {
|
|||
},
|
||||
EventTargetTypeId::AudioNode(AudioNodeTypeId::PannerNode) => {
|
||||
if value == ChannelCountMode::Max {
|
||||
return Err(Error::NotSupported)
|
||||
}
|
||||
return Err(Error::NotSupported);
|
||||
}
|
||||
},
|
||||
EventTargetTypeId::AudioNode(AudioNodeTypeId::ChannelMergerNode) => {
|
||||
if value != ChannelCountMode::Explicit {
|
||||
return Err(Error::InvalidState)
|
||||
}
|
||||
return Err(Error::InvalidState);
|
||||
}
|
||||
},
|
||||
// XXX We do not support any of the other AudioNodes with
|
||||
// constraints yet. Add more cases here as we add support
|
||||
// for new AudioNodes.
|
||||
|
@ -321,14 +327,17 @@ impl From<ChannelInterpretation> for ServoMediaChannelInterpretation {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
impl AudioNodeOptions {
|
||||
pub fn unwrap_or(&self, count: u32, mode: ChannelCountMode,
|
||||
interpretation: ChannelInterpretation) -> UnwrappedAudioNodeOptions {
|
||||
pub fn unwrap_or(
|
||||
&self,
|
||||
count: u32,
|
||||
mode: ChannelCountMode,
|
||||
interpretation: ChannelInterpretation,
|
||||
) -> UnwrappedAudioNodeOptions {
|
||||
UnwrappedAudioNodeOptions {
|
||||
count: self.channelCount.unwrap_or(count),
|
||||
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) {
|
||||
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 {
|
||||
|
@ -101,25 +103,25 @@ impl AudioParamMethods for AudioParam {
|
|||
// https://webaudio.github.io/web-audio-api/#dom-audioparam-automationrate
|
||||
fn SetAutomationRate(&self, automation_rate: AutomationRate) {
|
||||
self.automation_rate.set(automation_rate);
|
||||
self.message_node(
|
||||
AudioNodeMessage::SetParamRate(self.param, automation_rate.into())
|
||||
);
|
||||
self.message_node(AudioNodeMessage::SetParamRate(
|
||||
self.param,
|
||||
automation_rate.into(),
|
||||
));
|
||||
}
|
||||
|
||||
// https://webaudio.github.io/web-audio-api/#dom-audioparam-value
|
||||
fn Value(&self) -> Finite<f32> {
|
||||
let (tx, rx) = mpsc::channel();
|
||||
self.message_node(
|
||||
AudioNodeMessage::GetParamValue(self.param, tx)
|
||||
);
|
||||
self.message_node(AudioNodeMessage::GetParamValue(self.param, tx));
|
||||
Finite::wrap(rx.recv().unwrap())
|
||||
}
|
||||
|
||||
// https://webaudio.github.io/web-audio-api/#dom-audioparam-value
|
||||
fn SetValue(&self, value: Finite<f32>) {
|
||||
self.message_node(
|
||||
AudioNodeMessage::SetParam(self.param, UserAutomationEvent::SetValue(*value)),
|
||||
);
|
||||
self.message_node(AudioNodeMessage::SetParam(
|
||||
self.param,
|
||||
UserAutomationEvent::SetValue(*value),
|
||||
));
|
||||
}
|
||||
|
||||
// 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
|
||||
fn SetValueAtTime(&self, value: Finite<f32>, start_time: Finite<f64>) -> DomRoot<AudioParam> {
|
||||
self.message_node(
|
||||
AudioNodeMessage::SetParam(
|
||||
self.message_node(AudioNodeMessage::SetParam(
|
||||
self.param,
|
||||
UserAutomationEvent::SetValueAtTime(*value, *start_time),
|
||||
)
|
||||
);
|
||||
));
|
||||
DomRoot::from_ref(self)
|
||||
}
|
||||
|
||||
|
@ -154,12 +154,10 @@ impl AudioParamMethods for AudioParam {
|
|||
value: Finite<f32>,
|
||||
end_time: Finite<f64>,
|
||||
) -> DomRoot<AudioParam> {
|
||||
self.message_node(
|
||||
AudioNodeMessage::SetParam(
|
||||
self.message_node(AudioNodeMessage::SetParam(
|
||||
self.param,
|
||||
UserAutomationEvent::RampToValueAtTime(RampKind::Linear, *value, *end_time),
|
||||
),
|
||||
);
|
||||
));
|
||||
DomRoot::from_ref(self)
|
||||
}
|
||||
|
||||
|
@ -169,12 +167,10 @@ impl AudioParamMethods for AudioParam {
|
|||
value: Finite<f32>,
|
||||
end_time: Finite<f64>,
|
||||
) -> DomRoot<AudioParam> {
|
||||
self.message_node(
|
||||
AudioNodeMessage::SetParam(
|
||||
self.message_node(AudioNodeMessage::SetParam(
|
||||
self.param,
|
||||
UserAutomationEvent::RampToValueAtTime(RampKind::Exponential, *value, *end_time),
|
||||
),
|
||||
);
|
||||
));
|
||||
DomRoot::from_ref(self)
|
||||
}
|
||||
|
||||
|
@ -185,34 +181,28 @@ impl AudioParamMethods for AudioParam {
|
|||
start_time: Finite<f64>,
|
||||
time_constant: Finite<f32>,
|
||||
) -> DomRoot<AudioParam> {
|
||||
self.message_node(
|
||||
AudioNodeMessage::SetParam(
|
||||
self.message_node(AudioNodeMessage::SetParam(
|
||||
self.param,
|
||||
UserAutomationEvent::SetTargetAtTime(*target, *start_time, (*time_constant).into()),
|
||||
),
|
||||
);
|
||||
));
|
||||
DomRoot::from_ref(self)
|
||||
}
|
||||
|
||||
// https://webaudio.github.io/web-audio-api/#dom-audioparam-cancelscheduledvalues
|
||||
fn CancelScheduledValues(&self, cancel_time: Finite<f64>) -> DomRoot<AudioParam> {
|
||||
self.message_node(
|
||||
AudioNodeMessage::SetParam(
|
||||
self.message_node(AudioNodeMessage::SetParam(
|
||||
self.param,
|
||||
UserAutomationEvent::CancelScheduledValues(*cancel_time),
|
||||
),
|
||||
);
|
||||
));
|
||||
DomRoot::from_ref(self)
|
||||
}
|
||||
|
||||
// https://webaudio.github.io/web-audio-api/#dom-audioparam-cancelandholdattime
|
||||
fn CancelAndHoldAtTime(&self, cancel_time: Finite<f64>) -> DomRoot<AudioParam> {
|
||||
self.message_node(
|
||||
AudioNodeMessage::SetParam(
|
||||
self.message_node(AudioNodeMessage::SetParam(
|
||||
self.param,
|
||||
UserAutomationEvent::CancelAndHoldAtTime(*cancel_time),
|
||||
),
|
||||
);
|
||||
));
|
||||
DomRoot::from_ref(self)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -84,9 +84,10 @@ impl AudioScheduledSourceNodeMethods for AudioScheduledSourceNode {
|
|||
);
|
||||
});
|
||||
|
||||
self.node().message(
|
||||
AudioNodeMessage::AudioScheduledSourceNode(
|
||||
AudioScheduledSourceNodeMessage::RegisterOnEndedCallback(callback)));
|
||||
self.node()
|
||||
.message(AudioNodeMessage::AudioScheduledSourceNode(
|
||||
AudioScheduledSourceNodeMessage::RegisterOnEndedCallback(callback),
|
||||
));
|
||||
|
||||
self.started.set(true);
|
||||
self.node
|
||||
|
|
|
@ -98,7 +98,9 @@ impl BaseAudioContext {
|
|||
pub fn new_inherited(options: BaseAudioContextOptions) -> BaseAudioContext {
|
||||
let (sample_rate, channel_count) = match options {
|
||||
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 {
|
||||
|
@ -312,9 +314,7 @@ impl BaseAudioContextMethods for BaseAudioContext {
|
|||
fn Listener(&self) -> DomRoot<AudioListener> {
|
||||
let global = self.global();
|
||||
let window = global.as_window();
|
||||
self.listener.or_init(|| {
|
||||
AudioListener::new(&window, self)
|
||||
})
|
||||
self.listener.or_init(|| AudioListener::new(&window, self))
|
||||
}
|
||||
|
||||
/// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-onstatechange
|
||||
|
@ -425,12 +425,10 @@ impl BaseAudioContextMethods for BaseAudioContext {
|
|||
.lock()
|
||||
.unwrap()
|
||||
.resize(channel_count as usize, Vec::new());
|
||||
})
|
||||
.progress(move |buffer, channel| {
|
||||
}).progress(move |buffer, channel| {
|
||||
let mut decoded_audio = decoded_audio_.lock().unwrap();
|
||||
decoded_audio[(channel - 1) as usize].extend_from_slice((*buffer).as_ref());
|
||||
})
|
||||
.eos(move || {
|
||||
}).eos(move || {
|
||||
let _ = task_source.queue_with_canceller(
|
||||
task!(audio_decode_eos: move || {
|
||||
let this = this.root();
|
||||
|
@ -456,8 +454,7 @@ impl BaseAudioContextMethods for BaseAudioContext {
|
|||
}),
|
||||
&canceller,
|
||||
);
|
||||
})
|
||||
.error(move || {
|
||||
}).error(move || {
|
||||
let _ = task_source_.queue_with_canceller(
|
||||
task!(audio_decode_eos: move || {
|
||||
let this = this_.root();
|
||||
|
@ -473,8 +470,7 @@ impl BaseAudioContextMethods for BaseAudioContext {
|
|||
}),
|
||||
&canceller_,
|
||||
);
|
||||
})
|
||||
.build();
|
||||
}).build();
|
||||
self.audio_context_impl
|
||||
.decode_audio_data(audio_data, callbacks);
|
||||
} else {
|
||||
|
@ -491,10 +487,12 @@ impl BaseAudioContextMethods for BaseAudioContext {
|
|||
impl From<BaseAudioContextOptions> for AudioContextOptions {
|
||||
fn from(options: BaseAudioContextOptions) -> Self {
|
||||
match options {
|
||||
BaseAudioContextOptions::AudioContext(options) =>
|
||||
AudioContextOptions::RealTimeAudioContext(options),
|
||||
BaseAudioContextOptions::OfflineAudioContext(options) =>
|
||||
AudioContextOptions::OfflineAudioContext(options),
|
||||
BaseAudioContextOptions::AudioContext(options) => {
|
||||
AudioContextOptions::RealTimeAudioContext(options)
|
||||
},
|
||||
BaseAudioContextOptions::OfflineAudioContext(options) => {
|
||||
AudioContextOptions::OfflineAudioContext(options)
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,20 +33,23 @@ impl 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,
|
||||
BeforeUnloadEventBinding::Wrap)
|
||||
BeforeUnloadEventBinding::Wrap,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn new(window: &Window,
|
||||
pub fn new(
|
||||
window: &Window,
|
||||
type_: Atom,
|
||||
bubbles: EventBubbles,
|
||||
cancelable: EventCancelable) -> DomRoot<BeforeUnloadEvent> {
|
||||
cancelable: EventCancelable,
|
||||
) -> DomRoot<BeforeUnloadEvent> {
|
||||
let ev = BeforeUnloadEvent::new_uninitialized(window);
|
||||
{
|
||||
let event = ev.upcast::<Event>();
|
||||
event.init_event(type_, bool::from(bubbles),
|
||||
bool::from(cancelable));
|
||||
event.init_event(type_, bool::from(bubbles), bool::from(cancelable));
|
||||
}
|
||||
ev
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ pub struct CallbackObject {
|
|||
///
|
||||
/// ["callback context"]: https://heycam.github.io/webidl/#dfn-callback-context
|
||||
/// [sometimes]: https://github.com/whatwg/html/issues/2248
|
||||
incumbent: Option<Dom<GlobalScope>>
|
||||
incumbent: Option<Dom<GlobalScope>>,
|
||||
}
|
||||
|
||||
impl Default for CallbackObject {
|
||||
|
@ -81,8 +81,11 @@ impl CallbackObject {
|
|||
unsafe fn init(&mut self, cx: *mut JSContext, callback: *mut JSObject) {
|
||||
self.callback.set(callback);
|
||||
self.permanent_js_root.set(ObjectValue(callback));
|
||||
assert!(AddRawValueRoot(cx, self.permanent_js_root.get_unsafe(),
|
||||
b"CallbackObject::root\n".as_c_char_ptr()));
|
||||
assert!(AddRawValueRoot(
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl PartialEq for CallbackObject {
|
||||
|
@ -103,7 +105,6 @@ impl PartialEq for CallbackObject {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/// A trait to be implemented by concrete IDL callback function and
|
||||
/// callback interface types.
|
||||
pub trait CallbackContainer {
|
||||
|
@ -124,7 +125,6 @@ pub trait CallbackContainer {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/// A common base class for representing IDL callback function types.
|
||||
#[derive(JSTraceable, PartialEq)]
|
||||
#[must_root]
|
||||
|
@ -153,9 +153,6 @@ impl CallbackFunction {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// A common base class for representing IDL callback interface types.
|
||||
#[derive(JSTraceable, PartialEq)]
|
||||
#[must_root]
|
||||
|
@ -194,19 +191,22 @@ impl CallbackInterface {
|
|||
}
|
||||
|
||||
if !callable.is_object() || !IsCallable(callable.to_object()) {
|
||||
return Err(Error::Type(format!("The value of the {} property is not callable",
|
||||
name)));
|
||||
return Err(Error::Type(format!(
|
||||
"The value of the {} property is not callable",
|
||||
name
|
||||
)));
|
||||
}
|
||||
}
|
||||
Ok(callable.get())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// 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,
|
||||
mut rval: MutableHandleObject) {
|
||||
mut rval: MutableHandleObject,
|
||||
) {
|
||||
rval.set(p.reflector().get_jsobject().get());
|
||||
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
|
||||
/// this class is on the stack. After `new` returns, the call is safe to make.
|
||||
pub struct CallSetup {
|
||||
|
@ -241,9 +240,7 @@ pub struct CallSetup {
|
|||
impl CallSetup {
|
||||
/// Performs the setup needed to make a call.
|
||||
#[allow(unrooted_must_root)]
|
||||
pub fn new<T: CallbackContainer>(callback: &T,
|
||||
handling: ExceptionHandling)
|
||||
-> CallSetup {
|
||||
pub fn new<T: CallbackContainer>(callback: &T, handling: ExceptionHandling) -> CallSetup {
|
||||
let global = unsafe { GlobalScope::from_object(callback.callback()) };
|
||||
let cx = global.get_cx();
|
||||
|
||||
|
@ -270,8 +267,10 @@ impl Drop for CallSetup {
|
|||
unsafe {
|
||||
JS_LeaveCompartment(self.cx, self.old_compartment);
|
||||
if self.handling == ExceptionHandling::Report {
|
||||
let _ac = JSAutoCompartment::new(self.cx,
|
||||
self.exception_global.reflector().get_jsobject().get());
|
||||
let _ac = JSAutoCompartment::new(
|
||||
self.cx,
|
||||
self.exception_global.reflector().get_jsobject().get(),
|
||||
);
|
||||
report_pending_exception(self.cx, true);
|
||||
}
|
||||
drop(self.incumbent_script.take());
|
||||
|
|
|
@ -55,7 +55,6 @@ impl<T> DomRefCell<T> {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/// Immutably borrows the wrapped value.
|
||||
///
|
||||
/// 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.
|
||||
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.
|
||||
|
@ -81,7 +81,8 @@ impl<T> DomRefCell<T> {
|
|||
///
|
||||
/// Panics if the value is currently borrowed.
|
||||
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.
|
||||
|
|
|
@ -51,16 +51,15 @@ impl ConstantSpec {
|
|||
|
||||
/// Defines constants on `obj`.
|
||||
/// Fails on JSAPI failure.
|
||||
pub unsafe fn define_constants(
|
||||
cx: *mut JSContext,
|
||||
obj: HandleObject,
|
||||
constants: &[ConstantSpec]) {
|
||||
pub unsafe fn define_constants(cx: *mut JSContext, obj: HandleObject, constants: &[ConstantSpec]) {
|
||||
for spec in constants {
|
||||
rooted!(in(cx) let value = spec.get_value());
|
||||
assert!(JS_DefineProperty(cx,
|
||||
assert!(JS_DefineProperty(
|
||||
cx,
|
||||
obj,
|
||||
spec.name.as_ptr() as *const libc::c_char,
|
||||
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.
|
||||
#[cfg_attr(feature = "unstable",
|
||||
rustc_on_unimplemented = "The IDL interface `{Self}` is not derived from `{T}`.")]
|
||||
#[cfg_attr(
|
||||
feature = "unstable",
|
||||
rustc_on_unimplemented = "The IDL interface `{Self}` is not derived from `{T}`."
|
||||
)]
|
||||
pub trait DerivedFrom<T: Castable>: Castable {}
|
||||
|
||||
impl<T: Float + ToJSValConvertible> ToJSValConvertible for Finite<T> {
|
||||
|
@ -84,17 +86,18 @@ impl<T: Float + ToJSValConvertible> ToJSValConvertible for Finite<T> {
|
|||
impl<T: Float + FromJSValConvertible<Config = ()>> FromJSValConvertible for Finite<T> {
|
||||
type Config = ();
|
||||
|
||||
unsafe fn from_jsval(cx: *mut JSContext,
|
||||
unsafe fn from_jsval(
|
||||
cx: *mut JSContext,
|
||||
value: HandleValue,
|
||||
option: ())
|
||||
-> Result<ConversionResult<Finite<T>>, ()> {
|
||||
option: (),
|
||||
) -> Result<ConversionResult<Finite<T>>, ()> {
|
||||
let result = match FromJSValConvertible::from_jsval(cx, value, option)? {
|
||||
ConversionResult::Success(v) => v,
|
||||
ConversionResult::Failure(error) => {
|
||||
// FIXME(emilio): Why throwing instead of propagating the error?
|
||||
throw_type_error(cx, &error);
|
||||
return Err(());
|
||||
}
|
||||
},
|
||||
};
|
||||
match Finite::new(result) {
|
||||
Some(v) => Ok(ConversionResult::Success(v)),
|
||||
|
@ -109,10 +112,11 @@ impl<T: Float + FromJSValConvertible<Config=()>> FromJSValConvertible for Finite
|
|||
impl<T: DomObject + IDLInterface> FromJSValConvertible for DomRoot<T> {
|
||||
type Config = ();
|
||||
|
||||
unsafe fn from_jsval(_cx: *mut JSContext,
|
||||
unsafe fn from_jsval(
|
||||
_cx: *mut JSContext,
|
||||
value: HandleValue,
|
||||
_config: Self::Config)
|
||||
-> Result<ConversionResult<DomRoot<T>>, ()> {
|
||||
_config: Self::Config,
|
||||
) -> Result<ConversionResult<DomRoot<T>>, ()> {
|
||||
Ok(match root_from_handlevalue(value) {
|
||||
Ok(result) => ConversionResult::Success(result),
|
||||
Err(()) => ConversionResult::Failure("value is not an object".into()),
|
||||
|
@ -131,17 +135,19 @@ impl<T: ToJSValConvertible + JSTraceable> ToJSValConvertible for RootedTraceable
|
|||
impl<T> FromJSValConvertible for RootedTraceableBox<Heap<T>>
|
||||
where
|
||||
T: FromJSValConvertible + js::rust::GCMethods + Copy,
|
||||
Heap<T>: JSTraceable + Default
|
||||
Heap<T>: JSTraceable + Default,
|
||||
{
|
||||
type Config = T::Config;
|
||||
|
||||
unsafe fn from_jsval(cx: *mut JSContext,
|
||||
unsafe fn from_jsval(
|
||||
cx: *mut JSContext,
|
||||
value: HandleValue,
|
||||
config: Self::Config)
|
||||
-> Result<ConversionResult<Self>, ()> {
|
||||
config: Self::Config,
|
||||
) -> Result<ConversionResult<Self>, ()> {
|
||||
T::from_jsval(cx, value, config).map(|result| match result {
|
||||
ConversionResult::Success(inner) =>
|
||||
ConversionResult::Success(RootedTraceableBox::from_box(Heap::boxed(inner))),
|
||||
ConversionResult::Success(inner) => {
|
||||
ConversionResult::Success(RootedTraceableBox::from_box(Heap::boxed(inner)))
|
||||
},
|
||||
ConversionResult::Failure(msg) => ConversionResult::Failure(msg),
|
||||
})
|
||||
}
|
||||
|
@ -190,12 +196,12 @@ impl ToJSValConvertible for DOMString {
|
|||
// https://heycam.github.io/webidl/#es-DOMString
|
||||
impl FromJSValConvertible for DOMString {
|
||||
type Config = StringificationBehavior;
|
||||
unsafe fn from_jsval(cx: *mut JSContext,
|
||||
unsafe fn from_jsval(
|
||||
cx: *mut JSContext,
|
||||
value: HandleValue,
|
||||
null_behavior: StringificationBehavior)
|
||||
-> Result<ConversionResult<DOMString>, ()> {
|
||||
if null_behavior == StringificationBehavior::Empty &&
|
||||
value.get().is_null() {
|
||||
null_behavior: StringificationBehavior,
|
||||
) -> Result<ConversionResult<DOMString>, ()> {
|
||||
if null_behavior == StringificationBehavior::Empty && value.get().is_null() {
|
||||
Ok(ConversionResult::Success(DOMString::new()))
|
||||
} else {
|
||||
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. \
|
||||
If you see this in real web content, \
|
||||
please comment on https://github.com/servo/servo/issues/6564"
|
||||
}
|
||||
};
|
||||
}
|
||||
if opts::get().replace_surrogates {
|
||||
error!(message!());
|
||||
s.push('\u{FFFD}');
|
||||
} else {
|
||||
panic!(concat!(message!(), " Use `-Z replace-surrogates` \
|
||||
on the command line to make this non-fatal."));
|
||||
}
|
||||
panic!(concat!(
|
||||
message!(),
|
||||
" Use `-Z replace-surrogates` \
|
||||
on the command line to make this non-fatal."
|
||||
));
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
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
|
||||
impl FromJSValConvertible for USVString {
|
||||
type Config = ();
|
||||
unsafe fn from_jsval(cx: *mut JSContext, value: HandleValue, _: ())
|
||||
-> Result<ConversionResult<USVString>, ()> {
|
||||
unsafe fn from_jsval(
|
||||
cx: *mut JSContext,
|
||||
value: HandleValue,
|
||||
_: (),
|
||||
) -> Result<ConversionResult<USVString>, ()> {
|
||||
let jsstr = ToString(cx, value);
|
||||
if jsstr.is_null() {
|
||||
debug!("ToString failed");
|
||||
|
@ -260,23 +272,28 @@ impl FromJSValConvertible for USVString {
|
|||
let latin1 = JS_StringHasLatin1Chars(jsstr);
|
||||
if latin1 {
|
||||
// FIXME(ajeffrey): Convert directly from DOMString to USVString
|
||||
return Ok(ConversionResult::Success(
|
||||
USVString(String::from(jsstring_to_str(cx, jsstr)))));
|
||||
return Ok(ConversionResult::Success(USVString(String::from(
|
||||
jsstring_to_str(cx, jsstr),
|
||||
))));
|
||||
}
|
||||
let mut length = 0;
|
||||
let chars = JS_GetTwoByteStringCharsAndLength(cx, ptr::null(), jsstr, &mut length);
|
||||
assert!(!chars.is_null());
|
||||
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
|
||||
impl ToJSValConvertible for ByteString {
|
||||
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.len() as libc::size_t);
|
||||
self.len() as libc::size_t,
|
||||
);
|
||||
if jsstr.is_null() {
|
||||
panic!("JS_NewStringCopyN failed");
|
||||
}
|
||||
|
@ -287,10 +304,11 @@ impl ToJSValConvertible for ByteString {
|
|||
// http://heycam.github.io/webidl/#es-ByteString
|
||||
impl FromJSValConvertible for ByteString {
|
||||
type Config = ();
|
||||
unsafe fn from_jsval(cx: *mut JSContext,
|
||||
unsafe fn from_jsval(
|
||||
cx: *mut JSContext,
|
||||
value: HandleValue,
|
||||
_option: ())
|
||||
-> Result<ConversionResult<ByteString>, ()> {
|
||||
_option: (),
|
||||
) -> Result<ConversionResult<ByteString>, ()> {
|
||||
let string = ToString(cx, value);
|
||||
if string.is_null() {
|
||||
debug!("ToString failed");
|
||||
|
@ -304,7 +322,9 @@ impl FromJSValConvertible for ByteString {
|
|||
assert!(!chars.is_null());
|
||||
|
||||
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;
|
||||
|
@ -315,13 +335,13 @@ impl FromJSValConvertible for ByteString {
|
|||
throw_type_error(cx, "Invalid ByteString");
|
||||
Err(())
|
||||
} else {
|
||||
Ok(ConversionResult::Success(
|
||||
ByteString::new(char_vec.iter().map(|&c| c as u8).collect())))
|
||||
Ok(ConversionResult::Success(ByteString::new(
|
||||
char_vec.iter().map(|&c| c as u8).collect(),
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl ToJSValConvertible for Reflector {
|
||||
unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {
|
||||
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
|
||||
/// proto_id and proto_depth).
|
||||
#[inline]
|
||||
pub unsafe fn private_from_proto_check<F>(mut obj: *mut JSObject,
|
||||
proto_check: F)
|
||||
-> Result<*const libc::c_void, ()>
|
||||
where F: Fn(&'static DOMClass) -> bool
|
||||
pub unsafe fn private_from_proto_check<F>(
|
||||
mut obj: *mut JSObject,
|
||||
proto_check: F,
|
||||
) -> Result<*const libc::c_void, ()>
|
||||
where
|
||||
F: Fn(&'static DOMClass) -> bool,
|
||||
{
|
||||
let dom_class = get_dom_class(obj).or_else(|_| {
|
||||
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`.
|
||||
pub fn native_from_object<T>(obj: *mut JSObject) -> Result<*const T, ()>
|
||||
where T: DomObject + IDLInterface
|
||||
where
|
||||
T: DomObject + IDLInterface,
|
||||
{
|
||||
unsafe {
|
||||
private_from_proto_check(obj, T::derives).map(|ptr| ptr as *const T)
|
||||
}
|
||||
unsafe { 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
|
||||
|
@ -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
|
||||
/// proto_id and proto_depth).
|
||||
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) })
|
||||
}
|
||||
|
@ -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`.
|
||||
/// 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, ()>
|
||||
where T: DomObject + IDLInterface
|
||||
where
|
||||
T: DomObject + IDLInterface,
|
||||
{
|
||||
if !v.get().is_object() {
|
||||
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`.
|
||||
/// 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>, ()>
|
||||
where T: DomObject + IDLInterface
|
||||
where
|
||||
T: DomObject + IDLInterface,
|
||||
{
|
||||
if !v.get().is_object() {
|
||||
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`.
|
||||
pub fn root_from_handleobject<T>(obj: HandleObject) -> Result<DomRoot<T>, ()>
|
||||
where T: DomObject + IDLInterface
|
||||
where
|
||||
T: DomObject + IDLInterface,
|
||||
{
|
||||
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.
|
||||
pub unsafe fn get_property_jsval(cx: *mut JSContext,
|
||||
pub unsafe fn get_property_jsval(
|
||||
cx: *mut JSContext,
|
||||
object: HandleObject,
|
||||
name: &str,
|
||||
mut rval: MutableHandleValue)
|
||||
-> Fallible<()>
|
||||
{
|
||||
mut rval: MutableHandleValue,
|
||||
) -> Fallible<()> {
|
||||
rval.set(UndefinedValue());
|
||||
let cname = match ffi::CString::new(name) {
|
||||
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.
|
||||
pub unsafe fn get_property<T>(cx: *mut JSContext,
|
||||
pub unsafe fn get_property<T>(
|
||||
cx: *mut JSContext,
|
||||
object: HandleObject,
|
||||
name: &str,
|
||||
option: T::Config)
|
||||
-> Fallible<Option<T>> where
|
||||
T: FromJSValConvertible
|
||||
option: T::Config,
|
||||
) -> Fallible<Option<T>>
|
||||
where
|
||||
T: FromJSValConvertible,
|
||||
{
|
||||
debug!("Getting property {}.", name);
|
||||
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 => {
|
||||
assert!(JS_IsExceptionPending(cx));
|
||||
return;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
assert!(!JS_IsExceptionPending(cx));
|
||||
|
@ -149,8 +149,7 @@ pub struct ErrorInfo {
|
|||
}
|
||||
|
||||
impl ErrorInfo {
|
||||
unsafe fn from_native_error(cx: *mut JSContext, object: HandleObject)
|
||||
-> Option<ErrorInfo> {
|
||||
unsafe fn from_native_error(cx: *mut JSContext, object: HandleObject) -> Option<ErrorInfo> {
|
||||
let report = JS_ErrorFromException(cx, object);
|
||||
if report.is_null() {
|
||||
return None;
|
||||
|
@ -205,7 +204,9 @@ impl ErrorInfo {
|
|||
/// The `dispatch_event` argument is temporary and non-standard; passing false
|
||||
/// prevents dispatching the `error` event.
|
||||
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());
|
||||
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());
|
||||
ErrorInfo::from_native_error(cx, object.handle())
|
||||
.or_else(|| ErrorInfo::from_dom_exception(object.handle()))
|
||||
.unwrap_or_else(|| {
|
||||
ErrorInfo {
|
||||
.unwrap_or_else(|| ErrorInfo {
|
||||
message: format!("uncaught exception: unknown (can't convert to string)"),
|
||||
filename: String::new(),
|
||||
lineno: 0,
|
||||
column: 0,
|
||||
}
|
||||
})
|
||||
} else {
|
||||
match USVString::from_jsval(cx, value.handle(), ()) {
|
||||
Ok(ConversionResult::Success(USVString(string))) => {
|
||||
ErrorInfo {
|
||||
Ok(ConversionResult::Success(USVString(string))) => ErrorInfo {
|
||||
message: format!("uncaught exception: {}", string),
|
||||
filename: String::new(),
|
||||
lineno: 0,
|
||||
column: 0,
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
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_info.filename,
|
||||
error_info.lineno,
|
||||
error_info.column,
|
||||
error_info.message);
|
||||
error!(
|
||||
"Error at {}:{}:{} {}",
|
||||
error_info.filename, error_info.lineno, error_info.column, error_info.message
|
||||
);
|
||||
|
||||
if dispatch_event {
|
||||
GlobalScope::from_context(cx)
|
||||
.report_an_error(error_info, value.handle());
|
||||
GlobalScope::from_context(cx).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.
|
||||
pub unsafe fn throw_invalid_this(cx: *mut JSContext, proto_id: u16) {
|
||||
debug_assert!(!JS_IsExceptionPending(cx));
|
||||
let error = format!("\"this\" object does not implement interface {}.",
|
||||
proto_id_to_name(proto_id));
|
||||
let error = format!(
|
||||
"\"this\" object does not implement interface {}.",
|
||||
proto_id_to_name(proto_id)
|
||||
);
|
||||
throw_type_error(cx, &error);
|
||||
}
|
||||
|
||||
impl Error {
|
||||
/// 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));
|
||||
throw_dom_exception(cx, global, self);
|
||||
assert!(JS_IsExceptionPending(cx));
|
||||
|
|
|
@ -89,7 +89,9 @@ use std::ptr;
|
|||
|
||||
// https://html.spec.whatwg.org/multipage/#htmlconstructor
|
||||
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();
|
||||
|
||||
// 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());
|
||||
let definition = match registry.lookup_definition_by_constructor(new_target.handle()) {
|
||||
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));
|
||||
|
@ -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
|
||||
|
||||
// Retrieve the constructor object for HTMLElement
|
||||
HTMLElementBinding::GetConstructorObject(window.get_cx(), global_object.handle(), constructor.handle_mut());
|
||||
|
||||
} else {
|
||||
// Step 5
|
||||
get_constructor_object_from_local_name(definition.local_name.clone(),
|
||||
HTMLElementBinding::GetConstructorObject(
|
||||
window.get_cx(),
|
||||
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.
|
||||
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.
|
||||
/// 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,
|
||||
global: HandleObject,
|
||||
rval: MutableHandleObject)
|
||||
-> bool {
|
||||
rval: MutableHandleObject,
|
||||
) -> bool {
|
||||
macro_rules! get_constructor(
|
||||
($binding:ident) => ({
|
||||
unsafe { $binding::GetConstructorObject(cx, global, rval); }
|
||||
|
|
|
@ -16,7 +16,8 @@ use std::mem;
|
|||
pub trait Castable: IDLInterface + DomObject + Sized {
|
||||
/// Check whether a DOM object implements one of its deriving interfaces.
|
||||
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() };
|
||||
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.
|
||||
fn upcast<T>(&self) -> &T
|
||||
where T: Castable,
|
||||
Self: DerivedFrom<T>
|
||||
where
|
||||
T: Castable,
|
||||
Self: DerivedFrom<T>,
|
||||
{
|
||||
unsafe { mem::transmute(self) }
|
||||
}
|
||||
|
||||
/// Cast a DOM object downwards to one of the interfaces it might implement.
|
||||
fn downcast<T>(&self) -> Option<&T>
|
||||
where T: DerivedFrom<Self>
|
||||
where
|
||||
T: DerivedFrom<Self>,
|
||||
{
|
||||
if self.is::<T>() {
|
||||
Some(unsafe { mem::transmute(self) })
|
||||
|
|
|
@ -52,11 +52,12 @@ unsafe impl Sync for NonCallbackInterfaceObjectClass {}
|
|||
|
||||
impl NonCallbackInterfaceObjectClass {
|
||||
/// 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],
|
||||
proto_id: PrototypeList::ID,
|
||||
proto_depth: u16)
|
||||
-> NonCallbackInterfaceObjectClass {
|
||||
proto_depth: u16,
|
||||
) -> NonCallbackInterfaceObjectClass {
|
||||
NonCallbackInterfaceObjectClass {
|
||||
class: Class {
|
||||
name: b"Function\0" as *const _ as *const libc::c_char,
|
||||
|
@ -74,9 +75,7 @@ impl NonCallbackInterfaceObjectClass {
|
|||
|
||||
/// cast own reference to `JSClass` reference
|
||||
pub fn as_jsclass(&self) -> &JSClass {
|
||||
unsafe {
|
||||
&*(self as *const _ as *const JSClass)
|
||||
}
|
||||
unsafe { &*(self as *const _ as *const JSClass) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -124,8 +123,7 @@ impl InterfaceConstructorBehavior {
|
|||
}
|
||||
|
||||
/// A trace hook.
|
||||
pub type TraceHook =
|
||||
unsafe extern "C" fn(trc: *mut JSTracer, obj: *mut JSObject);
|
||||
pub type TraceHook = unsafe extern "C" fn(trc: *mut JSTracer, obj: *mut JSObject);
|
||||
|
||||
/// Create a global object with the given class.
|
||||
pub unsafe fn create_global_object(
|
||||
|
@ -133,18 +131,21 @@ pub unsafe fn create_global_object(
|
|||
class: &'static JSClass,
|
||||
private: *const libc::c_void,
|
||||
trace: TraceHook,
|
||||
mut rval: MutableHandleObject) {
|
||||
mut rval: MutableHandleObject,
|
||||
) {
|
||||
assert!(rval.is_null());
|
||||
|
||||
let mut options = CompartmentOptions::default();
|
||||
options.creationOptions_.traceGlobal_ = Some(trace);
|
||||
options.creationOptions_.sharedMemoryAndAtomics_ = true;
|
||||
|
||||
rval.set(JS_NewGlobalObject(cx,
|
||||
rval.set(JS_NewGlobalObject(
|
||||
cx,
|
||||
class,
|
||||
ptr::null_mut(),
|
||||
OnNewGlobalHookOption::DontFireOnNewGlobalHook,
|
||||
&options));
|
||||
&options,
|
||||
));
|
||||
assert!(!rval.is_null());
|
||||
|
||||
// Initialize the reserved slots before doing anything that can GC, to
|
||||
|
@ -166,7 +167,8 @@ pub unsafe fn create_callback_interface_object(
|
|||
global: HandleObject,
|
||||
constants: &[Guard<&[ConstantSpec]>],
|
||||
name: &[u8],
|
||||
mut rval: MutableHandleObject) {
|
||||
mut rval: MutableHandleObject,
|
||||
) {
|
||||
assert!(!constants.is_empty());
|
||||
rval.set(JS_NewObject(cx, ptr::null()));
|
||||
assert!(!rval.is_null());
|
||||
|
@ -184,8 +186,17 @@ pub unsafe fn create_interface_prototype_object(
|
|||
regular_properties: &[Guard<&'static [JSPropertySpec]>],
|
||||
constants: &[Guard<&[ConstantSpec]>],
|
||||
unscopable_names: &[&[u8]],
|
||||
rval: MutableHandleObject) {
|
||||
create_object(cx, proto, class, regular_methods, regular_properties, constants, rval);
|
||||
rval: MutableHandleObject,
|
||||
) {
|
||||
create_object(
|
||||
cx,
|
||||
proto,
|
||||
class,
|
||||
regular_methods,
|
||||
regular_properties,
|
||||
constants,
|
||||
rval,
|
||||
);
|
||||
|
||||
if !unscopable_names.is_empty() {
|
||||
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));
|
||||
assert!(JS_DefinePropertyById4(
|
||||
cx, rval.handle(), unscopable_id.handle(), unscopable_obj.handle(),
|
||||
JSPROP_READONLY as u32))
|
||||
cx,
|
||||
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,
|
||||
name: &[u8],
|
||||
length: u32,
|
||||
rval: MutableHandleObject) {
|
||||
create_object(cx,
|
||||
rval: MutableHandleObject,
|
||||
) {
|
||||
create_object(
|
||||
cx,
|
||||
proto,
|
||||
class.as_jsclass(),
|
||||
static_methods,
|
||||
static_properties,
|
||||
constants,
|
||||
rval);
|
||||
assert!(JS_LinkConstructorAndPrototype(cx, rval.handle(), interface_prototype_object));
|
||||
rval,
|
||||
);
|
||||
assert!(JS_LinkConstructorAndPrototype(
|
||||
cx,
|
||||
rval.handle(),
|
||||
interface_prototype_object
|
||||
));
|
||||
define_name(cx, rval.handle(), name);
|
||||
define_length(cx, rval.handle(), i32::try_from(length).expect("overflow"));
|
||||
define_on_global_object(cx, global, name, rval.handle());
|
||||
|
@ -232,26 +254,31 @@ pub unsafe fn create_named_constructors(
|
|||
cx: *mut JSContext,
|
||||
global: HandleObject,
|
||||
named_constructors: &[(ConstructorClassHook, &[u8], u32)],
|
||||
interface_prototype_object: HandleObject) {
|
||||
interface_prototype_object: HandleObject,
|
||||
) {
|
||||
rooted!(in(cx) let mut constructor = ptr::null_mut::<JSObject>());
|
||||
|
||||
for &(native, name, arity) in named_constructors {
|
||||
assert_eq!(*name.last().unwrap(), b'\0');
|
||||
|
||||
let fun = JS_NewFunction(cx,
|
||||
let fun = JS_NewFunction(
|
||||
cx,
|
||||
Some(native),
|
||||
arity,
|
||||
JSFUN_CONSTRUCTOR,
|
||||
name.as_ptr() as *const libc::c_char);
|
||||
name.as_ptr() as *const libc::c_char,
|
||||
);
|
||||
assert!(!fun.is_null());
|
||||
constructor.set(JS_GetFunctionObject(fun));
|
||||
assert!(!constructor.is_null());
|
||||
|
||||
assert!(JS_DefineProperty2(cx,
|
||||
assert!(JS_DefineProperty2(
|
||||
cx,
|
||||
constructor.handle(),
|
||||
b"prototype\0".as_ptr() as *const libc::c_char,
|
||||
interface_prototype_object,
|
||||
(JSPROP_PERMANENT | JSPROP_READONLY) as u32));
|
||||
(JSPROP_PERMANENT | JSPROP_READONLY) as u32
|
||||
));
|
||||
|
||||
define_on_global_object(cx, global, name, constructor.handle());
|
||||
}
|
||||
|
@ -265,7 +292,8 @@ pub unsafe fn create_object(
|
|||
methods: &[Guard<&'static [JSFunctionSpec]>],
|
||||
properties: &[Guard<&'static [JSPropertySpec]>],
|
||||
constants: &[Guard<&[ConstantSpec]>],
|
||||
mut rval: MutableHandleObject) {
|
||||
mut rval: MutableHandleObject,
|
||||
) {
|
||||
rval.set(JS_NewObjectWithUniqueType(cx, class, proto));
|
||||
assert!(!rval.is_null());
|
||||
define_guarded_methods(cx, rval.handle(), methods);
|
||||
|
@ -277,7 +305,8 @@ pub unsafe fn create_object(
|
|||
pub unsafe fn define_guarded_constants(
|
||||
cx: *mut JSContext,
|
||||
obj: HandleObject,
|
||||
constants: &[Guard<&[ConstantSpec]>]) {
|
||||
constants: &[Guard<&[ConstantSpec]>],
|
||||
) {
|
||||
for guard in constants {
|
||||
if let Some(specs) = guard.expose(cx, obj) {
|
||||
define_constants(cx, obj, specs);
|
||||
|
@ -289,7 +318,8 @@ pub unsafe fn define_guarded_constants(
|
|||
pub unsafe fn define_guarded_methods(
|
||||
cx: *mut JSContext,
|
||||
obj: HandleObject,
|
||||
methods: &[Guard<&'static [JSFunctionSpec]>]) {
|
||||
methods: &[Guard<&'static [JSFunctionSpec]>],
|
||||
) {
|
||||
for guard in methods {
|
||||
if let Some(specs) = guard.expose(cx, obj) {
|
||||
define_methods(cx, obj, specs).unwrap();
|
||||
|
@ -301,7 +331,8 @@ pub unsafe fn define_guarded_methods(
|
|||
pub unsafe fn define_guarded_properties(
|
||||
cx: *mut JSContext,
|
||||
obj: HandleObject,
|
||||
properties: &[Guard<&'static [JSPropertySpec]>]) {
|
||||
properties: &[Guard<&'static [JSPropertySpec]>],
|
||||
) {
|
||||
for guard in properties {
|
||||
if let Some(specs) = guard.expose(cx, obj) {
|
||||
define_properties(cx, obj, specs).unwrap();
|
||||
|
@ -323,13 +354,16 @@ pub unsafe fn define_on_global_object(
|
|||
cx: *mut JSContext,
|
||||
global: HandleObject,
|
||||
name: &[u8],
|
||||
obj: HandleObject) {
|
||||
obj: HandleObject,
|
||||
) {
|
||||
assert_eq!(*name.last().unwrap(), b'\0');
|
||||
assert!(JS_DefineProperty2(cx,
|
||||
assert!(JS_DefineProperty2(
|
||||
cx,
|
||||
global,
|
||||
name.as_ptr() as *const libc::c_char,
|
||||
obj,
|
||||
JSPROP_RESOLVING));
|
||||
JSPROP_RESOLVING
|
||||
));
|
||||
}
|
||||
|
||||
const OBJECT_OPS: ObjectOps = ObjectOps {
|
||||
|
@ -344,10 +378,11 @@ const OBJECT_OPS: ObjectOps = ObjectOps {
|
|||
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,
|
||||
_is_to_source: bool)
|
||||
-> *mut JSString {
|
||||
_is_to_source: bool,
|
||||
) -> *mut JSString {
|
||||
let js_class = get_object_class(obj.get());
|
||||
assert!(!js_class.is_null());
|
||||
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.
|
||||
unsafe extern "C" fn has_instance_hook(cx: *mut JSContext,
|
||||
unsafe extern "C" fn has_instance_hook(
|
||||
cx: *mut JSContext,
|
||||
obj: RawHandleObject,
|
||||
value: RawMutableHandleValue,
|
||||
rval: *mut bool) -> bool {
|
||||
rval: *mut bool,
|
||||
) -> bool {
|
||||
let obj_raw = HandleObject::from_raw(obj);
|
||||
let val_raw = HandleValue::from_raw(value.handle());
|
||||
match has_instance(cx, obj_raw, val_raw) {
|
||||
Ok(result) => {
|
||||
*rval = result;
|
||||
true
|
||||
}
|
||||
},
|
||||
Err(()) => false,
|
||||
}
|
||||
}
|
||||
|
@ -378,8 +415,8 @@ unsafe extern "C" fn has_instance_hook(cx: *mut JSContext,
|
|||
unsafe fn has_instance(
|
||||
cx: *mut JSContext,
|
||||
interface_object: HandleObject,
|
||||
value: HandleValue)
|
||||
-> Result<bool, ()> {
|
||||
value: HandleValue,
|
||||
) -> Result<bool, ()> {
|
||||
if !value.is_object() {
|
||||
// Step 1.
|
||||
return Ok(false);
|
||||
|
@ -391,8 +428,10 @@ unsafe fn has_instance(
|
|||
let js_class = get_object_class(interface_object.get());
|
||||
let object_class = &*(js_class as *const NonCallbackInterfaceObjectClass);
|
||||
|
||||
if let Ok(dom_class) = get_dom_class(UncheckedUnwrapObject(value.get(),
|
||||
/* stopAtWindowProxy = */ 0)) {
|
||||
if let Ok(dom_class) = get_dom_class(UncheckedUnwrapObject(
|
||||
value.get(),
|
||||
/* stopAtWindowProxy = */ 0,
|
||||
)) {
|
||||
if dom_class.interface_chain[object_class.proto_depth as usize] == object_class.proto_id {
|
||||
// Step 4.
|
||||
return Ok(true);
|
||||
|
@ -424,7 +463,8 @@ unsafe fn has_instance(
|
|||
unsafe fn create_unscopable_object(
|
||||
cx: *mut JSContext,
|
||||
names: &[&[u8]],
|
||||
mut rval: MutableHandleObject) {
|
||||
mut rval: MutableHandleObject,
|
||||
) {
|
||||
assert!(!names.is_empty());
|
||||
assert!(rval.is_null());
|
||||
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');
|
||||
rooted!(in(cx) let name = JS_AtomizeAndPinString(cx, name.as_ptr() as *const libc::c_char));
|
||||
assert!(!name.is_null());
|
||||
assert!(JS_DefineProperty3(cx,
|
||||
assert!(JS_DefineProperty3(
|
||||
cx,
|
||||
obj,
|
||||
b"name\0".as_ptr() as *const libc::c_char,
|
||||
name.handle().into(),
|
||||
JSPROP_READONLY as u32));
|
||||
JSPROP_READONLY as u32
|
||||
));
|
||||
}
|
||||
|
||||
unsafe fn define_length(cx: *mut JSContext, obj: HandleObject, length: i32) {
|
||||
assert!(JS_DefineProperty4(cx,
|
||||
assert!(JS_DefineProperty4(
|
||||
cx,
|
||||
obj,
|
||||
b"length\0".as_ptr() as *const libc::c_char,
|
||||
length,
|
||||
JSPROP_READONLY as u32));
|
||||
JSPROP_READONLY as u32
|
||||
));
|
||||
}
|
||||
|
||||
unsafe extern "C" fn invalid_constructor(
|
||||
cx: *mut JSContext,
|
||||
_argc: libc::c_uint,
|
||||
_vp: *mut JSVal)
|
||||
-> bool {
|
||||
_vp: *mut JSVal,
|
||||
) -> bool {
|
||||
throw_type_error(cx, "Illegal constructor.");
|
||||
false
|
||||
}
|
||||
|
@ -472,8 +516,8 @@ unsafe extern "C" fn invalid_constructor(
|
|||
unsafe extern "C" fn non_new_constructor(
|
||||
cx: *mut JSContext,
|
||||
_argc: libc::c_uint,
|
||||
_vp: *mut JSVal)
|
||||
-> bool {
|
||||
_vp: *mut JSVal,
|
||||
) -> bool {
|
||||
throw_type_error(cx, "This constructor needs to be called with `new`.");
|
||||
false
|
||||
}
|
||||
|
|
|
@ -59,10 +59,11 @@ pub struct IterableIterator<T: DomObject + JSTraceable + Iterable> {
|
|||
|
||||
impl<T: DomObject + JSTraceable + Iterable> IterableIterator<T> {
|
||||
/// Create a new iterator instance for the provided iterable DOM interface.
|
||||
pub fn new(iterable: &T,
|
||||
pub fn new(
|
||||
iterable: &T,
|
||||
type_: IteratorType,
|
||||
wrap: unsafe fn(*mut JSContext, &GlobalScope, Box<IterableIterator<T>>)
|
||||
-> DomRoot<Self>) -> DomRoot<Self> {
|
||||
wrap: unsafe fn(*mut JSContext, &GlobalScope, Box<IterableIterator<T>>) -> DomRoot<Self>,
|
||||
) -> DomRoot<Self> {
|
||||
let iterator = Box::new(IterableIterator {
|
||||
reflector: Reflector::new(),
|
||||
type_: type_,
|
||||
|
@ -84,37 +85,45 @@ impl<T: DomObject + JSTraceable + Iterable> IterableIterator<T> {
|
|||
match self.type_ {
|
||||
IteratorType::Keys => {
|
||||
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())
|
||||
}
|
||||
},
|
||||
IteratorType::Values => {
|
||||
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())
|
||||
}
|
||||
},
|
||||
IteratorType::Entries => {
|
||||
rooted!(in(cx) let mut key = UndefinedValue());
|
||||
unsafe {
|
||||
self.iterable.get_key_at_index(index).to_jsval(cx, key.handle_mut());
|
||||
self.iterable.get_value_at_index(index).to_jsval(cx, value.handle_mut());
|
||||
self.iterable
|
||||
.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())
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
self.index.set(index + 1);
|
||||
result.map(|_| {
|
||||
NonNull::new(rval.get()).expect("got a null pointer")
|
||||
})
|
||||
result.map(|_| NonNull::new(rval.get()).expect("got a null pointer"))
|
||||
}
|
||||
}
|
||||
|
||||
fn dict_return(cx: *mut JSContext,
|
||||
fn dict_return(
|
||||
cx: *mut JSContext,
|
||||
mut result: MutableHandleObject,
|
||||
done: bool,
|
||||
value: HandleValue) -> Fallible<()> {
|
||||
value: HandleValue,
|
||||
) -> Fallible<()> {
|
||||
let mut dict = IterableKeyOrValueResult::empty();
|
||||
dict.done = done;
|
||||
dict.value.set(value.get());
|
||||
|
@ -126,16 +135,20 @@ fn dict_return(cx: *mut JSContext,
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn key_and_value_return(cx: *mut JSContext,
|
||||
fn key_and_value_return(
|
||||
cx: *mut JSContext,
|
||||
mut result: MutableHandleObject,
|
||||
key: HandleValue,
|
||||
value: HandleValue) -> Fallible<()> {
|
||||
value: HandleValue,
|
||||
) -> Fallible<()> {
|
||||
let mut dict = IterableKeyAndValueResult::empty();
|
||||
dict.done = false;
|
||||
dict.value = Some(vec![key, value]
|
||||
dict.value = Some(
|
||||
vec![key, value]
|
||||
.into_iter()
|
||||
.map(|handle| RootedTraceableBox::from_box(Heap::boxed(handle.get())))
|
||||
.collect());
|
||||
.collect(),
|
||||
);
|
||||
rooted!(in(cx) let mut dict_value = UndefinedValue());
|
||||
unsafe {
|
||||
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>
|
||||
where T: FromJSValConvertible<Config=C>,
|
||||
where
|
||||
T: FromJSValConvertible<Config = C>,
|
||||
C: Clone,
|
||||
{
|
||||
type Config = C;
|
||||
unsafe fn from_jsval(cx: *mut JSContext, value: HandleValue, config: C)
|
||||
-> Result<ConversionResult<Self>, ()> {
|
||||
unsafe fn from_jsval(
|
||||
cx: *mut JSContext,
|
||||
value: HandleValue,
|
||||
config: C,
|
||||
) -> Result<ConversionResult<Self>, ()> {
|
||||
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());
|
||||
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?
|
||||
// (it does so if the object has duplicate keys)
|
||||
// https://github.com/servo/servo/issues/21462
|
||||
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();
|
||||
|
@ -90,9 +103,7 @@ impl<T, C> FromJSValConvertible for MozMap<T>
|
|||
}
|
||||
}
|
||||
|
||||
Ok(ConversionResult::Success(MozMap {
|
||||
map: map,
|
||||
}))
|
||||
Ok(ConversionResult::Success(MozMap { map: map }))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -107,12 +118,14 @@ impl<T: ToJSValConvertible> ToJSValConvertible for MozMap<T> {
|
|||
let key = key.encode_utf16().collect::<Vec<_>>();
|
||||
value.to_jsval(cx, js_value.handle_mut());
|
||||
|
||||
assert!(JS_DefineUCProperty2(cx,
|
||||
assert!(JS_DefineUCProperty2(
|
||||
cx,
|
||||
js_object.handle(),
|
||||
key.as_ptr(),
|
||||
key.len(),
|
||||
js_value.handle(),
|
||||
JSPROP_ENUMERATE as u32));
|
||||
JSPROP_ENUMERATE as u32
|
||||
));
|
||||
}
|
||||
|
||||
rval.set(ObjectValue(js_object.handle().get()));
|
||||
|
|
|
@ -36,7 +36,8 @@ pub unsafe fn create_namespace_object(
|
|||
class: &'static NamespaceObjectClass,
|
||||
methods: &[Guard<&'static [JSFunctionSpec]>],
|
||||
name: &[u8],
|
||||
rval: MutableHandleObject) {
|
||||
rval: MutableHandleObject,
|
||||
) {
|
||||
create_object(cx, proto, &class.0, methods, &[], &[], rval);
|
||||
define_on_global_object(cx, global, name, rval.handle());
|
||||
}
|
||||
|
|
|
@ -26,8 +26,10 @@ impl<T: Float> Finite<T> {
|
|||
/// Create a new `Finite<T: Float>`.
|
||||
#[inline]
|
||||
pub fn wrap(value: T) -> Finite<T> {
|
||||
assert!(value.is_finite(),
|
||||
"Finite<T> doesn't encapsulate unrestricted value.");
|
||||
assert!(
|
||||
value.is_finite(),
|
||||
"Finite<T> doesn't encapsulate unrestricted value."
|
||||
);
|
||||
Finite(value)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,12 +30,12 @@ use js::rust::wrappers::JS_AlreadyHasOwnPropertyById;
|
|||
use js::rust::wrappers::JS_NewObjectWithGivenProto;
|
||||
use std::ptr;
|
||||
|
||||
|
||||
/// 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,
|
||||
id: RawHandleId)
|
||||
-> DOMProxyShadowsResult {
|
||||
id: RawHandleId,
|
||||
) -> DOMProxyShadowsResult {
|
||||
// TODO: support OverrideBuiltins when #12978 is fixed.
|
||||
|
||||
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.
|
||||
pub unsafe fn init() {
|
||||
SetDOMProxyInformation(GetProxyHandlerFamily(),
|
||||
Some(shadow_check_callback));
|
||||
SetDOMProxyInformation(GetProxyHandlerFamily(), Some(shadow_check_callback));
|
||||
}
|
||||
|
||||
/// Invoke the [[GetOwnProperty]] trap (`getOwnPropertyDescriptor`) on `proxy`,
|
||||
/// with argument `id` and return the result, if it is not `undefined`.
|
||||
/// Otherwise, walk along the prototype chain to find a property with that
|
||||
/// 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,
|
||||
id: RawHandleId,
|
||||
desc: RawMutableHandle<PropertyDescriptor>)
|
||||
-> bool {
|
||||
desc: RawMutableHandle<PropertyDescriptor>,
|
||||
) -> bool {
|
||||
let handler = GetProxyHandler(proxy.get());
|
||||
if !InvokeGetOwnPropertyDescriptor(handler, cx, proxy, id, desc) {
|
||||
return false;
|
||||
|
@ -91,23 +91,25 @@ pub unsafe extern "C" fn get_property_descriptor(cx: *mut JSContext,
|
|||
}
|
||||
|
||||
/// 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,
|
||||
id: RawHandleId,
|
||||
desc: RawHandle<PropertyDescriptor>,
|
||||
result: *mut ObjectOpResult)
|
||||
-> bool {
|
||||
result: *mut ObjectOpResult,
|
||||
) -> bool {
|
||||
rooted!(in(cx) let mut expando = ptr::null_mut::<JSObject>());
|
||||
ensure_expando_object(cx, proxy, expando.handle_mut());
|
||||
JS_DefinePropertyById(cx, expando.handle().into(), id, desc, result)
|
||||
}
|
||||
|
||||
/// 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,
|
||||
id: RawHandleId,
|
||||
bp: *mut ObjectOpResult)
|
||||
-> bool {
|
||||
bp: *mut ObjectOpResult,
|
||||
) -> bool {
|
||||
rooted!(in(cx) let mut expando = ptr::null_mut::<JSObject>());
|
||||
get_expando_object(proxy, expando.handle_mut());
|
||||
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
|
||||
pub unsafe extern "C" fn prevent_extensions(_cx: *mut JSContext,
|
||||
pub unsafe extern "C" fn prevent_extensions(
|
||||
_cx: *mut JSContext,
|
||||
_proxy: RawHandleObject,
|
||||
result: *mut ObjectOpResult)
|
||||
-> bool {
|
||||
result: *mut ObjectOpResult,
|
||||
) -> bool {
|
||||
(*result).code_ = JSErrNum::JSMSG_CANT_PREVENT_EXTENSIONS as ::libc::uintptr_t;
|
||||
true
|
||||
}
|
||||
|
||||
/// 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,
|
||||
succeeded: *mut bool)
|
||||
-> bool {
|
||||
succeeded: *mut bool,
|
||||
) -> bool {
|
||||
*succeeded = 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
|
||||
/// `[[GetPrototypeOf]]` behavior. An alternative implementation will be
|
||||
/// 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,
|
||||
is_ordinary: *mut bool,
|
||||
proto: RawMutableHandleObject)
|
||||
-> bool {
|
||||
proto: RawMutableHandleObject,
|
||||
) -> bool {
|
||||
*is_ordinary = true;
|
||||
proto.set(GetStaticPrototype(proxy.get()));
|
||||
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.
|
||||
/// 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()));
|
||||
get_expando_object(obj, expando);
|
||||
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());
|
||||
|
||||
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,
|
||||
/// 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,
|
||||
attrs: u32) {
|
||||
attrs: u32,
|
||||
) {
|
||||
desc.obj = obj;
|
||||
desc.attrs = attrs;
|
||||
desc.getter = None;
|
||||
|
|
|
@ -39,9 +39,9 @@ use std::rc::Rc;
|
|||
use std::sync::{Arc, Weak};
|
||||
use task::TaskOnce;
|
||||
|
||||
|
||||
#[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::rc::Rc;
|
||||
use super::LiveDOMReferences;
|
||||
|
@ -50,7 +50,6 @@ mod dummy { // Attributes don’t apply through the macro.
|
|||
}
|
||||
pub use self::dummy::LIVE_REFERENCES;
|
||||
|
||||
|
||||
/// A pointer to a Rust DOM object that needs to be destroyed.
|
||||
pub struct TrustedReference(*const libc::c_void);
|
||||
unsafe impl Send for TrustedReference {}
|
||||
|
@ -98,19 +97,28 @@ impl TrustedPromise {
|
|||
LIVE_REFERENCES.with(|ref r| {
|
||||
let r = r.borrow();
|
||||
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.
|
||||
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) => {
|
||||
let promise = {
|
||||
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() {
|
||||
entry.remove();
|
||||
}
|
||||
promise
|
||||
}
|
||||
},
|
||||
Vacant(_) => unreachable!(),
|
||||
};
|
||||
promise
|
||||
|
@ -182,9 +190,7 @@ impl<T: DomObject> Trusted<T> {
|
|||
let live_references = r.as_ref().unwrap();
|
||||
self.owner_thread == (&*live_references) as *const _ as *const libc::c_void
|
||||
}));
|
||||
unsafe {
|
||||
DomRoot::from_ref(&*(self.refcount.0 as *const T))
|
||||
}
|
||||
unsafe { DomRoot::from_ref(&*(self.refcount.0 as *const T)) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -246,15 +252,15 @@ impl LiveDOMReferences {
|
|||
let refcount = Arc::new(TrustedReference::new(ptr));
|
||||
entry.insert(Arc::downgrade(&refcount));
|
||||
refcount
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Remove null entries from the live references table
|
||||
fn remove_nulls<K: Eq + Hash + Clone, V>(table: &mut HashMap<K, Weak<V>>) {
|
||||
let to_remove: Vec<K> =
|
||||
table.iter()
|
||||
let to_remove: Vec<K> = table
|
||||
.iter()
|
||||
.filter(|&(_, value)| Weak::upgrade(value).is_none())
|
||||
.map(|(key, _)| key.clone())
|
||||
.collect();
|
||||
|
|
|
@ -16,14 +16,14 @@ use std::default::Default;
|
|||
pub fn reflect_dom_object<T, U>(
|
||||
obj: Box<T>,
|
||||
global: &U,
|
||||
wrap_fn: unsafe fn(*mut JSContext, &GlobalScope, Box<T>) -> DomRoot<T>)
|
||||
-> DomRoot<T>
|
||||
where T: DomObject, U: DerivedFrom<GlobalScope>
|
||||
wrap_fn: unsafe fn(*mut JSContext, &GlobalScope, Box<T>) -> DomRoot<T>,
|
||||
) -> DomRoot<T>
|
||||
where
|
||||
T: DomObject,
|
||||
U: DerivedFrom<GlobalScope>,
|
||||
{
|
||||
let global_scope = global.upcast();
|
||||
unsafe {
|
||||
wrap_fn(global_scope.get_cx(), global_scope, obj)
|
||||
}
|
||||
unsafe { wrap_fn(global_scope.get_cx(), global_scope, obj) }
|
||||
}
|
||||
|
||||
/// 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;
|
||||
|
||||
/// 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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -96,9 +96,7 @@ where
|
|||
trace_reflector(tracer, "on stack", &self.0);
|
||||
}
|
||||
}
|
||||
unsafe {
|
||||
&*(self.reflector() as *const Reflector as *const ReflectorStackRoot)
|
||||
}
|
||||
unsafe { &*(self.reflector() as *const Reflector as *const ReflectorStackRoot) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -131,15 +129,17 @@ pub type DomRoot<T> = Root<Dom<T>>;
|
|||
impl<T: Castable> DomRoot<T> {
|
||||
/// Cast a DOM object root upwards to one of the interfaces it derives from.
|
||||
pub fn upcast<U>(root: DomRoot<T>) -> DomRoot<U>
|
||||
where U: Castable,
|
||||
T: DerivedFrom<U>
|
||||
where
|
||||
U: Castable,
|
||||
T: DerivedFrom<U>,
|
||||
{
|
||||
unsafe { mem::transmute(root) }
|
||||
}
|
||||
|
||||
/// Cast a DOM object root downwards to one of the interfaces it might implement.
|
||||
pub fn downcast<U>(root: DomRoot<T>) -> Option<DomRoot<U>>
|
||||
where U: DerivedFrom<T>
|
||||
where
|
||||
U: DerivedFrom<T>,
|
||||
{
|
||||
if root.is::<U>() {
|
||||
Some(unsafe { mem::transmute(root) })
|
||||
|
@ -207,9 +207,7 @@ pub struct ThreadLocalStackRoots<'a>(PhantomData<&'a u32>);
|
|||
|
||||
impl<'a> ThreadLocalStackRoots<'a> {
|
||||
pub fn new(roots: &'a RootCollection) -> Self {
|
||||
STACK_ROOTS.with(|ref r| {
|
||||
r.set(Some(roots))
|
||||
});
|
||||
STACK_ROOTS.with(|ref r| r.set(Some(roots)));
|
||||
ThreadLocalStackRoots(PhantomData)
|
||||
}
|
||||
}
|
||||
|
@ -363,9 +361,7 @@ unsafe impl<T: DomObject> JSTraceable for Dom<T> {
|
|||
#[cfg(not(all(feature = "unstable", debug_assertions)))]
|
||||
let trace_info = "for DOM object on heap";
|
||||
|
||||
trace_reflector(trc,
|
||||
trace_info,
|
||||
(*self.ptr.as_ptr()).reflector());
|
||||
trace_reflector(trc, trace_info, (*self.ptr.as_ptr()).reflector());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -379,8 +375,9 @@ pub struct LayoutDom<T> {
|
|||
impl<T: Castable> LayoutDom<T> {
|
||||
/// Cast a DOM object root upwards to one of the interfaces it derives from.
|
||||
pub fn upcast<U>(&self) -> LayoutDom<U>
|
||||
where U: Castable,
|
||||
T: DerivedFrom<U>
|
||||
where
|
||||
U: Castable,
|
||||
T: DerivedFrom<U>,
|
||||
{
|
||||
debug_assert!(thread_state::get().is_layout());
|
||||
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.
|
||||
pub fn downcast<U>(&self) -> Option<LayoutDom<U>>
|
||||
where U: DerivedFrom<T>
|
||||
where
|
||||
U: DerivedFrom<T>,
|
||||
{
|
||||
debug_assert!(thread_state::get().is_layout());
|
||||
unsafe {
|
||||
|
@ -429,7 +427,6 @@ impl<'a, T: DomObject> PartialEq<&'a T> for Dom<T> {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
impl<T> Eq for Dom<T> {}
|
||||
|
||||
impl<T> PartialEq for LayoutDom<T> {
|
||||
|
@ -516,9 +513,7 @@ impl<T: DomObject> MutDom<T> {
|
|||
/// Get the value in this `MutDom`.
|
||||
pub fn get(&self) -> DomRoot<T> {
|
||||
debug_assert!(thread_state::get().is_script());
|
||||
unsafe {
|
||||
DomRoot::from_ref(&*ptr::read(self.val.get()))
|
||||
}
|
||||
unsafe { 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> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
unsafe {
|
||||
*self.val.get() == *other.val.get()
|
||||
}
|
||||
unsafe { *self.val.get() == *other.val.get() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: DomObject + PartialEq> PartialEq<T> for MutDom<T> {
|
||||
fn eq(&self, other: &T) -> bool {
|
||||
unsafe {
|
||||
**self.val.get() == *other
|
||||
}
|
||||
unsafe { **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
|
||||
/// initialized with the result of `cb` first.
|
||||
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());
|
||||
match self.get() {
|
||||
|
@ -594,9 +586,7 @@ impl<T: DomObject> MutNullableDom<T> {
|
|||
#[allow(unrooted_must_root)]
|
||||
pub fn get(&self) -> Option<DomRoot<T>> {
|
||||
debug_assert!(thread_state::get().is_script());
|
||||
unsafe {
|
||||
ptr::read(self.ptr.get()).map(|o| DomRoot::from_ref(&*o))
|
||||
}
|
||||
unsafe { ptr::read(self.ptr.get()).map(|o| DomRoot::from_ref(&*o)) }
|
||||
}
|
||||
|
||||
/// Set this `MutNullableDom` to the given value.
|
||||
|
@ -617,17 +607,13 @@ impl<T: DomObject> MutNullableDom<T> {
|
|||
|
||||
impl<T: DomObject> PartialEq for MutNullableDom<T> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
unsafe {
|
||||
*self.ptr.get() == *other.ptr.get()
|
||||
}
|
||||
unsafe { *self.ptr.get() == *other.ptr.get() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: DomObject> PartialEq<Option<&'a T>> for MutNullableDom<T> {
|
||||
fn eq(&self, other: &Option<&T>) -> bool {
|
||||
unsafe {
|
||||
*self.ptr.get() == other.map(Dom::from_ref)
|
||||
}
|
||||
unsafe { *self.ptr.get() == other.map(Dom::from_ref) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -661,13 +647,14 @@ pub struct DomOnceCell<T: DomObject> {
|
|||
|
||||
impl<T> DomOnceCell<T>
|
||||
where
|
||||
T: DomObject
|
||||
T: DomObject,
|
||||
{
|
||||
/// Retrieve a copy of the current inner value. If it is `None`, it is
|
||||
/// initialized with the result of `cb` first.
|
||||
#[allow(unrooted_must_root)]
|
||||
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());
|
||||
&self.ptr.init_once(|| Dom::from_ref(&cb()))
|
||||
|
@ -725,14 +712,17 @@ pub trait OptionalHeapSetter {
|
|||
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;
|
||||
fn set(&mut self, v: Option<T>) {
|
||||
let v = match v {
|
||||
None => {
|
||||
*self = None;
|
||||
return;
|
||||
}
|
||||
},
|
||||
Some(v) => v,
|
||||
};
|
||||
|
||||
|
|
|
@ -36,9 +36,7 @@ pub unsafe fn trace(tracer: *mut JSTracer) {
|
|||
}
|
||||
|
||||
pub fn is_execution_stack_empty() -> bool {
|
||||
STACK.with(|stack| {
|
||||
stack.borrow().is_empty()
|
||||
})
|
||||
STACK.with(|stack| stack.borrow().is_empty())
|
||||
}
|
||||
|
||||
/// RAII struct that pushes and pops entries from the script settings stack.
|
||||
|
@ -69,9 +67,10 @@ impl Drop for AutoEntryScript {
|
|||
STACK.with(|stack| {
|
||||
let mut stack = stack.borrow_mut();
|
||||
let entry = stack.pop().unwrap();
|
||||
assert_eq!(&*entry.global as *const GlobalScope,
|
||||
&*self.global as *const GlobalScope,
|
||||
"Dropped AutoEntryScript out of order.");
|
||||
assert_eq!(
|
||||
&*entry.global as *const GlobalScope, &*self.global as *const GlobalScope,
|
||||
"Dropped AutoEntryScript out of order."
|
||||
);
|
||||
assert_eq!(entry.kind, StackEntryKind::Entry);
|
||||
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
|
||||
pub fn entry_global() -> DomRoot<GlobalScope> {
|
||||
STACK.with(|stack| {
|
||||
stack.borrow()
|
||||
STACK
|
||||
.with(|stack| {
|
||||
stack
|
||||
.borrow()
|
||||
.iter()
|
||||
.rev()
|
||||
.find(|entry| entry.kind == StackEntryKind::Entry)
|
||||
|
@ -133,11 +134,15 @@ impl Drop for AutoIncumbentScript {
|
|||
let mut stack = stack.borrow_mut();
|
||||
let entry = stack.pop().unwrap();
|
||||
// Step 3.
|
||||
assert_eq!(&*entry.global as *const GlobalScope as usize,
|
||||
self.global,
|
||||
"Dropped AutoIncumbentScript out of order.");
|
||||
assert_eq!(
|
||||
&*entry.global as *const GlobalScope as usize, self.global,
|
||||
"Dropped AutoIncumbentScript out of order."
|
||||
);
|
||||
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 {
|
||||
// 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.
|
||||
STACK.with(|stack| {
|
||||
stack.borrow()
|
||||
stack
|
||||
.borrow()
|
||||
.last()
|
||||
.map(|entry| DomRoot::from_ref(&*entry.global))
|
||||
})
|
||||
|
|
|
@ -82,7 +82,6 @@ impl ops::Deref for ByteString {
|
|||
#[derive(Clone, Default, MallocSizeOf)]
|
||||
pub struct USVString(pub String);
|
||||
|
||||
|
||||
/// Returns whether `s` is a `token`, as defined by
|
||||
/// [RFC 2616](http://tools.ietf.org/html/rfc2616#page-17).
|
||||
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
|
||||
match x {
|
||||
0...31 | 127 => false, // CTLs
|
||||
40 |
|
||||
41 |
|
||||
60 |
|
||||
62 |
|
||||
64 |
|
||||
44 |
|
||||
59 |
|
||||
58 |
|
||||
92 |
|
||||
34 |
|
||||
47 |
|
||||
91 |
|
||||
93 |
|
||||
63 |
|
||||
61 |
|
||||
123 |
|
||||
125 |
|
||||
32 => false, // separators
|
||||
40 | 41 | 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
|
||||
_ => true,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
/// A DOMString.
|
||||
///
|
||||
/// This type corresponds to the [`DOMString`](idl) type in WebIDL.
|
||||
|
@ -196,14 +178,16 @@ impl DOMString {
|
|||
/// Removes leading and trailing ASCII whitespaces according to
|
||||
/// <https://infra.spec.whatwg.org/#strip-leading-and-trailing-ascii-whitespace>.
|
||||
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)) {
|
||||
Some(idx) => idx + 1,
|
||||
None => {
|
||||
self.0.clear();
|
||||
return;
|
||||
}
|
||||
},
|
||||
};
|
||||
let first_non_whitespace = self.0.find(|ref c| !char::is_ascii_whitespace(c)).unwrap();
|
||||
|
||||
|
@ -231,17 +215,21 @@ impl DOMString {
|
|||
Done,
|
||||
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| {
|
||||
match state {
|
||||
// Step 1 "HH"
|
||||
State::HourHigh => {
|
||||
match c {
|
||||
State::HourHigh => match c {
|
||||
'0' | '1' => State::HourLow09,
|
||||
'2' => State::HourLow03,
|
||||
_ => State::Error,
|
||||
}
|
||||
},
|
||||
State::HourLow09 => next_state(c.is_digit(10), 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
|
||||
/// 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<(), ()> {
|
||||
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 {
|
||||
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 {
|
||||
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(())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl Borrow<str> for DOMString {
|
||||
|
@ -452,7 +446,10 @@ impl<'a> Into<CowRcStr<'a>> 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)
|
||||
}
|
||||
}
|
||||
|
@ -611,12 +608,12 @@ fn parse_time_component(value: &str) -> Result<(u32, u32, f32), ()> {
|
|||
return Err(());
|
||||
}
|
||||
},
|
||||
None => {}
|
||||
None => {},
|
||||
}
|
||||
|
||||
second.parse::<f32>().map_err(|_| ())?
|
||||
},
|
||||
None => 0.0
|
||||
None => 0.0,
|
||||
};
|
||||
|
||||
// Step 8
|
||||
|
@ -660,7 +657,7 @@ fn max_day_in_month(year_num: u32, month_num: u32) -> Result<u32, ()> {
|
|||
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() {
|
||||
Weekday::Thu => 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
|
||||
fn parse_floating_point_number(input: &str) -> Result<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,
|
||||
// except for +1., NaN, and Infinity.
|
||||
val.is_infinite() || val.is_nan() || input.ends_with(".") || input.starts_with("+")
|
||||
) => {
|
||||
) =>
|
||||
{
|
||||
// TODO(#19773): need consider `min`, `max`, `step`, when they are implemented
|
||||
Ok(val.round())
|
||||
},
|
||||
_ => Err(())
|
||||
}
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,34 +47,38 @@ enum StructuredCloneTags {
|
|||
}
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
unsafe fn write_length(w: *mut JSStructuredCloneWriter,
|
||||
length: usize) {
|
||||
unsafe fn write_length(w: *mut JSStructuredCloneWriter, length: usize) {
|
||||
let high: u32 = (length >> 32) as u32;
|
||||
let low: u32 = length as u32;
|
||||
assert!(JS_WriteUint32Pair(w, high, low));
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
unsafe fn write_length(w: *mut JSStructuredCloneWriter,
|
||||
length: usize) {
|
||||
unsafe fn write_length(w: *mut JSStructuredCloneWriter, length: usize) {
|
||||
assert!(JS_WriteUint32Pair(w, length as u32, 0));
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
unsafe fn read_length(r: *mut JSStructuredCloneReader)
|
||||
-> usize {
|
||||
unsafe fn read_length(r: *mut JSStructuredCloneReader) -> usize {
|
||||
let mut high: 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;
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
unsafe fn read_length(r: *mut JSStructuredCloneReader)
|
||||
-> usize {
|
||||
unsafe fn read_length(r: *mut JSStructuredCloneReader) -> usize {
|
||||
let mut length: 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;
|
||||
}
|
||||
|
||||
|
@ -86,7 +90,11 @@ impl StructuredCloneWriter {
|
|||
unsafe fn write_slice(&self, v: &[u8]) {
|
||||
let type_length = v.len();
|
||||
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) {
|
||||
self.write_slice(s.as_bytes());
|
||||
|
@ -101,7 +109,11 @@ impl StructuredCloneReader {
|
|||
unsafe fn read_bytes(&self) -> Vec<u8> {
|
||||
let mut bytes = vec![0u8; read_length(self.r)];
|
||||
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;
|
||||
}
|
||||
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,
|
||||
sc_holder: &mut StructuredCloneHolder)
|
||||
-> *mut JSObject {
|
||||
sc_holder: &mut StructuredCloneHolder,
|
||||
) -> *mut JSObject {
|
||||
let structured_reader = StructuredCloneReader { r: r };
|
||||
let blob_buffer = structured_reader.read_bytes();
|
||||
let type_str = structured_reader.read_str();
|
||||
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();
|
||||
sc_holder.blob = Some(blob);
|
||||
js_object
|
||||
}
|
||||
|
||||
unsafe fn write_blob(blob: DomRoot<Blob>,
|
||||
w: *mut JSStructuredCloneWriter)
|
||||
-> Result<(), ()> {
|
||||
unsafe fn write_blob(blob: DomRoot<Blob>, w: *mut JSStructuredCloneWriter) -> Result<(), ()> {
|
||||
let structured_writer = StructuredCloneWriter { w: w };
|
||||
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_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,
|
||||
tag: u32,
|
||||
_data: u32,
|
||||
closure: *mut raw::c_void)
|
||||
-> *mut JSObject {
|
||||
assert!(tag < StructuredCloneTags::Max as u32, "tag should be lower than StructuredCloneTags::Max");
|
||||
assert!(tag > StructuredCloneTags::Min as u32, "tag should be higher than StructuredCloneTags::Min");
|
||||
closure: *mut raw::c_void,
|
||||
) -> *mut JSObject {
|
||||
assert!(
|
||||
tag < StructuredCloneTags::Max as u32,
|
||||
"tag should be lower than StructuredCloneTags::Max"
|
||||
);
|
||||
assert!(
|
||||
tag > StructuredCloneTags::Min as u32,
|
||||
"tag should be higher than StructuredCloneTags::Min"
|
||||
);
|
||||
if tag == StructuredCloneTags::DomBlob as u32 {
|
||||
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,
|
||||
obj: RawHandleObject,
|
||||
_closure: *mut raw::c_void)
|
||||
-> bool {
|
||||
_closure: *mut raw::c_void,
|
||||
) -> bool {
|
||||
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,
|
||||
_tag: u32,
|
||||
_content: *mut raw::c_void,
|
||||
_extra_data: u64,
|
||||
_closure: *mut raw::c_void,
|
||||
_return_object: RawMutableHandleObject)
|
||||
-> bool {
|
||||
_return_object: RawMutableHandleObject,
|
||||
) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
unsafe extern "C" fn write_transfer_callback(_cx: *mut JSContext,
|
||||
unsafe extern "C" fn write_transfer_callback(
|
||||
_cx: *mut JSContext,
|
||||
_obj: RawHandleObject,
|
||||
_closure: *mut raw::c_void,
|
||||
_tag: *mut u32,
|
||||
_ownership: *mut TransferableOwnership,
|
||||
_content: *mut *mut raw::c_void,
|
||||
_extra_data: *mut u64)
|
||||
-> bool {
|
||||
_extra_data: *mut u64,
|
||||
) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
unsafe extern "C" fn free_transfer_callback(_tag: u32,
|
||||
unsafe extern "C" fn free_transfer_callback(
|
||||
_tag: u32,
|
||||
_ownership: TransferableOwnership,
|
||||
_content: *mut raw::c_void,
|
||||
_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 {
|
||||
read: Some(read_callback),
|
||||
|
@ -202,7 +232,7 @@ static STRUCTURED_CLONE_CALLBACKS: JSStructuredCloneCallbacks = JSStructuredClon
|
|||
};
|
||||
|
||||
struct StructuredCloneHolder {
|
||||
blob: Option<DomRoot<Blob>>
|
||||
blob: Option<DomRoot<Blob>>,
|
||||
}
|
||||
|
||||
/// A buffer for a structured clone.
|
||||
|
@ -210,7 +240,7 @@ pub enum StructuredCloneData {
|
|||
/// A non-serializable (default) variant
|
||||
Struct(*mut u64, size_t),
|
||||
/// A variant that can be serialized
|
||||
Vector(Vec<u8>)
|
||||
Vector(Vec<u8>),
|
||||
}
|
||||
|
||||
impl StructuredCloneData {
|
||||
|
@ -218,21 +248,25 @@ impl StructuredCloneData {
|
|||
/// Writes a structured clone. Returns a `DataClone` error if that fails.
|
||||
pub fn write(cx: *mut JSContext, message: HandleValue) -> Fallible<StructuredCloneData> {
|
||||
unsafe {
|
||||
let scbuf = NewJSAutoStructuredCloneBuffer(StructuredCloneScope::DifferentProcess,
|
||||
&STRUCTURED_CLONE_CALLBACKS);
|
||||
let scbuf = NewJSAutoStructuredCloneBuffer(
|
||||
StructuredCloneScope::DifferentProcess,
|
||||
&STRUCTURED_CLONE_CALLBACKS,
|
||||
);
|
||||
let scdata = &mut ((*scbuf).data_);
|
||||
let policy = CloneDataPolicy {
|
||||
// TODO: SAB?
|
||||
sharedArrayBuffer_: false,
|
||||
};
|
||||
let result = JS_WriteStructuredClone(cx,
|
||||
let result = JS_WriteStructuredClone(
|
||||
cx,
|
||||
message,
|
||||
scdata,
|
||||
StructuredCloneScope::DifferentProcess,
|
||||
policy,
|
||||
&STRUCTURED_CLONE_CALLBACKS,
|
||||
ptr::null_mut(),
|
||||
HandleValue::undefined());
|
||||
HandleValue::undefined(),
|
||||
);
|
||||
if !result {
|
||||
JS_ClearPendingException(cx);
|
||||
return Err(Error::DataClone);
|
||||
|
@ -252,41 +286,40 @@ impl StructuredCloneData {
|
|||
/// Converts a StructuredCloneData to Vec<u8> for inter-thread sharing
|
||||
pub fn move_to_arraybuffer(self) -> Vec<u8> {
|
||||
match self {
|
||||
StructuredCloneData::Struct(data, nbytes) => {
|
||||
unsafe {
|
||||
StructuredCloneData::Struct(data, nbytes) => unsafe {
|
||||
slice::from_raw_parts(data as *mut u8, nbytes).to_vec()
|
||||
}
|
||||
}
|
||||
StructuredCloneData::Vector(msg) => msg
|
||||
},
|
||||
StructuredCloneData::Vector(msg) => msg,
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads a structured clone.
|
||||
///
|
||||
/// Panics if `JS_ReadStructuredClone` fails.
|
||||
fn read_clone(global: &GlobalScope,
|
||||
data: *mut u64,
|
||||
nbytes: size_t,
|
||||
rval: MutableHandleValue) {
|
||||
fn read_clone(global: &GlobalScope, data: *mut u64, nbytes: size_t, rval: MutableHandleValue) {
|
||||
let cx = global.get_cx();
|
||||
let globalhandle = global.reflector().get_jsobject();
|
||||
let _ac = JSAutoCompartment::new(cx, globalhandle.get());
|
||||
let mut sc_holder = StructuredCloneHolder { blob: None };
|
||||
let sc_holder_ptr = &mut sc_holder as *mut _;
|
||||
unsafe {
|
||||
let scbuf = NewJSAutoStructuredCloneBuffer(StructuredCloneScope::DifferentProcess,
|
||||
&STRUCTURED_CLONE_CALLBACKS);
|
||||
let scbuf = NewJSAutoStructuredCloneBuffer(
|
||||
StructuredCloneScope::DifferentProcess,
|
||||
&STRUCTURED_CLONE_CALLBACKS,
|
||||
);
|
||||
let scdata = &mut ((*scbuf).data_);
|
||||
|
||||
WriteBytesToJSStructuredCloneData(data as *const u8, nbytes, scdata);
|
||||
|
||||
assert!(JS_ReadStructuredClone(cx,
|
||||
assert!(JS_ReadStructuredClone(
|
||||
cx,
|
||||
scdata,
|
||||
JS_STRUCTURED_CLONE_VERSION,
|
||||
StructuredCloneScope::DifferentProcess,
|
||||
rval,
|
||||
&STRUCTURED_CLONE_CALLBACKS,
|
||||
sc_holder_ptr as *mut raw::c_void));
|
||||
sc_holder_ptr as *mut raw::c_void
|
||||
));
|
||||
|
||||
DeleteJSAutoStructuredCloneBuffer(scbuf);
|
||||
}
|
||||
|
@ -299,8 +332,10 @@ impl StructuredCloneData {
|
|||
let nbytes = vec_msg.len();
|
||||
let data = vec_msg.as_mut_ptr() as *mut u64;
|
||||
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);
|
||||
CallValueTracer(tracer,
|
||||
CallValueTracer(
|
||||
tracer,
|
||||
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>) {
|
||||
unsafe {
|
||||
trace!("tracing {}", description);
|
||||
CallObjectTracer(tracer,
|
||||
CallObjectTracer(
|
||||
tracer,
|
||||
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>
|
||||
where K: Hash + Eq + JSTraceable,
|
||||
where
|
||||
K: Hash + Eq + JSTraceable,
|
||||
V: JSTraceable,
|
||||
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>
|
||||
where T: Hash + Eq + JSTraceable,
|
||||
where
|
||||
T: Hash + Eq + JSTraceable,
|
||||
S: BuildHasher,
|
||||
{
|
||||
#[inline]
|
||||
|
@ -365,7 +371,12 @@ unsafe_no_jsmanaged_fields!(PropertyDeclarationBlock);
|
|||
// These three are interdependent, if you plan to put jsmanaged data
|
||||
// in one of these make sure it is propagated properly to containing structs
|
||||
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!(TimelineMarkerType);
|
||||
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]
|
||||
unsafe fn trace(&self, _: *mut JSTracer) {
|
||||
// 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]
|
||||
unsafe fn trace(&self, _: *mut JSTracer) {
|
||||
// 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]
|
||||
unsafe fn trace(&self, _: *mut JSTracer) {
|
||||
// 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]
|
||||
unsafe fn trace(&self, _: *mut JSTracer) {
|
||||
// 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) {
|
||||
self.underlying_object().trace(trc);
|
||||
}
|
||||
|
@ -682,31 +708,23 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/// Holds a set of JSTraceables that need to be rooted
|
||||
struct RootedTraceableSet {
|
||||
set: Vec<*const JSTraceable>,
|
||||
}
|
||||
|
||||
thread_local!(
|
||||
/// TLV Holds a set of JSTraceables that need to be rooted
|
||||
static ROOTED_TRACEABLES: RefCell<RootedTraceableSet> =
|
||||
RefCell::new(RootedTraceableSet::new());
|
||||
);
|
||||
thread_local!(/// TLV Holds a set of JSTraceables that need to be rooted
|
||||
static ROOTED_TRACEABLES: RefCell<RootedTraceableSet> = RefCell::new(RootedTraceableSet::new()););
|
||||
|
||||
impl RootedTraceableSet {
|
||||
fn new() -> RootedTraceableSet {
|
||||
RootedTraceableSet {
|
||||
set: vec![],
|
||||
}
|
||||
RootedTraceableSet { set: vec![] }
|
||||
}
|
||||
|
||||
unsafe fn remove(traceable: *const JSTraceable) {
|
||||
ROOTED_TRACEABLES.with(|ref traceables| {
|
||||
let mut traceables = traceables.borrow_mut();
|
||||
let idx =
|
||||
match traceables.set.iter()
|
||||
.rposition(|x| *x == traceable) {
|
||||
let idx = match traceables.set.iter().rposition(|x| *x == traceable) {
|
||||
Some(idx) => idx,
|
||||
None => unreachable!(),
|
||||
};
|
||||
|
@ -744,9 +762,7 @@ impl<'a, T: JSTraceable + 'static> RootedTraceable<'a, T> {
|
|||
unsafe {
|
||||
RootedTraceableSet::add(traceable);
|
||||
}
|
||||
RootedTraceable {
|
||||
ptr: traceable,
|
||||
}
|
||||
RootedTraceable { ptr: traceable }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -787,9 +803,7 @@ impl<T: JSTraceable + 'static> RootedTraceableBox<T> {
|
|||
unsafe {
|
||||
RootedTraceableSet::add(traceable);
|
||||
}
|
||||
RootedTraceableBox {
|
||||
ptr: traceable,
|
||||
}
|
||||
RootedTraceableBox { ptr: traceable }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -812,17 +826,13 @@ impl<T: JSTraceable + Default> Default for RootedTraceableBox<T> {
|
|||
impl<T: JSTraceable> Deref for RootedTraceableBox<T> {
|
||||
type Target = T;
|
||||
fn deref(&self) -> &T {
|
||||
unsafe {
|
||||
&*self.ptr
|
||||
}
|
||||
unsafe { &*self.ptr }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: JSTraceable> DerefMut for RootedTraceableBox<T> {
|
||||
fn deref_mut(&mut self) -> &mut T {
|
||||
unsafe {
|
||||
&mut *self.ptr
|
||||
}
|
||||
unsafe { &mut *self.ptr }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -849,9 +859,7 @@ pub struct RootableVec<T: JSTraceable> {
|
|||
impl<T: JSTraceable> RootableVec<T> {
|
||||
/// Create a vector of items of type T that can be rooted later.
|
||||
pub fn new_unrooted() -> RootableVec<T> {
|
||||
RootableVec {
|
||||
v: vec![],
|
||||
}
|
||||
RootableVec { v: vec![] }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -868,9 +876,7 @@ impl<'a, T: 'static + JSTraceable> RootedVec<'a, T> {
|
|||
unsafe {
|
||||
RootedTraceableSet::add(root);
|
||||
}
|
||||
RootedVec {
|
||||
root: root,
|
||||
}
|
||||
RootedVec { 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
|
||||
/// the lifetime of this struct
|
||||
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 {
|
||||
RootedTraceableSet::add(root);
|
||||
}
|
||||
root.v.extend(iter.map(|item| Dom::from_ref(&*item)));
|
||||
RootedVec {
|
||||
root: root,
|
||||
}
|
||||
RootedVec { root: root }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -85,7 +85,6 @@ pub const DOM_PROTOTYPE_SLOT: u32 = js::JSCLASS_GLOBAL_SLOT_COUNT;
|
|||
// changes.
|
||||
pub const JSCLASS_DOM_GLOBAL: u32 = js::JSCLASS_USERBIT1;
|
||||
|
||||
|
||||
/// The struct that holds inheritance information for DOM object reflectors.
|
||||
#[derive(Clone, Copy)]
|
||||
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.
|
||||
///
|
||||
/// 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,
|
||||
receiver: HandleValue,
|
||||
id: HandleId,
|
||||
found: *mut bool,
|
||||
vp: MutableHandleValue)
|
||||
-> bool {
|
||||
vp: MutableHandleValue,
|
||||
) -> bool {
|
||||
rooted!(in(cx) let mut proto = ptr::null_mut::<JSObject>());
|
||||
if !JS_GetPrototype(cx, proxy, proto.handle_mut()) || proto.is_null() {
|
||||
*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 }
|
||||
} else {
|
||||
IdToInt32(cx, id);
|
||||
}*/
|
||||
}
|
||||
}*/}
|
||||
|
||||
/// Find the enum equivelent of a string given by `v` in `pairs`.
|
||||
/// Returns `Err(())` on JSAPI failure (there is a pending exception), and
|
||||
/// `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,
|
||||
pairs: &'a [(&'static str, T)])
|
||||
-> Result<(Option<&'a T>, DOMString), ()> {
|
||||
pairs: &'a [(&'static str, T)],
|
||||
) -> Result<(Option<&'a T>, DOMString), ()> {
|
||||
let jsstr = ToString(cx, v);
|
||||
if jsstr.is_null() {
|
||||
return Err(());
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -228,23 +234,26 @@ pub fn is_platform_object(obj: *mut JSObject) -> bool {
|
|||
/// Get the property with name `property` from `object`.
|
||||
/// Returns `Err(())` on JSAPI failure (there is a pending exception), and
|
||||
/// `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,
|
||||
property: &str,
|
||||
rval: MutableHandleValue)
|
||||
-> Result<bool, ()> {
|
||||
fn has_property(cx: *mut JSContext,
|
||||
rval: MutableHandleValue,
|
||||
) -> Result<bool, ()> {
|
||||
fn has_property(
|
||||
cx: *mut JSContext,
|
||||
object: HandleObject,
|
||||
property: &CString,
|
||||
found: &mut bool)
|
||||
-> bool {
|
||||
found: &mut bool,
|
||||
) -> bool {
|
||||
unsafe { JS_HasProperty(cx, object, property.as_ptr(), found) }
|
||||
}
|
||||
fn get_property(cx: *mut JSContext,
|
||||
fn get_property(
|
||||
cx: *mut JSContext,
|
||||
object: HandleObject,
|
||||
property: &CString,
|
||||
value: MutableHandleValue)
|
||||
-> bool {
|
||||
value: MutableHandleValue,
|
||||
) -> bool {
|
||||
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`.
|
||||
/// Returns `Err(())` on JSAPI failure, or null object,
|
||||
/// and Ok(()) otherwise
|
||||
pub fn set_dictionary_property(cx: *mut JSContext,
|
||||
pub fn set_dictionary_property(
|
||||
cx: *mut JSContext,
|
||||
object: HandleObject,
|
||||
property: &str,
|
||||
value: HandleValue)
|
||||
-> Result<(), ()> {
|
||||
value: HandleValue,
|
||||
) -> Result<(), ()> {
|
||||
if object.get().is_null() {
|
||||
return Err(());
|
||||
}
|
||||
|
@ -292,11 +302,12 @@ pub fn set_dictionary_property(cx: *mut JSContext,
|
|||
}
|
||||
|
||||
/// 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,
|
||||
id: HandleId,
|
||||
found: &mut bool)
|
||||
-> bool {
|
||||
found: &mut bool,
|
||||
) -> bool {
|
||||
rooted!(in(cx) let mut proto = ptr::null_mut::<JSObject>());
|
||||
if !JS_GetPrototype(cx, proxy, proto.handle_mut()) {
|
||||
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);
|
||||
for proto in (*array).iter() {
|
||||
if !proto.is_null() {
|
||||
trace_object(tracer,
|
||||
trace_object(
|
||||
tracer,
|
||||
"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,
|
||||
obj: RawHandleObject,
|
||||
id: RawHandleId,
|
||||
rval: *mut bool)
|
||||
-> bool {
|
||||
rval: *mut bool,
|
||||
) -> bool {
|
||||
assert!(JS_IsGlobalObject(obj.get()));
|
||||
if !JS_ResolveStandardClass(cx, obj, id, rval) {
|
||||
return false;
|
||||
|
@ -379,20 +392,23 @@ pub unsafe extern "C" fn resolve_global(
|
|||
true
|
||||
}
|
||||
|
||||
unsafe extern "C" fn wrap(cx: *mut JSContext,
|
||||
unsafe extern "C" fn wrap(
|
||||
cx: *mut JSContext,
|
||||
_existing: RawHandleObject,
|
||||
obj: RawHandleObject)
|
||||
-> *mut JSObject {
|
||||
obj: RawHandleObject,
|
||||
) -> *mut JSObject {
|
||||
// FIXME terrible idea. need security wrappers
|
||||
// https://github.com/servo/servo/issues/2382
|
||||
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,
|
||||
obj: RawHandleObject,
|
||||
_object_passed_to_wrap: RawHandleObject,
|
||||
rval: RawMutableHandleObject) {
|
||||
rval: RawMutableHandleObject,
|
||||
) {
|
||||
let _ac = JSAutoCompartment::new(cx, obj.get());
|
||||
let obj = ToWindowProxyIfWindow(obj.get());
|
||||
assert!(!obj.is_null());
|
||||
|
@ -406,23 +422,29 @@ pub static WRAP_CALLBACKS: JSWrapObjectCallbacks = JSWrapObjectCallbacks {
|
|||
};
|
||||
|
||||
/// 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,
|
||||
id: HandleId,
|
||||
bp: *mut ObjectOpResult)
|
||||
-> bool {
|
||||
bp: *mut ObjectOpResult,
|
||||
) -> bool {
|
||||
JS_DeletePropertyById(cx, object, id, bp)
|
||||
}
|
||||
|
||||
unsafe fn generic_call(cx: *mut JSContext,
|
||||
unsafe fn generic_call(
|
||||
cx: *mut JSContext,
|
||||
argc: libc::c_uint,
|
||||
vp: *mut JSVal,
|
||||
is_lenient: bool,
|
||||
call: unsafe extern fn(*const JSJitInfo, *mut JSContext,
|
||||
RawHandleObject, *mut libc::c_void, u32,
|
||||
*mut JSVal)
|
||||
-> bool)
|
||||
-> bool {
|
||||
call: unsafe extern "C" fn(
|
||||
*const JSJitInfo,
|
||||
*mut JSContext,
|
||||
RawHandleObject,
|
||||
*mut libc::c_void,
|
||||
u32,
|
||||
*mut JSVal,
|
||||
) -> bool,
|
||||
) -> bool {
|
||||
let args = CallArgs::from_vp(vp, argc);
|
||||
|
||||
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);
|
||||
let depth = (*info).depth;
|
||||
let proto_check = |class: &'static DOMClass| {
|
||||
class.interface_chain[depth as usize] as u16 == proto_id
|
||||
};
|
||||
let proto_check =
|
||||
|class: &'static DOMClass| class.interface_chain[depth as usize] as u16 == proto_id;
|
||||
let this = match private_from_proto_check(obj.get(), proto_check) {
|
||||
Ok(val) => val,
|
||||
Err(()) => {
|
||||
|
@ -455,42 +476,53 @@ unsafe fn generic_call(cx: *mut JSContext,
|
|||
throw_invalid_this(cx, proto_id);
|
||||
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.
|
||||
pub unsafe extern "C" fn generic_method(cx: *mut JSContext,
|
||||
pub unsafe extern "C" fn generic_method(
|
||||
cx: *mut JSContext,
|
||||
argc: libc::c_uint,
|
||||
vp: *mut JSVal)
|
||||
-> bool {
|
||||
vp: *mut JSVal,
|
||||
) -> bool {
|
||||
generic_call(cx, argc, vp, false, CallJitMethodOp)
|
||||
}
|
||||
|
||||
/// 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,
|
||||
vp: *mut JSVal)
|
||||
-> bool {
|
||||
vp: *mut JSVal,
|
||||
) -> bool {
|
||||
generic_call(cx, argc, vp, false, CallJitGetterOp)
|
||||
}
|
||||
|
||||
/// 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,
|
||||
vp: *mut JSVal)
|
||||
-> bool {
|
||||
vp: *mut JSVal,
|
||||
) -> bool {
|
||||
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,
|
||||
handle: RawHandleObject,
|
||||
this: *mut libc::c_void,
|
||||
argc: u32,
|
||||
vp: *mut JSVal)
|
||||
-> bool {
|
||||
vp: *mut JSVal,
|
||||
) -> bool {
|
||||
if !CallJitSetterOp(info, cx, handle, this, argc, vp) {
|
||||
return false;
|
||||
}
|
||||
|
@ -499,25 +531,28 @@ unsafe extern "C" fn call_setter(info: *const JSJitInfo,
|
|||
}
|
||||
|
||||
/// 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,
|
||||
vp: *mut JSVal)
|
||||
-> bool {
|
||||
vp: *mut JSVal,
|
||||
) -> bool {
|
||||
generic_call(cx, argc, vp, false, call_setter)
|
||||
}
|
||||
|
||||
/// 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,
|
||||
vp: *mut JSVal)
|
||||
-> bool {
|
||||
vp: *mut JSVal,
|
||||
) -> bool {
|
||||
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,
|
||||
depth: u32)
|
||||
-> bool {
|
||||
depth: u32,
|
||||
) -> bool {
|
||||
let domclass: *const DOMJSClass = clasp as *const _;
|
||||
let domclass = &*domclass;
|
||||
domclass.dom_class.interface_chain[depth as usize] as u32 == proto_id
|
||||
|
|
|
@ -70,9 +70,11 @@ pub trait WeakReferenceable: DomObject + Sized {
|
|||
let box_ = &*ptr;
|
||||
assert!(box_.value.get().is_some());
|
||||
let new_count = box_.count.get() + 1;
|
||||
trace!("Incrementing WeakBox refcount for {:p} to {}.",
|
||||
trace!(
|
||||
"Incrementing WeakBox refcount for {:p} to {}.",
|
||||
self,
|
||||
new_count);
|
||||
new_count
|
||||
);
|
||||
box_.count.set(new_count);
|
||||
WeakRef {
|
||||
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.
|
||||
pub fn root(&self) -> Option<DomRoot<T>> {
|
||||
unsafe { &*self.ptr.as_ptr() }.value.get().map(|ptr| unsafe {
|
||||
DomRoot::from_ref(&*ptr.as_ptr())
|
||||
})
|
||||
unsafe { &*self.ptr.as_ptr() }
|
||||
.value
|
||||
.get()
|
||||
.map(|ptr| unsafe { DomRoot::from_ref(&*ptr.as_ptr()) })
|
||||
}
|
||||
|
||||
/// 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 new_count = box_.count.get() + 1;
|
||||
box_.count.set(new_count);
|
||||
WeakRef {
|
||||
ptr: self.ptr,
|
||||
}
|
||||
WeakRef { ptr: self.ptr }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -190,7 +191,9 @@ impl<T: WeakReferenceable> MutableWeakRef<T> {
|
|||
/// DomRoot a mutable weak reference. Returns `None` if the object
|
||||
/// was already collected.
|
||||
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;
|
||||
while i < self.vec.len() {
|
||||
if self.vec[i].is_alive() {
|
||||
f(WeakRefEntry { vec: self, index: &mut i });
|
||||
f(WeakRefEntry {
|
||||
vec: self,
|
||||
index: &mut i,
|
||||
});
|
||||
} else {
|
||||
self.vec.swap_remove(i);
|
||||
}
|
||||
|
@ -293,13 +299,13 @@ impl<'a, T: WeakReferenceable + 'a> Drop for WeakRefEntry<'a, T> {
|
|||
|
||||
#[derive(MallocSizeOf)]
|
||||
pub struct DOMTracker<T: WeakReferenceable> {
|
||||
dom_objects: DomRefCell<WeakRefVec<T>>
|
||||
dom_objects: DomRefCell<WeakRefVec<T>>,
|
||||
}
|
||||
|
||||
impl<T: WeakReferenceable> DOMTracker<T> {
|
||||
pub fn new() -> 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.
|
||||
/// See https://dom.spec.whatwg.org/#validate-and-extract for details.
|
||||
pub fn validate_and_extract(namespace: Option<DOMString>,
|
||||
qualified_name: &str)
|
||||
-> Fallible<(Namespace, Option<Prefix>, LocalName)> {
|
||||
pub fn validate_and_extract(
|
||||
namespace: Option<DOMString>,
|
||||
qualified_name: &str,
|
||||
) -> Fallible<(Namespace, Option<Prefix>, LocalName)> {
|
||||
// Step 1.
|
||||
let namespace = namespace_from_domstring(namespace);
|
||||
|
||||
|
@ -76,7 +77,7 @@ pub fn validate_and_extract(namespace: Option<DOMString>,
|
|||
(ns, p) => {
|
||||
// Step 10.
|
||||
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 {
|
||||
is_valid_start(c) ||
|
||||
match c {
|
||||
'-' |
|
||||
'.' |
|
||||
'0'...'9' |
|
||||
'\u{B7}' |
|
||||
'\u{300}'...'\u{36F}' |
|
||||
'\u{203F}'...'\u{2040}' => true,
|
||||
is_valid_start(c) || match c {
|
||||
'-' | '.' | '0'...'9' | '\u{B7}' | '\u{300}'...'\u{36F}' | '\u{203F}'...'\u{2040}' => {
|
||||
true
|
||||
},
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
@ -140,7 +137,7 @@ pub fn xml_name_type(name: &str) -> XMLName {
|
|||
non_qname_colons = true;
|
||||
}
|
||||
c
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
for c in iter {
|
||||
|
|
|
@ -30,7 +30,6 @@ pub struct FileBlob {
|
|||
size: u64,
|
||||
}
|
||||
|
||||
|
||||
/// Different backends of Blob
|
||||
#[must_root]
|
||||
#[derive(JSTraceable)]
|
||||
|
@ -43,7 +42,7 @@ pub enum BlobImpl {
|
|||
/// relative positions of current slicing range,
|
||||
/// IMPORTANT: The depth of tree is only two, i.e. the parent Blob must be
|
||||
/// either File-based or Memory-based
|
||||
Sliced(Dom<Blob>, RelativePos)
|
||||
Sliced(Dom<Blob>, RelativePos),
|
||||
}
|
||||
|
||||
impl BlobImpl {
|
||||
|
@ -76,9 +75,7 @@ pub struct Blob {
|
|||
|
||||
impl Blob {
|
||||
#[allow(unrooted_must_root)]
|
||||
pub fn new(
|
||||
global: &GlobalScope, blob_impl: BlobImpl, typeString: String)
|
||||
-> DomRoot<Blob> {
|
||||
pub fn new(global: &GlobalScope, blob_impl: BlobImpl, typeString: String) -> DomRoot<Blob> {
|
||||
let boxed_blob = Box::new(Blob::new_inherited(blob_impl, typeString));
|
||||
reflect_dom_object(boxed_blob, global, BlobBinding::Wrap)
|
||||
}
|
||||
|
@ -95,41 +92,49 @@ impl Blob {
|
|||
}
|
||||
|
||||
#[allow(unrooted_must_root)]
|
||||
fn new_sliced(parent: &Blob, rel_pos: RelativePos,
|
||||
relative_content_type: DOMString) -> DomRoot<Blob> {
|
||||
fn new_sliced(
|
||||
parent: &Blob,
|
||||
rel_pos: RelativePos,
|
||||
relative_content_type: DOMString,
|
||||
) -> DomRoot<Blob> {
|
||||
let blob_impl = match *parent.blob_impl.borrow() {
|
||||
BlobImpl::File(_) => {
|
||||
// Create new parent node
|
||||
BlobImpl::Sliced(Dom::from_ref(parent), rel_pos)
|
||||
}
|
||||
},
|
||||
BlobImpl::Memory(_) => {
|
||||
// Create new parent node
|
||||
BlobImpl::Sliced(Dom::from_ref(parent), rel_pos)
|
||||
}
|
||||
},
|
||||
BlobImpl::Sliced(ref grandparent, ref old_rel_pos) => {
|
||||
// Adjust the slicing position, using same parent
|
||||
BlobImpl::Sliced(grandparent.clone(), old_rel_pos.slice_inner(&rel_pos))
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
Blob::new(&parent.global(), blob_impl, relative_content_type.into())
|
||||
}
|
||||
|
||||
// https://w3c.github.io/FileAPI/#constructorBlob
|
||||
pub fn Constructor(global: &GlobalScope,
|
||||
pub fn Constructor(
|
||||
global: &GlobalScope,
|
||||
blobParts: Option<Vec<ArrayBufferOrArrayBufferViewOrBlobOrString>>,
|
||||
blobPropertyBag: &BlobBinding::BlobPropertyBag)
|
||||
-> Fallible<DomRoot<Blob>> {
|
||||
blobPropertyBag: &BlobBinding::BlobPropertyBag,
|
||||
) -> Fallible<DomRoot<Blob>> {
|
||||
// TODO: accept other blobParts types - ArrayBuffer or ArrayBufferView
|
||||
let bytes: Vec<u8> = match blobParts {
|
||||
None => Vec::new(),
|
||||
Some(blobparts) => match blob_parts_to_bytes(blobparts) {
|
||||
Ok(bytes) => bytes,
|
||||
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
|
||||
|
@ -141,7 +146,7 @@ impl Blob {
|
|||
None => {
|
||||
let bytes = read_file(&self.global(), f.id.clone())?;
|
||||
(bytes, true)
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// Cache
|
||||
|
@ -150,14 +155,12 @@ impl Blob {
|
|||
}
|
||||
|
||||
Ok(buffer)
|
||||
}
|
||||
},
|
||||
BlobImpl::Memory(ref s) => Ok(s.clone()),
|
||||
BlobImpl::Sliced(ref parent, ref rel_pos) => {
|
||||
parent.get_bytes().map(|v| {
|
||||
BlobImpl::Sliced(ref parent, ref rel_pos) => parent.get_bytes().map(|v| {
|
||||
let range = rel_pos.to_abs_range(v.len());
|
||||
v.index(range).to_vec()
|
||||
})
|
||||
}
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -171,13 +174,19 @@ impl Blob {
|
|||
pub fn get_blob_url_id(&self) -> Uuid {
|
||||
let opt_sliced_parent = match *self.blob_impl.borrow() {
|
||||
BlobImpl::Sliced(ref parent, ref rel_pos) => {
|
||||
Some((parent.promote(/* set_valid is */ false), rel_pos.clone(), parent.Size()))
|
||||
}
|
||||
_ => None
|
||||
Some((
|
||||
parent.promote(/* set_valid is */ false),
|
||||
rel_pos.clone(),
|
||||
parent.Size(),
|
||||
))
|
||||
},
|
||||
_ => None,
|
||||
};
|
||||
|
||||
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),
|
||||
}
|
||||
}
|
||||
|
@ -196,13 +205,15 @@ impl Blob {
|
|||
debug!("Sliced can't have a sliced parent");
|
||||
// Return dummy id
|
||||
return Uuid::new_v4();
|
||||
}
|
||||
},
|
||||
BlobImpl::File(ref f) => {
|
||||
if set_valid {
|
||||
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);
|
||||
|
||||
match rx.recv().unwrap() {
|
||||
|
@ -214,7 +225,7 @@ impl Blob {
|
|||
// no need to activate
|
||||
return f.id.clone();
|
||||
}
|
||||
}
|
||||
},
|
||||
BlobImpl::Memory(ref mut bytes_in) => mem::swap(bytes_in, &mut bytes),
|
||||
};
|
||||
|
||||
|
@ -240,21 +251,28 @@ impl Blob {
|
|||
size: bytes.len() as u64,
|
||||
});
|
||||
id
|
||||
}
|
||||
},
|
||||
// Dummy id
|
||||
Err(_) => Uuid::new_v4(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a FileID representing sliced parent-blob content
|
||||
fn create_sliced_url_id(&self, parent_id: &Uuid,
|
||||
rel_pos: &RelativePos, parent_len: u64) -> Uuid {
|
||||
fn create_sliced_url_id(
|
||||
&self,
|
||||
parent_id: &Uuid,
|
||||
rel_pos: &RelativePos,
|
||||
parent_len: u64,
|
||||
) -> Uuid {
|
||||
let origin = get_blob_origin(&self.global().get_url());
|
||||
|
||||
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(),
|
||||
tx, origin.clone());
|
||||
tx,
|
||||
origin.clone(),
|
||||
);
|
||||
self.send_to_file_manager(msg);
|
||||
match rx.recv().expect("File manager thread is down") {
|
||||
Ok(new_id) => {
|
||||
|
@ -267,11 +285,11 @@ impl Blob {
|
|||
|
||||
// Return the indirect id reference
|
||||
new_id
|
||||
}
|
||||
},
|
||||
Err(_) => {
|
||||
// Return dummy id
|
||||
Uuid::new_v4()
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -315,13 +333,13 @@ fn read_file(global: &GlobalScope, id: Uuid) -> Result<Vec<u8>, ()> {
|
|||
match recv.recv().unwrap() {
|
||||
Ok(ReadFileProgress::Meta(mut blob_buf)) => {
|
||||
bytes.append(&mut blob_buf.bytes);
|
||||
}
|
||||
},
|
||||
Ok(ReadFileProgress::Partial(mut bytes_in)) => {
|
||||
bytes.append(&mut bytes_in);
|
||||
}
|
||||
},
|
||||
Ok(ReadFileProgress::EOF) => {
|
||||
return Ok(bytes);
|
||||
}
|
||||
},
|
||||
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
|
||||
/// <https://w3c.github.io/FileAPI/#constructorBlob>
|
||||
#[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![];
|
||||
for blobpart in &mut blobparts {
|
||||
match blobpart {
|
||||
|
@ -348,7 +368,7 @@ pub fn blob_parts_to_bytes(mut blobparts: Vec<ArrayBufferOrArrayBufferViewOrBlob
|
|||
&mut ArrayBufferOrArrayBufferViewOrBlobOrString::ArrayBufferView(ref mut a) => unsafe {
|
||||
let bytes = a.as_slice();
|
||||
ret.extend(bytes);
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -361,8 +381,9 @@ impl BlobMethods for Blob {
|
|||
match *self.blob_impl.borrow() {
|
||||
BlobImpl::File(ref f) => f.size,
|
||||
BlobImpl::Memory(ref v) => v.len() as u64,
|
||||
BlobImpl::Sliced(ref parent, ref rel_pos) =>
|
||||
rel_pos.to_abs_range(parent.Size() as usize).len() as u64,
|
||||
BlobImpl::Sliced(ref parent, ref rel_pos) => {
|
||||
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
|
||||
fn Slice(&self,
|
||||
fn Slice(
|
||||
&self,
|
||||
start: Option<i64>,
|
||||
end: Option<i64>,
|
||||
content_type: Option<DOMString>)
|
||||
-> DomRoot<Blob> {
|
||||
content_type: Option<DOMString>,
|
||||
) -> DomRoot<Blob> {
|
||||
let rel_pos = RelativePos::from_opts(start, end);
|
||||
Blob::new_sliced(self, rel_pos, content_type.unwrap_or(DOMString::from("")))
|
||||
}
|
||||
|
|
|
@ -42,20 +42,26 @@ use std::str::FromStr;
|
|||
use std::sync::{Arc, Mutex};
|
||||
use task::TaskOnce;
|
||||
|
||||
const KEY_CONVERSION_ERROR: &'static str = "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 KEY_CONVERSION_ERROR: &'static str =
|
||||
"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 MANUFACTURER_DATA_ERROR: &'static str = "'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`.";
|
||||
const MANUFACTURER_DATA_ERROR: &'static str =
|
||||
"'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.
|
||||
const MAX_DEVICE_NAME_LENGTH: usize = 248;
|
||||
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 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 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.";
|
||||
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)]
|
||||
pub struct AllowedBluetoothDevice {
|
||||
|
@ -84,7 +90,10 @@ impl BluetoothExtraPermissionData {
|
|||
}
|
||||
|
||||
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> {
|
||||
reflect_dom_object(Box::new(Bluetooth::new_inherited()),
|
||||
reflect_dom_object(
|
||||
Box::new(Bluetooth::new_inherited()),
|
||||
global,
|
||||
BluetoothBinding::Wrap)
|
||||
BluetoothBinding::Wrap,
|
||||
)
|
||||
}
|
||||
|
||||
fn get_bluetooth_thread(&self) -> IpcSender<BluetoothRequest> {
|
||||
|
@ -146,15 +157,17 @@ impl Bluetooth {
|
|||
}
|
||||
|
||||
// https://webbluetoothcg.github.io/web-bluetooth/#request-bluetooth-devices
|
||||
fn request_bluetooth_devices(&self,
|
||||
fn request_bluetooth_devices(
|
||||
&self,
|
||||
p: &Rc<Promise>,
|
||||
filters: &Option<Vec<BluetoothLEScanFilterInit>>,
|
||||
optional_services: &Option<Vec<BluetoothServiceUUID>>,
|
||||
sender: IpcSender<BluetoothResponseResult>) {
|
||||
sender: IpcSender<BluetoothResponseResult>,
|
||||
) {
|
||||
// TODO: Step 1: Triggered by user activation.
|
||||
|
||||
// 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 {
|
||||
// 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 {
|
||||
for opt_service in opt_services {
|
||||
// Step 2.5 - 2.6.
|
||||
|
@ -201,30 +214,39 @@ impl Bluetooth {
|
|||
}
|
||||
}
|
||||
|
||||
let option = RequestDeviceoptions::new(BluetoothScanfilterSequence::new(uuid_filters),
|
||||
ServiceUUIDSequence::new(optional_services_uuids));
|
||||
let option = RequestDeviceoptions::new(
|
||||
BluetoothScanfilterSequence::new(uuid_filters),
|
||||
ServiceUUIDSequence::new(optional_services_uuids),
|
||||
);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// Note: Step 3, 6 - 8 are implemented in
|
||||
// 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>(
|
||||
promise: &Rc<Promise>,
|
||||
receiver: &T) -> IpcSender<BluetoothResponseResult> {
|
||||
receiver: &T,
|
||||
) -> IpcSender<BluetoothResponseResult> {
|
||||
let (action_sender, action_receiver) = ipc::channel().unwrap();
|
||||
let task_source = receiver.global().networking_task_source();
|
||||
let context = Arc::new(Mutex::new(BluetoothContext {
|
||||
promise: Some(TrustedPromise::new(promise.clone())),
|
||||
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> {
|
||||
context: Arc<Mutex<BluetoothContext<T>>>,
|
||||
action: BluetoothResponseResult,
|
||||
|
@ -249,7 +271,8 @@ pub fn response_async<T: AsyncBluetoothListener + DomObject + 'static>(
|
|||
if let Err(err) = result {
|
||||
warn!("failed to deliver network data: {:?}", err);
|
||||
}
|
||||
}));
|
||||
}),
|
||||
);
|
||||
action_sender
|
||||
}
|
||||
|
||||
|
@ -262,10 +285,12 @@ pub fn get_gatt_children<T, F> (
|
|||
uuid: Option<StringOrUnsignedLong>,
|
||||
instance_id: String,
|
||||
connected: bool,
|
||||
child_type: GATTType)
|
||||
-> Rc<Promise>
|
||||
where T: AsyncBluetoothListener + DomObject + 'static,
|
||||
F: FnOnce(StringOrUnsignedLong) -> Fallible<UUID> {
|
||||
child_type: GATTType,
|
||||
) -> Rc<Promise>
|
||||
where
|
||||
T: AsyncBluetoothListener + DomObject + 'static,
|
||||
F: FnOnce(StringOrUnsignedLong) -> Fallible<UUID>,
|
||||
{
|
||||
let p = Promise::new(&attribute.global());
|
||||
|
||||
let result_uuid = if let Some(u) = uuid {
|
||||
|
@ -275,7 +300,7 @@ pub fn get_gatt_children<T, F> (
|
|||
Err(e) => {
|
||||
p.reject_error(e);
|
||||
return p;
|
||||
}
|
||||
},
|
||||
};
|
||||
// Step 2.
|
||||
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
|
||||
// and in handle_response function.
|
||||
let sender = response_async(&p, attribute);
|
||||
attribute.global().as_window().bluetooth_thread().send(
|
||||
BluetoothRequest::GetGATTChildren(instance_id, result_uuid, single, child_type, sender)).unwrap();
|
||||
attribute
|
||||
.global()
|
||||
.as_window()
|
||||
.bluetooth_thread()
|
||||
.send(BluetoothRequest::GetGATTChildren(
|
||||
instance_id,
|
||||
result_uuid,
|
||||
single,
|
||||
child_type,
|
||||
sender,
|
||||
)).unwrap();
|
||||
return p;
|
||||
}
|
||||
|
||||
|
@ -310,7 +344,8 @@ fn canonicalize_filter(filter: &BluetoothLEScanFilterInit) -> Fallible<Bluetooth
|
|||
filter.name.is_none() &&
|
||||
filter.namePrefix.is_none() &&
|
||||
filter.manufacturerData.is_none() &&
|
||||
filter.serviceData.is_none() {
|
||||
filter.serviceData.is_none()
|
||||
{
|
||||
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()));
|
||||
}
|
||||
|
||||
let mut services_vec = vec!();
|
||||
let mut services_vec = vec![];
|
||||
|
||||
for service in services {
|
||||
// Step 3.2 - 3.3.
|
||||
|
@ -333,7 +368,7 @@ fn canonicalize_filter(filter: &BluetoothLEScanFilterInit) -> Fallible<Bluetooth
|
|||
|
||||
// Step 3.4.
|
||||
if uuid_is_blocklisted(uuid.as_ref(), Blocklist::All) {
|
||||
return Err(Security)
|
||||
return Err(Security);
|
||||
}
|
||||
|
||||
services_vec.push(uuid);
|
||||
|
@ -341,7 +376,7 @@ fn canonicalize_filter(filter: &BluetoothLEScanFilterInit) -> Fallible<Bluetooth
|
|||
// Step 3.5.
|
||||
services_vec
|
||||
},
|
||||
None => vec!(),
|
||||
None => vec![],
|
||||
};
|
||||
|
||||
// Step 4.
|
||||
|
@ -388,13 +423,18 @@ fn canonicalize_filter(filter: &BluetoothLEScanFilterInit) -> Fallible<Bluetooth
|
|||
// Step 7.1 - 7.2.
|
||||
let manufacturer_id = match u16::from_str(key.as_ref()) {
|
||||
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.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)
|
||||
},
|
||||
|
@ -414,7 +454,7 @@ fn canonicalize_filter(filter: &BluetoothLEScanFilterInit) -> Fallible<Bluetooth
|
|||
// Step 9.1.
|
||||
Ok(number) => StringOrUnsignedLong::UnsignedLong(number),
|
||||
// Step 9.2.
|
||||
_ => StringOrUnsignedLong::String(key.clone())
|
||||
_ => StringOrUnsignedLong::String(key.clone()),
|
||||
};
|
||||
|
||||
// Step 9.3 - 9.4.
|
||||
|
@ -436,16 +476,24 @@ fn canonicalize_filter(filter: &BluetoothLEScanFilterInit) -> Fallible<Bluetooth
|
|||
};
|
||||
|
||||
// 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
|
||||
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.
|
||||
let data_prefix = match bdfi.dataPrefix {
|
||||
Some(ArrayBufferViewOrArrayBuffer::ArrayBufferView(ref avb)) => avb.to_vec(),
|
||||
Some(ArrayBufferViewOrArrayBuffer::ArrayBuffer(ref ab)) => ab.to_vec(),
|
||||
None => vec![]
|
||||
None => vec![],
|
||||
};
|
||||
|
||||
// Step 2.
|
||||
|
@ -454,7 +502,7 @@ fn canonicalize_bluetooth_data_filter_init(bdfi: &BluetoothDataFilterInit) -> Fa
|
|||
let mask = match bdfi.mask {
|
||||
Some(ArrayBufferViewOrArrayBuffer::ArrayBufferView(ref avb)) => avb.to_vec(),
|
||||
Some(ArrayBufferViewOrArrayBuffer::ArrayBuffer(ref ab)) => ab.to_vec(),
|
||||
None => vec![0xFF; data_prefix.len()]
|
||||
None => vec![0xFF; data_prefix.len()],
|
||||
};
|
||||
|
||||
// Step 3.
|
||||
|
@ -486,7 +534,8 @@ impl BluetoothMethods for Bluetooth {
|
|||
let p = Promise::new(&self.global());
|
||||
// Step 1.
|
||||
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()));
|
||||
return p;
|
||||
}
|
||||
|
@ -505,13 +554,18 @@ impl BluetoothMethods for Bluetooth {
|
|||
// Step 1. We did not override the method
|
||||
// Step 2 - 3. in handle_response
|
||||
let sender = response_async(&p, self);
|
||||
self.get_bluetooth_thread().send(
|
||||
BluetoothRequest::GetAvailability(sender)).unwrap();
|
||||
self.get_bluetooth_thread()
|
||||
.send(BluetoothRequest::GetAvailability(sender))
|
||||
.unwrap();
|
||||
p
|
||||
}
|
||||
|
||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetooth-onavailabilitychanged
|
||||
event_handler!(availabilitychanged, GetOnavailabilitychanged, SetOnavailabilitychanged);
|
||||
event_handler!(
|
||||
availabilitychanged,
|
||||
GetOnavailabilitychanged,
|
||||
SetOnavailabilitychanged
|
||||
);
|
||||
}
|
||||
|
||||
impl AsyncBluetoothListener for Bluetooth {
|
||||
|
@ -524,18 +578,21 @@ impl AsyncBluetoothListener for Bluetooth {
|
|||
if let Some(existing_device) = device_instance_map.get(&device.id.clone()) {
|
||||
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()),
|
||||
device.name.map(DOMString::from),
|
||||
&self);
|
||||
&self,
|
||||
);
|
||||
device_instance_map.insert(device.id.clone(), Dom::from_ref(&bt_device));
|
||||
|
||||
self.global().as_window().bluetooth_extra_permission_data().add_new_allowed_device(
|
||||
AllowedBluetoothDevice {
|
||||
self.global()
|
||||
.as_window()
|
||||
.bluetooth_extra_permission_data()
|
||||
.add_new_allowed_device(AllowedBluetoothDevice {
|
||||
deviceId: DOMString::from(device.id),
|
||||
mayUseGATT: true,
|
||||
}
|
||||
);
|
||||
});
|
||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetooth-requestdevice
|
||||
// Step 5.
|
||||
promise.resolve_native(&bt_device);
|
||||
|
@ -544,7 +601,7 @@ impl AsyncBluetoothListener for Bluetooth {
|
|||
// Step 2 - 3.
|
||||
BluetoothResponse::GetAvailability(is_available) => {
|
||||
promise.resolve_native(&is_available);
|
||||
}
|
||||
},
|
||||
_ => promise.reject_error(Error::Type("Something went wrong...".to_owned())),
|
||||
}
|
||||
}
|
||||
|
@ -555,11 +612,14 @@ impl PermissionAlgorithm for Bluetooth {
|
|||
type Status = BluetoothPermissionResult;
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
fn create_descriptor(cx: *mut JSContext,
|
||||
permission_descriptor_obj: *mut JSObject)
|
||||
-> Result<BluetoothPermissionDescriptor, Error> {
|
||||
fn create_descriptor(
|
||||
cx: *mut JSContext,
|
||||
permission_descriptor_obj: *mut JSObject,
|
||||
) -> Result<BluetoothPermissionDescriptor, Error> {
|
||||
rooted!(in(cx) let mut property = UndefinedValue());
|
||||
property.handle_mut().set(ObjectValue(permission_descriptor_obj));
|
||||
property
|
||||
.handle_mut()
|
||||
.set(ObjectValue(permission_descriptor_obj));
|
||||
unsafe {
|
||||
match BluetoothPermissionDescriptor::new(cx, property.handle()) {
|
||||
Ok(ConversionResult::Success(descriptor)) => Ok(descriptor),
|
||||
|
@ -592,7 +652,10 @@ impl PermissionAlgorithm for Bluetooth {
|
|||
|
||||
// Step 5.
|
||||
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 device_map = bluetooth.get_device_map().borrow();
|
||||
|
@ -622,11 +685,15 @@ impl PermissionAlgorithm for Bluetooth {
|
|||
// Step 6.2.2.
|
||||
// Instead of creating an internal slot we send an ipc message to the Bluetooth thread
|
||||
// to check if one of the filters matches.
|
||||
let (sender, receiver) = ProfiledIpc::channel(global.time_profiler_chan().clone()).unwrap();
|
||||
status.get_bluetooth_thread()
|
||||
.send(BluetoothRequest::MatchesFilter(device_id.clone(),
|
||||
let (sender, receiver) =
|
||||
ProfiledIpc::channel(global.time_profiler_chan().clone()).unwrap();
|
||||
status
|
||||
.get_bluetooth_thread()
|
||||
.send(BluetoothRequest::MatchesFilter(
|
||||
device_id.clone(),
|
||||
BluetoothScanfilterSequence::new(scan_filters),
|
||||
sender)).unwrap();
|
||||
sender,
|
||||
)).unwrap();
|
||||
|
||||
match receiver.recv().unwrap() {
|
||||
Ok(true) => (),
|
||||
|
@ -666,17 +733,28 @@ impl PermissionAlgorithm for Bluetooth {
|
|||
// Step 2.
|
||||
let sender = response_async(promise, status);
|
||||
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.
|
||||
}
|
||||
|
||||
#[allow(unrooted_must_root)]
|
||||
// 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.
|
||||
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.
|
||||
let bluetooth = status.get_bluetooth();
|
||||
let device_map = bluetooth.get_device_map().borrow();
|
||||
|
@ -684,7 +762,8 @@ impl PermissionAlgorithm for Bluetooth {
|
|||
let id = DOMString::from(id.clone());
|
||||
// Step 2.1.
|
||||
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,
|
||||
// because we store it in the lower level
|
||||
// where it is already up-to-date
|
||||
|
|
|
@ -29,12 +29,13 @@ pub struct BluetoothAdvertisingEvent {
|
|||
}
|
||||
|
||||
impl BluetoothAdvertisingEvent {
|
||||
pub fn new_inherited(device: &BluetoothDevice,
|
||||
pub fn new_inherited(
|
||||
device: &BluetoothDevice,
|
||||
name: Option<DOMString>,
|
||||
appearance: Option<u16>,
|
||||
tx_power: Option<i8>,
|
||||
rssi: Option<i8>)
|
||||
-> BluetoothAdvertisingEvent {
|
||||
rssi: Option<i8>,
|
||||
) -> BluetoothAdvertisingEvent {
|
||||
BluetoothAdvertisingEvent {
|
||||
event: Event::new_inherited(),
|
||||
device: Dom::from_ref(device),
|
||||
|
@ -45,7 +46,8 @@ impl BluetoothAdvertisingEvent {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn new(global: &GlobalScope,
|
||||
pub fn new(
|
||||
global: &GlobalScope,
|
||||
type_: Atom,
|
||||
bubbles: EventBubbles,
|
||||
cancelable: EventCancelable,
|
||||
|
@ -53,18 +55,14 @@ impl BluetoothAdvertisingEvent {
|
|||
name: Option<DOMString>,
|
||||
appearance: Option<u16>,
|
||||
txPower: Option<i8>,
|
||||
rssi: Option<i8>)
|
||||
-> DomRoot<BluetoothAdvertisingEvent> {
|
||||
rssi: Option<i8>,
|
||||
) -> DomRoot<BluetoothAdvertisingEvent> {
|
||||
let ev = reflect_dom_object(
|
||||
Box::new(BluetoothAdvertisingEvent::new_inherited(
|
||||
device,
|
||||
name,
|
||||
appearance,
|
||||
txPower,
|
||||
rssi
|
||||
device, name, appearance, txPower, rssi,
|
||||
)),
|
||||
global,
|
||||
BluetoothAdvertisingEventBinding::Wrap
|
||||
BluetoothAdvertisingEventBinding::Wrap,
|
||||
);
|
||||
{
|
||||
let event = ev.upcast::<Event>();
|
||||
|
@ -74,10 +72,11 @@ impl BluetoothAdvertisingEvent {
|
|||
}
|
||||
|
||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothadvertisingevent-bluetoothadvertisingevent
|
||||
pub fn Constructor(window: &Window,
|
||||
pub fn Constructor(
|
||||
window: &Window,
|
||||
type_: DOMString,
|
||||
init: &BluetoothAdvertisingEventInit)
|
||||
-> Fallible<DomRoot<BluetoothAdvertisingEvent>> {
|
||||
init: &BluetoothAdvertisingEventInit,
|
||||
) -> Fallible<DomRoot<BluetoothAdvertisingEvent>> {
|
||||
let global = window.upcast::<GlobalScope>();
|
||||
let device = init.device.r();
|
||||
let name = init.name.clone();
|
||||
|
@ -86,7 +85,8 @@ impl BluetoothAdvertisingEvent {
|
|||
let rssi = init.rssi.clone();
|
||||
let bubbles = EventBubbles::from(init.parent.bubbles);
|
||||
let cancelable = EventCancelable::from(init.parent.cancelable);
|
||||
Ok(BluetoothAdvertisingEvent::new(global,
|
||||
Ok(BluetoothAdvertisingEvent::new(
|
||||
global,
|
||||
Atom::from(type_),
|
||||
bubbles,
|
||||
cancelable,
|
||||
|
@ -94,7 +94,8 @@ impl BluetoothAdvertisingEvent {
|
|||
name,
|
||||
appearance,
|
||||
txPower,
|
||||
rssi))
|
||||
rssi,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,8 @@ pub struct BluetoothCharacteristicProperties {
|
|||
}
|
||||
|
||||
impl BluetoothCharacteristicProperties {
|
||||
pub fn new_inherited(broadcast: bool,
|
||||
pub fn new_inherited(
|
||||
broadcast: bool,
|
||||
read: bool,
|
||||
write_without_response: bool,
|
||||
write: bool,
|
||||
|
@ -34,8 +35,8 @@ impl BluetoothCharacteristicProperties {
|
|||
indicate: bool,
|
||||
authenticated_signed_writes: bool,
|
||||
reliable_write: bool,
|
||||
writable_auxiliaries: bool)
|
||||
-> BluetoothCharacteristicProperties {
|
||||
writable_auxiliaries: bool,
|
||||
) -> BluetoothCharacteristicProperties {
|
||||
BluetoothCharacteristicProperties {
|
||||
reflector_: Reflector::new(),
|
||||
broadcast: broadcast,
|
||||
|
@ -50,7 +51,8 @@ impl BluetoothCharacteristicProperties {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn new(global: &GlobalScope,
|
||||
pub fn new(
|
||||
global: &GlobalScope,
|
||||
broadcast: bool,
|
||||
read: bool,
|
||||
writeWithoutResponse: bool,
|
||||
|
@ -59,8 +61,8 @@ impl BluetoothCharacteristicProperties {
|
|||
indicate: bool,
|
||||
authenticatedSignedWrites: bool,
|
||||
reliableWrite: bool,
|
||||
writableAuxiliaries: bool)
|
||||
-> DomRoot<BluetoothCharacteristicProperties> {
|
||||
writableAuxiliaries: bool,
|
||||
) -> DomRoot<BluetoothCharacteristicProperties> {
|
||||
reflect_dom_object(
|
||||
Box::new(BluetoothCharacteristicProperties::new_inherited(
|
||||
broadcast,
|
||||
|
@ -71,10 +73,10 @@ impl BluetoothCharacteristicProperties {
|
|||
indicate,
|
||||
authenticatedSignedWrites,
|
||||
reliableWrite,
|
||||
writableAuxiliaries
|
||||
writableAuxiliaries,
|
||||
)),
|
||||
global,
|
||||
BluetoothCharacteristicPropertiesBinding::Wrap
|
||||
BluetoothCharacteristicPropertiesBinding::Wrap,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,79 +38,90 @@ pub struct BluetoothDevice {
|
|||
name: Option<DOMString>,
|
||||
gatt: MutNullableDom<BluetoothRemoteGATTServer>,
|
||||
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<BluetoothRemoteGATTDescriptor>>>),
|
||||
DomRefCell<HashMap<String, Dom<BluetoothRemoteGATTDescriptor>>>,
|
||||
),
|
||||
watching_advertisements: Cell<bool>,
|
||||
}
|
||||
|
||||
impl BluetoothDevice {
|
||||
pub fn new_inherited(id: DOMString,
|
||||
pub fn new_inherited(
|
||||
id: DOMString,
|
||||
name: Option<DOMString>,
|
||||
context: &Bluetooth)
|
||||
-> BluetoothDevice {
|
||||
context: &Bluetooth,
|
||||
) -> BluetoothDevice {
|
||||
BluetoothDevice {
|
||||
eventtarget: EventTarget::new_inherited(),
|
||||
id: id,
|
||||
name: name,
|
||||
gatt: Default::default(),
|
||||
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()),
|
||||
),
|
||||
watching_advertisements: Cell::new(false),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(global: &GlobalScope,
|
||||
pub fn new(
|
||||
global: &GlobalScope,
|
||||
id: DOMString,
|
||||
name: Option<DOMString>,
|
||||
context: &Bluetooth)
|
||||
-> DomRoot<BluetoothDevice> {
|
||||
reflect_dom_object(Box::new(BluetoothDevice::new_inherited(id, name, context)),
|
||||
context: &Bluetooth,
|
||||
) -> DomRoot<BluetoothDevice> {
|
||||
reflect_dom_object(
|
||||
Box::new(BluetoothDevice::new_inherited(id, name, context)),
|
||||
global,
|
||||
BluetoothDeviceBinding::Wrap)
|
||||
BluetoothDeviceBinding::Wrap,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn get_gatt(&self) -> DomRoot<BluetoothRemoteGATTServer> {
|
||||
self.gatt.or_init(|| {
|
||||
BluetoothRemoteGATTServer::new(&self.global(), self)
|
||||
})
|
||||
self.gatt
|
||||
.or_init(|| BluetoothRemoteGATTServer::new(&self.global(), self))
|
||||
}
|
||||
|
||||
fn get_context(&self) -> DomRoot<Bluetooth> {
|
||||
DomRoot::from_ref(&self.context)
|
||||
}
|
||||
|
||||
pub fn get_or_create_service(&self,
|
||||
pub fn get_or_create_service(
|
||||
&self,
|
||||
service: &BluetoothServiceMsg,
|
||||
server: &BluetoothRemoteGATTServer)
|
||||
-> DomRoot<BluetoothRemoteGATTService> {
|
||||
server: &BluetoothRemoteGATTServer,
|
||||
) -> DomRoot<BluetoothRemoteGATTService> {
|
||||
let (ref service_map_ref, _, _) = self.attribute_instance_map;
|
||||
let mut service_map = service_map_ref.borrow_mut();
|
||||
if let Some(existing_service) = service_map.get(&service.instance_id) {
|
||||
return DomRoot::from_ref(&existing_service);
|
||||
}
|
||||
let bt_service = BluetoothRemoteGATTService::new(&server.global(),
|
||||
let bt_service = BluetoothRemoteGATTService::new(
|
||||
&server.global(),
|
||||
&server.Device(),
|
||||
DOMString::from(service.uuid.clone()),
|
||||
service.is_primary,
|
||||
service.instance_id.clone());
|
||||
service.instance_id.clone(),
|
||||
);
|
||||
service_map.insert(service.instance_id.clone(), Dom::from_ref(&bt_service));
|
||||
return bt_service;
|
||||
}
|
||||
|
||||
pub fn get_or_create_characteristic(&self,
|
||||
pub fn get_or_create_characteristic(
|
||||
&self,
|
||||
characteristic: &BluetoothCharacteristicMsg,
|
||||
service: &BluetoothRemoteGATTService)
|
||||
-> DomRoot<BluetoothRemoteGATTCharacteristic> {
|
||||
service: &BluetoothRemoteGATTService,
|
||||
) -> DomRoot<BluetoothRemoteGATTCharacteristic> {
|
||||
let (_, ref characteristic_map_ref, _) = self.attribute_instance_map;
|
||||
let mut characteristic_map = characteristic_map_ref.borrow_mut();
|
||||
if let Some(existing_characteristic) = characteristic_map.get(&characteristic.instance_id) {
|
||||
return DomRoot::from_ref(&existing_characteristic);
|
||||
}
|
||||
let properties =
|
||||
BluetoothCharacteristicProperties::new(&service.global(),
|
||||
let properties = BluetoothCharacteristicProperties::new(
|
||||
&service.global(),
|
||||
characteristic.broadcast,
|
||||
characteristic.read,
|
||||
characteristic.write_without_response,
|
||||
|
@ -119,37 +130,52 @@ impl BluetoothDevice {
|
|||
characteristic.indicate,
|
||||
characteristic.authenticated_signed_writes,
|
||||
characteristic.reliable_write,
|
||||
characteristic.writable_auxiliaries);
|
||||
let bt_characteristic = BluetoothRemoteGATTCharacteristic::new(&service.global(),
|
||||
characteristic.writable_auxiliaries,
|
||||
);
|
||||
let bt_characteristic = BluetoothRemoteGATTCharacteristic::new(
|
||||
&service.global(),
|
||||
service,
|
||||
DOMString::from(characteristic.uuid.clone()),
|
||||
&properties,
|
||||
characteristic.instance_id.clone());
|
||||
characteristic_map.insert(characteristic.instance_id.clone(), Dom::from_ref(&bt_characteristic));
|
||||
characteristic.instance_id.clone(),
|
||||
);
|
||||
characteristic_map.insert(
|
||||
characteristic.instance_id.clone(),
|
||||
Dom::from_ref(&bt_characteristic),
|
||||
);
|
||||
return bt_characteristic;
|
||||
}
|
||||
|
||||
pub fn is_represented_device_null(&self) -> bool {
|
||||
let (sender, receiver) = ipc::channel(self.global().time_profiler_chan().clone()).unwrap();
|
||||
self.get_bluetooth_thread().send(
|
||||
BluetoothRequest::IsRepresentedDeviceNull(self.Id().to_string(), sender)).unwrap();
|
||||
self.get_bluetooth_thread()
|
||||
.send(BluetoothRequest::IsRepresentedDeviceNull(
|
||||
self.Id().to_string(),
|
||||
sender,
|
||||
)).unwrap();
|
||||
receiver.recv().unwrap()
|
||||
}
|
||||
|
||||
pub fn get_or_create_descriptor(&self,
|
||||
pub fn get_or_create_descriptor(
|
||||
&self,
|
||||
descriptor: &BluetoothDescriptorMsg,
|
||||
characteristic: &BluetoothRemoteGATTCharacteristic)
|
||||
-> DomRoot<BluetoothRemoteGATTDescriptor> {
|
||||
characteristic: &BluetoothRemoteGATTCharacteristic,
|
||||
) -> DomRoot<BluetoothRemoteGATTDescriptor> {
|
||||
let (_, _, ref descriptor_map_ref) = self.attribute_instance_map;
|
||||
let mut descriptor_map = descriptor_map_ref.borrow_mut();
|
||||
if let Some(existing_descriptor) = descriptor_map.get(&descriptor.instance_id) {
|
||||
return DomRoot::from_ref(&existing_descriptor);
|
||||
}
|
||||
let bt_descriptor = BluetoothRemoteGATTDescriptor::new(&characteristic.global(),
|
||||
let bt_descriptor = BluetoothRemoteGATTDescriptor::new(
|
||||
&characteristic.global(),
|
||||
characteristic,
|
||||
DOMString::from(descriptor.uuid.clone()),
|
||||
descriptor.instance_id.clone());
|
||||
descriptor_map.insert(descriptor.instance_id.clone(), Dom::from_ref(&bt_descriptor));
|
||||
descriptor.instance_id.clone(),
|
||||
);
|
||||
descriptor_map.insert(
|
||||
descriptor.instance_id.clone(),
|
||||
Dom::from_ref(&bt_descriptor),
|
||||
);
|
||||
return bt_descriptor;
|
||||
}
|
||||
|
||||
|
@ -180,11 +206,17 @@ impl BluetoothDevice {
|
|||
|
||||
// Step 5, 6.4, 7.
|
||||
// TODO: Step 6: Implement `active notification context set` for BluetoothRemoteGATTCharacteristic.
|
||||
let _ = self.get_bluetooth_thread().send(
|
||||
BluetoothRequest::SetRepresentedToNull(service_ids, characteristic_ids, descriptor_ids));
|
||||
let _ = self
|
||||
.get_bluetooth_thread()
|
||||
.send(BluetoothRequest::SetRepresentedToNull(
|
||||
service_ids,
|
||||
characteristic_ids,
|
||||
descriptor_ids,
|
||||
));
|
||||
|
||||
// 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
|
||||
|
@ -206,8 +238,11 @@ impl BluetoothDevice {
|
|||
|
||||
// Step 3.
|
||||
let (sender, receiver) = ipc::channel(self.global().time_profiler_chan().clone()).unwrap();
|
||||
self.get_bluetooth_thread().send(
|
||||
BluetoothRequest::GATTServerDisconnect(String::from(self.Id()), sender)).unwrap();
|
||||
self.get_bluetooth_thread()
|
||||
.send(BluetoothRequest::GATTServerDisconnect(
|
||||
String::from(self.Id()),
|
||||
sender,
|
||||
)).unwrap();
|
||||
receiver.recv().unwrap().map_err(Error::from)
|
||||
}
|
||||
}
|
||||
|
@ -226,9 +261,14 @@ impl BluetoothDeviceMethods for BluetoothDevice {
|
|||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdevice-gatt
|
||||
fn GetGatt(&self) -> Option<DomRoot<BluetoothRemoteGATTServer>> {
|
||||
// Step 1.
|
||||
if self.global().as_window().bluetooth_extra_permission_data()
|
||||
.allowed_devices_contains_id(self.id.clone()) && !self.is_represented_device_null() {
|
||||
return Some(self.get_gatt())
|
||||
if self
|
||||
.global()
|
||||
.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.
|
||||
None
|
||||
|
@ -242,8 +282,11 @@ impl BluetoothDeviceMethods for BluetoothDevice {
|
|||
// TODO: Step 1.
|
||||
// Note: Steps 2 - 3 are implemented in components/bluetooth/lib.rs in watch_advertisements function
|
||||
// and in handle_response function.
|
||||
self.get_bluetooth_thread().send(
|
||||
BluetoothRequest::WatchAdvertisements(String::from(self.Id()), sender)).unwrap();
|
||||
self.get_bluetooth_thread()
|
||||
.send(BluetoothRequest::WatchAdvertisements(
|
||||
String::from(self.Id()),
|
||||
sender,
|
||||
)).unwrap();
|
||||
return p;
|
||||
}
|
||||
|
||||
|
@ -260,7 +303,11 @@ impl BluetoothDeviceMethods for BluetoothDevice {
|
|||
}
|
||||
|
||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdeviceeventhandlers-ongattserverdisconnected
|
||||
event_handler!(gattserverdisconnected, GetOngattserverdisconnected, SetOngattserverdisconnected);
|
||||
event_handler!(
|
||||
gattserverdisconnected,
|
||||
GetOngattserverdisconnected,
|
||||
SetOngattserverdisconnected
|
||||
);
|
||||
}
|
||||
|
||||
impl AsyncBluetoothListener for BluetoothDevice {
|
||||
|
|
|
@ -40,10 +40,15 @@ impl BluetoothPermissionResult {
|
|||
result
|
||||
}
|
||||
|
||||
pub fn new(global: &GlobalScope, status: &PermissionStatus) -> DomRoot<BluetoothPermissionResult> {
|
||||
reflect_dom_object(Box::new(BluetoothPermissionResult::new_inherited(status)),
|
||||
pub fn new(
|
||||
global: &GlobalScope,
|
||||
status: &PermissionStatus,
|
||||
) -> DomRoot<BluetoothPermissionResult> {
|
||||
reflect_dom_object(
|
||||
Box::new(BluetoothPermissionResult::new_inherited(status)),
|
||||
global,
|
||||
BluetoothPermissionResultBinding::Wrap)
|
||||
BluetoothPermissionResultBinding::Wrap,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn get_bluetooth(&self) -> DomRoot<Bluetooth> {
|
||||
|
@ -75,8 +80,12 @@ impl BluetoothPermissionResult {
|
|||
impl BluetoothPermissionResultMethods for BluetoothPermissionResult {
|
||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothpermissionresult-devices
|
||||
fn Devices(&self) -> Vec<DomRoot<BluetoothDevice>> {
|
||||
let device_vec: Vec<DomRoot<BluetoothDevice>> =
|
||||
self.devices.borrow().iter().map(|d| DomRoot::from_ref(&**d)).collect();
|
||||
let device_vec: Vec<DomRoot<BluetoothDevice>> = self
|
||||
.devices
|
||||
.borrow()
|
||||
.iter()
|
||||
.map(|d| DomRoot::from_ref(&**d))
|
||||
.collect();
|
||||
device_vec
|
||||
}
|
||||
}
|
||||
|
@ -93,26 +102,29 @@ impl AsyncBluetoothListener for BluetoothPermissionResult {
|
|||
if let Some(ref existing_device) = device_instance_map.get(&device.id) {
|
||||
// https://webbluetoothcg.github.io/web-bluetooth/#request-the-bluetooth-permission
|
||||
// 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
|
||||
// Step 8.
|
||||
return promise.resolve_native(self);
|
||||
}
|
||||
let bt_device = BluetoothDevice::new(&self.global(),
|
||||
let bt_device = BluetoothDevice::new(
|
||||
&self.global(),
|
||||
DOMString::from(device.id.clone()),
|
||||
device.name.map(DOMString::from),
|
||||
&bluetooth);
|
||||
&bluetooth,
|
||||
);
|
||||
device_instance_map.insert(device.id.clone(), Dom::from_ref(&bt_device));
|
||||
self.global().as_window().bluetooth_extra_permission_data().add_new_allowed_device(
|
||||
AllowedBluetoothDevice {
|
||||
self.global()
|
||||
.as_window()
|
||||
.bluetooth_extra_permission_data()
|
||||
.add_new_allowed_device(AllowedBluetoothDevice {
|
||||
deviceId: DOMString::from(device.id),
|
||||
mayUseGATT: true,
|
||||
}
|
||||
);
|
||||
});
|
||||
// https://webbluetoothcg.github.io/web-bluetooth/#request-the-bluetooth-permission
|
||||
// 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
|
||||
// Step 8.
|
||||
|
|
|
@ -45,11 +45,12 @@ pub struct BluetoothRemoteGATTCharacteristic {
|
|||
}
|
||||
|
||||
impl BluetoothRemoteGATTCharacteristic {
|
||||
pub fn new_inherited(service: &BluetoothRemoteGATTService,
|
||||
pub fn new_inherited(
|
||||
service: &BluetoothRemoteGATTService,
|
||||
uuid: DOMString,
|
||||
properties: &BluetoothCharacteristicProperties,
|
||||
instance_id: String)
|
||||
-> BluetoothRemoteGATTCharacteristic {
|
||||
instance_id: String,
|
||||
) -> BluetoothRemoteGATTCharacteristic {
|
||||
BluetoothRemoteGATTCharacteristic {
|
||||
eventtarget: EventTarget::new_inherited(),
|
||||
service: Dom::from_ref(service),
|
||||
|
@ -60,18 +61,19 @@ impl BluetoothRemoteGATTCharacteristic {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn new(global: &GlobalScope,
|
||||
pub fn new(
|
||||
global: &GlobalScope,
|
||||
service: &BluetoothRemoteGATTService,
|
||||
uuid: DOMString,
|
||||
properties: &BluetoothCharacteristicProperties,
|
||||
instanceID: String)
|
||||
-> DomRoot<BluetoothRemoteGATTCharacteristic> {
|
||||
instanceID: String,
|
||||
) -> DomRoot<BluetoothRemoteGATTCharacteristic> {
|
||||
reflect_dom_object(
|
||||
Box::new(BluetoothRemoteGATTCharacteristic::new_inherited(
|
||||
service, uuid, properties, instanceID
|
||||
service, uuid, properties, instanceID,
|
||||
)),
|
||||
global,
|
||||
BluetoothRemoteGATTCharacteristicBinding::Wrap
|
||||
BluetoothRemoteGATTCharacteristicBinding::Wrap,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -103,17 +105,29 @@ impl BluetoothRemoteGATTCharacteristicMethods for BluetoothRemoteGATTCharacteris
|
|||
#[allow(unrooted_must_root)]
|
||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-getdescriptor
|
||||
fn GetDescriptor(&self, descriptor: BluetoothDescriptorUUID) -> Rc<Promise> {
|
||||
get_gatt_children(self, true, BluetoothUUID::descriptor, Some(descriptor), self.get_instance_id(),
|
||||
self.Service().Device().get_gatt().Connected(), GATTType::Descriptor)
|
||||
get_gatt_children(
|
||||
self,
|
||||
true,
|
||||
BluetoothUUID::descriptor,
|
||||
Some(descriptor),
|
||||
self.get_instance_id(),
|
||||
self.Service().Device().get_gatt().Connected(),
|
||||
GATTType::Descriptor,
|
||||
)
|
||||
}
|
||||
|
||||
#[allow(unrooted_must_root)]
|
||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-getdescriptors
|
||||
fn GetDescriptors(&self,
|
||||
descriptor: Option<BluetoothDescriptorUUID>)
|
||||
-> Rc<Promise> {
|
||||
get_gatt_children(self, false, BluetoothUUID::descriptor, descriptor, self.get_instance_id(),
|
||||
self.Service().Device().get_gatt().Connected(), GATTType::Descriptor)
|
||||
fn GetDescriptors(&self, descriptor: Option<BluetoothDescriptorUUID>) -> Rc<Promise> {
|
||||
get_gatt_children(
|
||||
self,
|
||||
false,
|
||||
BluetoothUUID::descriptor,
|
||||
descriptor,
|
||||
self.get_instance_id(),
|
||||
self.Service().Device().get_gatt().Connected(),
|
||||
GATTType::Descriptor,
|
||||
)
|
||||
}
|
||||
|
||||
// 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
|
||||
// in readValue function and in handle_response function.
|
||||
let sender = response_async(&p, self);
|
||||
self.get_bluetooth_thread().send(
|
||||
BluetoothRequest::ReadValue(self.get_instance_id(), sender)).unwrap();
|
||||
self.get_bluetooth_thread()
|
||||
.send(BluetoothRequest::ReadValue(self.get_instance_id(), sender))
|
||||
.unwrap();
|
||||
return p;
|
||||
}
|
||||
|
||||
|
@ -187,7 +202,8 @@ impl BluetoothRemoteGATTCharacteristicMethods for BluetoothRemoteGATTCharacteris
|
|||
// Step 7.1.
|
||||
if !(self.Properties().Write() ||
|
||||
self.Properties().WriteWithoutResponse() ||
|
||||
self.Properties().AuthenticatedSignedWrites()) {
|
||||
self.Properties().AuthenticatedSignedWrites())
|
||||
{
|
||||
p.reject_error(NotSupported);
|
||||
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
|
||||
// in writeValue function and in handle_response function.
|
||||
let sender = response_async(&p, self);
|
||||
self.get_bluetooth_thread().send(
|
||||
BluetoothRequest::WriteValue(self.get_instance_id(), vec, sender)).unwrap();
|
||||
self.get_bluetooth_thread()
|
||||
.send(BluetoothRequest::WriteValue(
|
||||
self.get_instance_id(),
|
||||
vec,
|
||||
sender,
|
||||
)).unwrap();
|
||||
return p;
|
||||
}
|
||||
|
||||
|
@ -218,8 +238,7 @@ impl BluetoothRemoteGATTCharacteristicMethods for BluetoothRemoteGATTCharacteris
|
|||
}
|
||||
|
||||
// Step 5.
|
||||
if !(self.Properties().Notify() ||
|
||||
self.Properties().Indicate()) {
|
||||
if !(self.Properties().Notify() || self.Properties().Indicate()) {
|
||||
p.reject_error(NotSupported);
|
||||
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
|
||||
// and in handle_response function.
|
||||
let sender = response_async(&p, self);
|
||||
self.get_bluetooth_thread().send(
|
||||
BluetoothRequest::EnableNotification(self.get_instance_id(),
|
||||
self.get_bluetooth_thread()
|
||||
.send(BluetoothRequest::EnableNotification(
|
||||
self.get_instance_id(),
|
||||
true,
|
||||
sender)).unwrap();
|
||||
sender,
|
||||
)).unwrap();
|
||||
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
|
||||
// in enable_notification function and in handle_response function.
|
||||
self.get_bluetooth_thread().send(
|
||||
BluetoothRequest::EnableNotification(self.get_instance_id(),
|
||||
self.get_bluetooth_thread()
|
||||
.send(BluetoothRequest::EnableNotification(
|
||||
self.get_instance_id(),
|
||||
false,
|
||||
sender)).unwrap();
|
||||
sender,
|
||||
)).unwrap();
|
||||
return p;
|
||||
}
|
||||
|
||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-characteristiceventhandlers-oncharacteristicvaluechanged
|
||||
event_handler!(characteristicvaluechanged, GetOncharacteristicvaluechanged, SetOncharacteristicvaluechanged);
|
||||
event_handler!(
|
||||
characteristicvaluechanged,
|
||||
GetOncharacteristicvaluechanged,
|
||||
SetOncharacteristicvaluechanged
|
||||
);
|
||||
}
|
||||
|
||||
impl AsyncBluetoothListener for BluetoothRemoteGATTCharacteristic {
|
||||
|
@ -265,10 +292,12 @@ impl AsyncBluetoothListener for BluetoothRemoteGATTCharacteristic {
|
|||
// Step 7.
|
||||
BluetoothResponse::GetDescriptors(descriptors_vec, 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;
|
||||
}
|
||||
let mut descriptors = vec!();
|
||||
let mut descriptors = vec![];
|
||||
for descriptor in descriptors_vec {
|
||||
let bt_descriptor = device.get_or_create_descriptor(&descriptor, &self);
|
||||
descriptors.push(bt_descriptor);
|
||||
|
@ -285,7 +314,8 @@ impl AsyncBluetoothListener for BluetoothRemoteGATTCharacteristic {
|
|||
*self.value.borrow_mut() = Some(value.clone());
|
||||
|
||||
// Step 5.5.3.
|
||||
self.upcast::<EventTarget>().fire_bubbling_event(atom!("characteristicvaluechanged"));
|
||||
self.upcast::<EventTarget>()
|
||||
.fire_bubbling_event(atom!("characteristicvaluechanged"));
|
||||
|
||||
// Step 5.5.4.
|
||||
promise.resolve_native(&value);
|
||||
|
|
|
@ -35,10 +35,11 @@ pub struct BluetoothRemoteGATTDescriptor {
|
|||
}
|
||||
|
||||
impl BluetoothRemoteGATTDescriptor {
|
||||
pub fn new_inherited(characteristic: &BluetoothRemoteGATTCharacteristic,
|
||||
pub fn new_inherited(
|
||||
characteristic: &BluetoothRemoteGATTCharacteristic,
|
||||
uuid: DOMString,
|
||||
instance_id: String)
|
||||
-> BluetoothRemoteGATTDescriptor {
|
||||
instance_id: String,
|
||||
) -> BluetoothRemoteGATTDescriptor {
|
||||
BluetoothRemoteGATTDescriptor {
|
||||
reflector_: Reflector::new(),
|
||||
characteristic: Dom::from_ref(characteristic),
|
||||
|
@ -48,17 +49,20 @@ impl BluetoothRemoteGATTDescriptor {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn new(global: &GlobalScope,
|
||||
pub fn new(
|
||||
global: &GlobalScope,
|
||||
characteristic: &BluetoothRemoteGATTCharacteristic,
|
||||
uuid: DOMString,
|
||||
instanceID: String)
|
||||
-> DomRoot<BluetoothRemoteGATTDescriptor>{
|
||||
instanceID: String,
|
||||
) -> DomRoot<BluetoothRemoteGATTDescriptor> {
|
||||
reflect_dom_object(
|
||||
Box::new(BluetoothRemoteGATTDescriptor::new_inherited(
|
||||
characteristic, uuid, instanceID
|
||||
characteristic,
|
||||
uuid,
|
||||
instanceID,
|
||||
)),
|
||||
global,
|
||||
BluetoothRemoteGATTDescriptorBinding::Wrap
|
||||
BluetoothRemoteGATTDescriptorBinding::Wrap,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -99,7 +103,13 @@ impl BluetoothRemoteGATTDescriptorMethods for BluetoothRemoteGATTDescriptor {
|
|||
}
|
||||
|
||||
// Step 2.
|
||||
if !self.Characteristic().Service().Device().get_gatt().Connected() {
|
||||
if !self
|
||||
.Characteristic()
|
||||
.Service()
|
||||
.Device()
|
||||
.get_gatt()
|
||||
.Connected()
|
||||
{
|
||||
p.reject_error(Network);
|
||||
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
|
||||
// in readValue function and in handle_response function.
|
||||
let sender = response_async(&p, self);
|
||||
self.get_bluetooth_thread().send(
|
||||
BluetoothRequest::ReadValue(self.get_instance_id(), sender)).unwrap();
|
||||
self.get_bluetooth_thread()
|
||||
.send(BluetoothRequest::ReadValue(self.get_instance_id(), sender))
|
||||
.unwrap();
|
||||
return p;
|
||||
}
|
||||
|
||||
|
@ -135,7 +146,13 @@ impl BluetoothRemoteGATTDescriptorMethods for BluetoothRemoteGATTDescriptor {
|
|||
}
|
||||
|
||||
// Step 4.
|
||||
if !self.Characteristic().Service().Device().get_gatt().Connected() {
|
||||
if !self
|
||||
.Characteristic()
|
||||
.Service()
|
||||
.Device()
|
||||
.get_gatt()
|
||||
.Connected()
|
||||
{
|
||||
p.reject_error(Network);
|
||||
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
|
||||
// in writeValue function and in handle_response function.
|
||||
let sender = response_async(&p, self);
|
||||
self.get_bluetooth_thread().send(
|
||||
BluetoothRequest::WriteValue(self.get_instance_id(), vec, sender)).unwrap();
|
||||
self.get_bluetooth_thread()
|
||||
.send(BluetoothRequest::WriteValue(
|
||||
self.get_instance_id(),
|
||||
vec,
|
||||
sender,
|
||||
)).unwrap();
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,10 +37,15 @@ impl BluetoothRemoteGATTServer {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn new(global: &GlobalScope, device: &BluetoothDevice) -> DomRoot<BluetoothRemoteGATTServer> {
|
||||
reflect_dom_object(Box::new(BluetoothRemoteGATTServer::new_inherited(device)),
|
||||
pub fn new(
|
||||
global: &GlobalScope,
|
||||
device: &BluetoothDevice,
|
||||
) -> DomRoot<BluetoothRemoteGATTServer> {
|
||||
reflect_dom_object(
|
||||
Box::new(BluetoothRemoteGATTServer::new_inherited(device)),
|
||||
global,
|
||||
BluetoothRemoteGATTServerBinding::Wrap)
|
||||
BluetoothRemoteGATTServerBinding::Wrap,
|
||||
)
|
||||
}
|
||||
|
||||
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.
|
||||
// Steps 5.2.3 - 5.2.5 are in response function.
|
||||
self.get_bluetooth_thread().send(
|
||||
BluetoothRequest::GATTServerConnect(String::from(self.Device().Id()), sender)).unwrap();
|
||||
self.get_bluetooth_thread()
|
||||
.send(BluetoothRequest::GATTServerConnect(
|
||||
String::from(self.Device().Id()),
|
||||
sender,
|
||||
)).unwrap();
|
||||
// Step 5: return promise.
|
||||
return p;
|
||||
}
|
||||
|
@ -90,7 +98,7 @@ impl BluetoothRemoteGATTServerMethods for BluetoothRemoteGATTServer {
|
|||
|
||||
// Step 2.
|
||||
if !self.Connected() {
|
||||
return Ok(())
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Step 3.
|
||||
|
@ -104,17 +112,30 @@ impl BluetoothRemoteGATTServerMethods for BluetoothRemoteGATTServer {
|
|||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-getprimaryservice
|
||||
fn GetPrimaryService(&self, service: BluetoothServiceUUID) -> Rc<Promise> {
|
||||
// Step 1 - 2.
|
||||
get_gatt_children(self, true, BluetoothUUID::service, Some(service), String::from(self.Device().Id()),
|
||||
self.Device().get_gatt().Connected(), GATTType::PrimaryService)
|
||||
get_gatt_children(
|
||||
self,
|
||||
true,
|
||||
BluetoothUUID::service,
|
||||
Some(service),
|
||||
String::from(self.Device().Id()),
|
||||
self.Device().get_gatt().Connected(),
|
||||
GATTType::PrimaryService,
|
||||
)
|
||||
}
|
||||
|
||||
#[allow(unrooted_must_root)]
|
||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-getprimaryservices
|
||||
fn GetPrimaryServices(&self, service: Option<BluetoothServiceUUID>) -> Rc<Promise> {
|
||||
// Step 1 - 2.
|
||||
get_gatt_children(self, false, BluetoothUUID::service, service, String::from(self.Device().Id()),
|
||||
self.Connected(), GATTType::PrimaryService)
|
||||
|
||||
get_gatt_children(
|
||||
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));
|
||||
return;
|
||||
}
|
||||
let mut services = vec!();
|
||||
let mut services = vec![];
|
||||
for service in services_vec {
|
||||
let bt_service = device.get_or_create_service(&service, &self);
|
||||
services.push(bt_service);
|
||||
|
|
|
@ -30,11 +30,12 @@ pub struct BluetoothRemoteGATTService {
|
|||
}
|
||||
|
||||
impl BluetoothRemoteGATTService {
|
||||
pub fn new_inherited(device: &BluetoothDevice,
|
||||
pub fn new_inherited(
|
||||
device: &BluetoothDevice,
|
||||
uuid: DOMString,
|
||||
is_primary: bool,
|
||||
instance_id: String)
|
||||
-> BluetoothRemoteGATTService {
|
||||
instance_id: String,
|
||||
) -> BluetoothRemoteGATTService {
|
||||
BluetoothRemoteGATTService {
|
||||
eventtarget: EventTarget::new_inherited(),
|
||||
device: Dom::from_ref(device),
|
||||
|
@ -44,18 +45,19 @@ impl BluetoothRemoteGATTService {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn new(global: &GlobalScope,
|
||||
pub fn new(
|
||||
global: &GlobalScope,
|
||||
device: &BluetoothDevice,
|
||||
uuid: DOMString,
|
||||
isPrimary: bool,
|
||||
instanceID: String)
|
||||
-> DomRoot<BluetoothRemoteGATTService> {
|
||||
instanceID: String,
|
||||
) -> DomRoot<BluetoothRemoteGATTService> {
|
||||
reflect_dom_object(
|
||||
Box::new(BluetoothRemoteGATTService::new_inherited(
|
||||
device, uuid, isPrimary, instanceID
|
||||
device, uuid, isPrimary, instanceID,
|
||||
)),
|
||||
global,
|
||||
BluetoothRemoteGATTServiceBinding::Wrap
|
||||
BluetoothRemoteGATTServiceBinding::Wrap,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -82,39 +84,61 @@ impl BluetoothRemoteGATTServiceMethods for BluetoothRemoteGATTService {
|
|||
|
||||
#[allow(unrooted_must_root)]
|
||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getcharacteristic
|
||||
fn GetCharacteristic(&self,
|
||||
characteristic: BluetoothCharacteristicUUID)
|
||||
-> Rc<Promise> {
|
||||
get_gatt_children(self, true, BluetoothUUID::characteristic, Some(characteristic), self.get_instance_id(),
|
||||
self.Device().get_gatt().Connected(), GATTType::Characteristic)
|
||||
fn GetCharacteristic(&self, characteristic: BluetoothCharacteristicUUID) -> Rc<Promise> {
|
||||
get_gatt_children(
|
||||
self,
|
||||
true,
|
||||
BluetoothUUID::characteristic,
|
||||
Some(characteristic),
|
||||
self.get_instance_id(),
|
||||
self.Device().get_gatt().Connected(),
|
||||
GATTType::Characteristic,
|
||||
)
|
||||
}
|
||||
|
||||
#[allow(unrooted_must_root)]
|
||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getcharacteristics
|
||||
fn GetCharacteristics(&self,
|
||||
characteristic: Option<BluetoothCharacteristicUUID>)
|
||||
-> Rc<Promise> {
|
||||
get_gatt_children(self, false, BluetoothUUID::characteristic, characteristic, self.get_instance_id(),
|
||||
self.Device().get_gatt().Connected(), GATTType::Characteristic)
|
||||
fn GetCharacteristics(
|
||||
&self,
|
||||
characteristic: Option<BluetoothCharacteristicUUID>,
|
||||
) -> Rc<Promise> {
|
||||
get_gatt_children(
|
||||
self,
|
||||
false,
|
||||
BluetoothUUID::characteristic,
|
||||
characteristic,
|
||||
self.get_instance_id(),
|
||||
self.Device().get_gatt().Connected(),
|
||||
GATTType::Characteristic,
|
||||
)
|
||||
}
|
||||
|
||||
#[allow(unrooted_must_root)]
|
||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getincludedservice
|
||||
fn GetIncludedService(&self,
|
||||
service: BluetoothServiceUUID)
|
||||
-> Rc<Promise> {
|
||||
get_gatt_children(self, false, BluetoothUUID::service, Some(service), self.get_instance_id(),
|
||||
self.Device().get_gatt().Connected(), GATTType::IncludedService)
|
||||
fn GetIncludedService(&self, service: BluetoothServiceUUID) -> Rc<Promise> {
|
||||
get_gatt_children(
|
||||
self,
|
||||
false,
|
||||
BluetoothUUID::service,
|
||||
Some(service),
|
||||
self.get_instance_id(),
|
||||
self.Device().get_gatt().Connected(),
|
||||
GATTType::IncludedService,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
#[allow(unrooted_must_root)]
|
||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getincludedservices
|
||||
fn GetIncludedServices(&self,
|
||||
service: Option<BluetoothServiceUUID>)
|
||||
-> Rc<Promise> {
|
||||
get_gatt_children(self, false, BluetoothUUID::service, service, self.get_instance_id(),
|
||||
self.Device().get_gatt().Connected(), GATTType::IncludedService)
|
||||
fn GetIncludedServices(&self, service: Option<BluetoothServiceUUID>) -> Rc<Promise> {
|
||||
get_gatt_children(
|
||||
self,
|
||||
false,
|
||||
BluetoothUUID::service,
|
||||
service,
|
||||
self.get_instance_id(),
|
||||
self.Device().get_gatt().Connected(),
|
||||
GATTType::IncludedService,
|
||||
)
|
||||
}
|
||||
|
||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-serviceeventhandlers-onserviceadded
|
||||
|
@ -135,12 +159,15 @@ impl AsyncBluetoothListener for BluetoothRemoteGATTService {
|
|||
// Step 7.
|
||||
BluetoothResponse::GetCharacteristics(characteristics_vec, 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;
|
||||
}
|
||||
let mut characteristics = vec!();
|
||||
let mut 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);
|
||||
}
|
||||
promise.resolve_native(&characteristics);
|
||||
|
@ -149,9 +176,11 @@ impl AsyncBluetoothListener for BluetoothRemoteGATTService {
|
|||
// Step 7.
|
||||
BluetoothResponse::GetIncludedServices(services_vec, 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 {
|
||||
let bt_service = device.get_or_create_service(&service, &device.get_gatt());
|
||||
services.push(bt_service);
|
||||
|
|
|
@ -30,10 +30,16 @@ const BLUETOOTH_ASSIGNED_SERVICES: &'static [(&'static str, u32)] = &[
|
|||
("org.bluetooth.service.blood_pressure", 0x1810_u32),
|
||||
("org.bluetooth.service.body_composition", 0x181b_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.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.environmental_sensing", 0x181a_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.immediate_alert", 0x1802_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.location_and_navigation", 0x1819_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.pulse_oximeter", 0x1822_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.transport_discovery", 0x1824),
|
||||
("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
|
||||
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.age", 0x2a80_u32),
|
||||
("org.bluetooth.characteristic.aggregate", 0x2a5a_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_notification_control_point", 0x2a44_u32),
|
||||
(
|
||||
"org.bluetooth.characteristic.alert_notification_control_point",
|
||||
0x2a44_u32,
|
||||
),
|
||||
("org.bluetooth.characteristic.alert_status", 0x2a3f_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_threshold", 0x2a83_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_threshold",
|
||||
0x2a83_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.barometric_pressure_trend", 0x2aa3_u32),
|
||||
(
|
||||
"org.bluetooth.characteristic.barometric_pressure_trend",
|
||||
0x2aa3_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.body_composition_feature", 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.blood_pressure_feature",
|
||||
0x2a49_u32,
|
||||
),
|
||||
(
|
||||
"org.bluetooth.characteristic.blood_pressure_measurement",
|
||||
0x2a35_u32,
|
||||
),
|
||||
(
|
||||
"org.bluetooth.characteristic.body_composition_feature",
|
||||
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_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_specific_ops_control_point", 0x2aac_u32),
|
||||
(
|
||||
"org.bluetooth.characteristic.cgm_session_run_time",
|
||||
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.csc_feature", 0x2a5c_u32),
|
||||
("org.bluetooth.characteristic.csc_measurement", 0x2a5b_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_measurement", 0x2a63_u32),
|
||||
("org.bluetooth.characteristic.cycling_power_vector", 0x2a64_u32),
|
||||
("org.bluetooth.characteristic.database_change_increment", 0x2a99_u32),
|
||||
(
|
||||
"org.bluetooth.characteristic.cycling_power_control_point",
|
||||
0x2a66_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_threshold_assessment", 0x2a86_u32),
|
||||
(
|
||||
"org.bluetooth.characteristic.date_of_threshold_assessment",
|
||||
0x2a86_u32,
|
||||
),
|
||||
("org.bluetooth.characteristic.date_time", 0x2a08_u32),
|
||||
("org.bluetooth.characteristic.day_date_time", 0x2a0a_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.dew_point", 0x2a7b_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.email_address", 0x2a87_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.firmware_revision_string", 0x2a26_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.firmware_revision_string",
|
||||
0x2a26_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.gender", 0x2a8c_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.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_measurement", 0x2a37_u32),
|
||||
(
|
||||
"org.bluetooth.characteristic.heart_rate_measurement",
|
||||
0x2a37_u32,
|
||||
),
|
||||
("org.bluetooth.characteristic.heat_index", 0x2a7a_u32),
|
||||
("org.bluetooth.characteristic.height", 0x2a8e_u32),
|
||||
("org.bluetooth.characteristic.hid_control_point", 0x2a4c_u32),
|
||||
("org.bluetooth.characteristic.hid_information", 0x2a4a_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_headers", 0x2ab7_u32),
|
||||
("org.bluetooth.characteristic.http_status_code", 0x2ab8_u32),
|
||||
("org.bluetooth.characteristic.https_security", 0x2abb_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.intermediate_cuff_pressure", 0x2a36_u32),
|
||||
("org.bluetooth.characteristic.intermediate_temperature", 0x2a1e_u32),
|
||||
(
|
||||
"org.bluetooth.characteristic.ieee_11073-20601_regulatory_certification_data_list",
|
||||
0x2a2a_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.language", 0x2aa2_u32),
|
||||
("org.bluetooth.characteristic.last_name", 0x2a90_u32),
|
||||
("org.bluetooth.characteristic.latitude", 0x2aae_u32),
|
||||
("org.bluetooth.characteristic.ln_control_point", 0x2a6b_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_time_information", 0x2a0f_u32),
|
||||
("org.bluetooth.characteristic.location_and_speed", 0x2a67_u32),
|
||||
(
|
||||
"org.bluetooth.characteristic.local_east_coordinate.xml",
|
||||
0x2ab1_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.longitude", 0x2aaf_u32),
|
||||
("org.bluetooth.characteristic.magnetic_declination", 0x2a2c_u32),
|
||||
("org.bluetooth.characteristic.magnetic_flux_density_2d", 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.magnetic_declination",
|
||||
0x2a2c_u32,
|
||||
),
|
||||
(
|
||||
"org.bluetooth.characteristic.magnetic_flux_density_2d",
|
||||
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.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_first_created", 0x2ac1_u32),
|
||||
(
|
||||
"org.bluetooth.characteristic.object_first_created",
|
||||
0x2ac1_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_list_filter", 0x2ac7_u32),
|
||||
(
|
||||
"org.bluetooth.characteristic.object_last_modified",
|
||||
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_properties", 0x2ac4_u32),
|
||||
("org.bluetooth.characteristic.object_size", 0x2ac0_u32),
|
||||
("org.bluetooth.characteristic.object_type", 0x2abf_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.plx_continuous_measurement", 0x2a5f_u32),
|
||||
(
|
||||
"org.bluetooth.characteristic.gap.peripheral_preferred_connection_parameters",
|
||||
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_spot_check_measurement", 0x2a5e_u32),
|
||||
(
|
||||
"org.bluetooth.characteristic.plx_spot_check_measurement",
|
||||
0x2a5e_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.pressure", 0x2a6d_u32),
|
||||
("org.bluetooth.characteristic.protocol_mode", 0x2a4e_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.reference_time_information", 0x2a14_u32),
|
||||
(
|
||||
"org.bluetooth.characteristic.gap.reconnection_address",
|
||||
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_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.rsc_feature", 0x2a54_u32),
|
||||
("org.bluetooth.characteristic.rsc_measurement", 0x2a53_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.sensor_location", 0x2a5d_u32),
|
||||
("org.bluetooth.characteristic.serial_number_string", 0x2a25_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.serial_number_string",
|
||||
0x2a25_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.tds_control_point", 0x2abc_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.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_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_with_dst", 0x2a11_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.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.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.user_control_point", 0x2a9f_u32),
|
||||
(
|
||||
"org.bluetooth.characteristic.user_control_point",
|
||||
0x2a9f_u32,
|
||||
),
|
||||
("org.bluetooth.characteristic.user_index", 0x2a9a_u32),
|
||||
("org.bluetooth.characteristic.uv_index", 0x2a76_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_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),
|
||||
];
|
||||
|
||||
//https://developer.bluetooth.org/gatt/services/Pages/ServicesHome.aspx
|
||||
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.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.gatt.characteristic_extended_properties",
|
||||
0x2900_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.external_report_reference", 0x2907_u32),
|
||||
(
|
||||
"org.bluetooth.descriptor.external_report_reference",
|
||||
0x2907_u32,
|
||||
),
|
||||
("org.bluetooth.descriptor.report_reference", 0x2908_u32),
|
||||
("org.bluetooth.descriptor.number_of_digitals", 0x2909_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 CHARACTERISTIC_PREFIX: &'static str = "org.bluetooth.characteristic";
|
||||
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
|
||||
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";
|
||||
// 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'.";
|
||||
// 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'.";
|
||||
// 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'.";
|
||||
|
||||
impl BluetoothUUID {
|
||||
|
@ -310,7 +611,11 @@ impl BluetoothUUID {
|
|||
}
|
||||
|
||||
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> {
|
||||
|
@ -335,13 +640,11 @@ fn canonical_uuid(alias: u32) -> UUID {
|
|||
fn resolve_uuid_name(
|
||||
name: StringOrUnsignedLong,
|
||||
assigned_numbers_table: &'static [(&'static str, u32)],
|
||||
prefix: &str)
|
||||
-> Fallible<DOMString> {
|
||||
prefix: &str,
|
||||
) -> Fallible<DOMString> {
|
||||
match name {
|
||||
// Step 1.
|
||||
StringOrUnsignedLong::UnsignedLong(unsigned32) => {
|
||||
Ok(canonical_uuid(unsigned32))
|
||||
},
|
||||
StringOrUnsignedLong::UnsignedLong(unsigned32) => Ok(canonical_uuid(unsigned32)),
|
||||
StringOrUnsignedLong::String(dstring) => {
|
||||
// Step 2.
|
||||
let regex = Regex::new(VALID_UUID_REGEX).unwrap();
|
||||
|
@ -356,16 +659,17 @@ fn resolve_uuid_name(
|
|||
None => {
|
||||
let (attribute_type, error_url_message) = match prefix {
|
||||
SERVICE_PREFIX => ("Service", SERVICES_ERROR_MESSAGE),
|
||||
CHARACTERISTIC_PREFIX => ("Characteristic", CHARACTERISTIC_ERROR_MESSAGE),
|
||||
CHARACTERISTIC_PREFIX => {
|
||||
("Characteristic", CHARACTERISTIC_ERROR_MESSAGE)
|
||||
},
|
||||
DESCRIPTOR_PREFIX => ("Descriptor", DESCRIPTOR_ERROR_MESSAGE),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
// Step 4.
|
||||
return Err(Type(format!("Invalid {} name : '{}'.\n{} {}",
|
||||
attribute_type,
|
||||
dstring,
|
||||
UUID_ERROR_MESSAGE,
|
||||
error_url_message)));
|
||||
return Err(Type(format!(
|
||||
"Invalid {} name : '{}'.\n{} {}",
|
||||
attribute_type, dstring, UUID_ERROR_MESSAGE, error_url_message
|
||||
)));
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,9 +40,11 @@ impl 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,
|
||||
CanvasGradientBinding::Wrap)
|
||||
CanvasGradientBinding::Wrap,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -60,10 +62,10 @@ impl CanvasGradientMethods for CanvasGradient {
|
|||
match color {
|
||||
Ok(CSSColor::RGBA(rgba)) => rgba,
|
||||
Ok(CSSColor::CurrentColor) => RGBA::new(0, 0, 0, 255),
|
||||
_ => return Err(Error::Syntax)
|
||||
_ => return Err(Error::Syntax),
|
||||
}
|
||||
} else {
|
||||
return Err(Error::Syntax)
|
||||
return Err(Error::Syntax);
|
||||
};
|
||||
|
||||
self.stops.borrow_mut().push(CanvasGradientStop {
|
||||
|
@ -83,21 +85,25 @@ impl<'a> ToFillOrStrokeStyle for &'a CanvasGradient {
|
|||
let gradient_stops = self.stops.borrow().clone();
|
||||
match self.style {
|
||||
CanvasGradientStyle::Linear(ref gradient) => {
|
||||
FillOrStrokeStyle::LinearGradient(LinearGradientStyle::new(gradient.x0,
|
||||
FillOrStrokeStyle::LinearGradient(LinearGradientStyle::new(
|
||||
gradient.x0,
|
||||
gradient.y0,
|
||||
gradient.x1,
|
||||
gradient.y1,
|
||||
gradient_stops))
|
||||
}
|
||||
gradient_stops,
|
||||
))
|
||||
},
|
||||
CanvasGradientStyle::Radial(ref gradient) => {
|
||||
FillOrStrokeStyle::RadialGradient(RadialGradientStyle::new(gradient.x0,
|
||||
FillOrStrokeStyle::RadialGradient(RadialGradientStyle::new(
|
||||
gradient.x0,
|
||||
gradient.y0,
|
||||
gradient.r0,
|
||||
gradient.x1,
|
||||
gradient.y1,
|
||||
gradient.r1,
|
||||
gradient_stops))
|
||||
}
|
||||
gradient_stops,
|
||||
))
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,11 +23,12 @@ pub struct CanvasPattern {
|
|||
}
|
||||
|
||||
impl CanvasPattern {
|
||||
fn new_inherited(surface_data: Vec<u8>,
|
||||
fn new_inherited(
|
||||
surface_data: Vec<u8>,
|
||||
surface_size: Size2D<i32>,
|
||||
repeat: RepetitionStyle,
|
||||
origin_clean: bool)
|
||||
-> CanvasPattern {
|
||||
origin_clean: bool,
|
||||
) -> CanvasPattern {
|
||||
let (x, y) = match repeat {
|
||||
RepetitionStyle::Repeat => (true, true),
|
||||
RepetitionStyle::RepeatX => (true, false),
|
||||
|
@ -44,18 +45,22 @@ impl CanvasPattern {
|
|||
origin_clean: origin_clean,
|
||||
}
|
||||
}
|
||||
pub fn new(global: &GlobalScope,
|
||||
pub fn new(
|
||||
global: &GlobalScope,
|
||||
surface_data: Vec<u8>,
|
||||
surface_size: Size2D<i32>,
|
||||
repeat: RepetitionStyle,
|
||||
origin_clean: bool)
|
||||
-> DomRoot<CanvasPattern> {
|
||||
origin_clean: bool,
|
||||
) -> DomRoot<CanvasPattern> {
|
||||
reflect_dom_object(
|
||||
Box::new(CanvasPattern::new_inherited(
|
||||
surface_data, surface_size, repeat, origin_clean
|
||||
surface_data,
|
||||
surface_size,
|
||||
repeat,
|
||||
origin_clean,
|
||||
)),
|
||||
global,
|
||||
CanvasPatternBinding::Wrap
|
||||
CanvasPatternBinding::Wrap,
|
||||
)
|
||||
}
|
||||
pub fn origin_is_clean(&self) -> bool {
|
||||
|
@ -65,9 +70,11 @@ impl CanvasPattern {
|
|||
|
||||
impl<'a> ToFillOrStrokeStyle for &'a CanvasPattern {
|
||||
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.repeat_x,
|
||||
self.repeat_y))
|
||||
self.repeat_y,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -123,17 +123,21 @@ impl CanvasContextState {
|
|||
}
|
||||
|
||||
impl CanvasRenderingContext2D {
|
||||
pub fn new_inherited(global: &GlobalScope,
|
||||
pub fn new_inherited(
|
||||
global: &GlobalScope,
|
||||
canvas: Option<&HTMLCanvasElement>,
|
||||
image_cache: Arc<ImageCache>,
|
||||
base_url: ServoUrl,
|
||||
size: Size2D<i32>)
|
||||
-> CanvasRenderingContext2D {
|
||||
size: Size2D<i32>,
|
||||
) -> CanvasRenderingContext2D {
|
||||
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();
|
||||
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();
|
||||
debug!("Done.");
|
||||
CanvasRenderingContext2D {
|
||||
|
@ -150,15 +154,20 @@ impl CanvasRenderingContext2D {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn new(global: &GlobalScope,
|
||||
pub fn new(
|
||||
global: &GlobalScope,
|
||||
canvas: &HTMLCanvasElement,
|
||||
size: Size2D<i32>)
|
||||
-> DomRoot<CanvasRenderingContext2D> {
|
||||
size: Size2D<i32>,
|
||||
) -> DomRoot<CanvasRenderingContext2D> {
|
||||
let window = window_from_node(canvas);
|
||||
let image_cache = window.image_cache();
|
||||
let base_url = window.get_url();
|
||||
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)
|
||||
}
|
||||
|
@ -191,7 +200,8 @@ impl CanvasRenderingContext2D {
|
|||
// on the drawImage call arguments
|
||||
// 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
|
||||
fn adjust_source_dest_rects(&self,
|
||||
fn adjust_source_dest_rects(
|
||||
&self,
|
||||
image_size: Size2D<f64>,
|
||||
sx: f64,
|
||||
sy: f64,
|
||||
|
@ -200,19 +210,25 @@ impl CanvasRenderingContext2D {
|
|||
dx: f64,
|
||||
dy: f64,
|
||||
dw: f64,
|
||||
dh: f64)
|
||||
-> (Rect<f64>, Rect<f64>) {
|
||||
let image_rect = Rect::new(Point2D::new(0f64, 0f64),
|
||||
Size2D::new(image_size.width as f64, image_size.height as f64));
|
||||
dh: f64,
|
||||
) -> (Rect<f64>, Rect<f64>) {
|
||||
let image_rect = Rect::new(
|
||||
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),
|
||||
// (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)),
|
||||
Size2D::new(sw.abs(), sh.abs()));
|
||||
let source_rect = Rect::new(
|
||||
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,
|
||||
// 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
|
||||
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),
|
||||
// (dx+dw, dy), (dx+dw, dy+dh), (dx, dy+dh).
|
||||
let dest_rect = Rect::new(Point2D::new(dx.min(dx + dest_rect_width_scaled),
|
||||
dy.min(dy + dest_rect_height_scaled)),
|
||||
Size2D::new(dest_rect_width_scaled.abs(),
|
||||
dest_rect_height_scaled.abs()));
|
||||
let dest_rect = Rect::new(
|
||||
Point2D::new(
|
||||
dx.min(dx + dest_rect_width_scaled),
|
||||
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,
|
||||
source_rect_clipped.origin.y),
|
||||
Size2D::new(source_rect_clipped.size.width,
|
||||
source_rect_clipped.size.height));
|
||||
let source_rect = Rect::new(
|
||||
Point2D::new(source_rect_clipped.origin.x, source_rect_clipped.origin.y),
|
||||
Size2D::new(
|
||||
source_rect_clipped.size.width,
|
||||
source_rect_clipped.size.height,
|
||||
),
|
||||
);
|
||||
|
||||
(source_rect, dest_rect)
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#the-image-argument-is-not-origin-clean
|
||||
fn is_origin_clean(&self,
|
||||
image: CanvasImageSource)
|
||||
-> bool {
|
||||
fn is_origin_clean(&self, image: CanvasImageSource) -> bool {
|
||||
match image {
|
||||
CanvasImageSource::HTMLCanvasElement(canvas) => {
|
||||
canvas.origin_is_clean()
|
||||
}
|
||||
CanvasImageSource::HTMLCanvasElement(canvas) => canvas.origin_is_clean(),
|
||||
CanvasImageSource::HTMLImageElement(image) => {
|
||||
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
|
||||
//
|
||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-drawimage
|
||||
fn draw_image(&self,
|
||||
fn draw_image(
|
||||
&self,
|
||||
image: CanvasImageSource,
|
||||
sx: f64,
|
||||
sy: f64,
|
||||
|
@ -283,29 +302,25 @@ impl CanvasRenderingContext2D {
|
|||
dx: f64,
|
||||
dy: f64,
|
||||
dw: Option<f64>,
|
||||
dh: Option<f64>)
|
||||
-> ErrorResult {
|
||||
dh: Option<f64>,
|
||||
) -> ErrorResult {
|
||||
let result = match image {
|
||||
CanvasImageSource::HTMLCanvasElement(ref canvas) => {
|
||||
self.draw_html_canvas_element(&canvas,
|
||||
sx, sy, sw, sh,
|
||||
dx, dy, dw, dh)
|
||||
}
|
||||
self.draw_html_canvas_element(&canvas, sx, sy, sw, sh, dx, dy, dw, dh)
|
||||
},
|
||||
CanvasImageSource::HTMLImageElement(ref image) => {
|
||||
// https://html.spec.whatwg.org/multipage/#img-error
|
||||
// If the image argument is an HTMLImageElement object that is in the broken state,
|
||||
// then throw an InvalidStateError exception
|
||||
let url = image.get_url().ok_or(Error::InvalidState)?;
|
||||
self.fetch_and_draw_image_data(url,
|
||||
sx, sy, sw, sh,
|
||||
dx, dy, dw, dh)
|
||||
}
|
||||
self.fetch_and_draw_image_data(url, sx, sy, sw, sh, dx, dy, dw, dh)
|
||||
},
|
||||
CanvasImageSource::CSSStyleValue(ref value) => {
|
||||
let url = value.get_url(self.base_url.clone()).ok_or(Error::InvalidState)?;
|
||||
self.fetch_and_draw_image_data(url,
|
||||
sx, sy, sw, sh,
|
||||
dx, dy, dw, dh)
|
||||
}
|
||||
let url = value
|
||||
.get_url(self.base_url.clone())
|
||||
.ok_or(Error::InvalidState)?;
|
||||
self.fetch_and_draw_image_data(url, sx, sy, sw, sh, dx, dy, dw, dh)
|
||||
},
|
||||
};
|
||||
|
||||
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);
|
||||
// 2. Establish the source and destination rectangles
|
||||
let (source_rect, dest_rect) = self.adjust_source_dest_rects(
|
||||
image_size,
|
||||
sx,
|
||||
sy,
|
||||
sw,
|
||||
sh,
|
||||
dx,
|
||||
dy,
|
||||
dw,
|
||||
dh,
|
||||
);
|
||||
let (source_rect, dest_rect) =
|
||||
self.adjust_source_dest_rects(image_size, sx, sy, sw, sh, dx, dy, dw, dh);
|
||||
|
||||
if !is_rect_valid(source_rect) || !is_rect_valid(dest_rect) {
|
||||
return Ok(());
|
||||
|
@ -384,7 +390,8 @@ impl CanvasRenderingContext2D {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn fetch_and_draw_image_data(&self,
|
||||
fn fetch_and_draw_image_data(
|
||||
&self,
|
||||
url: ServoUrl,
|
||||
sx: f64,
|
||||
sy: f64,
|
||||
|
@ -393,8 +400,8 @@ impl CanvasRenderingContext2D {
|
|||
dx: f64,
|
||||
dy: f64,
|
||||
dw: Option<f64>,
|
||||
dh: Option<f64>)
|
||||
-> ErrorResult {
|
||||
dh: Option<f64>,
|
||||
) -> ErrorResult {
|
||||
debug!("Fetching image {}.", url);
|
||||
// https://html.spec.whatwg.org/multipage/#img-error
|
||||
// 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 sw = sw.unwrap_or(image_size.width);
|
||||
let sh = sh.unwrap_or(image_size.height);
|
||||
self.draw_image_data(image_data,
|
||||
image_size,
|
||||
sx, sy, sw, sh,
|
||||
dx, dy, dw, dh)
|
||||
self.draw_image_data(image_data, 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_size: Size2D<f64>,
|
||||
sx: f64,
|
||||
|
@ -429,18 +434,11 @@ impl CanvasRenderingContext2D {
|
|||
dx: f64,
|
||||
dy: f64,
|
||||
dw: f64,
|
||||
dh: f64)
|
||||
-> ErrorResult {
|
||||
dh: f64,
|
||||
) -> ErrorResult {
|
||||
// Establish the source and destination rectangles
|
||||
let (source_rect, dest_rect) = self.adjust_source_dest_rects(image_size,
|
||||
sx,
|
||||
sy,
|
||||
sw,
|
||||
sh,
|
||||
dx,
|
||||
dy,
|
||||
dw,
|
||||
dh);
|
||||
let (source_rect, dest_rect) =
|
||||
self.adjust_source_dest_rects(image_size, sx, sy, sw, sh, dx, dy, dw, dh);
|
||||
|
||||
if !is_rect_valid(source_rect) || !is_rect_valid(dest_rect) {
|
||||
return Ok(());
|
||||
|
@ -465,7 +463,7 @@ impl CanvasRenderingContext2D {
|
|||
ImageResponse::None |
|
||||
ImageResponse::MetadataLoaded(_) => {
|
||||
return None;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
let image_size = Size2D::new(img.width as i32, img.height as i32);
|
||||
|
@ -481,15 +479,16 @@ impl CanvasRenderingContext2D {
|
|||
|
||||
#[inline]
|
||||
fn request_image_from_cache(&self, url: ServoUrl) -> ImageResponse {
|
||||
let response = self.image_cache
|
||||
.find_image_or_metadata(url.clone(),
|
||||
let response = self.image_cache.find_image_or_metadata(
|
||||
url.clone(),
|
||||
UsePlaceholder::No,
|
||||
CanRequestImages::No);
|
||||
CanRequestImages::No,
|
||||
);
|
||||
match response {
|
||||
Ok(ImageOrMetadataAvailable::ImageAvailable(image, url)) =>
|
||||
ImageResponse::Loaded(image, url),
|
||||
Err(ImageState::Pending(_)) =>
|
||||
ImageResponse::None,
|
||||
Ok(ImageOrMetadataAvailable::ImageAvailable(image, url)) => {
|
||||
ImageResponse::Loaded(image, url)
|
||||
},
|
||||
Err(ImageState::Pending(_)) => ImageResponse::None,
|
||||
_ => {
|
||||
// Rather annoyingly, we get the same response back from
|
||||
// A load which really failed and from a load which hasn't started yet.
|
||||
|
@ -512,8 +511,10 @@ impl CanvasRenderingContext2D {
|
|||
return None;
|
||||
}
|
||||
|
||||
Some(Rect::new(Point2D::new(x as f32, y as f32),
|
||||
Size2D::new(w as f32, h as f32)))
|
||||
Some(Rect::new(
|
||||
Point2D::new(x as f32, y as f32),
|
||||
Size2D::new(w as f32, h as f32),
|
||||
))
|
||||
}
|
||||
|
||||
fn parse_color(&self, string: &str) -> Result<RGBA, ()> {
|
||||
|
@ -540,11 +541,13 @@ impl CanvasRenderingContext2D {
|
|||
let canvas_element = canvas.upcast::<Element>();
|
||||
|
||||
match canvas_element.style() {
|
||||
Some(ref s) if canvas_element.has_css_layout_box() => Ok(s.get_color().color),
|
||||
_ => Ok(RGBA::new(0, 0, 0, 255))
|
||||
Some(ref s) if canvas_element.has_css_layout_box() => {
|
||||
Ok(s.get_color().color)
|
||||
},
|
||||
_ => Ok(RGBA::new(0, 0, 0, 255)),
|
||||
}
|
||||
},
|
||||
_ => Err(())
|
||||
_ => Err(()),
|
||||
}
|
||||
} else {
|
||||
Err(())
|
||||
|
@ -556,7 +559,9 @@ impl CanvasRenderingContext2D {
|
|||
}
|
||||
|
||||
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> {
|
||||
|
@ -610,7 +615,9 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
|
|||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-save
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -643,10 +650,14 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
|
|||
|
||||
let (sin, cos) = (angle.sin(), angle.cos());
|
||||
let transform = self.state.borrow().transform;
|
||||
self.state.borrow_mut().transform = transform.pre_mul(
|
||||
&Transform2D::row_major(cos as f32, sin as f32,
|
||||
-sin as f32, cos as f32,
|
||||
0.0, 0.0));
|
||||
self.state.borrow_mut().transform = transform.pre_mul(&Transform2D::row_major(
|
||||
cos as f32,
|
||||
sin as f32,
|
||||
-sin as f32,
|
||||
cos as f32,
|
||||
0.0,
|
||||
0.0,
|
||||
));
|
||||
self.update_transform()
|
||||
}
|
||||
|
||||
|
@ -663,21 +674,32 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
|
|||
|
||||
// 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) {
|
||||
if !(a.is_finite() && b.is_finite() && c.is_finite() &&
|
||||
d.is_finite() && e.is_finite() && f.is_finite()) {
|
||||
if !(a.is_finite() &&
|
||||
b.is_finite() &&
|
||||
c.is_finite() &&
|
||||
d.is_finite() &&
|
||||
e.is_finite() &&
|
||||
f.is_finite())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
let transform = self.state.borrow().transform;
|
||||
self.state.borrow_mut().transform = transform.pre_mul(
|
||||
&Transform2D::row_major(a as f32, b as f32, c as f32, d as f32, e as f32, f as f32));
|
||||
self.state.borrow_mut().transform = transform.pre_mul(&Transform2D::row_major(
|
||||
a as f32, b as f32, c as f32, d as f32, e as f32, f as f32,
|
||||
));
|
||||
self.update_transform()
|
||||
}
|
||||
|
||||
// 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) {
|
||||
if !(a.is_finite() && b.is_finite() && c.is_finite() &&
|
||||
d.is_finite() && e.is_finite() && f.is_finite()) {
|
||||
if !(a.is_finite() &&
|
||||
b.is_finite() &&
|
||||
c.is_finite() &&
|
||||
d.is_finite() &&
|
||||
e.is_finite() &&
|
||||
f.is_finite())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -784,7 +806,8 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
|
|||
CanvasFillRule::Nonzero => FillRule::Nonzero,
|
||||
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));
|
||||
receiver.recv().unwrap()
|
||||
}
|
||||
|
@ -797,11 +820,7 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
|
|||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-drawimage
|
||||
fn DrawImage(&self,
|
||||
image: CanvasImageSource,
|
||||
dx: f64,
|
||||
dy: f64)
|
||||
-> ErrorResult {
|
||||
fn DrawImage(&self, image: CanvasImageSource, dx: f64, dy: f64) -> ErrorResult {
|
||||
if !(dx.is_finite() && dy.is_finite()) {
|
||||
return Ok(());
|
||||
}
|
||||
|
@ -810,13 +829,14 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
|
|||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-drawimage
|
||||
fn DrawImage_(&self,
|
||||
fn DrawImage_(
|
||||
&self,
|
||||
image: CanvasImageSource,
|
||||
dx: f64,
|
||||
dy: f64,
|
||||
dw: f64,
|
||||
dh: f64)
|
||||
-> ErrorResult {
|
||||
dh: f64,
|
||||
) -> ErrorResult {
|
||||
if !(dx.is_finite() && dy.is_finite() && dw.is_finite() && dh.is_finite()) {
|
||||
return Ok(());
|
||||
}
|
||||
|
@ -825,7 +845,8 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
|
|||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-drawimage
|
||||
fn DrawImage__(&self,
|
||||
fn DrawImage__(
|
||||
&self,
|
||||
image: CanvasImageSource,
|
||||
sx: f64,
|
||||
sy: f64,
|
||||
|
@ -834,14 +855,22 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
|
|||
dx: f64,
|
||||
dy: f64,
|
||||
dw: f64,
|
||||
dh: f64)
|
||||
-> ErrorResult {
|
||||
if !(sx.is_finite() && sy.is_finite() && sw.is_finite() && sh.is_finite() &&
|
||||
dx.is_finite() && dy.is_finite() && dw.is_finite() && dh.is_finite()) {
|
||||
dh: f64,
|
||||
) -> ErrorResult {
|
||||
if !(sx.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(());
|
||||
}
|
||||
|
||||
self.draw_image(image,
|
||||
self.draw_image(
|
||||
image,
|
||||
sx,
|
||||
sy,
|
||||
Some(sw),
|
||||
|
@ -849,7 +878,8 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
|
|||
dx,
|
||||
dy,
|
||||
Some(dw),
|
||||
Some(dh))
|
||||
Some(dh),
|
||||
)
|
||||
}
|
||||
|
||||
// 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
|
||||
fn Rect(&self, x: f64, y: f64, width: f64, height: f64) {
|
||||
if [x, y, width, height].iter().all(|val| val.is_finite()) {
|
||||
let rect = Rect::new(Point2D::new(x as f32, y as f32),
|
||||
Size2D::new(width as f32, height as f32));
|
||||
let rect = Rect::new(
|
||||
Point2D::new(x as f32, y as f32),
|
||||
Size2D::new(width as f32, height as f32),
|
||||
);
|
||||
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()) {
|
||||
return;
|
||||
}
|
||||
self.send_canvas_2d_msg(Canvas2dMsg::QuadraticCurveTo(Point2D::new(cpx as f32,
|
||||
cpy as f32),
|
||||
Point2D::new(x as f32,
|
||||
y as f32)));
|
||||
self.send_canvas_2d_msg(Canvas2dMsg::QuadraticCurveTo(
|
||||
Point2D::new(cpx as f32, cpy as f32),
|
||||
Point2D::new(x as f32, y as f32),
|
||||
));
|
||||
}
|
||||
|
||||
// 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) {
|
||||
if !(cp1x.is_finite() && cp1y.is_finite() && cp2x.is_finite() && cp2y.is_finite() &&
|
||||
x.is_finite() && y.is_finite()) {
|
||||
if !(cp1x.is_finite() &&
|
||||
cp1y.is_finite() &&
|
||||
cp2x.is_finite() &&
|
||||
cp2y.is_finite() &&
|
||||
x.is_finite() &&
|
||||
y.is_finite())
|
||||
{
|
||||
return;
|
||||
}
|
||||
self.send_canvas_2d_msg(Canvas2dMsg::BezierCurveTo(Point2D::new(cp1x as f32,
|
||||
cp1y as f32),
|
||||
Point2D::new(cp2x as f32,
|
||||
cp2y as f32),
|
||||
Point2D::new(x as f32, y as f32)));
|
||||
self.send_canvas_2d_msg(Canvas2dMsg::BezierCurveTo(
|
||||
Point2D::new(cp1x as f32, cp1y as f32),
|
||||
Point2D::new(cp2x as f32, cp2y as f32),
|
||||
Point2D::new(x as f32, y as f32),
|
||||
));
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-arc
|
||||
|
@ -911,11 +948,13 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
|
|||
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,
|
||||
start as f32,
|
||||
end as f32,
|
||||
ccw));
|
||||
ccw,
|
||||
));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -928,28 +967,45 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
|
|||
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),
|
||||
r as f32));
|
||||
r as f32,
|
||||
));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// 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 {
|
||||
if !([x, y, rx, ry, rotation, start, end].iter().all(|x| x.is_finite())) {
|
||||
fn Ellipse(
|
||||
&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(());
|
||||
}
|
||||
if rx < 0.0 || ry < 0.0 {
|
||||
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,
|
||||
ry as f32,
|
||||
rotation as f32,
|
||||
start as f32,
|
||||
end as f32,
|
||||
ccw));
|
||||
ccw,
|
||||
));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -977,7 +1033,7 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
|
|||
},
|
||||
CanvasFillOrStrokeStyle::Pattern(ref pattern) => {
|
||||
StringOrCanvasGradientOrCanvasPattern::CanvasPattern(DomRoot::from_ref(&*pattern))
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -987,23 +1043,28 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
|
|||
StringOrCanvasGradientOrCanvasPattern::String(string) => {
|
||||
if let Ok(rgba) = self.parse_color(&string) {
|
||||
self.state.borrow_mut().stroke_style = CanvasFillOrStrokeStyle::Color(rgba);
|
||||
self.send_canvas_2d_msg(Canvas2dMsg::SetStrokeStyle(
|
||||
FillOrStrokeStyle::Color(rgba)));
|
||||
self.send_canvas_2d_msg(Canvas2dMsg::SetStrokeStyle(FillOrStrokeStyle::Color(
|
||||
rgba,
|
||||
)));
|
||||
}
|
||||
},
|
||||
StringOrCanvasGradientOrCanvasPattern::CanvasGradient(gradient) => {
|
||||
self.state.borrow_mut().stroke_style =
|
||||
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) => {
|
||||
self.state.borrow_mut().stroke_style =
|
||||
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() {
|
||||
self.set_origin_unclean();
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1020,7 +1081,7 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
|
|||
},
|
||||
CanvasFillOrStrokeStyle::Pattern(ref pattern) => {
|
||||
StringOrCanvasGradientOrCanvasPattern::CanvasPattern(DomRoot::from_ref(&*pattern))
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1030,23 +1091,28 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
|
|||
StringOrCanvasGradientOrCanvasPattern::String(string) => {
|
||||
if let Ok(rgba) = self.parse_color(&string) {
|
||||
self.state.borrow_mut().fill_style = CanvasFillOrStrokeStyle::Color(rgba);
|
||||
self.send_canvas_2d_msg(Canvas2dMsg::SetFillStyle(
|
||||
FillOrStrokeStyle::Color(rgba)))
|
||||
}
|
||||
self.send_canvas_2d_msg(Canvas2dMsg::SetFillStyle(FillOrStrokeStyle::Color(
|
||||
rgba,
|
||||
)))
|
||||
}
|
||||
},
|
||||
StringOrCanvasGradientOrCanvasPattern::CanvasGradient(gradient) => {
|
||||
self.state.borrow_mut().fill_style =
|
||||
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) => {
|
||||
self.state.borrow_mut().fill_style =
|
||||
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() {
|
||||
self.set_origin_unclean();
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1063,21 +1129,19 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
|
|||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-createimagedata
|
||||
fn CreateImageData_(&self, imagedata: &ImageData) -> Fallible<DomRoot<ImageData>> {
|
||||
ImageData::new(&self.global(),
|
||||
imagedata.Width(),
|
||||
imagedata.Height(),
|
||||
None)
|
||||
ImageData::new(&self.global(), imagedata.Width(), imagedata.Height(), None)
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-getimagedata
|
||||
fn GetImageData(&self,
|
||||
fn GetImageData(
|
||||
&self,
|
||||
sx: Finite<f64>,
|
||||
sy: Finite<f64>,
|
||||
sw: Finite<f64>,
|
||||
sh: Finite<f64>)
|
||||
-> Fallible<DomRoot<ImageData>> {
|
||||
sh: Finite<f64>,
|
||||
) -> Fallible<DomRoot<ImageData>> {
|
||||
if !self.origin_is_clean() {
|
||||
return Err(Error::Security)
|
||||
return Err(Error::Security);
|
||||
}
|
||||
|
||||
let mut sx = *sx;
|
||||
|
@ -1102,9 +1166,15 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
|
|||
let sw = cmp::max(1, sw.to_u32().unwrap());
|
||||
|
||||
let (sender, receiver) = ipc::bytes_channel().unwrap();
|
||||
let dest_rect = Rect::new(Point2D::new(sx.to_i32().unwrap(), sy.to_i32().unwrap()),
|
||||
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 dest_rect = Rect::new(
|
||||
Point2D::new(sx.to_i32().unwrap(), sy.to_i32().unwrap()),
|
||||
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);
|
||||
self.send_canvas_2d_msg(Canvas2dMsg::GetImageData(dest_rect, canvas_size, sender));
|
||||
let mut data = receiver.recv().unwrap();
|
||||
|
@ -1122,97 +1192,110 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
|
|||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-putimagedata
|
||||
fn PutImageData(&self, imagedata: &ImageData, dx: Finite<f64>, dy: Finite<f64>) {
|
||||
self.PutImageData_(imagedata,
|
||||
self.PutImageData_(
|
||||
imagedata,
|
||||
dx,
|
||||
dy,
|
||||
Finite::wrap(0f64),
|
||||
Finite::wrap(0f64),
|
||||
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
|
||||
fn PutImageData_(&self,
|
||||
fn PutImageData_(
|
||||
&self,
|
||||
imagedata: &ImageData,
|
||||
dx: Finite<f64>,
|
||||
dy: Finite<f64>,
|
||||
dirty_x: Finite<f64>,
|
||||
dirty_y: Finite<f64>,
|
||||
dirty_width: Finite<f64>,
|
||||
dirty_height: Finite<f64>) {
|
||||
dirty_height: Finite<f64>,
|
||||
) {
|
||||
let data = imagedata.get_data_array();
|
||||
let offset = Vector2D::new(*dx, *dy);
|
||||
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),
|
||||
Size2D::new(*dirty_width, *dirty_height));
|
||||
self.send_canvas_2d_msg(Canvas2dMsg::PutImageData(data.into(),
|
||||
let dirty_rect = Rect::new(
|
||||
Point2D::new(*dirty_x, *dirty_y),
|
||||
Size2D::new(*dirty_width, *dirty_height),
|
||||
);
|
||||
self.send_canvas_2d_msg(Canvas2dMsg::PutImageData(
|
||||
data.into(),
|
||||
offset,
|
||||
image_data_size,
|
||||
dirty_rect));
|
||||
dirty_rect,
|
||||
));
|
||||
self.mark_as_dirty();
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-createlineargradient
|
||||
fn CreateLinearGradient(&self,
|
||||
fn CreateLinearGradient(
|
||||
&self,
|
||||
x0: Finite<f64>,
|
||||
y0: Finite<f64>,
|
||||
x1: Finite<f64>,
|
||||
y1: Finite<f64>)
|
||||
-> DomRoot<CanvasGradient> {
|
||||
CanvasGradient::new(&self.global(),
|
||||
CanvasGradientStyle::Linear(LinearGradientStyle::new(*x0,
|
||||
*y0,
|
||||
*x1,
|
||||
*y1,
|
||||
Vec::new())))
|
||||
y1: Finite<f64>,
|
||||
) -> DomRoot<CanvasGradient> {
|
||||
CanvasGradient::new(
|
||||
&self.global(),
|
||||
CanvasGradientStyle::Linear(LinearGradientStyle::new(*x0, *y0, *x1, *y1, Vec::new())),
|
||||
)
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-createradialgradient
|
||||
fn CreateRadialGradient(&self,
|
||||
fn CreateRadialGradient(
|
||||
&self,
|
||||
x0: Finite<f64>,
|
||||
y0: Finite<f64>,
|
||||
r0: Finite<f64>,
|
||||
x1: Finite<f64>,
|
||||
y1: Finite<f64>,
|
||||
r1: Finite<f64>)
|
||||
-> Fallible<DomRoot<CanvasGradient>> {
|
||||
r1: Finite<f64>,
|
||||
) -> Fallible<DomRoot<CanvasGradient>> {
|
||||
if *r0 < 0. || *r1 < 0. {
|
||||
return Err(Error::IndexSize);
|
||||
}
|
||||
|
||||
Ok(CanvasGradient::new(&self.global(),
|
||||
CanvasGradientStyle::Radial(RadialGradientStyle::new(*x0,
|
||||
Ok(CanvasGradient::new(
|
||||
&self.global(),
|
||||
CanvasGradientStyle::Radial(RadialGradientStyle::new(
|
||||
*x0,
|
||||
*y0,
|
||||
*r0,
|
||||
*x1,
|
||||
*y1,
|
||||
*r1,
|
||||
Vec::new()))))
|
||||
Vec::new(),
|
||||
)),
|
||||
))
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-createpattern
|
||||
fn CreatePattern(&self,
|
||||
fn CreatePattern(
|
||||
&self,
|
||||
image: CanvasImageSource,
|
||||
mut repetition: DOMString)
|
||||
-> Fallible<DomRoot<CanvasPattern>> {
|
||||
mut repetition: DOMString,
|
||||
) -> Fallible<DomRoot<CanvasPattern>> {
|
||||
let (image_data, image_size) = match image {
|
||||
CanvasImageSource::HTMLImageElement(ref image) => {
|
||||
// https://html.spec.whatwg.org/multipage/#img-error
|
||||
// If the image argument is an HTMLImageElement object that is in the broken state,
|
||||
// then throw an InvalidStateError exception
|
||||
image.get_url()
|
||||
image
|
||||
.get_url()
|
||||
.and_then(|url| self.fetch_image_data(url))
|
||||
.ok_or(Error::InvalidState)?
|
||||
},
|
||||
CanvasImageSource::HTMLCanvasElement(ref canvas) => {
|
||||
canvas.fetch_all_data().ok_or(Error::InvalidState)?
|
||||
},
|
||||
CanvasImageSource::CSSStyleValue(ref value) => {
|
||||
value.get_url(self.base_url.clone())
|
||||
CanvasImageSource::CSSStyleValue(ref value) => value
|
||||
.get_url(self.base_url.clone())
|
||||
.and_then(|url| self.fetch_image_data(url))
|
||||
.ok_or(Error::InvalidState)?
|
||||
}
|
||||
.ok_or(Error::InvalidState)?,
|
||||
};
|
||||
|
||||
if repetition.is_empty() {
|
||||
|
@ -1220,11 +1303,13 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
|
|||
}
|
||||
|
||||
if let Ok(rep) = RepetitionStyle::from_str(&repetition) {
|
||||
Ok(CanvasPattern::new(&self.global(),
|
||||
Ok(CanvasPattern::new(
|
||||
&self.global(),
|
||||
image_data,
|
||||
image_size,
|
||||
rep,
|
||||
self.is_origin_clean(image)))
|
||||
self.is_origin_clean(image),
|
||||
))
|
||||
} else {
|
||||
Err(Error::Syntax)
|
||||
}
|
||||
|
@ -1362,7 +1447,10 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
|
|||
|
||||
impl Drop for CanvasRenderingContext2D {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -1391,22 +1479,32 @@ fn is_rect_valid(rect: Rect<f64>) -> bool {
|
|||
|
||||
// https://html.spec.whatwg.org/multipage/#serialisation-of-a-colour
|
||||
fn serialize<W>(color: &RGBA, dest: &mut W) -> fmt::Result
|
||||
where W: fmt::Write
|
||||
where
|
||||
W: fmt::Write,
|
||||
{
|
||||
let red = color.red;
|
||||
let green = color.green;
|
||||
let blue = color.blue;
|
||||
|
||||
if color.alpha == 255 {
|
||||
write!(dest,
|
||||
write!(
|
||||
dest,
|
||||
"#{:x}{:x}{:x}{:x}{:x}{:x}",
|
||||
red >> 4,
|
||||
red & 0xF,
|
||||
green >> 4,
|
||||
green & 0xF,
|
||||
blue >> 4,
|
||||
blue & 0xF)
|
||||
blue & 0xF
|
||||
)
|
||||
} 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,
|
||||
options: &ChannelMergerOptions,
|
||||
) -> Fallible<ChannelMergerNode> {
|
||||
let node_options = options.parent
|
||||
.unwrap_or(1, ChannelCountMode::Explicit,
|
||||
ChannelInterpretation::Speakers);
|
||||
let node_options = options.parent.unwrap_or(
|
||||
1,
|
||||
ChannelCountMode::Explicit,
|
||||
ChannelInterpretation::Speakers,
|
||||
);
|
||||
|
||||
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 {
|
||||
return Err(Error::IndexSize)
|
||||
return Err(Error::IndexSize);
|
||||
}
|
||||
|
||||
let node = AudioNode::new_inherited(
|
||||
|
@ -45,9 +47,7 @@ impl ChannelMergerNode {
|
|||
options.numberOfInputs, // inputs
|
||||
1, // outputs
|
||||
)?;
|
||||
Ok(ChannelMergerNode {
|
||||
node,
|
||||
})
|
||||
Ok(ChannelMergerNode { node })
|
||||
}
|
||||
|
||||
#[allow(unrooted_must_root)]
|
||||
|
@ -57,7 +57,11 @@ impl ChannelMergerNode {
|
|||
options: &ChannelMergerOptions,
|
||||
) -> Fallible<DomRoot<ChannelMergerNode>> {
|
||||
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(
|
||||
|
|
|
@ -45,7 +45,7 @@ impl CharacterData {
|
|||
match self.upcast::<Node>().type_id() {
|
||||
NodeTypeId::CharacterData(CharacterDataTypeId::Comment) => {
|
||||
DomRoot::upcast(Comment::new(data, &document))
|
||||
}
|
||||
},
|
||||
NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) => {
|
||||
let pi = self.downcast::<ProcessingInstruction>().unwrap();
|
||||
DomRoot::upcast(ProcessingInstruction::new(pi.Target(), data, &document))
|
||||
|
@ -107,7 +107,8 @@ impl CharacterDataMethods for CharacterData {
|
|||
*self.data.borrow_mut() = data;
|
||||
self.content_changed();
|
||||
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
|
||||
|
@ -130,7 +131,7 @@ impl CharacterDataMethods for CharacterData {
|
|||
substring = substring + "\u{FFFD}";
|
||||
}
|
||||
remaining = s;
|
||||
}
|
||||
},
|
||||
// Step 2.
|
||||
Err(()) => return Err(Error::IndexSize),
|
||||
}
|
||||
|
@ -146,7 +147,7 @@ impl CharacterDataMethods for CharacterData {
|
|||
if astral.is_some() {
|
||||
substring = substring + "\u{FFFD}";
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
Ok(DOMString::from(substring))
|
||||
}
|
||||
|
@ -183,7 +184,7 @@ impl CharacterDataMethods for CharacterData {
|
|||
// since our DOMString is currently strict UTF-8.
|
||||
replacement_before = if astral.is_some() { "\u{FFFD}" } else { "" };
|
||||
remaining = r;
|
||||
}
|
||||
},
|
||||
// Step 2.
|
||||
Err(()) => return Err(Error::IndexSize),
|
||||
};
|
||||
|
@ -194,14 +195,14 @@ impl CharacterDataMethods for CharacterData {
|
|||
Err(()) => {
|
||||
replacement_after = "";
|
||||
suffix = "";
|
||||
}
|
||||
},
|
||||
Ok((_, astral, s)) => {
|
||||
// As if we had split the UTF-16 surrogate pair in half
|
||||
// and then transcoded that to UTF-8 lossily,
|
||||
// since our DOMString is currently strict UTF-8.
|
||||
replacement_after = if astral.is_some() { "\u{FFFD}" } else { "" };
|
||||
suffix = s;
|
||||
}
|
||||
},
|
||||
};
|
||||
// Step 4: Mutation observers.
|
||||
self.queue_mutation_record();
|
||||
|
@ -212,7 +213,8 @@ impl CharacterDataMethods for CharacterData {
|
|||
replacement_before.len() +
|
||||
arg.len() +
|
||||
replacement_after.len() +
|
||||
suffix.len());
|
||||
suffix.len(),
|
||||
);
|
||||
new_data.push_str(prefix);
|
||||
new_data.push_str(replacement_before);
|
||||
new_data.push_str(&arg);
|
||||
|
@ -223,8 +225,8 @@ impl CharacterDataMethods for CharacterData {
|
|||
self.content_changed();
|
||||
// Steps 8-11.
|
||||
let node = self.upcast::<Node>();
|
||||
node.ranges().replace_code_units(
|
||||
node, offset, count, arg.encode_utf16().count() as u32);
|
||||
node.ranges()
|
||||
.replace_code_units(node, offset, count, arg.encode_utf16().count() as u32);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -251,12 +253,18 @@ impl CharacterDataMethods for CharacterData {
|
|||
|
||||
// https://dom.spec.whatwg.org/#dom-nondocumenttypechildnode-previouselementsibling
|
||||
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
|
||||
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 opts::get().replace_surrogates {
|
||||
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\
|
||||
If you see this in real content, please comment with the URL\n\
|
||||
on https://github.com/servo/servo/issues/6873\n\
|
||||
\n");
|
||||
\n"
|
||||
);
|
||||
}
|
||||
code_units += 1;
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ pub struct Client {
|
|||
url: ServoUrl,
|
||||
frame_type: FrameType,
|
||||
#[ignore_malloc_size_of = "Defined in uuid"]
|
||||
id: Uuid
|
||||
id: Uuid,
|
||||
}
|
||||
|
||||
impl Client {
|
||||
|
@ -31,14 +31,16 @@ impl Client {
|
|||
active_worker: Default::default(),
|
||||
url: url,
|
||||
frame_type: FrameType::None,
|
||||
id: Uuid::new_v4()
|
||||
id: Uuid::new_v4(),
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
Wrap)
|
||||
Wrap,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn creation_url(&self) -> ServoUrl {
|
||||
|
|
|
@ -34,45 +34,48 @@ impl 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,
|
||||
CloseEventBinding::Wrap)
|
||||
CloseEventBinding::Wrap,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn new(global: &GlobalScope,
|
||||
pub fn new(
|
||||
global: &GlobalScope,
|
||||
type_: Atom,
|
||||
bubbles: EventBubbles,
|
||||
cancelable: EventCancelable,
|
||||
wasClean: bool,
|
||||
code: u16,
|
||||
reason: DOMString)
|
||||
-> DomRoot<CloseEvent> {
|
||||
reason: DOMString,
|
||||
) -> DomRoot<CloseEvent> {
|
||||
let event = Box::new(CloseEvent::new_inherited(wasClean, code, reason));
|
||||
let ev = reflect_dom_object(event, global, CloseEventBinding::Wrap);
|
||||
{
|
||||
let event = ev.upcast::<Event>();
|
||||
event.init_event(type_,
|
||||
bool::from(bubbles),
|
||||
bool::from(cancelable));
|
||||
event.init_event(type_, bool::from(bubbles), bool::from(cancelable));
|
||||
}
|
||||
ev
|
||||
}
|
||||
|
||||
pub fn Constructor(global: &GlobalScope,
|
||||
pub fn Constructor(
|
||||
global: &GlobalScope,
|
||||
type_: DOMString,
|
||||
init: &CloseEventBinding::CloseEventInit)
|
||||
-> Fallible<DomRoot<CloseEvent>> {
|
||||
init: &CloseEventBinding::CloseEventInit,
|
||||
) -> Fallible<DomRoot<CloseEvent>> {
|
||||
let bubbles = EventBubbles::from(init.parent.bubbles);
|
||||
let cancelable = EventCancelable::from(init.parent.cancelable);
|
||||
Ok(CloseEvent::new(global,
|
||||
Ok(CloseEvent::new(
|
||||
global,
|
||||
Atom::from(type_),
|
||||
bubbles,
|
||||
cancelable,
|
||||
init.wasClean,
|
||||
init.code,
|
||||
init.reason.clone()))
|
||||
init.reason.clone(),
|
||||
))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl CloseEventMethods for CloseEvent {
|
||||
|
|
|
@ -27,9 +27,11 @@ impl 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,
|
||||
CommentBinding::Wrap)
|
||||
CommentBinding::Wrap,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn Constructor(window: &Window, data: DOMString) -> Fallible<DomRoot<Comment>> {
|
||||
|
|
|
@ -19,34 +19,42 @@ pub struct CompositionEvent {
|
|||
}
|
||||
|
||||
impl CompositionEvent {
|
||||
pub fn new(window: &Window,
|
||||
pub fn new(
|
||||
window: &Window,
|
||||
type_: DOMString,
|
||||
can_bubble: bool,
|
||||
cancelable: bool,
|
||||
view: Option<&Window>,
|
||||
detail: i32,
|
||||
data: DOMString) -> DomRoot<CompositionEvent> {
|
||||
let ev = reflect_dom_object(Box::new(CompositionEvent {
|
||||
data: DOMString,
|
||||
) -> DomRoot<CompositionEvent> {
|
||||
let ev = reflect_dom_object(
|
||||
Box::new(CompositionEvent {
|
||||
uievent: UIEvent::new_inherited(),
|
||||
data: data,
|
||||
}),
|
||||
window,
|
||||
CompositionEventBinding::Wrap);
|
||||
ev.uievent.InitUIEvent(type_, can_bubble, cancelable, view, detail);
|
||||
CompositionEventBinding::Wrap,
|
||||
);
|
||||
ev.uievent
|
||||
.InitUIEvent(type_, can_bubble, cancelable, view, detail);
|
||||
ev
|
||||
}
|
||||
|
||||
pub fn Constructor(window: &Window,
|
||||
pub fn Constructor(
|
||||
window: &Window,
|
||||
type_: DOMString,
|
||||
init: &CompositionEventBinding::CompositionEventInit)
|
||||
-> Fallible<DomRoot<CompositionEvent>> {
|
||||
let event = CompositionEvent::new(window,
|
||||
init: &CompositionEventBinding::CompositionEventInit,
|
||||
) -> Fallible<DomRoot<CompositionEvent>> {
|
||||
let event = CompositionEvent::new(
|
||||
window,
|
||||
type_,
|
||||
init.parent.parent.bubbles,
|
||||
init.parent.parent.cancelable,
|
||||
init.parent.view.r(),
|
||||
init.parent.detail,
|
||||
init.data.clone());
|
||||
init.data.clone(),
|
||||
);
|
||||
Ok(event)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,13 +16,14 @@ impl Console {
|
|||
fn send_to_devtools(global: &GlobalScope, level: LogLevel, message: DOMString) {
|
||||
if let Some(chan) = global.devtools_chan() {
|
||||
let console_message = prepare_message(level, message);
|
||||
let worker_id = global.downcast::<WorkerGlobalScope>().map(|worker| {
|
||||
worker.get_worker_id()
|
||||
});
|
||||
let worker_id = global
|
||||
.downcast::<WorkerGlobalScope>()
|
||||
.map(|worker| worker.get_worker_id());
|
||||
let devtools_message = ScriptToDevtoolsControlMsg::ConsoleAPI(
|
||||
global.pipeline_id(),
|
||||
console_message,
|
||||
worker_id);
|
||||
worker_id,
|
||||
);
|
||||
chan.send(devtools_message).unwrap();
|
||||
}
|
||||
}
|
||||
|
@ -33,7 +34,10 @@ impl Console {
|
|||
// 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
|
||||
// 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 _handle = stderr.lock();
|
||||
f()
|
||||
|
@ -116,9 +120,7 @@ impl Console {
|
|||
pub fn TimeEnd(global: &GlobalScope, label: DOMString) {
|
||||
with_stderr_lock(move || {
|
||||
if let Ok(delta) = global.time_end(&label) {
|
||||
let message = DOMString::from(
|
||||
format!("{}: {}ms", label, delta)
|
||||
);
|
||||
let message = DOMString::from(format!("{}: {}ms", label, delta));
|
||||
println!("{}", message);
|
||||
Self::send_to_devtools(global, LogLevel::Log, message);
|
||||
};
|
||||
|
|
|
@ -84,10 +84,11 @@ use js::jsapi::JSAutoCompartment;
|
|||
use script_thread::ScriptThread;
|
||||
use servo_config::prefs::PREFS;
|
||||
|
||||
fn create_svg_element(name: QualName,
|
||||
fn create_svg_element(
|
||||
name: QualName,
|
||||
prefix: Option<Prefix>,
|
||||
document: &Document)
|
||||
-> DomRoot<Element> {
|
||||
document: &Document,
|
||||
) -> DomRoot<Element> {
|
||||
assert_eq!(name.ns, ns!(svg));
|
||||
|
||||
macro_rules! make(
|
||||
|
@ -113,13 +114,14 @@ fn create_svg_element(name: QualName,
|
|||
|
||||
// https://dom.spec.whatwg.org/#concept-create-element
|
||||
#[allow(unsafe_code)]
|
||||
fn create_html_element(name: QualName,
|
||||
fn create_html_element(
|
||||
name: QualName,
|
||||
prefix: Option<Prefix>,
|
||||
is: Option<LocalName>,
|
||||
document: &Document,
|
||||
creator: ElementCreator,
|
||||
mode: CustomElementCreationMode)
|
||||
-> DomRoot<Element> {
|
||||
mode: CustomElementCreationMode,
|
||||
) -> DomRoot<Element> {
|
||||
assert_eq!(name.ns, ns!(html));
|
||||
|
||||
// Step 4
|
||||
|
@ -129,8 +131,11 @@ fn create_html_element(name: QualName,
|
|||
if definition.is_autonomous() {
|
||||
match mode {
|
||||
CustomElementCreationMode::Asynchronous => {
|
||||
let result = DomRoot::upcast::<Element>(
|
||||
HTMLElement::new(name.local.clone(), prefix.clone(), document));
|
||||
let result = DomRoot::upcast::<Element>(HTMLElement::new(
|
||||
name.local.clone(),
|
||||
prefix.clone(),
|
||||
document,
|
||||
));
|
||||
result.set_custom_element_state(CustomElementState::Undefined);
|
||||
ScriptThread::enqueue_upgrade_reaction(&*result, definition);
|
||||
return result;
|
||||
|
@ -144,19 +149,24 @@ fn create_html_element(name: QualName,
|
|||
},
|
||||
Err(error) => {
|
||||
// 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();
|
||||
|
||||
// Step 6.1.1
|
||||
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);
|
||||
report_pending_exception(cx, true);
|
||||
}
|
||||
|
||||
// Step 6.1.2
|
||||
let element = DomRoot::upcast::<Element>(
|
||||
HTMLUnknownElement::new(local_name, prefix, document));
|
||||
let element = DomRoot::upcast::<Element>(HTMLUnknownElement::new(
|
||||
local_name, prefix, document,
|
||||
));
|
||||
element.set_custom_element_state(CustomElementState::Failed);
|
||||
element
|
||||
},
|
||||
|
@ -170,11 +180,11 @@ fn create_html_element(name: QualName,
|
|||
element.set_custom_element_state(CustomElementState::Undefined);
|
||||
match mode {
|
||||
// Step 5.3
|
||||
CustomElementCreationMode::Synchronous =>
|
||||
upgrade_element(definition, &*element),
|
||||
CustomElementCreationMode::Synchronous => upgrade_element(definition, &*element),
|
||||
// Step 5.4
|
||||
CustomElementCreationMode::Asynchronous =>
|
||||
ScriptThread::enqueue_upgrade_reaction(&*element, definition),
|
||||
CustomElementCreationMode::Asynchronous => {
|
||||
ScriptThread::enqueue_upgrade_reaction(&*element, definition)
|
||||
},
|
||||
}
|
||||
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>,
|
||||
document: &Document,
|
||||
creator: ElementCreator,
|
||||
mode: CustomElementCreationMode)
|
||||
-> DomRoot<Element> {
|
||||
mode: CustomElementCreationMode,
|
||||
) -> DomRoot<Element> {
|
||||
let prefix = name.prefix.clone();
|
||||
match name.ns {
|
||||
ns!(html) => create_html_element(name, prefix, is, document, creator, mode),
|
||||
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> {
|
||||
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 {
|
||||
#[allow(unsafe_code)]
|
||||
// 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,
|
||||
mut input: CustomAutoRooterGuard<ArrayBufferView>)
|
||||
-> Fallible<NonNull<JSObject>> {
|
||||
mut input: CustomAutoRooterGuard<ArrayBufferView>,
|
||||
) -> Fallible<NonNull<JSObject>> {
|
||||
let array_type = input.get_array_type();
|
||||
|
||||
if !is_integer_buffer(array_type) {
|
||||
|
|
|
@ -20,8 +20,10 @@ pub struct CSSConditionRule {
|
|||
}
|
||||
|
||||
impl CSSConditionRule {
|
||||
pub fn new_inherited(parent_stylesheet: &CSSStyleSheet,
|
||||
rules: Arc<Locked<StyleCssRules>>) -> CSSConditionRule {
|
||||
pub fn new_inherited(
|
||||
parent_stylesheet: &CSSStyleSheet,
|
||||
rules: Arc<Locked<StyleCssRules>>,
|
||||
) -> CSSConditionRule {
|
||||
CSSConditionRule {
|
||||
cssgroupingrule: CSSGroupingRule::new_inherited(parent_stylesheet, rules),
|
||||
}
|
||||
|
|
|
@ -22,8 +22,10 @@ pub struct CSSFontFaceRule {
|
|||
}
|
||||
|
||||
impl CSSFontFaceRule {
|
||||
fn new_inherited(parent_stylesheet: &CSSStyleSheet, fontfacerule: Arc<Locked<FontFaceRule>>)
|
||||
-> CSSFontFaceRule {
|
||||
fn new_inherited(
|
||||
parent_stylesheet: &CSSStyleSheet,
|
||||
fontfacerule: Arc<Locked<FontFaceRule>>,
|
||||
) -> CSSFontFaceRule {
|
||||
CSSFontFaceRule {
|
||||
cssrule: CSSRule::new_inherited(parent_stylesheet),
|
||||
fontfacerule: fontfacerule,
|
||||
|
@ -31,11 +33,19 @@ impl CSSFontFaceRule {
|
|||
}
|
||||
|
||||
#[allow(unrooted_must_root)]
|
||||
pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet,
|
||||
fontfacerule: Arc<Locked<FontFaceRule>>) -> DomRoot<CSSFontFaceRule> {
|
||||
reflect_dom_object(Box::new(CSSFontFaceRule::new_inherited(parent_stylesheet, fontfacerule)),
|
||||
pub fn new(
|
||||
window: &Window,
|
||||
parent_stylesheet: &CSSStyleSheet,
|
||||
fontfacerule: Arc<Locked<FontFaceRule>>,
|
||||
) -> DomRoot<CSSFontFaceRule> {
|
||||
reflect_dom_object(
|
||||
Box::new(CSSFontFaceRule::new_inherited(
|
||||
parent_stylesheet,
|
||||
fontfacerule,
|
||||
)),
|
||||
window,
|
||||
CSSFontFaceRuleBinding::Wrap)
|
||||
CSSFontFaceRuleBinding::Wrap,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -47,6 +57,9 @@ impl SpecificCSSRule for CSSFontFaceRule {
|
|||
|
||||
fn get_css(&self) -> DOMString {
|
||||
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 {
|
||||
pub fn new_inherited(parent_stylesheet: &CSSStyleSheet,
|
||||
rules: Arc<Locked<StyleCssRules>>) -> CSSGroupingRule {
|
||||
pub fn new_inherited(
|
||||
parent_stylesheet: &CSSStyleSheet,
|
||||
rules: Arc<Locked<StyleCssRules>>,
|
||||
) -> CSSGroupingRule {
|
||||
CSSGroupingRule {
|
||||
cssrule: CSSRule::new_inherited(parent_stylesheet),
|
||||
rules: rules,
|
||||
|
@ -36,9 +38,13 @@ impl CSSGroupingRule {
|
|||
|
||||
fn rulelist(&self) -> DomRoot<CSSRuleList> {
|
||||
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,
|
||||
RulesSource::Rules(self.rules.clone())))
|
||||
RulesSource::Rules(self.rules.clone()),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn parent_stylesheet(&self) -> &CSSStyleSheet {
|
||||
|
|
|
@ -22,9 +22,10 @@ pub struct CSSImportRule {
|
|||
}
|
||||
|
||||
impl CSSImportRule {
|
||||
fn new_inherited(parent_stylesheet: &CSSStyleSheet,
|
||||
import_rule: Arc<Locked<ImportRule>>)
|
||||
-> Self {
|
||||
fn new_inherited(
|
||||
parent_stylesheet: &CSSStyleSheet,
|
||||
import_rule: Arc<Locked<ImportRule>>,
|
||||
) -> Self {
|
||||
CSSImportRule {
|
||||
cssrule: CSSRule::new_inherited(parent_stylesheet),
|
||||
import_rule: import_rule,
|
||||
|
@ -32,12 +33,16 @@ impl CSSImportRule {
|
|||
}
|
||||
|
||||
#[allow(unrooted_must_root)]
|
||||
pub fn new(window: &Window,
|
||||
pub fn new(
|
||||
window: &Window,
|
||||
parent_stylesheet: &CSSStyleSheet,
|
||||
import_rule: Arc<Locked<ImportRule>>) -> DomRoot<Self> {
|
||||
reflect_dom_object(Box::new(Self::new_inherited(parent_stylesheet, import_rule)),
|
||||
import_rule: Arc<Locked<ImportRule>>,
|
||||
) -> DomRoot<Self> {
|
||||
reflect_dom_object(
|
||||
Box::new(Self::new_inherited(parent_stylesheet, import_rule)),
|
||||
window,
|
||||
CSSImportRuleBinding::Wrap)
|
||||
CSSImportRuleBinding::Wrap,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -49,6 +54,9 @@ impl SpecificCSSRule for CSSImportRule {
|
|||
|
||||
fn get_css(&self) -> DOMString {
|
||||
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 {
|
||||
fn new_inherited(parent_stylesheet: &CSSStyleSheet, keyframerule: Arc<Locked<Keyframe>>)
|
||||
-> CSSKeyframeRule {
|
||||
fn new_inherited(
|
||||
parent_stylesheet: &CSSStyleSheet,
|
||||
keyframerule: Arc<Locked<Keyframe>>,
|
||||
) -> CSSKeyframeRule {
|
||||
CSSKeyframeRule {
|
||||
cssrule: CSSRule::new_inherited(parent_stylesheet),
|
||||
keyframerule: keyframerule,
|
||||
|
@ -35,11 +37,19 @@ impl CSSKeyframeRule {
|
|||
}
|
||||
|
||||
#[allow(unrooted_must_root)]
|
||||
pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet,
|
||||
keyframerule: Arc<Locked<Keyframe>>) -> DomRoot<CSSKeyframeRule> {
|
||||
reflect_dom_object(Box::new(CSSKeyframeRule::new_inherited(parent_stylesheet, keyframerule)),
|
||||
pub fn new(
|
||||
window: &Window,
|
||||
parent_stylesheet: &CSSStyleSheet,
|
||||
keyframerule: Arc<Locked<Keyframe>>,
|
||||
) -> DomRoot<CSSKeyframeRule> {
|
||||
reflect_dom_object(
|
||||
Box::new(CSSKeyframeRule::new_inherited(
|
||||
parent_stylesheet,
|
||||
keyframerule,
|
||||
)),
|
||||
window,
|
||||
CSSKeyframeRuleBinding::Wrap)
|
||||
CSSKeyframeRuleBinding::Wrap,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,6 +79,9 @@ impl SpecificCSSRule for CSSKeyframeRule {
|
|||
|
||||
fn get_css(&self) -> DOMString {
|
||||
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 {
|
||||
fn new_inherited(parent_stylesheet: &CSSStyleSheet, keyframesrule: Arc<Locked<KeyframesRule>>)
|
||||
-> CSSKeyframesRule {
|
||||
fn new_inherited(
|
||||
parent_stylesheet: &CSSStyleSheet,
|
||||
keyframesrule: Arc<Locked<KeyframesRule>>,
|
||||
) -> CSSKeyframesRule {
|
||||
CSSKeyframesRule {
|
||||
cssrule: CSSRule::new_inherited(parent_stylesheet),
|
||||
keyframesrule: keyframesrule,
|
||||
|
@ -40,19 +42,29 @@ impl CSSKeyframesRule {
|
|||
}
|
||||
|
||||
#[allow(unrooted_must_root)]
|
||||
pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet,
|
||||
keyframesrule: Arc<Locked<KeyframesRule>>) -> DomRoot<CSSKeyframesRule> {
|
||||
reflect_dom_object(Box::new(CSSKeyframesRule::new_inherited(parent_stylesheet, keyframesrule)),
|
||||
pub fn new(
|
||||
window: &Window,
|
||||
parent_stylesheet: &CSSStyleSheet,
|
||||
keyframesrule: Arc<Locked<KeyframesRule>>,
|
||||
) -> DomRoot<CSSKeyframesRule> {
|
||||
reflect_dom_object(
|
||||
Box::new(CSSKeyframesRule::new_inherited(
|
||||
parent_stylesheet,
|
||||
keyframesrule,
|
||||
)),
|
||||
window,
|
||||
CSSKeyframesRuleBinding::Wrap)
|
||||
CSSKeyframesRuleBinding::Wrap,
|
||||
)
|
||||
}
|
||||
|
||||
fn rulelist(&self) -> DomRoot<CSSRuleList> {
|
||||
self.rulelist.or_init(|| {
|
||||
let parent_stylesheet = &self.upcast::<CSSRule>().parent_stylesheet();
|
||||
CSSRuleList::new(self.global().as_window(),
|
||||
CSSRuleList::new(
|
||||
self.global().as_window(),
|
||||
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();
|
||||
// This finds the *last* element matching a selector
|
||||
// because that's the rule that applies. Thus, rposition
|
||||
self.keyframesrule.read_with(&guard)
|
||||
.keyframes.iter().rposition(|frame| {
|
||||
frame.read_with(&guard).selector == sel
|
||||
})
|
||||
self.keyframesrule
|
||||
.read_with(&guard)
|
||||
.keyframes
|
||||
.iter()
|
||||
.rposition(|frame| frame.read_with(&guard).selector == sel)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
@ -86,12 +99,15 @@ impl CSSKeyframesRuleMethods for CSSKeyframesRule {
|
|||
let rule = Keyframe::parse(
|
||||
&rule,
|
||||
&style_stylesheet.contents,
|
||||
&style_stylesheet.shared_lock
|
||||
&style_stylesheet.shared_lock,
|
||||
);
|
||||
|
||||
if let Ok(rule) = rule {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
@ -105,9 +121,9 @@ impl CSSKeyframesRuleMethods for CSSKeyframesRule {
|
|||
|
||||
// https://drafts.csswg.org/css-animations/#dom-csskeyframesrule-findrule
|
||||
fn FindRule(&self, selector: DOMString) -> Option<DomRoot<CSSKeyframeRule>> {
|
||||
self.find_rule(&selector).and_then(|idx| {
|
||||
self.rulelist().item(idx as u32)
|
||||
}).and_then(DomRoot::downcast)
|
||||
self.find_rule(&selector)
|
||||
.and_then(|idx| self.rulelist().item(idx as u32))
|
||||
.and_then(DomRoot::downcast)
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/css-animations/#dom-csskeyframesrule-name
|
||||
|
@ -136,7 +152,10 @@ impl SpecificCSSRule for CSSKeyframesRule {
|
|||
|
||||
fn get_css(&self) -> DOMString {
|
||||
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) {
|
||||
|
|
|
@ -31,8 +31,10 @@ pub struct CSSMediaRule {
|
|||
}
|
||||
|
||||
impl CSSMediaRule {
|
||||
fn new_inherited(parent_stylesheet: &CSSStyleSheet, mediarule: Arc<Locked<MediaRule>>)
|
||||
-> CSSMediaRule {
|
||||
fn new_inherited(
|
||||
parent_stylesheet: &CSSStyleSheet,
|
||||
mediarule: Arc<Locked<MediaRule>>,
|
||||
) -> CSSMediaRule {
|
||||
let guard = parent_stylesheet.shared_lock().read();
|
||||
let list = mediarule.read_with(&guard).rules.clone();
|
||||
CSSMediaRule {
|
||||
|
@ -43,19 +45,26 @@ impl CSSMediaRule {
|
|||
}
|
||||
|
||||
#[allow(unrooted_must_root)]
|
||||
pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet,
|
||||
mediarule: Arc<Locked<MediaRule>>) -> DomRoot<CSSMediaRule> {
|
||||
reflect_dom_object(Box::new(CSSMediaRule::new_inherited(parent_stylesheet, mediarule)),
|
||||
pub fn new(
|
||||
window: &Window,
|
||||
parent_stylesheet: &CSSStyleSheet,
|
||||
mediarule: Arc<Locked<MediaRule>>,
|
||||
) -> DomRoot<CSSMediaRule> {
|
||||
reflect_dom_object(
|
||||
Box::new(CSSMediaRule::new_inherited(parent_stylesheet, mediarule)),
|
||||
window,
|
||||
CSSMediaRuleBinding::Wrap)
|
||||
CSSMediaRuleBinding::Wrap,
|
||||
)
|
||||
}
|
||||
|
||||
fn medialist(&self) -> DomRoot<MediaList> {
|
||||
self.medialist.or_init(|| {
|
||||
let guard = self.cssconditionrule.shared_lock().read();
|
||||
MediaList::new(self.global().as_window(),
|
||||
MediaList::new(
|
||||
self.global().as_window(),
|
||||
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 {
|
||||
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 {
|
||||
fn new_inherited(parent_stylesheet: &CSSStyleSheet, namespacerule: Arc<Locked<NamespaceRule>>)
|
||||
-> CSSNamespaceRule {
|
||||
fn new_inherited(
|
||||
parent_stylesheet: &CSSStyleSheet,
|
||||
namespacerule: Arc<Locked<NamespaceRule>>,
|
||||
) -> CSSNamespaceRule {
|
||||
CSSNamespaceRule {
|
||||
cssrule: CSSRule::new_inherited(parent_stylesheet),
|
||||
namespacerule: namespacerule,
|
||||
|
@ -32,11 +34,19 @@ impl CSSNamespaceRule {
|
|||
}
|
||||
|
||||
#[allow(unrooted_must_root)]
|
||||
pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet,
|
||||
namespacerule: Arc<Locked<NamespaceRule>>) -> DomRoot<CSSNamespaceRule> {
|
||||
reflect_dom_object(Box::new(CSSNamespaceRule::new_inherited(parent_stylesheet, namespacerule)),
|
||||
pub fn new(
|
||||
window: &Window,
|
||||
parent_stylesheet: &CSSStyleSheet,
|
||||
namespacerule: Arc<Locked<NamespaceRule>>,
|
||||
) -> DomRoot<CSSNamespaceRule> {
|
||||
reflect_dom_object(
|
||||
Box::new(CSSNamespaceRule::new_inherited(
|
||||
parent_stylesheet,
|
||||
namespacerule,
|
||||
)),
|
||||
window,
|
||||
CSSNamespaceRuleBinding::Wrap)
|
||||
CSSNamespaceRuleBinding::Wrap,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -44,8 +54,11 @@ impl CSSNamespaceRuleMethods for CSSNamespaceRule {
|
|||
// https://drafts.csswg.org/cssom/#dom-cssnamespacerule-prefix
|
||||
fn Prefix(&self) -> DOMString {
|
||||
let guard = self.cssrule.shared_lock().read();
|
||||
self.namespacerule.read_with(&guard).prefix
|
||||
.as_ref().map(|s| s.to_string().into())
|
||||
self.namespacerule
|
||||
.read_with(&guard)
|
||||
.prefix
|
||||
.as_ref()
|
||||
.map(|s| s.to_string().into())
|
||||
.unwrap_or(DOMString::new())
|
||||
}
|
||||
|
||||
|
@ -64,6 +77,9 @@ impl SpecificCSSRule for CSSNamespaceRule {
|
|||
|
||||
fn get_css(&self) -> DOMString {
|
||||
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::stylesheets::CssRule as StyleCssRule;
|
||||
|
||||
|
||||
#[dom_struct]
|
||||
pub struct CSSRule {
|
||||
reflector_: Reflector,
|
||||
|
@ -71,20 +70,39 @@ impl CSSRule {
|
|||
|
||||
// Given a StyleCssRule, create a new instance of a derived class of
|
||||
// CSSRule based on which rule it is
|
||||
pub fn new_specific(window: &Window, parent_stylesheet: &CSSStyleSheet,
|
||||
rule: StyleCssRule) -> DomRoot<CSSRule> {
|
||||
pub fn new_specific(
|
||||
window: &Window,
|
||||
parent_stylesheet: &CSSStyleSheet,
|
||||
rule: StyleCssRule,
|
||||
) -> DomRoot<CSSRule> {
|
||||
// be sure to update the match in as_specific when this is updated
|
||||
match rule {
|
||||
StyleCssRule::Import(s) => DomRoot::upcast(CSSImportRule::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::Import(s) => {
|
||||
DomRoot::upcast(CSSImportRule::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::CounterStyle(_) => unimplemented!(),
|
||||
StyleCssRule::Keyframes(s) => DomRoot::upcast(CSSKeyframesRule::new(window, parent_stylesheet, s)),
|
||||
StyleCssRule::Media(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::Keyframes(s) => {
|
||||
DomRoot::upcast(CSSKeyframesRule::new(window, parent_stylesheet, s))
|
||||
},
|
||||
StyleCssRule::Media(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::Document(_) => unimplemented!(), // TODO
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ pub struct CSSRuleList {
|
|||
parent_stylesheet: Dom<CSSStyleSheet>,
|
||||
#[ignore_malloc_size_of = "Arc"]
|
||||
rules: RulesSource,
|
||||
dom_rules: DomRefCell<Vec<MutNullableDom<CSSRule>>>
|
||||
dom_rules: DomRefCell<Vec<MutNullableDom<CSSRule>>>,
|
||||
}
|
||||
|
||||
pub enum RulesSource {
|
||||
|
@ -52,12 +52,18 @@ impl CSSRuleList {
|
|||
pub fn new_inherited(parent_stylesheet: &CSSStyleSheet, rules: RulesSource) -> CSSRuleList {
|
||||
let guard = parent_stylesheet.shared_lock().read();
|
||||
let dom_rules = match rules {
|
||||
RulesSource::Rules(ref rules) => {
|
||||
rules.read_with(&guard).0.iter().map(|_| MutNullableDom::new(None)).collect()
|
||||
}
|
||||
RulesSource::Keyframes(ref rules) => {
|
||||
rules.read_with(&guard).keyframes.iter().map(|_| MutNullableDom::new(None)).collect()
|
||||
}
|
||||
RulesSource::Rules(ref rules) => rules
|
||||
.read_with(&guard)
|
||||
.0
|
||||
.iter()
|
||||
.map(|_| MutNullableDom::new(None))
|
||||
.collect(),
|
||||
RulesSource::Keyframes(ref rules) => rules
|
||||
.read_with(&guard)
|
||||
.keyframes
|
||||
.iter()
|
||||
.map(|_| MutNullableDom::new(None))
|
||||
.collect(),
|
||||
};
|
||||
|
||||
CSSRuleList {
|
||||
|
@ -69,11 +75,16 @@ impl CSSRuleList {
|
|||
}
|
||||
|
||||
#[allow(unrooted_must_root)]
|
||||
pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet,
|
||||
rules: RulesSource) -> DomRoot<CSSRuleList> {
|
||||
reflect_dom_object(Box::new(CSSRuleList::new_inherited(parent_stylesheet, rules)),
|
||||
pub fn new(
|
||||
window: &Window,
|
||||
parent_stylesheet: &CSSStyleSheet,
|
||||
rules: RulesSource,
|
||||
) -> DomRoot<CSSRuleList> {
|
||||
reflect_dom_object(
|
||||
Box::new(CSSRuleList::new_inherited(parent_stylesheet, rules)),
|
||||
window,
|
||||
CSSRuleListBinding::Wrap)
|
||||
CSSRuleListBinding::Wrap,
|
||||
)
|
||||
}
|
||||
|
||||
/// 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 new_rule = css_rules.with_raw_offset_arc(|arc| {
|
||||
arc.insert_rule(&parent_stylesheet.shared_lock,
|
||||
arc.insert_rule(
|
||||
&parent_stylesheet.shared_lock,
|
||||
rule,
|
||||
&parent_stylesheet.contents,
|
||||
index,
|
||||
nested,
|
||||
None)
|
||||
None,
|
||||
)
|
||||
})?;
|
||||
|
||||
|
||||
let parent_stylesheet = &*self.parent_stylesheet;
|
||||
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)
|
||||
}
|
||||
|
||||
|
@ -118,7 +132,7 @@ impl CSSRuleList {
|
|||
dom_rules[index].get().map(|r| r.detach());
|
||||
dom_rules.remove(index);
|
||||
Ok(())
|
||||
}
|
||||
},
|
||||
RulesSource::Keyframes(ref kf) => {
|
||||
// https://drafts.csswg.org/css-animations/#dom-csskeyframesrule-deleterule
|
||||
let mut dom_rules = self.dom_rules.borrow_mut();
|
||||
|
@ -126,7 +140,7 @@ impl CSSRuleList {
|
|||
dom_rules.remove(index);
|
||||
kf.write_with(&mut guard).keyframes.remove(index);
|
||||
Ok(())
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -143,20 +157,17 @@ impl CSSRuleList {
|
|||
let parent_stylesheet = &self.parent_stylesheet;
|
||||
let guard = parent_stylesheet.shared_lock().read();
|
||||
match self.rules {
|
||||
RulesSource::Rules(ref rules) => {
|
||||
CSSRule::new_specific(self.global().as_window(),
|
||||
RulesSource::Rules(ref rules) => CSSRule::new_specific(
|
||||
self.global().as_window(),
|
||||
parent_stylesheet,
|
||||
rules.read_with(&guard).0[idx as usize].clone())
|
||||
}
|
||||
RulesSource::Keyframes(ref rules) => {
|
||||
DomRoot::upcast(CSSKeyframeRule::new(self.global().as_window(),
|
||||
rules.read_with(&guard).0[idx as usize].clone(),
|
||||
),
|
||||
RulesSource::Keyframes(ref rules) => DomRoot::upcast(CSSKeyframeRule::new(
|
||||
self.global().as_window(),
|
||||
parent_stylesheet,
|
||||
rules.read_with(&guard)
|
||||
.keyframes[idx as usize]
|
||||
.clone()))
|
||||
rules.read_with(&guard).keyframes[idx as usize].clone(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
})
|
||||
}
|
||||
|
@ -190,4 +201,3 @@ impl CSSRuleListMethods for CSSRuleList {
|
|||
self.Item(index)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -36,16 +36,18 @@ pub struct CSSStyleDeclaration {
|
|||
#[must_root]
|
||||
pub enum CSSStyleOwner {
|
||||
Element(Dom<Element>),
|
||||
CSSRule(Dom<CSSRule>,
|
||||
#[ignore_malloc_size_of = "Arc"]
|
||||
Arc<Locked<PropertyDeclarationBlock>>),
|
||||
CSSRule(
|
||||
Dom<CSSRule>,
|
||||
#[ignore_malloc_size_of = "Arc"] Arc<Locked<PropertyDeclarationBlock>>,
|
||||
),
|
||||
}
|
||||
|
||||
impl CSSStyleOwner {
|
||||
// Mutate the declaration block associated to this style owner, and
|
||||
// optionally indicate if it has changed (assumed to be true).
|
||||
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.
|
||||
//
|
||||
|
@ -87,9 +89,10 @@ impl CSSStyleOwner {
|
|||
let guard = shared_lock.read();
|
||||
let mut serialization = String::new();
|
||||
pdb.read_with(&guard).to_css(&mut serialization).unwrap();
|
||||
el.set_attribute(&local_name!("style"),
|
||||
AttrValue::Declaration(serialization,
|
||||
pdb));
|
||||
el.set_attribute(
|
||||
&local_name!("style"),
|
||||
AttrValue::Declaration(serialization, pdb),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// Remember to put it back.
|
||||
|
@ -97,7 +100,7 @@ impl CSSStyleOwner {
|
|||
}
|
||||
|
||||
result
|
||||
}
|
||||
},
|
||||
CSSStyleOwner::CSSRule(ref rule, ref pdb) => {
|
||||
let result = {
|
||||
let mut guard = rule.shared_lock().write();
|
||||
|
@ -106,34 +109,36 @@ impl CSSStyleOwner {
|
|||
if changed {
|
||||
// If this is changed, see also
|
||||
// CSSStyleRule::SetSelectorText, which does the same thing.
|
||||
rule.global().as_window().Document().invalidate_stylesheets();
|
||||
rule.global()
|
||||
.as_window()
|
||||
.Document()
|
||||
.invalidate_stylesheets();
|
||||
}
|
||||
result
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn with_block<F, R>(&self, f: F) -> R
|
||||
where F: FnOnce(&PropertyDeclarationBlock) -> R,
|
||||
where
|
||||
F: FnOnce(&PropertyDeclarationBlock) -> R,
|
||||
{
|
||||
match *self {
|
||||
CSSStyleOwner::Element(ref el) => {
|
||||
match *el.style_attribute().borrow() {
|
||||
CSSStyleOwner::Element(ref el) => match *el.style_attribute().borrow() {
|
||||
Some(ref pdb) => {
|
||||
let document = document_from_node(&**el);
|
||||
let guard = document.style_shared_lock().read();
|
||||
f(pdb.read_with(&guard))
|
||||
}
|
||||
},
|
||||
None => {
|
||||
let pdb = PropertyDeclarationBlock::new();
|
||||
f(&pdb)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
CSSStyleOwner::CSSRule(ref rule, ref pdb) => {
|
||||
let guard = rule.shared_lock().read();
|
||||
f(pdb.read_with(&guard))
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -147,9 +152,12 @@ impl CSSStyleOwner {
|
|||
fn base_url(&self) -> ServoUrl {
|
||||
match *self {
|
||||
CSSStyleOwner::Element(ref el) => window_from_node(&**el).Document().base_url(),
|
||||
CSSStyleOwner::CSSRule(ref rule, _) => {
|
||||
(*rule.parent_stylesheet().style_stylesheet().contents.url_data.read()).clone()
|
||||
}
|
||||
CSSStyleOwner::CSSRule(ref rule, _) => (*rule
|
||||
.parent_stylesheet()
|
||||
.style_stylesheet()
|
||||
.contents
|
||||
.url_data
|
||||
.read()).clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -181,10 +189,7 @@ macro_rules! css_properties(
|
|||
);
|
||||
);
|
||||
|
||||
fn remove_property(
|
||||
decls: &mut PropertyDeclarationBlock,
|
||||
id: &PropertyId,
|
||||
) -> bool {
|
||||
fn remove_property(decls: &mut PropertyDeclarationBlock, id: &PropertyId) -> bool {
|
||||
let first_declaration = decls.first_declaration_to_remove(id);
|
||||
let first_declaration = match first_declaration {
|
||||
Some(i) => i,
|
||||
|
@ -196,10 +201,11 @@ fn remove_property(
|
|||
|
||||
impl CSSStyleDeclaration {
|
||||
#[allow(unrooted_must_root)]
|
||||
pub fn new_inherited(owner: CSSStyleOwner,
|
||||
pub fn new_inherited(
|
||||
owner: CSSStyleOwner,
|
||||
pseudo: Option<PseudoElement>,
|
||||
modification_access: CSSModificationAccess)
|
||||
-> CSSStyleDeclaration {
|
||||
modification_access: CSSModificationAccess,
|
||||
) -> CSSStyleDeclaration {
|
||||
CSSStyleDeclaration {
|
||||
reflector_: Reflector::new(),
|
||||
owner: owner,
|
||||
|
@ -209,22 +215,28 @@ impl CSSStyleDeclaration {
|
|||
}
|
||||
|
||||
#[allow(unrooted_must_root)]
|
||||
pub fn new(global: &Window,
|
||||
pub fn new(
|
||||
global: &Window,
|
||||
owner: CSSStyleOwner,
|
||||
pseudo: Option<PseudoElement>,
|
||||
modification_access: CSSModificationAccess)
|
||||
-> DomRoot<CSSStyleDeclaration> {
|
||||
modification_access: CSSModificationAccess,
|
||||
) -> DomRoot<CSSStyleDeclaration> {
|
||||
reflect_dom_object(
|
||||
Box::new(CSSStyleDeclaration::new_inherited(owner, pseudo, modification_access)),
|
||||
Box::new(CSSStyleDeclaration::new_inherited(
|
||||
owner,
|
||||
pseudo,
|
||||
modification_access,
|
||||
)),
|
||||
global,
|
||||
CSSStyleDeclarationBinding::Wrap
|
||||
CSSStyleDeclarationBinding::Wrap,
|
||||
)
|
||||
}
|
||||
|
||||
fn get_computed_style(&self, property: PropertyId) -> DOMString {
|
||||
match self.owner {
|
||||
CSSStyleOwner::CSSRule(..) =>
|
||||
panic!("get_computed_style called on CSSStyleDeclaration with a CSSRule owner"),
|
||||
CSSStyleOwner::CSSRule(..) => {
|
||||
panic!("get_computed_style called on CSSStyleDeclaration with a CSSRule owner")
|
||||
},
|
||||
CSSStyleOwner::Element(ref el) => {
|
||||
let node = el.upcast::<Node>();
|
||||
if !node.is_in_doc() {
|
||||
|
@ -234,7 +246,7 @@ impl CSSStyleDeclaration {
|
|||
}
|
||||
let addr = node.to_trusted_node_address();
|
||||
window_from_node(node).resolved_style_query(addr, self.pseudo.clone(), property)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -277,7 +289,7 @@ impl CSSStyleDeclaration {
|
|||
_ => {
|
||||
*changed = false;
|
||||
return Ok(());
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// Step 5
|
||||
|
@ -300,12 +312,11 @@ impl CSSStyleDeclaration {
|
|||
Err(_) => {
|
||||
*changed = false;
|
||||
return Ok(());
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
let mut updates = Default::default();
|
||||
*changed =
|
||||
pdb.prepare_for_update(&declarations, importance, &mut updates);
|
||||
*changed = pdb.prepare_for_update(&declarations, importance, &mut updates);
|
||||
|
||||
if !*changed {
|
||||
return Ok(());
|
||||
|
@ -323,9 +334,7 @@ impl CSSStyleDeclaration {
|
|||
impl CSSStyleDeclarationMethods for CSSStyleDeclaration {
|
||||
// https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-length
|
||||
fn Length(&self) -> u32 {
|
||||
self.owner.with_block(|pdb| {
|
||||
pdb.declarations().len() as u32
|
||||
})
|
||||
self.owner.with_block(|pdb| pdb.declarations().len() as u32)
|
||||
}
|
||||
|
||||
// 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
|
||||
fn SetProperty(&self,
|
||||
fn SetProperty(
|
||||
&self,
|
||||
property: DOMString,
|
||||
value: DOMString,
|
||||
priority: DOMString)
|
||||
-> ErrorResult {
|
||||
priority: DOMString,
|
||||
) -> ErrorResult {
|
||||
// Step 3
|
||||
let id = match PropertyId::parse_enabled_for_all_content(&property) {
|
||||
Ok(id) => id,
|
||||
|
@ -444,10 +454,12 @@ impl CSSStyleDeclarationMethods for CSSStyleDeclaration {
|
|||
let quirks_mode = window.Document().quirks_mode();
|
||||
self.owner.mutate_associated_block(|pdb, _changed| {
|
||||
// Step 3
|
||||
*pdb = parse_style_attribute(&value,
|
||||
*pdb = parse_style_attribute(
|
||||
&value,
|
||||
&self.owner.base_url(),
|
||||
window.css_error_reporter(),
|
||||
quirks_mode);
|
||||
quirks_mode,
|
||||
);
|
||||
});
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -31,8 +31,10 @@ pub struct CSSStyleRule {
|
|||
}
|
||||
|
||||
impl CSSStyleRule {
|
||||
fn new_inherited(parent_stylesheet: &CSSStyleSheet, stylerule: Arc<Locked<StyleRule>>)
|
||||
-> CSSStyleRule {
|
||||
fn new_inherited(
|
||||
parent_stylesheet: &CSSStyleSheet,
|
||||
stylerule: Arc<Locked<StyleRule>>,
|
||||
) -> CSSStyleRule {
|
||||
CSSStyleRule {
|
||||
cssrule: CSSRule::new_inherited(parent_stylesheet),
|
||||
stylerule: stylerule,
|
||||
|
@ -41,11 +43,16 @@ impl CSSStyleRule {
|
|||
}
|
||||
|
||||
#[allow(unrooted_must_root)]
|
||||
pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet,
|
||||
stylerule: Arc<Locked<StyleRule>>) -> DomRoot<CSSStyleRule> {
|
||||
reflect_dom_object(Box::new(CSSStyleRule::new_inherited(parent_stylesheet, stylerule)),
|
||||
pub fn new(
|
||||
window: &Window,
|
||||
parent_stylesheet: &CSSStyleSheet,
|
||||
stylerule: Arc<Locked<StyleRule>>,
|
||||
) -> DomRoot<CSSStyleRule> {
|
||||
reflect_dom_object(
|
||||
Box::new(CSSStyleRule::new_inherited(parent_stylesheet, stylerule)),
|
||||
window,
|
||||
CSSStyleRuleBinding::Wrap)
|
||||
CSSStyleRuleBinding::Wrap,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -57,7 +64,10 @@ impl SpecificCSSRule for CSSStyleRule {
|
|||
|
||||
fn get_css(&self) -> DOMString {
|
||||
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(),
|
||||
CSSStyleOwner::CSSRule(
|
||||
Dom::from_ref(self.upcast()),
|
||||
self.stylerule.read_with(&guard).block.clone()
|
||||
self.stylerule.read_with(&guard).block.clone(),
|
||||
),
|
||||
None,
|
||||
CSSModificationAccess::ReadWrite
|
||||
CSSModificationAccess::ReadWrite,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
@ -89,7 +99,13 @@ impl CSSStyleRuleMethods for CSSStyleRule {
|
|||
fn SetSelectorText(&self, value: DOMString) {
|
||||
// It's not clear from the spec if we should use the stylesheet's namespaces.
|
||||
// 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 {
|
||||
stylesheet_origin: Origin::Author,
|
||||
namespaces: &namespaces,
|
||||
|
@ -104,7 +120,10 @@ impl CSSStyleRuleMethods for CSSStyleRule {
|
|||
mem::swap(&mut stylerule.selectors, &mut s);
|
||||
// It seems like we will want to avoid having to invalidate all
|
||||
// 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 {
|
||||
fn new_inherited(owner: &Element,
|
||||
fn new_inherited(
|
||||
owner: &Element,
|
||||
type_: DOMString,
|
||||
href: Option<DOMString>,
|
||||
title: Option<DOMString>,
|
||||
stylesheet: Arc<StyleStyleSheet>) -> CSSStyleSheet {
|
||||
stylesheet: Arc<StyleStyleSheet>,
|
||||
) -> CSSStyleSheet {
|
||||
CSSStyleSheet {
|
||||
stylesheet: StyleSheet::new_inherited(type_, href, title),
|
||||
owner: Dom::from_ref(owner),
|
||||
|
@ -45,25 +47,27 @@ impl CSSStyleSheet {
|
|||
}
|
||||
|
||||
#[allow(unrooted_must_root)]
|
||||
pub fn new(window: &Window,
|
||||
pub fn new(
|
||||
window: &Window,
|
||||
owner: &Element,
|
||||
type_: DOMString,
|
||||
href: Option<DOMString>,
|
||||
title: Option<DOMString>,
|
||||
stylesheet: Arc<StyleStyleSheet>) -> DomRoot<CSSStyleSheet> {
|
||||
reflect_dom_object(Box::new(CSSStyleSheet::new_inherited(owner, type_, href, title, stylesheet)),
|
||||
stylesheet: Arc<StyleStyleSheet>,
|
||||
) -> DomRoot<CSSStyleSheet> {
|
||||
reflect_dom_object(
|
||||
Box::new(CSSStyleSheet::new_inherited(
|
||||
owner, type_, href, title, stylesheet,
|
||||
)),
|
||||
window,
|
||||
CSSStyleSheetBinding::Wrap)
|
||||
CSSStyleSheetBinding::Wrap,
|
||||
)
|
||||
}
|
||||
|
||||
fn rulelist(&self) -> DomRoot<CSSRuleList> {
|
||||
self.rulelist.or_init(|| {
|
||||
let rules = self.style_stylesheet.contents.rules.clone();
|
||||
CSSRuleList::new(
|
||||
self.global().as_window(),
|
||||
self,
|
||||
RulesSource::Rules(rules)
|
||||
)
|
||||
CSSRuleList::new(self.global().as_window(), self, RulesSource::Rules(rules))
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -73,7 +77,10 @@ impl CSSStyleSheet {
|
|||
|
||||
pub fn set_disabled(&self, disabled: bool) {
|
||||
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() {
|
||||
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
|
||||
|
@ -115,4 +123,3 @@ impl CSSStyleSheetMethods for CSSStyleSheet {
|
|||
self.rulelist().remove_rule(index)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -48,7 +48,9 @@ impl CSSStyleValue {
|
|||
pub fn get_url(&self, base_url: ServoUrl) -> Option<ServoUrl> {
|
||||
let mut input = ParserInput::new(&*self.value);
|
||||
let mut parser = Parser::new(&mut input);
|
||||
parser.expect_url().ok()
|
||||
parser
|
||||
.expect_url()
|
||||
.ok()
|
||||
.and_then(|string| base_url.join(&*string).ok())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,8 +28,10 @@ pub struct CSSSupportsRule {
|
|||
}
|
||||
|
||||
impl CSSSupportsRule {
|
||||
fn new_inherited(parent_stylesheet: &CSSStyleSheet, supportsrule: Arc<Locked<SupportsRule>>)
|
||||
-> CSSSupportsRule {
|
||||
fn new_inherited(
|
||||
parent_stylesheet: &CSSStyleSheet,
|
||||
supportsrule: Arc<Locked<SupportsRule>>,
|
||||
) -> CSSSupportsRule {
|
||||
let guard = parent_stylesheet.shared_lock().read();
|
||||
let list = supportsrule.read_with(&guard).rules.clone();
|
||||
CSSSupportsRule {
|
||||
|
@ -39,11 +41,19 @@ impl CSSSupportsRule {
|
|||
}
|
||||
|
||||
#[allow(unrooted_must_root)]
|
||||
pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet,
|
||||
supportsrule: Arc<Locked<SupportsRule>>) -> DomRoot<CSSSupportsRule> {
|
||||
reflect_dom_object(Box::new(CSSSupportsRule::new_inherited(parent_stylesheet, supportsrule)),
|
||||
pub fn new(
|
||||
window: &Window,
|
||||
parent_stylesheet: &CSSStyleSheet,
|
||||
supportsrule: Arc<Locked<SupportsRule>>,
|
||||
) -> DomRoot<CSSSupportsRule> {
|
||||
reflect_dom_object(
|
||||
Box::new(CSSSupportsRule::new_inherited(
|
||||
parent_stylesheet,
|
||||
supportsrule,
|
||||
)),
|
||||
window,
|
||||
CSSSupportsRuleBinding::Wrap)
|
||||
CSSSupportsRuleBinding::Wrap,
|
||||
)
|
||||
}
|
||||
|
||||
/// <https://drafts.csswg.org/css-conditional-3/#the-csssupportsrule-interface>
|
||||
|
@ -88,6 +98,9 @@ impl SpecificCSSRule for CSSSupportsRule {
|
|||
|
||||
fn get_css(&self) -> DOMString {
|
||||
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 {
|
||||
fn new_inherited(parent_stylesheet: &CSSStyleSheet, viewportrule: Arc<Locked<ViewportRule>>) -> CSSViewportRule {
|
||||
fn new_inherited(
|
||||
parent_stylesheet: &CSSStyleSheet,
|
||||
viewportrule: Arc<Locked<ViewportRule>>,
|
||||
) -> CSSViewportRule {
|
||||
CSSViewportRule {
|
||||
cssrule: CSSRule::new_inherited(parent_stylesheet),
|
||||
viewportrule: viewportrule,
|
||||
|
@ -30,11 +33,19 @@ impl CSSViewportRule {
|
|||
}
|
||||
|
||||
#[allow(unrooted_must_root)]
|
||||
pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet,
|
||||
viewportrule: Arc<Locked<ViewportRule>>) -> DomRoot<CSSViewportRule> {
|
||||
reflect_dom_object(Box::new(CSSViewportRule::new_inherited(parent_stylesheet, viewportrule)),
|
||||
pub fn new(
|
||||
window: &Window,
|
||||
parent_stylesheet: &CSSStyleSheet,
|
||||
viewportrule: Arc<Locked<ViewportRule>>,
|
||||
) -> DomRoot<CSSViewportRule> {
|
||||
reflect_dom_object(
|
||||
Box::new(CSSViewportRule::new_inherited(
|
||||
parent_stylesheet,
|
||||
viewportrule,
|
||||
)),
|
||||
window,
|
||||
CSSViewportRuleBinding::Wrap)
|
||||
CSSViewportRuleBinding::Wrap,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -46,6 +57,9 @@ impl SpecificCSSRule for CSSViewportRule {
|
|||
|
||||
fn get_css(&self) -> DOMString {
|
||||
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> {
|
||||
reflect_dom_object(Box::new(CustomElementRegistry::new_inherited(window)),
|
||||
reflect_dom_object(
|
||||
Box::new(CustomElementRegistry::new_inherited(window)),
|
||||
window,
|
||||
CustomElementRegistryBinding::Wrap)
|
||||
CustomElementRegistryBinding::Wrap,
|
||||
)
|
||||
}
|
||||
|
||||
/// Cleans up any active promises
|
||||
|
@ -83,40 +85,57 @@ impl CustomElementRegistry {
|
|||
}
|
||||
|
||||
/// <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,
|
||||
is: Option<&LocalName>)
|
||||
-> Option<Rc<CustomElementDefinition>> {
|
||||
self.definitions.borrow().values().find(|definition| {
|
||||
is: Option<&LocalName>,
|
||||
) -> Option<Rc<CustomElementDefinition>> {
|
||||
self.definitions
|
||||
.borrow()
|
||||
.values()
|
||||
.find(|definition| {
|
||||
// Step 4-5
|
||||
definition.local_name == *local_name &&
|
||||
(definition.name == *local_name || Some(&definition.name) == is)
|
||||
}).cloned()
|
||||
}
|
||||
|
||||
pub fn lookup_definition_by_constructor(&self, constructor: HandleObject) -> Option<Rc<CustomElementDefinition>> {
|
||||
self.definitions.borrow().values().find(|definition| {
|
||||
definition.constructor.callback() == constructor.get()
|
||||
}).cloned()
|
||||
pub fn lookup_definition_by_constructor(
|
||||
&self,
|
||||
constructor: HandleObject,
|
||||
) -> Option<Rc<CustomElementDefinition>> {
|
||||
self.definitions
|
||||
.borrow()
|
||||
.values()
|
||||
.find(|definition| definition.constructor.callback() == constructor.get())
|
||||
.cloned()
|
||||
}
|
||||
|
||||
/// <https://html.spec.whatwg.org/multipage/#dom-customelementregistry-define>
|
||||
/// Steps 10.1, 10.2
|
||||
#[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>();
|
||||
unsafe {
|
||||
// Step 10.1
|
||||
if !JS_GetProperty(global_scope.get_cx(),
|
||||
if !JS_GetProperty(
|
||||
global_scope.get_cx(),
|
||||
constructor,
|
||||
b"prototype\0".as_ptr() as *const _,
|
||||
prototype) {
|
||||
prototype,
|
||||
) {
|
||||
return Err(Error::JSFailed);
|
||||
}
|
||||
|
||||
// Step 10.2
|
||||
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(())
|
||||
|
@ -143,10 +162,14 @@ impl CustomElementRegistry {
|
|||
fn get_observed_attributes(&self, constructor: HandleObject) -> Fallible<Vec<DOMString>> {
|
||||
let cx = self.window.get_cx();
|
||||
rooted!(in(cx) let mut observed_attributes = UndefinedValue());
|
||||
if unsafe { !JS_GetProperty(cx,
|
||||
if unsafe {
|
||||
!JS_GetProperty(
|
||||
cx,
|
||||
constructor,
|
||||
b"observedAttributes\0".as_ptr() as *const _,
|
||||
observed_attributes.handle_mut()) } {
|
||||
observed_attributes.handle_mut(),
|
||||
)
|
||||
} {
|
||||
return Err(Error::JSFailed);
|
||||
}
|
||||
|
||||
|
@ -155,7 +178,11 @@ impl CustomElementRegistry {
|
|||
}
|
||||
|
||||
let conversion = unsafe {
|
||||
FromJSValConvertible::from_jsval(cx, observed_attributes.handle(), StringificationBehavior::Default)
|
||||
FromJSValConvertible::from_jsval(
|
||||
cx,
|
||||
observed_attributes.handle(),
|
||||
StringificationBehavior::Default,
|
||||
)
|
||||
};
|
||||
match conversion {
|
||||
Ok(ConversionResult::Success(attributes)) => Ok(attributes),
|
||||
|
@ -176,7 +203,12 @@ unsafe fn get_callback(
|
|||
rooted!(in(cx) let mut callback = UndefinedValue());
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
|
@ -195,9 +227,10 @@ impl CustomElementRegistryMethods for CustomElementRegistry {
|
|||
#[allow(unsafe_code, unrooted_must_root)]
|
||||
/// <https://html.spec.whatwg.org/multipage/#dom-customelementregistry-define>
|
||||
fn Define(
|
||||
&self, name: DOMString,
|
||||
&self,
|
||||
name: DOMString,
|
||||
constructor_: Rc<CustomElementConstructor>,
|
||||
options: &ElementDefinitionOptions
|
||||
options: &ElementDefinitionOptions,
|
||||
) -> ErrorResult {
|
||||
let cx = self.window.get_cx();
|
||||
rooted!(in(cx) let constructor = constructor_.callback());
|
||||
|
@ -213,12 +246,14 @@ impl CustomElementRegistryMethods for CustomElementRegistry {
|
|||
}
|
||||
|
||||
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
|
||||
if !is_valid_custom_element_name(&name) {
|
||||
return Err(Error::Syntax)
|
||||
return Err(Error::Syntax);
|
||||
}
|
||||
|
||||
// Step 3
|
||||
|
@ -227,7 +262,12 @@ impl CustomElementRegistryMethods for CustomElementRegistry {
|
|||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
|
@ -238,12 +278,12 @@ impl CustomElementRegistryMethods for CustomElementRegistry {
|
|||
let local_name = if let Some(ref extended_name) = *extends {
|
||||
// Step 7.1
|
||||
if is_valid_custom_element_name(extended_name) {
|
||||
return Err(Error::NotSupported)
|
||||
return Err(Error::NotSupported);
|
||||
}
|
||||
|
||||
// Step 7.2
|
||||
if !is_extendable_element_interface(extended_name) {
|
||||
return Err(Error::NotSupported)
|
||||
return Err(Error::NotSupported);
|
||||
}
|
||||
|
||||
LocalName::from(&**extended_name)
|
||||
|
@ -300,20 +340,28 @@ impl CustomElementRegistryMethods for CustomElementRegistry {
|
|||
self.element_definition_is_running.set(false);
|
||||
|
||||
// Step 11
|
||||
let definition = Rc::new(CustomElementDefinition::new(name.clone(),
|
||||
let definition = Rc::new(CustomElementDefinition::new(
|
||||
name.clone(),
|
||||
local_name.clone(),
|
||||
constructor_,
|
||||
observed_attributes,
|
||||
callbacks));
|
||||
callbacks,
|
||||
));
|
||||
|
||||
// Step 12
|
||||
self.definitions.borrow_mut().insert(name.clone(), definition.clone());
|
||||
self.definitions
|
||||
.borrow_mut()
|
||||
.insert(name.clone(), definition.clone());
|
||||
|
||||
// Step 13
|
||||
let document = self.window.Document();
|
||||
|
||||
// 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();
|
||||
if *candidate.local_name() == local_name &&
|
||||
*candidate.namespace() == ns!(html) &&
|
||||
|
@ -336,7 +384,9 @@ impl CustomElementRegistryMethods for CustomElementRegistry {
|
|||
match self.definitions.borrow().get(&LocalName::from(&*name)) {
|
||||
Some(definition) => {
|
||||
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()
|
||||
},
|
||||
None => UndefinedValue(),
|
||||
|
@ -353,14 +403,14 @@ impl CustomElementRegistryMethods for CustomElementRegistry {
|
|||
if !is_valid_custom_element_name(&name) {
|
||||
let promise = Promise::new(global_scope);
|
||||
promise.reject_native(&DOMException::new(global_scope, DOMErrorName::SyntaxError));
|
||||
return promise
|
||||
return promise;
|
||||
}
|
||||
|
||||
// Step 2
|
||||
if self.definitions.borrow().contains_key(&name) {
|
||||
let promise = Promise::new(global_scope);
|
||||
promise.resolve_native(&UndefinedValue());
|
||||
return promise
|
||||
return promise;
|
||||
}
|
||||
|
||||
// Step 3
|
||||
|
@ -417,12 +467,13 @@ pub struct CustomElementDefinition {
|
|||
}
|
||||
|
||||
impl CustomElementDefinition {
|
||||
fn new(name: LocalName,
|
||||
fn new(
|
||||
name: LocalName,
|
||||
local_name: LocalName,
|
||||
constructor: Rc<CustomElementConstructor>,
|
||||
observed_attributes: Vec<DOMString>,
|
||||
callbacks: LifecycleCallbacks)
|
||||
-> CustomElementDefinition {
|
||||
callbacks: LifecycleCallbacks,
|
||||
) -> CustomElementDefinition {
|
||||
CustomElementDefinition {
|
||||
name: name,
|
||||
local_name: local_name,
|
||||
|
@ -440,7 +491,11 @@ impl CustomElementDefinition {
|
|||
|
||||
/// https://dom.spec.whatwg.org/#concept-create-element Step 6.1
|
||||
#[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 cx = window.get_cx();
|
||||
// Step 2
|
||||
|
@ -456,16 +511,22 @@ impl CustomElementDefinition {
|
|||
}
|
||||
|
||||
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::Failure(..)) =>
|
||||
return Err(Error::Type("Constructor did not return a DOM node".to_owned())),
|
||||
Ok(ConversionResult::Failure(..)) => {
|
||||
return Err(Error::Type(
|
||||
"Constructor did not return a DOM node".to_owned(),
|
||||
))
|
||||
},
|
||||
_ => return Err(Error::JSFailed),
|
||||
};
|
||||
|
||||
// Step 3
|
||||
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
|
||||
|
@ -503,17 +564,27 @@ pub fn upgrade_element(definition: Rc<CustomElementDefinition>, element: &Elemen
|
|||
let local_name = attr.local_name().clone();
|
||||
let value = DOMString::from(&**attr.value());
|
||||
let namespace = attr.namespace().clone();
|
||||
ScriptThread::enqueue_callback_reaction(element,
|
||||
CallbackReaction::AttributeChanged(local_name, None, Some(value), namespace), Some(definition.clone()));
|
||||
ScriptThread::enqueue_callback_reaction(
|
||||
element,
|
||||
CallbackReaction::AttributeChanged(local_name, None, Some(value), namespace),
|
||||
Some(definition.clone()),
|
||||
);
|
||||
}
|
||||
|
||||
// Step 4
|
||||
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
|
||||
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
|
||||
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>
|
||||
/// Steps 7.1-7.2
|
||||
#[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 cx = window.get_cx();
|
||||
rooted!(in(cx) let constructor_val = ObjectValue(constructor.callback()));
|
||||
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>());
|
||||
{
|
||||
// Go into the constructor's compartment
|
||||
let _ac = JSAutoCompartment::new(cx, constructor.callback());
|
||||
let args = HandleValueArray::new();
|
||||
// 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);
|
||||
}
|
||||
// Step 7.2
|
||||
let mut same = false;
|
||||
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);
|
||||
}
|
||||
if !same {
|
||||
|
@ -583,7 +673,9 @@ pub fn try_upgrade_element(element: &Element) {
|
|||
let namespace = element.namespace();
|
||||
let local_name = element.local_name();
|
||||
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
|
||||
ScriptThread::enqueue_upgrade_reaction(element, definition);
|
||||
}
|
||||
|
@ -592,14 +684,10 @@ pub fn try_upgrade_element(element: &Element) {
|
|||
#[derive(JSTraceable, MallocSizeOf)]
|
||||
#[must_root]
|
||||
pub enum CustomElementReaction {
|
||||
Upgrade(
|
||||
#[ignore_malloc_size_of = "Rc"]
|
||||
Rc<CustomElementDefinition>
|
||||
),
|
||||
Upgrade(#[ignore_malloc_size_of = "Rc"] Rc<CustomElementDefinition>),
|
||||
Callback(
|
||||
#[ignore_malloc_size_of = "Rc"]
|
||||
Rc<Function>,
|
||||
Box<[Heap<JSVal>]>
|
||||
#[ignore_malloc_size_of = "Rc"] Rc<Function>,
|
||||
Box<[Heap<JSVal>]>,
|
||||
),
|
||||
}
|
||||
|
||||
|
@ -609,12 +697,17 @@ impl CustomElementReaction {
|
|||
pub fn invoke(&self, element: &Element) {
|
||||
// Step 2.1
|
||||
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) => {
|
||||
// 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);
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -675,7 +768,8 @@ impl CustomElementReactionStack {
|
|||
self.backup_queue.invoke_reactions();
|
||||
|
||||
// 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>
|
||||
|
@ -693,7 +787,8 @@ impl CustomElementReactionStack {
|
|||
}
|
||||
|
||||
// Step 1.3
|
||||
self.processing_backup_element_queue.set(BackupElementQueueFlag::Processing);
|
||||
self.processing_backup_element_queue
|
||||
.set(BackupElementQueueFlag::Processing);
|
||||
|
||||
// Step 4
|
||||
ScriptThread::enqueue_microtask(Microtask::CustomElementReaction);
|
||||
|
@ -702,10 +797,12 @@ impl CustomElementReactionStack {
|
|||
|
||||
/// <https://html.spec.whatwg.org/multipage/#enqueue-a-custom-element-callback-reaction>
|
||||
#[allow(unsafe_code)]
|
||||
pub fn enqueue_callback_reaction(&self,
|
||||
pub fn enqueue_callback_reaction(
|
||||
&self,
|
||||
element: &Element,
|
||||
reaction: CallbackReaction,
|
||||
definition: Option<Rc<CustomElementDefinition>>) {
|
||||
definition: Option<Rc<CustomElementDefinition>>,
|
||||
) {
|
||||
// Step 1
|
||||
let definition = match definition.or_else(|| element.get_custom_element_definition()) {
|
||||
Some(definition) => definition,
|
||||
|
@ -714,8 +811,13 @@ impl CustomElementReactionStack {
|
|||
|
||||
// Step 2
|
||||
let (callback, args) = match reaction {
|
||||
CallbackReaction::Connected => (definition.callbacks.connected_callback.clone(), Vec::new()),
|
||||
CallbackReaction::Disconnected => (definition.callbacks.disconnected_callback.clone(), Vec::new()),
|
||||
CallbackReaction::Connected => {
|
||||
(definition.callbacks.connected_callback.clone(), Vec::new())
|
||||
},
|
||||
CallbackReaction::Disconnected => (
|
||||
definition.callbacks.disconnected_callback.clone(),
|
||||
Vec::new(),
|
||||
),
|
||||
CallbackReaction::Adopted(ref old_doc, ref new_doc) => {
|
||||
let args = vec![Heap::default(), Heap::default()];
|
||||
args[0].set(ObjectValue(old_doc.reflector().get_jsobject().get()));
|
||||
|
@ -724,7 +826,11 @@ impl CustomElementReactionStack {
|
|||
},
|
||||
CallbackReaction::AttributeChanged(local_name, old_val, val, namespace) => {
|
||||
// Step 4
|
||||
if !definition.observed_attributes.iter().any(|attr| *attr == *local_name) {
|
||||
if !definition
|
||||
.observed_attributes
|
||||
.iter()
|
||||
.any(|attr| *attr == *local_name)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -732,31 +838,47 @@ impl CustomElementReactionStack {
|
|||
|
||||
let local_name = DOMString::from(&*local_name);
|
||||
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());
|
||||
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());
|
||||
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());
|
||||
if namespace != ns!() {
|
||||
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[1].set(old_value.get());
|
||||
args[2].set(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>
|
||||
pub fn enqueue_upgrade_reaction(&self, element: &Element, definition: Rc<CustomElementDefinition>) {
|
||||
pub fn enqueue_upgrade_reaction(
|
||||
&self,
|
||||
element: &Element,
|
||||
definition: Rc<CustomElementDefinition>,
|
||||
) {
|
||||
// Step 1
|
||||
element.push_upgrade_reaction(definition);
|
||||
// Step 2
|
||||
|
@ -806,7 +932,12 @@ impl ElementQueue {
|
|||
}
|
||||
|
||||
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) {
|
||||
|
@ -859,7 +990,10 @@ pub fn is_valid_custom_element_name(name: &str) -> bool {
|
|||
/// Check if this character is a PCENChar
|
||||
/// <https://html.spec.whatwg.org/multipage/#prod-pcenchar>
|
||||
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 >= 'a' && c <= 'z') ||
|
||||
(c >= '\u{C0}' && c <= '\u{D6}') ||
|
||||
|
|
|
@ -36,38 +36,46 @@ impl 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,
|
||||
CustomEventBinding::Wrap)
|
||||
CustomEventBinding::Wrap,
|
||||
)
|
||||
}
|
||||
pub fn new(global: &GlobalScope,
|
||||
pub fn new(
|
||||
global: &GlobalScope,
|
||||
type_: Atom,
|
||||
bubbles: bool,
|
||||
cancelable: bool,
|
||||
detail: HandleValue)
|
||||
-> DomRoot<CustomEvent> {
|
||||
detail: HandleValue,
|
||||
) -> DomRoot<CustomEvent> {
|
||||
let ev = CustomEvent::new_uninitialized(global);
|
||||
ev.init_custom_event(type_, bubbles, cancelable, detail);
|
||||
ev
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
pub fn Constructor(global: &GlobalScope,
|
||||
pub fn Constructor(
|
||||
global: &GlobalScope,
|
||||
type_: DOMString,
|
||||
init: RootedTraceableBox<CustomEventBinding::CustomEventInit>)
|
||||
-> Fallible<DomRoot<CustomEvent>> {
|
||||
Ok(CustomEvent::new(global,
|
||||
init: RootedTraceableBox<CustomEventBinding::CustomEventInit>,
|
||||
) -> Fallible<DomRoot<CustomEvent>> {
|
||||
Ok(CustomEvent::new(
|
||||
global,
|
||||
Atom::from(type_),
|
||||
init.parent.bubbles,
|
||||
init.parent.cancelable,
|
||||
init.detail.handle()))
|
||||
init.detail.handle(),
|
||||
))
|
||||
}
|
||||
|
||||
fn init_custom_event(&self,
|
||||
fn init_custom_event(
|
||||
&self,
|
||||
type_: Atom,
|
||||
can_bubble: bool,
|
||||
cancelable: bool,
|
||||
detail: HandleValue) {
|
||||
detail: HandleValue,
|
||||
) {
|
||||
let event = self.upcast::<Event>();
|
||||
if event.dispatching() {
|
||||
return;
|
||||
|
@ -87,12 +95,14 @@ impl CustomEventMethods for CustomEvent {
|
|||
|
||||
#[allow(unsafe_code)]
|
||||
// https://dom.spec.whatwg.org/#dom-customevent-initcustomevent
|
||||
unsafe fn InitCustomEvent(&self,
|
||||
unsafe fn InitCustomEvent(
|
||||
&self,
|
||||
_cx: *mut JSContext,
|
||||
type_: DOMString,
|
||||
can_bubble: bool,
|
||||
cancelable: bool,
|
||||
detail: HandleValue) {
|
||||
detail: HandleValue,
|
||||
) {
|
||||
self.init_custom_event(Atom::from(type_), can_bubble, cancelable, detail)
|
||||
}
|
||||
|
||||
|
|
|
@ -57,9 +57,10 @@ pub struct AutoWorkerReset<'a> {
|
|||
}
|
||||
|
||||
impl<'a> AutoWorkerReset<'a> {
|
||||
fn new(workerscope: &'a DedicatedWorkerGlobalScope,
|
||||
worker: TrustedWorkerAddress)
|
||||
-> AutoWorkerReset<'a> {
|
||||
fn new(
|
||||
workerscope: &'a DedicatedWorkerGlobalScope,
|
||||
worker: TrustedWorkerAddress,
|
||||
) -> AutoWorkerReset<'a> {
|
||||
AutoWorkerReset {
|
||||
workerscope: workerscope,
|
||||
old_worker: replace(&mut *workerscope.worker.borrow_mut(), Some(worker)),
|
||||
|
@ -83,7 +84,7 @@ pub enum DedicatedWorkerScriptMsg {
|
|||
pub enum MixedMessage {
|
||||
FromWorker(DedicatedWorkerScriptMsg),
|
||||
FromScheduler((TrustedWorkerAddress, TimerEvent)),
|
||||
FromDevtools(DevtoolScriptControlMsg)
|
||||
FromDevtools(DevtoolScriptControlMsg),
|
||||
}
|
||||
|
||||
impl QueuedTaskConversion for DedicatedWorkerScriptMsg {
|
||||
|
@ -97,14 +98,18 @@ impl QueuedTaskConversion for DedicatedWorkerScriptMsg {
|
|||
_ => return None,
|
||||
};
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
fn into_queued_task(self) -> Option<QueuedTask> {
|
||||
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,
|
||||
};
|
||||
let script_msg = match common_worker_msg {
|
||||
|
@ -112,8 +117,9 @@ impl QueuedTaskConversion for DedicatedWorkerScriptMsg {
|
|||
_ => return None,
|
||||
};
|
||||
let (category, boxed, pipeline_id, task_source) = match script_msg {
|
||||
CommonScriptMsg::Task(category, boxed, pipeline_id, task_source) =>
|
||||
(category, boxed, pipeline_id, task_source),
|
||||
CommonScriptMsg::Task(category, boxed, pipeline_id, task_source) => {
|
||||
(category, boxed, pipeline_id, task_source)
|
||||
},
|
||||
_ => return None,
|
||||
};
|
||||
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 {
|
||||
let (worker, category, boxed, pipeline_id, task_source) = queued_task;
|
||||
let script_msg = CommonScriptMsg::Task(
|
||||
category,
|
||||
boxed,
|
||||
pipeline_id,
|
||||
task_source
|
||||
);
|
||||
let script_msg = CommonScriptMsg::Task(category, boxed, pipeline_id, task_source);
|
||||
DedicatedWorkerScriptMsg::CommonWorker(worker.unwrap(), WorkerScriptMsg::Common(script_msg))
|
||||
}
|
||||
|
||||
|
@ -197,7 +198,8 @@ impl WorkerEventLoopMethods for DedicatedWorkerGlobalScope {
|
|||
}
|
||||
|
||||
impl DedicatedWorkerGlobalScope {
|
||||
fn new_inherited(init: WorkerGlobalScopeInit,
|
||||
fn new_inherited(
|
||||
init: WorkerGlobalScopeInit,
|
||||
worker_url: ServoUrl,
|
||||
from_devtools_receiver: Receiver<DevtoolScriptControlMsg>,
|
||||
runtime: Runtime,
|
||||
|
@ -206,15 +208,17 @@ impl DedicatedWorkerGlobalScope {
|
|||
receiver: Receiver<DedicatedWorkerScriptMsg>,
|
||||
timer_event_chan: IpcSender<TimerEvent>,
|
||||
timer_event_port: Receiver<(TrustedWorkerAddress, TimerEvent)>,
|
||||
closing: Arc<AtomicBool>)
|
||||
-> DedicatedWorkerGlobalScope {
|
||||
closing: Arc<AtomicBool>,
|
||||
) -> DedicatedWorkerGlobalScope {
|
||||
DedicatedWorkerGlobalScope {
|
||||
workerglobalscope: WorkerGlobalScope::new_inherited(init,
|
||||
workerglobalscope: WorkerGlobalScope::new_inherited(
|
||||
init,
|
||||
worker_url,
|
||||
runtime,
|
||||
from_devtools_receiver,
|
||||
timer_event_chan,
|
||||
Some(closing)),
|
||||
Some(closing),
|
||||
),
|
||||
task_queue: TaskQueue::new(receiver, own_sender.clone()),
|
||||
own_sender: own_sender,
|
||||
timer_event_port: timer_event_port,
|
||||
|
@ -224,7 +228,8 @@ impl DedicatedWorkerGlobalScope {
|
|||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
pub fn new(init: WorkerGlobalScopeInit,
|
||||
pub fn new(
|
||||
init: WorkerGlobalScopeInit,
|
||||
worker_url: ServoUrl,
|
||||
from_devtools_receiver: Receiver<DevtoolScriptControlMsg>,
|
||||
runtime: Runtime,
|
||||
|
@ -233,8 +238,8 @@ impl DedicatedWorkerGlobalScope {
|
|||
receiver: Receiver<DedicatedWorkerScriptMsg>,
|
||||
timer_event_chan: IpcSender<TimerEvent>,
|
||||
timer_event_port: Receiver<(TrustedWorkerAddress, TimerEvent)>,
|
||||
closing: Arc<AtomicBool>)
|
||||
-> DomRoot<DedicatedWorkerGlobalScope> {
|
||||
closing: Arc<AtomicBool>,
|
||||
) -> DomRoot<DedicatedWorkerGlobalScope> {
|
||||
let cx = runtime.cx();
|
||||
let scope = Box::new(DedicatedWorkerGlobalScope::new_inherited(
|
||||
init,
|
||||
|
@ -246,16 +251,15 @@ impl DedicatedWorkerGlobalScope {
|
|||
receiver,
|
||||
timer_event_chan,
|
||||
timer_event_port,
|
||||
closing
|
||||
closing,
|
||||
));
|
||||
unsafe {
|
||||
DedicatedWorkerGlobalScopeBinding::Wrap(cx, scope)
|
||||
}
|
||||
unsafe { DedicatedWorkerGlobalScopeBinding::Wrap(cx, scope) }
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
// 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,
|
||||
from_devtools_receiver: IpcReceiver<DevtoolScriptControlMsg>,
|
||||
worker: TrustedWorkerAddress,
|
||||
|
@ -263,13 +267,20 @@ impl DedicatedWorkerGlobalScope {
|
|||
own_sender: Sender<DedicatedWorkerScriptMsg>,
|
||||
receiver: Receiver<DedicatedWorkerScriptMsg>,
|
||||
worker_load_origin: WorkerScriptLoadOrigin,
|
||||
closing: Arc<AtomicBool>) {
|
||||
closing: Arc<AtomicBool>,
|
||||
) {
|
||||
let serialized_worker_url = worker_url.to_string();
|
||||
let name = format!("WebWorker for {}", serialized_worker_url);
|
||||
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);
|
||||
|
||||
if let Some(top_level_browsing_context_id) = top_level_browsing_context_id {
|
||||
|
@ -279,7 +290,11 @@ impl DedicatedWorkerGlobalScope {
|
|||
let roots = RootCollection::new();
|
||||
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 {
|
||||
url: worker_url.clone(),
|
||||
|
@ -293,19 +308,20 @@ impl DedicatedWorkerGlobalScope {
|
|||
..RequestInit::default()
|
||||
};
|
||||
|
||||
let (metadata, bytes) = match load_whole_resource(request,
|
||||
&init.resource_threads.sender()) {
|
||||
let (metadata, bytes) =
|
||||
match load_whole_resource(request, &init.resource_threads.sender()) {
|
||||
Err(_) => {
|
||||
println!("error loading script {}", serialized_worker_url);
|
||||
parent_sender.send(CommonScriptMsg::Task(
|
||||
parent_sender
|
||||
.send(CommonScriptMsg::Task(
|
||||
WorkerEvent,
|
||||
Box::new(SimpleWorkerErrorHandler::new(worker)),
|
||||
pipeline_id,
|
||||
TaskSourceName::DOMManipulation,
|
||||
)).unwrap();
|
||||
return;
|
||||
}
|
||||
Ok((metadata, bytes)) => (metadata, bytes)
|
||||
},
|
||||
Ok((metadata, bytes)) => (metadata, bytes),
|
||||
};
|
||||
let url = metadata.final_url;
|
||||
let source = String::from_utf8_lossy(&bytes);
|
||||
|
@ -318,15 +334,26 @@ impl DedicatedWorkerGlobalScope {
|
|||
let (timer_tx, timer_rx) = channel();
|
||||
let (timer_ipc_chan, timer_ipc_port) = ipc::channel().unwrap();
|
||||
let worker_for_route = worker.clone();
|
||||
ROUTER.add_route(timer_ipc_port.to_opaque(), Box::new(move |message| {
|
||||
ROUTER.add_route(
|
||||
timer_ipc_port.to_opaque(),
|
||||
Box::new(move |message| {
|
||||
let event = message.to().unwrap();
|
||||
timer_tx.send((worker_for_route.clone(), event)).unwrap();
|
||||
}));
|
||||
}),
|
||||
);
|
||||
|
||||
let global = DedicatedWorkerGlobalScope::new(
|
||||
init, url, devtools_mpsc_port, runtime,
|
||||
parent_sender.clone(), own_sender, receiver,
|
||||
timer_ipc_chan, timer_rx, closing);
|
||||
init,
|
||||
url,
|
||||
devtools_mpsc_port,
|
||||
runtime,
|
||||
parent_sender.clone(),
|
||||
own_sender,
|
||||
receiver,
|
||||
timer_ipc_chan,
|
||||
timer_rx,
|
||||
closing,
|
||||
);
|
||||
// FIXME(njn): workers currently don't have a unique ID suitable for using in reporter
|
||||
// registration (#6631), so we instead use a random number and cross our fingers.
|
||||
let scope = global.upcast::<WorkerGlobalScope>();
|
||||
|
@ -346,14 +373,24 @@ impl DedicatedWorkerGlobalScope {
|
|||
}
|
||||
|
||||
let reporter_name = format!("dedicated-worker-reporter-{}", random::<u64>());
|
||||
scope.upcast::<GlobalScope>().mem_profiler_chan().run_with_memory_reporting(|| {
|
||||
// Step 29, Run the responsible event loop specified by inside settings until it is destroyed.
|
||||
// The worker processing model remains on this step until the event loop is destroyed,
|
||||
scope
|
||||
.upcast::<GlobalScope>()
|
||||
.mem_profiler_chan()
|
||||
.run_with_memory_reporting(
|
||||
|| {
|
||||
// Step 29, Run the responsible event loop specified
|
||||
// by inside settings until it is destroyed.
|
||||
// The worker processing model remains on this step
|
||||
// until the event loop is destroyed,
|
||||
// which happens after the closing flag is set to true.
|
||||
while !scope.is_closing() {
|
||||
run_worker_event_loop(&*global, Some(&worker));
|
||||
}
|
||||
}, reporter_name, parent_sender, CommonScriptMsg::CollectReports);
|
||||
},
|
||||
reporter_name,
|
||||
parent_sender,
|
||||
CommonScriptMsg::CollectReports,
|
||||
);
|
||||
}).expect("Thread spawning failed");
|
||||
}
|
||||
|
||||
|
@ -378,8 +415,8 @@ impl DedicatedWorkerGlobalScope {
|
|||
WorkerScriptMsg::DOMMessage(data) => {
|
||||
let scope = self.upcast::<WorkerGlobalScope>();
|
||||
let target = self.upcast();
|
||||
let _ac = JSAutoCompartment::new(scope.get_cx(),
|
||||
scope.reflector().get_jsobject().get());
|
||||
let _ac =
|
||||
JSAutoCompartment::new(scope.get_cx(), scope.reflector().get_jsobject().get());
|
||||
rooted!(in(scope.get_cx()) let mut message = UndefinedValue());
|
||||
data.read(scope.upcast(), message.handle_mut());
|
||||
MessageEvent::dispatch_jsval(target, scope.upcast(), message.handle(), None);
|
||||
|
@ -392,33 +429,33 @@ impl DedicatedWorkerGlobalScope {
|
|||
|
||||
fn handle_mixed_message(&self, msg: MixedMessage) {
|
||||
match msg {
|
||||
MixedMessage::FromDevtools(msg) => {
|
||||
match msg {
|
||||
DevtoolScriptControlMsg::EvaluateJS(_pipe_id, 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::FromDevtools(msg) => match msg {
|
||||
DevtoolScriptControlMsg::EvaluateJS(_pipe_id, string, sender) => {
|
||||
devtools::handle_evaluate_js(self.upcast(), string, sender)
|
||||
},
|
||||
MixedMessage::FromScheduler((linked_worker, timer_event)) => {
|
||||
match timer_event {
|
||||
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)) => match timer_event {
|
||||
TimerEvent(TimerSource::FromWorker, id) => {
|
||||
let _ar = AutoWorkerReset::new(self, linked_worker);
|
||||
let scope = self.upcast::<WorkerGlobalScope>();
|
||||
scope.handle_fire_timer(id);
|
||||
},
|
||||
TimerEvent(_, _) => {
|
||||
panic!("A worker received a TimerEvent from a window.")
|
||||
}
|
||||
}
|
||||
}
|
||||
MixedMessage::FromWorker(DedicatedWorkerScriptMsg::CommonWorker(linked_worker, msg)) => {
|
||||
TimerEvent(_, _) => panic!("A worker received a TimerEvent from a window."),
|
||||
},
|
||||
MixedMessage::FromWorker(DedicatedWorkerScriptMsg::CommonWorker(
|
||||
linked_worker,
|
||||
msg,
|
||||
)) => {
|
||||
let _ar = AutoWorkerReset::new(self, linked_worker);
|
||||
self.handle_script_event(msg);
|
||||
}
|
||||
},
|
||||
MixedMessage::FromWorker(DedicatedWorkerScriptMsg::WakeUp) => {},
|
||||
}
|
||||
}
|
||||
|
@ -452,7 +489,8 @@ impl DedicatedWorkerGlobalScope {
|
|||
global.report_an_error(error_info, HandleValue::null());
|
||||
}
|
||||
}));
|
||||
self.parent_sender.send(CommonScriptMsg::Task(
|
||||
self.parent_sender
|
||||
.send(CommonScriptMsg::Task(
|
||||
WorkerEvent,
|
||||
task,
|
||||
Some(pipeline_id),
|
||||
|
@ -463,8 +501,7 @@ impl DedicatedWorkerGlobalScope {
|
|||
|
||||
#[allow(unsafe_code)]
|
||||
unsafe extern "C" fn interrupt_callback(cx: *mut JSContext) -> bool {
|
||||
let worker =
|
||||
DomRoot::downcast::<WorkerGlobalScope>(GlobalScope::from_context(cx))
|
||||
let worker = DomRoot::downcast::<WorkerGlobalScope>(GlobalScope::from_context(cx))
|
||||
.expect("global is not a worker scope");
|
||||
assert!(worker.is::<DedicatedWorkerGlobalScope>());
|
||||
|
||||
|
@ -483,7 +520,8 @@ impl DedicatedWorkerGlobalScopeMethods for DedicatedWorkerGlobalScope {
|
|||
Worker::handle_message(worker, data);
|
||||
}));
|
||||
// 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,
|
||||
task,
|
||||
Some(pipeline_id),
|
||||
|
|
|
@ -40,9 +40,11 @@ impl 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,
|
||||
DissimilarOriginLocationBinding::Wrap)
|
||||
DissimilarOriginLocationBinding::Wrap,
|
||||
)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
|
|
|
@ -46,10 +46,7 @@ pub struct DissimilarOriginWindow {
|
|||
|
||||
impl DissimilarOriginWindow {
|
||||
#[allow(unsafe_code)]
|
||||
pub fn new(
|
||||
global_to_clone_from: &GlobalScope,
|
||||
window_proxy: &WindowProxy,
|
||||
) -> DomRoot<Self> {
|
||||
pub fn new(global_to_clone_from: &GlobalScope, window_proxy: &WindowProxy) -> DomRoot<Self> {
|
||||
let cx = global_to_clone_from.get_cx();
|
||||
// Any timer events fired on this window are ignored.
|
||||
let (timer_event_chan, _) = ipc::channel().unwrap();
|
||||
|
@ -142,7 +139,12 @@ impl DissimilarOriginWindowMethods for DissimilarOriginWindow {
|
|||
|
||||
#[allow(unsafe_code)]
|
||||
// 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.
|
||||
let origin = match &origin[..] {
|
||||
"*" => None,
|
||||
|
@ -153,7 +155,7 @@ impl DissimilarOriginWindowMethods for DissimilarOriginWindow {
|
|||
url => match ServoUrl::parse(&url) {
|
||||
Ok(url) => Some(url.origin()),
|
||||
Err(_) => return Err(Error::Syntax),
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// Step 1-2, 6-8.
|
||||
|
@ -190,7 +192,8 @@ impl DissimilarOriginWindowMethods for DissimilarOriginWindow {
|
|||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-location
|
||||
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"),
|
||||
Some(incumbent) => incumbent,
|
||||
};
|
||||
let msg = ScriptMsg::PostMessage(self.window_proxy.browsing_context_id(),
|
||||
let msg = ScriptMsg::PostMessage(
|
||||
self.window_proxy.browsing_context_id(),
|
||||
origin,
|
||||
data.move_to_arraybuffer());
|
||||
data.move_to_arraybuffer(),
|
||||
);
|
||||
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> {
|
||||
Node::reflect_node(Box::new(DocumentFragment::new_inherited(document)),
|
||||
Node::reflect_node(
|
||||
Box::new(DocumentFragment::new_inherited(document)),
|
||||
document,
|
||||
DocumentFragmentBinding::Wrap)
|
||||
DocumentFragmentBinding::Wrap,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn Constructor(window: &Window) -> Fallible<DomRoot<DocumentFragment>> {
|
||||
|
@ -57,12 +59,14 @@ impl DocumentFragmentMethods for DocumentFragment {
|
|||
fn GetElementById(&self, id: DOMString) -> Option<DomRoot<Element>> {
|
||||
let node = self.upcast::<Node>();
|
||||
let id = Atom::from(id);
|
||||
node.traverse_preorder().filter_map(DomRoot::downcast::<Element>).find(|descendant| {
|
||||
match descendant.get_attribute(&ns!(), &local_name!("id")) {
|
||||
node.traverse_preorder()
|
||||
.filter_map(DomRoot::downcast::<Element>)
|
||||
.find(
|
||||
|descendant| match descendant.get_attribute(&ns!(), &local_name!("id")) {
|
||||
None => false,
|
||||
Some(attr) => *attr.value().as_atom() == id,
|
||||
}
|
||||
})
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#dom-parentnode-firstelementchild
|
||||
|
@ -72,7 +76,10 @@ impl DocumentFragmentMethods for DocumentFragment {
|
|||
|
||||
// https://dom.spec.whatwg.org/#dom-parentnode-lastelementchild
|
||||
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
|
||||
|
|
|
@ -24,11 +24,12 @@ pub struct DocumentType {
|
|||
}
|
||||
|
||||
impl DocumentType {
|
||||
fn new_inherited(name: DOMString,
|
||||
fn new_inherited(
|
||||
name: DOMString,
|
||||
public_id: Option<DOMString>,
|
||||
system_id: Option<DOMString>,
|
||||
document: &Document)
|
||||
-> DocumentType {
|
||||
document: &Document,
|
||||
) -> DocumentType {
|
||||
DocumentType {
|
||||
node: Node::new_inherited(document),
|
||||
name: name,
|
||||
|
@ -37,14 +38,19 @@ impl DocumentType {
|
|||
}
|
||||
}
|
||||
#[allow(unrooted_must_root)]
|
||||
pub fn new(name: DOMString,
|
||||
pub fn new(
|
||||
name: DOMString,
|
||||
public_id: Option<DOMString>,
|
||||
system_id: Option<DOMString>,
|
||||
document: &Document)
|
||||
-> DomRoot<DocumentType> {
|
||||
Node::reflect_node(Box::new(DocumentType::new_inherited(name, public_id, system_id, document)),
|
||||
document: &Document,
|
||||
) -> DomRoot<DocumentType> {
|
||||
Node::reflect_node(
|
||||
Box::new(DocumentType::new_inherited(
|
||||
name, public_id, system_id, document,
|
||||
)),
|
||||
document,
|
||||
DocumentTypeBinding::Wrap)
|
||||
DocumentTypeBinding::Wrap,
|
||||
)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
|
@ -53,9 +53,11 @@ impl 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,
|
||||
DOMExceptionBinding::Wrap)
|
||||
DOMExceptionBinding::Wrap,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -74,7 +76,9 @@ impl DOMExceptionMethods for DOMException {
|
|||
fn Message(&self) -> DOMString {
|
||||
let message = match self.code {
|
||||
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::InvalidCharacterError => "The string contains invalid characters.",
|
||||
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::InvalidModificationError => "The object can not be modified in this way.",
|
||||
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::NetworkError => "A network error occurred.",
|
||||
DOMErrorName::AbortError => "The operation was aborted.",
|
||||
DOMErrorName::TypeMismatchError => "The given type does not match any expected type.",
|
||||
DOMErrorName::QuotaExceededError => "The quota has been exceeded.",
|
||||
DOMErrorName::TimeoutError => "The operation timed out.",
|
||||
DOMErrorName::InvalidNodeTypeError =>
|
||||
"The supplied node is incorrect or has an incorrect ancestor for this operation.",
|
||||
DOMErrorName::InvalidNodeTypeError => {
|
||||
"The supplied node is incorrect or has an incorrect ancestor for this operation."
|
||||
},
|
||||
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)
|
||||
|
|
|
@ -44,42 +44,60 @@ impl DOMImplementation {
|
|||
|
||||
pub fn new(document: &Document) -> DomRoot<DOMImplementation> {
|
||||
let window = document.window();
|
||||
reflect_dom_object(Box::new(DOMImplementation::new_inherited(document)),
|
||||
reflect_dom_object(
|
||||
Box::new(DOMImplementation::new_inherited(document)),
|
||||
window,
|
||||
DOMImplementationBinding::Wrap)
|
||||
DOMImplementationBinding::Wrap,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#domimplementation
|
||||
impl DOMImplementationMethods for DOMImplementation {
|
||||
// https://dom.spec.whatwg.org/#dom-domimplementation-createdocumenttype
|
||||
fn CreateDocumentType(&self,
|
||||
fn CreateDocumentType(
|
||||
&self,
|
||||
qualified_name: DOMString,
|
||||
pubid: DOMString,
|
||||
sysid: DOMString)
|
||||
-> Fallible<DomRoot<DocumentType>> {
|
||||
sysid: DOMString,
|
||||
) -> Fallible<DomRoot<DocumentType>> {
|
||||
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
|
||||
fn CreateDocument(&self,
|
||||
fn CreateDocument(
|
||||
&self,
|
||||
maybe_namespace: Option<DOMString>,
|
||||
qname: DOMString,
|
||||
maybe_doctype: Option<&DocumentType>)
|
||||
-> Fallible<DomRoot<XMLDocument>> {
|
||||
maybe_doctype: Option<&DocumentType>,
|
||||
) -> Fallible<DomRoot<XMLDocument>> {
|
||||
let win = self.document.window();
|
||||
let loader = DocumentLoader::new(&self.document.loader());
|
||||
let namespace = namespace_from_domstring(maybe_namespace.to_owned());
|
||||
|
||||
let content_type = match namespace {
|
||||
ns!(html) => Mime(TopLevel::Application, 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![])
|
||||
ns!(html) => Mime(
|
||||
TopLevel::Application,
|
||||
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.
|
||||
let doc = XMLDocument::new(win,
|
||||
let doc = XMLDocument::new(
|
||||
win,
|
||||
HasBrowsingContext::No,
|
||||
None,
|
||||
self.document.origin().clone(),
|
||||
|
@ -88,13 +106,17 @@ impl DOMImplementationMethods for DOMImplementation {
|
|||
None,
|
||||
DocumentActivity::Inactive,
|
||||
DocumentSource::NotFromParser,
|
||||
loader);
|
||||
loader,
|
||||
);
|
||||
// Step 2-3.
|
||||
let maybe_elem = if qname.is_empty() {
|
||||
None
|
||||
} else {
|
||||
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),
|
||||
Ok(elem) => Some(elem),
|
||||
}
|
||||
|
@ -127,7 +149,8 @@ impl DOMImplementationMethods for DOMImplementation {
|
|||
let loader = DocumentLoader::new(&self.document.loader());
|
||||
|
||||
// Step 1-2.
|
||||
let doc = Document::new(win,
|
||||
let doc = Document::new(
|
||||
win,
|
||||
HasBrowsingContext::No,
|
||||
None,
|
||||
self.document.origin().clone(),
|
||||
|
@ -139,7 +162,8 @@ impl DOMImplementationMethods for DOMImplementation {
|
|||
loader,
|
||||
None,
|
||||
None,
|
||||
Default::default());
|
||||
Default::default(),
|
||||
);
|
||||
|
||||
{
|
||||
// Step 3.
|
||||
|
@ -151,25 +175,24 @@ impl DOMImplementationMethods for DOMImplementation {
|
|||
{
|
||||
// Step 4.
|
||||
let doc_node = doc.upcast::<Node>();
|
||||
let doc_html = DomRoot::upcast::<Node>(HTMLHtmlElement::new(local_name!("html"),
|
||||
None,
|
||||
&doc));
|
||||
let doc_html =
|
||||
DomRoot::upcast::<Node>(HTMLHtmlElement::new(local_name!("html"), None, &doc));
|
||||
doc_node.AppendChild(&doc_html).expect("Appending failed");
|
||||
|
||||
{
|
||||
// Step 5.
|
||||
let doc_head = DomRoot::upcast::<Node>(HTMLHeadElement::new(local_name!("head"),
|
||||
None,
|
||||
&doc));
|
||||
let doc_head =
|
||||
DomRoot::upcast::<Node>(HTMLHeadElement::new(local_name!("head"), None, &doc));
|
||||
doc_html.AppendChild(&doc_head).unwrap();
|
||||
|
||||
// Step 6.
|
||||
if let Some(title_str) = title {
|
||||
// Step 6.1.
|
||||
let doc_title =
|
||||
DomRoot::upcast::<Node>(HTMLTitleElement::new(local_name!("title"),
|
||||
let doc_title = DomRoot::upcast::<Node>(HTMLTitleElement::new(
|
||||
local_name!("title"),
|
||||
None,
|
||||
&doc));
|
||||
&doc,
|
||||
));
|
||||
doc_head.AppendChild(&doc_title).unwrap();
|
||||
|
||||
// Step 6.2.
|
||||
|
|
|
@ -17,7 +17,7 @@ use js::typedarray::{Float32Array, Float64Array};
|
|||
|
||||
#[dom_struct]
|
||||
pub struct DOMMatrix {
|
||||
parent: DOMMatrixReadOnly
|
||||
parent: DOMMatrixReadOnly,
|
||||
}
|
||||
|
||||
impl DOMMatrix {
|
||||
|
@ -29,7 +29,7 @@ impl DOMMatrix {
|
|||
|
||||
pub fn new_inherited(is2D: bool, matrix: Transform3D<f64>) -> Self {
|
||||
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
|
||||
pub fn Constructor_(global: &GlobalScope, entries: Vec<f64>) -> Fallible<DomRoot<Self>> {
|
||||
entries_to_matrix(&entries[..])
|
||||
.map(|(is2D, matrix)| {
|
||||
Self::new(global, is2D, matrix)
|
||||
})
|
||||
entries_to_matrix(&entries[..]).map(|(is2D, matrix)| Self::new(global, is2D, matrix))
|
||||
}
|
||||
|
||||
// https://drafts.fxtf.org/geometry-1/#dom-dommatrix-frommatrix
|
||||
pub fn FromMatrix(global: &GlobalScope, other: &DOMMatrixInit) -> Fallible<DomRoot<Self>> {
|
||||
dommatrixinit_to_matrix(&other)
|
||||
.map(|(is2D, matrix)| {
|
||||
Self::new(global, is2D, matrix)
|
||||
})
|
||||
dommatrixinit_to_matrix(&other).map(|(is2D, matrix)| Self::new(global, is2D, matrix))
|
||||
}
|
||||
|
||||
pub fn from_readonly(global: &GlobalScope, ro: &DOMMatrixReadOnly) -> DomRoot<Self> {
|
||||
|
@ -317,24 +311,40 @@ impl DOMMatrixMethods for DOMMatrix {
|
|||
// https://drafts.fxtf.org/geometry-1/#dom-dommatrix-translateself
|
||||
fn TranslateSelf(&self, tx: f64, ty: f64, tz: f64) -> DomRoot<DOMMatrix> {
|
||||
// Steps 1-2.
|
||||
self.upcast::<DOMMatrixReadOnly>().translate_self(tx, ty, tz);
|
||||
self.upcast::<DOMMatrixReadOnly>()
|
||||
.translate_self(tx, ty, tz);
|
||||
// Step 3.
|
||||
DomRoot::from_ref(&self)
|
||||
}
|
||||
|
||||
// https://drafts.fxtf.org/geometry-1/#dom-dommatrix-scaleself
|
||||
fn ScaleSelf(&self, scaleX: f64, scaleY: Option<f64>, scaleZ: f64,
|
||||
originX: f64, originY: f64, originZ: f64) -> DomRoot<DOMMatrix> {
|
||||
fn ScaleSelf(
|
||||
&self,
|
||||
scaleX: f64,
|
||||
scaleY: Option<f64>,
|
||||
scaleZ: f64,
|
||||
originX: f64,
|
||||
originY: f64,
|
||||
originZ: f64,
|
||||
) -> DomRoot<DOMMatrix> {
|
||||
// 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.
|
||||
DomRoot::from_ref(&self)
|
||||
}
|
||||
|
||||
// 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.
|
||||
self.upcast::<DOMMatrixReadOnly>().scale_3d_self(scale, originX, originY, originZ);
|
||||
self.upcast::<DOMMatrixReadOnly>()
|
||||
.scale_3d_self(scale, originX, originY, originZ);
|
||||
// Step 5.
|
||||
DomRoot::from_ref(&self)
|
||||
}
|
||||
|
@ -342,7 +352,8 @@ impl DOMMatrixMethods for DOMMatrix {
|
|||
// https://drafts.fxtf.org/geometry-1/#dom-dommatrix-rotateself
|
||||
fn RotateSelf(&self, rotX: f64, rotY: Option<f64>, rotZ: Option<f64>) -> DomRoot<DOMMatrix> {
|
||||
// Steps 1-7.
|
||||
self.upcast::<DOMMatrixReadOnly>().rotate_self(rotX, rotY, rotZ);
|
||||
self.upcast::<DOMMatrixReadOnly>()
|
||||
.rotate_self(rotX, rotY, rotZ);
|
||||
// Step 8.
|
||||
DomRoot::from_ref(&self)
|
||||
}
|
||||
|
@ -350,7 +361,8 @@ impl DOMMatrixMethods for DOMMatrix {
|
|||
// https://drafts.fxtf.org/geometry-1/#dom-dommatrix-rotatefromvectorself
|
||||
fn RotateFromVectorSelf(&self, x: f64, y: f64) -> DomRoot<DOMMatrix> {
|
||||
// Step 1.
|
||||
self.upcast::<DOMMatrixReadOnly>().rotate_from_vector_self(x, y);
|
||||
self.upcast::<DOMMatrixReadOnly>()
|
||||
.rotate_from_vector_self(x, y);
|
||||
// Step 2.
|
||||
DomRoot::from_ref(&self)
|
||||
}
|
||||
|
@ -358,7 +370,8 @@ impl DOMMatrixMethods for DOMMatrix {
|
|||
// https://drafts.fxtf.org/geometry-1/#dom-dommatrix-rotateaxisangleself
|
||||
fn RotateAxisAngleSelf(&self, x: f64, y: f64, z: f64, angle: f64) -> DomRoot<DOMMatrix> {
|
||||
// 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.
|
||||
DomRoot::from_ref(&self)
|
||||
}
|
||||
|
|
|
@ -53,18 +53,12 @@ impl DOMMatrixReadOnly {
|
|||
|
||||
// https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-dommatrixreadonly-numbersequence
|
||||
pub fn Constructor_(global: &GlobalScope, entries: Vec<f64>) -> Fallible<DomRoot<Self>> {
|
||||
entries_to_matrix(&entries[..])
|
||||
.map(|(is2D, matrix)| {
|
||||
Self::new(global, is2D, matrix)
|
||||
})
|
||||
entries_to_matrix(&entries[..]).map(|(is2D, matrix)| Self::new(global, is2D, matrix))
|
||||
}
|
||||
|
||||
// https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-frommatrix
|
||||
pub fn FromMatrix(global: &GlobalScope, other: &DOMMatrixInit) -> Fallible<DomRoot<Self>> {
|
||||
dommatrixinit_to_matrix(&other)
|
||||
.map(|(is2D, matrix)| {
|
||||
Self::new(global, is2D, matrix)
|
||||
})
|
||||
dommatrixinit_to_matrix(&other).map(|(is2D, matrix)| Self::new(global, is2D, matrix))
|
||||
}
|
||||
|
||||
pub fn matrix(&self) -> Ref<Transform3D<f64>> {
|
||||
|
@ -155,7 +149,6 @@ impl DOMMatrixReadOnly {
|
|||
self.matrix.borrow_mut().m44 = value;
|
||||
}
|
||||
|
||||
|
||||
// https://drafts.fxtf.org/geometry-1/#dom-dommatrix-multiplyself
|
||||
pub fn multiply_self(&self, other: &DOMMatrixInit) -> Fallible<()> {
|
||||
// Step 1.
|
||||
|
@ -200,8 +193,15 @@ impl DOMMatrixReadOnly {
|
|||
}
|
||||
|
||||
// https://drafts.fxtf.org/geometry-1/#dom-dommatrix-scaleself
|
||||
pub fn scale_self(&self, scaleX: f64, scaleY: Option<f64>, scaleZ: f64,
|
||||
mut originX: f64, mut originY: f64, mut originZ: f64) {
|
||||
pub fn scale_self(
|
||||
&self,
|
||||
scaleX: f64,
|
||||
scaleY: Option<f64>,
|
||||
scaleZ: f64,
|
||||
mut originX: f64,
|
||||
mut originY: f64,
|
||||
mut originZ: f64,
|
||||
) {
|
||||
// Step 1.
|
||||
self.translate_self(originX, originY, originZ);
|
||||
// Step 2.
|
||||
|
@ -262,19 +262,22 @@ impl DOMMatrixReadOnly {
|
|||
}
|
||||
if rotZ != 0.0 {
|
||||
// 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();
|
||||
*matrix = rotation.post_mul(&matrix);
|
||||
}
|
||||
if rotY != 0.0 {
|
||||
// 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();
|
||||
*matrix = rotation.post_mul(&matrix);
|
||||
}
|
||||
if rotX != 0.0 {
|
||||
// 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();
|
||||
*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) {
|
||||
// Step 1.
|
||||
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();
|
||||
*matrix = rotation.post_mul(&matrix);
|
||||
// Step 2.
|
||||
|
@ -333,10 +341,24 @@ impl DOMMatrixReadOnly {
|
|||
*matrix = matrix.inverse().unwrap_or_else(|| {
|
||||
// Step 2.
|
||||
self.is2D.set(false);
|
||||
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)
|
||||
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,
|
||||
)
|
||||
})
|
||||
// Step 3 in DOMMatrix.InvertSelf
|
||||
}
|
||||
|
@ -362,7 +384,6 @@ impl DOMMatrixReadOnly {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
impl DOMMatrixReadOnlyMethods for DOMMatrixReadOnly {
|
||||
// https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m11
|
||||
fn M11(&self) -> f64 {
|
||||
|
@ -482,10 +503,22 @@ impl DOMMatrixReadOnlyMethods for DOMMatrixReadOnly {
|
|||
// https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-isidentity
|
||||
fn IsIdentity(&self) -> bool {
|
||||
let matrix = self.matrix.borrow();
|
||||
matrix.m12 == 0.0 && matrix.m13 == 0.0 && matrix.m14 == 0.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
|
||||
matrix.m12 == 0.0 &&
|
||||
matrix.m13 == 0.0 &&
|
||||
matrix.m14 == 0.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
|
||||
|
@ -494,16 +527,22 @@ impl DOMMatrixReadOnlyMethods for DOMMatrixReadOnly {
|
|||
}
|
||||
|
||||
// https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-scale
|
||||
fn Scale(&self, scaleX: f64, scaleY: Option<f64>, scaleZ: f64,
|
||||
originX: f64, originY: f64, originZ: f64) -> DomRoot<DOMMatrix> {
|
||||
fn Scale(
|
||||
&self,
|
||||
scaleX: f64,
|
||||
scaleY: Option<f64>,
|
||||
scaleZ: f64,
|
||||
originX: f64,
|
||||
originY: f64,
|
||||
originZ: f64,
|
||||
) -> DomRoot<DOMMatrix> {
|
||||
DOMMatrix::from_readonly(&self.global(), self)
|
||||
.ScaleSelf(scaleX, scaleY, scaleZ, originX, originY, originZ)
|
||||
}
|
||||
|
||||
// https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-scale3d
|
||||
fn Scale3d(&self, scale: f64, originX: f64, originY: f64, originZ: f64) -> DomRoot<DOMMatrix> {
|
||||
DOMMatrix::from_readonly(&self.global(), self)
|
||||
.Scale3dSelf(scale, originX, originY, originZ)
|
||||
DOMMatrix::from_readonly(&self.global(), self).Scale3dSelf(scale, originX, originY, originZ)
|
||||
}
|
||||
|
||||
// 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
|
||||
fn FlipX(&self) -> DomRoot<DOMMatrix> {
|
||||
let is2D = self.is2D.get();
|
||||
let flip = Transform3D::row_major(-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);
|
||||
let flip = Transform3D::row_major(
|
||||
-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,
|
||||
);
|
||||
let matrix = flip.post_mul(&self.matrix.borrow());
|
||||
DOMMatrix::new(&self.global(), is2D, matrix)
|
||||
}
|
||||
|
@ -550,10 +588,9 @@ impl DOMMatrixReadOnlyMethods for DOMMatrixReadOnly {
|
|||
// https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-flipy
|
||||
fn FlipY(&self) -> DomRoot<DOMMatrix> {
|
||||
let is2D = self.is2D.get();
|
||||
let flip = Transform3D::row_major(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);
|
||||
let flip = Transform3D::row_major(
|
||||
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,
|
||||
);
|
||||
let matrix = flip.post_mul(&self.matrix.borrow());
|
||||
DOMMatrix::new(&self.global(), is2D, matrix)
|
||||
}
|
||||
|
@ -583,11 +620,15 @@ impl DOMMatrixReadOnlyMethods for DOMMatrixReadOnly {
|
|||
// https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-tofloat32array
|
||||
#[allow(unsafe_code)]
|
||||
unsafe fn ToFloat32Array(&self, cx: *mut JSContext) -> NonNull<JSObject> {
|
||||
let vec: Vec<f32> = self.matrix
|
||||
.borrow().to_row_major_array().iter().map(|&x| x as f32).collect();
|
||||
let vec: Vec<f32> = self
|
||||
.matrix
|
||||
.borrow()
|
||||
.to_row_major_array()
|
||||
.iter()
|
||||
.map(|&x| x as f32)
|
||||
.collect();
|
||||
rooted!(in (cx) let mut array = ptr::null_mut::<JSObject>());
|
||||
let _ = Float32Array::create(cx, CreateWith::Slice(&vec), array.handle_mut())
|
||||
.unwrap();
|
||||
let _ = Float32Array::create(cx, CreateWith::Slice(&vec), array.handle_mut()).unwrap();
|
||||
NonNull::new_unchecked(array.get())
|
||||
}
|
||||
|
||||
|
@ -596,28 +637,39 @@ impl DOMMatrixReadOnlyMethods for DOMMatrixReadOnly {
|
|||
unsafe fn ToFloat64Array(&self, cx: *mut JSContext) -> NonNull<JSObject> {
|
||||
let arr = self.matrix.borrow().to_row_major_array();
|
||||
rooted!(in (cx) let mut array = ptr::null_mut::<JSObject>());
|
||||
let _ = Float64Array::create(cx, CreateWith::Slice(&arr), array.handle_mut())
|
||||
.unwrap();
|
||||
let _ = Float64Array::create(cx, CreateWith::Slice(&arr), array.handle_mut()).unwrap();
|
||||
NonNull::new_unchecked(array.get())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// https://drafts.fxtf.org/geometry-1/#create-a-2d-matrix
|
||||
fn create_2d_matrix(entries: &[f64]) -> Transform3D<f64> {
|
||||
Transform3D::row_major(entries[0], entries[1], 0.0, 0.0,
|
||||
entries[2], entries[3], 0.0, 0.0,
|
||||
0.0, 0.0, 1.0, 0.0,
|
||||
entries[4], entries[5], 0.0, 1.0)
|
||||
Transform3D::row_major(
|
||||
entries[0], entries[1], 0.0, 0.0, entries[2], entries[3], 0.0, 0.0, 0.0, 0.0, 1.0, 0.0,
|
||||
entries[4], entries[5], 0.0, 1.0,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
// https://drafts.fxtf.org/geometry-1/#create-a-3d-matrix
|
||||
fn create_3d_matrix(entries: &[f64]) -> Transform3D<f64> {
|
||||
Transform3D::row_major(entries[0], entries[1], 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])
|
||||
Transform3D::row_major(
|
||||
entries[0],
|
||||
entries[1],
|
||||
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
|
||||
|
@ -632,7 +684,6 @@ pub fn entries_to_matrix(entries: &[f64]) -> Fallible<(bool, Transform3D<f64>)>
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// https://drafts.fxtf.org/geometry-1/#validate-and-fixup
|
||||
pub fn dommatrixinit_to_matrix(dict: &DOMMatrixInit) -> Fallible<(bool, Transform3D<f64>)> {
|
||||
// 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.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.is2D.is_some() && dict.is2D.unwrap() &&
|
||||
(dict.m31 != 0.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) {
|
||||
dict.is2D.is_some() &&
|
||||
dict.is2D.unwrap() &&
|
||||
(dict.m31 != 0.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()))
|
||||
} else {
|
||||
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));
|
||||
// Step 8.
|
||||
if is2D.is_none() &&
|
||||
(dict.m31 != 0.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) {
|
||||
(dict.m31 != 0.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)
|
||||
{
|
||||
is2D = Some(false);
|
||||
}
|
||||
// Step 9.
|
||||
if is2D.is_none() {
|
||||
is2D = Some(true);
|
||||
}
|
||||
let matrix = Transform3D::row_major(m11, m12, dict.m13, dict.m14,
|
||||
m21, m22, dict.m23, dict.m24,
|
||||
dict.m31, dict.m32, dict.m33, dict.m34,
|
||||
m41, m42, dict.m43, dict.m44);
|
||||
let matrix = Transform3D::row_major(
|
||||
m11, m12, dict.m13, dict.m14, m21, m22, dict.m23, dict.m24, dict.m31, dict.m32,
|
||||
dict.m33, dict.m34, m41, m42, dict.m43, dict.m44,
|
||||
);
|
||||
Ok((is2D.unwrap(), matrix))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[inline]
|
||||
fn normalize_point(x: f64, y: f64, z: f64) -> (f64, f64, f64) {
|
||||
let len = (x * x + y * y + z * z).sqrt();
|
||||
|
|
|
@ -37,9 +37,11 @@ impl 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,
|
||||
DOMParserBinding::Wrap)
|
||||
DOMParserBinding::Wrap,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn Constructor(window: &Window) -> Fallible<DomRoot<DOMParser>> {
|
||||
|
@ -49,17 +51,22 @@ impl DOMParser {
|
|||
|
||||
impl DOMParserMethods for DOMParser {
|
||||
// https://w3c.github.io/DOM-Parsing/#the-domparser-interface
|
||||
fn ParseFromString(&self,
|
||||
fn ParseFromString(
|
||||
&self,
|
||||
s: DOMString,
|
||||
ty: DOMParserBinding::SupportedType)
|
||||
-> Fallible<DomRoot<Document>> {
|
||||
ty: DOMParserBinding::SupportedType,
|
||||
) -> Fallible<DomRoot<Document>> {
|
||||
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 loader = DocumentLoader::new(&*doc.loader());
|
||||
match ty {
|
||||
Text_html => {
|
||||
let document = Document::new(&self.window,
|
||||
let document = Document::new(
|
||||
&self.window,
|
||||
HasBrowsingContext::No,
|
||||
Some(url.clone()),
|
||||
doc.origin().clone(),
|
||||
|
@ -71,13 +78,15 @@ impl DOMParserMethods for DOMParser {
|
|||
loader,
|
||||
None,
|
||||
None,
|
||||
Default::default());
|
||||
Default::default(),
|
||||
);
|
||||
ServoParser::parse_html_document(&document, s, url);
|
||||
document.set_ready_state(DocumentReadyState::Complete);
|
||||
Ok(document)
|
||||
}
|
||||
},
|
||||
Text_xml | Application_xml | Application_xhtml_xml => {
|
||||
let document = Document::new(&self.window,
|
||||
let document = Document::new(
|
||||
&self.window,
|
||||
HasBrowsingContext::No,
|
||||
Some(url.clone()),
|
||||
doc.origin().clone(),
|
||||
|
@ -89,11 +98,12 @@ impl DOMParserMethods for DOMParser {
|
|||
loader,
|
||||
None,
|
||||
None,
|
||||
Default::default());
|
||||
Default::default(),
|
||||
);
|
||||
ServoParser::parse_xml_document(&document, s, url);
|
||||
document.set_ready_state(DocumentReadyState::Complete);
|
||||
Ok(document)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,12 +28,13 @@ impl DOMPoint {
|
|||
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,
|
||||
y: f64,
|
||||
z: f64,
|
||||
w: f64)
|
||||
-> Fallible<DomRoot<DOMPoint>> {
|
||||
w: f64,
|
||||
) -> Fallible<DomRoot<DOMPoint>> {
|
||||
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> {
|
||||
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,
|
||||
Wrap)
|
||||
Wrap,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn Constructor(global: &GlobalScope,
|
||||
pub fn Constructor(
|
||||
global: &GlobalScope,
|
||||
x: f64,
|
||||
y: f64,
|
||||
z: f64,
|
||||
w: f64)
|
||||
-> Fallible<DomRoot<DOMPointReadOnly>> {
|
||||
w: f64,
|
||||
) -> Fallible<DomRoot<DOMPointReadOnly>> {
|
||||
Ok(DOMPointReadOnly::new(global, x, y, z, w))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,11 +24,7 @@ pub struct DOMQuad {
|
|||
}
|
||||
|
||||
impl DOMQuad {
|
||||
fn new_inherited(p1: &DOMPoint,
|
||||
p2: &DOMPoint,
|
||||
p3: &DOMPoint,
|
||||
p4: &DOMPoint)
|
||||
-> DOMQuad {
|
||||
fn new_inherited(p1: &DOMPoint, p2: &DOMPoint, p3: &DOMPoint, p4: &DOMPoint) -> DOMQuad {
|
||||
DOMQuad {
|
||||
reflector_: Reflector::new(),
|
||||
p1: Dom::from_ref(p1),
|
||||
|
@ -38,45 +34,62 @@ impl DOMQuad {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn new(global: &GlobalScope,
|
||||
pub fn new(
|
||||
global: &GlobalScope,
|
||||
p1: &DOMPoint,
|
||||
p2: &DOMPoint,
|
||||
p3: &DOMPoint,
|
||||
p4: &DOMPoint) -> DomRoot<DOMQuad> {
|
||||
reflect_dom_object(Box::new(DOMQuad::new_inherited(p1, p2, p3, p4)),
|
||||
p4: &DOMPoint,
|
||||
) -> DomRoot<DOMQuad> {
|
||||
reflect_dom_object(
|
||||
Box::new(DOMQuad::new_inherited(p1, p2, p3, p4)),
|
||||
global,
|
||||
Wrap)
|
||||
Wrap,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn Constructor(global: &GlobalScope,
|
||||
pub fn Constructor(
|
||||
global: &GlobalScope,
|
||||
p1: &DOMPointInit,
|
||||
p2: &DOMPointInit,
|
||||
p3: &DOMPointInit,
|
||||
p4: &DOMPointInit)
|
||||
-> Fallible<DomRoot<DOMQuad>> {
|
||||
Ok(DOMQuad::new(global,
|
||||
p4: &DOMPointInit,
|
||||
) -> Fallible<DomRoot<DOMQuad>> {
|
||||
Ok(DOMQuad::new(
|
||||
global,
|
||||
&*DOMPoint::new_from_init(global, p1),
|
||||
&*DOMPoint::new_from_init(global, p2),
|
||||
&*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
|
||||
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.width, other.y, 0f64, 1f64),
|
||||
&*DOMPoint::new(global, other.x + other.width, other.y + other.height, 0f64, 1f64),
|
||||
&*DOMPoint::new(global, other.x, other.y + other.height, 0f64, 1f64))
|
||||
&*DOMPoint::new(
|
||||
global,
|
||||
other.x + other.width,
|
||||
other.y + other.height,
|
||||
0f64,
|
||||
1f64,
|
||||
),
|
||||
&*DOMPoint::new(global, other.x, other.y + other.height, 0f64, 1f64),
|
||||
)
|
||||
}
|
||||
|
||||
// https://drafts.fxtf.org/geometry/#dom-domquad-fromquad
|
||||
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.p2),
|
||||
&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
|
||||
fn GetBounds(&self) -> DomRoot<DOMRect> {
|
||||
let left = self.p1.X().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());
|
||||
let left = self
|
||||
.p1
|
||||
.X()
|
||||
.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(),
|
||||
left,
|
||||
top,
|
||||
right - left,
|
||||
bottom - top)
|
||||
DOMRect::new(&self.global(), 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> {
|
||||
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,
|
||||
DOMRectBinding::Wrap)
|
||||
DOMRectBinding::Wrap,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn Constructor(global: &GlobalScope,
|
||||
pub fn Constructor(
|
||||
global: &GlobalScope,
|
||||
x: f64,
|
||||
y: f64,
|
||||
width: f64,
|
||||
height: f64)
|
||||
-> Fallible<DomRoot<DOMRect>> {
|
||||
height: f64,
|
||||
) -> Fallible<DomRoot<DOMRect>> {
|
||||
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,
|
||||
y: f64,
|
||||
width: f64,
|
||||
height: f64)
|
||||
-> DomRoot<DOMRectReadOnly> {
|
||||
reflect_dom_object(Box::new(DOMRectReadOnly::new_inherited(x, y, width, height)),
|
||||
height: f64,
|
||||
) -> DomRoot<DOMRectReadOnly> {
|
||||
reflect_dom_object(
|
||||
Box::new(DOMRectReadOnly::new_inherited(x, y, width, height)),
|
||||
global,
|
||||
Wrap)
|
||||
Wrap,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn Constructor(global: &GlobalScope,
|
||||
pub fn Constructor(
|
||||
global: &GlobalScope,
|
||||
x: f64,
|
||||
y: f64,
|
||||
width: f64,
|
||||
height: f64)
|
||||
-> Fallible<DomRoot<DOMRectReadOnly>> {
|
||||
height: f64,
|
||||
) -> Fallible<DomRoot<DOMRectReadOnly>> {
|
||||
Ok(DOMRectReadOnly::new(global, x, y, width, height))
|
||||
}
|
||||
|
||||
|
|
|
@ -28,9 +28,11 @@ impl DOMStringMap {
|
|||
|
||||
pub fn new(element: &HTMLElement) -> DomRoot<DOMStringMap> {
|
||||
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,
|
||||
DOMStringMapBinding::Wrap)
|
||||
DOMStringMapBinding::Wrap,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -53,6 +55,10 @@ impl DOMStringMapMethods for DOMStringMap {
|
|||
|
||||
// https://html.spec.whatwg.org/multipage/#the-domstringmap-interface:supported-property-names
|
||||
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> {
|
||||
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,
|
||||
DOMTokenListBinding::Wrap)
|
||||
DOMTokenListBinding::Wrap,
|
||||
)
|
||||
}
|
||||
|
||||
fn attribute(&self) -> Option<DomRoot<Attr>> {
|
||||
|
@ -56,16 +58,18 @@ impl DOMTokenList {
|
|||
impl DOMTokenListMethods for DOMTokenList {
|
||||
// https://dom.spec.whatwg.org/#dom-domtokenlist-length
|
||||
fn Length(&self) -> u32 {
|
||||
self.attribute().map_or(0, |attr| {
|
||||
attr.value().as_tokens().len()
|
||||
}) as u32
|
||||
self.attribute()
|
||||
.map_or(0, |attr| attr.value().as_tokens().len()) as u32
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#dom-domtokenlist-item
|
||||
fn Item(&self, index: u32) -> Option<DOMString> {
|
||||
self.attribute().and_then(|attr| {
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
self.element.set_atomic_tokenlist_attribute(&self.local_name, atoms);
|
||||
self.element
|
||||
.set_atomic_tokenlist_attribute(&self.local_name, atoms);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -98,9 +103,13 @@ impl DOMTokenListMethods for DOMTokenList {
|
|||
let mut atoms = self.element.get_tokenlist_attribute(&self.local_name);
|
||||
for token in &tokens {
|
||||
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(())
|
||||
}
|
||||
|
||||
|
@ -113,17 +122,19 @@ impl DOMTokenListMethods for DOMTokenList {
|
|||
Some(true) => Ok(true),
|
||||
_ => {
|
||||
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)
|
||||
}
|
||||
},
|
||||
},
|
||||
None => match force {
|
||||
Some(false) => Ok(false),
|
||||
_ => {
|
||||
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)
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -135,7 +146,8 @@ impl DOMTokenListMethods for DOMTokenList {
|
|||
|
||||
// https://dom.spec.whatwg.org/#dom-domtokenlist-value
|
||||
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
|
||||
|
@ -159,7 +171,8 @@ impl DOMTokenListMethods for DOMTokenList {
|
|||
atoms.remove(pos);
|
||||
}
|
||||
// Step 5.
|
||||
self.element.set_atomic_tokenlist_attribute(&self.local_name, atoms);
|
||||
self.element
|
||||
.set_atomic_tokenlist_attribute(&self.local_name, atoms);
|
||||
}
|
||||
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