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 swf;
|
||||
pub use swf::Color;
|
||||
pub use ttf_parser;
|
||||
|
|
|
@ -595,7 +595,9 @@ impl<'gc> Library<'gc> {
|
|||
let font =
|
||||
Font::from_swf_tag(gc_context, renderer, tag, encoding, FontType::Device);
|
||||
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);
|
||||
}
|
||||
FontDefinition::FontFile {
|
||||
|
@ -614,7 +616,7 @@ impl<'gc> Library<'gc> {
|
|||
FontType::Device,
|
||||
) {
|
||||
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);
|
||||
} else {
|
||||
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::compatibility_rules::CompatibilityRules;
|
||||
use ruffle_core::config::{Letterbox, NetworkingAccessMode};
|
||||
use ruffle_core::ttf_parser;
|
||||
use ruffle_core::{
|
||||
swf, Color, DefaultFont, Player, PlayerBuilder, PlayerRuntime, StageAlign, StageScaleMode,
|
||||
};
|
||||
|
@ -339,46 +340,71 @@ impl RuffleInstanceBuilder {
|
|||
impl RuffleInstanceBuilder {
|
||||
pub fn setup_fonts(&self, player: &mut Player) {
|
||||
for (font_name, bytes) in &self.custom_fonts {
|
||||
if let Ok(swf_stream) = swf::decompress_swf(&bytes[..]) {
|
||||
if let Ok(swf) = swf::parse_swf(&swf_stream) {
|
||||
let encoding = swf::SwfStr::encoding_for_version(swf.header.version());
|
||||
for tag in swf.tags {
|
||||
match tag {
|
||||
swf::Tag::DefineFont(_font) => {
|
||||
tracing::warn!("DefineFont1 tag is not yet supported by Ruffle, inside font swf {font_name}");
|
||||
}
|
||||
swf::Tag::DefineFont2(font) => {
|
||||
tracing::debug!(
|
||||
"Loaded font {} from font swf {font_name}",
|
||||
font.name.to_str_lossy(encoding)
|
||||
);
|
||||
player
|
||||
.register_device_font(FontDefinition::SwfTag(*font, encoding));
|
||||
}
|
||||
swf::Tag::DefineFont4(font) => {
|
||||
let name = font.name.to_str_lossy(encoding);
|
||||
if let Some(data) = font.data {
|
||||
tracing::debug!("Loaded font {name} from font swf {font_name}");
|
||||
player.register_device_font(FontDefinition::FontFile {
|
||||
name: name.to_string(),
|
||||
is_bold: font.is_bold,
|
||||
is_italic: font.is_italic,
|
||||
data: data.to_vec(),
|
||||
index: 0,
|
||||
})
|
||||
} else {
|
||||
tracing::warn!(
|
||||
"Font {name} from font swf {font_name} contains no data"
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
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"
|
||||
);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
tracing::debug!("Loading font {font_name} as SWF font");
|
||||
if let Ok(swf_stream) = swf::decompress_swf(&bytes[..]) {
|
||||
if let Ok(swf) = swf::parse_swf(&swf_stream) {
|
||||
let encoding = swf::SwfStr::encoding_for_version(swf.header.version());
|
||||
for tag in swf.tags {
|
||||
match tag {
|
||||
swf::Tag::DefineFont(_font) => {
|
||||
tracing::warn!("DefineFont1 tag is not yet supported by Ruffle, inside font swf {font_name}");
|
||||
}
|
||||
swf::Tag::DefineFont2(font) => {
|
||||
tracing::debug!(
|
||||
"Loaded font {} from font swf {font_name}",
|
||||
font.name.to_str_lossy(encoding)
|
||||
);
|
||||
player.register_device_font(FontDefinition::SwfTag(
|
||||
*font, encoding,
|
||||
));
|
||||
}
|
||||
swf::Tag::DefineFont4(font) => {
|
||||
let name = font.name.to_str_lossy(encoding);
|
||||
if let Some(data) = font.data {
|
||||
tracing::debug!(
|
||||
"Loaded font {name} from font swf {font_name}"
|
||||
);
|
||||
player.register_device_font(FontDefinition::FontFile {
|
||||
name: name.to_string(),
|
||||
is_bold: font.is_bold,
|
||||
is_italic: font.is_italic,
|
||||
data: data.to_vec(),
|
||||
index: 0,
|
||||
})
|
||||
} else {
|
||||
tracing::warn!(
|
||||
"Font {name} from font swf {font_name} contains no data"
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
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 {
|
||||
|
@ -386,6 +412,36 @@ impl RuffleInstanceBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
#[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>> {
|
||||
let layer = WASMLayer::new(
|
||||
WASMLayerConfigBuilder::new()
|
||||
|
|
Loading…
Reference in New Issue