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::{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>(
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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