Skip to main content

script/dom/filesystem/
filesystemfileentry.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use std::cell::Cell;
6
7use dom_struct::dom_struct;
8use js::context::JSContext;
9use script_bindings::cell::DomRefCell;
10use script_bindings::reflector::reflect_dom_object;
11
12use crate::dom::bindings::callback::{ExceptionHandling, RootedCallback, TracedCallback};
13use crate::dom::bindings::codegen::Bindings::FileSystemEntryBinding::ErrorCallback;
14use crate::dom::bindings::codegen::Bindings::FileSystemFileEntryBinding::{
15    FileCallback, FileSystemFileEntryMethods,
16};
17use crate::dom::bindings::refcounted::Trusted;
18use crate::dom::bindings::reflector::DomGlobal;
19use crate::dom::bindings::root::{Dom, DomRoot};
20use crate::dom::bindings::str::USVString;
21use crate::dom::file::File;
22use crate::dom::filesystem::FileSystem;
23use crate::dom::filesystementry::FileSystemEntry;
24use crate::dom::globalscope::GlobalScope;
25
26#[dom_struct]
27pub(crate) struct FileSystemFileEntry {
28    filesystementry: FileSystemEntry,
29    file: Dom<File>,
30    pending_callbacks: DomRefCell<Vec<PendingFileCallback>>,
31    next_callback: Cell<usize>,
32}
33
34#[derive(JSTraceable, MallocSizeOf)]
35#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
36struct PendingFileCallback {
37    id: usize,
38    callback: TracedCallback<FileCallback>,
39}
40
41impl FileSystemFileEntry {
42    fn new_inherited(name: USVString, full_path: USVString, file: &File) -> FileSystemFileEntry {
43        FileSystemFileEntry {
44            filesystementry: FileSystemEntry::new_inherited(name, full_path, true),
45            file: Dom::from_ref(file),
46            pending_callbacks: Default::default(),
47            next_callback: Cell::new(0),
48        }
49    }
50
51    pub(crate) fn new(
52        cx: &mut JSContext,
53        global: &GlobalScope,
54        name: USVString,
55        full_path: USVString,
56        file: &File,
57    ) -> DomRoot<FileSystemFileEntry> {
58        reflect_dom_object(
59            cx,
60            Box::new(FileSystemFileEntry::new_inherited(name, full_path, file)),
61            global,
62        )
63    }
64
65    pub(crate) fn set_filesystem(&self, fs: &FileSystem) {
66        self.filesystementry.set_filesystem(fs);
67    }
68}
69
70impl FileSystemFileEntryMethods<crate::DomTypeHolder> for FileSystemFileEntry {
71    /// <https://wicg.github.io/entries-api/#dom-filesystemfileentry-file>
72    fn File(
73        &self,
74        success_callback: RootedCallback<FileCallback>,
75        _error_callback: Option<RootedCallback<ErrorCallback>>,
76    ) {
77        // Per spec 7.4: in parallel,
78        // 1. (TODO) Evaluate path
79        // 2-3. (TODO) errorCallback
80
81        // Note: Step 1 - 3 is meant to re-check if file exists on OS filesystem.
82        // It is unreachable for now, as the file data is already
83        // stored in-memory on this entry as `File` (set by webkitGetAsEntry).
84
85        // 4. on success, queue a task to invoke successCallback
86        // with a new `File` object representing item and "report".
87
88        let id = self.next_callback.get();
89        self.pending_callbacks
90            .borrow_mut()
91            .push(PendingFileCallback {
92                id,
93                callback: success_callback.to_traced(),
94            });
95        self.next_callback.set(id + 1);
96
97        let this = Trusted::new(self);
98        self.global()
99            .task_manager()
100            .dom_manipulation_task_source()
101            .queue(task!(invoke_file_callback: move |cx| {
102                let this = this.root();
103                let maybe_index = this
104                    .pending_callbacks
105                    .borrow()
106                    .iter()
107                    .position(|val| val.id == id);
108                if let Some(index) = maybe_index {
109                    rooted!(&in(cx) let callback = this
110                        .pending_callbacks
111                        .safe_borrow_mut(cx.no_gc())
112                        .swap_remove(index)
113                        .callback);
114                    let file = DomRoot::from_ref(&*this.file);
115                    let _ = callback.Call__(cx, &file, ExceptionHandling::Report);
116                }
117            }));
118    }
119}