diff options
-rw-r--r-- | components/script/dom/blob.rs | 101 | ||||
-rw-r--r-- | components/script/dom/file.rs | 10 | ||||
-rw-r--r-- | components/script/dom/formdata.rs | 2 | ||||
-rw-r--r-- | components/script/dom/testbinding.rs | 8 | ||||
-rw-r--r-- | components/script/dom/webidls/Blob.webidl | 11 | ||||
-rw-r--r-- | tests/content/test_blob.html | 15 |
6 files changed, 125 insertions, 22 deletions
diff --git a/components/script/dom/blob.rs b/components/script/dom/blob.rs index 3380670d4f5..b0d0b155821 100644 --- a/components/script/dom/blob.rs +++ b/components/script/dom/blob.rs @@ -3,11 +3,15 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use dom::bindings::codegen::InheritTypes::FileDerived; -use dom::bindings::global::GlobalRef; -use dom::bindings::js::Temporary; +use dom::bindings::global::{GlobalRef, GlobalField}; +use dom::bindings::js::{JSRef, Temporary}; use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object}; use dom::bindings::error::Fallible; use dom::bindings::codegen::Bindings::BlobBinding; +use dom::bindings::codegen::Bindings::BlobBinding::BlobMethods; + +use servo_util::str::DOMString; +use std::cmp::{min, max}; #[jstraceable] pub enum BlobType { @@ -18,28 +22,107 @@ pub enum BlobType { #[dom_struct] pub struct Blob { reflector_: Reflector, - type_: BlobType + type_: BlobType, + bytes: Option<Vec<u8>>, + typeString: DOMString, + global: GlobalField + // isClosed_: bool } impl Blob { - pub fn new_inherited() -> Blob { + pub fn new_inherited(global: &GlobalRef, bytes: Option<Vec<u8>>) -> Blob { Blob { reflector_: Reflector::new(), - type_: BlobTypeId + type_: BlobTypeId, + bytes: bytes, + typeString: "".to_string(), + global: GlobalField::from_rooted(global) + //isClosed_: false } } - pub fn new(global: GlobalRef) -> Temporary<Blob> { - reflect_dom_object(box Blob::new_inherited(), - global, + pub fn new(global: &GlobalRef, bytes: Option<Vec<u8>>) -> Temporary<Blob> { + reflect_dom_object(box Blob::new_inherited(global, bytes), + *global, BlobBinding::Wrap) } pub fn Constructor(global: &GlobalRef) -> Fallible<Temporary<Blob>> { - Ok(Blob::new(*global)) + Ok(Blob::new(global, None)) + } + + pub fn Constructor_(global: &GlobalRef, blobParts: DOMString) -> Fallible<Temporary<Blob>> { + //TODO: accept other blobParts types - ArrayBuffer or ArrayBufferView or Blob + //TODO: accept options parameter + let bytes: Option<Vec<u8>> = Some(blobParts.into_bytes()); + Ok(Blob::new(global, bytes)) } } +impl<'a> BlobMethods for JSRef<'a, Blob> { + fn Size(self) -> u64{ + match self.bytes { + None => 0, + Some(ref bytes) => bytes.len() as u64 + } + } + + fn Type(self) -> DOMString { + self.typeString.clone() + } + + fn Slice(self, start: Option<i64>, end: Option<i64>, + _contentType: Option<DOMString>) -> Temporary<Blob> { + let size: i64 = self.Size().to_i64().unwrap(); + let relativeStart: i64 = match start { + None => 0, + Some(start) => { + if start < 0 { + max(size.to_i64().unwrap() + start, 0) + } else { + min(start, size) + } + } + }; + let relativeEnd: i64 = match end { + None => size, + Some(end) => { + if end < 0 { + max(size + end, 0) + } else { + min(end, size) + } + } + }; + /* + let relativeContentType = match contentType { + None => "".to_string(), + Some(str) => str + }; + */ + //TODO: actually use relativeContentType in constructor + let span: i64 = max(relativeEnd - relativeStart, 0); + let global = self.global.root(); + match self.bytes { + None => Blob::new(&global.root_ref(), None), + Some(ref vec) => { + let start = relativeStart.to_uint().unwrap(); + let end = (relativeStart + span).to_uint().unwrap(); + let mut bytes: Vec<u8> = Vec::new(); + bytes.push_all(vec.slice(start, end)); + Blob::new(&global.root_ref(), Some(bytes)) + } + } + } + + //fn IsClosed(self) -> bool { + // self.isClosed_.clone() + //} + + //fn Close(self) { + // TODO + //} +} impl Reflectable for Blob { fn reflector<'a>(&'a self) -> &'a Reflector { &self.reflector_ diff --git a/components/script/dom/file.rs b/components/script/dom/file.rs index 26555755401..52fb22abd12 100644 --- a/components/script/dom/file.rs +++ b/components/script/dom/file.rs @@ -18,9 +18,9 @@ pub struct File { } impl File { - fn new_inherited(_file_bits: JSRef<Blob>, name: DOMString) -> File { + fn new_inherited(global: &GlobalRef, _file_bits: JSRef<Blob>, name: DOMString) -> File { File { - blob: Blob::new_inherited(), + blob: Blob::new_inherited(global, None), name: name, type_: FileTypeId } @@ -28,9 +28,9 @@ impl File { // the relevant subfields of file_bits should be copied over } - pub fn new(global: GlobalRef, file_bits: JSRef<Blob>, name: DOMString) -> Temporary<File> { - reflect_dom_object(box File::new_inherited(file_bits, name), - global, + pub fn new(global: &GlobalRef, file_bits: JSRef<Blob>, name: DOMString) -> Temporary<File> { + reflect_dom_object(box File::new_inherited(global, file_bits, name), + *global, FileBinding::Wrap) } diff --git a/components/script/dom/formdata.rs b/components/script/dom/formdata.rs index 4334ca379cc..0c9a5e81f8b 100644 --- a/components/script/dom/formdata.rs +++ b/components/script/dom/formdata.rs @@ -121,6 +121,6 @@ impl PrivateFormDataHelpers for FormData { let global = self.global.root(); let f: Option<JSRef<File>> = FileCast::to_ref(value); let name = filename.unwrap_or(f.map(|inner| inner.name().clone()).unwrap_or("blob".to_string())); - File::new(global.root_ref(), value, name) + File::new(&global.root_ref(), value, name) } } diff --git a/components/script/dom/testbinding.rs b/components/script/dom/testbinding.rs index 47bc333475b..bdae481dcea 100644 --- a/components/script/dom/testbinding.rs +++ b/components/script/dom/testbinding.rs @@ -57,7 +57,7 @@ impl<'a> TestBindingMethods for JSRef<'a, TestBinding> { fn SetEnumAttribute(self, _: TestEnum) {} fn InterfaceAttribute(self) -> Temporary<Blob> { let global = self.global.root(); - Blob::new(global.root_ref()) + Blob::new(&global.root_ref(), None) } fn SetInterfaceAttribute(self, _: JSRef<Blob>) {} fn UnionAttribute(self) -> HTMLElementOrLong { eLong(0) } @@ -96,7 +96,7 @@ impl<'a> TestBindingMethods for JSRef<'a, TestBinding> { fn GetEnumAttributeNullable(self) -> Option<TestEnum> { Some(_empty) } fn GetInterfaceAttributeNullable(self) -> Option<Temporary<Blob>> { let global = self.global.root(); - Some(Blob::new(global.root_ref())) + Some(Blob::new(&global.root_ref(), None)) } fn SetInterfaceAttributeNullable(self, _: Option<JSRef<Blob>>) {} fn GetUnionAttributeNullable(self) -> Option<HTMLElementOrLong> { Some(eLong(0)) } @@ -120,7 +120,7 @@ impl<'a> TestBindingMethods for JSRef<'a, TestBinding> { fn ReceiveEnum(self) -> TestEnum { _empty } fn ReceiveInterface(self) -> Temporary<Blob> { let global = self.global.root(); - Blob::new(global.root_ref()) + Blob::new(&global.root_ref(), None) } fn ReceiveAny(self, _: *mut JSContext) -> JSVal { NullValue() } fn ReceiveUnion(self) -> HTMLElementOrLong { eLong(0) } @@ -142,7 +142,7 @@ impl<'a> TestBindingMethods for JSRef<'a, TestBinding> { fn ReceiveNullableEnum(self) -> Option<TestEnum> { Some(_empty) } fn ReceiveNullableInterface(self) -> Option<Temporary<Blob>> { let global = self.global.root(); - Some(Blob::new(global.root_ref())) + Some(Blob::new(&global.root_ref(), None)) } fn ReceiveNullableUnion(self) -> Option<HTMLElementOrLong> { Some(eLong(0)) } fn ReceiveNullableUnion2(self) -> Option<EventOrString> { Some(eString("".to_string())) } diff --git a/components/script/dom/webidls/Blob.webidl b/components/script/dom/webidls/Blob.webidl index 3a544024338..6c8bbed1935 100644 --- a/components/script/dom/webidls/Blob.webidl +++ b/components/script/dom/webidls/Blob.webidl @@ -6,18 +6,23 @@ // http://dev.w3.org/2006/webapi/FileAPI/#dfn-Blob //[Exposed=Window,Worker][Constructor, // Constructor(sequence<(ArrayBuffer or ArrayBufferView or Blob or DOMString)> blobParts, optional BlobPropertyBag options)] -[Constructor] +[Constructor, + Constructor(DOMString blobParts)] interface Blob { - //readonly attribute unsigned long long size; - //readonly attribute DOMString type; + readonly attribute unsigned long long size; + readonly attribute DOMString type; //readonly attribute boolean isClosed; //slice Blob into byte-ranged chunks + //TODO: implement slice with [Clamp] //Blob slice([Clamp] optional long long start, // [Clamp] optional long long end, // optional DOMString contentType); + Blob slice(optional long long start, + optional long long end, + optional DOMString contentType); //void close(); }; diff --git a/tests/content/test_blob.html b/tests/content/test_blob.html new file mode 100644 index 00000000000..e2b8b897eb4 --- /dev/null +++ b/tests/content/test_blob.html @@ -0,0 +1,15 @@ +<html> + <head> + <script src="harness.js"></script> + <script> + var testData = ['<a id="a"><b id="b">hey!</b></a>']; + var b = new Blob(testData); // the blob + is(b.size, 32); + is(b.type, ""); + + var bs = b.slice(0, 5); + is(bs.size, 5); + is(b.type, ""); + </script> + </head> +</html> |