From a9915c71bcde681f23947a1b38269a10db629a83 Mon Sep 17 00:00:00 2001 From: relrelb Date: Wed, 15 Jun 2022 22:43:32 +0300 Subject: [PATCH] avm2: Port `flash.geom.Rectangle` to ActionScript `flash.geom.Rectangle` is a good candidate, since it doesn't have any native function, and it depends only on `flash.geom.Point`, which was already been ported to ActionScript in #7071. --- core/src/avm2/globals.rs | 6 - core/src/avm2/globals/flash/geom.rs | 1 - core/src/avm2/globals/flash/geom/Rectangle.as | 200 ++++ core/src/avm2/globals/flash/geom/rectangle.rs | 906 ------------------ 4 files changed, 200 insertions(+), 913 deletions(-) create mode 100644 core/src/avm2/globals/flash/geom/Rectangle.as delete mode 100644 core/src/avm2/globals/flash/geom/rectangle.rs diff --git a/core/src/avm2/globals.rs b/core/src/avm2/globals.rs index 693c8d80a..dcd2765db 100644 --- a/core/src/avm2/globals.rs +++ b/core/src/avm2/globals.rs @@ -906,12 +906,6 @@ pub fn load_player_globals<'gc>( // package `flash.geom` class(activation, flash::geom::matrix::create_class(mc), script)?; - avm2_system_class!( - rectangle, - activation, - flash::geom::rectangle::create_class(mc), - script - ); // package `flash.media` avm2_system_class!( diff --git a/core/src/avm2/globals/flash/geom.rs b/core/src/avm2/globals/flash/geom.rs index 168603361..55d05bf87 100644 --- a/core/src/avm2/globals/flash/geom.rs +++ b/core/src/avm2/globals/flash/geom.rs @@ -1,4 +1,3 @@ //! `flash.geom` namespace pub mod matrix; -pub mod rectangle; diff --git a/core/src/avm2/globals/flash/geom/Rectangle.as b/core/src/avm2/globals/flash/geom/Rectangle.as new file mode 100644 index 000000000..506f8443f --- /dev/null +++ b/core/src/avm2/globals/flash/geom/Rectangle.as @@ -0,0 +1,200 @@ +package flash.geom { + public class Rectangle { + public var x: Number; + public var y: Number; + public var width: Number; + public var height: Number; + + public function Rectangle(x: Number = 0, y: Number = 0, width: Number = 0, height: Number = 0) { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + } + + public function get left(): Number { + return this.x; + } + + public function set left(value: Number): void { + this.width += this.x - value; + this.x = value; + } + + public function get right(): Number { + return this.x + this.width; + } + + public function set right(value: Number): void { + this.width = value - this.x; + } + + public function get top(): Number { + return this.y; + } + + public function set top(value: Number): void { + this.height += this.y - value; + this.y = value; + } + + public function get bottom(): Number { + return this.y + this.height; + } + + public function set bottom(value: Number): void { + this.height = value - this.y; + } + + public function get topLeft(): Point { + return new Point(this.x, this.y); + } + + public function set topLeft(value: Point): void { + this.width += this.x - value.x; + this.height += this.y - value.y; + this.x = value.x; + this.y = value.y; + } + + public function get bottomRight(): Point { + return new Point(this.right, this.bottom); + } + + public function set bottomRight(value: Point): void { + this.width = value.x - this.x; + this.height = value.y - this.y; + } + + public function get size(): Point { + return new Point(this.width, this.height); + } + + public function set size(value: Point): void { + this.width = value.x; + this.height = value.y; + } + + public function clone(): Rectangle { + return new Rectangle(this.x, this.y, this.width, this.height); + } + + public function isEmpty(): Boolean { + return this.width <= 0 || this.height <= 0; + } + + public function setEmpty(): void { + this.x = 0; + this.y = 0; + this.width = 0; + this.height = 0; + } + + public function inflate(dx: Number, dy: Number): void { + this.x -= dx; + this.width += 2 * dx; + this.y -= dy; + this.height += 2 * dy; + } + + public function inflatePoint(point: Point): void { + this.x -= point.x; + this.width += 2 * point.x; + this.y -= point.y; + this.height += 2 * point.y; + } + + public function offset(dx: Number, dy: Number): void { + this.x += dx; + this.y += dy; + } + + public function offsetPoint(point: Point): void { + this.x += point.x; + this.y += point.y; + } + + public function contains(x: Number, y: Number): Boolean { + return x >= this.x && x < this.x + this.width && y >= this.y && y < this.y + this.height; + } + + public function containsPoint(point: Point): Boolean { + return point.x >= this.x && point.x < this.x + this.width && point.y >= this.y && point.y < this.y + this.height; + } + + public function containsRect(rect: Rectangle): Boolean { + var r1 = rect.x + rect.width; + var b1 = rect.y + rect.height; + var r2 = this.x + this.width; + var b2 = this.y + this.height; + return rect.x >= this.x && rect.x < r2 && rect.y >= this.y && rect.y < b2 && r1 > this.x && r1 <= r2 && b1 > this.y && b1 <= b2; + } + + public function intersection(toIntersect: Rectangle): Rectangle { + var result = new Rectangle(); + if (this.isEmpty() || toIntersect.isEmpty()) { + result.setEmpty(); + return result; + } + result.x = Math.max(this.x, toIntersect.x); + result.y = Math.max(this.y, toIntersect.y); + result.width = Math.min(this.x + this.width, toIntersect.x + toIntersect.width) - result.x; + result.height = Math.min(this.y + this.height, toIntersect.y + toIntersect.height) - result.y; + if (result.width <= 0 || result.height <= 0) { + result.setEmpty(); + } + return result; + } + + public function intersects(toIntersect: Rectangle): Boolean { + if (this.isEmpty() || toIntersect.isEmpty()) { + return false; + } + var resultx = Math.max(this.x, toIntersect.x); + var resulty = Math.max(this.y, toIntersect.y); + var resultwidth = Math.min(this.x + this.width, toIntersect.x + toIntersect.width) - resultx; + var resultheight = Math.min(this.y + this.height, toIntersect.y + toIntersect.height) - resulty; + if (resultwidth <= 0 || resultheight <= 0) { + return false; + } + return true; + } + + public function union(toUnion: Rectangle): Rectangle { + if (this.isEmpty()) { + return toUnion.clone(); + } + if (toUnion.isEmpty()) { + return this.clone(); + } + var r = new Rectangle(); + r.x = Math.min(this.x, toUnion.x); + r.y = Math.min(this.y, toUnion.y); + r.width = Math.max(this.x + this.width, toUnion.x + toUnion.width) - r.x; + r.height = Math.max(this.y + this.height, toUnion.y + toUnion.height) - r.y; + return r; + } + + public function equals(toCompare: Rectangle): Boolean { + return toCompare.x == this.x && toCompare.y == this.y && toCompare.width == this.width && toCompare.height == this.height; + } + + public function toString(): String { + return "(x=" + this.x + ", y=" + this.y + ", w=" + this.width + ", h=" + this.height + ")"; + } + + public function copyFrom(sourceRect: Rectangle): void { + this.x = sourceRect.x; + this.y = sourceRect.y; + this.width = sourceRect.width; + this.height = sourceRect.height; + } + + public function setTo(xa: Number, ya: Number, widtha: Number, heighta: Number): void { + this.x = xa; + this.y = ya; + this.width = widtha; + this.height = heighta; + } + } +} diff --git a/core/src/avm2/globals/flash/geom/rectangle.rs b/core/src/avm2/globals/flash/geom/rectangle.rs deleted file mode 100644 index 794a449d5..000000000 --- a/core/src/avm2/globals/flash/geom/rectangle.rs +++ /dev/null @@ -1,906 +0,0 @@ -//! `flash.geom.Rectangle` builtin/prototype - -use crate::avm2::class::{Class, ClassAttributes}; -use crate::avm2::method::{Method, NativeMethodImpl}; -use crate::avm2::{Activation, Error, Namespace, Object, QName, TObject, Value}; -use crate::string::AvmString; -use gc_arena::{GcCell, MutationContext}; - -pub fn create_point<'gc>( - activation: &mut Activation<'_, 'gc, '_>, - coords: (f64, f64), -) -> Result, Error> { - let point_class = activation.context.avm2.classes().point; - - let args = [Value::Number(coords.0), Value::Number(coords.1)]; - let new_point = point_class.construct(activation, &args)?; - - Ok(new_point.into()) -} - -pub fn create_rectangle<'gc>( - activation: &mut Activation<'_, 'gc, '_>, - properties: (f64, f64, f64, f64), -) -> Result, Error> { - let rectangle_class = activation.context.avm2.classes().rectangle; - - let args = [ - Value::Number(properties.0), - Value::Number(properties.1), - Value::Number(properties.2), - Value::Number(properties.3), - ]; - let new_rectangle = rectangle_class.construct(activation, &args)?; - - Ok(new_rectangle.into()) -} - -macro_rules! get_prop { - ($this:expr, $activation:expr, $name: expr) => { - $this - .get_property(&QName::new(Namespace::public(), $name).into(), $activation)? - .coerce_to_number($activation) - }; -} - -macro_rules! set_prop { - ($this:expr, $activation:expr, $name: expr, $value: expr) => { - $this.set_property( - &QName::new(Namespace::public(), $name).into(), - $value.into(), - $activation, - ) - }; -} - -/// Implements `flash.geom.Rectangle`'s instance constructor. -pub fn instance_init<'gc>( - activation: &mut Activation<'_, 'gc, '_>, - this: Option>, - args: &[Value<'gc>], -) -> Result, Error> { - let _ = set_to(activation, this, args)?; - Ok(Value::Undefined) -} - -/// Implements `flash.geom.Rectangle`'s class initializer. -pub fn class_init<'gc>( - _activation: &mut Activation<'_, 'gc, '_>, - _this: Option>, - _args: &[Value<'gc>], -) -> Result, Error> { - Ok(Value::Undefined) -} - -/// Implement `top`'s getter -pub fn top<'gc>( - activation: &mut Activation<'_, 'gc, '_>, - this: Option>, - _args: &[Value<'gc>], -) -> Result, Error> { - if let Some(this) = this { - let top = get_prop!(this, activation, "y")?; - - return Ok(top.into()); - } - - Ok(Value::Undefined) -} - -/// Implement `top`'s setter -pub fn set_top<'gc>( - activation: &mut Activation<'_, 'gc, '_>, - this: Option>, - args: &[Value<'gc>], -) -> Result, Error> { - if let Some(mut this) = this { - let top = args - .get(0) - .unwrap_or(&0.into()) - .coerce_to_number(activation)?; - - let height = get_prop!(this, activation, "height")?; - - let y = get_prop!(this, activation, "y")?; - - let height = height + y - top; - - set_prop!(this, activation, "y", top)?; - set_prop!(this, activation, "height", height)?; - } - - Ok(Value::Undefined) -} - -/// Implement `bottom`'s getter -pub fn bottom<'gc>( - activation: &mut Activation<'_, 'gc, '_>, - this: Option>, - _args: &[Value<'gc>], -) -> Result, Error> { - if let Some(this) = this { - let y = get_prop!(this, activation, "y")?; - let height = get_prop!(this, activation, "height")?; - - let bottom = y + height; - - return Ok(bottom.into()); - } - - Ok(Value::Undefined) -} - -/// Implement `bottom`'s setter -pub fn set_bottom<'gc>( - activation: &mut Activation<'_, 'gc, '_>, - this: Option>, - args: &[Value<'gc>], -) -> Result, Error> { - if let Some(mut this) = this { - let bottom = args - .get(0) - .unwrap_or(&0.into()) - .coerce_to_number(activation)?; - - let y = get_prop!(this, activation, "y")?; - - let height = bottom - y; - - set_prop!(this, activation, "height", height)?; - } - - Ok(Value::Undefined) -} - -/// Implement `left`'s getter -pub fn left<'gc>( - activation: &mut Activation<'_, 'gc, '_>, - this: Option>, - _args: &[Value<'gc>], -) -> Result, Error> { - if let Some(this) = this { - let left = get_prop!(this, activation, "x")?; - - return Ok(left.into()); - } - - Ok(Value::Undefined) -} - -/// Implement `left`'s setter -pub fn set_left<'gc>( - activation: &mut Activation<'_, 'gc, '_>, - this: Option>, - args: &[Value<'gc>], -) -> Result, Error> { - if let Some(mut this) = this { - let left = args - .get(0) - .unwrap_or(&0.into()) - .coerce_to_number(activation)?; - - let width = get_prop!(this, activation, "width")?; - - let x = get_prop!(this, activation, "x")?; - - let width = width + x - left; - - set_prop!(this, activation, "x", left)?; - set_prop!(this, activation, "width", width)?; - } - - Ok(Value::Undefined) -} - -/// Implement `right`'s getter -pub fn right<'gc>( - activation: &mut Activation<'_, 'gc, '_>, - this: Option>, - _args: &[Value<'gc>], -) -> Result, Error> { - if let Some(this) = this { - let x = get_prop!(this, activation, "x")?; - let width = get_prop!(this, activation, "width")?; - - let right = x + width; - - return Ok(right.into()); - } - - Ok(Value::Undefined) -} - -/// Implement `right`'s setter -pub fn set_right<'gc>( - activation: &mut Activation<'_, 'gc, '_>, - this: Option>, - args: &[Value<'gc>], -) -> Result, Error> { - if let Some(mut this) = this { - let right = args - .get(0) - .unwrap_or(&0.into()) - .coerce_to_number(activation)?; - - let x = get_prop!(this, activation, "x")?; - - let width = right - x; - - set_prop!(this, activation, "width", width)?; - } - - Ok(Value::Undefined) -} - -/// Implement `bottomRight`'s getter -pub fn bottom_right<'gc>( - activation: &mut Activation<'_, 'gc, '_>, - this: Option>, - _args: &[Value<'gc>], -) -> Result, Error> { - if let Some(this) = this { - let y = get_prop!(this, activation, "y")?; - let height = get_prop!(this, activation, "height")?; - - let bottom = y + height; - - let x = get_prop!(this, activation, "x")?; - let width = get_prop!(this, activation, "width")?; - - let right = x + width; - - return create_point(activation, (right, bottom)); - } - - Ok(Value::Undefined) -} - -/// Implement `bottomRight`'s setter -pub fn set_bottom_right<'gc>( - activation: &mut Activation<'_, 'gc, '_>, - this: Option>, - args: &[Value<'gc>], -) -> Result, Error> { - if let Some(mut this) = this { - if let Some(point) = args.get(0) { - let point_obj = point.coerce_to_object(activation)?; - let right = get_prop!(point_obj, activation, "x")?; - let bottom = get_prop!(point_obj, activation, "y")?; - - let x = get_prop!(this, activation, "x")?; - let y = get_prop!(this, activation, "y")?; - let width = right - x; - let height = bottom - y; - - set_prop!(this, activation, "width", width)?; - set_prop!(this, activation, "height", height)?; - } - } - - Ok(Value::Undefined) -} - -/// Implement `topLeft`'s getter -pub fn top_left<'gc>( - activation: &mut Activation<'_, 'gc, '_>, - this: Option>, - _args: &[Value<'gc>], -) -> Result, Error> { - if let Some(this) = this { - let x = get_prop!(this, activation, "x")?; - let y = get_prop!(this, activation, "y")?; - - return create_point(activation, (x, y)); - } - - Ok(Value::Undefined) -} - -/// Implement `topLeft`'s setter -pub fn set_top_left<'gc>( - activation: &mut Activation<'_, 'gc, '_>, - this: Option>, - args: &[Value<'gc>], -) -> Result, Error> { - if let Some(mut this) = this { - if let Some(point) = args.get(0) { - let point_obj = point.coerce_to_object(activation)?; - - let left = get_prop!(point_obj, activation, "x")?; - let top = get_prop!(point_obj, activation, "y")?; - - let x = get_prop!(this, activation, "x")?; - let y = get_prop!(this, activation, "y")?; - - let width = get_prop!(this, activation, "width")? - left + x; - let height = get_prop!(this, activation, "height")? - top + y; - - set_prop!(this, activation, "x", left)?; - set_prop!(this, activation, "y", top)?; - set_prop!(this, activation, "width", width)?; - set_prop!(this, activation, "height", height)?; - } - } - - Ok(Value::Undefined) -} - -/// Implement `size`'s getter -pub fn size<'gc>( - activation: &mut Activation<'_, 'gc, '_>, - this: Option>, - _args: &[Value<'gc>], -) -> Result, Error> { - if let Some(this) = this { - let width = get_prop!(this, activation, "width")?; - let height = get_prop!(this, activation, "height")?; - - return create_point(activation, (width, height)); - } - - Ok(Value::Undefined) -} - -/// Implement `size`'s setter -pub fn set_size<'gc>( - activation: &mut Activation<'_, 'gc, '_>, - this: Option>, - args: &[Value<'gc>], -) -> Result, Error> { - if let Some(mut this) = this { - if let Some(point) = args.get(0) { - let point_obj = point.coerce_to_object(activation)?; - - let width = get_prop!(point_obj, activation, "x")?; - let height = get_prop!(point_obj, activation, "y")?; - - set_prop!(this, activation, "width", width)?; - set_prop!(this, activation, "height", height)?; - } - } - - Ok(Value::Undefined) -} - -/// Implement `clone` -pub fn clone<'gc>( - activation: &mut Activation<'_, 'gc, '_>, - this: Option>, - _args: &[Value<'gc>], -) -> Result, Error> { - if let Some(this) = this { - let x = get_prop!(this, activation, "x")?; - let y = get_prop!(this, activation, "y")?; - - let width = get_prop!(this, activation, "width")?; - let height = get_prop!(this, activation, "height")?; - - return create_rectangle(activation, (x, y, width, height)); - } - - Ok(Value::Undefined) -} - -fn contains_tuple<'gc>( - this: &Object<'gc>, - activation: &mut Activation<'_, 'gc, '_>, - coords: (f64, f64), -) -> Result { - let (x, y) = coords; - let left = get_prop!(*this, activation, "x")?; - let right = get_prop!(*this, activation, "width")? + left; - - let top = get_prop!(*this, activation, "y")?; - let bottom = get_prop!(*this, activation, "height")? + top; - - Ok(left <= x && x < right && top <= y && y < bottom) -} - -/// Implement `contains` -pub fn contains<'gc>( - activation: &mut Activation<'_, 'gc, '_>, - this: Option>, - args: &[Value<'gc>], -) -> Result, Error> { - if let Some(this) = this { - let x = args.get(0).unwrap().coerce_to_number(activation)?; - let y = args.get(1).unwrap().coerce_to_number(activation)?; - - return Ok(contains_tuple(&this, activation, (x, y))?.into()); - } - - Ok(Value::Undefined) -} - -/// Implement `containsPoint` -pub fn contains_point<'gc>( - activation: &mut Activation<'_, 'gc, '_>, - this: Option>, - args: &[Value<'gc>], -) -> Result, Error> { - if let Some(this) = this { - if let Some(point) = args.get(0) { - let point = point.coerce_to_object(activation)?; - let x = get_prop!(point, activation, "x")?; - let y = get_prop!(point, activation, "y")?; - - return Ok(contains_tuple(&this, activation, (x, y))?.into()); - } - } - - Ok(Value::Undefined) -} - -/// Implement `containsRect` -pub fn contains_rect<'gc>( - activation: &mut Activation<'_, 'gc, '_>, - this: Option>, - args: &[Value<'gc>], -) -> Result, Error> { - if let Some(this) = this { - if let Some(rect) = args.get(0) { - let rect = rect.coerce_to_object(activation)?; - let x = get_prop!(rect, activation, "x")?; - let y = get_prop!(rect, activation, "y")?; - let right = get_prop!(rect, activation, "width")? + x; - let bottom = get_prop!(rect, activation, "height")? + y; - - return Ok((contains_tuple(&this, activation, (x, y))? - && contains_tuple(&this, activation, (right, bottom))?) - .into()); - } - } - - Ok(Value::Undefined) -} - -/// Implement `copyFrom` -pub fn copy_from<'gc>( - activation: &mut Activation<'_, 'gc, '_>, - this: Option>, - args: &[Value<'gc>], -) -> Result, Error> { - if let Some(rect) = args.get(0) { - let rect = rect.coerce_to_object(activation)?; - let x = rect.get_property(&QName::new(Namespace::public(), "x").into(), activation)?; - let y = rect.get_property(&QName::new(Namespace::public(), "y").into(), activation)?; - let width = - rect.get_property(&QName::new(Namespace::public(), "width").into(), activation)?; - let height = rect.get_property( - &QName::new(Namespace::public(), "height").into(), - activation, - )?; - - set_to(activation, this, &[x, y, width, height])?; - } - - Ok(Value::Undefined) -} - -/// Implement `equals` -#[allow(clippy::float_cmp)] -pub fn equals<'gc>( - activation: &mut Activation<'_, 'gc, '_>, - this: Option>, - args: &[Value<'gc>], -) -> Result, Error> { - if let Some(this) = this { - if let Some(other) = args.get(0) { - let other = other.coerce_to_object(activation)?; - - let x = get_prop!(this, activation, "x")? == get_prop!(other, activation, "x")?; - let y = get_prop!(this, activation, "y")? == get_prop!(other, activation, "y")?; - let width = - get_prop!(this, activation, "width")? == get_prop!(other, activation, "width")?; - let height = - get_prop!(this, activation, "height")? == get_prop!(other, activation, "height")?; - - return Ok((x && y && width && height).into()); - } - } - - Ok(Value::Undefined) -} - -/// Implement `inflate` -pub fn inflate<'gc>( - activation: &mut Activation<'_, 'gc, '_>, - this: Option>, - args: &[Value<'gc>], -) -> Result, Error> { - if let Some(mut this) = this { - let dx = args.get(0).unwrap().coerce_to_number(activation)?; - let dy = args.get(1).unwrap().coerce_to_number(activation)?; - - let x = get_prop!(this, activation, "x")?; - let y = get_prop!(this, activation, "y")?; - - let width = get_prop!(this, activation, "width")?; - let height = get_prop!(this, activation, "height")?; - - set_prop!(this, activation, "x", x - dx)?; - set_prop!(this, activation, "y", y - dy)?; - set_prop!(this, activation, "width", width + 2. * dx)?; - set_prop!(this, activation, "height", height + 2. * dy)?; - } - - Ok(Value::Undefined) -} - -/// Implement `inflatePoint` -pub fn inflate_point<'gc>( - activation: &mut Activation<'_, 'gc, '_>, - this: Option>, - args: &[Value<'gc>], -) -> Result, Error> { - if let Some(mut this) = this { - if let Some(point) = args.get(0) { - let point = point.coerce_to_object(activation)?; - let dx = get_prop!(point, activation, "x")?; - let dy = get_prop!(point, activation, "y")?; - - let x = get_prop!(this, activation, "x")?; - let y = get_prop!(this, activation, "y")?; - - let width = get_prop!(this, activation, "width")?; - let height = get_prop!(this, activation, "height")?; - - set_prop!(this, activation, "x", x - dx)?; - set_prop!(this, activation, "y", y - dy)?; - set_prop!(this, activation, "width", width + 2. * dx)?; - set_prop!(this, activation, "height", height + 2. * dy)?; - } - } - - Ok(Value::Undefined) -} - -/// Implement `intersection` -pub fn intersection<'gc>( - activation: &mut Activation<'_, 'gc, '_>, - this: Option>, - args: &[Value<'gc>], -) -> Result, Error> { - if let Some(this) = this { - if let Some(other) = args.get(0) { - let other = other.coerce_to_object(activation)?; - let other_left = get_prop!(other, activation, "x")?; - let other_right = other_left + get_prop!(other, activation, "width")?; - let other_top = get_prop!(other, activation, "y")?; - let other_bottom = other_top + get_prop!(other, activation, "height")?; - - let this_left = get_prop!(this, activation, "x")?; - let this_right = this_left + get_prop!(this, activation, "width")?; - let this_top = get_prop!(this, activation, "y")?; - let this_bottom = this_top + get_prop!(this, activation, "height")?; - - let mut left = other_left.max(this_left); - let mut right = other_right.min(this_right); - let mut top = other_top.max(this_top); - let mut bottom = other_bottom.min(this_bottom); - - if right <= left || bottom <= top { - right = 0.0; - left = 0.0; - bottom = 0.0; - top = 0.0; - } - return create_rectangle(activation, (left, top, right - left, bottom - top)); - } - } - - Ok(Value::Undefined) -} - -/// Implement `intersects` -pub fn intersects<'gc>( - activation: &mut Activation<'_, 'gc, '_>, - this: Option>, - args: &[Value<'gc>], -) -> Result, Error> { - if let Some(this) = this { - if let Some(other) = args.get(0) { - let other = other.coerce_to_object(activation)?; - let other_left = get_prop!(other, activation, "x")?; - let other_right = other_left + get_prop!(other, activation, "width")?; - let other_top = get_prop!(other, activation, "y")?; - let other_bottom = other_top + get_prop!(other, activation, "height")?; - - let this_left = get_prop!(this, activation, "x")?; - let this_right = this_left + get_prop!(this, activation, "width")?; - let this_top = get_prop!(this, activation, "y")?; - let this_bottom = this_top + get_prop!(this, activation, "height")?; - - if (this_left, this_right, this_bottom, this_top) == (0., 0., 0., 0.) { - return Ok(false.into()); - } - - if (other_left, other_right, other_bottom, other_top) == (0., 0., 0., 0.) { - return Ok(false.into()); - } - - return Ok((this_left < other_right - && this_right > other_left - && this_top < other_bottom - && this_bottom > other_top) - .into()); - } - return Ok(false.into()); - } - - Ok(Value::Undefined) -} - -/// Implement `isEmpty` -pub fn is_empty<'gc>( - activation: &mut Activation<'_, 'gc, '_>, - this: Option>, - _args: &[Value<'gc>], -) -> Result, Error> { - if let Some(this) = this { - let width = get_prop!(this, activation, "width")?; - let height = get_prop!(this, activation, "height")?; - - return Ok((width <= 0. || height <= 0.).into()); - } - - Ok(Value::Undefined) -} - -/// Implement `offset` -pub fn offset<'gc>( - activation: &mut Activation<'_, 'gc, '_>, - this: Option>, - args: &[Value<'gc>], -) -> Result, Error> { - if let Some(mut this) = this { - let dx = args.get(0).unwrap().coerce_to_number(activation)?; - let dy = args.get(1).unwrap().coerce_to_number(activation)?; - - let x = get_prop!(this, activation, "x")?; - let y = get_prop!(this, activation, "y")?; - - set_prop!(this, activation, "x", x + dx)?; - set_prop!(this, activation, "y", y + dy)?; - } - - Ok(Value::Undefined) -} - -/// Implement `offsetPoint` -pub fn offset_point<'gc>( - activation: &mut Activation<'_, 'gc, '_>, - this: Option>, - args: &[Value<'gc>], -) -> Result, Error> { - if let Some(mut this) = this { - if let Some(point) = args.get(0) { - let point = point.coerce_to_object(activation)?; - let dx = get_prop!(point, activation, "x")?; - let dy = get_prop!(point, activation, "y")?; - - let x = get_prop!(this, activation, "x")?; - let y = get_prop!(this, activation, "y")?; - - set_prop!(this, activation, "x", x + dx)?; - set_prop!(this, activation, "y", y + dy)?; - } - } - - Ok(Value::Undefined) -} - -/// Implement `setEmpty` -pub fn set_empty<'gc>( - activation: &mut Activation<'_, 'gc, '_>, - this: Option>, - _args: &[Value<'gc>], -) -> Result, Error> { - let _ = set_to( - activation, - this, - &[ - Value::Number(0.), - Value::Number(0.), - Value::Number(0.), - Value::Number(0.), - ], - ); - - Ok(Value::Undefined) -} - -/// Implements `setTo` -pub fn set_to<'gc>( - activation: &mut Activation<'_, 'gc, '_>, - this: Option>, - args: &[Value<'gc>], -) -> Result, Error> { - if let Some(mut this) = this { - let x = args - .get(0) - .unwrap_or(&0.into()) - .coerce_to_number(activation)?; - let y = args - .get(1) - .unwrap_or(&0.into()) - .coerce_to_number(activation)?; - - let width = args - .get(2) - .unwrap_or(&0.into()) - .coerce_to_number(activation)?; - let height = args - .get(3) - .unwrap_or(&0.into()) - .coerce_to_number(activation)?; - - set_prop!(this, activation, "x", x)?; - set_prop!(this, activation, "y", y)?; - set_prop!(this, activation, "width", width)?; - set_prop!(this, activation, "height", height)?; - } - - Ok(Value::Undefined) -} - -/// Implements `toString` -pub fn to_string<'gc>( - activation: &mut Activation<'_, 'gc, '_>, - this: Option>, - _args: &[Value<'gc>], -) -> Result, Error> { - if let Some(this) = this { - let x = this - .get_property(&QName::new(Namespace::public(), "x").into(), activation)? - .coerce_to_string(activation)?; - let y = this - .get_property(&QName::new(Namespace::public(), "y").into(), activation)? - .coerce_to_string(activation)?; - let width = this - .get_property(&QName::new(Namespace::public(), "width").into(), activation)? - .coerce_to_string(activation)?; - let height = this - .get_property( - &QName::new(Namespace::public(), "height").into(), - activation, - )? - .coerce_to_string(activation)?; - - return Ok(AvmString::new_utf8( - activation.context.gc_context, - format!("(x={}, y={}, w={}, h={})", x, y, width, height), - ) - .into()); - } - - Ok(Value::Undefined) -} - -/// Implement `union` -pub fn union<'gc>( - activation: &mut Activation<'_, 'gc, '_>, - this: Option>, - args: &[Value<'gc>], -) -> Result, Error> { - if let Some(this) = this { - if let Some(other) = args.get(0) { - let other = other.coerce_to_object(activation)?; - let other_left = get_prop!(other, activation, "x")?; - let other_width = get_prop!(other, activation, "width")?; - let other_top = get_prop!(other, activation, "y")?; - let other_height = get_prop!(other, activation, "height")?; - let other_right = other_left + other_width; - let other_bottom = other_top + other_height; - - let this_left = get_prop!(this, activation, "x")?; - let this_width = get_prop!(this, activation, "width")?; - let this_top = get_prop!(this, activation, "y")?; - let this_height = get_prop!(this, activation, "height")?; - let this_right = this_left + this_width; - let this_bottom = this_top + this_height; - - if this_height <= 0. || this_width <= 0. { - return create_rectangle( - activation, - (other_left, other_top, other_width, other_height), - ); - } - - if other_height <= 0. || other_width <= 0. { - return create_rectangle( - activation, - (this_left, this_top, this_width, this_height), - ); - } - - let left = if this_left.is_nan() { - this_left - } else if other_left.is_nan() { - other_left - } else { - this_left.min(other_left) - }; - let top = if this_top.is_nan() { - this_top - } else if other_top.is_nan() { - other_top - } else { - this_top.min(other_top) - }; - let width = if this_right.is_nan() { - this_right - } else if other_right.is_nan() { - other_right - } else { - this_right.max(other_right) - } - left; - let height = if this_bottom.is_nan() { - this_bottom - } else if other_bottom.is_nan() { - other_bottom - } else { - this_bottom.max(other_bottom) - } - top; - - return create_rectangle(activation, (left, top, width, height)); - } - } - - Ok(Value::Undefined) -} - -/// Construct `Rectangle`'s class. -pub fn create_class<'gc>(mc: MutationContext<'gc, '_>) -> GcCell<'gc, Class<'gc>> { - let class = Class::new( - QName::new(Namespace::package("flash.geom"), "Rectangle"), - Some(QName::new(Namespace::public(), "Object").into()), - Method::from_builtin(instance_init, "", mc), - Method::from_builtin(class_init, "", mc), - mc, - ); - - let mut write = class.write(mc); - write.set_attributes(ClassAttributes::SEALED); - - const PUBLIC_INSTANCE_PROPERTIES: &[( - &str, - Option, - Option, - )] = &[ - ("top", Some(top), Some(set_top)), - ("bottom", Some(bottom), Some(set_bottom)), - ("left", Some(left), Some(set_left)), - ("right", Some(right), Some(set_right)), - ("bottomRight", Some(bottom_right), Some(set_bottom_right)), - ("topLeft", Some(top_left), Some(set_top_left)), - ("size", Some(size), Some(set_size)), - ]; - write.define_public_builtin_instance_properties(mc, PUBLIC_INSTANCE_PROPERTIES); - - const PUBLIC_INSTANCE_NUMBER_SLOTS: &[(&str, Option)] = - &[("x", None), ("y", None), ("width", None), ("height", None)]; - write.define_public_slot_number_instance_traits(PUBLIC_INSTANCE_NUMBER_SLOTS); - - const PUBLIC_INSTANCE_METHODS: &[(&str, NativeMethodImpl)] = &[ - ("contains", contains), - ("containsPoint", contains_point), - ("containsRect", contains_rect), - ("copyFrom", copy_from), - ("equals", equals), - ("inflate", inflate), - ("inflatePoint", inflate_point), - ("intersection", intersection), - ("intersects", intersects), - ("isEmpty", is_empty), - ("offset", offset), - ("offsetPoint", offset_point), - ("setEmpty", set_empty), - ("clone", clone), - ("setTo", set_to), - ("toString", to_string), - ("union", union), - ]; - write.define_public_builtin_instance_methods(mc, PUBLIC_INSTANCE_METHODS); - class -}