Skip to main content

script/dom/filesystem/
filesystementry.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 script_bindings::cell::DomRefCell;
9use script_bindings::reflector::Reflector;
10
11use crate::dom::bindings::callback::{ExceptionHandling, RootedCallback, TracedCallback};
12use crate::dom::bindings::codegen::Bindings::FileSystemBinding::FileSystemMethods;
13use crate::dom::bindings::codegen::Bindings::FileSystemEntryBinding::{
14    ErrorCallback, FileSystemEntryCallback, FileSystemEntryMethods,
15};
16use crate::dom::bindings::refcounted::Trusted;
17use crate::dom::bindings::reflector::DomGlobal;
18use crate::dom::bindings::root::{DomRoot, MutNullableDom};
19use crate::dom::bindings::str::USVString;
20use crate::dom::filesystem::FileSystem;
21
22#[dom_struct]
23pub(crate) struct FileSystemEntry {
24    reflector_: Reflector,
25    name: USVString,
26    full_path: USVString,
27    is_file: bool,
28    filesystem: MutNullableDom<FileSystem>,
29    pending_callbacks: DomRefCell<Vec<PendingEntryCallback>>,
30    next_callback: Cell<usize>,
31}
32
33#[derive(JSTraceable, MallocSizeOf)]
34#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
35struct PendingEntryCallback {
36    id: usize,
37    callback: TracedCallback<FileSystemEntryCallback>,
38}
39
40impl FileSystemEntry {
41    pub(crate) fn new_inherited(
42        name: USVString,
43        full_path: USVString,
44        is_file: bool,
45    ) -> FileSystemEntry {
46        FileSystemEntry {
47            reflector_: Reflector::new(),
48            name,
49            full_path,
50            is_file,
51            filesystem: MutNullableDom::new(None),
52            pending_callbacks: Default::default(),
53            next_callback: Cell::new(0),
54        }
55    }
56
57    pub(crate) fn set_filesystem(&self, fs: &FileSystem) {
58        self.filesystem.set(Some(fs));
59    }
60}
61
62impl FileSystemEntryMethods<crate::DomTypeHolder> for FileSystemEntry {
63    /// <https://wicg.github.io/entries-api/#dom-filesystementry-isfile>
64    fn IsFile(&self) -> bool {
65        self.is_file
66    }
67
68    /// <https://wicg.github.io/entries-api/#dom-filesystementry-isdirectory>
69    fn IsDirectory(&self) -> bool {
70        !self.is_file
71    }
72
73    /// <https://wicg.github.io/entries-api/#dom-filesystementry-name>
74    fn Name(&self) -> USVString {
75        self.name.clone()
76    }
77
78    /// <https://wicg.github.io/entries-api/#dom-filesystementry-fullpath>
79    fn FullPath(&self) -> USVString {
80        self.full_path.clone()
81    }
82
83    /// <https://wicg.github.io/entries-api/#dom-filesystementry-filesystem>
84    fn Filesystem(&self) -> DomRoot<FileSystem> {
85        self.filesystem
86            .get()
87            .expect("FileSystemEntry must be associated with a FileSystem")
88    }
89
90    /// <https://wicg.github.io/entries-api/#dom-filesystementry-getparent>
91    fn GetParent(
92        &self,
93        success_callback: Option<RootedCallback<FileSystemEntryCallback>>,
94        _error_callback: Option<RootedCallback<ErrorCallback>>,
95    ) {
96        let Some(callback) = success_callback else {
97            return;
98        };
99        // Per spec 7.1: in parallel,
100        // 1. (TODO) Let `path` be the result of resolve ".." relative to this's full path.
101        // 2. (TODO) Let `item` be the result of evaluating a path with this’s root and path.
102        // 3. (TODO) Queue errorCallback if `item` is failure.
103        // 4 - 5.  Queue a task to invoke
104        // successCallback with the parent directory entry.
105        //
106        // NOTE: For now, the parent is always the root directory, which is correct
107        // as the `FileSystemEntry` can only be created by webkitGetAsEntry(), which is
108        // single level DnD.
109
110        let id = self.next_callback.get();
111        self.pending_callbacks
112            .borrow_mut()
113            .push(PendingEntryCallback {
114                id,
115                callback: callback.to_traced(),
116            });
117        self.next_callback.set(id + 1);
118
119        let this = Trusted::new(self);
120        self.global()
121            .task_manager()
122            .dom_manipulation_task_source()
123            .queue(task!(invoke_get_parent: move |cx| {
124                let this = this.root();
125                let maybe_index = this
126                    .pending_callbacks
127                    .borrow()
128                    .iter()
129                    .position(|val| val.id == id);
130                if let Some(index) = maybe_index {
131                    rooted!(&in(cx) let callback = this
132                        .pending_callbacks
133                        .safe_borrow_mut(cx.no_gc())
134                        .swap_remove(index)
135                        .callback);
136                    let entry = DomRoot::upcast::<FileSystemEntry>(this.Filesystem().Root());
137                    let _ = callback.Call__(cx, &entry, ExceptionHandling::Report);
138                }
139            }));
140    }
141}