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