avm1: Implement StyleSheet.load

This commit is contained in:
Nathan Adams 2024-05-15 19:57:04 +02:00
parent c1e197189d
commit b25fe69bac
9 changed files with 175 additions and 4 deletions

View File

@ -5,6 +5,7 @@ use crate::avm1::{
}; };
use crate::avm1::{Activation, Error, Value}; use crate::avm1::{Activation, Error, Value};
use crate::avm1_stub; use crate::avm1_stub;
use crate::backend::navigator::Request;
use crate::context::GcContext; use crate::context::GcContext;
use crate::html::{transform_dashes_to_camel_case, CssStream, TextFormat}; use crate::html::{transform_dashes_to_camel_case, CssStream, TextFormat};
use crate::string::AvmString; use crate::string::AvmString;
@ -113,11 +114,24 @@ fn get_style_names<'gc>(
fn load<'gc>( fn load<'gc>(
activation: &mut Activation<'_, 'gc>, activation: &mut Activation<'_, 'gc>,
_this: Object<'gc>, this: Object<'gc>,
_args: &[Value<'gc>], args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> { ) -> Result<Value<'gc>, Error<'gc>> {
avm1_stub!(activation, "TextField.StyleSheet", "load"); let url = match args.get(0) {
Ok(Value::Undefined) Some(val) => val.coerce_to_string(activation)?,
None => return Ok(false.into()),
};
let request = Request::get(url.to_utf8_lossy().into_owned());
let future = activation.context.load_manager.load_stylesheet(
activation.context.player.clone(),
this,
request,
);
activation.context.navigator.spawn_future(future);
Ok(true.into())
} }
fn transform<'gc>( fn transform<'gc>(

View File

@ -284,6 +284,7 @@ impl<'gc> LoadManager<'gc> {
| Loader::SaveFileDialog { self_handle, .. } | Loader::SaveFileDialog { self_handle, .. }
| Loader::DownloadFileDialog { self_handle, .. } | Loader::DownloadFileDialog { self_handle, .. }
| Loader::UploadFile { self_handle, .. } | Loader::UploadFile { self_handle, .. }
| Loader::StyleSheet { self_handle, .. }
| Loader::MovieUnloader { self_handle, .. } => *self_handle = Some(handle), | Loader::MovieUnloader { self_handle, .. } => *self_handle = Some(handle),
} }
handle handle
@ -432,6 +433,24 @@ impl<'gc> LoadManager<'gc> {
loader.load_vars_loader(player, request) loader.load_vars_loader(player, request)
} }
/// Kick off an AVM1 StyleSheet load
///
/// Returns the loader's async process, which you will need to spawn.
pub fn load_stylesheet(
&mut self,
player: Weak<Mutex<Player>>,
target_object: Object<'gc>,
request: Request,
) -> OwnedFuture<(), Error> {
let loader = Loader::StyleSheet {
self_handle: None,
target_object,
};
let handle = self.add_loader(loader);
let loader = self.get_loader_mut(handle).unwrap();
loader.load_stylesheet_loader(player, request)
}
/// Kick off a data load into a `URLLoader`, updating /// Kick off a data load into a `URLLoader`, updating
/// its `data` property when the load completes. /// its `data` property when the load completes.
/// ///
@ -824,6 +843,16 @@ pub enum Loader<'gc> {
/// The target AVM1 object to select a file path from. /// The target AVM1 object to select a file path from.
target_object: Object<'gc>, target_object: Object<'gc>,
}, },
/// Loader that is downloading a stylesheet
StyleSheet {
/// The handle to refer to this loader instance.
#[collect(require_static)]
self_handle: Option<LoaderHandle>,
/// The target AVM1 object to submit the styles to
target_object: Object<'gc>,
},
} }
impl<'gc> Loader<'gc> { impl<'gc> Loader<'gc> {
@ -1287,6 +1316,78 @@ impl<'gc> Loader<'gc> {
}) })
} }
/// Creates a future for a LoadVars load call.
fn load_stylesheet_loader(
&mut self,
player: Weak<Mutex<Player>>,
request: Request,
) -> OwnedFuture<(), Error> {
let handle = match self {
Loader::StyleSheet { self_handle, .. } => {
self_handle.expect("Loader not self-introduced")
}
_ => return Box::pin(async { Err(Error::NotLoadVarsLoader) }),
};
let player = player
.upgrade()
.expect("Could not upgrade weak reference to player");
Box::pin(async move {
let fetch = player.lock().unwrap().navigator().fetch(request);
let response = Self::wait_for_full_response(fetch).await;
// Fire the load handler.
player.lock().unwrap().update(|uc| {
let loader = uc.load_manager.get_loader(handle);
let that = match loader {
Some(&Loader::StyleSheet { target_object, .. }) => target_object,
None => return Err(Error::Cancelled),
_ => return Err(Error::NotLoadVarsLoader),
};
let mut activation =
Activation::from_stub(uc.reborrow(), ActivationIdentifier::root("[Loader]"));
match response {
Ok((body, _, _, _)) => {
// Fire the parse & onLoad methods with the loaded string.
let css = AvmString::new_utf8(
activation.context.gc_context,
UTF_8.decode(&body).0,
);
let success = that
.call_method(
"parse".into(),
&[css.into()],
&mut activation,
ExecutionReason::Special,
)
.unwrap_or(Value::Bool(false));
let _ = that.call_method(
"onLoad".into(),
&[success],
&mut activation,
ExecutionReason::Special,
);
}
Err(_) => {
// TODO: Log "Error opening URL" trace similar to the Flash Player?
let _ = that.call_method(
"onLoad".into(),
&[Value::Bool(false)],
&mut activation,
ExecutionReason::Special,
);
}
}
Ok(())
})
})
}
/// Creates a future for a LoadURLLoader load call. /// Creates a future for a LoadURLLoader load call.
fn load_url_loader( fn load_url_loader(
&mut self, &mut self,

View File

@ -0,0 +1,3 @@
a { color: green }
b { color: purple }
c doesn't get a color. too bad.

View File

@ -0,0 +1,49 @@
/// Load valid
true
styleSheet.parse()
onLoad(true)
styleSheet.getStyle("a") = {
"color" = string "blue "
}
styleSheet.getStyle("b") = {
"color" = string "red "
}
styleSheet.getStyle("nonexistant") = null
/// Load valid2 (merged or not?)
true
styleSheet.parse()
onLoad(true)
styleSheet.getStyle("a") = {
"fontStyle" = string "italic "
}
styleSheet.getStyle("b") = {
"color" = string "red "
}
styleSheet.getStyle("nonexistant") = null
/// Load invalid
true
styleSheet.parse()
onLoad(false)
styleSheet.getStyle("a") = {
"fontStyle" = string "italic "
}
styleSheet.getStyle("b") = {
"color" = string "red "
}
styleSheet.getStyle("nonexistant") = null
/// Load non existant
true
onLoad(false)
styleSheet.getStyle("a") = {
"fontStyle" = string "italic "
}
styleSheet.getStyle("b") = {
"color" = string "red "
}
styleSheet.getStyle("nonexistant") = null
/// Load no value
false

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1 @@
num_ticks = 5

View File

@ -0,0 +1,2 @@
a { color: blue }
b { color: red }

View File

@ -0,0 +1 @@
a { font-style: italic }