Rewrite Blob constructor interface

This commit is contained in:
Zhen Zhang 2016-05-10 20:19:10 +08:00
parent 33fa63a3c5
commit f43009333f
5 changed files with 60 additions and 50 deletions

View file

@ -28,6 +28,7 @@ pub struct DataSlice {
} }
impl DataSlice { impl DataSlice {
/// Construct DataSlice from reference counted bytes
pub fn new(bytes: Arc<Vec<u8>>, start: Option<i64>, end: Option<i64>) -> DataSlice { pub fn new(bytes: Arc<Vec<u8>>, start: Option<i64>, end: Option<i64>) -> DataSlice {
let size = bytes.len() as i64; let size = bytes.len() as i64;
let relativeStart: i64 = match start { let relativeStart: i64 = match start {
@ -62,14 +63,21 @@ impl DataSlice {
} }
} }
/// Construct an empty data slice
pub fn empty() -> DataSlice {
DataSlice {
bytes: Arc::new(Vec::new()),
bytes_start: 0,
bytes_end: 0,
}
}
/// Get sliced bytes
pub fn get_bytes(&self) -> &[u8] { pub fn get_bytes(&self) -> &[u8] {
&self.bytes[self.bytes_start..self.bytes_end] &self.bytes[self.bytes_start..self.bytes_end]
} }
pub fn get_all_bytes(&self) -> Arc<Vec<u8>> { /// Get length of sliced bytes
self.bytes.clone()
}
pub fn size(&self) -> u64 { pub fn size(&self) -> u64 {
(self.bytes_end as u64) - (self.bytes_start as u64) (self.bytes_end as u64) - (self.bytes_start as u64)
} }
@ -86,38 +94,20 @@ pub struct Blob {
isClosed_: Cell<bool>, 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 { impl Blob {
pub fn new_inherited(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(),
isClosed_: Cell::new(false),
}
}
pub fn new(global: GlobalRef, bytes: Vec<u8>, typeString: &str) -> Root<Blob> { pub fn new(global: GlobalRef, slice: DataSlice, typeString: &str) -> Root<Blob> {
let boxed_blob = box Blob::new_inherited(Arc::new(bytes), None, None, typeString); let boxed_blob = box Blob::new_inherited(slice, typeString);
reflect_dom_object(boxed_blob, global, BlobBinding::Wrap) reflect_dom_object(boxed_blob, global, BlobBinding::Wrap)
} }
fn new_sliced(global: GlobalRef, pub fn new_inherited(slice: DataSlice, typeString: &str) -> Blob {
bytes: Arc<Vec<u8>>, Blob {
bytes_start: Option<i64>, reflector_: Reflector::new(),
bytes_end: Option<i64>, data: slice,
typeString: &str) -> Root<Blob> { typeString: typeString.to_owned(),
isClosed_: Cell::new(false),
let boxed_blob = box Blob::new_inherited(bytes, bytes_start, bytes_end, typeString); }
reflect_dom_object(boxed_blob, global, BlobBinding::Wrap)
} }
// https://w3c.github.io/FileAPI/#constructorBlob // https://w3c.github.io/FileAPI/#constructorBlob
@ -143,12 +133,9 @@ impl Blob {
.collect() .collect()
} }
}; };
let typeString = if is_ascii_printable(&blobPropertyBag.type_) {
&*blobPropertyBag.type_ let slice = DataSlice::new(Arc::new(bytes), None, None);
} else { Ok(Blob::new(global, slice, blobPropertyBag.get_typestring()))
""
};
Ok(Blob::new(global, bytes, &typeString.to_ascii_lowercase()))
} }
pub fn get_data(&self) -> &DataSlice { pub fn get_data(&self) -> &DataSlice {
@ -187,7 +174,7 @@ impl BlobMethods for Blob {
}; };
let global = self.global(); let global = self.global();
let bytes = self.data.bytes.clone(); let bytes = self.data.bytes.clone();
Blob::new_sliced(global.r(), bytes, start, end, &relativeContentType) Blob::new(global.r(), DataSlice::new(bytes, start, end), &relativeContentType)
} }
// https://w3c.github.io/FileAPI/#dfn-isClosed // https://w3c.github.io/FileAPI/#dfn-isClosed
@ -209,3 +196,20 @@ impl BlobMethods for Blob {
} }
} }
impl BlobBinding::BlobPropertyBag {
pub fn get_typestring(&self) -> &str {
if is_ascii_printable(&self.type_) {
&*self.type_
} else {
""
}
}
}
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')
}

View file

