avm2: Made a FontObject type and switch Font to use that instead of looking up per getter
This commit is contained in:
parent
5682e0101d
commit
8be05d8673
|
@ -166,6 +166,7 @@ pub struct SystemClasses<'gc> {
|
||||||
pub shaderfilter: ClassObject<'gc>,
|
pub shaderfilter: ClassObject<'gc>,
|
||||||
pub statusevent: ClassObject<'gc>,
|
pub statusevent: ClassObject<'gc>,
|
||||||
pub contextmenuevent: ClassObject<'gc>,
|
pub contextmenuevent: ClassObject<'gc>,
|
||||||
|
pub font: ClassObject<'gc>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'gc> SystemClasses<'gc> {
|
impl<'gc> SystemClasses<'gc> {
|
||||||
|
@ -291,6 +292,7 @@ impl<'gc> SystemClasses<'gc> {
|
||||||
shaderfilter: object,
|
shaderfilter: object,
|
||||||
statusevent: object,
|
statusevent: object,
|
||||||
contextmenuevent: object,
|
contextmenuevent: object,
|
||||||
|
font: object,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -794,6 +796,7 @@ fn load_playerglobal<'gc>(
|
||||||
("flash.net", "URLVariables", urlvariables),
|
("flash.net", "URLVariables", urlvariables),
|
||||||
("flash.utils", "ByteArray", bytearray),
|
("flash.utils", "ByteArray", bytearray),
|
||||||
("flash.system", "ApplicationDomain", application_domain),
|
("flash.system", "ApplicationDomain", application_domain),
|
||||||
|
("flash.text", "Font", font),
|
||||||
("flash.text", "StaticText", statictext),
|
("flash.text", "StaticText", statictext),
|
||||||
("flash.text", "TextFormat", textformat),
|
("flash.text", "TextFormat", textformat),
|
||||||
("flash.text", "TextField", textfield),
|
("flash.text", "TextField", textfield),
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
package flash.text {
|
package flash.text {
|
||||||
|
[Ruffle(InstanceAllocator)]
|
||||||
public class Font {
|
public class Font {
|
||||||
public static native function enumerateFonts(enumerateDeviceFonts:Boolean = false):Array;
|
public static native function enumerateFonts(enumerateDeviceFonts:Boolean = false):Array;
|
||||||
public static native function registerFont(font:Class):void;
|
public static native function registerFont(font:Class):void;
|
||||||
|
|
|
@ -6,95 +6,56 @@ use crate::avm2::parameters::ParametersExt;
|
||||||
use crate::avm2::value::Value;
|
use crate::avm2::value::Value;
|
||||||
use crate::avm2::{ArrayObject, ArrayStorage, Error};
|
use crate::avm2::{ArrayObject, ArrayStorage, Error};
|
||||||
use crate::avm2_stub_method;
|
use crate::avm2_stub_method;
|
||||||
use crate::character::Character;
|
|
||||||
use crate::string::AvmString;
|
use crate::string::AvmString;
|
||||||
|
|
||||||
|
pub use crate::avm2::object::font_allocator;
|
||||||
|
|
||||||
/// Implements `Font.fontName`
|
/// Implements `Font.fontName`
|
||||||
pub fn get_font_name<'gc>(
|
pub fn get_font_name<'gc>(
|
||||||
activation: &mut Activation<'_, 'gc>,
|
activation: &mut Activation<'_, 'gc>,
|
||||||
this: Object<'gc>,
|
this: Object<'gc>,
|
||||||
_args: &[Value<'gc>],
|
_args: &[Value<'gc>],
|
||||||
) -> Result<Value<'gc>, Error<'gc>> {
|
) -> Result<Value<'gc>, Error<'gc>> {
|
||||||
if let Some((movie, character_id)) = this.instance_of().and_then(|this| {
|
if let Some(font) = this.as_font() {
|
||||||
activation
|
return Ok(
|
||||||
.context
|
AvmString::new_utf8(activation.context.gc_context, font.descriptor().name()).into(),
|
||||||
.library
|
);
|
||||||
.avm2_class_registry()
|
|
||||||
.class_symbol(this)
|
|
||||||
}) {
|
|
||||||
if let Some(Character::Font(font)) = activation
|
|
||||||
.context
|
|
||||||
.library
|
|
||||||
.library_for_movie_mut(movie)
|
|
||||||
.character_by_id(character_id)
|
|
||||||
{
|
|
||||||
return Ok(AvmString::new_utf8(
|
|
||||||
activation.context.gc_context,
|
|
||||||
font.descriptor().name(),
|
|
||||||
)
|
|
||||||
.into());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Value::Undefined)
|
Ok(Value::Null)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Implements `Font.fontStyle`
|
/// Implements `Font.fontStyle`
|
||||||
pub fn get_font_style<'gc>(
|
pub fn get_font_style<'gc>(
|
||||||
activation: &mut Activation<'_, 'gc>,
|
_activation: &mut Activation<'_, 'gc>,
|
||||||
this: Object<'gc>,
|
this: Object<'gc>,
|
||||||
_args: &[Value<'gc>],
|
_args: &[Value<'gc>],
|
||||||
) -> Result<Value<'gc>, Error<'gc>> {
|
) -> Result<Value<'gc>, Error<'gc>> {
|
||||||
if let Some((movie, character_id)) = this.instance_of().and_then(|this| {
|
if let Some(font) = this.as_font() {
|
||||||
activation
|
return match (font.descriptor().bold(), font.descriptor().italic()) {
|
||||||
.context
|
(false, false) => Ok("regular".into()),
|
||||||
.library
|
(false, true) => Ok("italic".into()),
|
||||||
.avm2_class_registry()
|
(true, false) => Ok("bold".into()),
|
||||||
.class_symbol(this)
|
(true, true) => Ok("boldItalic".into()),
|
||||||
}) {
|
};
|
||||||
if let Some(Character::Font(font)) = activation
|
|
||||||
.context
|
|
||||||
.library
|
|
||||||
.library_for_movie_mut(movie)
|
|
||||||
.character_by_id(character_id)
|
|
||||||
{
|
|
||||||
return match (font.descriptor().bold(), font.descriptor().italic()) {
|
|
||||||
(false, false) => Ok("regular".into()),
|
|
||||||
(false, true) => Ok("italic".into()),
|
|
||||||
(true, false) => Ok("bold".into()),
|
|
||||||
(true, true) => Ok("boldItalic".into()),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Value::Undefined)
|
Ok(Value::Null)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Implements `Font.fontType`
|
/// Implements `Font.fontType`
|
||||||
pub fn get_font_type<'gc>(
|
pub fn get_font_type<'gc>(
|
||||||
activation: &mut Activation<'_, 'gc>,
|
_activation: &mut Activation<'_, 'gc>,
|
||||||
this: Object<'gc>,
|
this: Object<'gc>,
|
||||||
_args: &[Value<'gc>],
|
_args: &[Value<'gc>],
|
||||||
) -> Result<Value<'gc>, Error<'gc>> {
|
) -> Result<Value<'gc>, Error<'gc>> {
|
||||||
if let Some((movie, character_id)) = this.instance_of().and_then(|this| {
|
if let Some(_font) = this.as_font() {
|
||||||
activation
|
// [?] How do we distinguish between CFF and non-CFF embedded fonts?
|
||||||
.context
|
// [NA] DefineFont4 is CFF. This should be a property of Font struct
|
||||||
.library
|
return Ok("embedded".into());
|
||||||
.avm2_class_registry()
|
|
||||||
.class_symbol(this)
|
|
||||||
}) {
|
|
||||||
if let Some(Character::Font(_)) = activation
|
|
||||||
.context
|
|
||||||
.library
|
|
||||||
.library_for_movie_mut(movie)
|
|
||||||
.character_by_id(character_id)
|
|
||||||
{
|
|
||||||
//TODO: How do we distinguish between CFF and non-CFF embedded fonts?
|
|
||||||
return Ok("embedded".into());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Value::Undefined)
|
Ok(Value::Null)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Implements `Font.hasGlyphs`
|
/// Implements `Font.hasGlyphs`
|
||||||
|
@ -103,26 +64,12 @@ pub fn has_glyphs<'gc>(
|
||||||
this: Object<'gc>,
|
this: Object<'gc>,
|
||||||
args: &[Value<'gc>],
|
args: &[Value<'gc>],
|
||||||
) -> Result<Value<'gc>, Error<'gc>> {
|
) -> Result<Value<'gc>, Error<'gc>> {
|
||||||
if let Some((movie, character_id)) = this.instance_of().and_then(|this| {
|
if let Some(font) = this.as_font() {
|
||||||
activation
|
|
||||||
.context
|
|
||||||
.library
|
|
||||||
.avm2_class_registry()
|
|
||||||
.class_symbol(this)
|
|
||||||
}) {
|
|
||||||
let my_str = args.get_string(activation, 0)?;
|
let my_str = args.get_string(activation, 0)?;
|
||||||
|
return Ok(font.has_glyphs_for_str(&my_str).into());
|
||||||
if let Some(Character::Font(font)) = activation
|
|
||||||
.context
|
|
||||||
.library
|
|
||||||
.library_for_movie_mut(movie)
|
|
||||||
.character_by_id(character_id)
|
|
||||||
{
|
|
||||||
return Ok(font.has_glyphs_for_str(&my_str).into());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Value::Undefined)
|
Ok(Value::Bool(false))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `Font.enumerateFonts`
|
/// `Font.enumerateFonts`
|
||||||
|
|
|
@ -40,6 +40,7 @@ mod dispatch_object;
|
||||||
mod domain_object;
|
mod domain_object;
|
||||||
mod error_object;
|
mod error_object;
|
||||||
mod event_object;
|
mod event_object;
|
||||||
|
mod font_object;
|
||||||
mod function_object;
|
mod function_object;
|
||||||
mod index_buffer_3d_object;
|
mod index_buffer_3d_object;
|
||||||
mod loaderinfo_object;
|
mod loaderinfo_object;
|
||||||
|
@ -83,6 +84,7 @@ pub use crate::avm2::object::domain_object::{
|
||||||
};
|
};
|
||||||
pub use crate::avm2::object::error_object::{error_allocator, ErrorObject, ErrorObjectWeak};
|
pub use crate::avm2::object::error_object::{error_allocator, ErrorObject, ErrorObjectWeak};
|
||||||
pub use crate::avm2::object::event_object::{event_allocator, EventObject, EventObjectWeak};
|
pub use crate::avm2::object::event_object::{event_allocator, EventObject, EventObjectWeak};
|
||||||
|
pub use crate::avm2::object::font_object::{font_allocator, FontObject, FontObjectWeak};
|
||||||
pub use crate::avm2::object::function_object::{
|
pub use crate::avm2::object::function_object::{
|
||||||
function_allocator, FunctionObject, FunctionObjectWeak,
|
function_allocator, FunctionObject, FunctionObjectWeak,
|
||||||
};
|
};
|
||||||
|
@ -132,6 +134,7 @@ pub use crate::avm2::object::xml_list_object::{
|
||||||
xml_list_allocator, E4XOrXml, XmlListObject, XmlListObjectWeak,
|
xml_list_allocator, E4XOrXml, XmlListObject, XmlListObjectWeak,
|
||||||
};
|
};
|
||||||
pub use crate::avm2::object::xml_object::{xml_allocator, XmlObject, XmlObjectWeak};
|
pub use crate::avm2::object::xml_object::{xml_allocator, XmlObject, XmlObjectWeak};
|
||||||
|
use crate::font::Font;
|
||||||
|
|
||||||
/// Represents an object that can be directly interacted with by the AVM2
|
/// Represents an object that can be directly interacted with by the AVM2
|
||||||
/// runtime.
|
/// runtime.
|
||||||
|
@ -173,7 +176,8 @@ pub use crate::avm2::object::xml_object::{xml_allocator, XmlObject, XmlObjectWea
|
||||||
Program3DObject(Program3DObject<'gc>),
|
Program3DObject(Program3DObject<'gc>),
|
||||||
NetStreamObject(NetStreamObject<'gc>),
|
NetStreamObject(NetStreamObject<'gc>),
|
||||||
ShaderDataObject(ShaderDataObject<'gc>),
|
ShaderDataObject(ShaderDataObject<'gc>),
|
||||||
SocketObject(SocketObject<'gc>)
|
SocketObject(SocketObject<'gc>),
|
||||||
|
FontObject(FontObject<'gc>)
|
||||||
}
|
}
|
||||||
)]
|
)]
|
||||||
pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy {
|
pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy {
|
||||||
|
@ -1276,6 +1280,11 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Unwrap this object as a font.
|
||||||
|
fn as_font(&self) -> Option<Font<'gc>> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
/// Unwrap this object as a mutable regexp.
|
/// Unwrap this object as a mutable regexp.
|
||||||
fn as_regexp_mut(&self, _mc: &Mutation<'gc>) -> Option<RefMut<RegExp<'gc>>> {
|
fn as_regexp_mut(&self, _mc: &Mutation<'gc>) -> Option<RefMut<RegExp<'gc>>> {
|
||||||
None
|
None
|
||||||
|
@ -1424,7 +1433,8 @@ impl<'gc> Object<'gc> {
|
||||||
Self::Program3DObject(o) => WeakObject::Program3DObject(Program3DObjectWeak(Gc::downgrade(o.0))),
|
Self::Program3DObject(o) => WeakObject::Program3DObject(Program3DObjectWeak(Gc::downgrade(o.0))),
|
||||||
Self::NetStreamObject(o) => WeakObject::NetStreamObject(NetStreamObjectWeak(GcCell::downgrade(o.0))),
|
Self::NetStreamObject(o) => WeakObject::NetStreamObject(NetStreamObjectWeak(GcCell::downgrade(o.0))),
|
||||||
Self::ShaderDataObject(o) => WeakObject::ShaderDataObject(ShaderDataObjectWeak(Gc::downgrade(o.0))),
|
Self::ShaderDataObject(o) => WeakObject::ShaderDataObject(ShaderDataObjectWeak(Gc::downgrade(o.0))),
|
||||||
Self::SocketObject(o) => WeakObject::SocketObject(SocketObjectWeak(Gc::downgrade(o.0)))
|
Self::SocketObject(o) => WeakObject::SocketObject(SocketObjectWeak(Gc::downgrade(o.0))),
|
||||||
|
Self::FontObject(o) => WeakObject::FontObject(FontObjectWeak(GcCell::downgrade(o.0))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1481,6 +1491,7 @@ pub enum WeakObject<'gc> {
|
||||||
NetStreamObject(NetStreamObjectWeak<'gc>),
|
NetStreamObject(NetStreamObjectWeak<'gc>),
|
||||||
ShaderDataObject(ShaderDataObjectWeak<'gc>),
|
ShaderDataObject(ShaderDataObjectWeak<'gc>),
|
||||||
SocketObject(SocketObjectWeak<'gc>),
|
SocketObject(SocketObjectWeak<'gc>),
|
||||||
|
FontObject(FontObjectWeak<'gc>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'gc> WeakObject<'gc> {
|
impl<'gc> WeakObject<'gc> {
|
||||||
|
@ -1520,6 +1531,7 @@ impl<'gc> WeakObject<'gc> {
|
||||||
Self::NetStreamObject(o) => NetStreamObject(o.0.upgrade(mc)?).into(),
|
Self::NetStreamObject(o) => NetStreamObject(o.0.upgrade(mc)?).into(),
|
||||||
Self::ShaderDataObject(o) => ShaderDataObject(o.0.upgrade(mc)?).into(),
|
Self::ShaderDataObject(o) => ShaderDataObject(o.0.upgrade(mc)?).into(),
|
||||||
Self::SocketObject(o) => SocketObject(o.0.upgrade(mc)?).into(),
|
Self::SocketObject(o) => SocketObject(o.0.upgrade(mc)?).into(),
|
||||||
|
Self::FontObject(o) => FontObject(o.0.upgrade(mc)?).into(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,88 @@
|
||||||
|
use crate::avm2::object::script_object::ScriptObjectData;
|
||||||
|
use crate::avm2::object::{Object, ObjectPtr, TObject};
|
||||||
|
use crate::avm2::value::Value;
|
||||||
|
use crate::avm2::{Activation, ClassObject, Error};
|
||||||
|
use crate::character::Character;
|
||||||
|
use crate::font::Font;
|
||||||
|
use gc_arena::Mutation;
|
||||||
|
use gc_arena::{Collect, GcCell, GcWeakCell};
|
||||||
|
use std::cell::{Ref, RefMut};
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
/// A class instance allocator that allocates Font objects.
|
||||||
|
pub fn font_allocator<'gc>(
|
||||||
|
class: ClassObject<'gc>,
|
||||||
|
activation: &mut Activation<'_, 'gc>,
|
||||||
|
) -> Result<Object<'gc>, Error<'gc>> {
|
||||||
|
let base = ScriptObjectData::new(class);
|
||||||
|
|
||||||
|
let font = if let Some((movie, id)) = activation
|
||||||
|
.context
|
||||||
|
.library
|
||||||
|
.avm2_class_registry()
|
||||||
|
.class_symbol(class)
|
||||||
|
{
|
||||||
|
if let Some(lib) = activation.context.library.library_for_movie(movie) {
|
||||||
|
if let Some(Character::Font(font)) = lib.character_by_id(id) {
|
||||||
|
Some(*font)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(FontObject(GcCell::new(
|
||||||
|
activation.context.gc_context,
|
||||||
|
FontObjectData { base, font },
|
||||||
|
))
|
||||||
|
.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Collect, Copy)]
|
||||||
|
#[collect(no_drop)]
|
||||||
|
pub struct FontObject<'gc>(pub GcCell<'gc, FontObjectData<'gc>>);
|
||||||
|
|
||||||
|
#[derive(Clone, Collect, Copy, Debug)]
|
||||||
|
#[collect(no_drop)]
|
||||||
|
pub struct FontObjectWeak<'gc>(pub GcWeakCell<'gc, FontObjectData<'gc>>);
|
||||||
|
|
||||||
|
impl<'gc> TObject<'gc> for FontObject<'gc> {
|
||||||
|
fn base(&self) -> Ref<ScriptObjectData<'gc>> {
|
||||||
|
Ref::map(self.0.read(), |read| &read.base)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn base_mut(&self, mc: &Mutation<'gc>) -> RefMut<ScriptObjectData<'gc>> {
|
||||||
|
RefMut::map(self.0.write(mc), |write| &mut write.base)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_ptr(&self) -> *const ObjectPtr {
|
||||||
|
self.0.as_ptr() as *const ObjectPtr
|
||||||
|
}
|
||||||
|
|
||||||
|
fn value_of(&self, _mc: &Mutation<'gc>) -> Result<Value<'gc>, Error<'gc>> {
|
||||||
|
Ok(Value::Object(Object::from(*self)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_font(&self) -> Option<Font<'gc>> {
|
||||||
|
self.0.read().font
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Collect)]
|
||||||
|
#[collect(no_drop)]
|
||||||
|
pub struct FontObjectData<'gc> {
|
||||||
|
/// Base script object
|
||||||
|
base: ScriptObjectData<'gc>,
|
||||||
|
|
||||||
|
font: Option<Font<'gc>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for FontObject<'_> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "FontObject")
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue