Skip to content

Commit 862c098

Browse files
committed
avm1: Store AvmStrings in FileReference
This avoids extra `RefCell`s and back-and-forth conversions to `String`.
1 parent 1b8418b commit 862c098

File tree

1 file changed

+47
-56
lines changed

1 file changed

+47
-56
lines changed

core/src/avm1/globals/file_reference.rs

+47-56
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ use crate::backend::ui::{FileDialogResult, FileFilter};
1111
use crate::string::{AvmString, StringContext};
1212
use gc_arena::barrier::unlock;
1313
use gc_arena::lock::Lock;
14-
use gc_arena::{Collect, Gc, Mutation};
14+
use gc_arena::{Collect, Gc};
15+
use ruffle_macros::istr;
1516
use url::Url;
1617

1718
// There are two undocumented functions in FileReference: convertToPPT and deleteConvertedPPT.
@@ -32,6 +33,9 @@ impl<'gc> FileReferenceObject<'gc> {
3233
activation: &mut Activation<'_, 'gc>,
3334
dialog_result: &dyn FileDialogResult,
3435
) {
36+
let mc = activation.gc();
37+
let write = Gc::write(mc, self.0);
38+
3539
self.0.is_initialised.set(true);
3640

3741
let date_proto = activation.context.avm1.prototypes().date_constructor;
@@ -40,7 +44,7 @@ impl<'gc> FileReferenceObject<'gc> {
4044
activation,
4145
&[(creation_time.timestamp_millis() as f64).into()],
4246
) {
43-
self.set_creation_date(activation.gc(), Some(obj));
47+
unlock!(write, FileReferenceData, creation_date).set(Some(obj));
4448
}
4549
}
4650

@@ -49,39 +53,41 @@ impl<'gc> FileReferenceObject<'gc> {
4953
activation,
5054
&[(modification_time.timestamp_millis() as f64).into()],
5155
) {
52-
self.set_modification_date(activation.gc(), Some(obj));
56+
unlock!(write, FileReferenceData, modification_date).set(Some(obj));
5357
}
5458
}
5559

56-
self.0.file_type.replace(dialog_result.file_type());
57-
self.0.name.replace(dialog_result.file_name());
58-
self.0.size.replace(dialog_result.size());
59-
self.0.creator.replace(dialog_result.creator());
60-
self.0.data.replace(dialog_result.contents().to_vec());
61-
}
60+
let file_type = dialog_result
61+
.file_type()
62+
.map(|s| AvmString::new_utf8(mc, s));
63+
unlock!(write, FileReferenceData, file_type).set(file_type);
6264

63-
fn set_creation_date(self, gc: &'gc Mutation<'gc>, creation_date: Option<Object<'gc>>) {
64-
unlock!(Gc::write(gc, self.0), FileReferenceData, creation_date).set(creation_date);
65-
}
65+
let file_name = dialog_result
66+
.file_name()
67+
.map(|s| AvmString::new_utf8(mc, s));
68+
unlock!(write, FileReferenceData, name).set(file_name);
69+
70+
let creator = dialog_result.creator().map(|s| AvmString::new_utf8(mc, s));
71+
unlock!(write, FileReferenceData, creator).set(creator);
6672

67-
fn set_modification_date(self, gc: &'gc Mutation<'gc>, modification_date: Option<Object<'gc>>) {
68-
unlock!(Gc::write(gc, self.0), FileReferenceData, modification_date).set(modification_date);
73+
self.0.size.replace(dialog_result.size());
74+
self.0.data.replace(dialog_result.contents().to_vec());
6975
}
7076
}
7177

72-
#[derive(Default, Clone, Collect)]
78+
#[derive(Clone, Default, Collect)]
7379
#[collect(no_drop)]
7480
pub struct FileReferenceData<'gc> {
7581
/// Has this object been initialised from a dialog
7682
is_initialised: Cell<bool>,
7783

7884
creation_date: Lock<Option<Object<'gc>>>,
79-
creator: RefCell<Option<String>>,
85+
creator: Lock<Option<AvmString<'gc>>>,
8086
modification_date: Lock<Option<Object<'gc>>>,
81-
name: RefCell<Option<String>>,
82-
post_data: RefCell<String>,
87+
name: Lock<Option<AvmString<'gc>>>,
88+
post_data: Lock<Option<AvmString<'gc>>>,
8389
size: Cell<Option<u64>>,
84-
file_type: RefCell<Option<String>>,
90+
file_type: Lock<Option<AvmString<'gc>>>,
8591

8692
/// The contents of the referenced file
8793
/// We track this here so that it can be referenced in FileReference.upload
@@ -114,26 +120,23 @@ pub fn creation_date<'gc>(
114120
.0
115121
.creation_date
116122
.get()
117-
.map_or(Value::Undefined, |x| x.into()));
123+
.map_or(Value::Undefined, Into::into));
118124
}
119125

120126
Ok(Value::Undefined)
121127
}
122128

