Browse Source

avm1: MovieClip.getBytesLoaded/Total should return the clip's length

MovieClip.getBytesLoaded and getBytesTotal return the size of that
specific clip, even if it's not a loaded SWF.  The previous logic
only returned the size of the parent SWF.

If the clip is an SWF, the uncompressed size of the SWF is returned.
Otherwise, the length of the tag list inside the clip's DefineSprite
tag is returned.
pull/4257/head nightly-2021-05-05
Mike Welsh 2 months ago
parent
commit
b82391726f
  1. 28
      core/src/avm1/globals/movie_clip.rs
  2. 47
      core/src/display_object/movie_clip.rs
  3. 6
      tests/tests/swfs/avm1/get_bytes_total/output.txt
  4. BIN
      tests/tests/swfs/avm1/get_bytes_total/test.fla
  5. BIN
      tests/tests/swfs/avm1/get_bytes_total/test.swf

28
core/src/avm1/globals/movie_clip.rs

@ -824,10 +824,15 @@ fn get_bytes_loaded<'gc>(
_activation: &mut Activation<'_, 'gc, '_>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
Ok(movie_clip
.movie()
.map(|mv| (mv.header().uncompressed_length).into())
.unwrap_or(Value::Undefined))
let bytes_loaded = if movie_clip.is_swf() {
movie_clip
.movie()
.map(|mv| mv.header().uncompressed_length)
.unwrap_or_default()
} else {
movie_clip.tag_stream_len() as u32
};
Ok(bytes_loaded.into())
}
fn get_bytes_total<'gc>(
@ -835,10 +840,17 @@ fn get_bytes_total<'gc>(
_activation: &mut Activation<'_, 'gc, '_>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
Ok(movie_clip
.movie()
.map(|mv| (mv.header().uncompressed_length).into())
.unwrap_or(Value::Undefined))
// For a loaded SWF, returns the uncompressed size of the SWF.
// Otherwise, returns the size of the tag list in the clip's DefineSprite tag.
let bytes_total = if movie_clip.is_swf() {
movie_clip
.movie()
.map(|mv| mv.header().uncompressed_length)
.unwrap_or_default()
} else {
movie_clip.tag_stream_len() as u32
};
Ok(bytes_total.into())
}
fn get_instance_at_depth<'gc>(

47
core/src/display_object/movie_clip.rs

@ -185,12 +185,34 @@ impl<'gc> MovieClip<'gc> {
/// Construct a movie clip that represents an entire movie.
pub fn from_movie(gc_context: MutationContext<'gc, '_>, movie: Arc<SwfMovie>) -> Self {
Self::new_with_data(
let num_frames = movie.header().num_frames;
MovieClip(GcCell::allocate(
gc_context,
0,
movie.clone().into(),
movie.header().num_frames,
)
MovieClipData {
base: Default::default(),
static_data: Gc::allocate(
gc_context,
MovieClipStatic::with_data(0, movie.into(), num_frames),
),
tag_stream_pos: 0,
current_frame: 0,
audio_stream: None,
container: ChildContainer::new(),
object: None,
clip_actions: Vec::new(),
frame_scripts: Vec::new(),
has_button_clip_event: false,
flags: MovieClipFlags::PLAYING | MovieClipFlags::IS_SWF,
avm2_constructor: None,
drawing: Drawing::new(),
is_focusable: false,
has_focus: false,
enabled: true,
use_hand_cursor: true,
last_queued_script_frame: None,
queued_script_frame: None,
},
))
}
/// Replace the current MovieClip with a completely new SwfMovie.
@ -676,6 +698,10 @@ impl<'gc> MovieClip<'gc> {
self.0.write(mc).set_programmatically_played()
}
pub fn is_swf(&self) -> bool {
self.0.read().flags.contains(MovieClipFlags::IS_SWF)
}
pub fn next_frame(self, context: &mut UpdateContext<'_, 'gc, '_>) {
if self.current_frame() < self.total_frames() {
self.goto_frame(context, self.current_frame() + 1, true);
@ -1656,6 +1682,10 @@ impl<'gc> MovieClip<'gc> {
) {
self.0.write(context.gc_context).use_hand_cursor = use_hand_cursor;
}
pub fn tag_stream_len(&self) -> usize {
self.0.read().tag_stream_len()
}
}
impl<'gc> TDisplayObject<'gc> for MovieClip<'gc> {
@ -2117,6 +2147,7 @@ impl<'gc> MovieClipData<'gc> {
gc_context: MutationContext<'gc, '_>,
movie: Option<Arc<SwfMovie>>,
) {
let is_swf = movie.is_some();
let movie = movie.unwrap_or_else(|| Arc::new(SwfMovie::empty(self.movie().version())));
let total_frames = movie.header().num_frames;
@ -2127,6 +2158,9 @@ impl<'gc> MovieClipData<'gc> {
);
self.tag_stream_pos = 0;
self.flags = MovieClipFlags::PLAYING;
if is_swf {
self.flags |= MovieClipFlags::IS_SWF;
}
self.current_frame = 0;
self.audio_stream = None;
self.container = ChildContainer::new();
@ -3462,6 +3496,9 @@ bitflags! {
/// The AS3 `isPlaying` property is broken and yields false until you first
/// call `play` to unbreak it. This flag tracks that bug.
const PROGRAMMATICALLY_PLAYED = 1 << 2;
/// Whether this `MovieClip` is a loaded SWF.
const IS_SWF = 1 << 3;
}
}

6
tests/tests/swfs/avm1/get_bytes_total/output.txt

@ -1,2 +1,4 @@
getBytesLoaded(): 144
getBytesTotal(): 144
getBytesLoaded(): 356
getBytesTotal(): 356
clip.getBytesLoaded(): 12
clip.getBytesTotal(): 12

BIN
tests/tests/swfs/avm1/get_bytes_total/test.fla

BIN
tests/tests/swfs/avm1/get_bytes_total/test.swf

Loading…
Cancel
Save