Generate registration code for custom fonts imported in .60 files

This removes the need to manually register fonts. This is initially
applied to the printer demo, but the other demos and removal of the
public manual registration API will come in follow-up commits.
This commit is contained in:
Simon Hausmann 2021-04-13 16:44:18 +02:00
parent c301cc22b5
commit f7ce1ba8b4
13 changed files with 138 additions and 30 deletions

View file

@ -15,9 +15,6 @@ if (NOT TARGET SixtyFPS::SixtyFPS)
endif()
add_executable(printerdemo main.cpp)
target_compile_definitions(printerdemo PRIVATE
FONTS_DIR=\"${CMAKE_CURRENT_SOURCE_DIR}/../ui/fonts\"
)
if (MSVC)
target_compile_options(printerdemo PRIVATE /bigobj)
endif()

View file

@ -22,12 +22,6 @@ struct InkLevelModel : sixtyfps::Model<InkLevel>
int main()
{
if (auto error = sixtyfps::register_font_from_path(FONTS_DIR "/NotoSans-Regular.ttf")) {
fprintf(stderr, "Error registering Noto Sans Regular font: %s\n", error->data());
}
if (auto error = sixtyfps::register_font_from_path(FONTS_DIR "/NotoSans-Bold.ttf")) {
fprintf(stderr, "Error registering Noto Sans Bold font: %s\n", error->data());
}
auto printer_demo = MainWindow::create();
printer_demo->set_ink_levels(std::make_shared<InkLevelModel>());
printer_demo->on_quit([] { std::exit(0); });

View file

@ -16,7 +16,6 @@ endif()
add_executable(printerdemo_interpreted main.cpp)
target_compile_definitions(printerdemo_interpreted PRIVATE
FONTS_DIR=\"${CMAKE_CURRENT_SOURCE_DIR}/../ui/fonts\"
SOURCE_DIR=\"${CMAKE_CURRENT_SOURCE_DIR}\"
)
if (MSVC)

View file

@ -35,13 +35,6 @@ private:
int main()
{
if (auto error = sixtyfps::register_font_from_path(FONTS_DIR "/NotoSans-Regular.ttf")) {
fprintf(stderr, "Error registering Noto Sans Regular font: %s\n", error->data());
}
if (auto error = sixtyfps::register_font_from_path(FONTS_DIR "/NotoSans-Bold.ttf")) {
fprintf(stderr, "Error registering Noto Sans Bold font: %s\n", error->data());
}
sixtyfps::interpreter::ComponentCompiler compiler;
auto definition = compiler.build_from_path(SOURCE_DIR "/../ui/printerdemo.60");

View file

@ -12,14 +12,6 @@ LICENSE END */
const path = require("path");
let sixtyfps = require("sixtyfps");
try {
for (font_file of ["NotoSans-Regular.ttf", "NotoSans-Bold.ttf"]) {
sixtyfps.register_font_from_path(path.resolve(__dirname, "../ui/fonts", font_file));
}
} catch (load_exception) {
console.error(load_exception);
}
let demo = require("../ui/printerdemo.60");
let window = new demo.MainWindow();

View file

@ -41,11 +41,6 @@ pub fn main() {
#[cfg(all(debug_assertions, target_arch = "wasm32"))]
console_error_panic_hook::set_once();
sixtyfps::register_font_from_memory(include_bytes!("../ui/fonts/NotoSans-Regular.ttf"))
.expect("error registering noto sans regular");
sixtyfps::register_font_from_memory(include_bytes!("../ui/fonts/NotoSans-Bold.ttf"))
.expect("error registering noto sans bold");
let main_window = MainWindow::new();
main_window.set_ink_levels(sixtyfps::VecModel::from_slice(&[
InkLevel { color: sixtyfps::Color::from_rgb_u8(0, 255, 255), level: 0.40 },

View file

@ -13,6 +13,8 @@ import { HomePage } from "./home_page.60";
import { InkLevel, InkPage } from "./ink_page.60";
import { SettingsPage } from "./settings_page.60";
import "./fonts/NotoSans-Regular.ttf";
import "./fonts/NotoSans-Bold.ttf";
SideBarIcon := Rectangle {
property <bool> active;

View file

@ -44,6 +44,8 @@ pub enum BuiltinFunction {
ColorDarker,
Rgb,
ImplicitItemSize,
RegisterCustomFontByPath,
RegisterCustomFontByMemory,
}
#[derive(Debug, Clone)]
@ -119,6 +121,12 @@ impl BuiltinFunction {
return_type: Box::new(Type::Color),
args: vec![Type::Int32, Type::Int32, Type::Int32, Type::Float32],
},
BuiltinFunction::RegisterCustomFontByPath => {
Type::Function { return_type: Box::new(Type::Void), args: vec![Type::String] }
}
BuiltinFunction::RegisterCustomFontByMemory => {
Type::Function { return_type: Box::new(Type::Void), args: vec![Type::Int32] }
}
}
}
}

View file

@ -1439,6 +1439,12 @@ fn compile_expression(
BuiltinFunction::Rgb => {
"[](int r, int g, int b, float a) {{ return sixtyfps::Color::from_argb_uint8(std::clamp(a * 255., 0., 255.), std::clamp(r, 0, 255), std::clamp(g, 0, 255), std::clamp(b, 0, 255)); }}".into()
}
BuiltinFunction::RegisterCustomFontByPath => {
panic!("internal error: RegisterCustomFontByPath can only be evaluated from within a FunctionCall expression")
}
BuiltinFunction::RegisterCustomFontByMemory => {
panic!("embedding fonts is not supported in C++ yet")
}
},
Expression::ElementReference(_) => todo!("Element references are only supported in the context of built-in function calls at the moment"),
Expression::MemberFunction { .. } => panic!("member function expressions must not appear in the code generator anymore"),
@ -1574,6 +1580,16 @@ fn compile_expression(
panic!("internal error: argument to ImplicitItemSize must be an element")
}
}
Expression::BuiltinFunctionReference(BuiltinFunction::RegisterCustomFontByPath) => {
if arguments.len() != 1 {
panic!("internal error: incorrect argument count to RegisterCustomFontByPath call");
}
if let Expression::StringLiteral(font_path) = &arguments[0] {
format!("sixtyfps::register_font_from_path(\"{}\");", font_path)
} else {
panic!("internal error: argument to RegisterCustomFontByPath must be a string literal")
}
}
_ => {
let mut args = arguments.iter().map(|e| compile_expression(e, component));

View file

@ -1123,6 +1123,12 @@ fn compile_expression(expr: &Expression, component: &Rc<Component>) -> TokenStre
sixtyfps::re_exports::Color::from_argb_u8(a, r, g, b)
}))
}
BuiltinFunction::RegisterCustomFontByPath => {
panic!("internal error: BuiltinFunction::RegisterCustomFontByPath can only be compiled as part of a FunctionCall expression")
}
BuiltinFunction::RegisterCustomFontByMemory => {
panic!("internal error: BuiltinFunction::RegisterCustomFontByMemory can only be compiled as part of a FunctionCall expression")
}
},
Expression::ElementReference(_) => todo!("Element references are only supported in the context of built-in function calls at the moment"),
Expression::MemberFunction{ .. } => panic!("member function expressions must not appear in the code generator anymore"),
@ -1232,6 +1238,28 @@ fn compile_expression(expr: &Expression, component: &Rc<Component>) -> TokenStre
panic!("internal error: argument to ImplicitItemSize must be an element")
}
}
Expression::BuiltinFunctionReference(BuiltinFunction::RegisterCustomFontByPath) => {
if arguments.len() != 1 {
panic!("internal error: incorrect argument count to RegisterCustomFontByPath call");
}
if let Expression::StringLiteral(path) = &arguments[0] {
quote!(sixtyfps::register_font_from_path(&std::path::PathBuf::from(#path)))
} else {
panic!("internal error: argument to RegisterCustomFontByPath must be a string literal")
}
}
Expression::BuiltinFunctionReference(BuiltinFunction::RegisterCustomFontByMemory) => {
if arguments.len() != 1 {
panic!("internal error: incorrect argument count to RegisterCustomFontByMemory call");
}
if let Expression::NumberLiteral(resource_id, _) = &arguments[0] {
let resource_id: usize = *resource_id as _;
let symbol = format_ident!("SFPS_EMBEDDED_RESOURCE_{}", resource_id);
quote!(sixtyfps::register_font_from_memory(#symbol.into()))
} else {
panic!("internal error: argument to RegisterCustomFontByMemory must be a number")
}
}
_ => {
let f = compile_expression(function, &component);
let a = arguments.iter().map(|a| compile_expression(a, &component));

View file

@ -45,6 +45,7 @@ mod passes {
pub mod apply_default_properties_from_style;
pub mod check_expressions;
pub mod clip;
pub mod collect_custom_fonts;
pub mod collect_globals;
pub mod collect_structs;
pub mod compile_paths;
@ -192,6 +193,11 @@ pub async fn run_passes(
passes::collect_globals::collect_globals(&doc.root_component, diag);
passes::collect_structs::collect_structs(&doc.root_component, diag);
passes::generate_item_indices::generate_item_indices(&doc.root_component);
passes::collect_custom_fonts::collect_custom_fonts(
&doc.root_component,
std::iter::once(&*doc).chain(type_loader.all_documents()),
compiler_config.embed_resources,
);
}
mod library {

View file

@ -0,0 +1,67 @@
/* LICENSE BEGIN
This file is part of the SixtyFPS Project -- https://sixtyfps.io
Copyright (c) 2020 Olivier Goffart <olivier.goffart@sixtyfps.io>
Copyright (c) 2020 Simon Hausmann <simon.hausmann@sixtyfps.io>
SPDX-License-Identifier: GPL-3.0-only
This file is also available under commercial licensing terms.
Please contact info@sixtyfps.io for more information.
LICENSE END */
//! Passes that fills the root component used_global
use crate::{
expression_tree::{BuiltinFunction, Expression, Unit},
object_tree::*,
};
use std::collections::BTreeSet;
use std::rc::Rc;
/// Fill the root_component's used_globals
pub fn collect_custom_fonts<'a>(
root_component: &Rc<Component>,
all_docs: impl Iterator<Item = &'a crate::object_tree::Document> + 'a,
embed_fonts: bool,
) {
let mut all_fonts = BTreeSet::new();
for doc in all_docs {
all_fonts.extend(doc.custom_fonts.iter())
}
let registration_function = if embed_fonts {
Expression::BuiltinFunctionReference(BuiltinFunction::RegisterCustomFontByMemory)
} else {
Expression::BuiltinFunctionReference(BuiltinFunction::RegisterCustomFontByPath)
};
let prepare_font_registration_argument: Box<dyn Fn(&String) -> Expression> = if embed_fonts {
Box::new(|font_path| {
Expression::NumberLiteral(
{
let mut resources = root_component.embedded_file_resources.borrow_mut();
let resource_id = match resources.get(font_path) {
Some(id) => *id,
None => {
let id = resources.len();
resources.insert(font_path.clone(), id);
id
}
};
resource_id as _
},
Unit::None,
)
})
} else {
Box::new(|font_path| Expression::StringLiteral(font_path.clone()))
};
root_component.setup_code.borrow_mut().extend(all_fonts.into_iter().map(|font_path| {
Expression::FunctionCall {
function: Box::new(registration_function.clone()),
arguments: vec![prepare_font_registration_argument(font_path)],
source_location: None,
}
}));
}

View file

@ -421,6 +421,17 @@ pub fn eval_expression(e: &Expression, local_context: &mut EvalLocalContext) ->
panic!("internal error: argument to ImplicitItemWidth must be an element")
}
}
Expression::BuiltinFunctionReference(BuiltinFunction::RegisterCustomFontByPath) => {
if arguments.len() != 1 {
panic!("internal error: incorrect argument count to RegisterCustomFontByPath")
}
if let Value::String(s) = eval_expression(&arguments[0], local_context) {
crate::register_font_from_path(&std::path::PathBuf::from(s.as_str())).ok().unwrap();
Value::Void
} else {
panic!("Argument not a string");
}
}
_ => panic!("call of something not a callback"),
}
Expression::SelfAssignment { lhs, rhs, op } => {