Add separate libraries for each loaded movie.
This commit is contained in:
parent
e0c0779bd0
commit
5ce499d11e
|
@ -1577,6 +1577,7 @@ dependencies = [
|
||||||
"smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"swf 0.1.2",
|
"swf 0.1.2",
|
||||||
"url 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"url 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"weak-table 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2242,6 +2243,11 @@ dependencies = [
|
||||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "weak-table"
|
||||||
|
version = "0.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "web-sys"
|
name = "web-sys"
|
||||||
version = "0.3.34"
|
version = "0.3.34"
|
||||||
|
@ -2642,6 +2648,7 @@ dependencies = [
|
||||||
"checksum wayland-protocols 0.23.6 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc286643656742777d55dc8e70d144fa4699e426ca8e9d4ef454f4bf15ffcf9"
|
"checksum wayland-protocols 0.23.6 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc286643656742777d55dc8e70d144fa4699e426ca8e9d4ef454f4bf15ffcf9"
|
||||||
"checksum wayland-scanner 0.23.6 (registry+https://github.com/rust-lang/crates.io-index)" = "93b02247366f395b9258054f964fe293ddd019c3237afba9be2ccbe9e1651c3d"
|
"checksum wayland-scanner 0.23.6 (registry+https://github.com/rust-lang/crates.io-index)" = "93b02247366f395b9258054f964fe293ddd019c3237afba9be2ccbe9e1651c3d"
|
||||||
"checksum wayland-sys 0.23.6 (registry+https://github.com/rust-lang/crates.io-index)" = "d94e89a86e6d6d7c7c9b19ebf48a03afaac4af6bc22ae570e9a24124b75358f4"
|
"checksum wayland-sys 0.23.6 (registry+https://github.com/rust-lang/crates.io-index)" = "d94e89a86e6d6d7c7c9b19ebf48a03afaac4af6bc22ae570e9a24124b75358f4"
|
||||||
|
"checksum weak-table 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a5862bb244c852a56c6f3c39668ff181271bda44513ef30d2073a3eedd9898d"
|
||||||
"checksum web-sys 0.3.34 (registry+https://github.com/rust-lang/crates.io-index)" = "ba09295448c0b93bc87d2769614d371a924749e5e6c87e4c1df8b2416b49b775"
|
"checksum web-sys 0.3.34 (registry+https://github.com/rust-lang/crates.io-index)" = "ba09295448c0b93bc87d2769614d371a924749e5e6c87e4c1df8b2416b49b775"
|
||||||
"checksum webbrowser 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "97d468a911faaaeb783693b004e1c62e0063e646b0afae5c146cd144e566e66d"
|
"checksum webbrowser 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "97d468a911faaaeb783693b004e1c62e0063e646b0afae5c146cd144e566e66d"
|
||||||
"checksum weedle 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3bb43f70885151e629e2a19ce9e50bd730fd436cfd4b666894c9ce4de9141164"
|
"checksum weedle 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3bb43f70885151e629e2a19ce9e50bd730fd436cfd4b666894c9ce4de9141164"
|
||||||
|
|
|
@ -22,6 +22,7 @@ num_enum = "0.4.2"
|
||||||
quick-xml = "0.17.2"
|
quick-xml = "0.17.2"
|
||||||
downcast-rs = "1.1.1"
|
downcast-rs = "1.1.1"
|
||||||
url = "2.1.0"
|
url = "2.1.0"
|
||||||
|
weak-table = "0.2.3"
|
||||||
|
|
||||||
[dependencies.jpeg-decoder]
|
[dependencies.jpeg-decoder]
|
||||||
version = "0.1.18"
|
version = "0.1.18"
|
||||||
|
|
|
@ -1645,7 +1645,7 @@ impl<'gc> Avm1<'gc> {
|
||||||
let that = avm.unroot_object(slot).as_display_object().unwrap();
|
let that = avm.unroot_object(slot).as_display_object().unwrap();
|
||||||
let mut mc = that.as_movie_clip().unwrap();
|
let mut mc = that.as_movie_clip().unwrap();
|
||||||
|
|
||||||
mc.replace_with_movie(uc.gc_context, movie);
|
mc.replace_with_movie(uc.gc_context, movie.clone());
|
||||||
|
|
||||||
let mut morph_shapes = fnv::FnvHashMap::default();
|
let mut morph_shapes = fnv::FnvHashMap::default();
|
||||||
mc.preload(uc, &mut morph_shapes);
|
mc.preload(uc, &mut morph_shapes);
|
||||||
|
@ -1653,7 +1653,9 @@ impl<'gc> Avm1<'gc> {
|
||||||
// Finalize morph shapes.
|
// Finalize morph shapes.
|
||||||
for (id, static_data) in morph_shapes {
|
for (id, static_data) in morph_shapes {
|
||||||
let morph_shape = MorphShape::new(uc.gc_context, static_data);
|
let morph_shape = MorphShape::new(uc.gc_context, static_data);
|
||||||
uc.library.register_character(
|
uc.library
|
||||||
|
.library_for_movie_mut(movie.clone())
|
||||||
|
.register_character(
|
||||||
id,
|
id,
|
||||||
crate::character::Character::MorphShape(morph_shape),
|
crate::character::Character::MorphShape(morph_shape),
|
||||||
);
|
);
|
||||||
|
@ -1738,7 +1740,7 @@ impl<'gc> Avm1<'gc> {
|
||||||
let that = avm.unroot_object(slot).as_display_object().unwrap();
|
let that = avm.unroot_object(slot).as_display_object().unwrap();
|
||||||
let mut mc = that.as_movie_clip().unwrap();
|
let mut mc = that.as_movie_clip().unwrap();
|
||||||
|
|
||||||
mc.replace_with_movie(uc.gc_context, movie);
|
mc.replace_with_movie(uc.gc_context, movie.clone());
|
||||||
|
|
||||||
let mut morph_shapes = fnv::FnvHashMap::default();
|
let mut morph_shapes = fnv::FnvHashMap::default();
|
||||||
mc.preload(uc, &mut morph_shapes);
|
mc.preload(uc, &mut morph_shapes);
|
||||||
|
@ -1746,7 +1748,9 @@ impl<'gc> Avm1<'gc> {
|
||||||
// Finalize morph shapes.
|
// Finalize morph shapes.
|
||||||
for (id, static_data) in morph_shapes {
|
for (id, static_data) in morph_shapes {
|
||||||
let morph_shape = MorphShape::new(uc.gc_context, static_data);
|
let morph_shape = MorphShape::new(uc.gc_context, static_data);
|
||||||
uc.library.register_character(
|
uc.library
|
||||||
|
.library_for_movie_mut(movie.clone())
|
||||||
|
.register_character(
|
||||||
id,
|
id,
|
||||||
crate::character::Character::MorphShape(morph_shape),
|
crate::character::Character::MorphShape(morph_shape),
|
||||||
);
|
);
|
||||||
|
|
|
@ -246,11 +246,15 @@ fn attach_movie<'gc>(
|
||||||
if depth < 0 || depth > AVM_MAX_DEPTH {
|
if depth < 0 || depth > AVM_MAX_DEPTH {
|
||||||
return Ok(Value::Undefined.into());
|
return Ok(Value::Undefined.into());
|
||||||
}
|
}
|
||||||
if let Ok(mut new_clip) = context.library.instantiate_by_export_name(
|
|
||||||
&export_name,
|
if let Ok(mut new_clip) = context
|
||||||
context.gc_context,
|
.library
|
||||||
&avm.prototypes,
|
.library_for_movie(movie_clip.movie().unwrap())
|
||||||
) {
|
.ok_or_else(|| "Movie is missing!".into())
|
||||||
|
.and_then(|l| {
|
||||||
|
l.instantiate_by_export_name(&export_name, context.gc_context, &avm.prototypes)
|
||||||
|
})
|
||||||
|
{
|
||||||
// Set name and attach to parent.
|
// Set name and attach to parent.
|
||||||
new_clip.set_name(context.gc_context, &new_instance_name);
|
new_clip.set_name(context.gc_context, &new_instance_name);
|
||||||
movie_clip.add_child_from_avm(context, new_clip, depth);
|
movie_clip.add_child_from_avm(context, new_clip, depth);
|
||||||
|
@ -310,6 +314,7 @@ fn create_text_field<'gc>(
|
||||||
context: &mut UpdateContext<'_, 'gc, '_>,
|
context: &mut UpdateContext<'_, 'gc, '_>,
|
||||||
args: &[Value<'gc>],
|
args: &[Value<'gc>],
|
||||||
) -> Result<ReturnValue<'gc>, Error> {
|
) -> Result<ReturnValue<'gc>, Error> {
|
||||||
|
let movie = avm.base_clip().movie().unwrap();
|
||||||
let instance_name = args
|
let instance_name = args
|
||||||
.get(0)
|
.get(0)
|
||||||
.cloned()
|
.cloned()
|
||||||
|
@ -341,7 +346,8 @@ fn create_text_field<'gc>(
|
||||||
.unwrap_or(Value::Undefined)
|
.unwrap_or(Value::Undefined)
|
||||||
.as_number(avm, context)?;
|
.as_number(avm, context)?;
|
||||||
|
|
||||||
let mut text_field: DisplayObject<'gc> = EditText::new(context, x, y, width, height).into();
|
let mut text_field: DisplayObject<'gc> =
|
||||||
|
EditText::new(context, movie, x, y, width, height).into();
|
||||||
text_field.post_instantiation(context.gc_context, text_field, avm.prototypes().text_field);
|
text_field.post_instantiation(context.gc_context, text_field, avm.prototypes().text_field);
|
||||||
text_field.set_name(context.gc_context, &instance_name);
|
text_field.set_name(context.gc_context, &instance_name);
|
||||||
movie_clip.add_child_from_avm(context, text_field, depth as Depth);
|
movie_clip.add_child_from_avm(context, text_field, depth as Depth);
|
||||||
|
@ -385,10 +391,12 @@ pub fn duplicate_movie_clip<'gc>(
|
||||||
if depth < 0 || depth > AVM_MAX_DEPTH {
|
if depth < 0 || depth > AVM_MAX_DEPTH {
|
||||||
return Ok(Value::Undefined.into());
|
return Ok(Value::Undefined.into());
|
||||||
}
|
}
|
||||||
if let Ok(mut new_clip) =
|
|
||||||
context
|
if let Ok(mut new_clip) = context
|
||||||
.library
|
.library
|
||||||
.instantiate_by_id(movie_clip.id(), context.gc_context, &avm.prototypes)
|
.library_for_movie(movie_clip.movie().unwrap())
|
||||||
|
.ok_or_else(|| "Movie is missing!".into())
|
||||||
|
.and_then(|l| l.instantiate_by_id(movie_clip.id(), context.gc_context, &avm.prototypes))
|
||||||
{
|
{
|
||||||
// Set name and attach to parent.
|
// Set name and attach to parent.
|
||||||
new_clip.set_name(context.gc_context, &new_instance_name);
|
new_clip.set_name(context.gc_context, &new_instance_name);
|
||||||
|
|
|
@ -6,6 +6,7 @@ use crate::avm1::property::Attribute::*;
|
||||||
use crate::avm1::return_value::ReturnValue;
|
use crate::avm1::return_value::ReturnValue;
|
||||||
use crate::avm1::{Avm1, Error, Object, SoundObject, TObject, UpdateContext, Value};
|
use crate::avm1::{Avm1, Error, Object, SoundObject, TObject, UpdateContext, Value};
|
||||||
use crate::character::Character;
|
use crate::character::Character;
|
||||||
|
use crate::display_object::TDisplayObject;
|
||||||
use gc_arena::MutationContext;
|
use gc_arena::MutationContext;
|
||||||
|
|
||||||
/// Implements `Sound`
|
/// Implements `Sound`
|
||||||
|
@ -167,7 +168,13 @@ fn attach_sound<'gc>(
|
||||||
let name = args.get(0).unwrap_or(&Value::Undefined);
|
let name = args.get(0).unwrap_or(&Value::Undefined);
|
||||||
if let Some(sound_object) = this.as_sound_object() {
|
if let Some(sound_object) = this.as_sound_object() {
|
||||||
let name = name.clone().coerce_to_string(avm, context)?;
|
let name = name.clone().coerce_to_string(avm, context)?;
|
||||||
if let Some(Character::Sound(sound)) = context.library.get_character_by_export_name(&name) {
|
let movie = sound_object.owner().and_then(|o| o.movie());
|
||||||
|
if let Some(movie) = movie {
|
||||||
|
if let Some(Character::Sound(sound)) = context
|
||||||
|
.library
|
||||||
|
.library_for_movie_mut(movie)
|
||||||
|
.get_character_by_export_name(&name)
|
||||||
|
{
|
||||||
sound_object.set_sound(context.gc_context, Some(*sound));
|
sound_object.set_sound(context.gc_context, Some(*sound));
|
||||||
sound_object.set_duration(
|
sound_object.set_duration(
|
||||||
context.gc_context,
|
context.gc_context,
|
||||||
|
@ -177,6 +184,12 @@ fn attach_sound<'gc>(
|
||||||
} else {
|
} else {
|
||||||
log::warn!("Sound.attachSound: Sound '{}' not found", name);
|
log::warn!("Sound.attachSound: Sound '{}' not found", name);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
log::warn!(
|
||||||
|
"Sound.attachSound: Cannot attach Sound '{}' without a library to reference",
|
||||||
|
name
|
||||||
|
);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
log::warn!("Sound.attachSound: this is not a Sound");
|
log::warn!("Sound.attachSound: this is not a Sound");
|
||||||
}
|
}
|
||||||
|
@ -395,14 +408,24 @@ fn stop<'gc>(
|
||||||
if let Some(name) = args.get(0) {
|
if let Some(name) = args.get(0) {
|
||||||
// Usage 1: Stop all instances of a particular sound, using the name parameter.
|
// Usage 1: Stop all instances of a particular sound, using the name parameter.
|
||||||
let name = name.clone().coerce_to_string(avm, context)?;
|
let name = name.clone().coerce_to_string(avm, context)?;
|
||||||
if let Some(Character::Sound(sound)) =
|
let movie = sound.owner().and_then(|o| o.movie());
|
||||||
context.library.get_character_by_export_name(&name)
|
if let Some(movie) = movie {
|
||||||
|
if let Some(Character::Sound(sound)) = context
|
||||||
|
.library
|
||||||
|
.library_for_movie_mut(movie)
|
||||||
|
.get_character_by_export_name(&name)
|
||||||
{
|
{
|
||||||
// Stop all sounds with the given name.
|
// Stop all sounds with the given name.
|
||||||
context.audio.stop_sounds_with_handle(*sound);
|
context.audio.stop_sounds_with_handle(*sound);
|
||||||
} else {
|
} else {
|
||||||
log::warn!("Sound.stop: Sound '{}' not found", name);
|
log::warn!("Sound.stop: Sound '{}' not found", name);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
log::warn!(
|
||||||
|
"Sound.stop: Cannot stop Sound '{}' without a library to reference",
|
||||||
|
name
|
||||||
|
)
|
||||||
|
}
|
||||||
} else if let Some(_owner) = sound.owner() {
|
} else if let Some(_owner) = sound.owner() {
|
||||||
// Usage 2: Stop all sound running within a given clip.
|
// Usage 2: Stop all sound running within a given clip.
|
||||||
// TODO: We just stop the last played sound for now.
|
// TODO: We just stop the last played sound for now.
|
||||||
|
|
|
@ -604,7 +604,7 @@ mod tests {
|
||||||
b: 0,
|
b: 0,
|
||||||
a: 0,
|
a: 0,
|
||||||
},
|
},
|
||||||
library: &mut Library::new(),
|
library: &mut Library::default(),
|
||||||
navigator: &mut NullNavigatorBackend::new(),
|
navigator: &mut NullNavigatorBackend::new(),
|
||||||
renderer: &mut NullRenderer::new(),
|
renderer: &mut NullRenderer::new(),
|
||||||
system_prototypes: avm.prototypes().clone(),
|
system_prototypes: avm.prototypes().clone(),
|
||||||
|
|
|
@ -43,7 +43,7 @@ where
|
||||||
b: 0,
|
b: 0,
|
||||||
a: 0,
|
a: 0,
|
||||||
},
|
},
|
||||||
library: &mut Library::new(),
|
library: &mut Library::default(),
|
||||||
navigator: &mut NullNavigatorBackend::new(),
|
navigator: &mut NullNavigatorBackend::new(),
|
||||||
renderer: &mut NullRenderer::new(),
|
renderer: &mut NullRenderer::new(),
|
||||||
system_prototypes: avm.prototypes().clone(),
|
system_prototypes: avm.prototypes().clone(),
|
||||||
|
|
|
@ -2,12 +2,14 @@ use crate::avm1::{Object, Value};
|
||||||
use crate::context::{RenderContext, UpdateContext};
|
use crate::context::{RenderContext, UpdateContext};
|
||||||
use crate::player::NEWEST_PLAYER_VERSION;
|
use crate::player::NEWEST_PLAYER_VERSION;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use crate::tag_utils::SwfMovie;
|
||||||
use crate::transform::Transform;
|
use crate::transform::Transform;
|
||||||
use enumset::{EnumSet, EnumSetType};
|
use enumset::{EnumSet, EnumSetType};
|
||||||
use gc_arena::{Collect, MutationContext};
|
use gc_arena::{Collect, MutationContext};
|
||||||
use ruffle_macros::enum_trait_object;
|
use ruffle_macros::enum_trait_object;
|
||||||
use std::cell::{Ref, RefMut};
|
use std::cell::{Ref, RefMut};
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
mod bitmap;
|
mod bitmap;
|
||||||
mod button;
|
mod button;
|
||||||
|
@ -345,6 +347,10 @@ impl<'gc> DisplayObjectBase<'gc> {
|
||||||
.map(|p| p.swf_version())
|
.map(|p| p.swf_version())
|
||||||
.unwrap_or(NEWEST_PLAYER_VERSION)
|
.unwrap_or(NEWEST_PLAYER_VERSION)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn movie(&self) -> Option<Arc<SwfMovie>> {
|
||||||
|
self.parent.and_then(|p| p.movie())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[enum_trait_object(
|
#[enum_trait_object(
|
||||||
|
@ -725,7 +731,7 @@ pub trait TDisplayObject<'gc>: 'gc + Collect + Debug {
|
||||||
.clip_actions
|
.clip_actions
|
||||||
.iter()
|
.iter()
|
||||||
.cloned()
|
.cloned()
|
||||||
.map(|a| ClipAction::from_action_and_movie(a, clip.movie()))
|
.map(|a| ClipAction::from_action_and_movie(a, clip.movie().unwrap()))
|
||||||
.collect(),
|
.collect(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -784,6 +790,11 @@ pub trait TDisplayObject<'gc>: 'gc + Collect + Debug {
|
||||||
.unwrap_or(NEWEST_PLAYER_VERSION)
|
.unwrap_or(NEWEST_PLAYER_VERSION)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the SWF that defines this display object.
|
||||||
|
fn movie(&self) -> Option<Arc<SwfMovie>> {
|
||||||
|
self.parent().and_then(|p| p.movie())
|
||||||
|
}
|
||||||
|
|
||||||
fn instantiate(&self, gc_context: MutationContext<'gc, '_>) -> DisplayObject<'gc>;
|
fn instantiate(&self, gc_context: MutationContext<'gc, '_>) -> DisplayObject<'gc>;
|
||||||
fn as_ptr(&self) -> *const DisplayObjectPtr;
|
fn as_ptr(&self) -> *const DisplayObjectPtr;
|
||||||
|
|
||||||
|
|
|
@ -3,10 +3,11 @@ use crate::context::{ActionType, RenderContext, UpdateContext};
|
||||||
use crate::display_object::{DisplayObjectBase, TDisplayObject};
|
use crate::display_object::{DisplayObjectBase, TDisplayObject};
|
||||||
use crate::events::{ButtonEvent, ButtonEventResult, ButtonKeyCode};
|
use crate::events::{ButtonEvent, ButtonEventResult, ButtonKeyCode};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::tag_utils::SwfSlice;
|
use crate::tag_utils::{SwfMovie, SwfSlice};
|
||||||
use gc_arena::{Collect, GcCell, MutationContext};
|
use gc_arena::{Collect, GcCell, MutationContext};
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Collect, Copy)]
|
#[derive(Clone, Debug, Collect, Copy)]
|
||||||
#[collect(no_drop)]
|
#[collect(no_drop)]
|
||||||
|
@ -47,6 +48,7 @@ impl<'gc> Button<'gc> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let static_data = ButtonStatic {
|
let static_data = ButtonStatic {
|
||||||
|
swf: source_movie.movie.clone(),
|
||||||
id: button.id,
|
id: button.id,
|
||||||
records: button.records.clone(),
|
records: button.records.clone(),
|
||||||
actions,
|
actions,
|
||||||
|
@ -120,6 +122,10 @@ impl<'gc> TDisplayObject<'gc> for Button<'gc> {
|
||||||
self.0.read().static_data.read().id
|
self.0.read().static_data.read().id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn movie(&self) -> Option<Arc<SwfMovie>> {
|
||||||
|
Some(self.0.read().static_data.read().swf.clone())
|
||||||
|
}
|
||||||
|
|
||||||
fn post_instantiation(
|
fn post_instantiation(
|
||||||
&mut self,
|
&mut self,
|
||||||
gc_context: MutationContext<'gc, '_>,
|
gc_context: MutationContext<'gc, '_>,
|
||||||
|
@ -223,11 +229,11 @@ impl<'gc> ButtonData<'gc> {
|
||||||
self.children.clear();
|
self.children.clear();
|
||||||
for record in &self.static_data.read().records {
|
for record in &self.static_data.read().records {
|
||||||
if record.states.contains(&swf_state) {
|
if record.states.contains(&swf_state) {
|
||||||
if let Ok(mut child) = context.library.instantiate_by_id(
|
if let Ok(mut child) = context
|
||||||
record.id,
|
.library
|
||||||
context.gc_context,
|
.library_for_movie_mut(self.movie())
|
||||||
&context.system_prototypes,
|
.instantiate_by_id(record.id, context.gc_context, &context.system_prototypes)
|
||||||
) {
|
{
|
||||||
child.set_parent(context.gc_context, Some(self_display_object));
|
child.set_parent(context.gc_context, Some(self_display_object));
|
||||||
child.set_matrix(context.gc_context, &record.matrix.clone().into());
|
child.set_matrix(context.gc_context, &record.matrix.clone().into());
|
||||||
child.set_color_transform(
|
child.set_color_transform(
|
||||||
|
@ -253,7 +259,10 @@ impl<'gc> ButtonData<'gc> {
|
||||||
|
|
||||||
for record in &self.static_data.read().records {
|
for record in &self.static_data.read().records {
|
||||||
if record.states.contains(&swf::ButtonState::HitTest) {
|
if record.states.contains(&swf::ButtonState::HitTest) {
|
||||||
match context.library.instantiate_by_id(
|
match context
|
||||||
|
.library
|
||||||
|
.library_for_movie_mut(self.static_data.read().swf.clone())
|
||||||
|
.instantiate_by_id(
|
||||||
record.id,
|
record.id,
|
||||||
context.gc_context,
|
context.gc_context,
|
||||||
&context.system_prototypes,
|
&context.system_prototypes,
|
||||||
|
@ -335,7 +344,11 @@ impl<'gc> ButtonData<'gc> {
|
||||||
sound: Option<&swf::ButtonSound>,
|
sound: Option<&swf::ButtonSound>,
|
||||||
) {
|
) {
|
||||||
if let Some((id, sound_info)) = sound {
|
if let Some((id, sound_info)) = sound {
|
||||||
if let Some(sound_handle) = context.library.get_sound(*id) {
|
if let Some(sound_handle) = context
|
||||||
|
.library
|
||||||
|
.library_for_movie_mut(self.movie())
|
||||||
|
.get_sound(*id)
|
||||||
|
{
|
||||||
context.audio.start_sound(sound_handle, sound_info);
|
context.audio.start_sound(sound_handle, sound_info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -368,6 +381,10 @@ impl<'gc> ButtonData<'gc> {
|
||||||
}
|
}
|
||||||
handled
|
handled
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn movie(&self) -> Arc<SwfMovie> {
|
||||||
|
self.static_data.read().swf.clone()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<'gc> gc_arena::Collect for ButtonData<'gc> {
|
unsafe impl<'gc> gc_arena::Collect for ButtonData<'gc> {
|
||||||
|
@ -410,6 +427,7 @@ enum ButtonTracking {
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
struct ButtonStatic {
|
struct ButtonStatic {
|
||||||
|
swf: Arc<SwfMovie>,
|
||||||
id: CharacterId,
|
id: CharacterId,
|
||||||
records: Vec<swf::ButtonRecord>,
|
records: Vec<swf::ButtonRecord>,
|
||||||
actions: Vec<ButtonAction>,
|
actions: Vec<ButtonAction>,
|
||||||
|
|
|
@ -6,8 +6,10 @@ use crate::display_object::{DisplayObjectBase, TDisplayObject};
|
||||||
use crate::font::{Glyph, TextFormat};
|
use crate::font::{Glyph, TextFormat};
|
||||||
use crate::library::Library;
|
use crate::library::Library;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use crate::tag_utils::SwfMovie;
|
||||||
use crate::transform::Transform;
|
use crate::transform::Transform;
|
||||||
use gc_arena::{Collect, Gc, GcCell, MutationContext};
|
use gc_arena::{Collect, Gc, GcCell, MutationContext};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// A dynamic text field.
|
/// A dynamic text field.
|
||||||
/// The text in this text field can be changed dynamically.
|
/// The text in this text field can be changed dynamically.
|
||||||
|
@ -51,7 +53,11 @@ pub struct EditTextData<'gc> {
|
||||||
|
|
||||||
impl<'gc> EditText<'gc> {
|
impl<'gc> EditText<'gc> {
|
||||||
/// Creates a new `EditText` from an SWF `DefineEditText` tag.
|
/// Creates a new `EditText` from an SWF `DefineEditText` tag.
|
||||||
pub fn from_swf_tag(context: &mut UpdateContext<'_, 'gc, '_>, swf_tag: swf::EditText) -> Self {
|
pub fn from_swf_tag(
|
||||||
|
context: &mut UpdateContext<'_, 'gc, '_>,
|
||||||
|
swf_movie: Arc<SwfMovie>,
|
||||||
|
swf_tag: swf::EditText,
|
||||||
|
) -> Self {
|
||||||
let is_multiline = swf_tag.is_multiline;
|
let is_multiline = swf_tag.is_multiline;
|
||||||
let is_word_wrap = swf_tag.is_word_wrap;
|
let is_word_wrap = swf_tag.is_word_wrap;
|
||||||
|
|
||||||
|
@ -84,7 +90,13 @@ impl<'gc> EditText<'gc> {
|
||||||
base: Default::default(),
|
base: Default::default(),
|
||||||
text,
|
text,
|
||||||
new_format: TextFormat::default(),
|
new_format: TextFormat::default(),
|
||||||
static_data: gc_arena::Gc::allocate(context.gc_context, EditTextStatic(swf_tag)),
|
static_data: gc_arena::Gc::allocate(
|
||||||
|
context.gc_context,
|
||||||
|
EditTextStatic {
|
||||||
|
swf: swf_movie,
|
||||||
|
text: swf_tag,
|
||||||
|
},
|
||||||
|
),
|
||||||
is_multiline,
|
is_multiline,
|
||||||
is_word_wrap,
|
is_word_wrap,
|
||||||
object: None,
|
object: None,
|
||||||
|
@ -96,6 +108,7 @@ impl<'gc> EditText<'gc> {
|
||||||
/// Create a new, dynamic `EditText`.
|
/// Create a new, dynamic `EditText`.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
context: &mut UpdateContext<'_, 'gc, '_>,
|
context: &mut UpdateContext<'_, 'gc, '_>,
|
||||||
|
swf_movie: Arc<SwfMovie>,
|
||||||
x: f64,
|
x: f64,
|
||||||
y: f64,
|
y: f64,
|
||||||
width: f64,
|
width: f64,
|
||||||
|
@ -140,7 +153,7 @@ impl<'gc> EditText<'gc> {
|
||||||
is_device_font: false,
|
is_device_font: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
Self::from_swf_tag(context, swf_tag)
|
Self::from_swf_tag(context, swf_movie, swf_tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: This needs to strip away HTML
|
// TODO: This needs to strip away HTML
|
||||||
|
@ -191,11 +204,15 @@ impl<'gc> EditText<'gc> {
|
||||||
/// `DisplayObject`.
|
/// `DisplayObject`.
|
||||||
pub fn text_transform(self) -> Transform {
|
pub fn text_transform(self) -> Transform {
|
||||||
let edit_text = self.0.read();
|
let edit_text = self.0.read();
|
||||||
let static_data = &edit_text.static_data.0;
|
let static_data = &edit_text.static_data;
|
||||||
|
|
||||||
// TODO: Many of these properties should change be instance members instead
|
// TODO: Many of these properties should change be instance members instead
|
||||||
// of static data, because they can be altered via ActionScript.
|
// of static data, because they can be altered via ActionScript.
|
||||||
let color = static_data.color.as_ref().unwrap_or_else(|| &swf::Color {
|
let color = static_data
|
||||||
|
.text
|
||||||
|
.color
|
||||||
|
.as_ref()
|
||||||
|
.unwrap_or_else(|| &swf::Color {
|
||||||
r: 0,
|
r: 0,
|
||||||
g: 0,
|
g: 0,
|
||||||
b: 0,
|
b: 0,
|
||||||
|
@ -208,7 +225,7 @@ impl<'gc> EditText<'gc> {
|
||||||
transform.color_transform.b_mult = f32::from(color.b) / 255.0;
|
transform.color_transform.b_mult = f32::from(color.b) / 255.0;
|
||||||
transform.color_transform.a_mult = f32::from(color.a) / 255.0;
|
transform.color_transform.a_mult = f32::from(color.a) / 255.0;
|
||||||
|
|
||||||
if let Some(layout) = &static_data.layout {
|
if let Some(layout) = &static_data.text.layout {
|
||||||
transform.matrix.tx += layout.left_margin.get() as f32;
|
transform.matrix.tx += layout.left_margin.get() as f32;
|
||||||
transform.matrix.tx += layout.indent.get() as f32;
|
transform.matrix.tx += layout.indent.get() as f32;
|
||||||
transform.matrix.ty -= layout.leading.get() as f32;
|
transform.matrix.ty -= layout.leading.get() as f32;
|
||||||
|
@ -224,11 +241,11 @@ impl<'gc> EditText<'gc> {
|
||||||
/// and returns the adjusted transform.
|
/// and returns the adjusted transform.
|
||||||
pub fn newline(self, height: f32, mut transform: Transform) -> Transform {
|
pub fn newline(self, height: f32, mut transform: Transform) -> Transform {
|
||||||
let edit_text = self.0.read();
|
let edit_text = self.0.read();
|
||||||
let static_data = &edit_text.static_data.0;
|
let static_data = &edit_text.static_data;
|
||||||
|
|
||||||
transform.matrix.tx = 0.0;
|
transform.matrix.tx = 0.0;
|
||||||
transform.matrix.ty += height * Twips::TWIPS_PER_PIXEL as f32;
|
transform.matrix.ty += height * Twips::TWIPS_PER_PIXEL as f32;
|
||||||
if let Some(layout) = &static_data.layout {
|
if let Some(layout) = &static_data.text.layout {
|
||||||
transform.matrix.tx += layout.left_margin.get() as f32;
|
transform.matrix.tx += layout.left_margin.get() as f32;
|
||||||
transform.matrix.tx += layout.indent.get() as f32;
|
transform.matrix.tx += layout.indent.get() as f32;
|
||||||
transform.matrix.ty += layout.leading.get() as f32;
|
transform.matrix.ty += layout.leading.get() as f32;
|
||||||
|
@ -239,11 +256,11 @@ impl<'gc> EditText<'gc> {
|
||||||
|
|
||||||
pub fn line_width(self) -> f32 {
|
pub fn line_width(self) -> f32 {
|
||||||
let edit_text = self.0.read();
|
let edit_text = self.0.read();
|
||||||
let static_data = &edit_text.static_data.0;
|
let static_data = &edit_text.static_data;
|
||||||
|
|
||||||
let mut base_width = self.width() as f32;
|
let mut base_width = self.width() as f32;
|
||||||
|
|
||||||
if let Some(layout) = &static_data.layout {
|
if let Some(layout) = &static_data.text.layout {
|
||||||
base_width -= layout.left_margin.to_pixels() as f32;
|
base_width -= layout.left_margin.to_pixels() as f32;
|
||||||
base_width -= layout.indent.to_pixels() as f32;
|
base_width -= layout.indent.to_pixels() as f32;
|
||||||
base_width -= layout.right_margin.to_pixels() as f32;
|
base_width -= layout.right_margin.to_pixels() as f32;
|
||||||
|
@ -273,18 +290,26 @@ impl<'gc> EditText<'gc> {
|
||||||
/// calculating them is a relatively expensive operation.
|
/// calculating them is a relatively expensive operation.
|
||||||
fn line_breaks(self, library: &Library<'gc>) -> Vec<usize> {
|
fn line_breaks(self, library: &Library<'gc>) -> Vec<usize> {
|
||||||
let edit_text = self.0.read();
|
let edit_text = self.0.read();
|
||||||
let static_data = &edit_text.static_data.0;
|
let static_data = &edit_text.static_data;
|
||||||
let font_id = static_data.font_id.unwrap_or(0);
|
let font_id = static_data.text.font_id.unwrap_or(0);
|
||||||
|
|
||||||
if edit_text.is_multiline {
|
if edit_text.is_multiline {
|
||||||
if let Some(font) = library
|
if let Some(font) = library
|
||||||
|
.library_for_movie(self.movie().unwrap())
|
||||||
|
.unwrap()
|
||||||
.get_font(font_id)
|
.get_font(font_id)
|
||||||
.filter(|font| font.has_glyphs())
|
.filter(|font| font.has_glyphs())
|
||||||
.or_else(|| library.device_font())
|
.or_else(|| {
|
||||||
|
library
|
||||||
|
.library_for_movie(self.movie().unwrap())
|
||||||
|
.unwrap()
|
||||||
|
.device_font()
|
||||||
|
})
|
||||||
{
|
{
|
||||||
let mut breakpoints = vec![];
|
let mut breakpoints = vec![];
|
||||||
let mut break_base = 0;
|
let mut break_base = 0;
|
||||||
let height = static_data
|
let height = static_data
|
||||||
|
.text
|
||||||
.height
|
.height
|
||||||
.map(|v| v.to_pixels() as f32)
|
.map(|v| v.to_pixels() as f32)
|
||||||
.unwrap_or_else(|| font.scale());
|
.unwrap_or_else(|| font.scale());
|
||||||
|
@ -343,16 +368,24 @@ impl<'gc> EditText<'gc> {
|
||||||
let breakpoints = self.line_breaks_cached(context.gc_context, context.library);
|
let breakpoints = self.line_breaks_cached(context.gc_context, context.library);
|
||||||
|
|
||||||
let edit_text = self.0.read();
|
let edit_text = self.0.read();
|
||||||
let static_data = &edit_text.static_data.0;
|
let static_data = &edit_text.static_data;
|
||||||
let font_id = static_data.font_id.unwrap_or(0);
|
let font_id = static_data.text.font_id.unwrap_or(0);
|
||||||
|
|
||||||
let mut size: (f32, f32) = (0.0, 0.0);
|
let mut size: (f32, f32) = (0.0, 0.0);
|
||||||
|
|
||||||
if let Some(font) = context
|
if let Some(font) = context
|
||||||
.library
|
.library
|
||||||
|
.library_for_movie(self.movie().unwrap())
|
||||||
|
.unwrap()
|
||||||
.get_font(font_id)
|
.get_font(font_id)
|
||||||
.filter(|font| font.has_glyphs())
|
.filter(|font| font.has_glyphs())
|
||||||
.or_else(|| context.library.device_font())
|
.or_else(|| {
|
||||||
|
context
|
||||||
|
.library
|
||||||
|
.library_for_movie(self.movie().unwrap())
|
||||||
|
.unwrap()
|
||||||
|
.device_font()
|
||||||
|
})
|
||||||
{
|
{
|
||||||
let mut start = 0;
|
let mut start = 0;
|
||||||
let mut chunks = vec![];
|
let mut chunks = vec![];
|
||||||
|
@ -364,6 +397,7 @@ impl<'gc> EditText<'gc> {
|
||||||
chunks.push(&edit_text.text[start..]);
|
chunks.push(&edit_text.text[start..]);
|
||||||
|
|
||||||
let height = static_data
|
let height = static_data
|
||||||
|
.text
|
||||||
.height
|
.height
|
||||||
.map(|v| v.to_pixels() as f32)
|
.map(|v| v.to_pixels() as f32)
|
||||||
.unwrap_or_else(|| font.scale());
|
.unwrap_or_else(|| font.scale());
|
||||||
|
@ -372,7 +406,7 @@ impl<'gc> EditText<'gc> {
|
||||||
let chunk_size = font.measure(chunk, height);
|
let chunk_size = font.measure(chunk, height);
|
||||||
|
|
||||||
size.0 = size.0.max(chunk_size.0);
|
size.0 = size.0.max(chunk_size.0);
|
||||||
if let Some(layout) = &static_data.layout {
|
if let Some(layout) = &static_data.text.layout {
|
||||||
size.1 += layout.leading.to_pixels() as f32;
|
size.1 += layout.leading.to_pixels() as f32;
|
||||||
}
|
}
|
||||||
size.1 += chunk_size.1;
|
size.1 += chunk_size.1;
|
||||||
|
@ -387,7 +421,11 @@ impl<'gc> TDisplayObject<'gc> for EditText<'gc> {
|
||||||
impl_display_object!(base);
|
impl_display_object!(base);
|
||||||
|
|
||||||
fn id(&self) -> CharacterId {
|
fn id(&self) -> CharacterId {
|
||||||
self.0.read().static_data.0.id
|
self.0.read().static_data.text.id
|
||||||
|
}
|
||||||
|
|
||||||
|
fn movie(&self) -> Option<Arc<SwfMovie>> {
|
||||||
|
Some(self.0.read().static_data.swf.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_frame(&mut self, _context: &mut UpdateContext) {
|
fn run_frame(&mut self, _context: &mut UpdateContext) {
|
||||||
|
@ -424,7 +462,7 @@ impl<'gc> TDisplayObject<'gc> for EditText<'gc> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn self_bounds(&self) -> BoundingBox {
|
fn self_bounds(&self) -> BoundingBox {
|
||||||
self.0.read().static_data.0.bounds.clone().into()
|
self.0.read().static_data.text.bounds.clone().into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render(&self, context: &mut RenderContext<'_, 'gc>) {
|
fn render(&self, context: &mut RenderContext<'_, 'gc>) {
|
||||||
|
@ -433,20 +471,24 @@ impl<'gc> TDisplayObject<'gc> for EditText<'gc> {
|
||||||
let mut text_transform = self.text_transform();
|
let mut text_transform = self.text_transform();
|
||||||
|
|
||||||
let edit_text = self.0.read();
|
let edit_text = self.0.read();
|
||||||
let static_data = &edit_text.static_data.0;
|
let static_data = &edit_text.static_data;
|
||||||
let font_id = static_data.font_id.unwrap_or(0);
|
let font_id = static_data.text.font_id.unwrap_or(0);
|
||||||
|
|
||||||
// If the font can't be found or has no glyph information, use the "device font" instead.
|
// If the font can't be found or has no glyph information, use the "device font" instead.
|
||||||
// We're cheating a bit and not actually rendering text using the OS/web.
|
// We're cheating a bit and not actually rendering text using the OS/web.
|
||||||
// Instead, we embed an SWF version of Noto Sans to use as the "device font", and render
|
// Instead, we embed an SWF version of Noto Sans to use as the "device font", and render
|
||||||
// it the same as any other SWF outline text.
|
// it the same as any other SWF outline text.
|
||||||
if let Some(font) = context
|
let library = context
|
||||||
.library
|
.library
|
||||||
|
.library_for_movie(edit_text.static_data.swf.clone())
|
||||||
|
.unwrap();
|
||||||
|
if let Some(font) = library
|
||||||
.get_font(font_id)
|
.get_font(font_id)
|
||||||
.filter(|font| font.has_glyphs())
|
.filter(|font| font.has_glyphs())
|
||||||
.or_else(|| context.library.device_font())
|
.or_else(|| library.device_font())
|
||||||
{
|
{
|
||||||
let height = static_data
|
let height = static_data
|
||||||
|
.text
|
||||||
.height
|
.height
|
||||||
.map(|v| v.to_pixels() as f32)
|
.map(|v| v.to_pixels() as f32)
|
||||||
.unwrap_or_else(|| font.scale());
|
.unwrap_or_else(|| font.scale());
|
||||||
|
@ -503,7 +545,10 @@ unsafe impl<'gc> gc_arena::Collect for EditTextData<'gc> {
|
||||||
/// Static data shared between all instances of a text object.
|
/// Static data shared between all instances of a text object.
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
struct EditTextStatic(swf::EditText);
|
struct EditTextStatic {
|
||||||
|
swf: Arc<SwfMovie>,
|
||||||
|
text: swf::EditText,
|
||||||
|
}
|
||||||
|
|
||||||
unsafe impl<'gc> gc_arena::Collect for EditTextStatic {
|
unsafe impl<'gc> gc_arena::Collect for EditTextStatic {
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -301,10 +301,6 @@ impl<'gc> MovieClip<'gc> {
|
||||||
|
|
||||||
actions.into_iter()
|
actions.into_iter()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn movie(self) -> Arc<SwfMovie> {
|
|
||||||
self.0.read().movie()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'gc> TDisplayObject<'gc> for MovieClip<'gc> {
|
impl<'gc> TDisplayObject<'gc> for MovieClip<'gc> {
|
||||||
|
@ -314,6 +310,10 @@ impl<'gc> TDisplayObject<'gc> for MovieClip<'gc> {
|
||||||
self.0.read().id()
|
self.0.read().id()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn movie(&self) -> Option<Arc<SwfMovie>> {
|
||||||
|
Some(self.0.read().movie())
|
||||||
|
}
|
||||||
|
|
||||||
fn run_frame(&mut self, context: &mut UpdateContext<'_, 'gc, '_>) {
|
fn run_frame(&mut self, context: &mut UpdateContext<'_, 'gc, '_>) {
|
||||||
// Children must run first.
|
// Children must run first.
|
||||||
for mut child in self.children() {
|
for mut child in self.children() {
|
||||||
|
@ -595,9 +595,9 @@ impl<'gc> MovieClipData<'gc> {
|
||||||
place_object: &swf::PlaceObject,
|
place_object: &swf::PlaceObject,
|
||||||
copy_previous_properties: bool,
|
copy_previous_properties: bool,
|
||||||
) -> Option<DisplayObject<'gc>> {
|
) -> Option<DisplayObject<'gc>> {
|
||||||
if let Ok(mut child) =
|
if let Ok(mut child) = context
|
||||||
context
|
|
||||||
.library
|
.library
|
||||||
|
.library_for_movie_mut(self.movie())
|
||||||
.instantiate_by_id(id, context.gc_context, &context.system_prototypes)
|
.instantiate_by_id(id, context.gc_context, &context.system_prototypes)
|
||||||
{
|
{
|
||||||
// Remove previous child from children list,
|
// Remove previous child from children list,
|
||||||
|
@ -1095,6 +1095,7 @@ impl<'gc, 'a> MovieClipData<'gc> {
|
||||||
);
|
);
|
||||||
context
|
context
|
||||||
.library
|
.library
|
||||||
|
.library_for_movie_mut(self.movie())
|
||||||
.register_character(define_bits_lossless.id, Character::Bitmap(bitmap));
|
.register_character(define_bits_lossless.id, Character::Bitmap(bitmap));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1125,6 +1126,7 @@ impl<'gc, 'a> MovieClipData<'gc> {
|
||||||
let graphic = Graphic::from_swf_tag(context, &swf_shape);
|
let graphic = Graphic::from_swf_tag(context, &swf_shape);
|
||||||
context
|
context
|
||||||
.library
|
.library
|
||||||
|
.library_for_movie_mut(self.movie())
|
||||||
.register_character(swf_shape.id, Character::Graphic(graphic));
|
.register_character(swf_shape.id, Character::Graphic(graphic));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1232,10 +1234,14 @@ impl<'gc, 'a> MovieClipData<'gc> {
|
||||||
.get_mut()
|
.get_mut()
|
||||||
.take(data_len as u64)
|
.take(data_len as u64)
|
||||||
.read_to_end(&mut jpeg_data)?;
|
.read_to_end(&mut jpeg_data)?;
|
||||||
let bitmap_info =
|
let bitmap_info = context.renderer.register_bitmap_jpeg(
|
||||||
|
id,
|
||||||
|
&jpeg_data,
|
||||||
context
|
context
|
||||||
.renderer
|
.library
|
||||||
.register_bitmap_jpeg(id, &jpeg_data, context.library.jpeg_tables());
|
.library_for_movie_mut(self.movie())
|
||||||
|
.jpeg_tables(),
|
||||||
|
);
|
||||||
let bitmap = crate::display_object::Bitmap::new(
|
let bitmap = crate::display_object::Bitmap::new(
|
||||||
context,
|
context,
|
||||||
id,
|
id,
|
||||||
|
@ -1245,6 +1251,7 @@ impl<'gc, 'a> MovieClipData<'gc> {
|
||||||
);
|
);
|
||||||
context
|
context
|
||||||
.library
|
.library
|
||||||
|
.library_for_movie_mut(self.movie())
|
||||||
.register_character(id, Character::Bitmap(bitmap));
|
.register_character(id, Character::Bitmap(bitmap));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1274,6 +1281,7 @@ impl<'gc, 'a> MovieClipData<'gc> {
|
||||||
);
|
);
|
||||||
context
|
context
|
||||||
.library
|
.library
|
||||||
|
.library_for_movie_mut(self.movie())
|
||||||
.register_character(id, Character::Bitmap(bitmap));
|
.register_character(id, Character::Bitmap(bitmap));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1311,6 +1319,7 @@ impl<'gc, 'a> MovieClipData<'gc> {
|
||||||
);
|
);
|
||||||
context
|
context
|
||||||
.library
|
.library
|
||||||
|
.library_for_movie_mut(self.movie())
|
||||||
.register_character(id, Character::Bitmap(bitmap));
|
.register_character(id, Character::Bitmap(bitmap));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1349,6 +1358,7 @@ impl<'gc, 'a> MovieClipData<'gc> {
|
||||||
);
|
);
|
||||||
context
|
context
|
||||||
.library
|
.library
|
||||||
|
.library_for_movie_mut(self.movie())
|
||||||
.register_character(id, Character::Bitmap(bitmap));
|
.register_character(id, Character::Bitmap(bitmap));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1368,6 +1378,7 @@ impl<'gc, 'a> MovieClipData<'gc> {
|
||||||
);
|
);
|
||||||
context
|
context
|
||||||
.library
|
.library
|
||||||
|
.library_for_movie_mut(self.movie())
|
||||||
.register_character(swf_button.id, Character::Button(button));
|
.register_character(swf_button.id, Character::Button(button));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1387,6 +1398,7 @@ impl<'gc, 'a> MovieClipData<'gc> {
|
||||||
);
|
);
|
||||||
context
|
context
|
||||||
.library
|
.library
|
||||||
|
.library_for_movie_mut(self.movie())
|
||||||
.register_character(swf_button.id, Character::Button(button));
|
.register_character(swf_button.id, Character::Button(button));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1399,7 +1411,11 @@ impl<'gc, 'a> MovieClipData<'gc> {
|
||||||
tag_len: usize,
|
tag_len: usize,
|
||||||
) -> DecodeResult {
|
) -> DecodeResult {
|
||||||
let button_colors = reader.read_define_button_cxform(tag_len)?;
|
let button_colors = reader.read_define_button_cxform(tag_len)?;
|
||||||
if let Some(button) = context.library.get_character_by_id(button_colors.id) {
|
if let Some(button) = context
|
||||||
|
.library
|
||||||
|
.library_for_movie_mut(self.movie())
|
||||||
|
.get_character_by_id(button_colors.id)
|
||||||
|
{
|
||||||
if let Character::Button(button) = button {
|
if let Character::Button(button) = button {
|
||||||
button.set_colors(context.gc_context, &button_colors.color_transforms[..]);
|
button.set_colors(context.gc_context, &button_colors.color_transforms[..]);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1424,7 +1440,11 @@ impl<'gc, 'a> MovieClipData<'gc> {
|
||||||
reader: &mut SwfStream<&'a [u8]>,
|
reader: &mut SwfStream<&'a [u8]>,
|
||||||
) -> DecodeResult {
|
) -> DecodeResult {
|
||||||
let button_sounds = reader.read_define_button_sound()?;
|
let button_sounds = reader.read_define_button_sound()?;
|
||||||
if let Some(button) = context.library.get_character_by_id(button_sounds.id) {
|
if let Some(button) = context
|
||||||
|
.library
|
||||||
|
.library_for_movie_mut(self.movie())
|
||||||
|
.get_character_by_id(button_sounds.id)
|
||||||
|
{
|
||||||
if let Character::Button(button) = button {
|
if let Character::Button(button) = button {
|
||||||
button.set_sounds(context.gc_context, button_sounds);
|
button.set_sounds(context.gc_context, button_sounds);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1450,9 +1470,10 @@ impl<'gc, 'a> MovieClipData<'gc> {
|
||||||
reader: &mut SwfStream<&'a [u8]>,
|
reader: &mut SwfStream<&'a [u8]>,
|
||||||
) -> DecodeResult {
|
) -> DecodeResult {
|
||||||
let swf_edit_text = reader.read_define_edit_text()?;
|
let swf_edit_text = reader.read_define_edit_text()?;
|
||||||
let edit_text = EditText::from_swf_tag(context, swf_edit_text);
|
let edit_text = EditText::from_swf_tag(context, self.movie(), swf_edit_text);
|
||||||
context
|
context
|
||||||
.library
|
.library
|
||||||
|
.library_for_movie_mut(self.movie())
|
||||||
.register_character(edit_text.id(), Character::EditText(edit_text));
|
.register_character(edit_text.id(), Character::EditText(edit_text));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1491,6 +1512,7 @@ impl<'gc, 'a> MovieClipData<'gc> {
|
||||||
let font_object = Font::from_swf_tag(context.gc_context, context.renderer, &font).unwrap();
|
let font_object = Font::from_swf_tag(context.gc_context, context.renderer, &font).unwrap();
|
||||||
context
|
context
|
||||||
.library
|
.library
|
||||||
|
.library_for_movie_mut(self.movie())
|
||||||
.register_character(font.id, Character::Font(font_object));
|
.register_character(font.id, Character::Font(font_object));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1505,6 +1527,7 @@ impl<'gc, 'a> MovieClipData<'gc> {
|
||||||
let font_object = Font::from_swf_tag(context.gc_context, context.renderer, &font).unwrap();
|
let font_object = Font::from_swf_tag(context.gc_context, context.renderer, &font).unwrap();
|
||||||
context
|
context
|
||||||
.library
|
.library
|
||||||
|
.library_for_movie_mut(self.movie())
|
||||||
.register_character(font.id, Character::Font(font_object));
|
.register_character(font.id, Character::Font(font_object));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1519,6 +1542,7 @@ impl<'gc, 'a> MovieClipData<'gc> {
|
||||||
let font_object = Font::from_swf_tag(context.gc_context, context.renderer, &font).unwrap();
|
let font_object = Font::from_swf_tag(context.gc_context, context.renderer, &font).unwrap();
|
||||||
context
|
context
|
||||||
.library
|
.library
|
||||||
|
.library_for_movie_mut(self.movie())
|
||||||
.register_character(font.id, Character::Font(font_object));
|
.register_character(font.id, Character::Font(font_object));
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -1541,6 +1565,7 @@ impl<'gc, 'a> MovieClipData<'gc> {
|
||||||
let handle = context.audio.register_sound(&sound).unwrap();
|
let handle = context.audio.register_sound(&sound).unwrap();
|
||||||
context
|
context
|
||||||
.library
|
.library
|
||||||
|
.library_for_movie_mut(self.movie())
|
||||||
.register_character(sound.id, Character::Sound(handle));
|
.register_character(sound.id, Character::Sound(handle));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1573,6 +1598,7 @@ impl<'gc, 'a> MovieClipData<'gc> {
|
||||||
|
|
||||||
context
|
context
|
||||||
.library
|
.library
|
||||||
|
.library_for_movie_mut(self.movie())
|
||||||
.register_character(id, Character::MovieClip(movie_clip));
|
.register_character(id, Character::MovieClip(movie_clip));
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -1586,9 +1612,10 @@ impl<'gc, 'a> MovieClipData<'gc> {
|
||||||
version: u8,
|
version: u8,
|
||||||
) -> DecodeResult {
|
) -> DecodeResult {
|
||||||
let text = reader.read_define_text(version)?;
|
let text = reader.read_define_text(version)?;
|
||||||
let text_object = Text::from_swf_tag(context, &text);
|
let text_object = Text::from_swf_tag(context, self.movie(), &text);
|
||||||
context
|
context
|
||||||
.library
|
.library
|
||||||
|
.library_for_movie_mut(self.movie())
|
||||||
.register_character(text.id, Character::Text(text_object));
|
.register_character(text.id, Character::Text(text_object));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1601,7 +1628,10 @@ impl<'gc, 'a> MovieClipData<'gc> {
|
||||||
) -> DecodeResult {
|
) -> DecodeResult {
|
||||||
let exports = reader.read_export_assets()?;
|
let exports = reader.read_export_assets()?;
|
||||||
for export in exports {
|
for export in exports {
|
||||||
context.library.register_export(export.id, &export.name);
|
context
|
||||||
|
.library
|
||||||
|
.library_for_movie_mut(self.movie())
|
||||||
|
.register_export(export.id, &export.name);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1642,7 +1672,10 @@ impl<'gc, 'a> MovieClipData<'gc> {
|
||||||
.get_mut()
|
.get_mut()
|
||||||
.take(tag_len as u64)
|
.take(tag_len as u64)
|
||||||
.read_to_end(&mut jpeg_data)?;
|
.read_to_end(&mut jpeg_data)?;
|
||||||
context.library.set_jpeg_tables(jpeg_data);
|
context
|
||||||
|
.library
|
||||||
|
.library_for_movie_mut(self.movie())
|
||||||
|
.set_jpeg_tables(jpeg_data);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1852,7 +1885,11 @@ impl<'gc, 'a> MovieClipData<'gc> {
|
||||||
reader: &mut SwfStream<&'a [u8]>,
|
reader: &mut SwfStream<&'a [u8]>,
|
||||||
) -> DecodeResult {
|
) -> DecodeResult {
|
||||||
let start_sound = reader.read_start_sound_1()?;
|
let start_sound = reader.read_start_sound_1()?;
|
||||||
if let Some(handle) = context.library.get_sound(start_sound.id) {
|
if let Some(handle) = context
|
||||||
|
.library
|
||||||
|
.library_for_movie_mut(self.movie())
|
||||||
|
.get_sound(start_sound.id)
|
||||||
|
{
|
||||||
use swf::SoundEvent;
|
use swf::SoundEvent;
|
||||||
// The sound event type is controlled by the "Sync" setting in the Flash IDE.
|
// The sound event type is controlled by the "Sync" setting in the Flash IDE.
|
||||||
match start_sound.sound_info.event {
|
match start_sound.sound_info.event {
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
use crate::context::{RenderContext, UpdateContext};
|
use crate::context::{RenderContext, UpdateContext};
|
||||||
use crate::display_object::{DisplayObjectBase, TDisplayObject};
|
use crate::display_object::{DisplayObjectBase, TDisplayObject};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use crate::tag_utils::SwfMovie;
|
||||||
use crate::transform::Transform;
|
use crate::transform::Transform;
|
||||||
use gc_arena::{Collect, GcCell};
|
use gc_arena::{Collect, GcCell};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Collect, Copy)]
|
#[derive(Clone, Debug, Collect, Copy)]
|
||||||
#[collect(no_drop)]
|
#[collect(no_drop)]
|
||||||
|
@ -15,7 +17,11 @@ pub struct TextData<'gc> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'gc> Text<'gc> {
|
impl<'gc> Text<'gc> {
|
||||||
pub fn from_swf_tag(context: &mut UpdateContext<'_, 'gc, '_>, tag: &swf::Text) -> Self {
|
pub fn from_swf_tag(
|
||||||
|
context: &mut UpdateContext<'_, 'gc, '_>,
|
||||||
|
swf: Arc<SwfMovie>,
|
||||||
|
tag: &swf::Text,
|
||||||
|
) -> Self {
|
||||||
Text(GcCell::allocate(
|
Text(GcCell::allocate(
|
||||||
context.gc_context,
|
context.gc_context,
|
||||||
TextData {
|
TextData {
|
||||||
|
@ -23,6 +29,7 @@ impl<'gc> Text<'gc> {
|
||||||
static_data: gc_arena::Gc::allocate(
|
static_data: gc_arena::Gc::allocate(
|
||||||
context.gc_context,
|
context.gc_context,
|
||||||
TextStatic {
|
TextStatic {
|
||||||
|
swf,
|
||||||
id: tag.id,
|
id: tag.id,
|
||||||
text_transform: tag.matrix.clone().into(),
|
text_transform: tag.matrix.clone().into(),
|
||||||
text_blocks: tag.records.clone(),
|
text_blocks: tag.records.clone(),
|
||||||
|
@ -40,6 +47,10 @@ impl<'gc> TDisplayObject<'gc> for Text<'gc> {
|
||||||
self.0.read().static_data.id
|
self.0.read().static_data.id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn movie(&self) -> Option<Arc<SwfMovie>> {
|
||||||
|
Some(self.0.read().static_data.swf.clone())
|
||||||
|
}
|
||||||
|
|
||||||
fn run_frame(&mut self, _context: &mut UpdateContext) {
|
fn run_frame(&mut self, _context: &mut UpdateContext) {
|
||||||
// Noop
|
// Noop
|
||||||
}
|
}
|
||||||
|
@ -71,7 +82,12 @@ impl<'gc> TDisplayObject<'gc> for Text<'gc> {
|
||||||
color = block.color.as_ref().unwrap_or(&color).clone();
|
color = block.color.as_ref().unwrap_or(&color).clone();
|
||||||
font_id = block.font_id.unwrap_or(font_id);
|
font_id = block.font_id.unwrap_or(font_id);
|
||||||
height = block.height.map(|h| h.get() as f32).unwrap_or(height);
|
height = block.height.map(|h| h.get() as f32).unwrap_or(height);
|
||||||
if let Some(font) = context.library.get_font(font_id) {
|
if let Some(font) = context
|
||||||
|
.library
|
||||||
|
.library_for_movie(self.movie().unwrap())
|
||||||
|
.unwrap()
|
||||||
|
.get_font(font_id)
|
||||||
|
{
|
||||||
let scale = height / font.scale();
|
let scale = height / font.scale();
|
||||||
transform.matrix.a = scale;
|
transform.matrix.a = scale;
|
||||||
transform.matrix.d = scale;
|
transform.matrix.d = scale;
|
||||||
|
@ -108,6 +124,7 @@ unsafe impl<'gc> gc_arena::Collect for TextData<'gc> {
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
struct TextStatic {
|
struct TextStatic {
|
||||||
|
swf: Arc<SwfMovie>,
|
||||||
id: CharacterId,
|
id: CharacterId,
|
||||||
text_transform: Matrix,
|
text_transform: Matrix,
|
||||||
text_blocks: Vec<swf::TextRecord>,
|
text_blocks: Vec<swf::TextRecord>,
|
||||||
|
|
|
@ -5,20 +5,24 @@ use crate::character::Character;
|
||||||
use crate::display_object::TDisplayObject;
|
use crate::display_object::TDisplayObject;
|
||||||
use crate::font::Font;
|
use crate::font::Font;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use crate::tag_utils::SwfMovie;
|
||||||
use gc_arena::MutationContext;
|
use gc_arena::MutationContext;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::sync::{Arc, Weak};
|
||||||
use swf::CharacterId;
|
use swf::CharacterId;
|
||||||
|
use weak_table::PtrWeakKeyHashMap;
|
||||||
|
|
||||||
pub struct Library<'gc> {
|
/// Symbol library for a single given SWF.
|
||||||
|
pub struct MovieLibrary<'gc> {
|
||||||
characters: HashMap<CharacterId, Character<'gc>>,
|
characters: HashMap<CharacterId, Character<'gc>>,
|
||||||
export_characters: HashMap<String, Character<'gc>>,
|
export_characters: HashMap<String, Character<'gc>>,
|
||||||
jpeg_tables: Option<Vec<u8>>,
|
jpeg_tables: Option<Vec<u8>>,
|
||||||
device_font: Option<Font<'gc>>,
|
device_font: Option<Font<'gc>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'gc> Library<'gc> {
|
impl<'gc> MovieLibrary<'gc> {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Library {
|
MovieLibrary {
|
||||||
characters: HashMap::new(),
|
characters: HashMap::new(),
|
||||||
export_characters: HashMap::new(),
|
export_characters: HashMap::new(),
|
||||||
jpeg_tables: None,
|
jpeg_tables: None,
|
||||||
|
@ -181,7 +185,7 @@ impl<'gc> Library<'gc> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<'gc> gc_arena::Collect for Library<'gc> {
|
unsafe impl<'gc> gc_arena::Collect for MovieLibrary<'gc> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn trace(&self, cc: gc_arena::CollectionContext) {
|
fn trace(&self, cc: gc_arena::CollectionContext) {
|
||||||
for character in self.characters.values() {
|
for character in self.characters.values() {
|
||||||
|
@ -191,8 +195,46 @@ unsafe impl<'gc> gc_arena::Collect for Library<'gc> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Library<'_> {
|
impl Default for MovieLibrary<'_> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::new()
|
Self::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Symbol library for multiple movies.
|
||||||
|
pub struct Library<'gc> {
|
||||||
|
/// All the movie libraries.
|
||||||
|
movie_libraries: PtrWeakKeyHashMap<Weak<SwfMovie>, MovieLibrary<'gc>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl<'gc> gc_arena::Collect for Library<'gc> {
|
||||||
|
#[inline]
|
||||||
|
fn trace(&self, cc: gc_arena::CollectionContext) {
|
||||||
|
for (_, val) in self.movie_libraries.iter() {
|
||||||
|
val.trace(cc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'gc> Library<'gc> {
|
||||||
|
pub fn library_for_movie(&self, movie: Arc<SwfMovie>) -> Option<&MovieLibrary<'gc>> {
|
||||||
|
self.movie_libraries.get(&movie)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn library_for_movie_mut(&mut self, movie: Arc<SwfMovie>) -> &mut MovieLibrary<'gc> {
|
||||||
|
if !self.movie_libraries.contains_key(&movie) {
|
||||||
|
self.movie_libraries
|
||||||
|
.insert(movie.clone(), MovieLibrary::default());
|
||||||
|
};
|
||||||
|
|
||||||
|
self.movie_libraries.get_mut(&movie).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'gc> Default for Library<'gc> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
movie_libraries: PtrWeakKeyHashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -174,8 +174,11 @@ impl Player {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut library = Library::new();
|
let mut library = Library::default();
|
||||||
library.set_device_font(device_font);
|
library
|
||||||
|
.library_for_movie_mut(movie.clone())
|
||||||
|
.set_device_font(device_font);
|
||||||
|
|
||||||
GcRoot(GcCell::allocate(
|
GcRoot(GcCell::allocate(
|
||||||
gc_context,
|
gc_context,
|
||||||
GcRootData {
|
GcRootData {
|
||||||
|
@ -521,6 +524,7 @@ impl Player {
|
||||||
let morph_shape = MorphShape::new(context.gc_context, static_data);
|
let morph_shape = MorphShape::new(context.gc_context, static_data);
|
||||||
context
|
context
|
||||||
.library
|
.library
|
||||||
|
.library_for_movie_mut(root.as_movie_clip().unwrap().movie().unwrap())
|
||||||
.register_character(id, crate::character::Character::MorphShape(morph_shape));
|
.register_character(id, crate::character::Character::MorphShape(morph_shape));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue