avm1: Object.watch is case insensitive on SWFv6

This commit is contained in:
Mike Welsh 2020-07-10 02:11:56 -07:00
parent 8a0430d744
commit a1ff80bb18
13 changed files with 129 additions and 44 deletions

View File

@ -231,17 +231,23 @@ impl<'gc> TObject<'gc> for ColorTransformObject<'gc> {
fn set_watcher(
&self,
activation: &mut Activation<'_, 'gc>,
gc_context: MutationContext<'gc, '_>,
name: Cow<str>,
callback: Executable<'gc>,
user_data: Value<'gc>,
) {
self.base()
.set_watcher(gc_context, name, callback, user_data);
.set_watcher(activation, gc_context, name, callback, user_data);
}
fn remove_watcher(&self, gc_context: MutationContext<'gc, '_>, name: Cow<str>) -> bool {
self.base().remove_watcher(gc_context, name)
fn remove_watcher(
&self,
activation: &mut Activation<'_, 'gc>,
gc_context: MutationContext<'gc, '_>,
name: Cow<str>,
) -> bool {
self.base().remove_watcher(activation, gc_context, name)
}
fn has_property(

View File

@ -626,16 +626,23 @@ impl<'gc> TObject<'gc> for FunctionObject<'gc> {
fn set_watcher(
&self,
activation: &mut Activation<'_, 'gc>,
gc_context: MutationContext<'gc, '_>,
name: Cow<str>,
callback: Executable<'gc>,
user_data: Value<'gc>,
) {
self.base.set_watcher(gc_context, name, callback, user_data);
self.base
.set_watcher(activation, gc_context, name, callback, user_data);
}
fn remove_watcher(&self, gc_context: MutationContext<'gc, '_>, name: Cow<str>) -> bool {
self.base.remove_watcher(gc_context, name)
fn remove_watcher(
&self,
activation: &mut Activation<'_, 'gc>,
gc_context: MutationContext<'gc, '_>,
name: Cow<str>,
) -> bool {
self.base.remove_watcher(activation, gc_context, name)
}
fn has_property(

View File

@ -188,7 +188,7 @@ fn watch<'gc>(
};
let user_data = args.get(2).cloned().unwrap_or(Value::Undefined);
this.set_watcher(context.gc_context, name, callback, user_data);
this.set_watcher(activation, context.gc_context, name, callback, user_data);
Ok(true.into())
}
@ -206,7 +206,7 @@ fn unwatch<'gc>(
return Ok(false.into());
};
let result = this.remove_watcher(context.gc_context, name);
let result = this.remove_watcher(activation, context.gc_context, name);
Ok(result.into())
}

View File

