aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom
diff options
context:
space:
mode:
Diffstat (limited to 'components/script/dom')
-rw-r--r--components/script/dom/bindings/trace.rs3
-rw-r--r--components/script/dom/blob.rs206
-rw-r--r--components/script/dom/file.rs2
-rw-r--r--components/script/dom/htmlinputelement.rs5
-rw-r--r--components/script/dom/url.rs40
5 files changed, 173 insertions, 83 deletions
diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs
index 1d1433b2693..a0813a047df 100644
--- a/components/script/dom/bindings/trace.rs
+++ b/components/script/dom/bindings/trace.rs
@@ -57,7 +57,7 @@ use js::jsval::JSVal;
use js::rust::Runtime;
use libc;
use msg::constellation_msg::{FrameType, PipelineId, SubpageId, WindowSizeData, WindowSizeType, ReferrerPolicy};
-use net_traits::filemanager_thread::SelectedFileId;
+use net_traits::filemanager_thread::{SelectedFileId, RelativePos};
use net_traits::image::base::{Image, ImageMetadata};
use net_traits::image_cache_thread::{ImageCacheChan, ImageCacheThread};
use net_traits::response::HttpsState;
@@ -331,6 +331,7 @@ no_jsmanaged_fields!(ReferrerPolicy);
no_jsmanaged_fields!(ResourceThreads);
no_jsmanaged_fields!(SystemTime);
no_jsmanaged_fields!(SelectedFileId);
+no_jsmanaged_fields!(RelativePos);
no_jsmanaged_fields!(OpaqueStyleAndLayoutData);
no_jsmanaged_fields!(CSSErrorReporter);
no_jsmanaged_fields!(WebGLBufferId);
diff --git a/components/script/dom/blob.rs b/components/script/dom/blob.rs
index dcb4c68f34a..1bc0498fb35 100644
--- a/components/script/dom/blob.rs
+++ b/components/script/dom/blob.rs
@@ -8,17 +8,18 @@ use dom::bindings::codegen::Bindings::BlobBinding::BlobMethods;
use dom::bindings::codegen::UnionTypes::BlobOrString;
use dom::bindings::error::{Error, Fallible};
use dom::bindings::global::GlobalRef;
-use dom::bindings::js::Root;
+use dom::bindings::js::{JS, Root};
use dom::bindings::reflector::{Reflectable, Reflector, reflect_dom_object};
use dom::bindings::str::DOMString;
use encoding::all::UTF_8;
use encoding::types::{EncoderTrap, Encoding};
use ipc_channel::ipc;
-use net_traits::filemanager_thread::{FileManagerThreadMsg, SelectedFileId};
-use num_traits::ToPrimitive;
+use net_traits::IpcSend;
+use net_traits::blob_url_store::BlobURLStoreEntry;
+use net_traits::filemanager_thread::{FileManagerThreadMsg, SelectedFileId, RelativePos};
use std::ascii::AsciiExt;
use std::cell::Cell;
-use std::cmp::{max, min};
+use std::ops::Range;
use std::sync::Arc;
#[derive(Clone, JSTraceable)]
@@ -31,36 +32,12 @@ pub struct DataSlice {
impl DataSlice {
/// Construct DataSlice from reference counted bytes
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 + 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 span: i64 = max(relativeEnd - relativeStart, 0);
- let start = relativeStart.to_usize().unwrap();
- let end = (relativeStart + span).to_usize().unwrap();
+ let range = RelativePos::from_opts(start, end).to_abs_range(bytes.len());
DataSlice {
bytes: bytes,
- bytes_start: start,
- bytes_end: end
+ bytes_start: range.start,
+ bytes_end: range.end,
}
}
@@ -87,15 +64,30 @@ impl DataSlice {
pub fn size(&self) -> u64 {
(self.bytes_end as u64) - (self.bytes_start as u64)
}
-}
+ /// Further adjust the slice range based on passed-in relative positions
+ pub fn slice(&self, pos: &RelativePos) -> DataSlice {
+ let old_size = self.size();
+ let range = pos.to_abs_range(old_size as usize);
+ DataSlice {
+ bytes: self.bytes.clone(),
+ bytes_start: self.bytes_start + range.start,
+ bytes_end: self.bytes_start + range.end,
+ }
+ }
+}
-#[derive(Clone, JSTraceable)]
+#[must_root]
+#[derive(JSTraceable)]
pub enum BlobImpl {
- /// File-based, cached backend
+ /// File-based blob, including id and possibly cached content
File(SelectedFileId, DOMRefCell<Option<DataSlice>>),
- /// Memory-based backend
+ /// Memory-based blob
Memory(DataSlice),
+ /// Sliced blob, including parent blob and
+ /// relative positions representing current slicing range,
+ /// it is leaf of a two-layer fat tree
+ Sliced(JS<Blob>, RelativePos),
}
impl BlobImpl {
@@ -120,26 +112,58 @@ impl BlobImpl {
pub struct Blob {
reflector_: Reflector,
#[ignore_heap_size_of = "No clear owner"]
- blob_impl: BlobImpl,
+ blob_impl: DOMRefCell<BlobImpl>,
typeString: String,
isClosed_: Cell<bool>,
}
impl Blob {
+ #[allow(unrooted_must_root)]
pub fn new(global: GlobalRef, blob_impl: BlobImpl, typeString: String) -> Root<Blob> {
let boxed_blob = box Blob::new_inherited(blob_impl, typeString);
reflect_dom_object(boxed_blob, global, BlobBinding::Wrap)
}
+ #[allow(unrooted_must_root)]
pub fn new_inherited(blob_impl: BlobImpl, typeString: String) -> Blob {
Blob {
reflector_: Reflector::new(),
- blob_impl: blob_impl,
+ blob_impl: DOMRefCell::new(blob_impl),
typeString: typeString,
isClosed_: Cell::new(false),
}
}
+ #[allow(unrooted_must_root)]
+ fn new_sliced(parent: &Blob, rel_pos: RelativePos,
+ relativeContentType: DOMString) -> Root<Blob> {
+ let global = parent.global();
+ let blob_impl = match *parent.blob_impl.borrow() {
+ BlobImpl::File(ref id, _) => {
+ inc_ref_id(global.r(), id.clone());
+
+ // Create new parent node
+ BlobImpl::Sliced(JS::from_ref(parent), rel_pos)
+ }
+ BlobImpl::Memory(_) => {
+ // Create new parent node
+ BlobImpl::Sliced(JS::from_ref(parent), rel_pos)
+ }
+ BlobImpl::Sliced(ref grandparent, ref old_rel_pos) => {
+ // Adjust the slicing position, using same parent
+ let new_rel_pos = old_rel_pos.slice_inner(&rel_pos);
+
+ if let BlobImpl::File(ref id, _) = *grandparent.blob_impl.borrow() {
+ inc_ref_id(global.r(), id.clone());
+ }
+
+ BlobImpl::Sliced(grandparent.clone(), new_rel_pos)
+ }
+ };
+
+ Blob::new(global.r(), blob_impl, relativeContentType.into())
+ }
+
// https://w3c.github.io/FileAPI/#constructorBlob
pub fn Constructor(global: GlobalRef,
blobParts: Option<Vec<BlobOrString>>,
@@ -160,19 +184,29 @@ impl Blob {
/// Get a slice to inner data, this might incur synchronous read and caching
pub fn get_slice(&self) -> Result<DataSlice, ()> {
- match self.blob_impl {
- BlobImpl::File(ref id, ref slice) => {
- match *slice.borrow() {
+ match *self.blob_impl.borrow() {
+ BlobImpl::File(ref id, ref cached) => {
+ let buffer = match *cached.borrow() {
Some(ref s) => Ok(s.clone()),
None => {
let global = self.global();
let s = read_file(global.r(), id.clone())?;
- *slice.borrow_mut() = Some(s.clone()); // Cached
Ok(s)
}
+ };
+
+ // Cache
+ if let Ok(buf) = buffer.clone() {
+ *cached.borrow_mut() = Some(buf);
}
+
+ buffer
+ }
+ BlobImpl::Memory(ref s) => Ok(s.clone()),
+ BlobImpl::Sliced(ref parent, ref rel_pos) => {
+ let dataslice = parent.get_slice_or_empty();
+ Ok(dataslice.slice(rel_pos))
}
- BlobImpl::Memory(ref s) => Ok(s.clone())
}
}
@@ -180,12 +214,83 @@ impl Blob {
pub fn get_slice_or_empty(&self) -> DataSlice {
self.get_slice().unwrap_or(DataSlice::empty())
}
+
+ pub fn get_id(&self) -> SelectedFileId {
+ match *self.blob_impl.borrow() {
+ BlobImpl::File(ref id, _) => id.clone(),
+ BlobImpl::Memory(ref slice) => self.promote_to_file(slice),
+ BlobImpl::Sliced(ref parent, ref rel_pos) => {
+ match *parent.blob_impl.borrow() {
+ BlobImpl::Sliced(_, _) => {
+ debug!("Sliced can't have a sliced parent");
+ // Return dummy id
+ SelectedFileId("".to_string())
+ }
+ BlobImpl::File(ref parent_id, _) =>
+ self.create_sliced_id(parent_id, rel_pos),
+ BlobImpl::Memory(ref parent_slice) => {
+ let parent_id = parent.promote_to_file(parent_slice);
+ *self.blob_impl.borrow_mut() = BlobImpl::Sliced(parent.clone(), rel_pos.clone());
+ self.create_sliced_id(&parent_id, rel_pos)
+ }
+ }
+ }
+ }
+ }
+
+ /// Promite memory-based Blob to file-based,
+ /// The bytes in data slice will be transferred to file manager thread
+ fn promote_to_file(&self, self_slice: &DataSlice) -> SelectedFileId {
+ let global = self.global();
+ let origin = global.r().get_url().origin().unicode_serialization();
+ let filemanager = global.r().resource_threads().sender();
+ let bytes = self_slice.get_bytes();
+ let rel_pos = RelativePos::from_abs_range(Range {
+ start: self_slice.bytes_start,
+ end: self_slice.bytes_end,
+ }, self_slice.bytes.len());
+
+ let entry = BlobURLStoreEntry {
+ type_string: self.typeString.clone(),
+ size: self.Size(),
+ bytes: bytes.to_vec(),
+ };
+
+ let (tx, rx) = ipc::channel().unwrap();
+ let _ = filemanager.send(FileManagerThreadMsg::TransferMemory(entry, rel_pos, tx, origin.clone()));
+
+ match rx.recv().unwrap() {
+ Ok(new_id) => SelectedFileId(new_id.0),
+ // Dummy id
+ Err(_) => SelectedFileId("".to_string()),
+ }
+ }
+
+ fn create_sliced_id(&self, parent_id: &SelectedFileId,
+ rel_pos: &RelativePos) -> SelectedFileId {
+ let global = self.global();
+
+ let origin = global.r().get_url().origin().unicode_serialization();
+
+ let filemanager = global.r().resource_threads().sender();
+ let (tx, rx) = ipc::channel().unwrap();
+ let msg = FileManagerThreadMsg::AddSlicedEntry(parent_id.clone(),
+ rel_pos.clone(),
+ tx, origin.clone());
+ let _ = filemanager.send(msg);
+ let new_id = rx.recv().unwrap().unwrap();
+
+ // Return the indirect id reference
+ SelectedFileId(new_id.0)
+ }
}
fn read_file(global: GlobalRef, id: SelectedFileId) -> Result<DataSlice, ()> {
let file_manager = global.filemanager_thread();
let (chan, recv) = ipc::channel().map_err(|_|())?;
- let _ = file_manager.send(FileManagerThreadMsg::ReadFile(chan, id));
+ let origin = global.get_url().origin().unicode_serialization();
+ let msg = FileManagerThreadMsg::ReadFile(chan, id, origin);
+ let _ = file_manager.send(msg);
let result = match recv.recv() {
Ok(ret) => ret,
@@ -248,10 +353,8 @@ impl BlobMethods for Blob {
}
};
- let global = self.global();
- let bytes = self.get_slice_or_empty().bytes.clone();
- let slice = DataSlice::new(bytes, start, end);
- Blob::new(global.r(), BlobImpl::new_from_slice(slice), relativeContentType.into())
+ let rel_pos = RelativePos::from_opts(start, end);
+ Blob::new_sliced(self, rel_pos, relativeContentType)
}
// https://w3c.github.io/FileAPI/#dfn-isClosed
@@ -274,7 +377,6 @@ impl BlobMethods for Blob {
}
}
-
impl BlobBinding::BlobPropertyBag {
/// Get the normalized inner type string
/// https://w3c.github.io/FileAPI/#dfn-type
@@ -292,3 +394,11 @@ fn is_ascii_printable(string: &str) -> bool {
// https://w3c.github.io/FileAPI/#constructorBlob
string.chars().all(|c| c >= '\x20' && c <= '\x7E')
}
+
+/// Bump the reference counter in file manager thread
+fn inc_ref_id(global: GlobalRef, id: SelectedFileId) {
+ let file_manager = global.filemanager_thread();
+ let origin = global.get_url().origin().unicode_serialization();
+ let msg = FileManagerThreadMsg::IncRef(id, origin);
+ let _ = file_manager.send(msg);
+}
diff --git a/components/script/dom/file.rs b/components/script/dom/file.rs
index 86e8888a88f..bfc6b886282 100644
--- a/components/script/dom/file.rs
+++ b/components/script/dom/file.rs
@@ -23,6 +23,7 @@ pub struct File {
}
impl File {
+ #[allow(unrooted_must_root)]
fn new_inherited(blob_impl: BlobImpl, name: DOMString,
modified: Option<i64>, typeString: &str) -> File {
File {
@@ -39,6 +40,7 @@ impl File {
}
}
+ #[allow(unrooted_must_root)]
pub fn new(global: GlobalRef, blob_impl: BlobImpl,
name: DOMString, modified: Option<i64>, typeString: &str) -> Root<File> {
reflect_dom_object(box File::new_inherited(blob_impl, name, modified, typeString),
diff --git a/components/script/dom/htmlinputelement.rs b/components/script/dom/htmlinputelement.rs
index 4b2ff4013b4..762c10aa76d 100644
--- a/components/script/dom/htmlinputelement.rs
+++ b/components/script/dom/htmlinputelement.rs
@@ -1152,6 +1152,7 @@ impl Activatable for HTMLInputElement {
InputType::InputFile => {
// https://html.spec.whatwg.org/multipage/#file-upload-state-(type=file)
let window = window_from_node(self);
+ let origin = window.get_url().origin().unicode_serialization();
let filemanager = window.resource_threads().sender();
let mut files: Vec<Root<File>> = vec![];
@@ -1162,7 +1163,7 @@ impl Activatable for HTMLInputElement {
if self.Multiple() {
let (chan, recv) = ipc::channel().expect("Error initializing channel");
- let msg = FileManagerThreadMsg::SelectFiles(filter, chan);
+ let msg = FileManagerThreadMsg::SelectFiles(filter, chan, origin);
let _ = filemanager.send(msg).unwrap();
match recv.recv().expect("IpcSender side error") {
@@ -1182,7 +1183,7 @@ impl Activatable for HTMLInputElement {
};
} else {
let (chan, recv) = ipc::channel().expect("Error initializing channel");
- let msg = FileManagerThreadMsg::SelectFile(filter, chan);
+ let msg = FileManagerThreadMsg::SelectFile(filter, chan, origin);
let _ = filemanager.send(msg).unwrap();
match recv.recv().expect("IpcSender side error") {
diff --git a/components/script/dom/url.rs b/components/script/dom/url.rs
index 2a41f7c7bae..9a47be034f8 100644
--- a/components/script/dom/url.rs
+++ b/components/script/dom/url.rs
@@ -13,10 +13,9 @@ use dom::bindings::str::{DOMString, USVString};
use dom::blob::Blob;
use dom::urlhelper::UrlHelper;
use dom::urlsearchparams::URLSearchParams;
-use ipc_channel::ipc;
use net_traits::IpcSend;
-use net_traits::blob_url_store::{BlobURLStoreEntry, BlobURLStoreMsg, parse_blob_url};
-use net_traits::filemanager_thread::FileManagerThreadMsg;
+use net_traits::blob_url_store::parse_blob_url;
+use net_traits::filemanager_thread::{SelectedFileId, FileManagerThreadMsg};
use std::borrow::ToOwned;
use std::default::Default;
use url::quirks::domain_to_unicode;
@@ -125,34 +124,9 @@ impl URL {
return DOMString::from(URL::unicode_serialization_blob_url(&origin, &id));
}
- let filemanager = global.resource_threads().sender();
+ let id = blob.get_id();
- let slice = blob.get_slice_or_empty();
- let bytes = slice.get_bytes();
-
- let entry = BlobURLStoreEntry {
- type_string: blob.Type().to_string(),
- filename: None, // XXX: the filename is currently only in File object now
- size: blob.Size(),
- bytes: bytes.to_vec(),
- };
-
- let (tx, rx) = ipc::channel().unwrap();
-
- let msg = BlobURLStoreMsg::AddEntry(entry, origin.clone(), tx);
-
- let _ = filemanager.send(FileManagerThreadMsg::BlobURLStoreMsg(msg));
-
- match rx.recv().unwrap() {
- Ok(id) => {
- DOMString::from(URL::unicode_serialization_blob_url(&origin, &id))
- }
- Err(_) => {
- // Generate a dummy id
- let id = Uuid::new_v4().simple().to_string();
- DOMString::from(URL::unicode_serialization_blob_url(&origin, &id))
- }
- }
+ DOMString::from(URL::unicode_serialization_blob_url(&origin, &id.0))
}
// https://w3c.github.io/FileAPI/#dfn-revokeObjectURL
@@ -166,13 +140,15 @@ impl URL {
NOTE: The first step is unnecessary, since closed blobs do not exist in the store
*/
+ let origin = global.get_url().origin().unicode_serialization();
match Url::parse(&url) {
Ok(url) => match parse_blob_url(&url) {
Some((id, _)) => {
let filemanager = global.resource_threads().sender();
- let msg = BlobURLStoreMsg::DeleteEntry(id.simple().to_string());
- let _ = filemanager.send(FileManagerThreadMsg::BlobURLStoreMsg(msg));
+ let id = SelectedFileId(id.simple().to_string());
+ let msg = FileManagerThreadMsg::DecRef(id, origin);
+ let _ = filemanager.send(msg);
}
None => {}
},