web: Move font registration to builder, not after we've made the instance

This commit is contained in:
Nathan Adams 2024-06-05 14:35:53 +02:00
parent aa804e520b
commit 85ca0aeff8
3 changed files with 105 additions and 78 deletions

View File

@ -715,17 +715,13 @@ export class RufflePlayer extends HTMLElement {
throw e;
});
configureBuilder(builder, this.loadedConfig || {});
this.instance = await builder.build(this.container, this).catch((e) => {
console.error(`Serious error loading Ruffle: ${e}`);
this.panic(e);
throw e;
});
builder.setVolume(this.volumeSettings.get_volume());
if (this.loadedConfig?.fontSources) {
for (const url of this.loadedConfig.fontSources) {
try {
const response = await fetch(url);
this.instance!.add_font(
builder.addFont(
url,
new Uint8Array(await response.arrayBuffer()),
);
@ -739,25 +735,29 @@ export class RufflePlayer extends HTMLElement {
}
if (this.loadedConfig?.defaultFonts?.sans) {
this.instance!.set_default_font(
builder.setDefaultFont(
"sans",
this.loadedConfig?.defaultFonts.sans,
);
}
if (this.loadedConfig?.defaultFonts?.serif) {
this.instance!.set_default_font(
builder!.setDefaultFont(
"serif",
this.loadedConfig?.defaultFonts.serif,
);
}
if (this.loadedConfig?.defaultFonts?.typewriter) {
this.instance!.set_default_font(
builder!.setDefaultFont(
"typewriter",
this.loadedConfig?.defaultFonts.typewriter,
);
}
this.instance!.set_volume(this.volumeSettings.get_volume());
this.instance = await builder.build(this.container, this).catch((e) => {
console.error(`Serious error loading Ruffle: ${e}`);
this.panic(e);
throw e;
});
this.rendererDebugInfo = this.instance!.renderer_debug_info();

View File

@ -1,10 +1,12 @@
use crate::{set_panic_hook, JavascriptPlayer, RuffleHandle, SocketProxy, RUFFLE_GLOBAL_PANIC};
use js_sys::Promise;
use ruffle_core::backend::navigator::OpenURLMode;
use ruffle_core::backend::ui::FontDefinition;
use ruffle_core::compatibility_rules::CompatibilityRules;
use ruffle_core::config::{Letterbox, NetworkingAccessMode};
use ruffle_core::{Color, PlayerRuntime, StageAlign, StageScaleMode};
use ruffle_core::{swf, Color, DefaultFont, Player, PlayerRuntime, StageAlign, StageScaleMode};
use ruffle_render::quality::StageQuality;
use std::collections::HashMap;
use std::str::FromStr;
use std::time::Duration;
use wasm_bindgen::prelude::*;
@ -37,8 +39,9 @@ pub struct RuffleInstanceBuilder {
pub(crate) socket_proxy: Vec<SocketProxy>,
pub(crate) credential_allow_list: Vec<String>,
pub(crate) player_runtime: PlayerRuntime,
// TODO: Add font related options
// TODO: Add volume
pub(crate) volume: f32,
pub(crate) default_fonts: HashMap<DefaultFont, Vec<String>>,
pub(crate) custom_fonts: Vec<(String, Vec<u8>)>,
}
impl Default for RuffleInstanceBuilder {
@ -72,6 +75,9 @@ impl Default for RuffleInstanceBuilder {
socket_proxy: vec![],
credential_allow_list: vec![],
player_runtime: PlayerRuntime::FlashPlayer,
volume: 1.0,
default_fonts: HashMap::new(),
custom_fonts: vec![],
}
}
}
@ -262,6 +268,35 @@ impl RuffleInstanceBuilder {
};
}
#[wasm_bindgen(js_name = "setVolume")]
pub fn set_volume(&mut self, value: f32) {
self.volume = value;
}
#[wasm_bindgen(js_name = "addFont")]
pub fn add_font(&mut self, font_name: String, data: Vec<u8>) {
self.custom_fonts.push((font_name, data))
}
#[wasm_bindgen(js_name = "setDefaultFont")]
pub fn set_default_font(&mut self, default_name: &str, fonts: Vec<JsValue>) {
let default = match default_name {
"sans" => DefaultFont::Sans,
"serif" => DefaultFont::Serif,
"typewriter" => DefaultFont::Typewriter,
_ => {
return;
}
};
self.default_fonts.insert(
default,
fonts
.into_iter()
.flat_map(|value| value.as_string())
.collect(),
);
}
// TODO: This should be split into two methods that either load url or load data
// Right now, that's done immediately afterwards in TS
pub async fn build(&self, parent: HtmlElement, js_player: JavascriptPlayer) -> Promise {
@ -281,3 +316,54 @@ 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_bold,
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?)");
}
for (default, names) in &self.default_fonts {
player.set_default_font(*default, names.clone());
}
}
}

View File

@ -15,12 +15,10 @@ use crate::builder::RuffleInstanceBuilder;
use external_interface::{external_to_js_value, js_to_external_value, JavascriptInterface};
use input::{web_key_to_codepoint, web_to_ruffle_key_code, web_to_ruffle_text_control};
use js_sys::{Error as JsError, Uint8Array};
use ruffle_core::backend::ui::FontDefinition;
use ruffle_core::config::NetworkingAccessMode;
use ruffle_core::context::UpdateContext;
use ruffle_core::events::{MouseButton, MouseWheelDelta, TextControlCode};
use ruffle_core::tag_utils::SwfMovie;
use ruffle_core::{swf, DefaultFont};
use ruffle_core::{
Player, PlayerBuilder, PlayerEvent, SandboxType, StaticCallstack, ViewportDimensions,
};
@ -332,65 +330,6 @@ impl RuffleHandle {
// Instance is dropped at this point.
}
pub fn add_font(&mut self, font_name: &str, data: Uint8Array) {
let _ = self.with_core_mut(|core| {
let bytes: Vec<u8> = data.to_vec();
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)
);
core.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}");
core.register_device_font(FontDefinition::FontFile { name: name.to_string(), is_bold: font.is_bold, is_italic: font.is_bold, data: data.to_vec(), index: 0 })
} else {
tracing::warn!("Font {name} from font swf {font_name} contains no data");
}
}
_ => {}
}
}
return;
}
}
tracing::warn!("Font source {font_name} was not recognised (not a valid SWF?)");
});
}
pub fn set_default_font(&mut self, default_name: &str, fonts: Vec<JsValue>) {
let _ = self.with_core_mut(|core| {
let default = match default_name {
"sans" => DefaultFont::Sans,
"serif" => DefaultFont::Serif,
"typewriter" => DefaultFont::Typewriter,
name => {
tracing::error!("Unknown default font name '{name}'");
return;
}
};
core.set_default_font(
default,
fonts
.into_iter()
.flat_map(|value| value.as_string())
.collect(),
);
});
}
#[allow(clippy::boxed_local)] // for js_bind
pub fn call_exposed_callback(&self, name: &str, args: Box<[JsValue]>) -> JsValue {
let args: Vec<_> = args.iter().map(js_to_external_value).collect();
@ -481,11 +420,11 @@ impl RuffleHandle {
allow_script_access,
allow_networking,
config.upgrade_to_https,
config.base_url,
config.base_url.clone(),
log_subscriber.clone(),
config.open_url_mode,
config.socket_proxy,
config.credential_allow_list,
config.socket_proxy.clone(),
config.credential_allow_list.clone(),
));
match window.local_storage() {
@ -514,7 +453,7 @@ impl RuffleHandle {
.with_max_execution_duration(config.max_execution_duration)
.with_player_version(config.player_version)
.with_player_runtime(config.player_runtime)
.with_compatibility_rules(config.compatibility_rules)
.with_compatibility_rules(config.compatibility_rules.clone())
.with_quality(config.quality)
.with_align(config.stage_align, config.force_align)
.with_scale_mode(config.scale, config.force_scale)
@ -527,10 +466,12 @@ impl RuffleHandle {
let mut callstack = None;
if let Ok(mut core) = core.try_lock() {
// Set config parameters.
core.set_volume(config.volume);
core.set_background_color(config.background_color);
core.set_show_menu(config.show_menu);
core.set_allow_fullscreen(config.allow_fullscreen);
core.set_window_mode(config.wmode.as_deref().unwrap_or("window"));
config.setup_fonts(&mut core);
callstack = Some(core.callstack());
}