@ -264,6 +264,7 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
/// The property does not need to exist at the time of this being called.
fn set_watcher(
&self,
activation: &mut Activation<'_, 'gc>,
gc_context: MutationContext<'gc, '_>,
name: Cow<str>,
callback: Executable<'gc>,
@ -274,7 +275,12 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
///
/// The return value will indicate if there was a watcher present before this method was
/// called.
fn remove_watcher(&self, gc_context: MutationContext<'gc, '_>, name: Cow<str>) -> bool;
fn remove_watcher(
&self,
activation: &mut Activation<'_, 'gc>,
gc_context: MutationContext<'gc, '_>,
name: Cow<str>,
) -> bool;
/// Checks if the object has a given named property.
fn has_property(

View File

@ -8,7 +8,6 @@ use core::fmt;
use enumset::EnumSet;
use gc_arena::{Collect, GcCell, MutationContext};
use std::borrow::Cow;
use std::collections::HashMap;
pub const TYPE_OF_OBJECT: &str = "object";
@ -73,7 +72,7 @@ pub struct ScriptObjectData<'gc> {
interfaces: Vec<Object<'gc>>,
type_of: &'static str,
array: ArrayStorage<'gc>,
watchers: HashMap<String, Watcher<'gc>>,
watchers: PropertyMap<Watcher<'gc>>,
}
unsafe impl<'gc> Collect for ScriptObjectData<'gc> {
@ -110,7 +109,7 @@ impl<'gc> ScriptObject<'gc> {
values: PropertyMap::new(),
array: ArrayStorage::Properties { length: 0 },
interfaces: vec![],
watchers: HashMap::new(),
watchers: PropertyMap::new(),
},
))
}
@ -127,7 +126,7 @@ impl<'gc> ScriptObject<'gc> {
values: PropertyMap::new(),
array: ArrayStorage::Vector(Vec::new()),
interfaces: vec![],
watchers: HashMap::new(),
watchers: PropertyMap::new(),
},
));
object.sync_native_property("length", gc_context, Some(0.into()), false);
@ -147,7 +146,7 @@ impl<'gc> ScriptObject<'gc> {
values: PropertyMap::new(),
array: ArrayStorage::Properties { length: 0 },
interfaces: vec![],
watchers: HashMap::new(),
watchers: PropertyMap::new(),
},
))
.into()
@ -167,7 +166,7 @@ impl<'gc> ScriptObject<'gc> {
values: PropertyMap::new(),
array: ArrayStorage::Properties { length: 0 },
interfaces: vec![],
watchers: HashMap::new(),
watchers: PropertyMap::new(),
},
))
}
@ -309,7 +308,12 @@ impl<'gc> ScriptObject<'gc> {
//we'd resolve and return up there, but we have borrows that need
//to end before we can do so.
if !worked {
let watcher = self.0.read().watchers.get(name).cloned();
let watcher = self
.0
.read()
.watchers
.get(name, activation.is_case_sensitive())
.cloned();
let mut return_value = Ok(());
if let Some(watcher) = watcher {
let old_value = self.get(name, activation, context)?;
@ -557,19 +561,30 @@ impl<'gc> TObject<'gc> for ScriptObject<'gc> {
fn set_watcher(
&self,
activation: &mut Activation<'_, 'gc>,
gc_context: MutationContext<'gc, '_>,
name: Cow<str>,
callback: Executable<'gc>,
user_data: Value<'gc>,
) {
self.0
.write(gc_context)
.watchers
.insert(name.to_string(), Watcher::new(callback, user_data));
self.0.write(gc_context).watchers.insert(
&name,
Watcher::new(callback, user_data),
activation.is_case_sensitive(),
);
}
fn remove_watcher(&self, gc_context: MutationContext<'gc, '_>, name: Cow<str>) -> bool {
let old = self.0.write(gc_context).watchers.remove(name.as_ref());
fn remove_watcher(
&self,
activation: &mut Activation<'_, 'gc>,
gc_context: MutationContext<'gc, '_>,
name: Cow<str>,
) -> bool {
let old = self
.0
.write(gc_context)
.watchers
.remove(name.as_ref(), activation.is_case_sensitive());
old.is_some()
}

View File

@ -193,17 +193,23 @@ impl<'gc> TObject<'gc> for SharedObject<'gc> {
fn set_watcher(
&self,
activation: &mut Activation<'_, 'gc>,
gc_context: MutationContext<'gc, '_>,
name: Cow<str>,
callback: Executable<'gc>,
user_data: Value<'gc>,
) {
self.base()
.set_watcher(gc_context, name, callback, user_data);
.set_watcher(activation, gc_context, name, callback, user_data);
}
fn remove_watcher(&self, gc_context: MutationContext<'gc, '_>, name: Cow<str>) -> bool {
self.base().remove_watcher(gc_context, name)
fn remove_watcher(
&self,
activation: &mut Activation<'_, 'gc>,
gc_context: MutationContext<'gc, '_>,
name: Cow<str>,
) -> bool {
self.base().remove_watcher(activation, gc_context, name)
}
fn has_property(

View File

@ -253,17 +253,23 @@ impl<'gc> TObject<'gc> for SoundObject<'gc> {
fn set_watcher(
&self,
activation: &mut Activation<'_, 'gc>,
gc_context: MutationContext<'gc, '_>,
name: Cow<str>,
callback: Executable<'gc>,
user_data: Value<'gc>,
) {
self.base()
.set_watcher(gc_context, name, callback, user_data);
.set_watcher(activation, gc_context, name, callback, user_data);
}
fn remove_watcher(&self, gc_context: MutationContext<'gc, '_>, name: Cow<str>) -> bool {
self.base().remove_watcher(gc_context, name)
fn remove_watcher(
&self,
activation: &mut Activation<'_, 'gc>,
gc_context: MutationContext<'gc, '_>,
name: Cow<str>,
) -> bool {
self.base().remove_watcher(activation, gc_context, name)
}
fn has_property(

View File

@ -334,6 +334,7 @@ impl<'gc> TObject<'gc> for StageObject<'gc> {
fn set_watcher(
&self,
activation: &mut Activation<'_, 'gc>,
gc_context: MutationContext<'gc, '_>,
name: Cow<str>,
callback: Executable<'gc>,
@ -342,11 +343,19 @@ impl<'gc> TObject<'gc> for StageObject<'gc> {
self.0
.read()
.base
.set_watcher(gc_context, name, callback, user_data);
.set_watcher(activation, gc_context, name, callback, user_data);
}
fn remove_watcher(&self, gc_context: MutationContext<'gc, '_>, name: Cow<str>) -> bool {
self.0.read().base.remove_watcher(gc_context, name)
fn remove_watcher(
&self,
activation: &mut Activation<'_, 'gc>,
gc_context: MutationContext<'gc, '_>,
name: Cow<str>,
) -> bool {
self.0
.read()
.base
.remove_watcher(activation, gc_context, name)
}
fn has_property(

View File

@ -239,6 +239,7 @@ impl<'gc> TObject<'gc> for SuperObject<'gc> {
fn set_watcher(
&self,
_activation: &mut Activation<'_, 'gc>,
_gc_context: MutationContext<'gc, '_>,
_name: Cow<str>,
_callback: Executable<'gc>,
@ -247,7 +248,12 @@ impl<'gc> TObject<'gc> for SuperObject<'gc> {
//`super` cannot have properties defined on it
}
fn remove_watcher(&self, _gc_context: MutationContext<'gc, '_>, _name: Cow<str>) -> bool {
fn remove_watcher(
&self,
_activation: &mut Activation<'_, 'gc>,
_gc_context: MutationContext<'gc, '_>,
_name: Cow<str>,
) -> bool {
//`super` cannot have properties defined on it
false
}

View File

@ -233,6 +233,7 @@ impl<'gc> TObject<'gc> for ValueObject<'gc> {
fn set_watcher(
&self,
activation: &mut Activation<'_, 'gc>,
gc_context: MutationContext<'gc, '_>,
name: Cow<str>,
callback: Executable<'gc>,
@ -241,14 +242,19 @@ impl<'gc> TObject<'gc> for ValueObject<'gc> {
self.0
.read()
.base
.set_watcher(gc_context, name, callback, user_data);
.set_watcher(activation, gc_context, name, callback, user_data);
}
fn remove_watcher(&self, gc_context: MutationContext<'gc, '_>, name: Cow<str>) -> bool {
fn remove_watcher(
&self,
activation: &mut Activation<'_, 'gc>,
gc_context: MutationContext<'gc, '_>,
name: Cow<str>,
) -> bool {
self.0
.write(gc_context)
.base
.remove_watcher(gc_context, name)
.remove_watcher(activation, gc_context, name)
}
fn define_value(

View File

@ -159,17 +159,23 @@ impl<'gc> TObject<'gc> for XMLAttributesObject<'gc> {
fn set_watcher(
&self,
activation: &mut Activation<'_, 'gc>,
gc_context: MutationContext<'gc, '_>,
name: Cow<str>,
callback: Executable<'gc>,
user_data: Value<'gc>,
) {
self.base()
.set_watcher(gc_context, name, callback, user_data);
.set_watcher(activation, gc_context, name, callback, user_data);
}
fn remove_watcher(&self, gc_context: MutationContext<'gc, '_>, name: Cow<str>) -> bool {
self.base().remove_watcher(gc_context, name)
fn remove_watcher(
&self,
activation: &mut Activation<'_, 'gc>,
gc_context: MutationContext<'gc, '_>,
name: Cow<str>,
) -> bool {
self.base().remove_watcher(activation, gc_context, name)
}
fn define_value(

View File

@ -157,17 +157,23 @@ impl<'gc> TObject<'gc> for XMLIDMapObject<'gc> {
fn set_watcher(
&self,
activation: &mut Activation<'_, 'gc>,
gc_context: MutationContext<'gc, '_>,
name: Cow<str>,
callback: Executable<'gc>,
user_data: Value<'gc>,
) {
self.base()
.set_watcher(gc_context, name, callback, user_data);
.set_watcher(activation, gc_context, name, callback, user_data);
}
fn remove_watcher(&self, gc_context: MutationContext<'gc, '_>, name: Cow<str>) -> bool {
self.base().remove_watcher(gc_context, name)
fn remove_watcher(
&self,
activation: &mut Activation<'_, 'gc>,
gc_context: MutationContext<'gc, '_>,
name: Cow<str>,
) -> bool {
self.base().remove_watcher(activation, gc_context, name)
}
fn define_value(

View File

@ -147,17 +147,23 @@ impl<'gc> TObject<'gc> for XMLObject<'gc> {
fn set_watcher(
&self,
activation: &mut Activation<'_, 'gc>,
gc_context: MutationContext<'gc, '_>,
name: Cow<str>,
callback: Executable<'gc>,
user_data: Value<'gc>,
) {
self.base()
.set_watcher(gc_context, name, callback, user_data);
.set_watcher(activation, gc_context, name, callback, user_data);
}
fn remove_watcher(&self, gc_context: MutationContext<'gc, '_>, name: Cow<str>) -> bool {
self.base().remove_watcher(gc_context, name)
fn remove_watcher(
&self,
activation: &mut Activation<'_, 'gc>,
gc_context: MutationContext<'gc, '_>,
name: Cow<str>,
) -> bool {
self.base().remove_watcher(activation, gc_context, name)
}
fn define_value(