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)",
|
||||
"swf 0.1.2",
|
||||
"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]]
|
||||
|
@ -2242,6 +2243,11 @@ dependencies = [
|
|||
"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]]
|
||||
name = "web-sys"
|
||||
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-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 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 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"
|
||||
|
|
|
@ -22,6 +22,7 @@ num_enum = "0.4.2"
|
|||
quick-xml = "0.17.2"
|
||||
downcast-rs = "1.1.1"
|
||||
url = "2.1.0"
|
||||
weak-table = "0.2.3"
|
||||
|
||||
[dependencies.jpeg-decoder]
|
||||
version = "0.1.18"
|
||||
|
|
|
@ -1645,7 +1645,7 @@ impl<'gc> Avm1<'gc> {
|
|||
let that = avm.unroot_object(slot).as_display_object().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();
|
||||
mc.preload(uc, &mut morph_shapes);
|
||||
|
@ -1653,10 +1653,12 @@ impl<'gc> Avm1<'gc> {
|
|||
// Finalize morph shapes.
|
||||
for (id, static_data) in morph_shapes {
|
||||
let morph_shape = MorphShape::new(uc.gc_context, static_data);
|
||||
uc.library.register_character(
|
||||
id,
|
||||
crate::character::Character::MorphShape(morph_shape),
|
||||
);
|
||||
uc.library
|
||||
.library_for_movie_mut(movie.clone())
|
||||
.register_character(
|
||||
id,
|
||||
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 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();
|
||||
mc.preload(uc, &mut morph_shapes);
|
||||
|
@ -1746,10 +1748,12 @@ impl<'gc> Avm1<'gc> {
|
|||
// Finalize morph shapes.
|
||||
for (id, static_data) in morph_shapes {
|
||||
let morph_shape = MorphShape::new(uc.gc_context, static_data);
|
||||
uc.library.register_character(
|
||||
id,
|
||||
crate::character::Character::MorphShape(morph_shape),
|
||||
);
|
||||
uc.library
|
||||
.library_for_movie_mut(movie.clone())
|
||||
.register_character(
|
||||
id,
|
||||
crate::character::Character::MorphShape(morph_shape),
|
||||
);
|
||||
}
|
||||
})
|
||||
}))
|
||||
|
|
|
@ -246,11 +246,15 @@ fn attach_movie<'gc>(
|
|||
if depth < 0 || depth > AVM_MAX_DEPTH {
|
||||
return Ok(Value::Undefined.into());
|
||||
}
|
||||
if let Ok(mut new_clip) = context.library.instantiate_by_export_name(
|
||||
&export_name,
|
||||
context.gc_context,
|
||||
&avm.prototypes,
|
||||
) {
|
||||
|
||||
if let Ok(mut new_clip) = context
|
||||
.library
|
||||
.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.
|
||||
new_clip.set_name(context.gc_context, &new_instance_name);
|
||||
movie_clip.add_child_from_avm(context, new_clip, depth);
|
||||
|
@ -310,6 +314,7 @@ fn create_text_field<'gc>(
|
|||
context: &mut UpdateContext<'_, 'gc, '_>,
|
||||
args: &[Value<'gc>],
|
||||
) -> Result<ReturnValue<'gc>, Error> {
|
||||
let movie = avm.base_clip().movie().unwrap();
|
||||
let instance_name = args
|
||||
.get(0)
|
||||
.cloned()
|
||||
|
@ -341,7 +346,8 @@ fn create_text_field<'gc>(
|
|||
.unwrap_or(Value::Undefined)
|
||||
.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.set_name(context.gc_context, &instance_name);
|
||||
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 {
|
||||
return Ok(Value::Undefined.into());
|
||||
}
|
||||
if let Ok(mut new_clip) =
|
||||
context
|
||||
.library
|
||||
.instantiate_by_id(movie_clip.id(), context.gc_context, &avm.prototypes)
|
||||
|
||||
if let Ok(mut new_clip) = context
|
||||
.library
|
||||
.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.
|
||||
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::{Avm1, Error, Object, SoundObject, TObject, UpdateContext, Value};
|
||||
use crate::character::Character;
|
||||
use crate::display_object::TDisplayObject;
|
||||
use gc_arena::MutationContext;
|
||||
|
||||
/// Implements `Sound`
|
||||
|
@ -167,15 +168,27 @@ fn attach_sound<'gc>(
|
|||
let name = args.get(0).unwrap_or(&Value::Undefined);
|
||||
if let Some(sound_object) = this.as_sound_object() {
|
||||
let name = name.clone().coerce_to_string(avm, context)?;
|
||||
if let Some(Character::Sound(sound)) = context.library.get_character_by_export_name(&name) {
|
||||
sound_object.set_sound(context.gc_context, Some(*sound));
|
||||
sound_object.set_duration(
|
||||
context.gc_context,
|
||||
context.audio.get_sound_duration(*sound).unwrap_or(0),
|
||||
);
|
||||
sound_object.set_position(context.gc_context, 0);
|
||||
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_duration(
|
||||
context.gc_context,
|
||||
context.audio.get_sound_duration(*sound).unwrap_or(0),
|
||||
);
|
||||
sound_object.set_position(context.gc_context, 0);
|
||||
} else {
|
||||
log::warn!("Sound.attachSound: Sound '{}' not found", name);
|
||||
}
|
||||
} else {
|
||||
log::warn!("Sound.attachSound: Sound '{}' not found", name);
|
||||
log::warn!(
|
||||
"Sound.attachSound: Cannot attach Sound '{}' without a library to reference",
|
||||
name
|
||||
);
|
||||
}
|
||||
} else {
|
||||
log::warn!("Sound.attachSound: this is not a Sound");
|
||||
|
@ -395,13 +408,23 @@ fn stop<'gc>(
|
|||
if let Some(name) = args.get(0) {
|
||||
// Usage 1: Stop all instances of a particular sound, using the name parameter.
|
||||
let name = name.clone().coerce_to_string(avm, context)?;
|
||||
if let Some(Character::Sound(sound)) =
|
||||
context.library.get_character_by_export_name(&name)
|
||||
{
|
||||
// Stop all sounds with the given name.
|
||||
context.audio.stop_sounds_with_handle(*sound);
|
||||
let movie = sound.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)
|
||||
{
|
||||
// Stop all sounds with the given name.
|
||||
context.audio.stop_sounds_with_handle(*sound);
|
||||
} else {
|
||||
log::warn!("Sound.stop: Sound '{}' not found", name);
|
||||
}
|
||||
} else {
|
||||
log::warn!("Sound.stop: Sound '{}' not found", name);
|
||||
log::warn!(
|
||||
"Sound.stop: Cannot stop Sound '{}' without a library to reference",
|
||||
name
|
||||
)
|
||||
}
|
||||
} else if let Some(_owner) = sound.owner() {
|
||||
// Usage 2: Stop all sound running within a given clip.
|
||||
|
|
|
@ -604,7 +604,7 @@ mod tests {
|
|||
b: 0,
|
||||
a: 0,
|
||||
},
|
||||
library: &mut Library::new(),
|
||||
library: &mut Library::default(),
|
||||
navigator: &mut NullNavigatorBackend::new(),
|
||||
renderer: &mut NullRenderer::new(),
|
||||
system_prototypes: avm.prototypes().clone(),
|
||||
|
|
|
@ -43,7 +43,7 @@ where
|
|||
b: 0,
|
||||
a: 0,
|
||||
},
|
||||
library: &mut Library::new(),
|
||||
library: &mut Library::default(),
|
||||
navigator: &mut NullNavigatorBackend::new(),
|
||||
renderer: &mut NullRenderer::new(),
|
||||
system_prototypes: avm.prototypes().clone(),
|
||||
|
|
|
@ -2,12 +2,14 @@ use crate::avm1::{Object, Value};
|
|||
use crate::context::{RenderContext, UpdateContext};
|
||||
use crate::player::NEWEST_PLAYER_VERSION;
|
||||
use crate::prelude::*;
|
||||
use crate::tag_utils::SwfMovie;
|
||||
use crate::transform::Transform;
|
||||
use enumset::{EnumSet, EnumSetType};
|
||||
use gc_arena::{Collect, MutationContext};
|
||||
use ruffle_macros::enum_trait_object;
|
||||
use std::cell::{Ref, RefMut};
|
||||
use std::fmt::Debug;
|
||||
use std::sync::Arc;
|
||||
|
||||
mod bitmap;
|
||||
mod button;
|
||||
|
@ -345,6 +347,10 @@ impl<'gc> DisplayObjectBase<'gc> {
|
|||
.map(|p| p.swf_version())
|
||||
.unwrap_or(NEWEST_PLAYER_VERSION)
|
||||
}
|
||||
|
||||
fn movie(&self) -> Option<Arc<SwfMovie>> {
|
||||
self.parent.and_then(|p| p.movie())
|
||||
}
|
||||
}
|
||||
|
||||
#[enum_trait_object(
|
||||
|
@ -725,7 +731,7 @@ pub trait TDisplayObject<'gc>: 'gc + Collect + Debug {
|
|||
.clip_actions
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(|a| ClipAction::from_action_and_movie(a, clip.movie()))
|
||||
.map(|a| ClipAction::from_action_and_movie(a, clip.movie().unwrap()))
|
||||
.collect(),
|
||||
);
|
||||
}
|
||||
|
@ -784,6 +790,11 @@ pub trait TDisplayObject<'gc>: 'gc + Collect + Debug {
|
|||
.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 as_ptr(&self) -> *const DisplayObjectPtr;
|
||||
|
||||
|
|
|
@ -3,10 +3,11 @@ use crate::context::{ActionType, RenderContext, UpdateContext};
|
|||
use crate::display_object::{DisplayObjectBase, TDisplayObject};
|
||||
use crate::events::{ButtonEvent, ButtonEventResult, ButtonKeyCode};
|
||||
use crate::prelude::*;
|
||||
use crate::tag_utils::SwfSlice;
|
||||
use crate::tag_utils::{SwfMovie, SwfSlice};
|
||||
use gc_arena::{Collect, GcCell, MutationContext};
|
||||
use std::collections::BTreeMap;
|
||||
use std::convert::TryFrom;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Clone, Debug, Collect, Copy)]
|
||||
#[collect(no_drop)]
|
||||
|
@ -47,6 +48,7 @@ impl<'gc> Button<'gc> {
|
|||
}
|
||||
|
||||
let static_data = ButtonStatic {
|
||||
swf: source_movie.movie.clone(),
|
||||
id: button.id,
|
||||
records: button.records.clone(),
|
||||
actions,
|
||||
|
@ -120,6 +122,10 @@ impl<'gc> TDisplayObject<'gc> for Button<'gc> {
|
|||
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(
|
||||
&mut self,
|
||||
gc_context: MutationContext<'gc, '_>,
|
||||
|
@ -223,11 +229,11 @@ impl<'gc> ButtonData<'gc> {
|
|||
self.children.clear();
|
||||
for record in &self.static_data.read().records {
|
||||
if record.states.contains(&swf_state) {
|
||||
if let Ok(mut child) = context.library.instantiate_by_id(
|
||||
record.id,
|
||||
context.gc_context,
|
||||
&context.system_prototypes,
|
||||
) {
|
||||
if let Ok(mut child) = context
|
||||
.library
|
||||
.library_for_movie_mut(self.movie())
|
||||
.instantiate_by_id(record.id, context.gc_context, &context.system_prototypes)
|
||||
{
|
||||
child.set_parent(context.gc_context, Some(self_display_object));
|
||||
child.set_matrix(context.gc_context, &record.matrix.clone().into());
|
||||
child.set_color_transform(
|
||||
|
@ -253,11 +259,14 @@ impl<'gc> ButtonData<'gc> {
|
|||
|
||||
for record in &self.static_data.read().records {
|
||||
if record.states.contains(&swf::ButtonState::HitTest) {
|
||||
match context.library.instantiate_by_id(
|
||||
record.id,
|
||||
context.gc_context,
|
||||
&context.system_prototypes,
|
||||
) {
|
||||
match context
|
||||
.library
|
||||
.library_for_movie_mut(self.static_data.read().swf.clone())
|
||||
.instantiate_by_id(
|
||||
record.id,
|
||||
context.gc_context,
|
||||
&context.system_prototypes,
|
||||
) {
|
||||
Ok(mut child) => {
|
||||
{
|
||||
child.set_matrix(context.gc_context, &record.matrix.clone().into());
|
||||
|
@ -335,7 +344,11 @@ impl<'gc> ButtonData<'gc> {
|
|||
sound: Option<&swf::ButtonSound>,
|
||||
) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -368,6 +381,10 @@ impl<'gc> ButtonData<'gc> {
|
|||
}
|
||||
handled
|
||||
}
|
||||
|
||||
fn movie(&self) -> Arc<SwfMovie> {
|
||||
self.static_data.read().swf.clone()
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<'gc> gc_arena::Collect for ButtonData<'gc> {
|
||||
|
@ -410,6 +427,7 @@ enum ButtonTracking {
|
|||
#[allow(dead_code)]
|
||||
#[derive(Clone, Debug)]
|
||||
struct ButtonStatic {
|
||||
swf: Arc<SwfMovie>,
|
||||
id: CharacterId,
|
||||
records: Vec<swf::ButtonRecord>,
|
||||
actions: Vec<ButtonAction>,
|
||||
|
|
|
@ -6,8 +6,10 @@ use crate::display_object::{DisplayObjectBase, TDisplayObject};
|
|||
use crate::font::{Glyph, TextFormat};
|
||||
use crate::library::Library;
|
||||
use crate::prelude::*;
|
||||
use crate::tag_utils::SwfMovie;
|
||||
use crate::transform::Transform;
|
||||
use gc_arena::{Collect, Gc, GcCell, MutationContext};
|
||||
use std::sync::Arc;
|
||||
|
||||
/// A dynamic text field.
|
||||
/// The text in this text field can be changed dynamically.
|
||||
|
@ -51,7 +53,11 @@ pub struct EditTextData<'gc> {
|
|||
|
||||
impl<'gc> EditText<'gc> {
|
||||
/// 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_word_wrap = swf_tag.is_word_wrap;
|
||||
|
||||
|
@ -84,7 +90,13 @@ impl<'gc> EditText<'gc> {
|
|||
base: Default::default(),
|
||||
text,
|
||||
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_word_wrap,
|
||||
object: None,
|
||||
|
@ -96,6 +108,7 @@ impl<'gc> EditText<'gc> {
|
|||
/// Create a new, dynamic `EditText`.
|
||||
pub fn new(
|
||||
context: &mut UpdateContext<'_, 'gc, '_>,
|
||||
swf_movie: Arc<SwfMovie>,
|
||||
x: f64,
|
||||
y: f64,
|
||||
width: f64,
|
||||
|
@ -140,7 +153,7 @@ impl<'gc> EditText<'gc> {
|
|||
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
|
||||
|
@ -191,16 +204,20 @@ impl<'gc> EditText<'gc> {
|
|||
/// `DisplayObject`.
|
||||
pub fn text_transform(self) -> Transform {
|
||||
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
|
||||
// of static data, because they can be altered via ActionScript.
|
||||
let color = static_data.color.as_ref().unwrap_or_else(|| &swf::Color {
|
||||
r: 0,
|
||||
g: 0,
|
||||
b: 0,
|
||||
a: 255,
|
||||
});
|
||||
let color = static_data
|
||||
.text
|
||||
.color
|
||||
.as_ref()
|
||||
.unwrap_or_else(|| &swf::Color {
|
||||
r: 0,
|
||||
g: 0,
|
||||
b: 0,
|
||||
a: 255,
|
||||
});
|
||||
|
||||
let mut transform: Transform = Default::default();
|
||||
transform.color_transform.r_mult = f32::from(color.r) / 255.0;
|
||||
|
@ -208,7 +225,7 @@ impl<'gc> EditText<'gc> {
|
|||
transform.color_transform.b_mult = f32::from(color.b) / 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.indent.get() as f32;
|
||||
transform.matrix.ty -= layout.leading.get() as f32;
|
||||
|
@ -224,11 +241,11 @@ impl<'gc> EditText<'gc> {
|
|||
/// and returns the adjusted transform.
|
||||
pub fn newline(self, height: f32, mut transform: Transform) -> Transform {
|
||||
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.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.indent.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 {
|
||||
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;
|
||||
|
||||
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.indent.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.
|
||||
fn line_breaks(self, library: &Library<'gc>) -> Vec<usize> {
|
||||
let edit_text = self.0.read();
|
||||
let static_data = &edit_text.static_data.0;
|
||||
let font_id = static_data.font_id.unwrap_or(0);
|
||||
let static_data = &edit_text.static_data;
|
||||
let font_id = static_data.text.font_id.unwrap_or(0);
|
||||
|
||||
if edit_text.is_multiline {
|
||||
if let Some(font) = library
|
||||
.library_for_movie(self.movie().unwrap())
|
||||
.unwrap()
|
||||
.get_font(font_id)
|
||||
.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 break_base = 0;
|
||||
let height = static_data
|
||||
.text
|
||||
.height
|
||||
.map(|v| v.to_pixels() as f32)
|
||||
.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 edit_text = self.0.read();
|
||||
let static_data = &edit_text.static_data.0;
|
||||
let font_id = static_data.font_id.unwrap_or(0);
|
||||
let static_data = &edit_text.static_data;
|
||||
let font_id = static_data.text.font_id.unwrap_or(0);
|
||||
|
||||
let mut size: (f32, f32) = (0.0, 0.0);
|
||||
|
||||
if let Some(font) = context
|
||||
.library
|
||||
.library_for_movie(self.movie().unwrap())
|
||||
.unwrap()
|
||||
.get_font(font_id)
|
||||
.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 chunks = vec![];
|
||||
|
@ -364,6 +397,7 @@ impl<'gc> EditText<'gc> {
|
|||
chunks.push(&edit_text.text[start..]);
|
||||
|
||||
let height = static_data
|
||||
.text
|
||||
.height
|
||||
.map(|v| v.to_pixels() as f32)
|
||||
.unwrap_or_else(|| font.scale());
|
||||
|
@ -372,7 +406,7 @@ impl<'gc> EditText<'gc> {
|
|||
let chunk_size = font.measure(chunk, height);
|
||||
|
||||
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 += chunk_size.1;
|
||||
|
@ -387,7 +421,11 @@ impl<'gc> TDisplayObject<'gc> for EditText<'gc> {
|
|||
impl_display_object!(base);
|
||||
|
||||
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) {
|
||||
|
@ -424,7 +462,7 @@ impl<'gc> TDisplayObject<'gc> for EditText<'gc> {
|
|||
}
|
||||
|
||||
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>) {
|
||||
|
@ -433,20 +471,24 @@ impl<'gc> TDisplayObject<'gc> for EditText<'gc> {
|
|||
let mut text_transform = self.text_transform();
|
||||
|
||||
let edit_text = self.0.read();
|
||||
let static_data = &edit_text.static_data.0;
|
||||
let font_id = static_data.font_id.unwrap_or(0);
|
||||
let static_data = &edit_text.static_data;
|
||||
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.
|
||||
// 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
|
||||
// it the same as any other SWF outline text.
|
||||
if let Some(font) = context
|
||||
let library = context
|
||||
.library
|
||||
.library_for_movie(edit_text.static_data.swf.clone())
|
||||
.unwrap();
|
||||
if let Some(font) = library
|
||||
.get_font(font_id)
|
||||
.filter(|font| font.has_glyphs())
|
||||
.or_else(|| context.library.device_font())
|
||||
.or_else(|| library.device_font())
|
||||
{
|
||||
let height = static_data
|
||||
.text
|
||||
.height
|
||||
.map(|v| v.to_pixels() as f32)
|
||||
.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.
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Clone)]
|
||||
struct EditTextStatic(swf::EditText);
|
||||
struct EditTextStatic {
|
||||
swf: Arc<SwfMovie>,
|
||||
text: swf::EditText,
|
||||
}
|
||||
|
||||
unsafe impl<'gc> gc_arena::Collect for EditTextStatic {
|
||||
#[inline]
|
||||
|
|
|
@ -301,10 +301,6 @@ impl<'gc> MovieClip<'gc> {
|
|||
|
||||
actions.into_iter()
|
||||
}
|
||||
|
||||
pub fn movie(self) -> Arc<SwfMovie> {
|
||||
self.0.read().movie()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'gc> TDisplayObject<'gc> for MovieClip<'gc> {
|
||||
|
@ -314,6 +310,10 @@ impl<'gc> TDisplayObject<'gc> for MovieClip<'gc> {
|
|||
self.0.read().id()
|
||||
}
|
||||
|
||||
fn movie(&self) -> Option<Arc<SwfMovie>> {
|
||||
Some(self.0.read().movie())
|
||||
}
|
||||
|
||||
fn run_frame(&mut self, context: &mut UpdateContext<'_, 'gc, '_>) {
|
||||
// Children must run first.
|
||||
for mut child in self.children() {
|
||||
|
@ -595,10 +595,10 @@ impl<'gc> MovieClipData<'gc> {
|
|||
place_object: &swf::PlaceObject,
|
||||
copy_previous_properties: bool,
|
||||
) -> Option<DisplayObject<'gc>> {
|
||||
if let Ok(mut child) =
|
||||
context
|
||||
.library
|
||||
.instantiate_by_id(id, context.gc_context, &context.system_prototypes)
|
||||
if let Ok(mut child) = context
|
||||
.library
|
||||
.library_for_movie_mut(self.movie())
|
||||
.instantiate_by_id(id, context.gc_context, &context.system_prototypes)
|
||||
{
|
||||
// Remove previous child from children list,
|
||||
// and add new childonto front of the list.
|
||||
|
@ -1095,6 +1095,7 @@ impl<'gc, 'a> MovieClipData<'gc> {
|
|||
);
|
||||
context
|
||||
.library
|
||||
.library_for_movie_mut(self.movie())
|
||||
.register_character(define_bits_lossless.id, Character::Bitmap(bitmap));
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1125,6 +1126,7 @@ impl<'gc, 'a> MovieClipData<'gc> {
|
|||
let graphic = Graphic::from_swf_tag(context, &swf_shape);
|
||||
context
|
||||
.library
|
||||
.library_for_movie_mut(self.movie())
|
||||
.register_character(swf_shape.id, Character::Graphic(graphic));
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1232,10 +1234,14 @@ impl<'gc, 'a> MovieClipData<'gc> {
|
|||
.get_mut()
|
||||
.take(data_len as u64)
|
||||
.read_to_end(&mut jpeg_data)?;
|
||||
let bitmap_info =
|
||||
let bitmap_info = context.renderer.register_bitmap_jpeg(
|
||||
id,
|
||||
&jpeg_data,
|
||||
context
|
||||
.renderer
|
||||
.register_bitmap_jpeg(id, &jpeg_data, context.library.jpeg_tables());
|
||||
.library
|
||||
.library_for_movie_mut(self.movie())
|
||||
.jpeg_tables(),
|
||||
);
|
||||
let bitmap = crate::display_object::Bitmap::new(
|
||||
context,
|
||||
id,
|
||||
|
@ -1245,6 +1251,7 @@ impl<'gc, 'a> MovieClipData<'gc> {
|
|||
);
|
||||
context
|
||||
.library
|
||||
.library_for_movie_mut(self.movie())
|
||||
.register_character(id, Character::Bitmap(bitmap));
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1274,6 +1281,7 @@ impl<'gc, 'a> MovieClipData<'gc> {
|
|||
);
|
||||
context
|
||||
.library
|
||||
.library_for_movie_mut(self.movie())
|
||||
.register_character(id, Character::Bitmap(bitmap));
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1311,6 +1319,7 @@ impl<'gc, 'a> MovieClipData<'gc> {
|
|||
);
|
||||
context
|
||||
.library
|
||||
.library_for_movie_mut(self.movie())
|
||||
.register_character(id, Character::Bitmap(bitmap));
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1349,6 +1358,7 @@ impl<'gc, 'a> MovieClipData<'gc> {
|
|||
);
|
||||
context
|
||||
.library
|
||||
.library_for_movie_mut(self.movie())
|
||||
.register_character(id, Character::Bitmap(bitmap));
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1368,6 +1378,7 @@ impl<'gc, 'a> MovieClipData<'gc> {
|
|||
);
|
||||
context
|
||||
.library
|
||||
.library_for_movie_mut(self.movie())
|
||||
.register_character(swf_button.id, Character::Button(button));
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1387,6 +1398,7 @@ impl<'gc, 'a> MovieClipData<'gc> {
|
|||
);
|
||||
context
|
||||
.library
|
||||
.library_for_movie_mut(self.movie())
|
||||
.register_character(swf_button.id, Character::Button(button));
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1399,7 +1411,11 @@ impl<'gc, 'a> MovieClipData<'gc> {
|
|||
tag_len: usize,
|
||||
) -> DecodeResult {
|
||||
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 {
|
||||
button.set_colors(context.gc_context, &button_colors.color_transforms[..]);
|
||||
} else {
|
||||
|
@ -1424,7 +1440,11 @@ impl<'gc, 'a> MovieClipData<'gc> {
|
|||
reader: &mut SwfStream<&'a [u8]>,
|
||||
) -> DecodeResult {
|
||||
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 {
|
||||
button.set_sounds(context.gc_context, button_sounds);
|
||||
} else {
|
||||
|
@ -1450,9 +1470,10 @@ impl<'gc, 'a> MovieClipData<'gc> {
|
|||
reader: &mut SwfStream<&'a [u8]>,
|
||||
) -> DecodeResult {
|
||||
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
|
||||
.library
|
||||
.library_for_movie_mut(self.movie())
|
||||
.register_character(edit_text.id(), Character::EditText(edit_text));
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1491,6 +1512,7 @@ impl<'gc, 'a> MovieClipData<'gc> {
|
|||
let font_object = Font::from_swf_tag(context.gc_context, context.renderer, &font).unwrap();
|
||||
context
|
||||
.library
|
||||
.library_for_movie_mut(self.movie())
|
||||
.register_character(font.id, Character::Font(font_object));
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1505,6 +1527,7 @@ impl<'gc, 'a> MovieClipData<'gc> {
|
|||
let font_object = Font::from_swf_tag(context.gc_context, context.renderer, &font).unwrap();
|
||||
context
|
||||
.library
|
||||
.library_for_movie_mut(self.movie())
|
||||
.register_character(font.id, Character::Font(font_object));
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1519,6 +1542,7 @@ impl<'gc, 'a> MovieClipData<'gc> {
|
|||
let font_object = Font::from_swf_tag(context.gc_context, context.renderer, &font).unwrap();
|
||||
context
|
||||
.library
|
||||
.library_for_movie_mut(self.movie())
|
||||
.register_character(font.id, Character::Font(font_object));
|
||||
|
||||
Ok(())
|
||||
|
@ -1541,6 +1565,7 @@ impl<'gc, 'a> MovieClipData<'gc> {
|
|||
let handle = context.audio.register_sound(&sound).unwrap();
|
||||
context
|
||||
.library
|
||||
.library_for_movie_mut(self.movie())
|
||||
.register_character(sound.id, Character::Sound(handle));
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1573,6 +1598,7 @@ impl<'gc, 'a> MovieClipData<'gc> {
|
|||
|
||||
context
|
||||
.library
|
||||
.library_for_movie_mut(self.movie())
|
||||
.register_character(id, Character::MovieClip(movie_clip));
|
||||
|
||||
Ok(())
|
||||
|
@ -1586,9 +1612,10 @@ impl<'gc, 'a> MovieClipData<'gc> {
|
|||
version: u8,
|
||||
) -> DecodeResult {
|
||||
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
|
||||
.library
|
||||
.library_for_movie_mut(self.movie())
|
||||
.register_character(text.id, Character::Text(text_object));
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1601,7 +1628,10 @@ impl<'gc, 'a> MovieClipData<'gc> {
|
|||
) -> DecodeResult {
|
||||
let exports = reader.read_export_assets()?;
|
||||
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(())
|
||||
}
|
||||
|
@ -1642,7 +1672,10 @@ impl<'gc, 'a> MovieClipData<'gc> {
|
|||
.get_mut()
|
||||
.take(tag_len as u64)
|
||||
.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(())
|
||||
}
|
||||
|
||||
|
@ -1852,7 +1885,11 @@ impl<'gc, 'a> MovieClipData<'gc> {
|
|||
reader: &mut SwfStream<&'a [u8]>,
|
||||
) -> DecodeResult {
|
||||
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;
|
||||
// The sound event type is controlled by the "Sync" setting in the Flash IDE.
|
||||
match start_sound.sound_info.event {
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
use crate::context::{RenderContext, UpdateContext};
|
||||
use crate::display_object::{DisplayObjectBase, TDisplayObject};
|
||||
use crate::prelude::*;
|
||||
use crate::tag_utils::SwfMovie;
|
||||
use crate::transform::Transform;
|
||||
use gc_arena::{Collect, GcCell};
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Clone, Debug, Collect, Copy)]
|
||||
#[collect(no_drop)]
|
||||
|
@ -15,7 +17,11 @@ pub struct TextData<'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(
|
||||
context.gc_context,
|
||||
TextData {
|
||||
|
@ -23,6 +29,7 @@ impl<'gc> Text<'gc> {
|
|||
static_data: gc_arena::Gc::allocate(
|
||||
context.gc_context,
|
||||
TextStatic {
|
||||
swf,
|
||||
id: tag.id,
|
||||
text_transform: tag.matrix.clone().into(),
|
||||
text_blocks: tag.records.clone(),
|
||||
|
@ -40,6 +47,10 @@ impl<'gc> TDisplayObject<'gc> for Text<'gc> {
|
|||
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) {
|
||||
// Noop
|
||||
}
|
||||
|
@ -71,7 +82,12 @@ impl<'gc> TDisplayObject<'gc> for Text<'gc> {
|
|||
color = block.color.as_ref().unwrap_or(&color).clone();
|
||||
font_id = block.font_id.unwrap_or(font_id);
|
||||
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();
|
||||
transform.matrix.a = scale;
|
||||
transform.matrix.d = scale;
|
||||
|
@ -108,6 +124,7 @@ unsafe impl<'gc> gc_arena::Collect for TextData<'gc> {
|
|||
#[allow(dead_code)]
|
||||
#[derive(Debug, Clone)]
|
||||
struct TextStatic {
|
||||
swf: Arc<SwfMovie>,
|
||||
id: CharacterId,
|
||||
text_transform: Matrix,
|
||||
text_blocks: Vec<swf::TextRecord>,
|
||||
|
|
|
@ -5,20 +5,24 @@ use crate::character::Character;
|
|||
use crate::display_object::TDisplayObject;
|
||||
use crate::font::Font;
|
||||
use crate::prelude::*;
|
||||
use crate::tag_utils::SwfMovie;
|
||||
use gc_arena::MutationContext;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::{Arc, Weak};
|
||||
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>>,
|
||||
export_characters: HashMap<String, Character<'gc>>,
|
||||
jpeg_tables: Option<Vec<u8>>,
|
||||
device_font: Option<Font<'gc>>,
|
||||
}
|
||||
|
||||
impl<'gc> Library<'gc> {
|
||||
impl<'gc> MovieLibrary<'gc> {
|
||||
pub fn new() -> Self {
|
||||
Library {
|
||||
MovieLibrary {
|
||||
characters: HashMap::new(),
|
||||
export_characters: HashMap::new(),
|
||||
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]
|
||||
fn trace(&self, cc: gc_arena::CollectionContext) {
|
||||
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 {
|
||||
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();
|
||||
library.set_device_font(device_font);
|
||||
let mut library = Library::default();
|
||||
library
|
||||
.library_for_movie_mut(movie.clone())
|
||||
.set_device_font(device_font);
|
||||
|
||||
GcRoot(GcCell::allocate(
|
||||
gc_context,
|
||||
GcRootData {
|
||||
|
@ -521,6 +524,7 @@ impl Player {
|
|||
let morph_shape = MorphShape::new(context.gc_context, static_data);
|
||||
context
|
||||
.library
|
||||
.library_for_movie_mut(root.as_movie_clip().unwrap().movie().unwrap())
|
||||
.register_character(id, crate::character::Character::MorphShape(morph_shape));
|
||||
}
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue