mirror of
https://github.com/servo/servo.git
synced 2025-08-03 20:50:07 +01: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::js::Root;
|
||||
use dom::bindings::reflector::{Reflector, reflect_dom_object};
|
||||
use dom::bindings::trace::JSTraceable;
|
||||
use num::ToPrimitive;
|
||||
use std::ascii::AsciiExt;
|
||||
use std::borrow::ToOwned;
|
||||
use std::cell::Cell;
|
||||
use std::cmp::{max, min};
|
||||
use std::sync::mpsc::Sender;
|
||||
use std::sync::Arc;
|
||||
use util::str::DOMString;
|
||||
|
||||
// https://w3c.github.io/FileAPI/#blob
|
||||
#[dom_struct]
|
||||
pub struct Blob {
|
||||
reflector_: Reflector,
|
||||
bytes: Option<Vec<u8>>,
|
||||
typeString: String,
|
||||
global: GlobalField,
|
||||
isClosed_: Cell<bool>,
|
||||
#[derive(Clone, JSTraceable)]
|
||||
pub struct DataSlice {
|
||||
bytes: Arc<Vec<u8>>,
|
||||
bytes_start: usize,
|
||||
bytes_end: usize
|
||||
}
|
||||
|
||||
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: 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();
|
||||
impl DataSlice {
|
||||
pub fn new(bytes: Arc<Vec<u8>>, start: Option<i64>, end: Option<i64>) -> DataSlice {
|
||||
let size = bytes.len() as i64;
|
||||
let relativeStart: i64 = match start {
|
||||
None => 0,
|
||||
Some(start) => {
|
||||
if start < 0 {
|
||||
max(size.to_i64().unwrap() + start, 0)
|
||||
max(size + start, 0)
|
||||
} else {
|
||||
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 {
|
||||
None => DOMString::new(),
|
||||
Some(mut str) => {
|
||||
|
@ -132,18 +171,9 @@ impl BlobMethods for Blob {
|
|||
}
|
||||
}
|
||||
};
|
||||
let span: i64 = max(relativeEnd - relativeStart, 0);
|
||||
let global = self.global.root();
|
||||
match self.bytes {
|
||||
None => Blob::new(global.r(), None, &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)
|
||||
}
|
||||
}
|
||||
let bytes = self.data.bytes.clone();
|
||||
Blob::new_sliced(global.r(), bytes, start, end, &relativeContentType)
|
||||
}
|
||||
|
||||
// https://w3c.github.io/FileAPI/#dfn-isClosed
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue