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 statusevent: ClassObject<'gc>,
|
||||
pub contextmenuevent: ClassObject<'gc>,
|
||||
pub font: ClassObject<'gc>,
|
||||
}
|
||||
|
||||
impl<'gc> SystemClasses<'gc> {
|
||||
|
@ -291,6 +292,7 @@ impl<'gc> SystemClasses<'gc> {
|
|||
shaderfilter: object,
|
||||
statusevent: object,
|
||||
contextmenuevent: object,
|
||||
font: object,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -794,6 +796,7 @@ fn load_playerglobal<'gc>(
|
|||
("flash.net", "URLVariables", urlvariables),
|
||||
("flash.utils", "ByteArray", bytearray),
|
||||
("flash.system", "ApplicationDomain", application_domain),
|
||||
("flash.text", "Font", font),
|
||||
("flash.text", "StaticText", statictext),
|
||||
("flash.text", "TextFormat", textformat),
|
||||
("flash.text", "TextField", textfield),
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
package flash.text {
|
||||
[Ruffle(InstanceAllocator)]
|
||||
public class Font {
|
||||
public static native function enumerateFonts(enumerateDeviceFonts:Boolean = false):Array;
|
||||
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::{ArrayObject, ArrayStorage, Error};
|
||||
use crate::avm2_stub_method;
|
||||
use crate::character::Character;
|
||||
use crate::string::AvmString;
|
||||
|
||||
pub use crate::avm2::object::font_allocator;
|
||||
|
||||
/// Implements `Font.fontName`
|
||||
pub fn get_font_name<'gc>(
|
||||
activation: &mut Activation<'_, 'gc>,
|
||||
this: Object<'gc>,
|
||||
_args: &[Value<'gc>],
|
||||
) -> Result<Value<'gc>, Error<'gc>> {
|
||||
if let Some((movie, character_id)) = this.instance_of().and_then(|this| {
|
||||
activation
|
||||
.context
|
||||
.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());
|
||||
}
|
||||
if let Some(font) = this.as_font() {
|
||||
return Ok(
|
||||
AvmString::new_utf8(activation.context.gc_context, font.descriptor().name()).into(),
|
||||
);
|
||||
}
|
||||
|
||||
Ok(Value::Undefined)
|
||||
Ok(Value::Null)
|
||||
}
|
||||
|
||||
/// Implements `Font.fontStyle`
|
||||
pub fn get_font_style<'gc>(
|
||||
activation: &mut Activation<'_, 'gc>,
|
||||
_activation: &mut Activation<'_, 'gc>,
|
||||
this: Object<'gc>,
|
||||
_args: &[Value<'gc>],
|
||||
) -> Result<Value<'gc>, Error<'gc>> {
|
||||
if let Some((movie, character_id)) = this.instance_of().and_then(|this| {
|
||||
activation
|
||||
.context
|
||||
.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 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()),
|
||||
};
|
||||
}
|
||||
if let Some(font) = this.as_font() {
|
||||
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`
|
||||
pub fn get_font_type<'gc>(
|
||||
activation: &mut Activation<'_, 'gc>,
|
||||
_activation: &mut Activation<'_, 'gc>,
|
||||
this: Object<'gc>,
|
||||
_args: &[Value<'gc>],
|
||||
) -> Result<Value<'gc>, Error<'gc>> {
|
||||
if let Some((movie, character_id)) = this.instance_of().and_then(|this| {
|
||||
activation
|
||||
.context
|
||||
.library
|
||||
.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());
|
||||
}
|
||||
if let Some(_font) = this.as_font() {
|
||||
// [?] How do we distinguish between CFF and non-CFF embedded fonts?
|
||||
// [NA] DefineFont4 is CFF. This should be a property of Font struct
|
||||
return Ok("embedded".into());
|
||||
}
|
||||
|
||||
Ok(Value::Undefined)
|
||||
Ok(Value::Null)
|
||||
}
|
||||
|
||||
/// Implements `Font.hasGlyphs`
|
||||
|
@ -103,26 +64,12 @@ pub fn has_glyphs<'gc>(
|
|||
this: Object<'gc>,
|
||||
args: &[Value<'gc>],
|
||||
) -> Result<Value<'gc>, Error<'gc>> {
|
||||
if let Some((movie, character_id)) = this.instance_of().and_then(|this| {
|
||||
activation
|
||||
.context
|
||||
.library
|
||||
.avm2_class_registry()
|
||||
.class_symbol(this)
|
||||
}) {
|
||||
if let Some(font) = this.as_font() {
|
||||
let my_str = args.get_string(activation, 0)?;
|
||||
|
||||
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());
|
||||
}
|
||||
return Ok(font.has_glyphs_for_str(&my_str).into());
|
||||
}
|
||||
|
||||
Ok(Value::Undefined)
|
||||
Ok(Value::Bool(false))
|
||||
}
|
||||
|
||||
/// `Font.enumerateFonts`
|
||||
|
|
|
@ -40,6 +40,7 @@ mod dispatch_object;
|
|||
mod domain_object;
|
||||
mod error_object;
|
||||
mod event_object;
|
||||
mod font_object;
|
||||
mod function_object;
|
||||
mod index_buffer_3d_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::event_object::{event_allocator, EventObject, EventObjectWeak};
|
||||
pub use crate::avm2::object::font_object::{font_allocator, FontObject, FontObjectWeak};
|
||||
pub use crate::avm2::object::function_object::{
|
||||
function_allocator, FunctionObject, FunctionObjectWeak,
|
||||
};
|
||||
|
@ -132,6 +134,7 @@ pub use crate::avm2::object::xml_list_object::{
|
|||
xml_list_allocator, E4XOrXml, XmlListObject, XmlListObjectWeak,
|
||||
};
|
||||
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
|
||||
/// runtime.
|
||||
|
@ -173,7 +176,8 @@ pub use crate::avm2::object::xml_object::{xml_allocator, XmlObject, XmlObjectWea
|
|||
Program3DObject(Program3DObject<'gc>),
|
||||
NetStreamObject(NetStreamObject<'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 {
|
||||
|
@ -1276,6 +1280,11 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
|
|||
None
|
||||
}
|
||||
|
||||
/// Unwrap this object as a font.
|
||||
fn as_font(&self) -> Option<Font<'gc>> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Unwrap this object as a mutable regexp.
|
||||
fn as_regexp_mut(&self, _mc: &Mutation<'gc>) -> Option<RefMut<RegExp<'gc>>> {
|
||||
None
|
||||
|
@ -1424,7 +1433,8 @@ impl<'gc> Object<'gc> {
|
|||
Self::Program3DObject(o) => WeakObject::Program3DObject(Program3DObjectWeak(Gc::downgrade(o.0))),
|
||||
Self::NetStreamObject(o) => WeakObject::NetStreamObject(NetStreamObjectWeak(GcCell::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>),
|
||||
ShaderDataObject(ShaderDataObjectWeak<'gc>),
|
||||
SocketObject(SocketObjectWeak<'gc>),
|
||||
FontObject(FontObjectWeak<'gc>),
|
||||
}
|
||||
|
||||
impl<'gc> WeakObject<'gc> {
|
||||
|
@ -1520,6 +1531,7 @@ impl<'gc> WeakObject<'gc> {
|
|||
Self::NetStreamObject(o) => NetStreamObject(o.0.upgrade(mc)?).into(),
|
||||
Self::ShaderDataObject(o) => ShaderDataObject(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