@@ -12,15 +12,18 @@ use crate::display_object::{
12
12
} ;
13
13
use crate :: string:: { AvmString , StringContext , WStr } ;
14
14
use crate :: types:: Percent ;
15
- use gc_arena:: { Collect , GcCell , GcWeakCell , Mutation } ;
15
+ use gc_arena:: barrier:: unlock;
16
+ use gc_arena:: lock:: RefLock ;
17
+ use gc_arena:: { Collect , Gc , GcWeak , Mutation } ;
16
18
use ruffle_macros:: istr;
19
+ use std:: cell:: RefMut ;
17
20
use std:: fmt;
18
21
use swf:: Twips ;
19
22
20
23
/// A ScriptObject that is inherently tied to a display node.
21
24
#[ derive( Clone , Copy , Collect ) ]
22
25
#[ collect( no_drop) ]
23
- pub struct StageObject < ' gc > ( GcCell < ' gc , StageObjectData < ' gc > > ) ;
26
+ pub struct StageObject < ' gc > ( Gc < ' gc , StageObjectData < ' gc > > ) ;
24
27
25
28
#[ derive( Collect ) ]
26
29
#[ collect( no_drop) ]
@@ -34,13 +37,13 @@ pub struct StageObjectData<'gc> {
34
37
/// The display node this stage object
35
38
pub display_object : DisplayObject < ' gc > ,
36
39
37
- text_field_bindings : Vec < TextFieldBinding < ' gc > > ,
40
+ text_field_bindings : RefLock < Vec < TextFieldBinding < ' gc > > > ,
38
41
}
39
42
40
43
impl < ' gc > StageObject < ' gc > {
41
44
/// Create a weak reference to the underlying data of this `StageObject`
42
- pub fn as_weak ( & self ) -> GcWeakCell < ' gc , StageObjectData < ' gc > > {
43
- GcCell :: downgrade ( self . 0 )
45
+ pub fn as_weak ( self ) -> GcWeak < ' gc , StageObjectData < ' gc > > {
46
+ Gc :: downgrade ( self . 0 )
44
47
}
45
48
46
49
/// Create a stage object for a given display node.
@@ -49,16 +52,28 @@ impl<'gc> StageObject<'gc> {
49
52
display_object : DisplayObject < ' gc > ,
50
53
proto : Object < ' gc > ,
51
54
) -> Self {
52
- Self ( GcCell :: new (
55
+ Self ( Gc :: new (
53
56
context. gc ( ) ,
54
57
StageObjectData {
55
58
base : ScriptObject :: new ( context, Some ( proto) ) ,
56
59
display_object,
57
- text_field_bindings : Vec :: new ( ) ,
60
+ text_field_bindings : RefLock :: new ( Vec :: new ( ) ) ,
58
61
} ,
59
62
) )
60
63
}
61
64
65
+ fn text_field_bindings_mut (
66
+ self ,
67
+ gc_context : & Mutation < ' gc > ,
68
+ ) -> RefMut < ' gc , Vec < TextFieldBinding < ' gc > > > {
69
+ unlock ! (
70
+ Gc :: write( gc_context, self . 0 ) ,
71
+ StageObjectData ,
72
+ text_field_bindings
73
+ )
74
+ . borrow_mut ( )
75
+ }
76
+
62
77
/// Registers a text field variable binding for this stage object.
63
78
/// Whenever a property with the given name is changed, we should change the text in the text field.
64
79
pub fn register_text_field_binding (
@@ -67,9 +82,7 @@ impl<'gc> StageObject<'gc> {
67
82
text_field : EditText < ' gc > ,
68
83
variable_name : AvmString < ' gc > ,
69
84
) {
70
- self . 0
71
- . write ( gc_context)
72
- . text_field_bindings
85
+ self . text_field_bindings_mut ( gc_context)
73
86
. push ( TextFieldBinding {
74
87
text_field,
75
88
variable_name,
@@ -80,16 +93,14 @@ impl<'gc> StageObject<'gc> {
80
93
/// Does not place the text field on the unbound list.
81
94
/// Caller is responsible for placing the text field on the unbound list, if necessary.
82
95
pub fn clear_text_field_binding ( self , gc_context : & Mutation < ' gc > , text_field : EditText < ' gc > ) {
83
- self . 0
84
- . write ( gc_context)
85
- . text_field_bindings
96
+ self . text_field_bindings_mut ( gc_context)
86
97
. retain ( |binding| !DisplayObject :: ptr_eq ( text_field. into ( ) , binding. text_field . into ( ) ) ) ;
87
98
}
88
99
89
100
/// Clears all text field bindings from this stage object, and places the textfields on the unbound list.
90
101
/// This is called when the object is removed from the stage.
91
102
pub fn unregister_text_field_bindings ( self , context : & mut UpdateContext < ' gc > ) {
92
- for binding in self . 0 . write ( context. gc ( ) ) . text_field_bindings . drain ( ..) {
103
+ for binding in self . text_field_bindings_mut ( context. gc ( ) ) . drain ( ..) {
93
104
binding. text_field . clear_bound_stage_object ( context) ;
94
105
context. unbound_text_fields . push ( binding. text_field ) ;
95
106
}
@@ -106,7 +117,6 @@ impl<'gc> StageObject<'gc> {
106
117
} else if name. eq_with_case ( b"_parent" , case_sensitive) {
107
118
return Some (
108
119
self . 0
109
- . read ( )
110
120
. display_object
111
121
. avm1_parent ( )
112
122
. map ( |dn| dn. object ( ) . coerce_to_object ( activation) )
@@ -166,17 +176,16 @@ struct TextFieldBinding<'gc> {
166
176
167
177
impl fmt:: Debug for StageObject < ' _ > {
168
178
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
169
- let this = self . 0 . read ( ) ;
170
179
f. debug_struct ( "StageObject" )
171
- . field ( "ptr" , & self . 0 . as_ptr ( ) )
172
- . field ( "display_object" , & this . display_object )
180
+ . field ( "ptr" , & Gc :: as_ptr ( self . 0 ) )
181
+ . field ( "display_object" , & self . 0 . display_object )
173
182
. finish ( )
174
183
}
175
184
}
176
185
177
186
impl < ' gc > TObject < ' gc > for StageObject < ' gc > {
178
187
fn raw_script_object ( & self ) -> ScriptObject < ' gc > {
179
- self . 0 . read ( ) . base
188
+ self . 0 . base
180
189
}
181
190
182
191
fn get_local_stored (
@@ -186,11 +195,14 @@ impl<'gc> TObject<'gc> for StageObject<'gc> {
186
195
is_slash_path : bool ,
187
196
) -> Option < Value < ' gc > > {
188
197
let name = name. into ( ) ;
189
- let obj = self . 0 . read ( ) ;
190
198
191
199
// Property search order for DisplayObjects:
192
200
// 1) Actual properties on the underlying object
193
- if let Some ( value) = obj. base . get_local_stored ( name, activation, is_slash_path) {
201
+ if let Some ( value) = self
202
+ . 0
203
+ . base
204
+ . get_local_stored ( name, activation, is_slash_path)
205
+ {
194
206
return Some ( value) ;
195
207
}
196
208
@@ -203,7 +215,8 @@ impl<'gc> TObject<'gc> for StageObject<'gc> {
203
215
}
204
216
205
217
// 3) Child display objects with the given instance name
206
- if let Some ( child) = obj
218
+ if let Some ( child) = self
219
+ . 0
207
220
. display_object
208
221
. as_container ( )
209
222
. and_then ( |o| o. child_by_name ( & name, activation. is_case_sensitive ( ) ) )
@@ -228,7 +241,7 @@ impl<'gc> TObject<'gc> for StageObject<'gc> {
228
241
. get_by_name ( name)
229
242
. copied ( )
230
243
{
231
- return Some ( property. get ( activation, obj . display_object ) ) ;
244
+ return Some ( property. get ( activation, self . 0 . display_object ) ) ;
232
245
}
233
246
}
234
247
@@ -242,25 +255,28 @@ impl<'gc> TObject<'gc> for StageObject<'gc> {
242
255
activation : & mut Activation < ' _ , ' gc > ,
243
256
this : Object < ' gc > ,
244
257
) -> Result < ( ) , Error < ' gc > > {
245
- let obj = self . 0 . read ( ) ;
246
-
247
258
// Check if a text field is bound to this property and update the text if so.
248
259
let case_sensitive = activation. is_case_sensitive ( ) ;
249
- for binding in obj. text_field_bindings . iter ( ) . filter ( |binding| {
250
- if case_sensitive {
251
- binding. variable_name == name
252
- } else {
253
- binding. variable_name . eq_ignore_case ( & name)
254
- }
255
- } ) {
260
+ for binding in self
261
+ . 0
262
+ . text_field_bindings
263
+ . borrow ( )
264
+ . iter ( )
265
+ . filter ( |binding| {
266
+ if case_sensitive {
267
+ binding. variable_name == name
268
+ } else {
269
+ binding. variable_name . eq_ignore_case ( & name)
270
+ }
271
+ } )
272
+ {
256
273
binding
257
274
. text_field
258
275
. set_html_text ( & value. coerce_to_string ( activation) ?, activation. context ) ;
259
276
}
260
277
261
- let base = obj. base ;
262
- let display_object = obj. display_object ;
263
- drop ( obj) ;
278
+ let base = self . 0 . base ;
279
+ let display_object = self . 0 . display_object ;
264
280
265
281
if base. has_own_property ( activation, name) {
266
282
// 1) Actual properties on the underlying object
@@ -286,14 +302,12 @@ impl<'gc> TObject<'gc> for StageObject<'gc> {
286
302
this : Object < ' gc > ,
287
303
) -> Result < Object < ' gc > , Error < ' gc > > {
288
304
//TODO: Create a StageObject of some kind
289
- self . 0 . read ( ) . base . create_bare_object ( activation, this)
305
+ self . 0 . base . create_bare_object ( activation, this)
290
306
}
291
307
292
308
// Note that `hasOwnProperty` does NOT return true for child display objects.
293
309
fn has_property ( & self , activation : & mut Activation < ' _ , ' gc > , name : AvmString < ' gc > ) -> bool {
294
- let obj = self . 0 . read ( ) ;
295
-
296
- if !obj. display_object . avm1_removed ( ) && obj. base . has_property ( activation, name) {
310
+ if !self . 0 . display_object . avm1_removed ( ) && self . 0 . base . has_property ( activation, name) {
297
311
return true ;
298
312
}
299
313
@@ -311,8 +325,9 @@ impl<'gc> TObject<'gc> for StageObject<'gc> {
311
325
312
326
let case_sensitive = activation. is_case_sensitive ( ) ;
313
327
314
- if !obj. display_object . avm1_removed ( )
315
- && obj
328
+ if !self . 0 . display_object . avm1_removed ( )
329
+ && self
330
+ . 0
316
331
. display_object
317
332
. as_container ( )
318
333
. and_then ( |o| o. child_by_name ( & name, case_sensitive) )
@@ -335,10 +350,9 @@ impl<'gc> TObject<'gc> for StageObject<'gc> {
335
350
) -> Vec < AvmString < ' gc > > {
336
351
// Keys from the underlying object are listed first, followed by
337
352
// child display objects in order from highest depth to lowest depth.
338
- let obj = self . 0 . read ( ) ;
339
- let mut keys = obj. base . get_keys ( activation, include_hidden) ;
353
+ let mut keys = self . 0 . base . get_keys ( activation, include_hidden) ;
340
354
341
- if let Some ( ctr) = obj . display_object . as_container ( ) {
355
+ if let Some ( ctr) = self . 0 . display_object . as_container ( ) {
342
356
// Button/MovieClip children are included in key list.
343
357
for child in ctr. iter_render_list ( ) . rev ( ) {
344
358
if child. as_interactive ( ) . is_some ( ) {
@@ -356,11 +370,11 @@ impl<'gc> TObject<'gc> for StageObject<'gc> {
356
370
}
357
371
358
372
fn as_display_object ( & self ) -> Option < DisplayObject < ' gc > > {
359
- Some ( self . 0 . read ( ) . display_object )
373
+ Some ( self . 0 . display_object )
360
374
}
361
375
362
376
fn as_ptr ( & self ) -> * const ObjectPtr {
363
- self . 0 . read ( ) . base . as_ptr ( )
377
+ self . 0 . base . as_ptr ( )
364
378
}
365
379
}
366
380
0 commit comments