feat: Word Processor discovers fonts automatically (via 0:/fonts), UI fix

This commit is contained in:
daniel committed 2026-06-06 10:12:11 +02:00
1 parent 8341082bd6
commit 0728dd58e5
7 files changed
+435 -106

No files matched your search

+31 -52
View File
@@ -671,61 +671,28 @@ static int wp_pdf_style_index(uint8_t flags) {
return idx;
}
// Path and base-font lookups fall back to the regular variant when the
// requested style is missing, mirroring wp_get_font so a document with, say,
// bold-italic text in a regular-only family still embeds (in the regular face).
static const char* wp_pdf_font_path(uint8_t font_id, uint8_t style_index) {
static const char* PATHS[FONT_COUNT][4] = {
{
"0:/fonts/Roboto-Medium.ttf",
"0:/fonts/Roboto-Bold.ttf",
"0:/fonts/Roboto-Italic.ttf",
"0:/fonts/Roboto-BoldItalic.ttf",
},
{
"0:/fonts/NotoSerif-Regular.ttf",
"0:/fonts/NotoSerif-SemiBold.ttf",
"0:/fonts/NotoSerif-Italic.ttf",
"0:/fonts/NotoSerif-BoldItalic.ttf",
},
{
"0:/fonts/C059-Roman.ttf",
"0:/fonts/C059-Bold.ttf",
"0:/fonts/C059-Italic.ttf",
"0:/fonts/C059-Bold.ttf",
},
};
if (font_id >= FONT_COUNT || style_index > 3) return nullptr;
return PATHS[font_id][style_index];
if (font_id >= g_wp_fonts.count || style_index > 3) return nullptr;
int v = wp_resolve_variant(font_id, style_index);
if (v < 0) return nullptr;
const char* p = g_wp_fonts.families[font_id].paths[v];
return p[0] ? p : nullptr;
}
static const char* wp_pdf_base_font_name(uint8_t font_id, uint8_t style_index) {
static const char* NAMES[FONT_COUNT][4] = {
{
"Roboto-Medium",
"Roboto-Bold",
"Roboto-Italic",
"Roboto-BoldItalic",
},
{
"NotoSerif-Regular",
"NotoSerif-SemiBold",
"NotoSerif-Italic",
"NotoSerif-BoldItalic",
},
{
"C059-Roman",
"C059-Bold",
"C059-Italic",
"C059-Bold",
},
};
if (font_id >= FONT_COUNT || style_index > 3) return nullptr;
return NAMES[font_id][style_index];
if (font_id >= g_wp_fonts.count || style_index > 3) return nullptr;
int v = wp_resolve_variant(font_id, style_index);
if (v < 0) return nullptr;
const char* n = g_wp_fonts.families[font_id].basenames[v];
return n[0] ? n : nullptr;
}
static int wp_pdf_descriptor_flags(uint8_t font_id, uint8_t style_index) {
int flags = 32; // Nonsymbolic
if (font_id == FONT_NOTOSERIF || font_id == FONT_C059)
if (font_id < g_wp_fonts.count && g_wp_fonts.families[font_id].serif)
flags |= 2; // Serif
if (style_index == 2 || style_index == 3)
flags |= 64; // Italic
@@ -885,17 +852,18 @@ static bool wp_pdf_collect_fonts(WordProcessorState* wp,
if (out_count) *out_count = 0;
if (!wp || !defs) return false;
bool used[FONT_COUNT][4] = {};
bool used[WP_MAX_FONTS][4] = {};
for (int i = 0; i < wp->run_count; i++) {
StyledRun* run = &wp->runs[i];
if (run->len <= 0) continue;
int font_id = run->font_id < FONT_COUNT ? run->font_id : FONT_ROBOTO;
int font_id = run->font_id < wp_font_count() ? run->font_id : wp_default_font_id();
if (font_id < 0 || font_id >= WP_MAX_FONTS) font_id = 0;
int style_index = wp_pdf_style_index(run->flags);
used[font_id][style_index] = true;
}
int count = 0;
for (int font_id = 0; font_id < FONT_COUNT; font_id++) {
for (int font_id = 0; font_id < wp_font_count(); font_id++) {
for (int style_index = 0; style_index < 4; style_index++) {
if (!used[font_id][style_index]) continue;
if (!wp_pdf_prepare_font_def(&defs[count],
@@ -919,7 +887,7 @@ static const WpPdfFontDef* wp_pdf_find_font_def(const WpPdfFontDef* defs,
uint8_t font_id,
uint8_t flags) {
int want_style = wp_pdf_style_index(flags);
int want_font = font_id < FONT_COUNT ? font_id : FONT_ROBOTO;
int want_font = font_id < wp_font_count() ? font_id : wp_default_font_id();
for (int i = 0; i < count; i++) {
if (defs[i].font_id == want_font && defs[i].style_index == want_style)
return &defs[i];
@@ -1235,7 +1203,10 @@ bool wp_export_pdf_document(WordProcessorState* wp, const char* path, char* out_
}
bool success = false;
WpPdfFontDef fonts[FONT_COUNT * 4] = {};
// Sized for every discovered family in all four styles; heap-allocated to
// keep the deep PDF call chain off an already-tight user stack.
WpPdfFontDef* fonts = nullptr;
int font_cap = wp_font_count() > 0 ? wp_font_count() * 4 : 4;
int font_count = 0;
WpPdfPageStream* page_streams = nullptr;
int* page_obj_nums = nullptr;
@@ -1245,6 +1216,13 @@ bool wp_export_pdf_document(WordProcessorState* wp, const char* path, char* out_
int next_obj = 0;
int total_objects = 0;
fonts = (WpPdfFontDef*)montauk::malloc((uint64_t)font_cap * sizeof(WpPdfFontDef));
if (!fonts) {
wp_status_copy(out_status, out_status_len, "Out of memory while exporting PDF");
goto cleanup;
}
montauk::memset(fonts, 0, (uint64_t)font_cap * sizeof(WpPdfFontDef));
if (!wp_pdf_collect_fonts(wp, fonts, &font_count, err, sizeof(err))) {
wp_status_copy(out_status, out_status_len, err);
goto cleanup;
@@ -1473,6 +1451,7 @@ cleanup:
if (line_pages) montauk::mfree(line_pages);
if (line_y) montauk::mfree(line_y);
wp_pdf_free_fonts(fonts, font_count);
if (fonts) montauk::mfree(fonts);
wp_pdf_buffer_free(&pdf);
return success;