diff options
Diffstat (limited to 'components/script')
-rw-r--r-- | components/script/dom/filereader.rs | 135 |
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(()) } |