aboutsummaryrefslogtreecommitdiffstats
path: root/components/script
diff options
context:
space:
mode:
Diffstat (limited to 'components/script')
-rw-r--r--components/script/dom/filereader.rs135
1 files changed, 98 insertions, 37 deletions
diff --git a/components/script/dom/filereader.rs b/components/script/dom/filereader.rs
index 2f6e1796ab7..e3d0e1fd513 100644
--- a/components/script/dom/filereader.rs
+++ b/components/script/dom/filereader.rs
@@ -4,6 +4,7 @@
use std::cell::Cell;
use std::ptr;
+use std::rc::Rc;
use base64::Engine;
use dom_struct::dom_struct;
@@ -34,7 +35,7 @@ use crate::dom::event::{Event, EventBubbles, EventCancelable};
use crate::dom::eventtarget::EventTarget;
use crate::dom::globalscope::GlobalScope;
use crate::dom::progressevent::ProgressEvent;
-use crate::realms::enter_realm;
+use crate::realms::{InRealm, enter_realm};
use crate::script_runtime::{CanGc, JSContext};
use crate::task::TaskOnce;
@@ -390,18 +391,24 @@ impl FileReaderMethods<crate::DomTypeHolder> for FileReader {
event_handler!(loadend, GetOnloadend, SetOnloadend);
// https://w3c.github.io/FileAPI/#dfn-readAsArrayBuffer
- fn ReadAsArrayBuffer(&self, blob: &Blob) -> ErrorResult {
- self.read(FileReaderFunction::ArrayBuffer, blob, None)
+ fn ReadAsArrayBuffer(&self, blob: &Blob, realm: InRealm, can_gc: CanGc) -> ErrorResult {
+ self.read(FileReaderFunction::ArrayBuffer, blob, None, realm, can_gc)
}
// https://w3c.github.io/FileAPI/#dfn-readAsDataURL
- fn ReadAsDataURL(&self, blob: &Blob) -> ErrorResult {
- self.read(FileReaderFunction::DataUrl, blob, None)
+ fn ReadAsDataURL(&self, blob: &Blob, realm: InRealm, can_gc: CanGc) -> ErrorResult {
+ self.read(FileReaderFunction::DataUrl, blob, None, realm, can_gc)
}
// https://w3c.github.io/FileAPI/#dfn-readAsText
- fn ReadAsText(&self, blob: &Blob, label: Option<DOMString>) -> ErrorResult {
- self.read(FileReaderFunction::Text, blob, label)
+ fn ReadAsText(
+ &self,
+ blob: &Blob,
+ label: Option<DOMString>,
+ realm: InRealm,
+ can_gc: CanGc,
+ ) -> ErrorResult {
+ self.read(FileReaderFunction::Text, blob, label, realm, can_gc)
}
// https://w3c.github.io/FileAPI/#dfn-abort
@@ -474,18 +481,31 @@ impl FileReader {
function: FileReaderFunction,
blob: &Blob,
label: Option<DOMString>,
+ realm: InRealm,
+ can_gc: CanGc,
) -> ErrorResult {
- // Step 1
+ let cx = GlobalScope::get_cx();
+
+ // If fr’s state is "loading", throw an InvalidStateError DOMException.
if self.ready_state.get() == FileReaderReadyState::Loading {
return Err(Error::InvalidState);
}
- // Step 2
+ // Set fr’s state to "loading".
self.change_ready_state(FileReaderReadyState::Loading);
- // Step 3
+ // Set fr’s result to null.
*self.result.borrow_mut() = None;
+ // Set fr’s error to null.
+ // See the note below in the error steps.
+
+ // Let stream be the result of calling get stream on blob.
+ let stream = blob.get_stream(can_gc);
+
+ // Let reader be the result of getting a reader from stream.
+ let reader = stream.and_then(|s| s.acquire_default_reader(can_gc))?;
+
let type_ = blob.Type();
let load_data = ReadMetaData::new(String::from(type_), label.map(String::from), function);
@@ -494,35 +514,76 @@ impl FileReader {
self.generation_id.set(GenerationId(prev_id + 1));
let gen_id = self.generation_id.get();
- // Step 10, in parallel, wait on stream promises to resolve and queue tasks.
-
- // TODO: follow the spec which requires implementing blob `get_stream`,
- // see https://github.com/servo/servo/issues/25209
-
- // Currently bytes are first read "sync", and then the appropriate tasks are queued.
-
- // Read the blob bytes "sync".
- let blob_contents = blob.get_bytes().unwrap_or_else(|_| vec![]);
-
- let filereader = Trusted::new(self);
- let global = self.global();
- let task_manager = global.task_manager();
- let task_source = task_manager.file_reading_task_source();
-
- // Queue tasks as appropriate.
- task_source.queue(FileReadingTask::ProcessRead(filereader.clone(), gen_id));
+ let filereader_success = DomRoot::from_ref(self);
+ let filereader_error = DomRoot::from_ref(self);
- if !blob_contents.is_empty() {
- task_source.queue(FileReadingTask::ProcessReadData(filereader.clone(), gen_id));
- }
-
- task_source.queue(FileReadingTask::ProcessReadEOF(
- filereader,
- gen_id,
- load_data,
- blob_contents,
- ));
+ // In parallel, while true:
+ // Wait for chunkPromise to be fulfilled or rejected.
+ // Note: the spec appears wrong or outdated,
+ // so for now we use the simple `read_all_bytes` call,
+ // which means we cannot fire the progress event at each chunk.
+ // This can be revisisted following the discussion at
+ // <https://github.com/w3c/FileAPI/issues/208>
+ // Read all bytes from stream with reader.
+ reader.read_all_bytes(
+ cx,
+ &self.global(),
+ Rc::new(move |blob_contents| {
+ let global = filereader_success.global();
+ let task_manager = global.task_manager();
+ let task_source = task_manager.file_reading_task_source();
+
+ // If chunkPromise is fulfilled,
+ // and isFirstChunk is true,
+ // queue a task
+ // Note: this should be done for the first chunk,
+ // see issue above.
+ task_source.queue(FileReadingTask::ProcessRead(
+ Trusted::new(&filereader_success.clone()),
+ gen_id,
+ ));
+ // If chunkPromise is fulfilled
+ // with an object whose done property is false
+ // and whose value property is a Uint8Array object
+ // Note: this should be done for each chunk,
+ // see issue above.
+ if !blob_contents.is_empty() {
+ task_source.queue(FileReadingTask::ProcessReadData(
+ Trusted::new(&filereader_success.clone()),
+ gen_id,
+ ));
+ }
+ // Otherwise,
+ // if chunkPromise is fulfilled with an object whose done property is true,
+ // queue a task
+ // Note: we are in the succes steps of `read_all_bytes`,
+ // so the last chunk has been received.
+ task_source.queue(FileReadingTask::ProcessReadEOF(
+ Trusted::new(&filereader_success.clone()),
+ gen_id,
+ load_data.clone(),
+ blob_contents.to_vec(),
+ ));
+ }),
+ Rc::new(move |_cx, _error| {
+ let global = filereader_error.global();
+ let task_manager = global.task_manager();
+ let task_source = task_manager.file_reading_task_source();
+
+ // Otherwise, if chunkPromise is rejected with an error error,
+ // queue a task
+ // Note: not using the error from `read_all_bytes`,
+ // see issue above.
+ task_source.queue(FileReadingTask::ProcessReadError(
+ Trusted::new(&filereader_error),
+ gen_id,
+ DOMErrorName::OperationError,
+ ));
+ }),
+ realm,
+ can_gc,
+ );
Ok(())
}