123129
pub fn creator<'gc>(
124-
activation: &mut Activation<'_, 'gc>,
130+
_activation: &mut Activation<'_, 'gc>,
125131
this: Object<'gc>,
126132
_args: &[Value<'gc>],
127133
) -> Result<Value<'gc>, Error<'gc>> {
128134
if let NativeObject::FileReference(file_ref) = this.native() {
129135
return Ok(file_ref
130136
.0
131137
.creator
132-
.borrow()
133-
.as_ref()
134-
.map_or(Value::Undefined, |x| {
135-
AvmString::new_utf8(activation.gc(), x).into()
136-
}));
138+
.get()
139+
.map_or(Value::Undefined, Into::into));
137140
}
138141

139142
Ok(Value::Undefined)
@@ -149,26 +152,19 @@ pub fn modification_date<'gc>(
149152
.0
150153
.modification_date
151154
.get()
152-
.map_or(Value::Undefined, |x| x.into()));
155+
.map_or(Value::Undefined, Into::into));
153156
}
154157

155158
Ok(Value::Undefined)
156159
}
157160

158161
pub fn name<'gc>(
159-
activation: &mut Activation<'_, 'gc>,
162+
_activation: &mut Activation<'_, 'gc>,
160163
this: Object<'gc>,
161164
_args: &[Value<'gc>],
162165
) -> Result<Value<'gc>, Error<'gc>> {
163166
if let NativeObject::FileReference(file_ref) = this.native() {
164-
return Ok(file_ref
165-
.0
166-
.name
167-
.borrow()
168-
.as_ref()
169-
.map_or(Value::Undefined, |x| {
170-
AvmString::new_utf8(activation.gc(), x).into()
171-
}));
167+
return Ok(file_ref.0.name.get().map_or(Value::Undefined, Into::into));
172168
}
173169

174170
Ok(Value::Undefined)
@@ -180,9 +176,8 @@ pub fn post_data<'gc>(
180176
_args: &[Value<'gc>],
181177
) -> Result<Value<'gc>, Error<'gc>> {
182178
if let NativeObject::FileReference(file_ref) = this.native() {
183-
return Ok(
184-
AvmString::new_utf8(activation.gc(), file_ref.0.post_data.borrow().clone()).into(),
185-
);
179+
let post_data = file_ref.0.post_data.get();
180+
return Ok(post_data.unwrap_or_else(|| istr!("")).into());
186181
}
187182

188183
Ok(Value::Undefined)
@@ -199,7 +194,8 @@ pub fn set_post_data<'gc>(
199194
.coerce_to_string(activation)?;
200195

201196
if let NativeObject::FileReference(file_ref) = this.native() {
202-
file_ref.0.post_data.replace(post_data.to_string());
197+
let write = Gc::write(activation.gc(), file_ref.0);
198+
unlock!(write, FileReferenceData, post_data).set(Some(post_data));
203199
}
204200

205201
Ok(Value::Undefined)
@@ -211,26 +207,21 @@ pub fn size<'gc>(
211207
_args: &[Value<'gc>],
212208
) -> Result<Value<'gc>, Error<'gc>> {
213209
if let NativeObject::FileReference(file_ref) = this.native() {
214-
return Ok(file_ref.0.size.get().map_or(Value::Undefined, |x| x.into()));
210+
let size = file_ref.0.size.get();
211+
return Ok(size.map_or(Value::Undefined, Into::into));
215212
}
216213

217214
Ok(Value::Undefined)
218215
}
219216

220217
pub fn file_type<'gc>(
221-
activation: &mut Activation<'_, 'gc>,
218+
_activation: &mut Activation<'_, 'gc>,
222219
this: Object<'gc>,
223220
_args: &[Value<'gc>],
224221
) -> Result<Value<'gc>, Error<'gc>> {
225222
if let NativeObject::FileReference(file_ref) = this.native() {
226-
return Ok(file_ref
227-
.0
228-
.file_type
229-
.borrow()
230-
.as_ref()
231-
.map_or(Value::Undefined, |x| {
232-
AvmString::new_utf8(activation.gc(), x).into()
233-
}));
223+
let file_type = file_ref.0.file_type.get();
224+
return Ok(file_type.map_or(Value::Undefined, Into::into));
234225
}
235226

236227
Ok(Value::Undefined)
@@ -401,17 +392,17 @@ pub fn upload<'gc>(
401392
_ => return Ok(false.into()),
402393
}
403394

395+
let file_name = match file_reference.0.name.get() {
396+
Some(name) => name.to_string(),
397+
None => "file".to_string(),
398+
};
399+
404400
let process = activation.context.load_manager.upload_file(
405401
activation.context.player.clone(),
406402
this,
407403
url_string,
408404
file_reference.0.data.borrow().clone(),
409-
file_reference
410-
.0
411-
.name
412-
.borrow()
413-
.clone()
414-
.unwrap_or_else(|| "file".to_string()),
405+
file_name,
415406
);
416407

417408
activation.context.navigator.spawn_future(process);

0 commit comments

Comments
 (0)