avm1: Implement StyleSheet.load
This commit is contained in:
parent
c1e197189d
commit
b25fe69bac
|
@ -5,6 +5,7 @@ use crate::avm1::{
|
|||
};
|
||||
use crate::avm1::{Activation, Error, Value};
|
||||
use crate::avm1_stub;
|
||||
use crate::backend::navigator::Request;
|
||||
use crate::context::GcContext;
|
||||
use crate::html::{transform_dashes_to_camel_case, CssStream, TextFormat};
|
||||
use crate::string::AvmString;
|
||||
|
@ -113,11 +114,24 @@ fn get_style_names<'gc>(
|
|||
|
||||
fn load<'gc>(
|
||||
activation: &mut Activation<'_, 'gc>,
|
||||
_this: Object<'gc>,
|
||||
_args: &[Value<'gc>],
|
||||
this: Object<'gc>,
|
||||
args: &[Value<'gc>],
|
||||
) -> Result<Value<'gc>, Error<'gc>> {
|
||||
avm1_stub!(activation, "TextField.StyleSheet", "load");
|
||||
Ok(Value::Undefined)
|
||||
let url = match args.get(0) {
|
||||
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>(
|
||||
|
|
|
@ -284,6 +284,7 @@ impl<'gc> LoadManager<'gc> {
|
|||
| Loader::SaveFileDialog { self_handle, .. }
|
||||
| Loader::DownloadFileDialog { self_handle, .. }
|
||||
| Loader::UploadFile { self_handle, .. }
|
||||
| Loader::StyleSheet { self_handle, .. }
|
||||
| Loader::MovieUnloader { self_handle, .. } => *self_handle = Some(handle),
|
||||
}
|
||||
handle
|
||||
|
@ -432,6 +433,24 @@ impl<'gc> LoadManager<'gc> {
|
|||
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
|
||||
/// 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.
|
||||
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> {
|
||||
|
@ -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.
|
||||
fn load_url_loader(
|
||||
&mut self,
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
a { color: green }
|
||||
b { color: purple }
|
||||
c doesn't get a color. too bad.
|
|
@ -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.
|
@ -0,0 +1 @@
|
|||
num_ticks = 5
|
|
@ -0,0 +1,2 @@
|
|||
a { color: blue }
|
||||
b { color: red }
|
|
@ -0,0 +1 @@
|
|||
a { font-style: italic }
|
Loading…
Reference in New Issue