core,web: Add the ability to load TTF/OTF/OTC as default fonts for the extension
This commit is contained in:
parent
e6e92dd175
commit
7d1373368b
|
@ -71,3 +71,4 @@ pub use player::{Player, PlayerBuilder, PlayerRuntime, StaticCallstack};
|
||||||
pub use ruffle_render::backend::ViewportDimensions;
|
pub use ruffle_render::backend::ViewportDimensions;
|
||||||
pub use swf;
|
pub use swf;
|
||||||
pub use swf::Color;
|
pub use swf::Color;
|
||||||
|
pub use ttf_parser;
|
||||||
|
|
|
@ -595,7 +595,9 @@ impl<'gc> Library<'gc> {
|
||||||
let font =
|
let font =
|
||||||
Font::from_swf_tag(gc_context, renderer, tag, encoding, FontType::Device);
|
Font::from_swf_tag(gc_context, renderer, tag, encoding, FontType::Device);
|
||||||
let name = font.descriptor().name().to_owned();
|
let name = font.descriptor().name().to_owned();
|
||||||
info!("Loaded new device font \"{name}\" from swf tag");
|
let is_bold = font.descriptor().bold();
|
||||||
|
let is_italic = font.descriptor().italic();
|
||||||
|
info!("Loaded new device font \"{name}\" (bold: {is_bold}, italic: {is_italic}) from swf tag");
|
||||||
self.device_fonts.register(font);
|
self.device_fonts.register(font);
|
||||||
}
|
}
|
||||||
FontDefinition::FontFile {
|
FontDefinition::FontFile {
|
||||||
|
@ -614,7 +616,7 @@ impl<'gc> Library<'gc> {
|
||||||
FontType::Device,
|
FontType::Device,
|
||||||
) {
|
) {
|
||||||
let name = font.descriptor().name().to_owned();
|
let name = font.descriptor().name().to_owned();
|
||||||
info!("Loaded new device font \"{name}\" from file");
|
info!("Loaded new device font \"{name}\" (bold: {is_bold}, italic: {is_italic}) from file");
|
||||||
self.device_fonts.register(font);
|
self.device_fonts.register(font);
|
||||||
} else {
|
} else {
|
||||||
warn!("Failed to load device font from file");
|
warn!("Failed to load device font from file");
|
||||||
|
|
|
@ -11,6 +11,7 @@ use ruffle_core::backend::storage::{MemoryStorageBackend, StorageBackend};
|
||||||
use ruffle_core::backend::ui::FontDefinition;
|
use ruffle_core::backend::ui::FontDefinition;
|
||||||
use ruffle_core::compatibility_rules::CompatibilityRules;
|
use ruffle_core::compatibility_rules::CompatibilityRules;
|
||||||
use ruffle_core::config::{Letterbox, NetworkingAccessMode};
|
use ruffle_core::config::{Letterbox, NetworkingAccessMode};
|
||||||
|
use ruffle_core::ttf_parser;
|
||||||
use ruffle_core::{
|
use ruffle_core::{
|
||||||
swf, Color, DefaultFont, Player, PlayerBuilder, PlayerRuntime, StageAlign, StageScaleMode,
|
swf, Color, DefaultFont, Player, PlayerBuilder, PlayerRuntime, StageAlign, StageScaleMode,
|
||||||
};
|
};
|
||||||
|
@ -339,6 +340,27 @@ impl RuffleInstanceBuilder {
|
||||||
impl RuffleInstanceBuilder {
|
impl RuffleInstanceBuilder {
|
||||||
pub fn setup_fonts(&self, player: &mut Player) {
|
pub fn setup_fonts(&self, player: &mut Player) {
|
||||||
for (font_name, bytes) in &self.custom_fonts {
|
for (font_name, bytes) in &self.custom_fonts {
|
||||||
|
let bytes_slice = &bytes[..];
|
||||||
|
if let Ok(face) = ttf_parser::Face::parse(bytes_slice, 0) {
|
||||||
|
tracing::debug!("Loading font {font_name} as TTF/OTF/TTC/OTC font");
|
||||||
|
|
||||||
|
// Check if font collection
|
||||||
|
let number_of_fonts = ttf_parser::fonts_in_collection(bytes_slice).unwrap_or(1u32);
|
||||||
|
|
||||||
|
Self::register_ttf_face_by_name(font_name, bytes.clone(), face, 0, player);
|
||||||
|
|
||||||
|
// Register all remaining fonts in the collection if it is a collection
|
||||||
|
for i in 1u32..number_of_fonts {
|
||||||
|
if let Ok(face) = ttf_parser::Face::parse(bytes_slice, i) {
|
||||||
|
Self::register_ttf_face_by_name(font_name, bytes.clone(), face, i, player);
|
||||||
|
} else {
|
||||||
|
tracing::warn!(
|
||||||
|
"Failed to parse font {font_name} at index {i} in font collection"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tracing::debug!("Loading font {font_name} as SWF font");
|
||||||
if let Ok(swf_stream) = swf::decompress_swf(&bytes[..]) {
|
if let Ok(swf_stream) = swf::decompress_swf(&bytes[..]) {
|
||||||
if let Ok(swf) = swf::parse_swf(&swf_stream) {
|
if let Ok(swf) = swf::parse_swf(&swf_stream) {
|
||||||
let encoding = swf::SwfStr::encoding_for_version(swf.header.version());
|
let encoding = swf::SwfStr::encoding_for_version(swf.header.version());
|
||||||
|
@ -352,13 +374,16 @@ impl RuffleInstanceBuilder {
|
||||||
"Loaded font {} from font swf {font_name}",
|
"Loaded font {} from font swf {font_name}",
|
||||||
font.name.to_str_lossy(encoding)
|
font.name.to_str_lossy(encoding)
|
||||||
);
|
);
|
||||||
player
|
player.register_device_font(FontDefinition::SwfTag(
|
||||||
.register_device_font(FontDefinition::SwfTag(*font, encoding));
|
*font, encoding,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
swf::Tag::DefineFont4(font) => {
|
swf::Tag::DefineFont4(font) => {
|
||||||
let name = font.name.to_str_lossy(encoding);
|
let name = font.name.to_str_lossy(encoding);
|
||||||
if let Some(data) = font.data {
|
if let Some(data) = font.data {
|
||||||
tracing::debug!("Loaded font {name} from font swf {font_name}");
|
tracing::debug!(
|
||||||
|
"Loaded font {name} from font swf {font_name}"
|
||||||
|
);
|
||||||
player.register_device_font(FontDefinition::FontFile {
|
player.register_device_font(FontDefinition::FontFile {
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
is_bold: font.is_bold,
|
is_bold: font.is_bold,
|
||||||
|
@ -380,12 +405,43 @@ impl RuffleInstanceBuilder {
|
||||||
}
|
}
|
||||||
tracing::warn!("Font source {font_name} was not recognised (not a valid SWF?)");
|
tracing::warn!("Font source {font_name} was not recognised (not a valid SWF?)");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (default, names) in &self.default_fonts {
|
for (default, names) in &self.default_fonts {
|
||||||
player.set_default_font(*default, names.clone());
|
player.set_default_font(*default, names.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn register_ttf_face_by_name(
|
||||||
|
url: &String,
|
||||||
|
bytes: Vec<u8>,
|
||||||
|
face: ttf_parser::Face<'_>,
|
||||||
|
index: u32,
|
||||||
|
player: &mut Player,
|
||||||
|
) {
|
||||||
|
let full_name = face
|
||||||
|
.names()
|
||||||
|
.into_iter()
|
||||||
|
.find(|name| name.name_id == ttf_parser::name_id::FULL_NAME)
|
||||||
|
.and_then(|name| name.to_string());
|
||||||
|
|
||||||
|
let name = if let Some(full_name) = full_name {
|
||||||
|
full_name
|
||||||
|
} else {
|
||||||
|
tracing::warn!("Font {url} at index {index} has no full name, using URL as font name");
|
||||||
|
url.to_string()
|
||||||
|
};
|
||||||
|
|
||||||
|
player.register_device_font(FontDefinition::FontFile {
|
||||||
|
name: name.to_string(),
|
||||||
|
is_bold: face.is_bold(),
|
||||||
|
is_italic: face.is_italic(),
|
||||||
|
data: bytes,
|
||||||
|
index,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
pub fn create_log_subscriber(&self) -> Arc<Layered<WASMLayer, Registry>> {
|
pub fn create_log_subscriber(&self) -> Arc<Layered<WASMLayer, Registry>> {
|
||||||
let layer = WASMLayer::new(
|
let layer = WASMLayer::new(
|
||||||
WASMLayerConfigBuilder::new()
|
WASMLayerConfigBuilder::new()
|
||||||
|
|
Loading…
Reference in New Issue