core: Wrap Font in a Gc
This commit is contained in:
parent
289e0b8aff
commit
0f3bad8f1b
|
@ -9,7 +9,7 @@ pub enum Character<'gc> {
|
|||
MovieClip(MovieClip<'gc>),
|
||||
Bitmap(Bitmap<'gc>),
|
||||
Button(Button<'gc>),
|
||||
Font(Box<Font>),
|
||||
Font(Font<'gc>),
|
||||
MorphShape(MorphShape<'gc>),
|
||||
Text(Text<'gc>),
|
||||
Sound(SoundHandle),
|
||||
|
|
|
@ -1245,10 +1245,10 @@ impl<'gc, 'a> MovieClipData<'gc> {
|
|||
is_bold: false,
|
||||
is_italic: false,
|
||||
};
|
||||
let font_object = Font::from_swf_tag(context.renderer, &font).unwrap();
|
||||
let font_object = Font::from_swf_tag(context.gc_context, context.renderer, &font).unwrap();
|
||||
context
|
||||
.library
|
||||
.register_character(font.id, Character::Font(Box::new(font_object)));
|
||||
.register_character(font.id, Character::Font(font_object));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -1259,10 +1259,10 @@ impl<'gc, 'a> MovieClipData<'gc> {
|
|||
reader: &mut SwfStream<&'a [u8]>,
|
||||
) -> DecodeResult {
|
||||
let font = reader.read_define_font_2(2)?;
|
||||
let font_object = Font::from_swf_tag(context.renderer, &font).unwrap();
|
||||
let font_object = Font::from_swf_tag(context.gc_context, context.renderer, &font).unwrap();
|
||||
context
|
||||
.library
|
||||
.register_character(font.id, Character::Font(Box::new(font_object)));
|
||||
.register_character(font.id, Character::Font(font_object));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -1273,10 +1273,10 @@ impl<'gc, 'a> MovieClipData<'gc> {
|
|||
reader: &mut SwfStream<&'a [u8]>,
|
||||
) -> DecodeResult {
|
||||
let font = reader.read_define_font_2(3)?;
|
||||
let font_object = Font::from_swf_tag(context.renderer, &font).unwrap();
|
||||
let font_object = Font::from_swf_tag(context.gc_context, context.renderer, &font).unwrap();
|
||||
context
|
||||
.library
|
||||
.register_character(font.id, Character::Font(Box::new(font_object)));
|
||||
.register_character(font.id, Character::Font(font_object));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,10 +1,16 @@
|
|||
use crate::backend::render::{RenderBackend, ShapeHandle};
|
||||
use crate::prelude::*;
|
||||
use gc_arena::{Collect, Gc, MutationContext};
|
||||
|
||||
type Error = Box<dyn std::error::Error>;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Font {
|
||||
#[derive(Debug, Clone, Collect, Copy)]
|
||||
#[collect(no_drop)]
|
||||
pub struct Font<'gc>(Gc<'gc, FontData>);
|
||||
|
||||
#[derive(Debug, Clone, Collect)]
|
||||
#[collect(require_static)]
|
||||
struct FontData {
|
||||
/// The list of glyphs defined in the font.
|
||||
/// Used directly by `DefineText` tags.
|
||||
glyphs: Vec<Glyph>,
|
||||
|
@ -22,8 +28,12 @@ pub struct Font {
|
|||
kerning_pairs: fnv::FnvHashMap<(u16, u16), Twips>,
|
||||
}
|
||||
|
||||
impl Font {
|
||||
pub fn from_swf_tag(renderer: &mut dyn RenderBackend, tag: &swf::Font) -> Result<Font, Error> {
|
||||
impl<'gc> Font<'gc> {
|
||||
pub fn from_swf_tag(
|
||||
gc_context: MutationContext<'gc, '_>,
|
||||
renderer: &mut dyn RenderBackend,
|
||||
tag: &swf::Font,
|
||||
) -> Result<Font<'gc>, Error> {
|
||||
let mut glyphs = vec![];
|
||||
let mut code_point_to_glyph = fnv::FnvHashMap::default();
|
||||
for swf_glyph in &tag.glyphs {
|
||||
|
@ -44,7 +54,9 @@ impl Font {
|
|||
} else {
|
||||
fnv::FnvHashMap::default()
|
||||
};
|
||||
Ok(Font {
|
||||
Ok(Font(Gc::allocate(
|
||||
gc_context,
|
||||
FontData {
|
||||
glyphs,
|
||||
code_point_to_glyph,
|
||||
|
||||
|
@ -52,28 +64,28 @@ impl Font {
|
|||
/// (SWF19 p.164)
|
||||
scale: if tag.version >= 3 { 20480.0 } else { 1024.0 },
|
||||
kerning_pairs,
|
||||
})
|
||||
},
|
||||
)))
|
||||
}
|
||||
|
||||
/// Returns whether this font contains glyph shapes.
|
||||
/// If not, this font should be rendered as a device font.
|
||||
#[inline]
|
||||
pub fn has_glyphs(&self) -> bool {
|
||||
!self.glyphs.is_empty()
|
||||
pub fn has_glyphs(self) -> bool {
|
||||
!self.0.glyphs.is_empty()
|
||||
}
|
||||
|
||||
/// Returns a glyph entry by index.
|
||||
/// Used by `Text` display objects.
|
||||
pub fn get_glyph(&self, i: usize) -> Option<Glyph> {
|
||||
self.glyphs.get(i).cloned()
|
||||
pub fn get_glyph(self, i: usize) -> Option<Glyph> {
|
||||
self.0.glyphs.get(i).cloned()
|
||||
}
|
||||
|
||||
/// Returns a glyph entry by character.
|
||||
/// Used by `EditText` display objects.
|
||||
pub fn get_glyph_for_char(&self, c: char) -> Option<Glyph> {
|
||||
pub fn get_glyph_for_char(self, c: char) -> Option<Glyph> {
|
||||
// TODO: Properly handle UTF-16/out-of-bounds code points.
|
||||
let code_point = c as u16;
|
||||
if let Some(index) = self.code_point_to_glyph.get(&code_point) {
|
||||
if let Some(index) = self.0.code_point_to_glyph.get(&code_point) {
|
||||
self.get_glyph(*index)
|
||||
} else {
|
||||
None
|
||||
|
@ -83,25 +95,24 @@ impl Font {
|
|||
/// Given a pair of characters, applies the offset that should be applied
|
||||
/// to the advance value between these two characters.
|
||||
/// Returns 0 twips if no kerning offset exists between these two characters.
|
||||
pub fn get_kerning_offset(&self, left: char, right: char) -> Twips {
|
||||
pub fn get_kerning_offset(self, left: char, right: char) -> Twips {
|
||||
// TODO: Properly handle UTF-16/out-of-bounds code points.
|
||||
let left_code_point = left as u16;
|
||||
let right_code_point = right as u16;
|
||||
self.kerning_pairs
|
||||
self.0
|
||||
.kerning_pairs
|
||||
.get(&(left_code_point, right_code_point))
|
||||
.cloned()
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
/// Returns whether this font contains kerning information.
|
||||
#[inline]
|
||||
pub fn has_kerning_info(&self) -> bool {
|
||||
!self.kerning_pairs.is_empty()
|
||||
pub fn has_kerning_info(self) -> bool {
|
||||
!self.0.kerning_pairs.is_empty()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn scale(&self) -> f32 {
|
||||
self.scale
|
||||
pub fn scale(self) -> f32 {
|
||||
self.0.scale
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ pub struct Library<'gc> {
|
|||
characters: HashMap<CharacterId, Character<'gc>>,
|
||||
export_characters: HashMap<String, Character<'gc>>,
|
||||
jpeg_tables: Option<Vec<u8>>,
|
||||
device_font: Option<Box<Font>>,
|
||||
device_font: Option<Font<'gc>>,
|
||||
}
|
||||
|
||||
impl<'gc> Library<'gc> {
|
||||
|
@ -106,8 +106,8 @@ impl<'gc> Library<'gc> {
|
|||
Ok(obj)
|
||||
}
|
||||
|
||||
pub fn get_font(&self, id: CharacterId) -> Option<&Font> {
|
||||
if let Some(&Character::Font(ref font)) = self.characters.get(&id) {
|
||||
pub fn get_font(&self, id: CharacterId) -> Option<Font<'gc>> {
|
||||
if let Some(&Character::Font(font)) = self.characters.get(&id) {
|
||||
Some(font)
|
||||
} else {
|
||||
None
|
||||
|
@ -143,12 +143,12 @@ impl<'gc> Library<'gc> {
|
|||
}
|
||||
|
||||
/// Returns the device font for use when a font is unavailable.
|
||||
pub fn device_font(&self) -> Option<&Font> {
|
||||
self.device_font.as_ref().map(AsRef::as_ref)
|
||||
pub fn device_font(&self) -> Option<Font<'gc>> {
|
||||
self.device_font
|
||||
}
|
||||
|
||||
/// Sets the device font.
|
||||
pub fn set_device_font(&mut self, font: Option<Box<Font>>) {
|
||||
pub fn set_device_font(&mut self, font: Option<Font<'gc>>) {
|
||||
self.device_font = font;
|
||||
}
|
||||
}
|
||||
|
@ -159,6 +159,7 @@ unsafe impl<'gc> gc_arena::Collect for Library<'gc> {
|
|||
for character in self.characters.values() {
|
||||
character.trace(cc);
|
||||
}
|
||||
self.device_font.trace(cc);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -141,16 +141,6 @@ impl<Audio: AudioBackend, Renderer: RenderBackend, Navigator: NavigatorBackend>
|
|||
let movie_width = (header.stage_size.x_max - header.stage_size.x_min).to_pixels() as u32;
|
||||
let movie_height = (header.stage_size.y_max - header.stage_size.y_min).to_pixels() as u32;
|
||||
|
||||
// Load and parse the device font.
|
||||
// TODO: We could use lazy_static here.
|
||||
let device_font = match Self::load_device_font(DEVICE_FONT_TAG, &mut renderer) {
|
||||
Ok(font) => Some(font),
|
||||
Err(e) => {
|
||||
log::error!("Unable to load device font: {}", e);
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
let mut player = Player {
|
||||
player_version: NEWEST_PLAYER_VERSION,
|
||||
|
||||
|
@ -159,10 +149,6 @@ impl<Audio: AudioBackend, Renderer: RenderBackend, Navigator: NavigatorBackend>
|
|||
|
||||
is_playing: false,
|
||||
|
||||
renderer,
|
||||
audio,
|
||||
navigator,
|
||||
|
||||
background_color: Color {
|
||||
r: 255,
|
||||
g: 255,
|
||||
|
@ -176,6 +162,16 @@ impl<Audio: AudioBackend, Renderer: RenderBackend, Navigator: NavigatorBackend>
|
|||
rng: SmallRng::from_seed([0u8; 16]), // TODO(Herschel): Get a proper seed on all platforms.
|
||||
|
||||
gc_arena: GcArena::new(ArenaParameters::default(), |gc_context| {
|
||||
// Load and parse the device font.
|
||||
let device_font =
|
||||
match Self::load_device_font(gc_context, DEVICE_FONT_TAG, &mut renderer) {
|
||||
Ok(font) => Some(font),
|
||||
Err(e) => {
|
||||
log::error!("Unable to load device font: {}", e);
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
let mut library = Library::new();
|
||||
library.set_device_font(device_font);
|
||||
GcRoot(GcCell::allocate(
|
||||
|
@ -210,6 +206,10 @@ impl<Audio: AudioBackend, Renderer: RenderBackend, Navigator: NavigatorBackend>
|
|||
|
||||
mouse_pos: (Twips::new(0), Twips::new(0)),
|
||||
is_mouse_down: false,
|
||||
|
||||
renderer,
|
||||
audio,
|
||||
navigator,
|
||||
};
|
||||
|
||||
player.gc_arena.mutate(|gc_context, gc_root| {
|
||||
|
@ -674,15 +674,14 @@ impl<Audio: AudioBackend, Renderer: RenderBackend, Navigator: NavigatorBackend>
|
|||
/// Loads font data from the given buffer.
|
||||
/// The buffer should be the `DefineFont3` info for the tag.
|
||||
/// The tag header should not be included.
|
||||
fn load_device_font(
|
||||
fn load_device_font<'gc>(
|
||||
gc_context: gc_arena::MutationContext<'gc, '_>,
|
||||
data: &[u8],
|
||||
renderer: &mut Renderer,
|
||||
) -> Result<Box<crate::font::Font>, Error> {
|
||||
) -> Result<crate::font::Font<'gc>, Error> {
|
||||
let mut reader = swf::read::Reader::new(data, 8);
|
||||
let device_font = Box::new(crate::font::Font::from_swf_tag(
|
||||
renderer,
|
||||
&reader.read_define_font_2(3)?,
|
||||
)?);
|
||||
let device_font =
|
||||
crate::font::Font::from_swf_tag(gc_context, renderer, &reader.read_define_font_2(3)?)?;
|
||||
Ok(device_font)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue