mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
Changed blob to use DataSlice with Arc in order to limit wasteful copying of byte vector
This commit is contained in:
parent
238a8786de
commit
76f689cd06
7 changed files with 190 additions and 132 deletions
|
@ -8,104 +8,30 @@ use dom::bindings::error::Fallible;
|
||||||
use dom::bindings::global::{GlobalField, GlobalRef};
|
use dom::bindings::global::{GlobalField, GlobalRef};
|
||||||
use dom::bindings::js::Root;
|
use dom::bindings::js::Root;
|
||||||
use dom::bindings::reflector::{Reflector, reflect_dom_object};
|
use dom::bindings::reflector::{Reflector, reflect_dom_object};
|
||||||
|
use dom::bindings::trace::JSTraceable;
|
||||||
use num::ToPrimitive;
|
use num::ToPrimitive;
|
||||||
use std::ascii::AsciiExt;
|
use std::ascii::AsciiExt;
|
||||||
use std::borrow::ToOwned;
|
use std::borrow::ToOwned;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::cmp::{max, min};
|
use std::cmp::{max, min};
|
||||||
use std::sync::mpsc::Sender;
|
use std::sync::Arc;
|
||||||
use util::str::DOMString;
|
use util::str::DOMString;
|
||||||
|
|
||||||
// https://w3c.github.io/FileAPI/#blob
|
#[derive(Clone, JSTraceable)]
|
||||||
#[dom_struct]
|
pub struct DataSlice {
|
||||||
pub struct Blob {
|
bytes: Arc<Vec<u8>>,
|
||||||
reflector_: Reflector,
|
bytes_start: usize,
|
||||||
bytes: Option<Vec<u8>>,
|
bytes_end: usize
|
||||||
typeString: String,
|
|
||||||
global: GlobalField,
|
|
||||||
isClosed_: Cell<bool>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_ascii_printable(string: &str) -> bool {
|
impl DataSlice {
|
||||||
// Step 5.1 in Sec 5.1 of File API spec
|
pub fn new(bytes: Arc<Vec<u8>>, start: Option<i64>, end: Option<i64>) -> DataSlice {
|
||||||
// https://w3c.github.io/FileAPI/#constructorBlob
|
let size = bytes.len() as i64;
|
||||||
string.chars().all(|c| c >= '\x20' && c <= '\x7E')
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Blob {
|
|
||||||
pub fn new_inherited(global: GlobalRef, bytes: Option<Vec<u8>>, typeString: &str) -> Blob {
|
|
||||||
Blob {
|
|
||||||
reflector_: Reflector::new(),
|
|
||||||
bytes: bytes,
|
|
||||||
typeString: typeString.to_owned(),
|
|
||||||
global: GlobalField::from_rooted(&global),
|
|
||||||
isClosed_: Cell::new(false),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new(global: GlobalRef, bytes: Option<Vec<u8>>, typeString: &str) -> Root<Blob> {
|
|
||||||
reflect_dom_object(box Blob::new_inherited(global, bytes, typeString),
|
|
||||||
global,
|
|
||||||
BlobBinding::Wrap)
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://w3c.github.io/FileAPI/#constructorBlob
|
|
||||||
pub fn Constructor(global: GlobalRef) -> Fallible<Root<Blob>> {
|
|
||||||
Ok(Blob::new(global, None, ""))
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://w3c.github.io/FileAPI/#constructorBlob
|
|
||||||
pub fn Constructor_(global: GlobalRef,
|
|
||||||
blobParts: DOMString,
|
|
||||||
blobPropertyBag: &BlobBinding::BlobPropertyBag)
|
|
||||||
-> Fallible<Root<Blob>> {
|
|
||||||
// TODO: accept other blobParts types - ArrayBuffer or ArrayBufferView or Blob
|
|
||||||
// FIXME(ajeffrey): convert directly from a DOMString to a Vec<u8>
|
|
||||||
let bytes: Option<Vec<u8>> = Some(String::from(blobParts).into_bytes());
|
|
||||||
let typeString = if is_ascii_printable(&blobPropertyBag.type_) {
|
|
||||||
&*blobPropertyBag.type_
|
|
||||||
} else {
|
|
||||||
""
|
|
||||||
};
|
|
||||||
Ok(Blob::new(global, bytes, &typeString.to_ascii_lowercase()))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn read_out_buffer(&self, send: Sender<Vec<u8>>) {
|
|
||||||
send.send(self.bytes.clone().unwrap_or(vec![])).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
// simpler to use version of read_out_buffer
|
|
||||||
pub fn clone_bytes(&self) -> Vec<u8> {
|
|
||||||
self.bytes.clone().unwrap_or(vec![])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BlobMethods for Blob {
|
|
||||||
// https://w3c.github.io/FileAPI/#dfn-size
|
|
||||||
fn Size(&self) -> u64 {
|
|
||||||
match self.bytes {
|
|
||||||
None => 0,
|
|
||||||
Some(ref bytes) => bytes.len() as u64,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://w3c.github.io/FileAPI/#dfn-type
|
|
||||||
fn Type(&self) -> DOMString {
|
|
||||||
DOMString::from(self.typeString.clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://w3c.github.io/FileAPI/#slice-method-algo
|
|
||||||
fn Slice(&self,
|
|
||||||
start: Option<i64>,
|
|
||||||
end: Option<i64>,
|
|
||||||
contentType: Option<DOMString>)
|
|
||||||
-> Root<Blob> {
|
|
||||||
let size: i64 = self.Size().to_i64().unwrap();
|
|
||||||
let relativeStart: i64 = match start {
|
let relativeStart: i64 = match start {
|
||||||
None => 0,
|
None => 0,
|
||||||
Some(start) => {
|
Some(start) => {
|
||||||
if start < 0 {
|
if start < 0 {
|
||||||
max(size.to_i64().unwrap() + start, 0)
|
max(size + start, 0)
|
||||||
} else {
|
} else {
|
||||||
min(start, size)
|
min(start, size)
|
||||||
}
|
}
|
||||||
|
@ -121,6 +47,119 @@ impl BlobMethods for Blob {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let span: i64 = max(relativeEnd - relativeStart, 0);
|
||||||
|
let start = relativeStart.to_usize().unwrap();
|
||||||
|
let end = (relativeStart + span).to_usize().unwrap();
|
||||||
|
|
||||||
|
DataSlice {
|
||||||
|
bytes: bytes,
|
||||||
|
bytes_start: start,
|
||||||
|
bytes_end: end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_bytes(&self) -> &[u8] {
|
||||||
|
&self.bytes[self.bytes_start..self.bytes_end]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn size(&self) -> u64 {
|
||||||
|
(self.bytes_end as u64) - (self.bytes_start as u64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// https://w3c.github.io/FileAPI/#blob
|
||||||
|
#[dom_struct]
|
||||||
|
pub struct Blob {
|
||||||
|
reflector_: Reflector,
|
||||||
|
#[ignore_heap_size_of = "No clear owner"]
|
||||||
|
data: DataSlice,
|
||||||
|
typeString: String,
|
||||||
|
global: GlobalField,
|
||||||
|
isClosed_: Cell<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_ascii_printable(string: &str) -> bool {
|
||||||
|
// Step 5.1 in Sec 5.1 of File API spec
|
||||||
|
// https://w3c.github.io/FileAPI/#constructorBlob
|
||||||
|
string.chars().all(|c| c >= '\x20' && c <= '\x7E')
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Blob {
|
||||||
|
pub fn new_inherited(global: GlobalRef,
|
||||||
|
bytes: Arc<Vec<u8>>,
|
||||||
|
bytes_start: Option<i64>,
|
||||||
|
bytes_end: Option<i64>,
|
||||||
|
typeString: &str) -> Blob {
|
||||||
|
Blob {
|
||||||
|
reflector_: Reflector::new(),
|
||||||
|
data: DataSlice::new(bytes, bytes_start, bytes_end),
|
||||||
|
typeString: typeString.to_owned(),
|
||||||
|
global: GlobalField::from_rooted(&global),
|
||||||
|
isClosed_: Cell::new(false),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(global: GlobalRef, bytes: Vec<u8>, typeString: &str) -> Root<Blob> {
|
||||||
|
let boxed_blob = box Blob::new_inherited(global, Arc::new(bytes), None, None, typeString);
|
||||||
|
reflect_dom_object(boxed_blob, global, BlobBinding::Wrap)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_sliced(global: GlobalRef,
|
||||||
|
bytes: Arc<Vec<u8>>,
|
||||||
|
bytes_start: Option<i64>,
|
||||||
|
bytes_end: Option<i64>,
|
||||||
|
typeString: &str) -> Root<Blob> {
|
||||||
|
|
||||||
|
let boxed_blob = box Blob::new_inherited(global, bytes, bytes_start, bytes_end, typeString);
|
||||||
|
reflect_dom_object(boxed_blob, global, BlobBinding::Wrap)
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://w3c.github.io/FileAPI/#constructorBlob
|
||||||
|
pub fn Constructor(global: GlobalRef) -> Fallible<Root<Blob>> {
|
||||||
|
Ok(Blob::new(global, Vec::new(), ""))
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://w3c.github.io/FileAPI/#constructorBlob
|
||||||
|
pub fn Constructor_(global: GlobalRef,
|
||||||
|
blobParts: DOMString,
|
||||||
|
blobPropertyBag: &BlobBinding::BlobPropertyBag)
|
||||||
|
-> Fallible<Root<Blob>> {
|
||||||
|
// TODO: accept other blobParts types - ArrayBuffer or ArrayBufferView or Blob
|
||||||
|
// FIXME(ajeffrey): convert directly from a DOMString to a Vec<u8>
|
||||||
|
let bytes: Vec<u8> = String::from(blobParts).into_bytes();
|
||||||
|
let typeString = if is_ascii_printable(&blobPropertyBag.type_) {
|
||||||
|
&*blobPropertyBag.type_
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
};
|
||||||
|
Ok(Blob::new(global, bytes, &typeString.to_ascii_lowercase()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_data(&self) -> &DataSlice {
|
||||||
|
&self.data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BlobMethods for Blob {
|
||||||
|
// https://w3c.github.io/FileAPI/#dfn-size
|
||||||
|
fn Size(&self) -> u64 {
|
||||||
|
self.data.size()
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://w3c.github.io/FileAPI/#dfn-type
|
||||||
|
fn Type(&self) -> DOMString {
|
||||||
|
DOMString::from(self.typeString.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://w3c.github.io/FileAPI/#slice-method-algo
|
||||||
|
fn Slice(&self,
|
||||||
|
start: Option<i64>,
|
||||||
|
end: Option<i64>,
|
||||||
|
contentType: Option<DOMString>)
|
||||||
|
-> Root<Blob> {
|
||||||
|
|
||||||
let relativeContentType = match contentType {
|
let relativeContentType = match contentType {
|
||||||
None => DOMString::new(),
|
None => DOMString::new(),
|
||||||
Some(mut str) => {
|
Some(mut str) => {
|
||||||
|
@ -132,18 +171,9 @@ impl BlobMethods for Blob {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let span: i64 = max(relativeEnd - relativeStart, 0);
|
|
||||||
let global = self.global.root();
|
let global = self.global.root();
|
||||||
match self.bytes {
|
let bytes = self.data.bytes.clone();
|
||||||
None => Blob::new(global.r(), None, &relativeContentType),
|
Blob::new_sliced(global.r(), bytes, start, end, &relativeContentType)
|
||||||
Some(ref vec) => {
|
|
||||||
let start = relativeStart.to_usize().unwrap();
|
|
||||||
let end = (relativeStart + span).to_usize().unwrap();
|
|
||||||
let mut bytes: Vec<u8> = Vec::new();
|
|
||||||
bytes.extend_from_slice(&vec[start..end]);
|
|
||||||
Blob::new(global.r(), Some(bytes), &relativeContentType)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://w3c.github.io/FileAPI/#dfn-isClosed
|
// https://w3c.github.io/FileAPI/#dfn-isClosed
|
||||||
|
|
|
@ -8,6 +8,7 @@ use dom::bindings::global::GlobalRef;
|
||||||
use dom::bindings::js::Root;
|
use dom::bindings::js::Root;
|
||||||
use dom::bindings::reflector::reflect_dom_object;
|
use dom::bindings::reflector::reflect_dom_object;
|
||||||
use dom::blob::Blob;
|
use dom::blob::Blob;
|
||||||
|
use std::sync::Arc;
|
||||||
use util::str::DOMString;
|
use util::str::DOMString;
|
||||||
|
|
||||||
#[dom_struct]
|
#[dom_struct]
|
||||||
|
@ -21,7 +22,7 @@ impl File {
|
||||||
_file_bits: &Blob, name: DOMString) -> File {
|
_file_bits: &Blob, name: DOMString) -> File {
|
||||||
File {
|
File {
|
||||||
//TODO: get type from the underlying filesystem instead of "".to_string()
|
//TODO: get type from the underlying filesystem instead of "".to_string()
|
||||||
blob: Blob::new_inherited(global, None, ""),
|
blob: Blob::new_inherited(global, Arc::new(Vec::new()), None, None, ""),
|
||||||
name: name,
|
name: name,
|
||||||
}
|
}
|
||||||
// XXXManishearth Once Blob is able to store data
|
// XXXManishearth Once Blob is able to store data
|
||||||
|
|
|
@ -12,7 +12,7 @@ use dom::bindings::inheritance::Castable;
|
||||||
use dom::bindings::js::{JS, MutNullableHeap, Root};
|
use dom::bindings::js::{JS, MutNullableHeap, Root};
|
||||||
use dom::bindings::refcounted::Trusted;
|
use dom::bindings::refcounted::Trusted;
|
||||||
use dom::bindings::reflector::{Reflectable, reflect_dom_object};
|
use dom::bindings::reflector::{Reflectable, reflect_dom_object};
|
||||||
use dom::blob::Blob;
|
use dom::blob::{Blob, DataSlice};
|
||||||
use dom::domexception::{DOMErrorName, DOMException};
|
use dom::domexception::{DOMErrorName, DOMException};
|
||||||
use dom::event::{Event, EventBubbles, EventCancelable};
|
use dom::event::{Event, EventBubbles, EventCancelable};
|
||||||
use dom::eventtarget::EventTarget;
|
use dom::eventtarget::EventTarget;
|
||||||
|
@ -23,10 +23,8 @@ use encoding::types::{DecoderTrap, EncodingRef};
|
||||||
use hyper::mime::{Attr, Mime};
|
use hyper::mime::{Attr, Mime};
|
||||||
use rustc_serialize::base64::{CharacterSet, Config, Newline, ToBase64};
|
use rustc_serialize::base64::{CharacterSet, Config, Newline, ToBase64};
|
||||||
use script_task::ScriptTaskEventCategory::FileRead;
|
use script_task::ScriptTaskEventCategory::FileRead;
|
||||||
use script_task::{CommonScriptMsg, Runnable, ScriptChan, ScriptPort};
|
use script_task::{CommonScriptMsg, Runnable, ScriptChan};
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::sync::mpsc;
|
|
||||||
use std::sync::mpsc::Receiver;
|
|
||||||
use string_cache::Atom;
|
use string_cache::Atom;
|
||||||
use util::str::DOMString;
|
use util::str::DOMString;
|
||||||
use util::task::spawn_named;
|
use util::task::spawn_named;
|
||||||
|
@ -163,7 +161,7 @@ impl FileReader {
|
||||||
|
|
||||||
// https://w3c.github.io/FileAPI/#dfn-readAsText
|
// https://w3c.github.io/FileAPI/#dfn-readAsText
|
||||||
pub fn process_read_eof(filereader: TrustedFileReader, gen_id: GenerationId,
|
pub fn process_read_eof(filereader: TrustedFileReader, gen_id: GenerationId,
|
||||||
data: ReadMetaData, blob_contents: Vec<u8>) {
|
data: ReadMetaData, blob_contents: DataSlice) {
|
||||||
let fr = filereader.root();
|
let fr = filereader.root();
|
||||||
|
|
||||||
macro_rules! return_on_abort(
|
macro_rules! return_on_abort(
|
||||||
|
@ -178,11 +176,13 @@ impl FileReader {
|
||||||
// Step 8.1
|
// Step 8.1
|
||||||
fr.change_ready_state(FileReaderReadyState::Done);
|
fr.change_ready_state(FileReaderReadyState::Done);
|
||||||
// Step 8.2
|
// Step 8.2
|
||||||
|
|
||||||
|
let bytes = blob_contents.get_bytes();
|
||||||
let output = match data.function {
|
let output = match data.function {
|
||||||
FileReaderFunction::ReadAsDataUrl =>
|
FileReaderFunction::ReadAsDataUrl =>
|
||||||
FileReader::perform_readasdataurl(data, blob_contents),
|
FileReader::perform_readasdataurl(data, bytes),
|
||||||
FileReaderFunction::ReadAsText =>
|
FileReaderFunction::ReadAsText =>
|
||||||
FileReader::perform_readastext(data, blob_contents),
|
FileReader::perform_readastext(data, bytes),
|
||||||
};
|
};
|
||||||
|
|
||||||
*fr.result.borrow_mut() = Some(output);
|
*fr.result.borrow_mut() = Some(output);
|
||||||
|
@ -200,12 +200,11 @@ impl FileReader {
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://w3c.github.io/FileAPI/#dfn-readAsText
|
// https://w3c.github.io/FileAPI/#dfn-readAsText
|
||||||
fn perform_readastext(data: ReadMetaData, blob_contents: Vec<u8>)
|
fn perform_readastext(data: ReadMetaData, blob_bytes: &[u8])
|
||||||
-> DOMString {
|
-> DOMString {
|
||||||
|
|
||||||
let blob_label = &data.label;
|
let blob_label = &data.label;
|
||||||
let blob_type = &data.blobtype;
|
let blob_type = &data.blobtype;
|
||||||
let blob_bytes = &blob_contents[..];
|
|
||||||
|
|
||||||
//https://w3c.github.io/FileAPI/#encoding-determination
|
//https://w3c.github.io/FileAPI/#encoding-determination
|
||||||
// Steps 1 & 2 & 3
|
// Steps 1 & 2 & 3
|
||||||
|
@ -233,7 +232,7 @@ impl FileReader {
|
||||||
}
|
}
|
||||||
|
|
||||||
//https://w3c.github.io/FileAPI/#dfn-readAsDataURL
|
//https://w3c.github.io/FileAPI/#dfn-readAsDataURL
|
||||||
fn perform_readasdataurl(data: ReadMetaData, blob_contents: Vec<u8>)
|
fn perform_readasdataurl(data: ReadMetaData, bytes: &[u8])
|
||||||
-> DOMString {
|
-> DOMString {
|
||||||
let config = Config {
|
let config = Config {
|
||||||
char_set: CharacterSet::UrlSafe,
|
char_set: CharacterSet::UrlSafe,
|
||||||
|
@ -241,7 +240,7 @@ impl FileReader {
|
||||||
pad: true,
|
pad: true,
|
||||||
line_length: None
|
line_length: None
|
||||||
};
|
};
|
||||||
let base64 = blob_contents.to_base64(config);
|
let base64 = bytes.to_base64(config);
|
||||||
|
|
||||||
let output = if data.blobtype.is_empty() {
|
let output = if data.blobtype.is_empty() {
|
||||||
format!("data:base64,{}", base64)
|
format!("data:base64,{}", base64)
|
||||||
|
@ -355,8 +354,8 @@ impl FileReader {
|
||||||
self.change_ready_state(FileReaderReadyState::Loading);
|
self.change_ready_state(FileReaderReadyState::Loading);
|
||||||
|
|
||||||
// Step 4
|
// Step 4
|
||||||
let (send, bytes) = mpsc::channel();
|
let blob_contents = blob.get_data().clone();
|
||||||
blob.read_out_buffer(send);
|
|
||||||
let type_ = blob.Type();
|
let type_ = blob.Type();
|
||||||
|
|
||||||
let load_data = ReadMetaData::new(String::from(type_), label.map(String::from), function);
|
let load_data = ReadMetaData::new(String::from(type_), label.map(String::from), function);
|
||||||
|
@ -367,7 +366,7 @@ impl FileReader {
|
||||||
let script_chan = global.file_reading_task_source();
|
let script_chan = global.file_reading_task_source();
|
||||||
|
|
||||||
spawn_named("file reader async operation".to_owned(), move || {
|
spawn_named("file reader async operation".to_owned(), move || {
|
||||||
perform_annotated_read_operation(gen_id, load_data, bytes, fr, script_chan)
|
perform_annotated_read_operation(gen_id, load_data, blob_contents, fr, script_chan)
|
||||||
});
|
});
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -382,7 +381,7 @@ pub enum FileReaderEvent {
|
||||||
ProcessRead(TrustedFileReader, GenerationId),
|
ProcessRead(TrustedFileReader, GenerationId),
|
||||||
ProcessReadData(TrustedFileReader, GenerationId),
|
ProcessReadData(TrustedFileReader, GenerationId),
|
||||||
ProcessReadError(TrustedFileReader, GenerationId, DOMErrorName),
|
ProcessReadError(TrustedFileReader, GenerationId, DOMErrorName),
|
||||||
ProcessReadEOF(TrustedFileReader, GenerationId, ReadMetaData, Vec<u8>)
|
ProcessReadEOF(TrustedFileReader, GenerationId, ReadMetaData, DataSlice)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Runnable for FileReaderEvent {
|
impl Runnable for FileReaderEvent {
|
||||||
|
@ -406,7 +405,7 @@ impl Runnable for FileReaderEvent {
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://w3c.github.io/FileAPI/#task-read-operation
|
// https://w3c.github.io/FileAPI/#task-read-operation
|
||||||
fn perform_annotated_read_operation(gen_id: GenerationId, data: ReadMetaData, blob_contents: Receiver<Vec<u8>>,
|
fn perform_annotated_read_operation(gen_id: GenerationId, data: ReadMetaData, blob_contents: DataSlice,
|
||||||
filereader: TrustedFileReader, script_chan: Box<ScriptChan + Send>) {
|
filereader: TrustedFileReader, script_chan: Box<ScriptChan + Send>) {
|
||||||
let chan = &script_chan;
|
let chan = &script_chan;
|
||||||
// Step 4
|
// Step 4
|
||||||
|
@ -416,16 +415,6 @@ fn perform_annotated_read_operation(gen_id: GenerationId, data: ReadMetaData, bl
|
||||||
let task = box FileReaderEvent::ProcessReadData(filereader.clone(), gen_id);
|
let task = box FileReaderEvent::ProcessReadData(filereader.clone(), gen_id);
|
||||||
chan.send(CommonScriptMsg::RunnableMsg(FileRead, task)).unwrap();
|
chan.send(CommonScriptMsg::RunnableMsg(FileRead, task)).unwrap();
|
||||||
|
|
||||||
let bytes = match blob_contents.recv() {
|
let task = box FileReaderEvent::ProcessReadEOF(filereader, gen_id, data, blob_contents);
|
||||||
Ok(bytes) => bytes,
|
|
||||||
Err(_) => {
|
|
||||||
let task = box FileReaderEvent::ProcessReadError(filereader,
|
|
||||||
gen_id, DOMErrorName::NotFoundError);
|
|
||||||
chan.send(CommonScriptMsg::RunnableMsg(FileRead, task)).unwrap();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let task = box FileReaderEvent::ProcessReadEOF(filereader, gen_id, data, bytes);
|
|
||||||
chan.send(CommonScriptMsg::RunnableMsg(FileRead, task)).unwrap();
|
chan.send(CommonScriptMsg::RunnableMsg(FileRead, task)).unwrap();
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,7 +85,7 @@ impl TestBindingMethods for TestBinding {
|
||||||
fn EnumAttribute(&self) -> TestEnum { TestEnum::_empty }
|
fn EnumAttribute(&self) -> TestEnum { TestEnum::_empty }
|
||||||
fn SetEnumAttribute(&self, _: TestEnum) {}
|
fn SetEnumAttribute(&self, _: TestEnum) {}
|
||||||
fn InterfaceAttribute(&self) -> Root<Blob> {
|
fn InterfaceAttribute(&self) -> Root<Blob> {
|
||||||
Blob::new(global_root_from_reflector(self).r(), None, "")
|
Blob::new(global_root_from_reflector(self).r(), Vec::new(), "")
|
||||||
}
|
}
|
||||||
fn SetInterfaceAttribute(&self, _: &Blob) {}
|
fn SetInterfaceAttribute(&self, _: &Blob) {}
|
||||||
fn UnionAttribute(&self) -> HTMLElementOrLong { HTMLElementOrLong::eLong(0) }
|
fn UnionAttribute(&self) -> HTMLElementOrLong { HTMLElementOrLong::eLong(0) }
|
||||||
|
@ -143,7 +143,7 @@ impl TestBindingMethods for TestBinding {
|
||||||
fn SetAttr_to_automatically_rename(&self, _: DOMString) {}
|
fn SetAttr_to_automatically_rename(&self, _: DOMString) {}
|
||||||
fn GetEnumAttributeNullable(&self) -> Option<TestEnum> { Some(TestEnum::_empty) }
|
fn GetEnumAttributeNullable(&self) -> Option<TestEnum> { Some(TestEnum::_empty) }
|
||||||
fn GetInterfaceAttributeNullable(&self) -> Option<Root<Blob>> {
|
fn GetInterfaceAttributeNullable(&self) -> Option<Root<Blob>> {
|
||||||
Some(Blob::new(global_root_from_reflector(self).r(), None, ""))
|
Some(Blob::new(global_root_from_reflector(self).r(), Vec::new(), ""))
|
||||||
}
|
}
|
||||||
fn SetInterfaceAttributeNullable(&self, _: Option<&Blob>) {}
|
fn SetInterfaceAttributeNullable(&self, _: Option<&Blob>) {}
|
||||||
fn GetInterfaceAttributeWeak(&self) -> Option<Root<URL>> {
|
fn GetInterfaceAttributeWeak(&self) -> Option<Root<URL>> {
|
||||||
|
@ -182,7 +182,7 @@ impl TestBindingMethods for TestBinding {
|
||||||
fn ReceiveByteString(&self) -> ByteString { ByteString::new(vec!()) }
|
fn ReceiveByteString(&self) -> ByteString { ByteString::new(vec!()) }
|
||||||
fn ReceiveEnum(&self) -> TestEnum { TestEnum::_empty }
|
fn ReceiveEnum(&self) -> TestEnum { TestEnum::_empty }
|
||||||
fn ReceiveInterface(&self) -> Root<Blob> {
|
fn ReceiveInterface(&self) -> Root<Blob> {
|
||||||
Blob::new(global_root_from_reflector(self).r(), None, "")
|
Blob::new(global_root_from_reflector(self).r(), Vec::new(), "")
|
||||||
}
|
}
|
||||||
fn ReceiveAny(&self, _: *mut JSContext) -> JSVal { NullValue() }
|
fn ReceiveAny(&self, _: *mut JSContext) -> JSVal { NullValue() }
|
||||||
fn ReceiveObject(&self, _: *mut JSContext) -> *mut JSObject { panic!() }
|
fn ReceiveObject(&self, _: *mut JSContext) -> *mut JSObject { panic!() }
|
||||||
|
@ -207,7 +207,7 @@ impl TestBindingMethods for TestBinding {
|
||||||
fn ReceiveNullableByteString(&self) -> Option<ByteString> { Some(ByteString::new(vec!())) }
|
fn ReceiveNullableByteString(&self) -> Option<ByteString> { Some(ByteString::new(vec!())) }
|
||||||
fn ReceiveNullableEnum(&self) -> Option<TestEnum> { Some(TestEnum::_empty) }
|
fn ReceiveNullableEnum(&self) -> Option<TestEnum> { Some(TestEnum::_empty) }
|
||||||
fn ReceiveNullableInterface(&self) -> Option<Root<Blob>> {
|
fn ReceiveNullableInterface(&self) -> Option<Root<Blob>> {
|
||||||
Some(Blob::new(global_root_from_reflector(self).r(), None, ""))
|
Some(Blob::new(global_root_from_reflector(self).r(), Vec::new(), ""))
|
||||||
}
|
}
|
||||||
fn ReceiveNullableObject(&self, _: *mut JSContext) -> *mut JSObject { ptr::null_mut() }
|
fn ReceiveNullableObject(&self, _: *mut JSContext) -> *mut JSObject { ptr::null_mut() }
|
||||||
fn ReceiveNullableUnion(&self) -> Option<HTMLElementOrLong> {
|
fn ReceiveNullableUnion(&self) -> Option<HTMLElementOrLong> {
|
||||||
|
|
|
@ -381,19 +381,20 @@ impl WebSocketMethods for WebSocket {
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-websocket-send
|
// https://html.spec.whatwg.org/multipage/#dom-websocket-send
|
||||||
fn Send_(&self, data: &Blob) -> Fallible<()> {
|
fn Send_(&self, blob: &Blob) -> Fallible<()> {
|
||||||
|
|
||||||
/* As per https://html.spec.whatwg.org/multipage/#websocket
|
/* As per https://html.spec.whatwg.org/multipage/#websocket
|
||||||
the buffered amount needs to be clamped to u32, even though Blob.Size() is u64
|
the buffered amount needs to be clamped to u32, even though Blob.Size() is u64
|
||||||
If the buffer limit is reached in the first place, there are likely other major problems
|
If the buffer limit is reached in the first place, there are likely other major problems
|
||||||
*/
|
*/
|
||||||
let data_byte_len = data.Size();
|
let data_byte_len = blob.Size();
|
||||||
let send_data = try!(self.send_impl(data_byte_len));
|
let send_data = try!(self.send_impl(data_byte_len));
|
||||||
|
|
||||||
if send_data {
|
if send_data {
|
||||||
let mut other_sender = self.sender.borrow_mut();
|
let mut other_sender = self.sender.borrow_mut();
|
||||||
let my_sender = other_sender.as_mut().unwrap();
|
let my_sender = other_sender.as_mut().unwrap();
|
||||||
let _ = my_sender.send(WebSocketDomAction::SendMessage(MessageData::Binary(data.clone_bytes())));
|
let bytes = blob.get_data().get_bytes().to_vec();
|
||||||
|
let _ = my_sender.send(WebSocketDomAction::SendMessage(MessageData::Binary(bytes)));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -579,7 +580,7 @@ impl Runnable for MessageReceivedTask {
|
||||||
MessageData::Binary(data) => {
|
MessageData::Binary(data) => {
|
||||||
match ws.binary_type.get() {
|
match ws.binary_type.get() {
|
||||||
BinaryType::Blob => {
|
BinaryType::Blob => {
|
||||||
let blob = Blob::new(global.r(), Some(data), "");
|
let blob = Blob::new(global.r(), data, "");
|
||||||
blob.to_jsval(cx, message.handle_mut());
|
blob.to_jsval(cx, message.handle_mut());
|
||||||
}
|
}
|
||||||
BinaryType::Arraybuffer => {
|
BinaryType::Arraybuffer => {
|
||||||
|
|
34
tests/unit/script/dom/blob.rs
Normal file
34
tests/unit/script/dom/blob.rs
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
use script::dom::blob::{DataSlice};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_data_slice_without_start_end_should_match_buffer_size() {
|
||||||
|
let bytes = Arc::new(vec![1u8, 2u8, 3u8]);
|
||||||
|
let data = DataSlice::new(bytes, None, None);
|
||||||
|
assert_eq!(data.size(), 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_data_slice_should_prevent_reverse_bounds() {
|
||||||
|
let bytes = Arc::new(vec![1u8, 2, 3, 4, 5]);
|
||||||
|
let start = Some(3);
|
||||||
|
let end = Some(1);
|
||||||
|
|
||||||
|
let data = DataSlice::new(bytes, start, end);
|
||||||
|
assert_eq!(data.size(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_data_slice_should_respect_correct_bounds() {
|
||||||
|
let bytes = Arc::new(vec![1u8, 2, 3, 4, 5]);
|
||||||
|
let start = Some(1);
|
||||||
|
let end = Some(3);
|
||||||
|
|
||||||
|
let data = DataSlice::new(bytes, start, end);
|
||||||
|
let expected = [2u8, 3];
|
||||||
|
assert_eq!(&expected, data.get_bytes());
|
||||||
|
}
|
|
@ -8,3 +8,6 @@ extern crate util;
|
||||||
|
|
||||||
#[cfg(all(test, target_pointer_width = "64"))] mod size_of;
|
#[cfg(all(test, target_pointer_width = "64"))] mod size_of;
|
||||||
#[cfg(test)] mod textinput;
|
#[cfg(test)] mod textinput;
|
||||||
|
#[cfg(test)] mod dom {
|
||||||
|
mod blob;
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue