/src/mupdf/source/html/html-font.c
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright (C) 2004-2022 Artifex Software, Inc. |
2 | | // |
3 | | // This file is part of MuPDF. |
4 | | // |
5 | | // MuPDF is free software: you can redistribute it and/or modify it under the |
6 | | // terms of the GNU Affero General Public License as published by the Free |
7 | | // Software Foundation, either version 3 of the License, or (at your option) |
8 | | // any later version. |
9 | | // |
10 | | // MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY |
11 | | // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
12 | | // FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more |
13 | | // details. |
14 | | // |
15 | | // You should have received a copy of the GNU Affero General Public License |
16 | | // along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html> |
17 | | // |
18 | | // Alternative licensing terms are available from the licensor. |
19 | | // For commercial licensing, see <https://www.artifex.com/> or contact |
20 | | // Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, |
21 | | // CA 94129, USA, for further information. |
22 | | |
23 | | #include "mupdf/fitz.h" |
24 | | #include "html-imp.h" |
25 | | |
26 | | #include <string.h> |
27 | | |
28 | | static fz_font * |
29 | | fz_load_html_default_font(fz_context *ctx, fz_html_font_set *set, const char *family, int is_bold, int is_italic) |
30 | 613 | { |
31 | 613 | int is_mono = !strcmp(family, "monospace"); |
32 | 613 | int is_sans = !strcmp(family, "sans-serif"); |
33 | 613 | const char *real_family = is_mono ? "Courier" : is_sans ? "Helvetica" : "Charis SIL"; |
34 | 613 | const char *backup_family = is_mono ? "Courier" : is_sans ? "Helvetica" : "Times"; |
35 | 613 | int idx = (is_mono ? 8 : is_sans ? 4 : 0) + is_bold * 2 + is_italic; |
36 | 613 | if (!set->fonts[idx]) |
37 | 54 | { |
38 | 54 | const unsigned char *data; |
39 | 54 | int size; |
40 | | |
41 | 54 | data = fz_lookup_builtin_font(ctx, real_family, is_bold, is_italic, &size); |
42 | 54 | if (!data) |
43 | 0 | data = fz_lookup_builtin_font(ctx, backup_family, is_bold, is_italic, &size); |
44 | 54 | if (!data) |
45 | 0 | fz_throw(ctx, FZ_ERROR_UNSUPPORTED, "cannot load html font: %s", real_family); |
46 | 54 | set->fonts[idx] = fz_new_font_from_memory(ctx, NULL, data, size, 0, 1); |
47 | 54 | fz_font_flags(set->fonts[idx])->is_serif = !is_sans; |
48 | 54 | } |
49 | 613 | return set->fonts[idx]; |
50 | 613 | } |
51 | | |
52 | | void |
53 | | fz_add_html_font_face(fz_context *ctx, fz_html_font_set *set, |
54 | | const char *family, int is_bold, int is_italic, int is_small_caps, |
55 | | const char *src, fz_font *font) |
56 | 31 | { |
57 | 31 | fz_html_font_face *custom = fz_malloc_struct(ctx, fz_html_font_face); |
58 | | |
59 | 62 | fz_try(ctx) |
60 | 62 | { |
61 | 31 | custom->font = fz_keep_font(ctx, font); |
62 | 31 | custom->src = fz_strdup(ctx, src); |
63 | 31 | custom->family = fz_strdup(ctx, family); |
64 | 31 | custom->is_bold = is_bold; |
65 | 31 | custom->is_italic = is_italic; |
66 | 31 | custom->is_small_caps = is_small_caps; |
67 | 31 | custom->next = set->custom; |
68 | 31 | set->custom = custom; |
69 | 31 | } |
70 | 62 | fz_catch(ctx) |
71 | 0 | { |
72 | 0 | fz_drop_font(ctx, custom->font); |
73 | 0 | fz_free(ctx, custom->src); |
74 | 0 | fz_free(ctx, custom->family); |
75 | 0 | fz_rethrow(ctx); |
76 | 0 | } |
77 | 31 | } |
78 | | |
79 | | fz_font * |
80 | | fz_load_html_font(fz_context *ctx, fz_html_font_set *set, |
81 | | const char *family, int is_bold, int is_italic, int is_small_caps) |
82 | 752 | { |
83 | 752 | fz_html_font_face *custom; |
84 | 752 | const unsigned char *data; |
85 | 752 | int best_score = 0; |
86 | 752 | fz_font *best_font = NULL; |
87 | 752 | int size; |
88 | | |
89 | 822 | for (custom = set->custom; custom; custom = custom->next) |
90 | 70 | { |
91 | 70 | if (!strcmp(family, custom->family)) |
92 | 25 | { |
93 | 25 | int score = |
94 | 25 | 1 * (is_bold == custom->is_bold) + |
95 | 25 | 2 * (is_italic == custom->is_italic) + |
96 | 25 | 4 * (is_small_caps == custom->is_small_caps); |
97 | 25 | if (score > best_score) |
98 | 25 | { |
99 | 25 | best_score = score; |
100 | 25 | best_font = custom->font; |
101 | 25 | } |
102 | 25 | } |
103 | 70 | } |
104 | | |
105 | | // We found a perfect match! |
106 | 752 | if (best_font && best_score == 1 + 2 + 4) |
107 | 25 | return best_font; |
108 | | |
109 | | // Try to load a perfect match. |
110 | 727 | data = fz_lookup_builtin_font(ctx, family, is_bold, is_italic, &size); |
111 | 727 | if (!data) |
112 | 696 | data = fz_lookup_builtin_font(ctx, family, 0, 0, &size); |
113 | 727 | if (data) |
114 | 31 | { |
115 | 31 | fz_font *font = fz_new_font_from_memory(ctx, NULL, data, size, 0, 0); |
116 | 31 | fz_font_flags_t *flags = fz_font_flags(font); |
117 | 31 | if (is_bold && !flags->is_bold) |
118 | 0 | flags->fake_bold = 1; |
119 | 31 | if (is_italic && !flags->is_italic) |
120 | 0 | flags->fake_italic = 1; |
121 | 31 | fz_add_html_font_face(ctx, set, family, is_bold, is_italic, 0, "<builtin>", font); |
122 | 31 | fz_drop_font(ctx, font); |
123 | 31 | return font; |
124 | 31 | } |
125 | | |
126 | | // Use the imperfect match from before. |
127 | 696 | if (best_font) |
128 | 0 | return best_font; |
129 | | |
130 | | // Handle the "default" font aliases. |
131 | 696 | if (!strcmp(family, "monospace") || !strcmp(family, "sans-serif") || !strcmp(family, "serif")) |
132 | 613 | return fz_load_html_default_font(ctx, set, family, is_bold, is_italic); |
133 | | |
134 | 83 | return NULL; |
135 | 696 | } |
136 | | |
137 | | fz_html_font_set *fz_new_html_font_set(fz_context *ctx) |
138 | 80 | { |
139 | 80 | return fz_malloc_struct(ctx, fz_html_font_set); |
140 | 80 | } |
141 | | |
142 | | void fz_drop_html_font_set(fz_context *ctx, fz_html_font_set *set) |
143 | 80 | { |
144 | 80 | fz_html_font_face *font, *next; |
145 | 80 | int i; |
146 | | |
147 | 80 | if (!set) |
148 | 0 | return; |
149 | | |
150 | 80 | font = set->custom; |
151 | 111 | while (font) |
152 | 31 | { |
153 | 31 | next = font->next; |
154 | 31 | fz_drop_font(ctx, font->font); |
155 | 31 | fz_free(ctx, font->src); |
156 | 31 | fz_free(ctx, font->family); |
157 | 31 | fz_free(ctx, font); |
158 | 31 | font = next; |
159 | 31 | } |
160 | | |
161 | 1.04k | for (i = 0; i < (int)nelem(set->fonts); ++i) |
162 | 960 | fz_drop_font(ctx, set->fonts[i]); |
163 | | |
164 | 80 | fz_free(ctx, set); |
165 | 80 | } |