From e8b6d1a52a25902ca6e81b80f23520644b9d459b Mon Sep 17 00:00:00 2001 From: David Wendt Date: Fri, 26 Feb 2021 21:09:27 -0500 Subject: [PATCH] core: Migrate clip drawing commands to exposing the internal `Drawing` to mutation --- core/src/avm1/globals/movie_clip.rs | 78 +++-- .../avm2/globals/flash/display/graphics.rs | 285 ++++++++---------- core/src/display_object.rs | 4 + core/src/display_object/movie_clip.rs | 37 +-- core/src/drawing.rs | 6 + 5 files changed, 197 insertions(+), 213 deletions(-) diff --git a/core/src/avm1/globals/movie_clip.rs b/core/src/avm1/globals/movie_clip.rs index efddc5a0b..c63dd27e9 100644 --- a/core/src/avm1/globals/movie_clip.rs +++ b/core/src/avm1/globals/movie_clip.rs @@ -336,9 +336,10 @@ fn line_style<'gc>( Some("bevel") => LineJoinStyle::Bevel, _ => LineJoinStyle::Round, }; - movie_clip.set_line_style( - &mut activation.context, - Some(LineStyle { + movie_clip + .as_drawing(activation.context.gc_context) + .unwrap() + .set_line_style(Some(LineStyle { width, color, start_cap: cap_style, @@ -349,10 +350,12 @@ fn line_style<'gc>( allow_scale_y, is_pixel_hinted, allow_close: false, - }), - ); + })); } else { - movie_clip.set_line_style(&mut activation.context, None); + movie_clip + .as_drawing(activation.context.gc_context) + .unwrap() + .set_line_style(None); } Ok(Value::Undefined) } @@ -371,12 +374,15 @@ fn begin_fill<'gc>( } as f32 / 100.0 * 255.0; - movie_clip.set_fill_style( - &mut activation.context, - Some(FillStyle::Color(Color::from_rgb(rgb, alpha as u8))), - ); + movie_clip + .as_drawing(activation.context.gc_context) + .unwrap() + .set_fill_style(Some(FillStyle::Color(Color::from_rgb(rgb, alpha as u8)))); } else { - movie_clip.set_fill_style(&mut activation.context, None); + movie_clip + .as_drawing(activation.context.gc_context) + .unwrap() + .set_fill_style(None); } Ok(Value::Undefined) } @@ -461,9 +467,15 @@ fn begin_gradient_fill<'gc>( return Ok(Value::Undefined); } }; - movie_clip.set_fill_style(&mut activation.context, Some(style)); + movie_clip + .as_drawing(activation.context.gc_context) + .unwrap() + .set_fill_style(Some(style)); } else { - movie_clip.set_fill_style(&mut activation.context, None); + movie_clip + .as_drawing(activation.context.gc_context) + .unwrap() + .set_fill_style(None); } Ok(Value::Undefined) } @@ -476,13 +488,13 @@ fn move_to<'gc>( if let (Some(x), Some(y)) = (args.get(0), args.get(1)) { let x = x.coerce_to_f64(activation)?; let y = y.coerce_to_f64(activation)?; - movie_clip.draw_command( - &mut activation.context, - DrawCommand::MoveTo { + movie_clip + .as_drawing(activation.context.gc_context) + .unwrap() + .draw_command(DrawCommand::MoveTo { x: Twips::from_pixels(x), y: Twips::from_pixels(y), - }, - ); + }); } Ok(Value::Undefined) } @@ -495,13 +507,13 @@ fn line_to<'gc>( if let (Some(x), Some(y)) = (args.get(0), args.get(1)) { let x = x.coerce_to_f64(activation)?; let y = y.coerce_to_f64(activation)?; - movie_clip.draw_command( - &mut activation.context, - DrawCommand::LineTo { + movie_clip + .as_drawing(activation.context.gc_context) + .unwrap() + .draw_command(DrawCommand::LineTo { x: Twips::from_pixels(x), y: Twips::from_pixels(y), - }, - ); + }); } Ok(Value::Undefined) } @@ -518,15 +530,15 @@ fn curve_to<'gc>( let y1 = y1.coerce_to_f64(activation)?; let x2 = x2.coerce_to_f64(activation)?; let y2 = y2.coerce_to_f64(activation)?; - movie_clip.draw_command( - &mut activation.context, - DrawCommand::CurveTo { + movie_clip + .as_drawing(activation.context.gc_context) + .unwrap() + .draw_command(DrawCommand::CurveTo { x1: Twips::from_pixels(x1), y1: Twips::from_pixels(y1), x2: Twips::from_pixels(x2), y2: Twips::from_pixels(y2), - }, - ); + }); } Ok(Value::Undefined) } @@ -536,7 +548,10 @@ fn end_fill<'gc>( activation: &mut Activation<'_, 'gc, '_>, _args: &[Value<'gc>], ) -> Result, Error<'gc>> { - movie_clip.set_fill_style(&mut activation.context, None); + movie_clip + .as_drawing(activation.context.gc_context) + .unwrap() + .set_fill_style(None); Ok(Value::Undefined) } @@ -545,7 +560,10 @@ fn clear<'gc>( activation: &mut Activation<'_, 'gc, '_>, _args: &[Value<'gc>], ) -> Result, Error<'gc>> { - movie_clip.clear(&mut activation.context); + movie_clip + .as_drawing(activation.context.gc_context) + .unwrap() + .clear(); Ok(Value::Undefined) } diff --git a/core/src/avm2/globals/flash/display/graphics.rs b/core/src/avm2/globals/flash/display/graphics.rs index 76690e455..808ed9a99 100644 --- a/core/src/avm2/globals/flash/display/graphics.rs +++ b/core/src/avm2/globals/flash/display/graphics.rs @@ -47,25 +47,20 @@ pub fn begin_fill<'gc>( this: Option>, args: &[Value<'gc>], ) -> Result, Error> { - if let Some(this) = this { - if let Some(dobj) = this.as_display_object() { - if let Some(mc) = dobj.as_movie_clip() { - let color = args - .get(0) - .cloned() - .unwrap_or(Value::Undefined) - .coerce_to_u32(activation)?; - let alpha = args - .get(1) - .cloned() - .unwrap_or_else(|| 1.0.into()) - .coerce_to_number(activation)?; + if let Some(this) = this.and_then(|t| t.as_display_object()) { + let color = args + .get(0) + .cloned() + .unwrap_or(Value::Undefined) + .coerce_to_u32(activation)?; + let alpha = args + .get(1) + .cloned() + .unwrap_or_else(|| 1.0.into()) + .coerce_to_number(activation)?; - mc.set_fill_style( - &mut activation.context, - Some(FillStyle::Color(color_from_args(color, alpha))), - ); - } + if let Some(mut draw) = this.as_drawing(activation.context.gc_context) { + draw.set_fill_style(Some(FillStyle::Color(color_from_args(color, alpha)))); } } @@ -78,11 +73,9 @@ pub fn clear<'gc>( this: Option>, _args: &[Value<'gc>], ) -> Result, Error> { - if let Some(this) = this { - if let Some(dobj) = this.as_display_object() { - if let Some(mc) = dobj.as_movie_clip() { - mc.clear(&mut activation.context) - } + if let Some(this) = this.and_then(|t| t.as_display_object()) { + if let Some(mut draw) = this.as_drawing(activation.context.gc_context) { + draw.clear() } } @@ -95,39 +88,34 @@ pub fn curve_to<'gc>( this: Option>, args: &[Value<'gc>], ) -> Result, Error> { - if let Some(this) = this { - if let Some(dobj) = this.as_display_object() { - if let Some(mc) = dobj.as_movie_clip() { - let x1 = Twips::from_pixels( - args.get(0) - .cloned() - .unwrap_or(Value::Undefined) - .coerce_to_number(activation)?, - ); - let y1 = Twips::from_pixels( - args.get(1) - .cloned() - .unwrap_or(Value::Undefined) - .coerce_to_number(activation)?, - ); - let x2 = Twips::from_pixels( - args.get(2) - .cloned() - .unwrap_or(Value::Undefined) - .coerce_to_number(activation)?, - ); - let y2 = Twips::from_pixels( - args.get(3) - .cloned() - .unwrap_or(Value::Undefined) - .coerce_to_number(activation)?, - ); + if let Some(this) = this.and_then(|t| t.as_display_object()) { + let x1 = Twips::from_pixels( + args.get(0) + .cloned() + .unwrap_or(Value::Undefined) + .coerce_to_number(activation)?, + ); + let y1 = Twips::from_pixels( + args.get(1) + .cloned() + .unwrap_or(Value::Undefined) + .coerce_to_number(activation)?, + ); + let x2 = Twips::from_pixels( + args.get(2) + .cloned() + .unwrap_or(Value::Undefined) + .coerce_to_number(activation)?, + ); + let y2 = Twips::from_pixels( + args.get(3) + .cloned() + .unwrap_or(Value::Undefined) + .coerce_to_number(activation)?, + ); - mc.draw_command( - &mut activation.context, - DrawCommand::CurveTo { x1, y1, x2, y2 }, - ); - } + if let Some(mut draw) = this.as_drawing(activation.context.gc_context) { + draw.draw_command(DrawCommand::CurveTo { x1, y1, x2, y2 }); } } @@ -140,11 +128,9 @@ pub fn end_fill<'gc>( this: Option>, _args: &[Value<'gc>], ) -> Result, Error> { - if let Some(this) = this { - if let Some(dobj) = this.as_display_object() { - if let Some(mc) = dobj.as_movie_clip() { - mc.set_fill_style(&mut activation.context, None); - } + if let Some(this) = this.and_then(|t| t.as_display_object()) { + if let Some(mut draw) = this.as_drawing(activation.context.gc_context) { + draw.set_fill_style(None); } } @@ -200,67 +186,66 @@ pub fn line_style<'gc>( this: Option>, args: &[Value<'gc>], ) -> Result, Error> { - if let Some(this) = this { - if let Some(dobj) = this.as_display_object() { - if let Some(mc) = dobj.as_movie_clip() { - let thickness = args - .get(0) - .cloned() - .unwrap_or_else(|| f64::NAN.into()) - .coerce_to_number(activation)?; - if thickness.is_nan() { - mc.set_line_style(&mut activation.context, None); - } else { - let color = args - .get(1) - .cloned() - .unwrap_or_else(|| 0.into()) - .coerce_to_u32(activation)?; - let alpha = args - .get(2) - .cloned() - .unwrap_or_else(|| 1.0.into()) - .coerce_to_number(activation)?; - let is_pixel_hinted = args - .get(3) - .cloned() - .unwrap_or_else(|| false.into()) - .coerce_to_boolean(); - let scale_mode = args - .get(4) - .cloned() - .unwrap_or_else(|| "normal".into()) - .coerce_to_string(activation)?; - let caps = - caps_to_cap_style(activation, args.get(5).cloned().unwrap_or(Value::Null))?; - let joints = args.get(6).cloned().unwrap_or(Value::Null); - let miter_limit = args - .get(7) - .cloned() - .unwrap_or_else(|| 3.0.into()) - .coerce_to_number(activation)?; + if let Some(this) = this.and_then(|t| t.as_display_object()) { + let thickness = args + .get(0) + .cloned() + .unwrap_or_else(|| f64::NAN.into()) + .coerce_to_number(activation)?; - let width = Twips::from_pixels(thickness.min(255.0).max(0.0)); - let color = color_from_args(color, alpha); - let join_style = joints_to_join_style(activation, joints, miter_limit as f32)?; - let (allow_scale_x, allow_scale_y) = - scale_mode_to_allow_scale_bits(&scale_mode)?; + if thickness.is_nan() { + if let Some(mut draw) = this.as_drawing(activation.context.gc_context) { + draw.set_line_style(None); + } + } else { + let color = args + .get(1) + .cloned() + .unwrap_or_else(|| 0.into()) + .coerce_to_u32(activation)?; + let alpha = args + .get(2) + .cloned() + .unwrap_or_else(|| 1.0.into()) + .coerce_to_number(activation)?; + let is_pixel_hinted = args + .get(3) + .cloned() + .unwrap_or_else(|| false.into()) + .coerce_to_boolean(); + let scale_mode = args + .get(4) + .cloned() + .unwrap_or_else(|| "normal".into()) + .coerce_to_string(activation)?; + let caps = caps_to_cap_style(activation, args.get(5).cloned().unwrap_or(Value::Null))?; + let joints = args.get(6).cloned().unwrap_or(Value::Null); + let miter_limit = args + .get(7) + .cloned() + .unwrap_or_else(|| 3.0.into()) + .coerce_to_number(activation)?; - let line_style = LineStyle { - width, - color, - start_cap: caps, - end_cap: caps, - join_style, - fill_style: None, - allow_scale_x, - allow_scale_y, - is_pixel_hinted, - allow_close: true, - }; + let width = Twips::from_pixels(thickness.min(255.0).max(0.0)); + let color = color_from_args(color, alpha); + let join_style = joints_to_join_style(activation, joints, miter_limit as f32)?; + let (allow_scale_x, allow_scale_y) = scale_mode_to_allow_scale_bits(&scale_mode)?; - mc.set_line_style(&mut activation.context, Some(line_style)); - } + let line_style = LineStyle { + width, + color, + start_cap: caps, + end_cap: caps, + join_style, + fill_style: None, + allow_scale_x, + allow_scale_y, + is_pixel_hinted, + allow_close: true, + }; + + if let Some(mut draw) = this.as_drawing(activation.context.gc_context) { + draw.set_line_style(Some(line_style)); } } } @@ -274,24 +259,22 @@ pub fn line_to<'gc>( this: Option>, args: &[Value<'gc>], ) -> Result, Error> { - if let Some(this) = this { - if let Some(dobj) = this.as_display_object() { - if let Some(mc) = dobj.as_movie_clip() { - let x = Twips::from_pixels( - args.get(0) - .cloned() - .unwrap_or(Value::Undefined) - .coerce_to_number(activation)?, - ); - let y = Twips::from_pixels( - args.get(1) - .cloned() - .unwrap_or(Value::Undefined) - .coerce_to_number(activation)?, - ); + if let Some(this) = this.and_then(|t| t.as_display_object()) { + let x = Twips::from_pixels( + args.get(0) + .cloned() + .unwrap_or(Value::Undefined) + .coerce_to_number(activation)?, + ); + let y = Twips::from_pixels( + args.get(1) + .cloned() + .unwrap_or(Value::Undefined) + .coerce_to_number(activation)?, + ); - mc.draw_command(&mut activation.context, DrawCommand::LineTo { x, y }); - } + if let Some(mut draw) = this.as_drawing(activation.context.gc_context) { + draw.draw_command(DrawCommand::LineTo { x, y }); } } @@ -304,24 +287,22 @@ pub fn move_to<'gc>( this: Option>, args: &[Value<'gc>], ) -> Result, Error> { - if let Some(this) = this { - if let Some(dobj) = this.as_display_object() { - if let Some(mc) = dobj.as_movie_clip() { - let x = Twips::from_pixels( - args.get(0) - .cloned() - .unwrap_or(Value::Undefined) - .coerce_to_number(activation)?, - ); - let y = Twips::from_pixels( - args.get(1) - .cloned() - .unwrap_or(Value::Undefined) - .coerce_to_number(activation)?, - ); + if let Some(this) = this.and_then(|t| t.as_display_object()) { + let x = Twips::from_pixels( + args.get(0) + .cloned() + .unwrap_or(Value::Undefined) + .coerce_to_number(activation)?, + ); + let y = Twips::from_pixels( + args.get(1) + .cloned() + .unwrap_or(Value::Undefined) + .coerce_to_number(activation)?, + ); - mc.draw_command(&mut activation.context, DrawCommand::MoveTo { x, y }); - } + if let Some(mut draw) = this.as_drawing(activation.context.gc_context) { + draw.draw_command(DrawCommand::MoveTo { x, y }); } } diff --git a/core/src/display_object.rs b/core/src/display_object.rs index e95db4969..5369f26c5 100644 --- a/core/src/display_object.rs +++ b/core/src/display_object.rs @@ -3,6 +3,7 @@ use crate::avm1::{ }; use crate::avm2::{Avm2, Event as Avm2Event, TObject as Avm2TObject, Value as Avm2Value}; use crate::context::{RenderContext, UpdateContext}; +use crate::drawing::Drawing; use crate::player::NEWEST_PLAYER_VERSION; use crate::prelude::*; use crate::tag_utils::SwfMovie; @@ -991,6 +992,9 @@ pub trait TDisplayObject<'gc>: fn as_video(self) -> Option> { None } + fn as_drawing(&self, _gc_context: MutationContext<'gc, '_>) -> Option> { + None + } fn apply_place_object( &self, diff --git a/core/src/display_object/movie_clip.rs b/core/src/display_object/movie_clip.rs index c90e7538e..22ac52a6c 100644 --- a/core/src/display_object/movie_clip.rs +++ b/core/src/display_object/movie_clip.rs @@ -26,18 +26,17 @@ use crate::drawing::Drawing; use crate::events::{ButtonKeyCode, ClipEvent, ClipEventResult}; use crate::font::Font; use crate::prelude::*; -use crate::shape_utils::DrawCommand; use crate::tag_utils::{self, DecodeResult, SwfMovie, SwfSlice, SwfStream}; use crate::types::{Degrees, Percent}; use crate::vminterface::{AvmObject, AvmType, Instantiator}; use gc_arena::{Collect, Gc, GcCell, MutationContext}; use smallvec::SmallVec; -use std::cell::{Ref, RefCell}; +use std::cell::{Ref, RefCell, RefMut}; use std::collections::HashMap; use std::convert::TryFrom; use std::sync::Arc; use swf::extensions::ReadSwfExt; -use swf::{FillStyle, FrameLabelData, LineStyle, Tag}; +use swf::{FrameLabelData, Tag}; type FrameNumber = u16; @@ -1013,34 +1012,6 @@ impl<'gc> MovieClip<'gc> { actions.into_iter() } - pub fn set_fill_style( - self, - context: &mut UpdateContext<'_, 'gc, '_>, - style: Option, - ) { - let mut mc = self.0.write(context.gc_context); - mc.drawing.set_fill_style(style); - } - - pub fn clear(self, context: &mut UpdateContext<'_, 'gc, '_>) { - let mut mc = self.0.write(context.gc_context); - mc.drawing.clear(); - } - - pub fn set_line_style( - self, - context: &mut UpdateContext<'_, 'gc, '_>, - style: Option, - ) { - let mut mc = self.0.write(context.gc_context); - mc.drawing.set_line_style(style); - } - - pub fn draw_command(self, context: &mut UpdateContext<'_, 'gc, '_>, command: DrawCommand) { - let mut mc = self.0.write(context.gc_context); - mc.drawing.draw_command(command); - } - pub fn run_clip_event( self, context: &mut crate::context::UpdateContext<'_, 'gc, '_>, @@ -1936,6 +1907,10 @@ impl<'gc> TDisplayObject<'gc> for MovieClip<'gc> { Some(self.into()) } + fn as_drawing(&self, gc_context: MutationContext<'gc, '_>) -> Option> { + Some(RefMut::map(self.0.write(gc_context), |s| &mut s.drawing)) + } + fn post_instantiation( &self, context: &mut UpdateContext<'_, 'gc, '_>, diff --git a/core/src/drawing.rs b/core/src/drawing.rs index 50fe03713..732eaec23 100644 --- a/core/src/drawing.rs +++ b/core/src/drawing.rs @@ -20,6 +20,12 @@ pub struct Drawing { cursor: (Twips, Twips), } +impl Default for Drawing { + fn default() -> Self { + Self::new() + } +} + impl Drawing { pub fn new() -> Self { Self {