// Copyright (C) 2004-2022 Artifex Software, Inc. // // This file is part of MuPDF. // // MuPDF is free software: you can redistribute it and/or modify it under the // terms of the GNU Affero General Public License as published by the Free // Software Foundation, either version 3 of the License, or (at your option) // any later version. // // MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more // details. // // You should have received a copy of the GNU Affero General Public License // along with MuPDF. If not, see // // Alternative licensing terms are available from the licensor. // For commercial licensing, see or contact // Artifex Software, Inc., 1305 Grant Avenue - Suite 200, Novato, // CA 94945, U.S.A., +1(415)492-9861, for further information. #include "mupdf/fitz.h" #include "html-imp.h" #include static fz_font * fz_load_html_default_font(fz_context *ctx, fz_html_font_set *set, const char *family, int is_bold, int is_italic) { int is_mono = !strcmp(family, "monospace"); int is_sans = !strcmp(family, "sans-serif"); const char *real_family = is_mono ? "Courier" : is_sans ? "Helvetica" : "Charis SIL"; const char *backup_family = is_mono ? "Courier" : is_sans ? "Helvetica" : "Times"; int idx = (is_mono ? 8 : is_sans ? 4 : 0) + is_bold * 2 + is_italic; if (!set->fonts[idx]) { const unsigned char *data; int size; data = fz_lookup_builtin_font(ctx, real_family, is_bold, is_italic, &size); if (!data) data = fz_lookup_builtin_font(ctx, backup_family, is_bold, is_italic, &size); if (!data) fz_throw(ctx, FZ_ERROR_GENERIC, "cannot load html font: %s", real_family); set->fonts[idx] = fz_new_font_from_memory(ctx, NULL, data, size, 0, 1); fz_font_flags(set->fonts[idx])->is_serif = !is_sans; } return set->fonts[idx]; } void fz_add_html_font_face(fz_context *ctx, fz_html_font_set *set, const char *family, int is_bold, int is_italic, int is_small_caps, const char *src, fz_font *font) { fz_html_font_face *custom = fz_malloc_struct(ctx, fz_html_font_face); fz_try(ctx) { custom->font = fz_keep_font(ctx, font); custom->src = fz_strdup(ctx, src); custom->family = fz_strdup(ctx, family); custom->is_bold = is_bold; custom->is_italic = is_italic; custom->is_small_caps = is_small_caps; custom->next = set->custom; set->custom = custom; } fz_catch(ctx) { fz_drop_font(ctx, custom->font); fz_free(ctx, custom->src); fz_free(ctx, custom->family); fz_rethrow(ctx); } } fz_font * fz_load_html_font(fz_context *ctx, fz_html_font_set *set, const char *family, int is_bold, int is_italic, int is_small_caps) { fz_html_font_face *custom; const unsigned char *data; int best_score = 0; fz_font *best_font = NULL; int size; for (custom = set->custom; custom; custom = custom->next) { if (!strcmp(family, custom->family)) { int score = 1 * (is_bold == custom->is_bold) + 2 * (is_italic == custom->is_italic) + 4 * (is_small_caps == custom->is_small_caps); if (score > best_score) { best_score = score; best_font = custom->font; } } } // We found a perfect match! if (best_font && best_score == 1 + 2 + 4) return best_font; // Try to load a perfect match. data = fz_lookup_builtin_font(ctx, family, is_bold, is_italic, &size); if (!data) data = fz_lookup_builtin_font(ctx, family, 0, 0, &size); if (data) { fz_font *font = fz_new_font_from_memory(ctx, NULL, data, size, 0, 0); fz_font_flags_t *flags = fz_font_flags(font); if (is_bold && !flags->is_bold) flags->fake_bold = 1; if (is_italic && !flags->is_italic) flags->fake_italic = 1; fz_add_html_font_face(ctx, set, family, is_bold, is_italic, 0, "", font); fz_drop_font(ctx, font); return font; } // Use the imperfect match from before. if (best_font) return best_font; // Handle the "default" font aliases. if (!strcmp(family, "monospace") || !strcmp(family, "sans-serif") || !strcmp(family, "serif")) return fz_load_html_default_font(ctx, set, family, is_bold, is_italic); return NULL; } fz_html_font_set *fz_new_html_font_set(fz_context *ctx) { return fz_malloc_struct(ctx, fz_html_font_set); } void fz_drop_html_font_set(fz_context *ctx, fz_html_font_set *set) { fz_html_font_face *font, *next; int i; if (!set) return; font = set->custom; while (font) { next = font->next; fz_drop_font(ctx, font->font); fz_free(ctx, font->src); fz_free(ctx, font->family); fz_free(ctx, font); font = next; } for (i = 0; i < (int)nelem(set->fonts); ++i) fz_drop_font(ctx, set->fonts[i]); fz_free(ctx, set); }