Skip to main content

cadmus_core/font/
mod.rs

1mod freetype_sys;
2mod harfbuzz_sys;
3
4use self::freetype_sys::*;
5use self::harfbuzz_sys::*;
6
7use crate::color::Color;
8use crate::device::CURRENT_DEVICE;
9use crate::framebuffer::Framebuffer;
10use crate::geom::{Point, Vec2};
11use crate::helpers::IsHidden;
12use anyhow::{Error, format_err};
13use bitflags::bitflags;
14use fxhash::FxHashMap;
15use globset::Glob;
16use lazy_static::lazy_static;
17use std::collections::BTreeSet;
18use std::ffi::{CStr, CString};
19use std::os::unix::ffi::OsStrExt;
20use std::path::Path;
21use std::path::PathBuf;
22use std::ptr;
23use std::rc::Rc;
24use std::slice;
25use std::str;
26use thiserror::Error;
27use tracing::{error, warn};
28use walkdir::WalkDir;
29
30// Font sizes in 1/64th of a point
31pub const FONT_SIZES: [u32; 3] = [349, 524, 629];
32
33pub const KEYBOARD_FONT_SIZES: [u32; 2] = [337, 843];
34
35pub const DISPLAY_FONT_SIZE: u32 = 2516;
36
37pub const NORMAL_STYLE: Style = Style {
38    family: Family::SansSerif,
39    variant: Variant::REGULAR,
40    size: FONT_SIZES[1],
41};
42
43pub const SPECIAL_STYLE: Style = Style {
44    family: Family::SansSerif,
45    variant: Variant::ITALIC,
46    size: FONT_SIZES[1],
47};
48
49pub const KBD_CHAR: Style = Style {
50    family: Family::Keyboard,
51    variant: Variant::REGULAR,
52    size: KEYBOARD_FONT_SIZES[1],
53};
54
55pub const KBD_LABEL: Style = Style {
56    family: Family::Keyboard,
57    variant: Variant::REGULAR,
58    size: FONT_SIZES[0],
59};
60
61pub const DISPLAY_STYLE: Style = Style {
62    family: Family::Display,
63    variant: Variant::REGULAR,
64    size: DISPLAY_FONT_SIZE,
65};
66
67lazy_static! {
68    pub static ref MD_TITLE: Style = {
69        // Compute the ratio between the physical width of the
70        // current device and that of the Aura ONE.
71        let ratio = (CURRENT_DEVICE.dims.0 as f32 * 300.0) /
72                    (CURRENT_DEVICE.dpi as f32 * 1404.0);
73        let size = ((FONT_SIZES[2] as f32 * ratio) as u32).clamp(FONT_SIZES[1],
74                                                                 FONT_SIZES[2]);
75        Style {
76            family: Family::Serif,
77            variant: Variant::ITALIC,
78            size,
79        }
80    };
81}
82
83pub const MD_AUTHOR: Style = Style {
84    family: Family::Serif,
85    variant: Variant::REGULAR,
86    size: FONT_SIZES[1],
87};
88
89pub const MD_YEAR: Style = NORMAL_STYLE;
90
91pub const MD_KIND: Style = Style {
92    family: Family::SansSerif,
93    variant: Variant::BOLD,
94    size: FONT_SIZES[0],
95};
96
97pub const MD_SIZE: Style = Style {
98    family: Family::SansSerif,
99    variant: Variant::REGULAR,
100    size: FONT_SIZES[0],
101};
102
103#[cfg(any(not(target_os = "linux"), target_arch = "arm"))]
104#[link(name = "mupdf")]
105unsafe extern "C" {
106    // Based on the outputs of:
107    // arm-linux-gnueabihf-readelf -Ws ./libs/libmupdf.so | grep '\b_binary_' | \
108    // grep -v '_size$' | awk '{print $8, strtonum($3)-1}' | sort -u
109    pub static _binary_DroidSansFallback_ttf: [libc::c_uchar; 3556308];
110    pub static _binary_NotoEmoji_Regular_ttf: [libc::c_uchar; 418804];
111    pub static _binary_NotoMusic_Regular_otf: [libc::c_uchar; 60812];
112    pub static _binary_NotoNaskhArabic_Regular_otf: [libc::c_uchar; 119664];
113    pub static _binary_NotoNastaliqUrdu_Regular_otf: [libc::c_uchar; 373220];
114    pub static _binary_NotoSans_Regular_otf: [libc::c_uchar; 290336];
115    pub static _binary_NotoSansAdlam_Regular_otf: [libc::c_uchar; 33448];
116    pub static _binary_NotoSansAnatolianHieroglyphs_Regular_otf: [libc::c_uchar; 134420];
117    pub static _binary_NotoSansAvestan_Regular_otf: [libc::c_uchar; 9300];
118    pub static _binary_NotoSansBamum_Regular_otf: [libc::c_uchar; 103668];
119    pub static _binary_NotoSansBassaVah_Regular_otf: [libc::c_uchar; 6300];
120    pub static _binary_NotoSansBatak_Regular_otf: [libc::c_uchar; 11108];
121    pub static _binary_NotoSansBhaiksuki_Regular_otf: [libc::c_uchar; 121620];
122    pub static _binary_NotoSansBrahmi_Regular_otf: [libc::c_uchar; 29544];
123    pub static _binary_NotoSansBuginese_Regular_otf: [libc::c_uchar; 6256];
124    pub static _binary_NotoSansBuhid_Regular_otf: [libc::c_uchar; 5076];
125    pub static _binary_NotoSansCanadianAboriginal_Regular_otf: [libc::c_uchar; 38068];
126    pub static _binary_NotoSansCarian_Regular_otf: [libc::c_uchar; 5592];
127    pub static _binary_NotoSansCaucasianAlbanian_Regular_otf: [libc::c_uchar; 17388];
128    pub static _binary_NotoSansChakma_Regular_otf: [libc::c_uchar; 29488];
129    pub static _binary_NotoSansCham_Regular_otf: [libc::c_uchar; 21224];
130    pub static _binary_NotoSansCherokee_Regular_otf: [libc::c_uchar; 57308];
131    pub static _binary_NotoSansChorasmian_Regular_otf: [libc::c_uchar; 12460];
132    pub static _binary_NotoSansCoptic_Regular_otf: [libc::c_uchar; 21380];
133    pub static _binary_NotoSansCuneiform_Regular_otf: [libc::c_uchar; 416308];
134    pub static _binary_NotoSansCypriot_Regular_otf: [libc::c_uchar; 7024];
135    pub static _binary_NotoSansCyproMinoan_Regular_otf: [libc::c_uchar; 8568];
136    pub static _binary_NotoSansDeseret_Regular_otf: [libc::c_uchar; 9016];
137    pub static _binary_NotoSansDuployan_Regular_otf: [libc::c_uchar; 10276];
138    pub static _binary_NotoSansEgyptianHieroglyphs_Regular_otf: [libc::c_uchar; 362960];
139    pub static _binary_NotoSansElbasan_Regular_otf: [libc::c_uchar; 8684];
140    pub static _binary_NotoSansElymaic_Regular_otf: [libc::c_uchar; 7620];
141    pub static _binary_NotoSansGlagolitic_Regular_otf: [libc::c_uchar; 17176];
142    pub static _binary_NotoSansGothic_Regular_otf: [libc::c_uchar; 5416];
143    pub static _binary_NotoSansGunjalaGondi_Regular_otf: [libc::c_uchar; 32372];
144    pub static _binary_NotoSansHanifiRohingya_Regular_otf: [libc::c_uchar; 16576];
145    pub static _binary_NotoSansHanunoo_Regular_otf: [libc::c_uchar; 6596];
146    pub static _binary_NotoSansHatran_Regular_otf: [libc::c_uchar; 4324];
147    pub static _binary_NotoSansImperialAramaic_Regular_otf: [libc::c_uchar; 5436];
148    pub static _binary_NotoSansInscriptionalPahlavi_Regular_otf: [libc::c_uchar; 5464];
149    pub static _binary_NotoSansInscriptionalParthian_Regular_otf: [libc::c_uchar; 6788];
150    pub static _binary_NotoSansJavanese_Regular_otf: [libc::c_uchar; 86944];
151    pub static _binary_NotoSansKaithi_Regular_otf: [libc::c_uchar; 39756];
152    pub static _binary_NotoSansKawi_Regular_otf: [libc::c_uchar; 30940];
153    pub static _binary_NotoSansKayahLi_Regular_otf: [libc::c_uchar; 7100];
154    pub static _binary_NotoSansKharoshthi_Regular_otf: [libc::c_uchar; 27708];
155    pub static _binary_NotoSansKhudawadi_Regular_otf: [libc::c_uchar; 14764];
156    pub static _binary_NotoSansLepcha_Regular_otf: [libc::c_uchar; 18832];
157    pub static _binary_NotoSansLimbu_Regular_otf: [libc::c_uchar; 10040];
158    pub static _binary_NotoSansLinearA_Regular_otf: [libc::c_uchar; 33640];
159    pub static _binary_NotoSansLinearB_Regular_otf: [libc::c_uchar; 36892];
160    pub static _binary_NotoSansLisu_Regular_otf: [libc::c_uchar; 5688];
161    pub static _binary_NotoSansLycian_Regular_otf: [libc::c_uchar; 4108];
162    pub static _binary_NotoSansLydian_Regular_otf: [libc::c_uchar; 4088];
163    pub static _binary_NotoSansMahajani_Regular_otf: [libc::c_uchar; 10136];
164    pub static _binary_NotoSansMandaic_Regular_otf: [libc::c_uchar; 13160];
165    pub static _binary_NotoSansManichaean_Regular_otf: [libc::c_uchar; 16496];
166    pub static _binary_NotoSansMarchen_Regular_otf: [libc::c_uchar; 69240];
167    pub static _binary_NotoSansMasaramGondi_Regular_otf: [libc::c_uchar; 23052];
168    pub static _binary_NotoSansMath_Regular_otf: [libc::c_uchar; 258796];
169    pub static _binary_NotoSansMedefaidrin_Regular_otf: [libc::c_uchar; 27060];
170    pub static _binary_NotoSansMeeteiMayek_Regular_otf: [libc::c_uchar; 13056];
171    pub static _binary_NotoSansMendeKikakui_Regular_otf: [libc::c_uchar; 19664];
172    pub static _binary_NotoSansMeroitic_Regular_otf: [libc::c_uchar; 19980];
173    pub static _binary_NotoSansMiao_Regular_otf: [libc::c_uchar; 26460];
174    pub static _binary_NotoSansModi_Regular_otf: [libc::c_uchar; 29412];
175    pub static _binary_NotoSansMongolian_Regular_otf: [libc::c_uchar; 111040];
176    pub static _binary_NotoSansMro_Regular_otf: [libc::c_uchar; 5608];
177    pub static _binary_NotoSansMultani_Regular_otf: [libc::c_uchar; 7852];
178    pub static _binary_NotoSansNabataean_Regular_otf: [libc::c_uchar; 6448];
179    pub static _binary_NotoSansNagMundari_Regular_otf: [libc::c_uchar; 8612];
180    pub static _binary_NotoSansNandinagari_Regular_otf: [libc::c_uchar; 86940];
181    pub static _binary_NotoSansNewa_Regular_otf: [libc::c_uchar; 99568];
182    pub static _binary_NotoSansNewTaiLue_Regular_otf: [libc::c_uchar; 10884];
183    pub static _binary_NotoSansNKo_Regular_otf: [libc::c_uchar; 15164];
184    pub static _binary_NotoSansNushu_Regular_otf: [libc::c_uchar; 72472];
185    pub static _binary_NotoSansOgham_Regular_otf: [libc::c_uchar; 3720];
186    pub static _binary_NotoSansOlChiki_Regular_otf: [libc::c_uchar; 7024];
187    pub static _binary_NotoSansOldHungarian_Regular_otf: [libc::c_uchar; 44628];
188    pub static _binary_NotoSansOldItalic_Regular_otf: [libc::c_uchar; 6360];
189    pub static _binary_NotoSansOldNorthArabian_Regular_otf: [libc::c_uchar; 6132];
190    pub static _binary_NotoSansOldPermic_Regular_otf: [libc::c_uchar; 8512];
191    pub static _binary_NotoSansOldPersian_Regular_otf: [libc::c_uchar; 9856];
192    pub static _binary_NotoSansOldSogdian_Regular_otf: [libc::c_uchar; 12260];
193    pub static _binary_NotoSansOldSouthArabian_Regular_otf: [libc::c_uchar; 4624];
194    pub static _binary_NotoSansOldTurkic_Regular_otf: [libc::c_uchar; 6884];
195    pub static _binary_NotoSansOsage_Regular_otf: [libc::c_uchar; 9292];
196    pub static _binary_NotoSansOsmanya_Regular_otf: [libc::c_uchar; 6784];
197    pub static _binary_NotoSansPahawhHmong_Regular_otf: [libc::c_uchar; 13024];
198    pub static _binary_NotoSansPalmyrene_Regular_otf: [libc::c_uchar; 8480];
199    pub static _binary_NotoSansPauCinHau_Regular_otf: [libc::c_uchar; 8124];
200    pub static _binary_NotoSansPhagsPa_Regular_otf: [libc::c_uchar; 24036];
201    pub static _binary_NotoSansPhoenician_Regular_otf: [libc::c_uchar; 5288];
202    pub static _binary_NotoSansPsalterPahlavi_Regular_otf: [libc::c_uchar; 12748];
203    pub static _binary_NotoSansRejang_Regular_otf: [libc::c_uchar; 6440];
204    pub static _binary_NotoSansRunic_Regular_otf: [libc::c_uchar; 7200];
205    pub static _binary_NotoSansSamaritan_Regular_otf: [libc::c_uchar; 9024];
206    pub static _binary_NotoSansSaurashtra_Regular_otf: [libc::c_uchar; 16020];
207    pub static _binary_NotoSansSharada_Regular_otf: [libc::c_uchar; 32824];
208    pub static _binary_NotoSansShavian_Regular_otf: [libc::c_uchar; 5468];
209    pub static _binary_NotoSansSiddham_Regular_otf: [libc::c_uchar; 91992];
210    pub static _binary_NotoSansSignWriting_Regular_otf: [libc::c_uchar; 2780224];
211    pub static _binary_NotoSansSogdian_Regular_otf: [libc::c_uchar; 48356];
212    pub static _binary_NotoSansSoraSompeng_Regular_otf: [libc::c_uchar; 6332];
213    pub static _binary_NotoSansSoyombo_Regular_otf: [libc::c_uchar; 52036];
214    pub static _binary_NotoSansSundanese_Regular_otf: [libc::c_uchar; 9420];
215    pub static _binary_NotoSansSylotiNagri_Regular_otf: [libc::c_uchar; 12852];
216    pub static _binary_NotoSansSymbols_Regular_otf: [libc::c_uchar; 109696];
217    pub static _binary_NotoSansSymbols2_Regular_otf: [libc::c_uchar; 375388];
218    pub static _binary_NotoSansSyriac_Regular_otf: [libc::c_uchar; 124756];
219    pub static _binary_NotoSansTagalog_Regular_otf: [libc::c_uchar; 5500];
220    pub static _binary_NotoSansTagbanwa_Regular_otf: [libc::c_uchar; 5356];
221    pub static _binary_NotoSansTaiLe_Regular_otf: [libc::c_uchar; 8616];
222    pub static _binary_NotoSansTaiTham_Regular_otf: [libc::c_uchar; 76880];
223    pub static _binary_NotoSansTaiViet_Regular_otf: [libc::c_uchar; 12280];
224    pub static _binary_NotoSansTakri_Regular_otf: [libc::c_uchar; 17864];
225    pub static _binary_NotoSansTangsa_Regular_otf: [libc::c_uchar; 16908];
226    pub static _binary_NotoSansThaana_Regular_otf: [libc::c_uchar; 12392];
227    pub static _binary_NotoSansTifinagh_Regular_otf: [libc::c_uchar; 24776];
228    pub static _binary_NotoSansTirhuta_Regular_otf: [libc::c_uchar; 52432];
229    pub static _binary_NotoSansUgaritic_Regular_otf: [libc::c_uchar; 5048];
230    pub static _binary_NotoSansVai_Regular_otf: [libc::c_uchar; 24088];
231    pub static _binary_NotoSansWancho_Regular_otf: [libc::c_uchar; 15140];
232    pub static _binary_NotoSansWarangCiti_Regular_otf: [libc::c_uchar; 23484];
233    pub static _binary_NotoSansYi_Regular_otf: [libc::c_uchar; 92164];
234    pub static _binary_NotoSansZanabazarSquare_Regular_otf: [libc::c_uchar; 13804];
235    pub static _binary_NotoSerif_Regular_otf: [libc::c_uchar; 289412];
236    pub static _binary_NotoSerifAhom_Regular_otf: [libc::c_uchar; 14516];
237    pub static _binary_NotoSerifArmenian_Regular_otf: [libc::c_uchar; 14160];
238    pub static _binary_NotoSerifBalinese_Regular_otf: [libc::c_uchar; 32348];
239    pub static _binary_NotoSerifBengali_Regular_otf: [libc::c_uchar; 101332];
240    pub static _binary_NotoSerifDevanagari_Regular_otf: [libc::c_uchar; 169744];
241    pub static _binary_NotoSerifDivesAkuru_Regular_otf: [libc::c_uchar; 27972];
242    pub static _binary_NotoSerifDogra_Regular_otf: [libc::c_uchar; 19944];
243    pub static _binary_NotoSerifEthiopic_Regular_otf: [libc::c_uchar; 113328];
244    pub static _binary_NotoSerifGeorgian_Regular_otf: [libc::c_uchar; 31988];
245    pub static _binary_NotoSerifGrantha_Regular_otf: [libc::c_uchar; 368396];
246    pub static _binary_NotoSerifGujarati_Regular_otf: [libc::c_uchar; 64848];
247    pub static _binary_NotoSerifGurmukhi_Regular_otf: [libc::c_uchar; 26992];
248    pub static _binary_NotoSerifHebrew_Regular_otf: [libc::c_uchar; 15320];
249    pub static _binary_NotoSerifKannada_Regular_otf: [libc::c_uchar; 89032];
250    pub static _binary_NotoSerifKhitanSmallScript_Regular_otf: [libc::c_uchar; 508920];
251    pub static _binary_NotoSerifKhmer_Regular_otf: [libc::c_uchar; 40436];
252    pub static _binary_NotoSerifKhojki_Regular_otf: [libc::c_uchar; 60112];
253    pub static _binary_NotoSerifLao_Regular_otf: [libc::c_uchar; 16196];
254    pub static _binary_NotoSerifMakasar_Regular_otf: [libc::c_uchar; 5864];
255    pub static _binary_NotoSerifMalayalam_Regular_otf: [libc::c_uchar; 45668];
256    pub static _binary_NotoSerifMyanmar_Regular_otf: [libc::c_uchar; 127564];
257    pub static _binary_NotoSerifNyiakengPuachueHmong_Regular_otf: [libc::c_uchar; 12208];
258    pub static _binary_NotoSerifOldUyghur_Regular_otf: [libc::c_uchar; 15620];
259    pub static _binary_NotoSerifOriya_Regular_otf: [libc::c_uchar; 105824];
260    pub static _binary_NotoSerifSinhala_Regular_otf: [libc::c_uchar; 74924];
261    pub static _binary_NotoSerifTamil_Regular_otf: [libc::c_uchar; 33752];
262    pub static _binary_NotoSerifTelugu_Regular_otf: [libc::c_uchar; 82032];
263    pub static _binary_NotoSerifThai_Regular_otf: [libc::c_uchar; 17556];
264    pub static _binary_NotoSerifTibetan_Regular_otf: [libc::c_uchar; 334156];
265    pub static _binary_NotoSerifToto_Regular_otf: [libc::c_uchar; 5732];
266    pub static _binary_NotoSerifVithkuqi_Regular_otf: [libc::c_uchar; 42508];
267    pub static _binary_NotoSerifYezidi_Regular_otf: [libc::c_uchar; 8664];
268}
269
270#[cfg(all(target_os = "linux", not(target_arch = "arm")))]
271#[link(name = "mupdf")]
272unsafe extern "C" {
273    pub static _binary_resources_fonts_droid_DroidSansFallback_ttf_start: [libc::c_uchar; 3556308];
274    pub static _binary_resources_fonts_noto_NotoEmoji_Regular_ttf_start: [libc::c_uchar; 418804];
275    pub static _binary_resources_fonts_noto_NotoMusic_Regular_otf_start: [libc::c_uchar; 60812];
276    pub static _binary_resources_fonts_noto_NotoNaskhArabic_Regular_otf_start:
277        [libc::c_uchar; 119664];
278    pub static _binary_resources_fonts_noto_NotoNastaliqUrdu_Regular_otf_start:
279        [libc::c_uchar; 373220];
280    pub static _binary_resources_fonts_noto_NotoSans_Regular_otf_start: [libc::c_uchar; 290336];
281    pub static _binary_resources_fonts_noto_NotoSansAdlam_Regular_otf_start: [libc::c_uchar; 33448];
282    pub static _binary_resources_fonts_noto_NotoSansAnatolianHieroglyphs_Regular_otf_start:
283        [libc::c_uchar; 134420];
284    pub static _binary_resources_fonts_noto_NotoSansAvestan_Regular_otf_start:
285        [libc::c_uchar; 9300];
286    pub static _binary_resources_fonts_noto_NotoSansBamum_Regular_otf_start:
287        [libc::c_uchar; 103668];
288    pub static _binary_resources_fonts_noto_NotoSansBassaVah_Regular_otf_start:
289        [libc::c_uchar; 6300];
290    pub static _binary_resources_fonts_noto_NotoSansBatak_Regular_otf_start: [libc::c_uchar; 11108];
291    pub static _binary_resources_fonts_noto_NotoSansBhaiksuki_Regular_otf_start:
292        [libc::c_uchar; 121620];
293    pub static _binary_resources_fonts_noto_NotoSansBrahmi_Regular_otf_start:
294        [libc::c_uchar; 29544];
295    pub static _binary_resources_fonts_noto_NotoSansBuginese_Regular_otf_start:
296        [libc::c_uchar; 6256];
297    pub static _binary_resources_fonts_noto_NotoSansBuhid_Regular_otf_start: [libc::c_uchar; 5076];
298    pub static _binary_resources_fonts_noto_NotoSansCanadianAboriginal_Regular_otf_start:
299        [libc::c_uchar; 38068];
300    pub static _binary_resources_fonts_noto_NotoSansCarian_Regular_otf_start: [libc::c_uchar; 5592];
301    pub static _binary_resources_fonts_noto_NotoSansCaucasianAlbanian_Regular_otf_start:
302        [libc::c_uchar; 17388];
303    pub static _binary_resources_fonts_noto_NotoSansChakma_Regular_otf_start:
304        [libc::c_uchar; 29488];
305    pub static _binary_resources_fonts_noto_NotoSansCham_Regular_otf_start: [libc::c_uchar; 21224];
306    pub static _binary_resources_fonts_noto_NotoSansCherokee_Regular_otf_start:
307        [libc::c_uchar; 57308];
308    pub static _binary_resources_fonts_noto_NotoSansChorasmian_Regular_otf_start:
309        [libc::c_uchar; 12460];
310    pub static _binary_resources_fonts_noto_NotoSansCoptic_Regular_otf_start:
311        [libc::c_uchar; 21380];
312    pub static _binary_resources_fonts_noto_NotoSansCuneiform_Regular_otf_start:
313        [libc::c_uchar; 416308];
314    pub static _binary_resources_fonts_noto_NotoSansCypriot_Regular_otf_start:
315        [libc::c_uchar; 7024];
316    pub static _binary_resources_fonts_noto_NotoSansCyproMinoan_Regular_otf_start:
317        [libc::c_uchar; 8568];
318    pub static _binary_resources_fonts_noto_NotoSansDeseret_Regular_otf_start:
319        [libc::c_uchar; 9016];
320    pub static _binary_resources_fonts_noto_NotoSansDuployan_Regular_otf_start:
321        [libc::c_uchar; 10276];
322    pub static _binary_resources_fonts_noto_NotoSansEgyptianHieroglyphs_Regular_otf_start:
323        [libc::c_uchar; 362960];
324    pub static _binary_resources_fonts_noto_NotoSansElbasan_Regular_otf_start:
325        [libc::c_uchar; 8684];
326    pub static _binary_resources_fonts_noto_NotoSansElymaic_Regular_otf_start:
327        [libc::c_uchar; 7620];
328    pub static _binary_resources_fonts_noto_NotoSansGlagolitic_Regular_otf_start:
329        [libc::c_uchar; 17176];
330    pub static _binary_resources_fonts_noto_NotoSansGothic_Regular_otf_start: [libc::c_uchar; 5416];
331    pub static _binary_resources_fonts_noto_NotoSansGunjalaGondi_Regular_otf_start:
332        [libc::c_uchar; 32372];
333    pub static _binary_resources_fonts_noto_NotoSansHanifiRohingya_Regular_otf_start:
334        [libc::c_uchar; 16576];
335    pub static _binary_resources_fonts_noto_NotoSansHanunoo_Regular_otf_start:
336        [libc::c_uchar; 6596];
337    pub static _binary_resources_fonts_noto_NotoSansHatran_Regular_otf_start: [libc::c_uchar; 4324];
338    pub static _binary_resources_fonts_noto_NotoSansImperialAramaic_Regular_otf_start:
339        [libc::c_uchar; 5436];
340    pub static _binary_resources_fonts_noto_NotoSansInscriptionalPahlavi_Regular_otf_start:
341        [libc::c_uchar; 5464];
342    pub static _binary_resources_fonts_noto_NotoSansInscriptionalParthian_Regular_otf_start:
343        [libc::c_uchar; 6788];
344    pub static _binary_resources_fonts_noto_NotoSansJavanese_Regular_otf_start:
345        [libc::c_uchar; 86944];
346    pub static _binary_resources_fonts_noto_NotoSansKaithi_Regular_otf_start:
347        [libc::c_uchar; 39756];
348    pub static _binary_resources_fonts_noto_NotoSansKawi_Regular_otf_start: [libc::c_uchar; 30940];
349    pub static _binary_resources_fonts_noto_NotoSansKayahLi_Regular_otf_start:
350        [libc::c_uchar; 7100];
351    pub static _binary_resources_fonts_noto_NotoSansKharoshthi_Regular_otf_start:
352        [libc::c_uchar; 27708];
353    pub static _binary_resources_fonts_noto_NotoSansKhudawadi_Regular_otf_start:
354        [libc::c_uchar; 14764];
355    pub static _binary_resources_fonts_noto_NotoSansLepcha_Regular_otf_start:
356        [libc::c_uchar; 18832];
357    pub static _binary_resources_fonts_noto_NotoSansLimbu_Regular_otf_start: [libc::c_uchar; 10040];
358    pub static _binary_resources_fonts_noto_NotoSansLinearA_Regular_otf_start:
359        [libc::c_uchar; 33640];
360    pub static _binary_resources_fonts_noto_NotoSansLinearB_Regular_otf_start:
361        [libc::c_uchar; 36892];
362    pub static _binary_resources_fonts_noto_NotoSansLisu_Regular_otf_start: [libc::c_uchar; 5688];
363    pub static _binary_resources_fonts_noto_NotoSansLycian_Regular_otf_start: [libc::c_uchar; 4108];
364    pub static _binary_resources_fonts_noto_NotoSansLydian_Regular_otf_start: [libc::c_uchar; 4088];
365    pub static _binary_resources_fonts_noto_NotoSansMahajani_Regular_otf_start:
366        [libc::c_uchar; 10136];
367    pub static _binary_resources_fonts_noto_NotoSansMandaic_Regular_otf_start:
368        [libc::c_uchar; 13160];
369    pub static _binary_resources_fonts_noto_NotoSansManichaean_Regular_otf_start:
370        [libc::c_uchar; 16496];
371    pub static _binary_resources_fonts_noto_NotoSansMarchen_Regular_otf_start:
372        [libc::c_uchar; 69240];
373    pub static _binary_resources_fonts_noto_NotoSansMasaramGondi_Regular_otf_start:
374        [libc::c_uchar; 23052];
375    pub static _binary_resources_fonts_noto_NotoSansMath_Regular_otf_start: [libc::c_uchar; 258796];
376    pub static _binary_resources_fonts_noto_NotoSansMedefaidrin_Regular_otf_start:
377        [libc::c_uchar; 27060];
378    pub static _binary_resources_fonts_noto_NotoSansMeeteiMayek_Regular_otf_start:
379        [libc::c_uchar; 13056];
380    pub static _binary_resources_fonts_noto_NotoSansMendeKikakui_Regular_otf_start:
381        [libc::c_uchar; 19664];
382    pub static _binary_resources_fonts_noto_NotoSansMeroitic_Regular_otf_start:
383        [libc::c_uchar; 19980];
384    pub static _binary_resources_fonts_noto_NotoSansMiao_Regular_otf_start: [libc::c_uchar; 26460];
385    pub static _binary_resources_fonts_noto_NotoSansModi_Regular_otf_start: [libc::c_uchar; 29412];
386    pub static _binary_resources_fonts_noto_NotoSansMongolian_Regular_otf_start:
387        [libc::c_uchar; 111040];
388    pub static _binary_resources_fonts_noto_NotoSansMro_Regular_otf_start: [libc::c_uchar; 5608];
389    pub static _binary_resources_fonts_noto_NotoSansMultani_Regular_otf_start:
390        [libc::c_uchar; 7852];
391    pub static _binary_resources_fonts_noto_NotoSansNabataean_Regular_otf_start:
392        [libc::c_uchar; 6448];
393    pub static _binary_resources_fonts_noto_NotoSansNagMundari_Regular_otf_start:
394        [libc::c_uchar; 8612];
395    pub static _binary_resources_fonts_noto_NotoSansNandinagari_Regular_otf_start:
396        [libc::c_uchar; 86940];
397    pub static _binary_resources_fonts_noto_NotoSansNewa_Regular_otf_start: [libc::c_uchar; 99568];
398    pub static _binary_resources_fonts_noto_NotoSansNewTaiLue_Regular_otf_start:
399        [libc::c_uchar; 10884];
400    pub static _binary_resources_fonts_noto_NotoSansNKo_Regular_otf_start: [libc::c_uchar; 15164];
401    pub static _binary_resources_fonts_noto_NotoSansNushu_Regular_otf_start: [libc::c_uchar; 72472];
402    pub static _binary_resources_fonts_noto_NotoSansOgham_Regular_otf_start: [libc::c_uchar; 3720];
403    pub static _binary_resources_fonts_noto_NotoSansOlChiki_Regular_otf_start:
404        [libc::c_uchar; 7024];
405    pub static _binary_resources_fonts_noto_NotoSansOldHungarian_Regular_otf_start:
406        [libc::c_uchar; 44628];
407    pub static _binary_resources_fonts_noto_NotoSansOldItalic_Regular_otf_start:
408        [libc::c_uchar; 6360];
409    pub static _binary_resources_fonts_noto_NotoSansOldNorthArabian_Regular_otf_start:
410        [libc::c_uchar; 6132];
411    pub static _binary_resources_fonts_noto_NotoSansOldPermic_Regular_otf_start:
412        [libc::c_uchar; 8512];
413    pub static _binary_resources_fonts_noto_NotoSansOldPersian_Regular_otf_start:
414        [libc::c_uchar; 9856];
415    pub static _binary_resources_fonts_noto_NotoSansOldSogdian_Regular_otf_start:
416        [libc::c_uchar; 12260];
417    pub static _binary_resources_fonts_noto_NotoSansOldSouthArabian_Regular_otf_start:
418        [libc::c_uchar; 4624];
419    pub static _binary_resources_fonts_noto_NotoSansOldTurkic_Regular_otf_start:
420        [libc::c_uchar; 6884];
421    pub static _binary_resources_fonts_noto_NotoSansOsage_Regular_otf_start: [libc::c_uchar; 9292];
422    pub static _binary_resources_fonts_noto_NotoSansOsmanya_Regular_otf_start:
423        [libc::c_uchar; 6784];
424    pub static _binary_resources_fonts_noto_NotoSansPahawhHmong_Regular_otf_start:
425        [libc::c_uchar; 13024];
426    pub static _binary_resources_fonts_noto_NotoSansPalmyrene_Regular_otf_start:
427        [libc::c_uchar; 8480];
428    pub static _binary_resources_fonts_noto_NotoSansPauCinHau_Regular_otf_start:
429        [libc::c_uchar; 8124];
430    pub static _binary_resources_fonts_noto_NotoSansPhagsPa_Regular_otf_start:
431        [libc::c_uchar; 24036];
432    pub static _binary_resources_fonts_noto_NotoSansPhoenician_Regular_otf_start:
433        [libc::c_uchar; 5288];
434    pub static _binary_resources_fonts_noto_NotoSansPsalterPahlavi_Regular_otf_start:
435        [libc::c_uchar; 12748];
436    pub static _binary_resources_fonts_noto_NotoSansRejang_Regular_otf_start: [libc::c_uchar; 6440];
437    pub static _binary_resources_fonts_noto_NotoSansRunic_Regular_otf_start: [libc::c_uchar; 7200];
438    pub static _binary_resources_fonts_noto_NotoSansSamaritan_Regular_otf_start:
439        [libc::c_uchar; 9024];
440    pub static _binary_resources_fonts_noto_NotoSansSaurashtra_Regular_otf_start:
441        [libc::c_uchar; 16020];
442    pub static _binary_resources_fonts_noto_NotoSansSharada_Regular_otf_start:
443        [libc::c_uchar; 32824];
444    pub static _binary_resources_fonts_noto_NotoSansShavian_Regular_otf_start:
445        [libc::c_uchar; 5468];
446    pub static _binary_resources_fonts_noto_NotoSansSiddham_Regular_otf_start:
447        [libc::c_uchar; 91992];
448    pub static _binary_resources_fonts_noto_NotoSansSignWriting_Regular_otf_start:
449        [libc::c_uchar; 2780224];
450    pub static _binary_resources_fonts_noto_NotoSansSogdian_Regular_otf_start:
451        [libc::c_uchar; 48356];
452    pub static _binary_resources_fonts_noto_NotoSansSoraSompeng_Regular_otf_start:
453        [libc::c_uchar; 6332];
454    pub static _binary_resources_fonts_noto_NotoSansSoyombo_Regular_otf_start:
455        [libc::c_uchar; 52036];
456    pub static _binary_resources_fonts_noto_NotoSansSundanese_Regular_otf_start:
457        [libc::c_uchar; 9420];
458    pub static _binary_resources_fonts_noto_NotoSansSylotiNagri_Regular_otf_start:
459        [libc::c_uchar; 12852];
460    pub static _binary_resources_fonts_noto_NotoSansSymbols_Regular_otf_start:
461        [libc::c_uchar; 109696];
462    pub static _binary_resources_fonts_noto_NotoSansSymbols2_Regular_otf_start:
463        [libc::c_uchar; 375388];
464    pub static _binary_resources_fonts_noto_NotoSansSyriac_Regular_otf_start:
465        [libc::c_uchar; 124756];
466    pub static _binary_resources_fonts_noto_NotoSansTagalog_Regular_otf_start:
467        [libc::c_uchar; 5500];
468    pub static _binary_resources_fonts_noto_NotoSansTagbanwa_Regular_otf_start:
469        [libc::c_uchar; 5356];
470    pub static _binary_resources_fonts_noto_NotoSansTaiLe_Regular_otf_start: [libc::c_uchar; 8616];
471    pub static _binary_resources_fonts_noto_NotoSansTaiTham_Regular_otf_start:
472        [libc::c_uchar; 76880];
473    pub static _binary_resources_fonts_noto_NotoSansTaiViet_Regular_otf_start:
474        [libc::c_uchar; 12280];
475    pub static _binary_resources_fonts_noto_NotoSansTakri_Regular_otf_start: [libc::c_uchar; 17864];
476    pub static _binary_resources_fonts_noto_NotoSansTangsa_Regular_otf_start:
477        [libc::c_uchar; 16908];
478    pub static _binary_resources_fonts_noto_NotoSansThaana_Regular_otf_start:
479        [libc::c_uchar; 12392];
480    pub static _binary_resources_fonts_noto_NotoSansTifinagh_Regular_otf_start:
481        [libc::c_uchar; 24776];
482    pub static _binary_resources_fonts_noto_NotoSansTirhuta_Regular_otf_start:
483        [libc::c_uchar; 52432];
484    pub static _binary_resources_fonts_noto_NotoSansUgaritic_Regular_otf_start:
485        [libc::c_uchar; 5048];
486    pub static _binary_resources_fonts_noto_NotoSansVai_Regular_otf_start: [libc::c_uchar; 24088];
487    pub static _binary_resources_fonts_noto_NotoSansWancho_Regular_otf_start:
488        [libc::c_uchar; 15140];
489    pub static _binary_resources_fonts_noto_NotoSansWarangCiti_Regular_otf_start:
490        [libc::c_uchar; 23484];
491    pub static _binary_resources_fonts_noto_NotoSansYi_Regular_otf_start: [libc::c_uchar; 92164];
492    pub static _binary_resources_fonts_noto_NotoSansZanabazarSquare_Regular_otf_start:
493        [libc::c_uchar; 13804];
494    pub static _binary_resources_fonts_noto_NotoSerif_Regular_otf_start: [libc::c_uchar; 289412];
495    pub static _binary_resources_fonts_noto_NotoSerifAhom_Regular_otf_start: [libc::c_uchar; 14516];
496    pub static _binary_resources_fonts_noto_NotoSerifArmenian_Regular_otf_start:
497        [libc::c_uchar; 14160];
498    pub static _binary_resources_fonts_noto_NotoSerifBalinese_Regular_otf_start:
499        [libc::c_uchar; 32348];
500    pub static _binary_resources_fonts_noto_NotoSerifBengali_Regular_otf_start:
501        [libc::c_uchar; 101332];
502    pub static _binary_resources_fonts_noto_NotoSerifDevanagari_Regular_otf_start:
503        [libc::c_uchar; 169744];
504    pub static _binary_resources_fonts_noto_NotoSerifDivesAkuru_Regular_otf_start:
505        [libc::c_uchar; 27972];
506    pub static _binary_resources_fonts_noto_NotoSerifDogra_Regular_otf_start:
507        [libc::c_uchar; 19944];
508    pub static _binary_resources_fonts_noto_NotoSerifEthiopic_Regular_otf_start:
509        [libc::c_uchar; 113328];
510    pub static _binary_resources_fonts_noto_NotoSerifGeorgian_Regular_otf_start:
511        [libc::c_uchar; 31988];
512    pub static _binary_resources_fonts_noto_NotoSerifGrantha_Regular_otf_start:
513        [libc::c_uchar; 368396];
514    pub static _binary_resources_fonts_noto_NotoSerifGujarati_Regular_otf_start:
515        [libc::c_uchar; 64848];
516    pub static _binary_resources_fonts_noto_NotoSerifGurmukhi_Regular_otf_start:
517        [libc::c_uchar; 26992];
518    pub static _binary_resources_fonts_noto_NotoSerifHebrew_Regular_otf_start:
519        [libc::c_uchar; 15320];
520    pub static _binary_resources_fonts_noto_NotoSerifKannada_Regular_otf_start:
521        [libc::c_uchar; 89032];
522    pub static _binary_resources_fonts_noto_NotoSerifKhitanSmallScript_Regular_otf_start:
523        [libc::c_uchar; 508920];
524    pub static _binary_resources_fonts_noto_NotoSerifKhmer_Regular_otf_start:
525        [libc::c_uchar; 40436];
526    pub static _binary_resources_fonts_noto_NotoSerifKhojki_Regular_otf_start:
527        [libc::c_uchar; 60112];
528    pub static _binary_resources_fonts_noto_NotoSerifLao_Regular_otf_start: [libc::c_uchar; 16196];
529    pub static _binary_resources_fonts_noto_NotoSerifMakasar_Regular_otf_start:
530        [libc::c_uchar; 5864];
531    pub static _binary_resources_fonts_noto_NotoSerifMalayalam_Regular_otf_start:
532        [libc::c_uchar; 45668];
533    pub static _binary_resources_fonts_noto_NotoSerifMyanmar_Regular_otf_start:
534        [libc::c_uchar; 127564];
535    pub static _binary_resources_fonts_noto_NotoSerifNyiakengPuachueHmong_Regular_otf_start:
536        [libc::c_uchar; 12208];
537    pub static _binary_resources_fonts_noto_NotoSerifOldUyghur_Regular_otf_start:
538        [libc::c_uchar; 15620];
539    pub static _binary_resources_fonts_noto_NotoSerifOriya_Regular_otf_start:
540        [libc::c_uchar; 105824];
541    pub static _binary_resources_fonts_noto_NotoSerifSinhala_Regular_otf_start:
542        [libc::c_uchar; 74924];
543    pub static _binary_resources_fonts_noto_NotoSerifTamil_Regular_otf_start:
544        [libc::c_uchar; 33752];
545    pub static _binary_resources_fonts_noto_NotoSerifTelugu_Regular_otf_start:
546        [libc::c_uchar; 82032];
547    pub static _binary_resources_fonts_noto_NotoSerifThai_Regular_otf_start: [libc::c_uchar; 17556];
548    pub static _binary_resources_fonts_noto_NotoSerifTibetan_Regular_otf_start:
549        [libc::c_uchar; 334156];
550    pub static _binary_resources_fonts_noto_NotoSerifToto_Regular_otf_start: [libc::c_uchar; 5732];
551    pub static _binary_resources_fonts_noto_NotoSerifVithkuqi_Regular_otf_start:
552        [libc::c_uchar; 42508];
553    pub static _binary_resources_fonts_noto_NotoSerifYezidi_Regular_otf_start:
554        [libc::c_uchar; 8664];
555}
556
557pub const SLIDER_VALUE: Style = MD_SIZE;
558
559pub struct FontFamily {
560    pub regular: Font,
561    pub italic: Font,
562    pub bold: Font,
563    pub bold_italic: Font,
564}
565
566pub fn family_names<P: AsRef<Path>>(search_path: P) -> Result<BTreeSet<String>, Error> {
567    if !search_path.as_ref().exists() {
568        return Err(format_err!("the search path doesn't exist"));
569    }
570
571    let opener = FontOpener::new()?;
572    let glob = Glob::new("**/*.[ot]tf")?.compile_matcher();
573
574    let mut families = BTreeSet::new();
575
576    for entry in WalkDir::new(search_path.as_ref())
577        .min_depth(1)
578        .into_iter()
579        .filter_entry(|e| !e.is_hidden())
580    {
581        if entry.is_err() {
582            continue;
583        }
584        let entry = entry.unwrap();
585        let path = entry.path();
586        if !glob.is_match(path) {
587            continue;
588        }
589        if let Ok(font) = opener
590            .open(path)
591            .map_err(|e| error!("Can't open '{}': {:#}.", path.display(), e))
592        {
593            if let Some(family_name) = font.family_name() {
594                families.insert(family_name.to_string());
595            } else {
596                warn!("Can't get the family name of '{}'.", path.display());
597            }
598        }
599    }
600
601    Ok(families)
602}
603
604impl FontFamily {
605    pub fn from_name<P: AsRef<Path>>(
606        family_name: &str,
607        search_path: P,
608    ) -> Result<FontFamily, Error> {
609        let opener = FontOpener::new()?;
610        let glob = Glob::new("**/*.[ot]tf")?.compile_matcher();
611        let mut styles = FxHashMap::default();
612
613        for entry in WalkDir::new(search_path.as_ref())
614            .min_depth(1)
615            .into_iter()
616            .filter_entry(|e| !e.is_hidden())
617        {
618            if entry.is_err() {
619                continue;
620            }
621            let entry = entry.unwrap();
622            let path = entry.path();
623            if !glob.is_match(path) {
624                continue;
625            }
626            if let Ok(font) = opener
627                .open(path)
628                .map_err(|e| error!("Can't open '{}': {:#}.", path.display(), e))
629            {
630                if font.family_name() == Some(family_name) {
631                    styles.insert(
632                        font.style_name()
633                            .map(String::from)
634                            .unwrap_or_else(|| "Regular".to_string()),
635                        path.to_path_buf(),
636                    );
637                }
638            }
639        }
640
641        let regular_path = if styles.len() == 1 {
642            styles.values().next().unwrap()
643        } else {
644            styles
645                .get("Regular")
646                .or_else(|| styles.get("Roman"))
647                .or_else(|| styles.get("Book"))
648                .ok_or_else(|| format_err!("can't find regular style"))?
649        };
650        let italic_path = styles
651            .get("Italic")
652            .or_else(|| styles.get("Book Italic"))
653            .or_else(|| styles.get("Regular Italic"))
654            .unwrap_or(regular_path);
655        let bold_path = styles
656            .get("Bold")
657            .or_else(|| styles.get("Semibold"))
658            .or_else(|| styles.get("SemiBold"))
659            .or_else(|| styles.get("Medium"))
660            .unwrap_or(regular_path);
661        let bold_italic_path = styles
662            .get("Bold Italic")
663            .or_else(|| styles.get("SemiBold Italic"))
664            .or_else(|| styles.get("Medium Italic"))
665            .unwrap_or(italic_path);
666        Ok(FontFamily {
667            regular: opener.open(regular_path)?,
668            italic: opener.open(italic_path)?,
669            bold: opener.open(bold_path)?,
670            bold_italic: opener.open(bold_italic_path)?,
671        })
672    }
673}
674
675pub struct Fonts {
676    pub sans_serif: FontFamily,
677    pub serif: FontFamily,
678    pub monospace: FontFamily,
679    pub keyboard: Font,
680    pub display: Font,
681}
682
683impl Fonts {
684    fn _load(root_dir: Option<PathBuf>) -> Result<Fonts, Error> {
685        let search_path = if let Some(root_dir) = root_dir {
686            root_dir.join("fonts")
687        } else {
688            CURRENT_DEVICE.install_path("fonts")
689        };
690
691        let opener = FontOpener::new()?;
692        let mut fonts = Fonts {
693            sans_serif: FontFamily {
694                regular: opener.open(search_path.join("NotoSans-Regular.ttf").as_path())?,
695                italic: opener.open(search_path.join("NotoSans-Italic.ttf").as_path())?,
696                bold: opener.open(search_path.join("NotoSans-Bold.ttf").as_path())?,
697                bold_italic: opener.open(search_path.join("NotoSans-BoldItalic.ttf").as_path())?,
698            },
699            serif: FontFamily {
700                regular: opener.open(search_path.join("NotoSerif-Regular.ttf").as_path())?,
701                italic: opener.open(search_path.join("NotoSerif-Italic.ttf").as_path())?,
702                bold: opener.open(search_path.join("NotoSerif-Bold.ttf").as_path())?,
703                bold_italic: opener.open(search_path.join("NotoSerif-BoldItalic.ttf").as_path())?,
704            },
705            monospace: FontFamily {
706                regular: opener.open(search_path.join("SourceCodeVariable-Roman.otf").as_path())?,
707                italic: opener.open(search_path.join("SourceCodeVariable-Italic.otf").as_path())?,
708                bold: opener.open(search_path.join("SourceCodeVariable-Roman.otf").as_path())?,
709                bold_italic: opener
710                    .open(search_path.join("SourceCodeVariable-Italic.otf").as_path())?,
711            },
712            keyboard: opener.open(search_path.join("VarelaRound-Regular.ttf").as_path())?,
713            display: opener.open(search_path.join("Cormorant-Regular.ttf").as_path())?,
714        };
715        fonts.monospace.bold.set_variations(&["wght=600"]);
716        fonts.monospace.bold_italic.set_variations(&["wght=600"]);
717        Ok(fonts)
718    }
719
720    pub fn load() -> Result<Fonts, Error> {
721        Fonts::_load(None)
722    }
723
724    pub fn load_from(root_dir: PathBuf) -> Result<Fonts, Error> {
725        Fonts::_load(Some(root_dir))
726    }
727}
728
729bitflags! {
730    #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
731    pub struct Variant: u8 {
732        const REGULAR = 0;
733        const ITALIC = 1;
734        const BOLD = 2;
735    }
736}
737
738#[derive(Debug, Copy, Clone, Eq, PartialEq)]
739pub enum Family {
740    SansSerif,
741    Serif,
742    Monospace,
743    Keyboard,
744    Display,
745}
746
747pub struct Style {
748    family: Family,
749    variant: Variant,
750    pub size: u32,
751}
752
753pub fn font_from_variant(family: &mut FontFamily, variant: Variant) -> &mut Font {
754    if variant.contains(Variant::ITALIC | Variant::BOLD) {
755        &mut family.bold_italic
756    } else if variant.contains(Variant::ITALIC) {
757        &mut family.italic
758    } else if variant.contains(Variant::BOLD) {
759        &mut family.bold
760    } else {
761        &mut family.regular
762    }
763}
764
765pub fn font_from_style<'a>(fonts: &'a mut Fonts, style: &Style, dpi: u16) -> &'a mut Font {
766    let font = match style.family {
767        Family::SansSerif => {
768            let family = &mut fonts.sans_serif;
769            font_from_variant(family, style.variant)
770        }
771        Family::Serif => {
772            let family = &mut fonts.serif;
773            font_from_variant(family, style.variant)
774        }
775        Family::Monospace => {
776            let family = &mut fonts.monospace;
777            font_from_variant(family, style.variant)
778        }
779        Family::Keyboard => &mut fonts.keyboard,
780        Family::Display => &mut fonts.display,
781    };
782    font.set_size(style.size, dpi);
783    font
784}
785
786#[inline]
787unsafe fn font_data_from_script(script: HbScript) -> &'static [libc::c_uchar] {
788    unsafe {
789        // Extracted from mupdf in source/fitz/noto.c
790        #[cfg(any(not(target_os = "linux"), target_arch = "arm"))]
791        match script {
792            HB_SCRIPT_HANGUL | HB_SCRIPT_HIRAGANA | HB_SCRIPT_KATAKANA | HB_SCRIPT_BOPOMOFO
793            | HB_SCRIPT_HAN => &_binary_DroidSansFallback_ttf,
794
795            HB_SCRIPT_ARABIC => &_binary_NotoNaskhArabic_Regular_otf,
796            HB_SCRIPT_SYRIAC => &_binary_NotoSansSyriac_Regular_otf,
797            HB_SCRIPT_MEROITIC_CURSIVE | HB_SCRIPT_MEROITIC_HIEROGLYPHS => {
798                &_binary_NotoSansMeroitic_Regular_otf
799            }
800
801            HB_SCRIPT_ADLAM => &_binary_NotoSansAdlam_Regular_otf,
802            HB_SCRIPT_AHOM => &_binary_NotoSerifAhom_Regular_otf,
803            HB_SCRIPT_ANATOLIAN_HIEROGLYPHS => &_binary_NotoSansAnatolianHieroglyphs_Regular_otf,
804            HB_SCRIPT_ARMENIAN => &_binary_NotoSerifArmenian_Regular_otf,
805            HB_SCRIPT_AVESTAN => &_binary_NotoSansAvestan_Regular_otf,
806            HB_SCRIPT_BALINESE => &_binary_NotoSerifBalinese_Regular_otf,
807            HB_SCRIPT_BAMUM => &_binary_NotoSansBamum_Regular_otf,
808            HB_SCRIPT_BASSA_VAH => &_binary_NotoSansBassaVah_Regular_otf,
809            HB_SCRIPT_BATAK => &_binary_NotoSansBatak_Regular_otf,
810            HB_SCRIPT_BENGALI => &_binary_NotoSerifBengali_Regular_otf,
811            HB_SCRIPT_BHAIKSUKI => &_binary_NotoSansBhaiksuki_Regular_otf,
812            HB_SCRIPT_BRAHMI => &_binary_NotoSansBrahmi_Regular_otf,
813            HB_SCRIPT_BUGINESE => &_binary_NotoSansBuginese_Regular_otf,
814            HB_SCRIPT_BUHID => &_binary_NotoSansBuhid_Regular_otf,
815            HB_SCRIPT_CANADIAN_SYLLABICS => &_binary_NotoSansCanadianAboriginal_Regular_otf,
816            HB_SCRIPT_CARIAN => &_binary_NotoSansCarian_Regular_otf,
817            HB_SCRIPT_CAUCASIAN_ALBANIAN => &_binary_NotoSansCaucasianAlbanian_Regular_otf,
818            HB_SCRIPT_CHAKMA => &_binary_NotoSansChakma_Regular_otf,
819            HB_SCRIPT_CHAM => &_binary_NotoSansCham_Regular_otf,
820            HB_SCRIPT_CHEROKEE => &_binary_NotoSansCherokee_Regular_otf,
821            HB_SCRIPT_CHORASMIAN => &_binary_NotoSansChorasmian_Regular_otf,
822            HB_SCRIPT_COPTIC => &_binary_NotoSansCoptic_Regular_otf,
823            HB_SCRIPT_CUNEIFORM => &_binary_NotoSansCuneiform_Regular_otf,
824            HB_SCRIPT_CYPRIOT => &_binary_NotoSansCypriot_Regular_otf,
825            HB_SCRIPT_CYPRO_MINOAN => &_binary_NotoSansCyproMinoan_Regular_otf,
826            HB_SCRIPT_DESERET => &_binary_NotoSansDeseret_Regular_otf,
827            HB_SCRIPT_DEVANAGARI => &_binary_NotoSerifDevanagari_Regular_otf,
828            HB_SCRIPT_DIVES_AKURU => &_binary_NotoSerifDivesAkuru_Regular_otf,
829            HB_SCRIPT_DOGRA => &_binary_NotoSerifDogra_Regular_otf,
830            HB_SCRIPT_DUPLOYAN => &_binary_NotoSansDuployan_Regular_otf,
831            HB_SCRIPT_EGYPTIAN_HIEROGLYPHS => &_binary_NotoSansEgyptianHieroglyphs_Regular_otf,
832            HB_SCRIPT_ELBASAN => &_binary_NotoSansElbasan_Regular_otf,
833            HB_SCRIPT_ELYMAIC => &_binary_NotoSansElymaic_Regular_otf,
834            HB_SCRIPT_ETHIOPIC => &_binary_NotoSerifEthiopic_Regular_otf,
835            HB_SCRIPT_GEORGIAN => &_binary_NotoSerifGeorgian_Regular_otf,
836            HB_SCRIPT_GLAGOLITIC => &_binary_NotoSansGlagolitic_Regular_otf,
837            HB_SCRIPT_GOTHIC => &_binary_NotoSansGothic_Regular_otf,
838            HB_SCRIPT_GRANTHA => &_binary_NotoSerifGrantha_Regular_otf,
839            HB_SCRIPT_GUJARATI => &_binary_NotoSerifGujarati_Regular_otf,
840            HB_SCRIPT_GUNJALA_GONDI => &_binary_NotoSansGunjalaGondi_Regular_otf,
841            HB_SCRIPT_GURMUKHI => &_binary_NotoSerifGurmukhi_Regular_otf,
842            HB_SCRIPT_HANIFI_ROHINGYA => &_binary_NotoSansHanifiRohingya_Regular_otf,
843            HB_SCRIPT_HANUNOO => &_binary_NotoSansHanunoo_Regular_otf,
844            HB_SCRIPT_HATRAN => &_binary_NotoSansHatran_Regular_otf,
845            HB_SCRIPT_HEBREW => &_binary_NotoSerifHebrew_Regular_otf,
846            HB_SCRIPT_IMPERIAL_ARAMAIC => &_binary_NotoSansImperialAramaic_Regular_otf,
847            HB_SCRIPT_INSCRIPTIONAL_PAHLAVI => &_binary_NotoSansInscriptionalPahlavi_Regular_otf,
848            HB_SCRIPT_INSCRIPTIONAL_PARTHIAN => &_binary_NotoSansInscriptionalParthian_Regular_otf,
849            HB_SCRIPT_JAVANESE => &_binary_NotoSansJavanese_Regular_otf,
850            HB_SCRIPT_KAITHI => &_binary_NotoSansKaithi_Regular_otf,
851            HB_SCRIPT_KANNADA => &_binary_NotoSerifKannada_Regular_otf,
852            HB_SCRIPT_KAWI => &_binary_NotoSansKawi_Regular_otf,
853            HB_SCRIPT_KAYAH_LI => &_binary_NotoSansKayahLi_Regular_otf,
854            HB_SCRIPT_KHAROSHTHI => &_binary_NotoSansKharoshthi_Regular_otf,
855            HB_SCRIPT_KHITAN_SMALL_SCRIPT => &_binary_NotoSerifKhitanSmallScript_Regular_otf,
856            HB_SCRIPT_KHMER => &_binary_NotoSerifKhmer_Regular_otf,
857            HB_SCRIPT_KHOJKI => &_binary_NotoSerifKhojki_Regular_otf,
858            HB_SCRIPT_KHUDAWADI => &_binary_NotoSansKhudawadi_Regular_otf,
859            HB_SCRIPT_LAO => &_binary_NotoSerifLao_Regular_otf,
860            HB_SCRIPT_LEPCHA => &_binary_NotoSansLepcha_Regular_otf,
861            HB_SCRIPT_LIMBU => &_binary_NotoSansLimbu_Regular_otf,
862            HB_SCRIPT_LINEAR_A => &_binary_NotoSansLinearA_Regular_otf,
863            HB_SCRIPT_LINEAR_B => &_binary_NotoSansLinearB_Regular_otf,
864            HB_SCRIPT_LISU => &_binary_NotoSansLisu_Regular_otf,
865            HB_SCRIPT_LYCIAN => &_binary_NotoSansLycian_Regular_otf,
866            HB_SCRIPT_LYDIAN => &_binary_NotoSansLydian_Regular_otf,
867            HB_SCRIPT_MAHAJANI => &_binary_NotoSansMahajani_Regular_otf,
868            HB_SCRIPT_MAKASAR => &_binary_NotoSerifMakasar_Regular_otf,
869            HB_SCRIPT_MALAYALAM => &_binary_NotoSerifMalayalam_Regular_otf,
870            HB_SCRIPT_MANDAIC => &_binary_NotoSansMandaic_Regular_otf,
871            HB_SCRIPT_MANICHAEAN => &_binary_NotoSansManichaean_Regular_otf,
872            HB_SCRIPT_MARCHEN => &_binary_NotoSansMarchen_Regular_otf,
873            HB_SCRIPT_MASARAM_GONDI => &_binary_NotoSansMasaramGondi_Regular_otf,
874            HB_SCRIPT_MEDEFAIDRIN => &_binary_NotoSansMedefaidrin_Regular_otf,
875            HB_SCRIPT_MEETEI_MAYEK => &_binary_NotoSansMeeteiMayek_Regular_otf,
876            HB_SCRIPT_MENDE_KIKAKUI => &_binary_NotoSansMendeKikakui_Regular_otf,
877            HB_SCRIPT_MIAO => &_binary_NotoSansMiao_Regular_otf,
878            HB_SCRIPT_MODI => &_binary_NotoSansModi_Regular_otf,
879            HB_SCRIPT_MONGOLIAN => &_binary_NotoSansMongolian_Regular_otf,
880            HB_SCRIPT_MRO => &_binary_NotoSansMro_Regular_otf,
881            HB_SCRIPT_MULTANI => &_binary_NotoSansMultani_Regular_otf,
882            HB_SCRIPT_MYANMAR => &_binary_NotoSerifMyanmar_Regular_otf,
883            HB_SCRIPT_NABATAEAN => &_binary_NotoSansNabataean_Regular_otf,
884            HB_SCRIPT_NAG_MUNDARI => &_binary_NotoSansNagMundari_Regular_otf,
885            HB_SCRIPT_NANDINAGARI => &_binary_NotoSansNandinagari_Regular_otf,
886            HB_SCRIPT_NEWA => &_binary_NotoSansNewa_Regular_otf,
887            HB_SCRIPT_NEW_TAI_LUE => &_binary_NotoSansNewTaiLue_Regular_otf,
888            HB_SCRIPT_NKO => &_binary_NotoSansNKo_Regular_otf,
889            HB_SCRIPT_NUSHU => &_binary_NotoSansNushu_Regular_otf,
890            HB_SCRIPT_NYIAKENG_PUACHUE_HMONG => &_binary_NotoSerifNyiakengPuachueHmong_Regular_otf,
891            HB_SCRIPT_OGHAM => &_binary_NotoSansOgham_Regular_otf,
892            HB_SCRIPT_OLD_HUNGARIAN => &_binary_NotoSansOldHungarian_Regular_otf,
893            HB_SCRIPT_OLD_ITALIC => &_binary_NotoSansOldItalic_Regular_otf,
894            HB_SCRIPT_OLD_NORTH_ARABIAN => &_binary_NotoSansOldNorthArabian_Regular_otf,
895            HB_SCRIPT_OLD_PERMIC => &_binary_NotoSansOldPermic_Regular_otf,
896            HB_SCRIPT_OLD_PERSIAN => &_binary_NotoSansOldPersian_Regular_otf,
897            HB_SCRIPT_OLD_SOGDIAN => &_binary_NotoSansOldSogdian_Regular_otf,
898            HB_SCRIPT_OLD_SOUTH_ARABIAN => &_binary_NotoSansOldSouthArabian_Regular_otf,
899            HB_SCRIPT_OLD_TURKIC => &_binary_NotoSansOldTurkic_Regular_otf,
900            HB_SCRIPT_OLD_UYGHUR => &_binary_NotoSerifOldUyghur_Regular_otf,
901            HB_SCRIPT_OL_CHIKI => &_binary_NotoSansOlChiki_Regular_otf,
902            HB_SCRIPT_ORIYA => &_binary_NotoSerifOriya_Regular_otf,
903            HB_SCRIPT_OSAGE => &_binary_NotoSansOsage_Regular_otf,
904            HB_SCRIPT_OSMANYA => &_binary_NotoSansOsmanya_Regular_otf,
905            HB_SCRIPT_PAHAWH_HMONG => &_binary_NotoSansPahawhHmong_Regular_otf,
906            HB_SCRIPT_PALMYRENE => &_binary_NotoSansPalmyrene_Regular_otf,
907            HB_SCRIPT_PAU_CIN_HAU => &_binary_NotoSansPauCinHau_Regular_otf,
908            HB_SCRIPT_PHAGS_PA => &_binary_NotoSansPhagsPa_Regular_otf,
909            HB_SCRIPT_PHOENICIAN => &_binary_NotoSansPhoenician_Regular_otf,
910            HB_SCRIPT_PSALTER_PAHLAVI => &_binary_NotoSansPsalterPahlavi_Regular_otf,
911            HB_SCRIPT_REJANG => &_binary_NotoSansRejang_Regular_otf,
912            HB_SCRIPT_RUNIC => &_binary_NotoSansRunic_Regular_otf,
913            HB_SCRIPT_SAMARITAN => &_binary_NotoSansSamaritan_Regular_otf,
914            HB_SCRIPT_SAURASHTRA => &_binary_NotoSansSaurashtra_Regular_otf,
915            HB_SCRIPT_SHARADA => &_binary_NotoSansSharada_Regular_otf,
916            HB_SCRIPT_SHAVIAN => &_binary_NotoSansShavian_Regular_otf,
917            HB_SCRIPT_SIDDHAM => &_binary_NotoSansSiddham_Regular_otf,
918            HB_SCRIPT_SIGNWRITING => &_binary_NotoSansSignWriting_Regular_otf,
919            HB_SCRIPT_SINHALA => &_binary_NotoSerifSinhala_Regular_otf,
920            HB_SCRIPT_SOGDIAN => &_binary_NotoSansSogdian_Regular_otf,
921            HB_SCRIPT_SORA_SOMPENG => &_binary_NotoSansSoraSompeng_Regular_otf,
922            HB_SCRIPT_SOYOMBO => &_binary_NotoSansSoyombo_Regular_otf,
923            HB_SCRIPT_SUNDANESE => &_binary_NotoSansSundanese_Regular_otf,
924            HB_SCRIPT_SYLOTI_NAGRI => &_binary_NotoSansSylotiNagri_Regular_otf,
925            HB_SCRIPT_TAGALOG => &_binary_NotoSansTagalog_Regular_otf,
926            HB_SCRIPT_TAGBANWA => &_binary_NotoSansTagbanwa_Regular_otf,
927            HB_SCRIPT_TAI_LE => &_binary_NotoSansTaiLe_Regular_otf,
928            HB_SCRIPT_TAI_THAM => &_binary_NotoSansTaiTham_Regular_otf,
929            HB_SCRIPT_TAI_VIET => &_binary_NotoSansTaiViet_Regular_otf,
930            HB_SCRIPT_TAKRI => &_binary_NotoSansTakri_Regular_otf,
931            HB_SCRIPT_TAMIL => &_binary_NotoSerifTamil_Regular_otf,
932            HB_SCRIPT_TANGSA => &_binary_NotoSansTangsa_Regular_otf,
933            HB_SCRIPT_TELUGU => &_binary_NotoSerifTelugu_Regular_otf,
934            HB_SCRIPT_THAANA => &_binary_NotoSansThaana_Regular_otf,
935            HB_SCRIPT_THAI => &_binary_NotoSerifThai_Regular_otf,
936            HB_SCRIPT_TIBETAN => &_binary_NotoSerifTibetan_Regular_otf,
937            HB_SCRIPT_TIFINAGH => &_binary_NotoSansTifinagh_Regular_otf,
938            HB_SCRIPT_TIRHUTA => &_binary_NotoSansTirhuta_Regular_otf,
939            HB_SCRIPT_TOTO => &_binary_NotoSerifToto_Regular_otf,
940            HB_SCRIPT_UGARITIC => &_binary_NotoSansUgaritic_Regular_otf,
941            HB_SCRIPT_VAI => &_binary_NotoSansVai_Regular_otf,
942            HB_SCRIPT_VITHKUQI => &_binary_NotoSerifVithkuqi_Regular_otf,
943            HB_SCRIPT_WANCHO => &_binary_NotoSansWancho_Regular_otf,
944            HB_SCRIPT_WARANG_CITI => &_binary_NotoSansWarangCiti_Regular_otf,
945            HB_SCRIPT_YEZIDI => &_binary_NotoSerifYezidi_Regular_otf,
946            HB_SCRIPT_YI => &_binary_NotoSansYi_Regular_otf,
947            HB_SCRIPT_ZANABAZAR_SQUARE => &_binary_NotoSansZanabazarSquare_Regular_otf,
948
949            HB_SYMBOL_MATHS => &_binary_NotoSansMath_Regular_otf,
950            HB_SYMBOL_MUSIC => &_binary_NotoMusic_Regular_otf,
951            HB_SYMBOL_MISC_ONE => &_binary_NotoSansSymbols_Regular_otf,
952            HB_SCRIPT_BRAILLE | HB_SYMBOL_MISC_TWO => &_binary_NotoSansSymbols2_Regular_otf,
953            HB_SYMBOL_EMOJI => &_binary_NotoEmoji_Regular_ttf,
954
955            _ => &_binary_DroidSansFallback_ttf,
956        }
957
958        #[cfg(all(target_os = "linux", not(target_arch = "arm")))]
959        match script {
960            HB_SCRIPT_HANGUL | HB_SCRIPT_HIRAGANA | HB_SCRIPT_KATAKANA | HB_SCRIPT_BOPOMOFO
961            | HB_SCRIPT_HAN => &_binary_resources_fonts_droid_DroidSansFallback_ttf_start,
962
963            HB_SCRIPT_ARABIC => &_binary_resources_fonts_noto_NotoNaskhArabic_Regular_otf_start,
964            HB_SCRIPT_SYRIAC => &_binary_resources_fonts_noto_NotoSansSyriac_Regular_otf_start,
965            HB_SCRIPT_MEROITIC_CURSIVE | HB_SCRIPT_MEROITIC_HIEROGLYPHS => {
966                &_binary_resources_fonts_noto_NotoSansMeroitic_Regular_otf_start
967            }
968
969            HB_SCRIPT_ADLAM => &_binary_resources_fonts_noto_NotoSansAdlam_Regular_otf_start,
970            HB_SCRIPT_AHOM => &_binary_resources_fonts_noto_NotoSerifAhom_Regular_otf_start,
971            HB_SCRIPT_ANATOLIAN_HIEROGLYPHS => {
972                &_binary_resources_fonts_noto_NotoSansAnatolianHieroglyphs_Regular_otf_start
973            }
974            HB_SCRIPT_ARMENIAN => &_binary_resources_fonts_noto_NotoSerifArmenian_Regular_otf_start,
975            HB_SCRIPT_AVESTAN => &_binary_resources_fonts_noto_NotoSansAvestan_Regular_otf_start,
976            HB_SCRIPT_BALINESE => &_binary_resources_fonts_noto_NotoSerifBalinese_Regular_otf_start,
977            HB_SCRIPT_BAMUM => &_binary_resources_fonts_noto_NotoSansBamum_Regular_otf_start,
978            HB_SCRIPT_BASSA_VAH => &_binary_resources_fonts_noto_NotoSansBassaVah_Regular_otf_start,
979            HB_SCRIPT_BATAK => &_binary_resources_fonts_noto_NotoSansBatak_Regular_otf_start,
980            HB_SCRIPT_BENGALI => &_binary_resources_fonts_noto_NotoSerifBengali_Regular_otf_start,
981            HB_SCRIPT_BHAIKSUKI => {
982                &_binary_resources_fonts_noto_NotoSansBhaiksuki_Regular_otf_start
983            }
984            HB_SCRIPT_BRAHMI => &_binary_resources_fonts_noto_NotoSansBrahmi_Regular_otf_start,
985            HB_SCRIPT_BUGINESE => &_binary_resources_fonts_noto_NotoSansBuginese_Regular_otf_start,
986            HB_SCRIPT_BUHID => &_binary_resources_fonts_noto_NotoSansBuhid_Regular_otf_start,
987            HB_SCRIPT_CANADIAN_SYLLABICS => {
988                &_binary_resources_fonts_noto_NotoSansCanadianAboriginal_Regular_otf_start
989            }
990            HB_SCRIPT_CARIAN => &_binary_resources_fonts_noto_NotoSansCarian_Regular_otf_start,
991            HB_SCRIPT_CAUCASIAN_ALBANIAN => {
992                &_binary_resources_fonts_noto_NotoSansCaucasianAlbanian_Regular_otf_start
993            }
994            HB_SCRIPT_CHAKMA => &_binary_resources_fonts_noto_NotoSansChakma_Regular_otf_start,
995            HB_SCRIPT_CHAM => &_binary_resources_fonts_noto_NotoSansCham_Regular_otf_start,
996            HB_SCRIPT_CHEROKEE => &_binary_resources_fonts_noto_NotoSansCherokee_Regular_otf_start,
997            HB_SCRIPT_CHORASMIAN => {
998                &_binary_resources_fonts_noto_NotoSansChorasmian_Regular_otf_start
999            }
1000            HB_SCRIPT_COPTIC => &_binary_resources_fonts_noto_NotoSansCoptic_Regular_otf_start,
1001            HB_SCRIPT_CUNEIFORM => {
1002                &_binary_resources_fonts_noto_NotoSansCuneiform_Regular_otf_start
1003            }
1004            HB_SCRIPT_CYPRIOT => &_binary_resources_fonts_noto_NotoSansCypriot_Regular_otf_start,
1005            HB_SCRIPT_CYPRO_MINOAN => {
1006                &_binary_resources_fonts_noto_NotoSansCyproMinoan_Regular_otf_start
1007            }
1008            HB_SCRIPT_DESERET => &_binary_resources_fonts_noto_NotoSansDeseret_Regular_otf_start,
1009            HB_SCRIPT_DEVANAGARI => {
1010                &_binary_resources_fonts_noto_NotoSerifDevanagari_Regular_otf_start
1011            }
1012            HB_SCRIPT_DIVES_AKURU => {
1013                &_binary_resources_fonts_noto_NotoSerifDivesAkuru_Regular_otf_start
1014            }
1015            HB_SCRIPT_DOGRA => &_binary_resources_fonts_noto_NotoSerifDogra_Regular_otf_start,
1016            HB_SCRIPT_DUPLOYAN => &_binary_resources_fonts_noto_NotoSansDuployan_Regular_otf_start,
1017            HB_SCRIPT_EGYPTIAN_HIEROGLYPHS => {
1018                &_binary_resources_fonts_noto_NotoSansEgyptianHieroglyphs_Regular_otf_start
1019            }
1020            HB_SCRIPT_ELBASAN => &_binary_resources_fonts_noto_NotoSansElbasan_Regular_otf_start,
1021            HB_SCRIPT_ELYMAIC => &_binary_resources_fonts_noto_NotoSansElymaic_Regular_otf_start,
1022            HB_SCRIPT_ETHIOPIC => &_binary_resources_fonts_noto_NotoSerifEthiopic_Regular_otf_start,
1023            HB_SCRIPT_GEORGIAN => &_binary_resources_fonts_noto_NotoSerifGeorgian_Regular_otf_start,
1024            HB_SCRIPT_GLAGOLITIC => {
1025                &_binary_resources_fonts_noto_NotoSansGlagolitic_Regular_otf_start
1026            }
1027            HB_SCRIPT_GOTHIC => &_binary_resources_fonts_noto_NotoSansGothic_Regular_otf_start,
1028            HB_SCRIPT_GRANTHA => &_binary_resources_fonts_noto_NotoSerifGrantha_Regular_otf_start,
1029            HB_SCRIPT_GUJARATI => &_binary_resources_fonts_noto_NotoSerifGujarati_Regular_otf_start,
1030            HB_SCRIPT_GUNJALA_GONDI => {
1031                &_binary_resources_fonts_noto_NotoSansGunjalaGondi_Regular_otf_start
1032            }
1033            HB_SCRIPT_GURMUKHI => &_binary_resources_fonts_noto_NotoSerifGurmukhi_Regular_otf_start,
1034            HB_SCRIPT_HANIFI_ROHINGYA => {
1035                &_binary_resources_fonts_noto_NotoSansHanifiRohingya_Regular_otf_start
1036            }
1037            HB_SCRIPT_HANUNOO => &_binary_resources_fonts_noto_NotoSansHanunoo_Regular_otf_start,
1038            HB_SCRIPT_HATRAN => &_binary_resources_fonts_noto_NotoSansHatran_Regular_otf_start,
1039            HB_SCRIPT_HEBREW => &_binary_resources_fonts_noto_NotoSerifHebrew_Regular_otf_start,
1040            HB_SCRIPT_IMPERIAL_ARAMAIC => {
1041                &_binary_resources_fonts_noto_NotoSansImperialAramaic_Regular_otf_start
1042            }
1043            HB_SCRIPT_INSCRIPTIONAL_PAHLAVI => {
1044                &_binary_resources_fonts_noto_NotoSansInscriptionalPahlavi_Regular_otf_start
1045            }
1046            HB_SCRIPT_INSCRIPTIONAL_PARTHIAN => {
1047                &_binary_resources_fonts_noto_NotoSansInscriptionalParthian_Regular_otf_start
1048            }
1049            HB_SCRIPT_JAVANESE => &_binary_resources_fonts_noto_NotoSansJavanese_Regular_otf_start,
1050            HB_SCRIPT_KAITHI => &_binary_resources_fonts_noto_NotoSansKaithi_Regular_otf_start,
1051            HB_SCRIPT_KANNADA => &_binary_resources_fonts_noto_NotoSerifKannada_Regular_otf_start,
1052            HB_SCRIPT_KAWI => &_binary_resources_fonts_noto_NotoSansKawi_Regular_otf_start,
1053            HB_SCRIPT_KAYAH_LI => &_binary_resources_fonts_noto_NotoSansKayahLi_Regular_otf_start,
1054            HB_SCRIPT_KHAROSHTHI => {
1055                &_binary_resources_fonts_noto_NotoSansKharoshthi_Regular_otf_start
1056            }
1057            HB_SCRIPT_KHITAN_SMALL_SCRIPT => {
1058                &_binary_resources_fonts_noto_NotoSerifKhitanSmallScript_Regular_otf_start
1059            }
1060            HB_SCRIPT_KHMER => &_binary_resources_fonts_noto_NotoSerifKhmer_Regular_otf_start,
1061            HB_SCRIPT_KHOJKI => &_binary_resources_fonts_noto_NotoSerifKhojki_Regular_otf_start,
1062            HB_SCRIPT_KHUDAWADI => {
1063                &_binary_resources_fonts_noto_NotoSansKhudawadi_Regular_otf_start
1064            }
1065            HB_SCRIPT_LAO => &_binary_resources_fonts_noto_NotoSerifLao_Regular_otf_start,
1066            HB_SCRIPT_LEPCHA => &_binary_resources_fonts_noto_NotoSansLepcha_Regular_otf_start,
1067            HB_SCRIPT_LIMBU => &_binary_resources_fonts_noto_NotoSansLimbu_Regular_otf_start,
1068            HB_SCRIPT_LINEAR_A => &_binary_resources_fonts_noto_NotoSansLinearA_Regular_otf_start,
1069            HB_SCRIPT_LINEAR_B => &_binary_resources_fonts_noto_NotoSansLinearB_Regular_otf_start,
1070            HB_SCRIPT_LISU => &_binary_resources_fonts_noto_NotoSansLisu_Regular_otf_start,
1071            HB_SCRIPT_LYCIAN => &_binary_resources_fonts_noto_NotoSansLycian_Regular_otf_start,
1072            HB_SCRIPT_LYDIAN => &_binary_resources_fonts_noto_NotoSansLydian_Regular_otf_start,
1073            HB_SCRIPT_MAHAJANI => &_binary_resources_fonts_noto_NotoSansMahajani_Regular_otf_start,
1074            HB_SCRIPT_MAKASAR => &_binary_resources_fonts_noto_NotoSerifMakasar_Regular_otf_start,
1075            HB_SCRIPT_MALAYALAM => {
1076                &_binary_resources_fonts_noto_NotoSerifMalayalam_Regular_otf_start
1077            }
1078            HB_SCRIPT_MANDAIC => &_binary_resources_fonts_noto_NotoSansMandaic_Regular_otf_start,
1079            HB_SCRIPT_MANICHAEAN => {
1080                &_binary_resources_fonts_noto_NotoSansManichaean_Regular_otf_start
1081            }
1082            HB_SCRIPT_MARCHEN => &_binary_resources_fonts_noto_NotoSansMarchen_Regular_otf_start,
1083            HB_SCRIPT_MASARAM_GONDI => {
1084                &_binary_resources_fonts_noto_NotoSansMasaramGondi_Regular_otf_start
1085            }
1086            HB_SCRIPT_MEDEFAIDRIN => {
1087                &_binary_resources_fonts_noto_NotoSansMedefaidrin_Regular_otf_start
1088            }
1089            HB_SCRIPT_MEETEI_MAYEK => {
1090                &_binary_resources_fonts_noto_NotoSansMeeteiMayek_Regular_otf_start
1091            }
1092            HB_SCRIPT_MENDE_KIKAKUI => {
1093                &_binary_resources_fonts_noto_NotoSansMendeKikakui_Regular_otf_start
1094            }
1095            HB_SCRIPT_MIAO => &_binary_resources_fonts_noto_NotoSansMiao_Regular_otf_start,
1096            HB_SCRIPT_MODI => &_binary_resources_fonts_noto_NotoSansModi_Regular_otf_start,
1097            HB_SCRIPT_MONGOLIAN => {
1098                &_binary_resources_fonts_noto_NotoSansMongolian_Regular_otf_start
1099            }
1100            HB_SCRIPT_MRO => &_binary_resources_fonts_noto_NotoSansMro_Regular_otf_start,
1101            HB_SCRIPT_MULTANI => &_binary_resources_fonts_noto_NotoSansMultani_Regular_otf_start,
1102            HB_SCRIPT_MYANMAR => &_binary_resources_fonts_noto_NotoSerifMyanmar_Regular_otf_start,
1103            HB_SCRIPT_NABATAEAN => {
1104                &_binary_resources_fonts_noto_NotoSansNabataean_Regular_otf_start
1105            }
1106            HB_SCRIPT_NAG_MUNDARI => {
1107                &_binary_resources_fonts_noto_NotoSansNagMundari_Regular_otf_start
1108            }
1109            HB_SCRIPT_NANDINAGARI => {
1110                &_binary_resources_fonts_noto_NotoSansNandinagari_Regular_otf_start
1111            }
1112            HB_SCRIPT_NEWA => &_binary_resources_fonts_noto_NotoSansNewa_Regular_otf_start,
1113            HB_SCRIPT_NEW_TAI_LUE => {
1114                &_binary_resources_fonts_noto_NotoSansNewTaiLue_Regular_otf_start
1115            }
1116            HB_SCRIPT_NKO => &_binary_resources_fonts_noto_NotoSansNKo_Regular_otf_start,
1117            HB_SCRIPT_NUSHU => &_binary_resources_fonts_noto_NotoSansNushu_Regular_otf_start,
1118            HB_SCRIPT_NYIAKENG_PUACHUE_HMONG => {
1119                &_binary_resources_fonts_noto_NotoSerifNyiakengPuachueHmong_Regular_otf_start
1120            }
1121            HB_SCRIPT_OGHAM => &_binary_resources_fonts_noto_NotoSansOgham_Regular_otf_start,
1122            HB_SCRIPT_OLD_HUNGARIAN => {
1123                &_binary_resources_fonts_noto_NotoSansOldHungarian_Regular_otf_start
1124            }
1125            HB_SCRIPT_OLD_ITALIC => {
1126                &_binary_resources_fonts_noto_NotoSansOldItalic_Regular_otf_start
1127            }
1128            HB_SCRIPT_OLD_NORTH_ARABIAN => {
1129                &_binary_resources_fonts_noto_NotoSansOldNorthArabian_Regular_otf_start
1130            }
1131            HB_SCRIPT_OLD_PERMIC => {
1132                &_binary_resources_fonts_noto_NotoSansOldPermic_Regular_otf_start
1133            }
1134            HB_SCRIPT_OLD_PERSIAN => {
1135                &_binary_resources_fonts_noto_NotoSansOldPersian_Regular_otf_start
1136            }
1137            HB_SCRIPT_OLD_SOGDIAN => {
1138                &_binary_resources_fonts_noto_NotoSansOldSogdian_Regular_otf_start
1139            }
1140            HB_SCRIPT_OLD_SOUTH_ARABIAN => {
1141                &_binary_resources_fonts_noto_NotoSansOldSouthArabian_Regular_otf_start
1142            }
1143            HB_SCRIPT_OLD_TURKIC => {
1144                &_binary_resources_fonts_noto_NotoSansOldTurkic_Regular_otf_start
1145            }
1146            HB_SCRIPT_OLD_UYGHUR => {
1147                &_binary_resources_fonts_noto_NotoSerifOldUyghur_Regular_otf_start
1148            }
1149            HB_SCRIPT_OL_CHIKI => &_binary_resources_fonts_noto_NotoSansOlChiki_Regular_otf_start,
1150            HB_SCRIPT_ORIYA => &_binary_resources_fonts_noto_NotoSerifOriya_Regular_otf_start,
1151            HB_SCRIPT_OSAGE => &_binary_resources_fonts_noto_NotoSansOsage_Regular_otf_start,
1152            HB_SCRIPT_OSMANYA => &_binary_resources_fonts_noto_NotoSansOsmanya_Regular_otf_start,
1153            HB_SCRIPT_PAHAWH_HMONG => {
1154                &_binary_resources_fonts_noto_NotoSansPahawhHmong_Regular_otf_start
1155            }
1156            HB_SCRIPT_PALMYRENE => {
1157                &_binary_resources_fonts_noto_NotoSansPalmyrene_Regular_otf_start
1158            }
1159            HB_SCRIPT_PAU_CIN_HAU => {
1160                &_binary_resources_fonts_noto_NotoSansPauCinHau_Regular_otf_start
1161            }
1162            HB_SCRIPT_PHAGS_PA => &_binary_resources_fonts_noto_NotoSansPhagsPa_Regular_otf_start,
1163            HB_SCRIPT_PHOENICIAN => {
1164                &_binary_resources_fonts_noto_NotoSansPhoenician_Regular_otf_start
1165            }
1166            HB_SCRIPT_PSALTER_PAHLAVI => {
1167                &_binary_resources_fonts_noto_NotoSansPsalterPahlavi_Regular_otf_start
1168            }
1169            HB_SCRIPT_REJANG => &_binary_resources_fonts_noto_NotoSansRejang_Regular_otf_start,
1170            HB_SCRIPT_RUNIC => &_binary_resources_fonts_noto_NotoSansRunic_Regular_otf_start,
1171            HB_SCRIPT_SAMARITAN => {
1172                &_binary_resources_fonts_noto_NotoSansSamaritan_Regular_otf_start
1173            }
1174            HB_SCRIPT_SAURASHTRA => {
1175                &_binary_resources_fonts_noto_NotoSansSaurashtra_Regular_otf_start
1176            }
1177            HB_SCRIPT_SHARADA => &_binary_resources_fonts_noto_NotoSansSharada_Regular_otf_start,
1178            HB_SCRIPT_SHAVIAN => &_binary_resources_fonts_noto_NotoSansShavian_Regular_otf_start,
1179            HB_SCRIPT_SIDDHAM => &_binary_resources_fonts_noto_NotoSansSiddham_Regular_otf_start,
1180            HB_SCRIPT_SIGNWRITING => {
1181                &_binary_resources_fonts_noto_NotoSansSignWriting_Regular_otf_start
1182            }
1183            HB_SCRIPT_SINHALA => &_binary_resources_fonts_noto_NotoSerifSinhala_Regular_otf_start,
1184            HB_SCRIPT_SOGDIAN => &_binary_resources_fonts_noto_NotoSansSogdian_Regular_otf_start,
1185            HB_SCRIPT_SORA_SOMPENG => {
1186                &_binary_resources_fonts_noto_NotoSansSoraSompeng_Regular_otf_start
1187            }
1188            HB_SCRIPT_SOYOMBO => &_binary_resources_fonts_noto_NotoSansSoyombo_Regular_otf_start,
1189            HB_SCRIPT_SUNDANESE => {
1190                &_binary_resources_fonts_noto_NotoSansSundanese_Regular_otf_start
1191            }
1192            HB_SCRIPT_SYLOTI_NAGRI => {
1193                &_binary_resources_fonts_noto_NotoSansSylotiNagri_Regular_otf_start
1194            }
1195            HB_SCRIPT_TAGALOG => &_binary_resources_fonts_noto_NotoSansTagalog_Regular_otf_start,
1196            HB_SCRIPT_TAGBANWA => &_binary_resources_fonts_noto_NotoSansTagbanwa_Regular_otf_start,
1197            HB_SCRIPT_TAI_LE => &_binary_resources_fonts_noto_NotoSansTaiLe_Regular_otf_start,
1198            HB_SCRIPT_TAI_THAM => &_binary_resources_fonts_noto_NotoSansTaiTham_Regular_otf_start,
1199            HB_SCRIPT_TAI_VIET => &_binary_resources_fonts_noto_NotoSansTaiViet_Regular_otf_start,
1200            HB_SCRIPT_TAKRI => &_binary_resources_fonts_noto_NotoSansTakri_Regular_otf_start,
1201            HB_SCRIPT_TAMIL => &_binary_resources_fonts_noto_NotoSerifTamil_Regular_otf_start,
1202            HB_SCRIPT_TANGSA => &_binary_resources_fonts_noto_NotoSansTangsa_Regular_otf_start,
1203            HB_SCRIPT_TELUGU => &_binary_resources_fonts_noto_NotoSerifTelugu_Regular_otf_start,
1204            HB_SCRIPT_THAANA => &_binary_resources_fonts_noto_NotoSansThaana_Regular_otf_start,
1205            HB_SCRIPT_THAI => &_binary_resources_fonts_noto_NotoSerifThai_Regular_otf_start,
1206            HB_SCRIPT_TIBETAN => &_binary_resources_fonts_noto_NotoSerifTibetan_Regular_otf_start,
1207            HB_SCRIPT_TIFINAGH => &_binary_resources_fonts_noto_NotoSansTifinagh_Regular_otf_start,
1208            HB_SCRIPT_TIRHUTA => &_binary_resources_fonts_noto_NotoSansTirhuta_Regular_otf_start,
1209            HB_SCRIPT_TOTO => &_binary_resources_fonts_noto_NotoSerifToto_Regular_otf_start,
1210            HB_SCRIPT_UGARITIC => &_binary_resources_fonts_noto_NotoSansUgaritic_Regular_otf_start,
1211            HB_SCRIPT_VAI => &_binary_resources_fonts_noto_NotoSansVai_Regular_otf_start,
1212            HB_SCRIPT_VITHKUQI => &_binary_resources_fonts_noto_NotoSerifVithkuqi_Regular_otf_start,
1213            HB_SCRIPT_WANCHO => &_binary_resources_fonts_noto_NotoSansWancho_Regular_otf_start,
1214            HB_SCRIPT_WARANG_CITI => {
1215                &_binary_resources_fonts_noto_NotoSansWarangCiti_Regular_otf_start
1216            }
1217            HB_SCRIPT_YEZIDI => &_binary_resources_fonts_noto_NotoSerifYezidi_Regular_otf_start,
1218            HB_SCRIPT_YI => &_binary_resources_fonts_noto_NotoSansYi_Regular_otf_start,
1219            HB_SCRIPT_ZANABAZAR_SQUARE => {
1220                &_binary_resources_fonts_noto_NotoSansZanabazarSquare_Regular_otf_start
1221            }
1222
1223            HB_SYMBOL_MATHS => &_binary_resources_fonts_noto_NotoSansMath_Regular_otf_start,
1224            HB_SYMBOL_MUSIC => &_binary_resources_fonts_noto_NotoMusic_Regular_otf_start,
1225            HB_SYMBOL_MISC_ONE => &_binary_resources_fonts_noto_NotoSansSymbols_Regular_otf_start,
1226            HB_SCRIPT_BRAILLE | HB_SYMBOL_MISC_TWO => {
1227                &_binary_resources_fonts_noto_NotoSansSymbols2_Regular_otf_start
1228            }
1229            HB_SYMBOL_EMOJI => &_binary_resources_fonts_noto_NotoEmoji_Regular_ttf_start,
1230
1231            _ => &_binary_resources_fonts_droid_DroidSansFallback_ttf_start,
1232        }
1233    }
1234}
1235
1236#[inline]
1237fn script_from_code(code: u32) -> HbScript {
1238    // Can be updated when the font changes by comparing the expanded output of
1239    // `ttfdump -t cmap` for each font.
1240    match code {
1241        0x2032..=0x2037
1242        | 0x2057
1243        | 0x20D0..=0x20DC
1244        | 0x20E1
1245        | 0x20E5..=0x20EF
1246        | 0x2102
1247        | 0x210A..=0x210E
1248        | 0x2110..=0x2112
1249        | 0x2115
1250        | 0x2119..=0x211D
1251        | 0x2124
1252        | 0x2128
1253        | 0x212C
1254        | 0x212D
1255        | 0x212F..=0x2131
1256        | 0x2133..=0x2138
1257        | 0x213C..=0x2140
1258        | 0x2145..=0x2149
1259        | 0x2190..=0x21AE
1260        | 0x21B0..=0x21E5
1261        | 0x21F1
1262        | 0x21F2
1263        | 0x21F4..=0x22FF
1264        | 0x2308..=0x230B
1265        | 0x2310
1266        | 0x2319
1267        | 0x231C..=0x2321
1268        | 0x2336..=0x237A
1269        | 0x237C
1270        | 0x2395
1271        | 0x239B..=0x23B6
1272        | 0x23D0
1273        | 0x23DC..=0x23E1
1274        | 0x2474
1275        | 0x2475
1276        | 0x25AF
1277        | 0x25B3
1278        | 0x25B7
1279        | 0x25BD
1280        | 0x25C1
1281        | 0x25CA
1282        | 0x25CC
1283        | 0x25FB
1284        | 0x266D..=0x266F
1285        | 0x27C0..=0x27FF
1286        | 0x2900..=0x2AFF
1287        | 0x2B0E..=0x2B11
1288        | 0x2B30..=0x2B4C
1289        | 0x2BFE
1290        | 0xFF5B
1291        | 0xFF5D
1292        | 0x1D400..=0x1D454
1293        | 0x1D456..=0x1D49C
1294        | 0x1D49E
1295        | 0x1D49F
1296        | 0x1D4A2
1297        | 0x1D4A5
1298        | 0x1D4A6
1299        | 0x1D4A9..=0x1D4AC
1300        | 0x1D4AE..=0x1D4B9
1301        | 0x1D4BB
1302        | 0x1D4BD..=0x1D4C3
1303        | 0x1D4C5..=0x1D505
1304        | 0x1D507..=0x1D50A
1305        | 0x1D50D..=0x1D514
1306        | 0x1D516..=0x1D51C
1307        | 0x1D51E..=0x1D539
1308        | 0x1D53B..=0x1D53E
1309        | 0x1D540..=0x1D544
1310        | 0x1D546
1311        | 0x1D54A..=0x1D550
1312        | 0x1D552..=0x1D6A5
1313        | 0x1D6A8..=0x1D7CB
1314        | 0x1D7CE..=0x1D7FF
1315        | 0x1EE00..=0x1EE03
1316        | 0x1EE05..=0x1EE1F
1317        | 0x1EE21
1318        | 0x1EE22
1319        | 0x1EE24
1320        | 0x1EE27
1321        | 0x1EE29..=0x1EE32
1322        | 0x1EE34..=0x1EE37
1323        | 0x1EE39
1324        | 0x1EE3B
1325        | 0x1EE42
1326        | 0x1EE47
1327        | 0x1EE49
1328        | 0x1EE4B
1329        | 0x1EE4D..=0x1EE4F
1330        | 0x1EE51
1331        | 0x1EE52
1332        | 0x1EE54
1333        | 0x1EE57
1334        | 0x1EE59
1335        | 0x1EE5B
1336        | 0x1EE5D
1337        | 0x1EE5F
1338        | 0x1EE61
1339        | 0x1EE62
1340        | 0x1EE64
1341        | 0x1EE67..=0x1EE6A
1342        | 0x1EE6C..=0x1EE72
1343        | 0x1EE74..=0x1EE77
1344        | 0x1EE79..=0x1EE7C
1345        | 0x1EE7E
1346        | 0x1EE80..=0x1EE89
1347        | 0x1EE8B..=0x1EE9B
1348        | 0x1EEA1..=0x1EEA3
1349        | 0x1EEA5..=0x1EEA9
1350        | 0x1EEAB..=0x1EEBB
1351        | 0x1EEF0
1352        | 0x1EEF1 => HB_SYMBOL_MATHS,
1353
1354        0x1D000..=0x1D0F5 | 0x1D100..=0x1D126 | 0x1D129..=0x1D1E8 | 0x1D200..=0x1D245 => {
1355            HB_SYMBOL_MUSIC
1356        }
1357
1358        0x20DD..=0x20E0
1359        | 0x20E2..=0x20E4
1360        | 0x2160..=0x2183
1361        | 0x2185..=0x2188
1362        | 0x218A
1363        | 0x218B
1364        | 0x2300..=0x230F
1365        | 0x2311..=0x2315
1366        | 0x2317
1367        | 0x2322
1368        | 0x2323
1369        | 0x2329
1370        | 0x232A
1371        | 0x232C..=0x2335
1372        | 0x2380..=0x2394
1373        | 0x2396..=0x239A
1374        | 0x23BE..=0x23CD
1375        | 0x23D1..=0x23DB
1376        | 0x23E2..=0x23E8
1377        | 0x2460..=0x24FF
1378        | 0x260A..=0x260D
1379        | 0x2613
1380        | 0x2624..=0x262F
1381        | 0x2638..=0x263B
1382        | 0x263D..=0x2653
1383        | 0x2669..=0x267E
1384        | 0x2690..=0x269D
1385        | 0x26A2..=0x26A9
1386        | 0x26AD..=0x26BC
1387        | 0x26CE
1388        | 0x26E2..=0x26FF
1389        | 0x271D..=0x2721
1390        | 0x2776..=0x2793
1391        | 0x1F100..=0x1F10C
1392        | 0x1F110..=0x1F12F
1393        | 0x1F130..=0x1F16C
1394        | 0x1F170..=0x1F190
1395        | 0x1F19B..=0x1F1AC
1396        | 0x1F546..=0x1F549
1397        | 0x1F54F
1398        | 0x1F610
1399        | 0x1F700..=0x1F773 => HB_SYMBOL_MISC_ONE,
1400
1401        0x2022
1402        | 0x21AF
1403        | 0x21E6..=0x21F0
1404        | 0x21F3
1405        | 0x2316
1406        | 0x2318
1407        | 0x231A
1408        | 0x231B
1409        | 0x2324..=0x2328
1410        | 0x232B
1411        | 0x237B
1412        | 0x237D..=0x237F
1413        | 0x23CE
1414        | 0x23CF
1415        | 0x23E9
1416        | 0x23ED..=0x23EF
1417        | 0x23F1..=0x23FF
1418        | 0x2400..=0x2426
1419        | 0x2440..=0x244A
1420        | 0x25A0..=0x2609
1421        | 0x260E..=0x2612
1422        | 0x2614..=0x2623
1423        | 0x2630..=0x2637
1424        | 0x263C
1425        | 0x2654..=0x2668
1426        | 0x267F..=0x268F
1427        | 0x269E..=0x26A1
1428        | 0x26AA..=0x26AC
1429        | 0x26BD..=0x26CD
1430        | 0x26CF..=0x26E1
1431        | 0x2700..=0x2704
1432        | 0x2706..=0x2709
1433        | 0x270B..=0x271C
1434        | 0x2722..=0x2727
1435        | 0x2729..=0x274B
1436        | 0x274D
1437        | 0x274F..=0x2752
1438        | 0x2756..=0x2775
1439        | 0x2794
1440        | 0x2798..=0x27AF
1441        | 0x27B1..=0x27BE
1442        | 0x2800..=0x28FF
1443        | 0x2B00..=0x2B0D
1444        | 0x2B12..=0x2B2F
1445        | 0x2B4D..=0x2B73
1446        | 0x2B76..=0x2B95
1447        | 0x2B97..=0x2BFD
1448        | 0x2BFF
1449        | 0x4DC0..=0x4DFF
1450        | 0xFFF9..=0xFFFB
1451        | 0x10140..=0x1018E
1452        | 0x10190..=0x1019C
1453        | 0x101A0
1454        | 0x101D0..=0x101FD
1455        | 0x102E0..=0x102FB
1456        | 0x10E60..=0x10E7E
1457        | 0x1D2E0..=0x1D2F3
1458        | 0x1D300..=0x1D356
1459        | 0x1D360..=0x1D378
1460        | 0x1F000..=0x1F02B
1461        | 0x1F030..=0x1F093
1462        | 0x1F0A0..=0x1F0AE
1463        | 0x1F0B1..=0x1F0BF
1464        | 0x1F0C1..=0x1F0CF
1465        | 0x1F0D1..=0x1F0F5
1466        | 0x1F30D..=0x1F30F
1467        | 0x1F315
1468        | 0x1F31C
1469        | 0x1F321..=0x1F32C
1470        | 0x1F336
1471        | 0x1F378
1472        | 0x1F37D
1473        | 0x1F394..=0x1F39F
1474        | 0x1F3A7
1475        | 0x1F3AC..=0x1F3AE
1476        | 0x1F3C2
1477        | 0x1F3CB..=0x1F3CE
1478        | 0x1F3D4..=0x1F3DF
1479        | 0x1F3ED
1480        | 0x1F3F1..=0x1F3F3
1481        | 0x1F3F5..=0x1F3F7
1482        | 0x1F408
1483        | 0x1F415
1484        | 0x1F41F
1485        | 0x1F426
1486        | 0x1F43F
1487        | 0x1F441
1488        | 0x1F446..=0x1F449
1489        | 0x1F44C..=0x1F44E
1490        | 0x1F453
1491        | 0x1F46A
1492        | 0x1F47D
1493        | 0x1F4A3
1494        | 0x1F4B0
1495        | 0x1F4B3
1496        | 0x1F4B9
1497        | 0x1F4BB
1498        | 0x1F4BF
1499        | 0x1F4C8..=0x1F4CB
1500        | 0x1F4DA
1501        | 0x1F4DF
1502        | 0x1F4E4..=0x1F4E6
1503        | 0x1F4EA..=0x1F4ED
1504        | 0x1F4F9..=0x1F4FB
1505        | 0x1F4FD
1506        | 0x1F4FE
1507        | 0x1F503
1508        | 0x1F507..=0x1F50A
1509        | 0x1F50D
1510        | 0x1F512
1511        | 0x1F513
1512        | 0x1F53E..=0x1F545
1513        | 0x1F54A
1514        | 0x1F550..=0x1F579
1515        | 0x1F57B..=0x1F594
1516        | 0x1F597..=0x1F5A3
1517        | 0x1F5A5..=0x1F5FA
1518        | 0x1F650..=0x1F67F
1519        | 0x1F687
1520        | 0x1F68D
1521        | 0x1F691
1522        | 0x1F694
1523        | 0x1F698
1524        | 0x1F6AD
1525        | 0x1F6B2
1526        | 0x1F6B9
1527        | 0x1F6BA
1528        | 0x1F6BC
1529        | 0x1F6C6..=0x1F6CB
1530        | 0x1F6CD..=0x1F6CF
1531        | 0x1F6D3..=0x1F6D7
1532        | 0x1F6E0..=0x1F6EA
1533        | 0x1F6F0..=0x1F6F3
1534        | 0x1F6F7..=0x1F6FC
1535        | 0x1F780..=0x1F7D8
1536        | 0x1F7E0..=0x1F7EB
1537        | 0x1F800..=0x1F80B
1538        | 0x1F810..=0x1F847
1539        | 0x1F850..=0x1F859
1540        | 0x1F860..=0x1F887
1541        | 0x1F890..=0x1F8AD
1542        | 0x1F8B0..=0x1F8B1
1543        | 0x1F93B
1544        | 0x1F946
1545        | 0x1FA00..=0x1FA53
1546        | 0x1FA60..=0x1FA6D
1547        | 0x1FA70..=0x1FA74
1548        | 0x1FA78..=0x1FA7A
1549        | 0x1FA80..=0x1FA86
1550        | 0x1FA90..=0x1FAA8
1551        | 0x1FAB0..=0x1FAB6
1552        | 0x1FAC0..=0x1FAC2
1553        | 0x1FAD0..=0x1FAD6
1554        | 0x1FB00..=0x1FBCA
1555        | 0x1FBF0..=0x1FBF9 => HB_SYMBOL_MISC_TWO,
1556
1557        0x2049
1558        | 0x2122
1559        | 0x2139
1560        | 0x23EA..=0x23EC
1561        | 0x23F0
1562        | 0x2705
1563        | 0x2708..=0x270C
1564        | 0x2728
1565        | 0x274C
1566        | 0x274E
1567        | 0x2753..=0x2755
1568        | 0x2795..=0x2797
1569        | 0x27B0
1570        | 0x27BF
1571        | 0x3030
1572        | 0x303D
1573        | 0x3297
1574        | 0x3299
1575        | 0xFEFF
1576        | 0x1F191..=0x1F19A
1577        | 0x1F1E6..=0x1F1FF
1578        | 0x1F201
1579        | 0x1F202
1580        | 0x1F21A
1581        | 0x1F22F
1582        | 0x1F232..=0x1F23A
1583        | 0x1F250
1584        | 0x1F251
1585        | 0x1F300..=0x1F320
1586        | 0x1F330..=0x1F335
1587        | 0x1F337..=0x1F37C
1588        | 0x1F380..=0x1F393
1589        | 0x1F3A0..=0x1F3C4
1590        | 0x1F3C6..=0x1F3CA
1591        | 0x1F3E0..=0x1F3F0
1592        | 0x1F400..=0x1F429
1593        | 0x1F42B..=0x1F43E
1594        | 0x1F440
1595        | 0x1F442..=0x1F4F7
1596        | 0x1F4F9..=0x1F4FC
1597        | 0x1F500..=0x1F53D
1598        | 0x1F5FB..=0x1F640
1599        | 0x1F645..=0x1F64F
1600        | 0x1F680..=0x1F697
1601        | 0x1F699..=0x1F6C5
1602        | 0xFE4E5..=0xFE4EE
1603        | 0xFE82C
1604        | 0xFE82E..=0xFE837 => HB_SYMBOL_EMOJI,
1605
1606        _ => HB_SCRIPT_UNKNOWN,
1607    }
1608}
1609
1610pub struct FontLibrary(*mut FtLibrary);
1611
1612pub struct FontOpener(Rc<FontLibrary>);
1613
1614pub struct Font {
1615    lib: Rc<FontLibrary>,
1616    face: *mut FtFace,
1617    font: *mut HbFont,
1618    size: u32,
1619    dpi: u16,
1620    // used as truncation mark
1621    pub ellipsis: RenderPlan,
1622    // lowercase and uppercase x heights
1623    pub x_heights: (u32, u32),
1624    space_codepoint: u32,
1625}
1626
1627impl FontOpener {
1628    pub fn new() -> Result<FontOpener, Error> {
1629        unsafe {
1630            let mut lib = ptr::null_mut();
1631            let ret = FT_Init_FreeType(&mut lib);
1632            if ret != FT_ERR_OK {
1633                Err(Error::from(FreetypeError::from(ret)))
1634            } else {
1635                Ok(FontOpener(Rc::new(FontLibrary(lib))))
1636            }
1637        }
1638    }
1639
1640    pub fn open<P: AsRef<Path>>(&self, path: P) -> Result<Font, Error> {
1641        unsafe {
1642            let mut face = ptr::null_mut();
1643            let c_path = CString::new(path.as_ref().as_os_str().as_bytes()).unwrap();
1644            let ret = FT_New_Face((self.0).0, c_path.as_ptr(), 0, &mut face);
1645            if ret != FT_ERR_OK {
1646                return Err(Error::from(FreetypeError::from(ret)));
1647            }
1648            let font = ptr::null_mut();
1649            let ellipsis = RenderPlan::default();
1650            let x_heights = (0, 0);
1651            let space_codepoint = FT_Get_Char_Index(face, ' ' as libc::c_ulong);
1652            Ok(Font {
1653                lib: self.0.clone(),
1654                face,
1655                font,
1656                size: 0,
1657                dpi: 0,
1658                ellipsis,
1659                x_heights,
1660                space_codepoint,
1661            })
1662        }
1663    }
1664
1665    pub fn open_memory(&self, buf: &[u8]) -> Result<Font, Error> {
1666        unsafe {
1667            let mut face = ptr::null_mut();
1668            let ret = FT_New_Memory_Face(
1669                (self.0).0,
1670                buf.as_ptr() as *const FtByte,
1671                buf.len() as libc::c_long,
1672                0,
1673                &mut face,
1674            );
1675            if ret != FT_ERR_OK {
1676                return Err(Error::from(FreetypeError::from(ret)));
1677            }
1678            let ellipsis = RenderPlan::default();
1679            let font = ptr::null_mut();
1680            let x_heights = (0, 0);
1681            let space_codepoint = FT_Get_Char_Index(face, ' ' as libc::c_ulong);
1682            Ok(Font {
1683                lib: self.0.clone(),
1684                face,
1685                font,
1686                size: 0,
1687                dpi: 0,
1688                ellipsis,
1689                x_heights,
1690                space_codepoint,
1691            })
1692        }
1693    }
1694}
1695
1696impl Font {
1697    pub fn family_name(&self) -> Option<&str> {
1698        unsafe {
1699            let ptr = (*self.face).family_name;
1700            if ptr.is_null() {
1701                return None;
1702            }
1703            CStr::from_ptr(ptr).to_str().ok()
1704        }
1705    }
1706
1707    pub fn style_name(&self) -> Option<&str> {
1708        unsafe {
1709            let ptr = (*self.face).style_name;
1710            if ptr.is_null() {
1711                return None;
1712            }
1713            CStr::from_ptr(ptr).to_str().ok()
1714        }
1715    }
1716
1717    pub fn set_size(&mut self, size: u32, dpi: u16) {
1718        if !self.font.is_null() && self.size == size && self.dpi == dpi {
1719            return;
1720        }
1721
1722        self.size = size;
1723        self.dpi = dpi;
1724
1725        unsafe {
1726            let ret = FT_Set_Char_Size(self.face, size as FtF26Dot6, 0, dpi as libc::c_uint, 0);
1727
1728            if ret != FT_ERR_OK {
1729                return;
1730            }
1731
1732            if self.font.is_null() {
1733                self.font = hb_ft_font_create(self.face, ptr::null());
1734            } else {
1735                hb_ft_font_changed(self.font);
1736            }
1737
1738            self.ellipsis = self.plan("…", None, None);
1739            self.x_heights = (self.height('x'), self.height('X'));
1740        }
1741    }
1742
1743    pub fn set_variations(&mut self, specs: &[&str]) {
1744        unsafe {
1745            let mut varia = ptr::null_mut();
1746            let ret = FT_Get_MM_Var(self.face, &mut varia);
1747
1748            if ret != FT_ERR_OK {
1749                return;
1750            }
1751
1752            let axes_count = (*varia).num_axis as usize;
1753            let mut coords = Vec::with_capacity(axes_count);
1754
1755            for i in 0..(axes_count as isize) {
1756                let axis = ((*varia).axis).offset(i);
1757                coords.push((*axis).def);
1758            }
1759
1760            for s in specs {
1761                let tn = s[..4].as_bytes();
1762                let tag = tag(tn[0], tn[1], tn[2], tn[3]);
1763                let value: f32 = s[5..].parse().unwrap_or_default();
1764
1765                for i in 0..(axes_count as isize) {
1766                    let axis = ((*varia).axis).offset(i);
1767
1768                    if (*axis).tag == tag as libc::c_ulong {
1769                        let scaled_value = ((value * 65536.0) as FtFixed)
1770                            .min((*axis).maximum)
1771                            .max((*axis).minimum);
1772                        *coords.get_unchecked_mut(i as usize) = scaled_value;
1773                        break;
1774                    }
1775                }
1776            }
1777
1778            let ret = FT_Set_Var_Design_Coordinates(
1779                self.face,
1780                coords.len() as libc::c_uint,
1781                coords.as_ptr(),
1782            );
1783
1784            if ret == FT_ERR_OK && !self.font.is_null() {
1785                hb_ft_font_changed(self.font);
1786            }
1787
1788            FT_Done_MM_Var(self.lib.0, varia);
1789        }
1790    }
1791
1792    pub fn set_variations_from_name(&mut self, name: &str) -> bool {
1793        let mut found = false;
1794
1795        unsafe {
1796            let mut varia = ptr::null_mut();
1797            let ret = FT_Get_MM_Var(self.face, &mut varia);
1798
1799            if ret != FT_ERR_OK {
1800                return found;
1801            }
1802
1803            let styles_count = (*varia).num_namedstyles as isize;
1804            let names_count = FT_Get_Sfnt_Name_Count(self.face);
1805            let mut sfnt_name = FtSfntName::default();
1806
1807            'outer: for i in 0..styles_count {
1808                let style = ((*varia).namedstyle).offset(i);
1809                let strid = (*style).strid as libc::c_ushort;
1810                for j in 0..names_count {
1811                    let ret = FT_Get_Sfnt_Name(self.face, j, &mut sfnt_name);
1812
1813                    if ret != FT_ERR_OK || sfnt_name.name_id != strid {
1814                        continue;
1815                    }
1816
1817                    if sfnt_name.platform_id != TT_PLATFORM_MICROSOFT
1818                        || sfnt_name.encoding_id != TT_MS_ID_UNICODE_CS
1819                        || sfnt_name.language_id != TT_MS_LANGID_ENGLISH_UNITED_STATES
1820                    {
1821                        continue;
1822                    }
1823
1824                    let slice = slice::from_raw_parts(sfnt_name.text, sfnt_name.len as usize);
1825                    // We're assuming ASCII encoded as UTF_16BE
1826                    let vec_ascii: Vec<u8> = slice
1827                        .iter()
1828                        .enumerate()
1829                        .filter_map(|x| if x.0 % 2 == 0 { None } else { Some(*x.1) })
1830                        .collect();
1831
1832                    if let Ok(name_str) = str::from_utf8(&vec_ascii[..]) {
1833                        if name.eq_ignore_ascii_case(name_str) {
1834                            found = true;
1835                            let ret = FT_Set_Var_Design_Coordinates(
1836                                self.face,
1837                                (*varia).num_axis,
1838                                (*style).coords,
1839                            );
1840                            if ret == FT_ERR_OK && !self.font.is_null() {
1841                                hb_ft_font_changed(self.font);
1842                            }
1843                            break 'outer;
1844                        }
1845                    }
1846                }
1847            }
1848
1849            FT_Done_MM_Var(self.lib.0, varia);
1850        }
1851
1852        found
1853    }
1854
1855    #[inline]
1856    unsafe fn patch(
1857        &mut self,
1858        txt: &str,
1859        features: &[HbFeature],
1860        render_plan: &mut RenderPlan,
1861        missing_glyphs: Vec<(usize, usize)>,
1862        buf: *mut HbBuffer,
1863    ) {
1864        unsafe {
1865            let mut drift = 0;
1866            for (mut start, mut end) in missing_glyphs.into_iter() {
1867                start = (start as i32 + drift).max(0) as usize;
1868                end = (end as i32 + drift).max(0) as usize;
1869                hb_buffer_clear_contents(buf);
1870                let start_index = render_plan.glyphs[start].cluster;
1871                let end_index = render_plan
1872                    .glyphs
1873                    .get(end)
1874                    .map(|g| g.cluster)
1875                    .unwrap_or_else(|| txt.len());
1876                let chunk = &txt[start_index..end_index];
1877                hb_buffer_add_utf8(
1878                    buf,
1879                    chunk.as_ptr() as *const libc::c_char,
1880                    chunk.len() as libc::c_int,
1881                    0,
1882                    -1,
1883                );
1884                hb_buffer_guess_segment_properties(buf);
1885                let mut script = hb_buffer_get_script(buf);
1886                if (script == HB_SCRIPT_INVALID || script == HB_SCRIPT_UNKNOWN)
1887                    && let Some(c) = chunk.chars().next()
1888                {
1889                    script = script_from_code(u32::from(c));
1890                }
1891                let font_data = font_data_from_script(script);
1892                let mut face = ptr::null_mut();
1893                let face_error = FT_New_Memory_Face(
1894                    (self.lib).0,
1895                    font_data.as_ptr() as *const FtByte,
1896                    font_data.len() as libc::c_long,
1897                    0,
1898                    &mut face,
1899                );
1900                if face_error != 0 || face.is_null() {
1901                    hb_buffer_destroy(buf);
1902                    tracing::warn!(face_error = face_error, "there has been a face_error");
1903
1904                    continue;
1905                }
1906                FT_Set_Pixel_Sizes(face, (*(*self.face).size).metrics.x_ppem as libc::c_uint, 0);
1907                let font = hb_ft_font_create(face, ptr::null());
1908                hb_shape(font, buf, features.as_ptr(), features.len() as libc::c_uint);
1909                let len = hb_buffer_get_length(buf) as usize;
1910                let info = hb_buffer_get_glyph_infos(buf, ptr::null_mut());
1911                let pos = hb_buffer_get_glyph_positions(buf, ptr::null_mut());
1912                let mut glyphs = Vec::with_capacity(len);
1913
1914                for i in 0..len {
1915                    let pos_i = &*pos.add(i);
1916                    let info_i = &*info.add(i);
1917                    render_plan.width += pos_i.x_advance >> 6;
1918                    glyphs.push(GlyphPlan {
1919                        codepoint: info_i.codepoint,
1920                        cluster: start_index + info_i.cluster as usize,
1921                        advance: pt!(pos_i.x_advance >> 6, pos_i.y_advance >> 6),
1922                        offset: pt!(pos_i.x_offset >> 6, -pos_i.y_offset >> 6),
1923                    });
1924                    render_plan.scripts.insert(start + i, script);
1925                }
1926
1927                render_plan.glyphs.splice(start..end, glyphs);
1928                drift += len as i32 - (end - start) as i32;
1929
1930                hb_font_destroy(font);
1931                FT_Done_Face(face);
1932            }
1933        }
1934    }
1935
1936    pub fn plan<S: AsRef<str>>(
1937        &mut self,
1938        text: S,
1939        max_width: Option<i32>,
1940        features: Option<&[String]>,
1941    ) -> RenderPlan {
1942        unsafe {
1943            let buf = hb_buffer_create();
1944            hb_buffer_add_utf8(
1945                buf,
1946                text.as_ref().as_ptr() as *const libc::c_char,
1947                text.as_ref().len() as libc::c_int,
1948                0,
1949                -1,
1950            );
1951
1952            // If the direction is RTL, the clusters are given in reverse order.
1953            hb_buffer_set_direction(buf, HB_DIRECTION_LTR);
1954            hb_buffer_guess_segment_properties(buf);
1955
1956            let features_vec: Vec<HbFeature> = features
1957                .map(|ftr| {
1958                    ftr.iter()
1959                        .filter_map(|f| {
1960                            let mut feature = HbFeature::default();
1961                            let ret = hb_feature_from_string(
1962                                f.as_ptr() as *const libc::c_char,
1963                                f.len() as libc::c_int,
1964                                &mut feature,
1965                            );
1966                            if ret == 1 { Some(feature) } else { None }
1967                        })
1968                        .collect()
1969                })
1970                .unwrap_or_default();
1971
1972            hb_shape(
1973                self.font,
1974                buf,
1975                features_vec.as_ptr(),
1976                features_vec.len() as libc::c_uint,
1977            );
1978
1979            let len = hb_buffer_get_length(buf) as usize;
1980            let info = hb_buffer_get_glyph_infos(buf, ptr::null_mut());
1981            let pos = hb_buffer_get_glyph_positions(buf, ptr::null_mut());
1982            let mut render_plan = RenderPlan::default();
1983            let mut missing_glyphs = Vec::new();
1984
1985            for i in 0..len {
1986                let pos_i = &*pos.add(i);
1987                let info_i = &*info.add(i);
1988                if info_i.codepoint == 0 {
1989                    if let Some((start, end)) = missing_glyphs.pop() {
1990                        if i == end {
1991                            missing_glyphs.push((start, end + 1));
1992                        } else {
1993                            missing_glyphs.push((start, end));
1994                            missing_glyphs.push((i, i + 1));
1995                        }
1996                    } else {
1997                        missing_glyphs.push((i, i + 1));
1998                    }
1999                } else {
2000                    render_plan.width += pos_i.x_advance >> 6;
2001                }
2002                let glyph = GlyphPlan {
2003                    codepoint: info_i.codepoint,
2004                    cluster: info_i.cluster as usize,
2005                    advance: pt!(pos_i.x_advance >> 6, pos_i.y_advance >> 6),
2006                    offset: pt!(pos_i.x_offset >> 6, -pos_i.y_offset >> 6),
2007                };
2008                render_plan.glyphs.push(glyph);
2009            }
2010
2011            self.patch(
2012                text.as_ref(),
2013                &features_vec,
2014                &mut render_plan,
2015                missing_glyphs,
2016                buf,
2017            );
2018
2019            hb_buffer_destroy(buf);
2020
2021            if let Some(mw) = max_width {
2022                self.crop_right(&mut render_plan, mw);
2023            }
2024
2025            render_plan
2026        }
2027    }
2028
2029    #[inline]
2030    pub fn crop_right(&self, render_plan: &mut RenderPlan, max_width: i32) {
2031        if render_plan.width <= max_width {
2032            return;
2033        }
2034
2035        render_plan.width += self.ellipsis.width;
2036
2037        while let Some(gp) = render_plan.glyphs.pop() {
2038            render_plan.width -= gp.advance.x;
2039            if render_plan.width <= max_width {
2040                break;
2041            }
2042        }
2043
2044        let len = render_plan.glyphs.len();
2045        render_plan.scripts.retain(|&k, _| k < len);
2046        render_plan
2047            .glyphs
2048            .extend_from_slice(&self.ellipsis.glyphs[..]);
2049    }
2050
2051    #[inline]
2052    pub fn trim_left(&self, render_plan: &mut RenderPlan) {
2053        if render_plan.glyphs.is_empty() {
2054            return;
2055        }
2056
2057        let mut i = 0;
2058
2059        while render_plan.glyphs[i].codepoint == self.space_codepoint {
2060            render_plan.width -= render_plan.glyphs[i].advance.x;
2061            i += 1;
2062        }
2063
2064        render_plan.glyphs.drain(..i);
2065        render_plan.scripts = render_plan
2066            .scripts
2067            .iter()
2068            .filter_map(|(&k, &v)| if k < i { None } else { Some((k - i, v)) })
2069            .collect();
2070    }
2071
2072    #[inline]
2073    pub fn crop_around(&self, render_plan: &mut RenderPlan, index: usize, max_width: i32) -> usize {
2074        if render_plan.width <= max_width {
2075            return 0;
2076        }
2077
2078        let len = render_plan.glyphs.len();
2079        let mut width = 0;
2080        let mut polarity = 0;
2081        let mut upper_index = index;
2082        let mut lower_index = index as i32 - 1;
2083
2084        loop {
2085            let next_width;
2086            if upper_index < len && (polarity % 2 == 0 || lower_index < 0) {
2087                next_width = width + render_plan.glyphs[upper_index].advance.x;
2088                if next_width > max_width {
2089                    break;
2090                } else {
2091                    width = next_width;
2092                }
2093                upper_index += 1;
2094            } else if lower_index >= 0 && (polarity % 2 == 1 || upper_index == len) {
2095                next_width = width + render_plan.glyphs[lower_index as usize].advance.x;
2096                if next_width > max_width {
2097                    break;
2098                } else {
2099                    width = next_width;
2100                }
2101                lower_index -= 1;
2102            }
2103            polarity += 1;
2104        }
2105
2106        if upper_index < len {
2107            width += self.ellipsis.width;
2108            upper_index -= 1;
2109            while width > max_width && upper_index > (lower_index.max(0) as usize) {
2110                width -= render_plan.glyphs[upper_index].advance.x;
2111                upper_index -= 1;
2112            }
2113            render_plan.glyphs.truncate(upper_index + 1);
2114            render_plan
2115                .glyphs
2116                .extend_from_slice(&self.ellipsis.glyphs[..]);
2117        }
2118
2119        if lower_index >= 0 {
2120            width += self.ellipsis.width;
2121            lower_index += 1;
2122            while width > max_width && (lower_index as usize) < upper_index {
2123                width -= render_plan.glyphs[lower_index as usize].advance.x;
2124                lower_index += 1;
2125            }
2126            render_plan.glyphs = self
2127                .ellipsis
2128                .glyphs
2129                .iter()
2130                .chain(render_plan.glyphs[lower_index as usize..].iter())
2131                .cloned()
2132                .collect();
2133        }
2134
2135        render_plan
2136            .scripts
2137            .retain(|&k, _| k >= lower_index.max(0) as usize && k <= upper_index);
2138        if lower_index > 0 {
2139            render_plan.scripts = render_plan
2140                .scripts
2141                .drain()
2142                .map(|(k, v)| (k - lower_index as usize + 1, v))
2143                .collect();
2144        }
2145        render_plan.width = width;
2146
2147        if lower_index < 0 {
2148            0
2149        } else {
2150            lower_index as usize
2151        }
2152    }
2153
2154    pub fn cut_point(&self, render_plan: &RenderPlan, max_width: i32) -> (usize, i32) {
2155        let mut width = render_plan.width;
2156        let glyphs = &render_plan.glyphs;
2157        let mut i = glyphs.len() - 1;
2158
2159        width -= glyphs[i].advance.x;
2160
2161        while i > 0 && width > max_width {
2162            i -= 1;
2163            width -= glyphs[i].advance.x;
2164        }
2165
2166        let j = i;
2167        let last_width = width;
2168
2169        while i > 0 && glyphs[i].codepoint != self.space_codepoint {
2170            i -= 1;
2171            width -= glyphs[i].advance.x;
2172        }
2173
2174        if i == 0 {
2175            i = j;
2176            width = last_width;
2177        }
2178
2179        (i, width)
2180    }
2181
2182    pub fn render(
2183        &mut self,
2184        fb: &mut dyn Framebuffer,
2185        color: Color,
2186        render_plan: &RenderPlan,
2187        origin: Point,
2188    ) {
2189        unsafe {
2190            let mut pos = origin;
2191            let mut fallback_faces = FxHashMap::default();
2192
2193            for (index, glyph) in render_plan.glyphs.iter().enumerate() {
2194                let face = if let Some(script) = render_plan.scripts.get(&index) {
2195                    *fallback_faces.entry(script).or_insert_with(|| {
2196                        let font_data = font_data_from_script(*script);
2197                        let mut face = ptr::null_mut();
2198                        FT_New_Memory_Face(
2199                            (self.lib).0,
2200                            font_data.as_ptr() as *const FtByte,
2201                            font_data.len() as libc::c_long,
2202                            0,
2203                            &mut face,
2204                        );
2205                        FT_Set_Pixel_Sizes(
2206                            face,
2207                            (*(*self.face).size).metrics.x_ppem as libc::c_uint,
2208                            0,
2209                        );
2210                        face
2211                    })
2212                } else {
2213                    self.face
2214                };
2215
2216                FT_Load_Glyph(face, glyph.codepoint, FT_LOAD_RENDER | FT_LOAD_NO_HINTING);
2217
2218                let glyph_slot = (*face).glyph;
2219                let top_left =
2220                    pos + glyph.offset + pt!((*glyph_slot).bitmap_left, -(*glyph_slot).bitmap_top);
2221                let bitmap = &(*glyph_slot).bitmap;
2222
2223                for y in 0..bitmap.rows {
2224                    for x in 0..bitmap.width {
2225                        let blackness = *bitmap.buffer.offset((bitmap.pitch * y + x) as isize);
2226                        let alpha = blackness as f32 / 255.0;
2227                        let pt = top_left + pt!(x, y);
2228                        fb.set_blended_pixel(pt.x as u32, pt.y as u32, color, alpha);
2229                    }
2230                }
2231
2232                pos += glyph.advance;
2233            }
2234
2235            for (_, face) in fallback_faces {
2236                FT_Done_Face(face);
2237            }
2238        }
2239    }
2240
2241    pub fn height(&self, c: char) -> u32 {
2242        unsafe {
2243            FT_Load_Char(self.face, c as libc::c_ulong, FT_LOAD_DEFAULT);
2244            let metrics = &((*(*self.face).glyph).metrics);
2245            (metrics.height >> 6) as u32
2246        }
2247    }
2248
2249    pub fn em(&self) -> u16 {
2250        unsafe { (*(*self.face).size).metrics.x_ppem as u16 }
2251    }
2252
2253    pub fn ascender(&self) -> i32 {
2254        unsafe { (*(*self.face).size).metrics.ascender as i32 / 64 }
2255    }
2256
2257    pub fn descender(&self) -> i32 {
2258        unsafe { (*(*self.face).size).metrics.descender as i32 / 64 }
2259    }
2260
2261    pub fn line_height(&self) -> i32 {
2262        unsafe { (*(*self.face).size).metrics.height as i32 / 64 }
2263    }
2264}
2265
2266#[derive(Debug, Copy, Clone)]
2267struct GlyphPlan {
2268    codepoint: u32,
2269    cluster: usize,
2270    offset: Point,
2271    advance: Point,
2272}
2273
2274#[derive(Debug, Clone)]
2275pub struct RenderPlan {
2276    pub width: i32,
2277    scripts: FxHashMap<usize, HbScript>,
2278    glyphs: Vec<GlyphPlan>,
2279}
2280
2281impl Default for RenderPlan {
2282    fn default() -> RenderPlan {
2283        RenderPlan {
2284            width: 0,
2285            scripts: FxHashMap::default(),
2286            glyphs: Vec::new(),
2287        }
2288    }
2289}
2290
2291impl RenderPlan {
2292    pub fn scale(&self, scale: f32) -> RenderPlan {
2293        let width = (scale * self.width as f32) as i32;
2294        let scripts = self.scripts.clone();
2295        let glyphs = self
2296            .glyphs
2297            .iter()
2298            .map(|gp| GlyphPlan {
2299                offset: Point::from(scale * Vec2::from(gp.offset)),
2300                advance: Point::from(scale * Vec2::from(gp.advance)),
2301                ..*gp
2302            })
2303            .collect();
2304        RenderPlan {
2305            width,
2306            scripts,
2307            glyphs,
2308        }
2309    }
2310
2311    pub fn space_out(&mut self, letter_spacing: i32) {
2312        if letter_spacing == 0 {
2313            return;
2314        }
2315
2316        if let Some((_, start)) = self.glyphs.split_last_mut() {
2317            let len = start.len() as i32;
2318            for glyph in start {
2319                glyph.advance.x += letter_spacing;
2320            }
2321            self.width += len * letter_spacing;
2322        }
2323    }
2324
2325    pub fn split_off(&mut self, index: usize, width: i32) -> RenderPlan {
2326        let mut next_scripts = FxHashMap::default();
2327        if !self.scripts.is_empty() {
2328            for i in index..self.glyphs.len() {
2329                self.scripts
2330                    .remove_entry(&i)
2331                    .map(|(k, v)| next_scripts.insert(k - index, v));
2332            }
2333        }
2334        let next_glyphs = self.glyphs.split_off(index);
2335        let next_width = self.width - width;
2336        self.width = width;
2337        RenderPlan {
2338            width: next_width,
2339            scripts: next_scripts,
2340            glyphs: next_glyphs,
2341        }
2342    }
2343
2344    pub fn index_from_advance(&self, advance: i32) -> usize {
2345        let mut sum = 0;
2346        let mut index = 0;
2347        while index < self.glyphs.len() {
2348            let gad = self.glyph_advance(index);
2349            sum += gad;
2350            if sum > advance {
2351                if sum - advance < advance - sum + gad {
2352                    index += 1;
2353                }
2354                break;
2355            }
2356            index += 1;
2357        }
2358        index
2359    }
2360
2361    pub fn append(&mut self, other: &mut Self) {
2362        let next_index = self.glyphs.len();
2363        self.scripts
2364            .extend(other.scripts.iter().map(|(k, v)| (next_index + k, *v)));
2365        self.glyphs.append(&mut other.glyphs);
2366        self.width += other.width;
2367    }
2368
2369    pub fn total_advance(&self, index: usize) -> i32 {
2370        self.glyphs.iter().take(index).map(|g| g.advance.x).sum()
2371    }
2372
2373    #[inline]
2374    pub fn glyph_advance(&self, index: usize) -> i32 {
2375        self.glyphs[index].advance.x
2376    }
2377}
2378
2379impl Drop for FontLibrary {
2380    fn drop(&mut self) {
2381        unsafe {
2382            FT_Done_FreeType(self.0);
2383        }
2384    }
2385}
2386
2387impl Drop for Font {
2388    fn drop(&mut self) {
2389        unsafe {
2390            FT_Done_Face(self.face);
2391            if !self.font.is_null() {
2392                hb_font_destroy(self.font);
2393            }
2394        }
2395    }
2396}
2397
2398#[inline]
2399fn tag(c1: u8, c2: u8, c3: u8, c4: u8) -> u32 {
2400    ((c1 as u32) << 24) | ((c2 as u32) << 16) | ((c3 as u32) << 8) | c4 as u32
2401}
2402
2403#[derive(Error, Debug)]
2404enum FreetypeError {
2405    #[error("Unknown error with code {0}.")]
2406    UnknownError(FtError),
2407
2408    #[error("Cannot open resource.")]
2409    CannotOpenResource,
2410
2411    #[error("Unknown file format.")]
2412    UnknownFileFormat,
2413
2414    #[error("Broken file.")]
2415    InvalidFileFormat,
2416
2417    #[error("Invalid FreeType version.")]
2418    InvalidVersion,
2419
2420    #[error("Module version is too low.")]
2421    LowerModuleVersion,
2422
2423    #[error("Invalid argument.")]
2424    InvalidArgument,
2425
2426    #[error("Unimplemented feature.")]
2427    UnimplementedFeature,
2428
2429    #[error("Broken table.")]
2430    InvalidTable,
2431
2432    #[error("Broken offset within table.")]
2433    InvalidOffset,
2434
2435    #[error("Array allocation size too large.")]
2436    ArrayTooLarge,
2437
2438    #[error("Missing module.")]
2439    MissingModule,
2440
2441    #[error("Missing property.")]
2442    MissingProperty,
2443
2444    #[error("Invalid glyph index.")]
2445    InvalidGlyphIndex,
2446
2447    #[error("Invalid character code.")]
2448    InvalidCharacterCode,
2449
2450    #[error("Unsupported glyph image format.")]
2451    InvalidGlyphFormat,
2452
2453    #[error("Cannot render this glyph format.")]
2454    CannotRenderGlyph,
2455
2456    #[error("Invalid outline.")]
2457    InvalidOutline,
2458
2459    #[error("Invalid composite glyph.")]
2460    InvalidComposite,
2461
2462    #[error("Too many hints.")]
2463    TooManyHints,
2464
2465    #[error("Invalid pixel size.")]
2466    InvalidPixelSize,
2467
2468    #[error("Invalid object handle.")]
2469    InvalidHandle,
2470
2471    #[error("Invalid library handle.")]
2472    InvalidLibraryHandle,
2473
2474    #[error("Invalid module handle.")]
2475    InvalidDriverHandle,
2476
2477    #[error("Invalid face handle.")]
2478    InvalidFaceHandle,
2479
2480    #[error("Invalid size handle.")]
2481    InvalidSizeHandle,
2482
2483    #[error("Invalid glyph slot handle.")]
2484    InvalidSlotHandle,
2485
2486    #[error("Invalid charmap handle.")]
2487    InvalidCharMapHandle,
2488
2489    #[error("Invalid cache manager handle.")]
2490    InvalidCacheHandle,
2491
2492    #[error("Invalid stream handle.")]
2493    InvalidStreamHandle,
2494
2495    #[error("Too many modules.")]
2496    TooManyDrivers,
2497
2498    #[error("Too many extensions.")]
2499    TooManyExtensions,
2500
2501    #[error("Out of memory.")]
2502    OutOfMemory,
2503
2504    #[error("Unlisted object.")]
2505    UnlistedObject,
2506
2507    #[error("Cannot open stream.")]
2508    CannotOpenStream,
2509
2510    #[error("Invalid stream seek.")]
2511    InvalidStreamSeek,
2512
2513    #[error("Invalid stream skip.")]
2514    InvalidStreamSkip,
2515
2516    #[error("Invalid stream read.")]
2517    InvalidStreamRead,
2518
2519    #[error("Invalid stream operation.")]
2520    InvalidStreamOperation,
2521
2522    #[error("Invalid frame operation.")]
2523    InvalidFrameOperation,
2524
2525    #[error("Nested frame access.")]
2526    NestedFrameAccess,
2527
2528    #[error("Invalid frame read.")]
2529    InvalidFrameRead,
2530
2531    #[error("Raster uninitialized.")]
2532    RasterUninitialized,
2533
2534    #[error("Raster corrupted.")]
2535    RasterCorrupted,
2536
2537    #[error("Raster overflow.")]
2538    RasterOverflow,
2539
2540    #[error("Negative height while rastering.")]
2541    RasterNegativeHeight,
2542
2543    #[error("Too many registered caches.")]
2544    TooManyCaches,
2545
2546    #[error("Invalid opcode.")]
2547    InvalidOpcode,
2548
2549    #[error("Too few arguments.")]
2550    TooFewArguments,
2551
2552    #[error("Stack overflow.")]
2553    StackOverflow,
2554
2555    #[error("Code overflow.")]
2556    CodeOverflow,
2557
2558    #[error("Bad argument.")]
2559    BadArgument,
2560
2561    #[error("Division by zero.")]
2562    DivideByZero,
2563
2564    #[error("Invalid reference.")]
2565    InvalidReference,
2566
2567    #[error("Found debug opcode.")]
2568    DebugOpCode,
2569
2570    #[error("Found ENDF opcode in execution stream.")]
2571    ENDFInExecStream,
2572
2573    #[error("Nested DEFS.")]
2574    NestedDEFS,
2575
2576    #[error("Invalid code range.")]
2577    InvalidCodeRange,
2578
2579    #[error("Execution context too long.")]
2580    ExecutionTooLong,
2581
2582    #[error("Too many function definitions.")]
2583    TooManyFunctionDefs,
2584
2585    #[error("Too many instruction definitions.")]
2586    TooManyInstructionDefs,
2587
2588    #[error("SFNT font table missing.")]
2589    TableMissing,
2590
2591    #[error("Horizontal header (hhea) table missing.")]
2592    HorizHeaderMissing,
2593
2594    #[error("Locations (loca) table missing.")]
2595    LocationsMissing,
2596
2597    #[error("Name table missing.")]
2598    NameTableMissing,
2599
2600    #[error("Character map (cmap) table missing.")]
2601    CMapTableMissing,
2602
2603    #[error("Horizontal metrics (hmtx) table missing.")]
2604    HmtxTableMissing,
2605
2606    #[error("PostScript (post) table missing.")]
2607    PostTableMissing,
2608
2609    #[error("Invalid horizontal metrics.")]
2610    InvalidHorizMetrics,
2611
2612    #[error("Invalid character map (cmap) format.")]
2613    InvalidCharMapFormat,
2614
2615    #[error("Invalid ppem value.")]
2616    InvalidPPem,
2617
2618    #[error("Invalid vertical metrics.")]
2619    InvalidVertMetrics,
2620
2621    #[error("Could not find context.")]
2622    CouldNotFindContext,
2623
2624    #[error("Invalid PostScript (post) table format.")]
2625    InvalidPostTableFormat,
2626
2627    #[error("Invalid PostScript (post) table.")]
2628    InvalidPostTable,
2629
2630    #[error("Found FDEF or IDEF opcode in glyf bytecode.")]
2631    DEFInGlyfBytecode,
2632
2633    #[error("Missing bitmap in strike.")]
2634    MissingBitmap,
2635
2636    #[error("Opcode syntax error.")]
2637    SyntaxError,
2638
2639    #[error("Argument stack underflow.")]
2640    StackUnderflow,
2641
2642    #[error("Ignore.")]
2643    Ignore,
2644
2645    #[error("No Unicode glyph name found.")]
2646    NoUnicodeGlyphName,
2647
2648    #[error("Glyph too big for hinting.")]
2649    GlyphTooBig,
2650
2651    #[error("`STARTFONT' field missing.")]
2652    MissingStartfontField,
2653
2654    #[error("`FONT' field missing.")]
2655    MissingFontField,
2656
2657    #[error("`SIZE' field missing.")]
2658    MissingSizeField,
2659
2660    #[error("`FONTBOUNDINGBOX' field missing.")]
2661    MissingFontboundingboxField,
2662
2663    #[error("`CHARS' field missing.")]
2664    MissingCharsField,
2665
2666    #[error("`STARTCHAR' field missing.")]
2667    MissingStartcharField,
2668
2669    #[error("`ENCODING' field missing.")]
2670    MissingEncodingField,
2671
2672    #[error("`BBX' field missing.")]
2673    MissingBbxField,
2674
2675    #[error("`BBX' too big.")]
2676    BbxTooBig,
2677
2678    #[error("Font header corrupted or missing fields.")]
2679    CorruptedFontHeader,
2680
2681    #[error("Font glyphs corrupted or missing fields.")]
2682    CorruptedFontGlyphs,
2683}
2684
2685impl From<FtError> for FreetypeError {
2686    fn from(code: FtError) -> FreetypeError {
2687        match code {
2688            0x01 => FreetypeError::CannotOpenResource,
2689            0x02 => FreetypeError::UnknownFileFormat,
2690            0x03 => FreetypeError::InvalidFileFormat,
2691            0x04 => FreetypeError::InvalidVersion,
2692            0x05 => FreetypeError::LowerModuleVersion,
2693            0x06 => FreetypeError::InvalidArgument,
2694            0x07 => FreetypeError::UnimplementedFeature,
2695            0x08 => FreetypeError::InvalidTable,
2696            0x09 => FreetypeError::InvalidOffset,
2697            0x0A => FreetypeError::ArrayTooLarge,
2698            0x0B => FreetypeError::MissingModule,
2699            0x0C => FreetypeError::MissingProperty,
2700            0x10 => FreetypeError::InvalidGlyphIndex,
2701            0x11 => FreetypeError::InvalidCharacterCode,
2702            0x12 => FreetypeError::InvalidGlyphFormat,
2703            0x13 => FreetypeError::CannotRenderGlyph,
2704            0x14 => FreetypeError::InvalidOutline,
2705            0x15 => FreetypeError::InvalidComposite,
2706            0x16 => FreetypeError::TooManyHints,
2707            0x17 => FreetypeError::InvalidPixelSize,
2708            0x20 => FreetypeError::InvalidHandle,
2709            0x21 => FreetypeError::InvalidLibraryHandle,
2710            0x22 => FreetypeError::InvalidDriverHandle,
2711            0x23 => FreetypeError::InvalidFaceHandle,
2712            0x24 => FreetypeError::InvalidSizeHandle,
2713            0x25 => FreetypeError::InvalidSlotHandle,
2714            0x26 => FreetypeError::InvalidCharMapHandle,
2715            0x27 => FreetypeError::InvalidCacheHandle,
2716            0x28 => FreetypeError::InvalidStreamHandle,
2717            0x30 => FreetypeError::TooManyDrivers,
2718            0x31 => FreetypeError::TooManyExtensions,
2719            0x40 => FreetypeError::OutOfMemory,
2720            0x41 => FreetypeError::UnlistedObject,
2721            0x51 => FreetypeError::CannotOpenStream,
2722            0x52 => FreetypeError::InvalidStreamSeek,
2723            0x53 => FreetypeError::InvalidStreamSkip,
2724            0x54 => FreetypeError::InvalidStreamRead,
2725            0x55 => FreetypeError::InvalidStreamOperation,
2726            0x56 => FreetypeError::InvalidFrameOperation,
2727            0x57 => FreetypeError::NestedFrameAccess,
2728            0x58 => FreetypeError::InvalidFrameRead,
2729            0x60 => FreetypeError::RasterUninitialized,
2730            0x61 => FreetypeError::RasterCorrupted,
2731            0x62 => FreetypeError::RasterOverflow,
2732            0x63 => FreetypeError::RasterNegativeHeight,
2733            0x70 => FreetypeError::TooManyCaches,
2734            0x80 => FreetypeError::InvalidOpcode,
2735            0x81 => FreetypeError::TooFewArguments,
2736            0x82 => FreetypeError::StackOverflow,
2737            0x83 => FreetypeError::CodeOverflow,
2738            0x84 => FreetypeError::BadArgument,
2739            0x85 => FreetypeError::DivideByZero,
2740            0x86 => FreetypeError::InvalidReference,
2741            0x87 => FreetypeError::DebugOpCode,
2742            0x88 => FreetypeError::ENDFInExecStream,
2743            0x89 => FreetypeError::NestedDEFS,
2744            0x8A => FreetypeError::InvalidCodeRange,
2745            0x8B => FreetypeError::ExecutionTooLong,
2746            0x8C => FreetypeError::TooManyFunctionDefs,
2747            0x8D => FreetypeError::TooManyInstructionDefs,
2748            0x8E => FreetypeError::TableMissing,
2749            0x8F => FreetypeError::HorizHeaderMissing,
2750            0x90 => FreetypeError::LocationsMissing,
2751            0x91 => FreetypeError::NameTableMissing,
2752            0x92 => FreetypeError::CMapTableMissing,
2753            0x93 => FreetypeError::HmtxTableMissing,
2754            0x94 => FreetypeError::PostTableMissing,
2755            0x95 => FreetypeError::InvalidHorizMetrics,
2756            0x96 => FreetypeError::InvalidCharMapFormat,
2757            0x97 => FreetypeError::InvalidPPem,
2758            0x98 => FreetypeError::InvalidVertMetrics,
2759            0x99 => FreetypeError::CouldNotFindContext,
2760            0x9A => FreetypeError::InvalidPostTableFormat,
2761            0x9B => FreetypeError::InvalidPostTable,
2762            0x9C => FreetypeError::DEFInGlyfBytecode,
2763            0x9D => FreetypeError::MissingBitmap,
2764            0xA0 => FreetypeError::SyntaxError,
2765            0xA1 => FreetypeError::StackUnderflow,
2766            0xA2 => FreetypeError::Ignore,
2767            0xA3 => FreetypeError::NoUnicodeGlyphName,
2768            0xA4 => FreetypeError::GlyphTooBig,
2769            0xB0 => FreetypeError::MissingStartfontField,
2770            0xB1 => FreetypeError::MissingFontField,
2771            0xB2 => FreetypeError::MissingSizeField,
2772            0xB3 => FreetypeError::MissingFontboundingboxField,
2773            0xB4 => FreetypeError::MissingCharsField,
2774            0xB5 => FreetypeError::MissingStartcharField,
2775            0xB6 => FreetypeError::MissingEncodingField,
2776            0xB7 => FreetypeError::MissingBbxField,
2777            0xB8 => FreetypeError::BbxTooBig,
2778            0xB9 => FreetypeError::CorruptedFontHeader,
2779            0xBA => FreetypeError::CorruptedFontGlyphs,
2780            _ => FreetypeError::UnknownError(code),
2781        }
2782    }
2783}