Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

core: Allow Regular/Bold/Italic device fonts to be registered separately #14083

Merged
merged 1 commit into from
Nov 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions core/src/backend/ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,13 @@ pub trait UiBackend: Downcast {
/// You may call `register` any amount of times with any amount of found device fonts.
/// If you do not call `register` with any fonts that match the request,
/// then the font will simply be marked as not found - this may or may not fall back to another font.
fn load_device_font(&self, name: &str, register: &dyn FnMut(FontDefinition));
fn load_device_font(
&self,
name: &str,
is_bold: bool,
is_italic: bool,
register: &dyn FnMut(FontDefinition),
);

/// Displays a file selection dialog, returning None if the dialog cannot be displayed
/// (e.g because it is already open)
Expand Down Expand Up @@ -267,7 +273,14 @@ impl UiBackend for NullUiBackend {

fn display_unsupported_video(&self, _url: Url) {}

fn load_device_font(&self, _name: &str, _register: &dyn FnMut(FontDefinition)) {}
fn load_device_font(
&self,
_name: &str,
_is_bold: bool,
_is_italic: bool,
_register: &dyn FnMut(FontDefinition),
) {
}

fn open_virtual_keyboard(&self) {}

Expand Down
2 changes: 2 additions & 0 deletions core/src/html/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,8 @@ impl<'a, 'gc> LayoutContext<'a, 'gc> {

if let Some(font) = context.library.get_or_load_device_font(
&font_name,
span.bold,
span.italic,
context.ui,
context.renderer,
context.gc_context,
Expand Down
26 changes: 16 additions & 10 deletions core/src/library.rs
Original file line number Diff line number Diff line change
Expand Up @@ -373,15 +373,15 @@ pub struct Library<'gc> {

/// A cache of seen device fonts.
// TODO: Descriptors shouldn't be stored in fonts. Fonts should be a list that we iterate and ask "do you match". A font can have zero or many names.
device_fonts: FnvHashMap<String, Font<'gc>>,
device_fonts: FontMap<'gc>,

/// "Global" embedded fonts, registered through AVM2 `Font.registerFont`.
/// These should be checked before any Movie-specific library's own fonts.
global_fonts: FontMap<'gc>,

/// A set of which fonts we've asked from the backend already, to help with negative caching.
/// If we've asked for a specific font, record it here and don't ask again.
font_lookup_cache: FnvHashSet<String>,
font_lookup_cache: FnvHashSet<(String, bool, bool)>,

/// The implementation names of each default font.
default_font_names: FnvHashMap<DefaultFont, Vec<String>>,
Expand Down Expand Up @@ -454,7 +454,9 @@ impl<'gc> Library<'gc> {

let mut result = vec![];
for name in self.default_font_names.entry(name).or_default().clone() {
if let Some(font) = self.get_or_load_device_font(&name, ui, renderer, gc_context) {
if let Some(font) =
self.get_or_load_device_font(&name, false, false, ui, renderer, gc_context)
{
result.push(font);
}
}
Expand All @@ -467,35 +469,39 @@ impl<'gc> Library<'gc> {
pub fn get_or_load_device_font(
&mut self,
name: &str,
is_bold: bool,
is_italic: bool,
ui: &dyn UiBackend,
renderer: &mut dyn RenderBackend,
gc_context: &Mutation<'gc>,
) -> Option<Font<'gc>> {
// If we have the font already, use that
// TODO: We should instead ask each font if it matches a given name. Partial matches are allowed, and fonts may have any amount of names.
if let Some(font) = self.device_fonts.get(name) {
return Some(*font);
if let Some(font) = self.device_fonts.find(name, is_bold, is_italic) {
return Some(font);
}

// We don't have this font already. Did we ask for it before?
let new_request = self.font_lookup_cache.insert(name.to_string());
let new_request = self
.font_lookup_cache
.insert((name.to_string(), is_bold, is_italic));
if new_request {
// First time asking for this font, see if our backend can provide anything relevant
ui.load_device_font(name, &|definition| {
ui.load_device_font(name, is_bold, is_italic, &|definition| {
self.register_device_font(gc_context, renderer, definition)
});
}

// Check again. A backend may or may not have provided some new fonts,
// and they may or may not be relevant to the one we're asking for.
match self.device_fonts.get(name) {
match self.device_fonts.find(name, is_bold, is_italic) {
None => {
if new_request {
warn!("Unknown device font \"{name}\"");
}
None
}
Some(font) => Some(*font),
Some(font) => Some(font),
}
}

Expand All @@ -516,7 +522,7 @@ impl<'gc> Library<'gc> {
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");
self.device_fonts.insert(name, font);
self.device_fonts.register(font);
}
}
self.default_font_cache.clear();
Expand Down
9 changes: 8 additions & 1 deletion desktop/src/backends/ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,14 @@ impl UiBackend for DesktopUiBackend {
};
}

fn load_device_font(&self, _name: &str, _register: &dyn FnMut(FontDefinition)) {}
fn load_device_font(
&self,
_name: &str,
_is_bold: bool,
_is_italic: bool,
_register: &dyn FnMut(FontDefinition),
) {
}

// Unused on desktop
fn open_virtual_keyboard(&self) {}
Expand Down
9 changes: 8 additions & 1 deletion tests/framework/src/backends/ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,14 @@ impl UiBackend for TestUiBackend {

fn display_unsupported_video(&self, _url: Url) {}

fn load_device_font(&self, _name: &str, _register: &dyn FnMut(FontDefinition)) {}
fn load_device_font(
&self,
_name: &str,
_is_bold: bool,
_is_italic: bool,
_register: &dyn FnMut(FontDefinition),
) {
}

fn display_file_open_dialog(&mut self, filters: Vec<FileFilter>) -> Option<DialogResultFuture> {
Some(Box::pin(async move {
Expand Down
8 changes: 7 additions & 1 deletion web/src/ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,13 @@ impl UiBackend for WebUiBackend {
self.js_player.display_unsupported_video(url.as_str());
}

fn load_device_font(&self, _name: &str, _register: &dyn FnMut(FontDefinition)) {
fn load_device_font(
&self,
_name: &str,
_is_bold: bool,
_is_italic: bool,
_register: &dyn FnMut(FontDefinition),
) {
// Because fonts must be loaded instantly (no async),
// we actually just provide them all upfront at time of Player creation.
}
Expand Down