mirror of
https://github.com/servo/servo.git
synced 2025-06-11 10:00:18 +00:00
Issue #1820 - Improve the Blob implementation
This commit is contained in:
parent
bdb3a2538b
commit
f2885b8fc7
6 changed files with 125 additions and 22 deletions
|
@ -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_
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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())) }
|
||||
|
|
|
@ -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();
|
||||
|
||||
};
|
||||
|
|
15
tests/content/test_blob.html
Normal file
15
tests/content/test_blob.html
Normal file
|
@ -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>
|
Loading…
Add table
Add a link
Reference in a new issue