@ -20,7 +20,7 @@ use dom::bindings::num::Finite;
use dom::bindings::reflector::{Reflectable, Reflector, reflect_dom_object}; use dom::bindings::reflector::{Reflectable, Reflector, reflect_dom_object};
use dom::bindings::str::{ByteString, USVString}; use dom::bindings::str::{ByteString, USVString};
use dom::bindings::weakref::MutableWeakRef; use dom::bindings::weakref::MutableWeakRef;
use dom::blob::Blob; use dom::blob::{Blob, DataSlice};
use dom::url::URL; use dom::url::URL;
use js::jsapi::{HandleValue, JSContext, JSObject}; use js::jsapi::{HandleValue, JSContext, JSObject};
use js::jsval::{JSVal, NullValue}; use js::jsval::{JSVal, NullValue};
@ -100,7 +100,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(self.global().r(), Vec::new(), "") Blob::new(self.global().r(), DataSlice::empty(), "")
} }
fn SetInterfaceAttribute(&self, _: &Blob) {} fn SetInterfaceAttribute(&self, _: &Blob) {}
fn UnionAttribute(&self) -> HTMLElementOrLong { HTMLElementOrLong::Long(0) } fn UnionAttribute(&self) -> HTMLElementOrLong { HTMLElementOrLong::Long(0) }
@ -178,7 +178,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(self.global().r(), Vec::new(), "")) Some(Blob::new(self.global().r(), DataSlice::empty(), ""))
} }
fn SetInterfaceAttributeNullable(&self, _: Option<&Blob>) {} fn SetInterfaceAttributeNullable(&self, _: Option<&Blob>) {}
fn GetInterfaceAttributeWeak(&self) -> Option<Root<URL>> { fn GetInterfaceAttributeWeak(&self) -> Option<Root<URL>> {
@ -229,7 +229,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(self.global().r(), Vec::new(), "") Blob::new(self.global().r(), DataSlice::empty(), "")
} }
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!() }
@ -246,7 +246,7 @@ impl TestBindingMethods for TestBinding {
} }
fn ReceiveSequence(&self) -> Vec<i32> { vec![1] } fn ReceiveSequence(&self) -> Vec<i32> { vec![1] }
fn ReceiveInterfaceSequence(&self) -> Vec<Root<Blob>> { fn ReceiveInterfaceSequence(&self) -> Vec<Root<Blob>> {
vec![Blob::new(self.global().r(), Vec::new(), "")] vec![Blob::new(self.global().r(), DataSlice::empty(), "")]
} }
fn ReceiveNullableBoolean(&self) -> Option<bool> { Some(false) } fn ReceiveNullableBoolean(&self) -> Option<bool> { Some(false) }
@ -267,7 +267,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(self.global().r(), Vec::new(), "")) Some(Blob::new(self.global().r(), DataSlice::empty(), ""))
} }
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> {

View file

@ -2,8 +2,9 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// http://dev.w3.org/2006/webapi/FileAPI/#dfn-Blob // https://w3c.github.io/FileAPI/#blob
[Constructor(optional sequence<(/*ArrayBuffer or ArrayBufferView or */Blob or DOMString)> blobParts,
[Constructor(optional sequence<BlobPart> blobParts,
optional BlobPropertyBag options), optional BlobPropertyBag options),
Exposed=Window/*,Worker*/] Exposed=Window/*,Worker*/]
interface Blob { interface Blob {
@ -26,3 +27,5 @@ dictionary BlobPropertyBag {
DOMString type = ""; DOMString type = "";
}; };
typedef (/*ArrayBuffer or ArrayBufferView or */Blob or DOMString) BlobPart;

View file

@ -18,7 +18,7 @@ use dom::bindings::refcounted::Trusted;
use dom::bindings::reflector::{Reflectable, reflect_dom_object}; use dom::bindings::reflector::{Reflectable, reflect_dom_object};
use dom::bindings::str::{USVString, is_token}; use dom::bindings::str::{USVString, is_token};
use dom::bindings::trace::JSTraceable; use dom::bindings::trace::JSTraceable;
use dom::blob::Blob; use dom::blob::{Blob, DataSlice};
use dom::closeevent::CloseEvent; use dom::closeevent::CloseEvent;
use dom::event::{Event, EventBubbles, EventCancelable}; use dom::event::{Event, EventBubbles, EventCancelable};
use dom::eventtarget::EventTarget; use dom::eventtarget::EventTarget;
@ -42,6 +42,7 @@ use std::ascii::AsciiExt;
use std::borrow::ToOwned; use std::borrow::ToOwned;
use std::cell::Cell; use std::cell::Cell;
use std::ptr; use std::ptr;
use std::sync::Arc;
use std::thread; use std::thread;
use util::str::DOMString; use util::str::DOMString;
use websocket::client::request::Url; use websocket::client::request::Url;
@ -598,7 +599,8 @@ 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(), data, ""); let slice = DataSlice::new(Arc::new(data), None, None);
let blob = Blob::new(global.r(), slice, "");
blob.to_jsval(cx, message.handle_mut()); blob.to_jsval(cx, message.handle_mut());
} }
BinaryType::Arraybuffer => { BinaryType::Arraybuffer => {

View file

@ -22,7 +22,7 @@ use dom::bindings::js::{Root, RootedReference};
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::bindings::str::{ByteString, USVString, is_token}; use dom::bindings::str::{ByteString, USVString, is_token};
use dom::blob::Blob; use dom::blob::{Blob, DataSlice};
use dom::document::DocumentSource; use dom::document::DocumentSource;
use dom::document::{Document, IsHTMLDocument}; use dom::document::{Document, IsHTMLDocument};
use dom::event::{Event, EventBubbles, EventCancelable}; use dom::event::{Event, EventBubbles, EventCancelable};
@ -1117,7 +1117,8 @@ impl XMLHttpRequest {
let mime = self.final_mime_type().as_ref().map(Mime::to_string).unwrap_or("".to_owned()); let mime = self.final_mime_type().as_ref().map(Mime::to_string).unwrap_or("".to_owned());
// Step 3, 4 // Step 3, 4
let blob = Blob::new(self.global().r(), self.response.borrow().to_vec(), &mime); let slice = DataSlice::new(Arc::new(self.response.borrow().to_vec()), None, None);
let blob = Blob::new(self.global().r(), slice, &mime);
self.response_blob.set(Some(blob.r())); self.response_blob.set(Some(blob.r()));
blob blob
} }