1 #![allow(unknown_lints)]
2 #![warn(clippy)]
3 #![allow(too_many_arguments, cast_lossless, many_single_char_names,)]
4
5 extern crate byteorder;
6
7 use byteorder::{BigEndian as BE, ByteOrder};
8 use std::ops::Deref;
9
10 #[derive(Clone, Debug)]
11 pub struct FontInfo<Data: Deref<Target = [u8]>> {
12 data: Data, // pointer to .ttf file
13 // fontstart: usize, // offset of start of font
14 num_glyphs: u32, // number of glyphs, needed for range checking
15 loca: u32,
16 head: u32,
17 glyf: u32,
18 hhea: u32,
19 hmtx: u32,
20 name: u32,
21 kern: u32, // table locations as offset from start of .ttf
22 index_map: u32, // a cmap mapping for our chosen character encoding
23 index_to_loc_format: u32, // format needed to map from glyph index to glyph
24 }
25
26 #[derive(Copy, Clone, Debug)]
27 #[repr(C)]
28 pub struct Vertex {
29 pub x: i16,
30 pub y: i16,
31 pub cx: i16,
32 pub cy: i16,
33 type_: u8,
34 }
35
36 impl Vertex {
vertex_type(&self) -> VertexType37 pub fn vertex_type(&self) -> VertexType {
38 match self.type_ {
39 1 => VertexType::MoveTo,
40 2 => VertexType::LineTo,
41 3 => VertexType::CurveTo,
42 type_ => panic!("Invalid vertex type: {}", type_),
43 }
44 }
45 }
46
47 #[test]
test_vertex_type()48 fn test_vertex_type() {
49 fn v(type_: VertexType) -> Vertex {
50 Vertex {
51 x: 0,
52 y: 0,
53 cx: 0,
54 cy: 0,
55 type_: type_ as u8,
56 }
57 }
58 assert_eq!(v(VertexType::MoveTo).vertex_type(), VertexType::MoveTo);
59 assert_eq!(v(VertexType::LineTo).vertex_type(), VertexType::LineTo);
60 assert_eq!(v(VertexType::CurveTo).vertex_type(), VertexType::CurveTo);
61 }
62
63 #[test]
64 #[should_panic]
test_invalid_vertex_type()65 fn test_invalid_vertex_type() {
66 let v = Vertex {
67 x: 0,
68 y: 0,
69 cx: 0,
70 cy: 0,
71 type_: 255,
72 };
73 let s = match v.vertex_type() {
74 VertexType::MoveTo => "move to",
75 VertexType::LineTo => "line to",
76 VertexType::CurveTo => "curve to",
77 };
78 // With `Vertex::vertex_type` defined as `transmute` this would be undefined
79 // behavior:
80 println!("{}", s);
81 }
82
83 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
84 #[repr(u8)]
85 pub enum VertexType {
86 MoveTo = 1,
87 LineTo = 2,
88 CurveTo = 3,
89 }
90
91 #[derive(Copy, Clone, Debug)]
92 pub struct Rect<T> {
93 pub x0: T,
94 pub y0: T,
95 pub x1: T,
96 pub y1: T,
97 }
98
99 #[derive(Copy, Clone, Debug)]
100 pub struct HMetrics {
101 pub advance_width: i32,
102 pub left_side_bearing: i32,
103 }
104
105 #[derive(Copy, Clone, Debug)]
106 pub struct VMetrics {
107 pub ascent: i32,
108 pub descent: i32,
109 pub line_gap: i32,
110 }
111
112 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
113 #[repr(C)]
114 pub enum PlatformId {
115 // platformID
116 Unicode = 0,
117 Mac = 1,
118 Iso = 2,
119 Microsoft = 3,
120 }
platform_id(v: u16) -> Option<PlatformId>121 fn platform_id(v: u16) -> Option<PlatformId> {
122 use PlatformId::*;
123 match v {
124 0 => Some(Unicode),
125 1 => Some(Mac),
126 2 => Some(Iso),
127 3 => Some(Microsoft),
128 _ => None,
129 }
130 }
131
132 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
133 #[repr(C)]
134 #[allow(non_camel_case_types)]
135 pub enum UnicodeEid {
136 // encodingID for PLATFORM_ID_UNICODE
137 Unicode_1_0 = 0,
138 Unicode_1_1 = 1,
139 Iso_10646 = 2,
140 Unicode_2_0_Bmp = 3,
141 Unicode_2_0_Full = 4,
142 }
unicode_eid(v: u16) -> Option<UnicodeEid>143 fn unicode_eid(v: u16) -> Option<UnicodeEid> {
144 use UnicodeEid::*;
145 match v {
146 0 => Some(Unicode_1_0),
147 1 => Some(Unicode_1_1),
148 2 => Some(Iso_10646),
149 3 => Some(Unicode_2_0_Bmp),
150 4 => Some(Unicode_2_0_Full),
151 _ => None,
152 }
153 }
154
155 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
156 #[repr(C)]
157 pub enum MicrosoftEid {
158 // encodingID for PLATFORM_ID_MICROSOFT
159 Symbol = 0,
160 UnicodeBMP = 1,
161 Shiftjis = 2,
162 UnicodeFull = 10,
163 }
microsoft_eid(v: u16) -> Option<MicrosoftEid>164 fn microsoft_eid(v: u16) -> Option<MicrosoftEid> {
165 use MicrosoftEid::*;
166 match v {
167 0 => Some(Symbol),
168 1 => Some(UnicodeBMP),
169 2 => Some(Shiftjis),
170 10 => Some(UnicodeFull),
171 _ => None,
172 }
173 }
174
175 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
176 #[repr(C)]
177 pub enum MacEid {
178 // encodingID for PLATFORM_ID_MAC; same as Script Manager codes
179 Roman = 0,
180 Arabic = 4,
181 Japanese = 1,
182 Hebrew = 5,
183 ChineseTrad = 2,
184 Greek = 6,
185 Korean = 3,
186 Russian = 7,
187 }
mac_eid(v: u16) -> Option<MacEid>188 fn mac_eid(v: u16) -> Option<MacEid> {
189 use MacEid::*;
190 match v {
191 0 => Some(Roman),
192 1 => Some(Japanese),
193 2 => Some(ChineseTrad),
194 3 => Some(Korean),
195 4 => Some(Arabic),
196 5 => Some(Hebrew),
197 6 => Some(Greek),
198 7 => Some(Russian),
199 _ => None,
200 }
201 }
202
203 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
204 #[repr(C)]
205 pub enum MicrosoftLang {
206 // languageID for PLATFORM_ID_MICROSOFT; same as LCID...
207 // problematic because there are e.g. 16 english LCIDs and 16 arabic LCIDs
208 English = 0x0409,
209 Italian = 0x0410,
210 Chinese = 0x0804,
211 Japanese = 0x0411,
212 Dutch = 0x0413,
213 Korean = 0x0412,
214 French = 0x040c,
215 Russian = 0x0419,
216 German = 0x0407,
217 // Spanish = 0x0409,
218 Hebrew = 0x040d,
219 Swedish = 0x041D,
220 }
microsoft_lang(v: u16) -> Option<MicrosoftLang>221 fn microsoft_lang(v: u16) -> Option<MicrosoftLang> {
222 use MicrosoftLang::*;
223 match v {
224 0x0409 => Some(English),
225 0x0804 => Some(Chinese),
226 0x0413 => Some(Dutch),
227 0x040c => Some(French),
228 0x0407 => Some(German),
229 0x040d => Some(Hebrew),
230 0x0410 => Some(Italian),
231 0x0411 => Some(Japanese),
232 0x0412 => Some(Korean),
233 0x0419 => Some(Russian),
234 0x041D => Some(Swedish),
235 _ => None,
236 }
237 }
238
239 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
240 #[repr(C)]
241 pub enum MacLang {
242 // languageID for PLATFORM_ID_MAC
243 English = 0,
244 Japanese = 11,
245 Arabic = 12,
246 Korean = 23,
247 Dutch = 4,
248 Russian = 32,
249 French = 1,
250 Spanish = 6,
251 German = 2,
252 Swedish = 5,
253 Hebrew = 10,
254 ChineseSimplified = 33,
255 Italian = 3,
256 ChineseTrad = 19,
257 }
mac_lang(v: u16) -> Option<MacLang>258 fn mac_lang(v: u16) -> Option<MacLang> {
259 use MacLang::*;
260 match v {
261 0 => Some(English),
262 12 => Some(Arabic),
263 4 => Some(Dutch),
264 1 => Some(French),
265 2 => Some(German),
266 10 => Some(Hebrew),
267 3 => Some(Italian),
268 11 => Some(Japanese),
269 23 => Some(Korean),
270 32 => Some(Russian),
271 6 => Some(Spanish),
272 5 => Some(Swedish),
273 33 => Some(ChineseSimplified),
274 19 => Some(ChineseTrad),
275 _ => None,
276 }
277 }
278
279 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
280 pub enum PlatformEncodingLanguageId {
281 Unicode(Option<Result<UnicodeEid, u16>>, Option<u16>),
282 Mac(Option<Result<MacEid, u16>>, Option<Result<MacLang, u16>>),
283 Iso(Option<u16>, Option<u16>),
284 Microsoft(
285 Option<Result<MicrosoftEid, u16>>,
286 Option<Result<MicrosoftLang, u16>>,
287 ),
288 }
platform_encoding_id( platform_id: PlatformId, encoding_id: Option<u16>, language_id: Option<u16>, ) -> PlatformEncodingLanguageId289 fn platform_encoding_id(
290 platform_id: PlatformId,
291 encoding_id: Option<u16>,
292 language_id: Option<u16>,
293 ) -> PlatformEncodingLanguageId {
294 match platform_id {
295 PlatformId::Unicode => PlatformEncodingLanguageId::Unicode(
296 encoding_id.map(|id| unicode_eid(id).ok_or(id)),
297 language_id,
298 ),
299 PlatformId::Mac => PlatformEncodingLanguageId::Mac(
300 encoding_id.map(|id| mac_eid(id).ok_or(id)),
301 language_id.map(|id| mac_lang(id).ok_or(id)),
302 ),
303 PlatformId::Iso => PlatformEncodingLanguageId::Iso(encoding_id, language_id),
304 PlatformId::Microsoft => PlatformEncodingLanguageId::Microsoft(
305 encoding_id.map(|id| microsoft_eid(id).ok_or(id)),
306 language_id.map(|id| microsoft_lang(id).ok_or(id)),
307 ),
308 }
309 }
310
311 // # accessors to parse data from file
312
313 // on platforms that don't allow misaligned reads, if we want to allow
314 // truetype fonts that aren't padded to alignment, define
315 // ALLOW_UNALIGNED_TRUETYPE
316
317 /// Return `true` if `data` holds a font stored in a format this crate
318 /// recognizes, according to its signature in the initial bytes.
is_font(data: &[u8]) -> bool319 pub fn is_font(data: &[u8]) -> bool {
320 if data.len() >= 4 {
321 let tag = &data[0..4];
322 tag == [b'1', 0, 0, 0] || tag == b"typ1" || tag == b"OTTO" || tag == [0, 1, 0, 0]
323 } else {
324 false
325 }
326 }
327
328 /// Return `true` if `data` holds a TrueType Collection, according to its
329 /// signature in the initial bytes. A TrueType Collection stores several fonts
330 /// in a single file, allowing them to share data for glyphs they have in
331 /// common.
is_collection(data: &[u8]) -> bool332 pub fn is_collection(data: &[u8]) -> bool {
333 data.len() >= 4 && &data[0..4] == b"ttcf"
334 }
335
find_table(data: &[u8], fontstart: usize, tag: &[u8]) -> u32336 fn find_table(data: &[u8], fontstart: usize, tag: &[u8]) -> u32 {
337 let num_tables = BE::read_u16(&data[fontstart + 4..]);
338 let tabledir = fontstart + 12;
339 for i in 0..num_tables {
340 let loc = tabledir + 16 * (i as usize);
341 if &data[loc..loc + 4] == tag {
342 return BE::read_u32(&data[loc + 8..]);
343 }
344 }
345 0
346 }
347
348 /// Each .ttf/.ttc file may have more than one font. Each font has a sequential
349 /// index number starting from 0. Call this function to get the font offset for
350 /// a given index; it returns None if the index is out of range. A regular .ttf
351 /// file will only define one font and it always be at offset 0, so it will
352 /// return Some(0) for index 0, and None for all other indices. You can just
353 /// skip this step if you know it's that kind of font.
get_font_offset_for_index(font_collection: &[u8], index: i32) -> Option<u32>354 pub fn get_font_offset_for_index(font_collection: &[u8], index: i32) -> Option<u32> {
355 // if it's just a font, there's only one valid index
356 if is_font(font_collection) {
357 return if index == 0 { Some(0) } else { None };
358 }
359 // check if it's a TTC
360 if is_collection(font_collection)
361 && (BE::read_u32(&font_collection[4..]) == 0x0001_0000
362 || BE::read_u32(&font_collection[4..]) == 0x0002_0000)
363 {
364 let n = BE::read_i32(&font_collection[8..]);
365 if index >= n {
366 return None;
367 }
368 return Some(BE::read_u32(&font_collection[12 + (index as usize) * 4..]));
369 }
370 None
371 }
372
373 macro_rules! read_ints {
374 ($n:expr, i16, $data:expr) => {{
375 let mut nums = [0; $n];
376 let data = $data;
377 BE::read_i16_into(&data[..$n * 2], &mut nums);
378 nums
379 }};
380 ($n:expr, u16, $data:expr) => {{
381 let mut nums = [0; $n];
382 let data = $data;
383 BE::read_u16_into(&data[..$n * 2], &mut nums);
384 nums
385 }};
386 ($n:expr, u32, $data:expr) => {{
387 let mut nums = [0; $n];
388 let data = $data;
389 BE::read_u32_into(&data[..$n * 4], &mut nums);
390 nums
391 }};
392 }
393
394 impl<Data: Deref<Target = [u8]>> FontInfo<Data> {
395 /// Given an offset into the file that defines a font, this function builds
396 /// the necessary cached info for the rest of the system.
new(data: Data, fontstart: usize) -> Option<FontInfo<Data>>397 pub fn new(data: Data, fontstart: usize) -> Option<FontInfo<Data>> {
398 let cmap = find_table(&data, fontstart, b"cmap"); // required
399 let loca = find_table(&data, fontstart, b"loca"); // required
400 let head = find_table(&data, fontstart, b"head"); // required
401 let glyf = find_table(&data, fontstart, b"glyf"); // required
402 let hhea = find_table(&data, fontstart, b"hhea"); // required
403 let hmtx = find_table(&data, fontstart, b"hmtx"); // required
404 let name = find_table(&data, fontstart, b"name"); // not required
405 let kern = find_table(&data, fontstart, b"kern"); // not required
406 if cmap == 0 || loca == 0 || head == 0 || glyf == 0 || hhea == 0 || hmtx == 0 {
407 return None;
408 }
409 let t = find_table(&data, fontstart, b"maxp");
410 let num_glyphs = if t != 0 {
411 BE::read_u16(&data[t as usize + 4..])
412 } else {
413 0xffff
414 };
415
416 // find a cmap encoding table we understand *now* to avoid searching
417 // later. (todo: could make this installable)
418 // the same regardless of glyph.
419 let num_tables = BE::read_u16(&data[cmap as usize + 2..]);
420 let mut index_map = 0;
421 for i in 0..num_tables {
422 let encoding_record = (cmap + 4 + 8 * (i as u32)) as usize;
423 // find an encoding we understand:
424 match platform_id(BE::read_u16(&data[encoding_record..])) {
425 Some(PlatformId::Microsoft) => {
426 match microsoft_eid(BE::read_u16(&data[encoding_record + 2..])) {
427 Some(MicrosoftEid::UnicodeBMP) | Some(MicrosoftEid::UnicodeFull) => {
428 // MS/Unicode
429 index_map = cmap + BE::read_u32(&data[encoding_record + 4..]);
430 }
431 _ => (),
432 }
433 }
434 Some(PlatformId::Unicode) => {
435 // Mac/iOS has these
436 // all the encodingIDs are unicode, so we don't bother to check it
437 index_map = cmap + BE::read_u32(&data[encoding_record + 4..]);
438 }
439 _ => (),
440 }
441 }
442 if index_map == 0 {
443 return None;
444 }
445 let index_to_loc_format = BE::read_u16(&data[head as usize + 50..]) as u32;
446 Some(FontInfo {
447 // fontstart: fontstart,
448 data,
449 loca,
450 head,
451 glyf,
452 hhea,
453 hmtx,
454 name,
455 kern,
456 num_glyphs: num_glyphs as u32,
457 index_map,
458 index_to_loc_format,
459 })
460 }
461
get_num_glyphs(&self) -> u32462 pub fn get_num_glyphs(&self) -> u32 {
463 self.num_glyphs
464 }
465
466 /// If you're going to perform multiple operations on the same character
467 /// and you want a speed-up, call this function with the character you're
468 /// going to process, then use glyph-based functions instead of the
469 /// codepoint-based functions.
find_glyph_index(&self, unicode_codepoint: u32) -> u32470 pub fn find_glyph_index(&self, unicode_codepoint: u32) -> u32 {
471 let data = &self.data;
472 let index_map = &data[self.index_map as usize..]; //self.index_map as usize;
473
474 let format = BE::read_u16(index_map);
475 match format {
476 0 => {
477 // apple byte encoding
478 let bytes = BE::read_u16(&index_map[2..]);
479 if unicode_codepoint < bytes as u32 - 6 {
480 return index_map[6 + unicode_codepoint as usize] as u32;
481 }
482 0
483 }
484 6 => {
485 let first = BE::read_u16(&index_map[6..]) as u32;
486 let count = BE::read_u16(&index_map[8..]) as u32;
487 if unicode_codepoint >= first && unicode_codepoint < first + count {
488 return BE::read_u16(&index_map[10 + (unicode_codepoint - first) as usize * 2..])
489 as u32;
490 }
491 0
492 }
493 2 => {
494 // @TODO: high-byte mapping for japanese/chinese/korean
495 panic!("Index map format unsupported: 2");
496 }
497 4 => {
498 // standard mapping for windows fonts: binary search collection of ranges
499 let segcount = BE::read_u16(&index_map[6..]) as usize >> 1;
500 let mut search_range = BE::read_u16(&index_map[8..]) as usize >> 1;
501 let mut entry_selector = BE::read_u16(&index_map[10..]);
502 let range_shift = BE::read_u16(&index_map[12..]) as usize >> 1;
503
504 // do a binary search of the segments
505 let end_count = self.index_map as usize + 14;
506 let mut search = end_count;
507
508 if unicode_codepoint > 0xffff {
509 return 0;
510 }
511
512 // they lie from endCount .. endCount + segCount
513 // but searchRange is the nearest power of two, so...
514 if unicode_codepoint >= BE::read_u16(&data[search + range_shift * 2..]) as u32 {
515 search += range_shift * 2;
516 }
517
518 // now decrement to bias correctly to find smallest
519 search -= 2;
520 while entry_selector != 0 {
521 search_range >>= 1;
522 let end = BE::read_u16(&data[search + search_range * 2..]) as u32;
523 if unicode_codepoint > end {
524 search += search_range * 2;
525 }
526 entry_selector -= 1;
527 }
528 search += 2;
529
530 {
531 let item = (search - end_count) >> 1;
532 assert!(
533 unicode_codepoint <= BE::read_u16(&data[end_count + 2 * item..]) as u32
534 );
535 let start = BE::read_u16(&index_map[14 + segcount * 2 + 2 + 2 * item..]) as u32;
536 if unicode_codepoint < start {
537 return 0;
538 }
539 let offset =
540 BE::read_u16(&index_map[14 + segcount * 6 + 2 + 2 * item..]) as usize;
541 if offset == 0 {
542 return (unicode_codepoint as i32 + BE::read_i16(
543 &index_map[14 + segcount * 4 + 2 + 2 * item..],
544 ) as i32) as u16 as u32;
545 }
546 BE::read_u16(
547 &index_map[offset
548 + (unicode_codepoint - start) as usize * 2
549 + 14
550 + segcount * 6
551 + 2
552 + 2 * item..],
553 ) as u32
554 }
555 }
556 12 | 13 => {
557 let mut low = 0u32;
558 let mut high = BE::read_u32(&index_map[12..]);
559 let groups = &index_map[16..];
560
561 // Binary search of the right group
562 while low < high {
563 let mid = (low + high) / 2; // rounds down, so low <= mid < high
564 let mid12 = (mid * 12) as usize;
565 let group = &groups[mid12..mid12 + 12];
566 let start_char = BE::read_u32(group);
567 if unicode_codepoint < start_char {
568 high = mid;
569 } else if unicode_codepoint > BE::read_u32(&group[4..]) {
570 low = mid + 1;
571 } else {
572 let start_glyph = BE::read_u32(&group[8..]);
573 if format == 12 {
574 return start_glyph + unicode_codepoint - start_char;
575 } else {
576 return start_glyph;
577 }
578 }
579 }
580
581 0
582 }
583 n => panic!("Index map format unsupported: {}", n),
584 }
585 }
586
587 /// Returns the series of vertices encoding the shape of the glyph for this
588 /// codepoint.
589 ///
590 /// The shape is a series of countours. Each one starts with
591 /// a moveto, then consists of a series of mixed
592 /// lineto and curveto segments. A lineto
593 /// draws a line from previous endpoint to its x,y; a curveto
594 /// draws a quadratic bezier from previous endpoint to
595 /// its x,y, using cx,cy as the bezier control point.
get_codepoint_shape(&self, unicode_codepoint: u32) -> Option<Vec<Vertex>>596 pub fn get_codepoint_shape(&self, unicode_codepoint: u32) -> Option<Vec<Vertex>> {
597 self.get_glyph_shape(self.find_glyph_index(unicode_codepoint))
598 }
599
get_glyf_offset(&self, glyph_index: u32) -> Option<u32>600 fn get_glyf_offset(&self, glyph_index: u32) -> Option<u32> {
601 if glyph_index >= self.num_glyphs || self.index_to_loc_format >= 2 {
602 // glyph index out of range or unknown index->glyph map format
603 return None;
604 }
605
606 let [g1, g2] = if self.index_to_loc_format == 0 {
607 let d = &self.data[(self.loca + glyph_index * 2) as usize..];
608 let [g1, g2] = read_ints!(2, u16, d);
609 [g1 as u32 * 2, g2 as u32 * 2]
610 } else {
611 read_ints!(2, u32, &self.data[(self.loca + glyph_index * 4) as usize..])
612 };
613 if g1 == g2 {
614 None
615 } else {
616 Some(self.glyf + g1)
617 }
618 }
619
620 /// Like `get_codepoint_box`, but takes a glyph index. Use this if you have
621 /// cached the glyph index for a codepoint.
get_glyph_box(&self, glyph_index: u32) -> Option<Rect<i16>>622 pub fn get_glyph_box(&self, glyph_index: u32) -> Option<Rect<i16>> {
623 let g = self.get_glyf_offset(glyph_index)? as usize;
624 let [x0, y0, x1, y1] = read_ints!(4, i16, &self.data[g + 2..]);
625 Some(Rect { x0, y0, x1, y1 })
626 }
627
628 /// Gets the bounding box of the visible part of the glyph, in unscaled
629 /// coordinates
get_codepoint_box(&self, codepoint: u32) -> Option<Rect<i16>>630 pub fn get_codepoint_box(&self, codepoint: u32) -> Option<Rect<i16>> {
631 self.get_glyph_box(self.find_glyph_index(codepoint))
632 }
633
634 /// returns true if nothing is drawn for this glyph
is_glyph_empty(&self, glyph_index: u32) -> bool635 pub fn is_glyph_empty(&self, glyph_index: u32) -> bool {
636 match self.get_glyf_offset(glyph_index) {
637 Some(g) => {
638 let number_of_contours = BE::read_i16(&self.data[g as usize..]);
639 number_of_contours == 0
640 }
641 None => true,
642 }
643 }
644
645 /// Like `get_codepoint_shape`, but takes a glyph index instead. Use this
646 /// if you have cached the glyph index for a codepoint.
get_glyph_shape(&self, glyph_index: u32) -> Option<Vec<Vertex>>647 pub fn get_glyph_shape(&self, glyph_index: u32) -> Option<Vec<Vertex>> {
648 let g = match self.get_glyf_offset(glyph_index) {
649 Some(g) => &self.data[g as usize..],
650 None => return None,
651 };
652
653 let number_of_contours = BE::read_i16(g);
654 let vertices: Vec<Vertex> = if number_of_contours > 0 {
655 self.glyph_shape_positive_contours(g, number_of_contours as usize)
656 } else if number_of_contours == -1 {
657 // Compound shapes
658 let mut more = true;
659 let mut comp = &g[10..];
660 let mut vertices = Vec::new();
661 while more {
662 let mut mtx = [1.0, 0.0, 0.0, 1.0, 0.0, 0.0];
663
664 let [flags, gidx] = read_ints!(2, i16, comp);
665 comp = &comp[4..];
666 let gidx = gidx as u16;
667
668 if flags & 2 != 0 {
669 // XY values
670 if flags & 1 != 0 {
671 // shorts
672 let [a, b] = read_ints!(2, i16, comp);
673 comp = &comp[4..];
674 mtx[4] = a as f32;
675 mtx[5] = b as f32;
676 } else {
677 mtx[4] = (comp[0] as i8) as f32;
678 mtx[5] = (comp[1] as i8) as f32;
679 comp = &comp[2..];
680 }
681 } else {
682 panic!("Matching points not supported.");
683 }
684 if flags & (1 << 3) != 0 {
685 // WE_HAVE_A_SCALE
686 mtx[0] = BE::read_i16(comp) as f32 / 16384.0;
687 comp = &comp[2..];
688 mtx[1] = 0.0;
689 mtx[2] = 0.0;
690 mtx[3] = mtx[0];
691 } else if flags & (1 << 6) != 0 {
692 // WE_HAVE_AN_X_AND_YSCALE
693 let [a, b] = read_ints!(2, i16, comp);
694 comp = &comp[4..];
695 mtx[0] = a as f32 / 16384.0;
696 mtx[1] = 0.0;
697 mtx[2] = 0.0;
698 mtx[3] = b as f32 / 16384.0;
699 } else if flags & (1 << 7) != 0 {
700 // WE_HAVE_A_TWO_BY_TWO
701 let [a, b, c, d] = read_ints!(4, i16, comp);
702 comp = &comp[8..];
703 mtx[0] = a as f32 / 16384.0;
704 mtx[1] = b as f32 / 16384.0;
705 mtx[2] = c as f32 / 16384.0;
706 mtx[3] = d as f32 / 16384.0;
707 }
708
709 // Find transformation scales.
710 let m = (mtx[0] * mtx[0] + mtx[1] * mtx[1]).sqrt();
711 let n = (mtx[2] * mtx[2] + mtx[3] * mtx[3]).sqrt();
712
713 // Get indexed glyph.
714 let mut comp_verts = self.get_glyph_shape(gidx as u32).unwrap_or_else(Vec::new);
715 if !comp_verts.is_empty() {
716 // Transform vertices
717 for v in &mut *comp_verts {
718 let (x, y, cx, cy) = (v.x as f32, v.y as f32, v.cx as f32, v.cy as f32);
719 *v = Vertex {
720 type_: v.type_,
721 x: (m * (mtx[0] * x + mtx[2] * y + mtx[4])) as i16,
722 y: (n * (mtx[1] * x + mtx[3] * y + mtx[5])) as i16,
723 cx: (m * (mtx[0] * cx + mtx[2] * cy + mtx[4])) as i16,
724 cy: (n * (mtx[1] * cx + mtx[3] * cy + mtx[5])) as i16,
725 };
726 }
727 // Append vertices.
728 vertices.append(&mut comp_verts);
729 }
730 // More components ?
731 more = flags & (1 << 5) != 0;
732 }
733 vertices
734 } else if number_of_contours < 0 {
735 panic!("Contour format not supported.")
736 } else {
737 return None;
738 };
739 Some(vertices)
740 }
741
742 #[inline]
glyph_shape_positive_contours( &self, glyph_data: &[u8], number_of_contours: usize, ) -> Vec<Vertex>743 fn glyph_shape_positive_contours(
744 &self,
745 glyph_data: &[u8],
746 number_of_contours: usize,
747 ) -> Vec<Vertex> {
748 use VertexType::*;
749
750 struct FlagData {
751 flags: u8,
752 x: i16,
753 y: i16,
754 }
755
756 #[inline]
757 fn close_shape(
758 vertices: &mut Vec<Vertex>,
759 was_off: bool,
760 start_off: bool,
761 sx: i16,
762 sy: i16,
763 scx: i16,
764 scy: i16,
765 cx: i16,
766 cy: i16,
767 ) {
768 if start_off {
769 if was_off {
770 vertices.push(Vertex {
771 type_: CurveTo as u8,
772 x: (cx + scx) >> 1,
773 y: (cy + scy) >> 1,
774 cx,
775 cy,
776 });
777 }
778 vertices.push(Vertex {
779 type_: CurveTo as u8,
780 x: sx,
781 y: sy,
782 cx: scx,
783 cy: scy,
784 });
785 } else {
786 vertices.push(if was_off {
787 Vertex {
788 type_: CurveTo as u8,
789 x: sx,
790 y: sy,
791 cx,
792 cy,
793 }
794 } else {
795 Vertex {
796 type_: LineTo as u8,
797 x: sx,
798 y: sy,
799 cx: 0,
800 cy: 0,
801 }
802 });
803 }
804 }
805
806 let number_of_contours = number_of_contours as usize;
807 let mut start_off = false;
808 let mut was_off = false;
809 let end_points_of_contours = &glyph_data[10..];
810 let ins = BE::read_u16(&glyph_data[10 + number_of_contours * 2..]) as usize;
811 let mut points = &glyph_data[10 + number_of_contours * 2 + 2 + ins..];
812
813 let n = 1 + BE::read_u16(&end_points_of_contours[number_of_contours * 2 - 2..]) as usize;
814
815 let m = n + 2 * number_of_contours; // a loose bound on how many vertices we might need
816 let mut vertices: Vec<Vertex> = Vec::with_capacity(m);
817
818 let mut flag_data = Vec::with_capacity(n);
819
820 let mut next_move = 0;
821
822 // in first pass, we load uninterpreted data into the allocated array above
823
824 // first load flags
825 {
826 let mut flagcount = 0;
827 let mut flags = 0;
828 for _ in 0..n {
829 if flagcount == 0 {
830 flags = points[0];
831 if flags & 8 != 0 {
832 flagcount = points[1];
833 points = &points[2..];
834 } else {
835 points = &points[1..];
836 }
837 } else {
838 flagcount -= 1;
839 }
840 flag_data.push(FlagData { flags, x: 0, y: 0 });
841 }
842 }
843
844 // now load x coordinates
845 let mut x_coord = 0_i16;
846 for flag_data in &mut flag_data {
847 let flags = flag_data.flags;
848 if flags & 2 != 0 {
849 let dx = i16::from(points[0]);
850 points = &points[1..];
851 if flags & 16 != 0 {
852 // ???
853 x_coord += dx;
854 } else {
855 x_coord -= dx;
856 }
857 } else if flags & 16 == 0 {
858 x_coord += BE::read_i16(points);
859 points = &points[2..];
860 }
861 flag_data.x = x_coord;
862 }
863
864 // now load y coordinates
865 let mut y_coord = 0_i16;
866 for flag_data in &mut flag_data {
867 let flags = flag_data.flags;
868 if flags & 4 != 0 {
869 let dy = i16::from(points[0]);
870 points = &points[1..];
871 if flags & 32 != 0 {
872 y_coord += dy;
873 } else {
874 y_coord -= dy;
875 }
876 } else if flags & 32 == 0 {
877 y_coord += BE::read_i16(points);
878 points = &points[2..];
879 }
880 flag_data.y = y_coord;
881 }
882
883 // now convert them to our format
884 let mut sx = 0;
885 let mut sy = 0;
886 let mut cx = 0;
887 let mut cy = 0;
888 let mut scx = 0;
889 let mut scy = 0;
890 let mut j = 0;
891
892 let mut iter = flag_data.into_iter().enumerate().peekable();
893
894 while let Some((index, FlagData { flags, x, y })) = iter.next() {
895 if next_move == index {
896 if index != 0 {
897 close_shape(&mut vertices, was_off, start_off, sx, sy, scx, scy, cx, cy);
898 }
899
900 // now start the new one
901 start_off = flags & 1 == 0;
902 if start_off {
903 // if we start off with an off-curve point, then when we need to find a
904 // point on the curve where we can start, and we
905 // need to save some state for
906 // when we wraparound.
907 scx = x;
908 scy = y;
909
910 let (next_flags, next_x, next_y) = {
911 let peek = &iter.peek().unwrap().1;
912 (peek.flags, peek.x, peek.y)
913 };
914
915 if next_flags & 1 == 0 {
916 // next point is also a curve point, so interpolate an on-point curve
917 sx = (x + next_x) >> 1;
918 sy = (y + next_y) >> 1;
919 } else {
920 // otherwise just use the next point as our start point
921 sx = next_x;
922 sy = next_y;
923
924 // we're using point i+1 as the starting point, so skip it
925 let _ = iter.next();
926 }
927 } else {
928 sx = x;
929 sy = y;
930 }
931 vertices.push(Vertex {
932 type_: MoveTo as u8,
933 x: sx,
934 y: sy,
935 cx: 0,
936 cy: 0,
937 });
938 was_off = false;
939 next_move = 1 + BE::read_u16(&end_points_of_contours[j * 2..]) as usize;
940 j += 1;
941 } else if flags & 1 == 0 {
942 // if it's a curve
943 if was_off {
944 // two off-curve control points in a row means interpolate an on-curve
945 // midpoint
946 vertices.push(Vertex {
947 type_: CurveTo as u8,
948 x: ((cx + x) >> 1),
949 y: ((cy + y) >> 1),
950 cx,
951 cy,
952 });
953 }
954 cx = x;
955 cy = y;
956 was_off = true;
957 } else {
958 vertices.push(if was_off {
959 Vertex {
960 type_: CurveTo as u8,
961 x,
962 y,
963 cx,
964 cy,
965 }
966 } else {
967 Vertex {
968 type_: LineTo as u8,
969 x,
970 y,
971 cx: 0,
972 cy: 0,
973 }
974 });
975 was_off = false;
976 }
977 }
978 close_shape(
979 &mut vertices,
980 // &mut num_vertices,
981 was_off,
982 start_off,
983 sx,
984 sy,
985 scx,
986 scy,
987 cx,
988 cy,
989 );
990
991 vertices
992 }
993
994 /// like `get_codepoint_h_metrics`, but takes a glyph index instead. Use
995 /// this if you have cached the glyph index for a codepoint.
get_glyph_h_metrics(&self, glyph_index: u32) -> HMetrics996 pub fn get_glyph_h_metrics(&self, glyph_index: u32) -> HMetrics {
997 let num_of_long_hor_metrics = BE::read_u16(&self.data[self.hhea as usize + 34..]) as usize;
998 let glyph_index = glyph_index as usize;
999 if glyph_index < num_of_long_hor_metrics {
1000 let data = &self.data[self.hmtx as usize + 4 * glyph_index..];
1001 let [advance_width, left_side_bearing] = read_ints!(2, i16, data);
1002 HMetrics {
1003 advance_width: i32::from(advance_width),
1004 left_side_bearing: i32::from(left_side_bearing),
1005 }
1006 } else {
1007 HMetrics {
1008 advance_width: BE::read_i16(
1009 &self.data[self.hmtx as usize + 4 * (num_of_long_hor_metrics - 1)..],
1010 ) as i32,
1011 left_side_bearing: BE::read_i16(
1012 &self.data[self.hmtx as usize
1013 + 4 * num_of_long_hor_metrics
1014 + 2 * (glyph_index as isize - num_of_long_hor_metrics as isize)
1015 as usize..],
1016 ) as i32,
1017 }
1018 }
1019 }
1020
1021 /// like `get_codepoint_kern_advance`, but takes glyph indices instead. Use
1022 /// this if you have cached the glyph indices for the codepoints.
get_glyph_kern_advance(&self, glyph_1: u32, glyph_2: u32) -> i321023 pub fn get_glyph_kern_advance(&self, glyph_1: u32, glyph_2: u32) -> i32 {
1024 let kern = &self.data[self.kern as usize..];
1025 // we only look at the first table. it must be 'horizontal' and format 0
1026 if self.kern == 0 || BE::read_u16(&kern[2..]) < 1 || BE::read_u16(&kern[8..]) != 1 {
1027 // kern not present, OR
1028 // no tables (need at least one), OR
1029 // horizontal flag not set in format
1030 return 0;
1031 }
1032
1033 let mut l: i32 = 0;
1034 let mut r: i32 = BE::read_u16(&kern[10..]) as i32 - 1;
1035 let needle = glyph_1 << 16 | glyph_2;
1036 while l <= r {
1037 let m = (l + r) >> 1;
1038 let straw = BE::read_u32(&kern[18 + (m as usize) * 6..]); // note: unaligned read
1039 if needle < straw {
1040 r = m - 1;
1041 } else if needle > straw {
1042 l = m + 1;
1043 } else {
1044 return BE::read_i16(&kern[22 + (m as usize) * 6..]) as i32;
1045 }
1046 }
1047 0
1048 }
1049
1050 /// an additional amount to add to the 'advance' value between cp1 and cp2
get_codepoint_kern_advance(&self, cp1: u32, cp2: u32) -> i321051 pub fn get_codepoint_kern_advance(&self, cp1: u32, cp2: u32) -> i32 {
1052 if self.kern == 0 {
1053 // if no kerning table, don't waste time looking up both codepoint->glyphs
1054 0
1055 } else {
1056 self.get_glyph_kern_advance(self.find_glyph_index(cp1), self.find_glyph_index(cp2))
1057 }
1058 }
1059
1060 /// `left_side_bearing` is the offset from the current horizontal position
1061 /// to the left edge of the character `advance_width` is the offset
1062 /// from the current horizontal position to the next horizontal
1063 /// position these are
1064 /// expressed in unscaled
1065 /// coordinates
get_codepoint_h_metrics(&self, codepoint: u32) -> HMetrics1066 pub fn get_codepoint_h_metrics(&self, codepoint: u32) -> HMetrics {
1067 self.get_glyph_h_metrics(self.find_glyph_index(codepoint))
1068 }
1069
1070 /// `ascent` is the coordinate above the baseline the font extends; descent
1071 /// is the coordinate below the baseline the font extends (i.e. it is
1072 /// typically negative) `line_gap` is the spacing between one row's
1073 /// descent and the next row's ascent... so you should advance the
1074 /// vertical position by `ascent -
1075 /// descent + line_gap` these are expressed in unscaled coordinates, so
1076 /// you must multiply by the scale factor for a given size
get_v_metrics(&self) -> VMetrics1077 pub fn get_v_metrics(&self) -> VMetrics {
1078 let hhea = &self.data[self.hhea as usize..];
1079 let [ascent, descent, line_gap] = read_ints!(3, i16, &hhea[4..]);
1080 VMetrics {
1081 ascent: i32::from(ascent),
1082 descent: i32::from(descent),
1083 line_gap: i32::from(line_gap),
1084 }
1085 }
1086
1087 /// the bounding box around all possible characters
get_bounding_box(&self) -> Rect<i16>1088 pub fn get_bounding_box(&self) -> Rect<i16> {
1089 let head = &self.data[self.head as usize..];
1090 Rect {
1091 x0: BE::read_i16(&head[36..]),
1092 y0: BE::read_i16(&head[38..]),
1093 x1: BE::read_i16(&head[40..]),
1094 y1: BE::read_i16(&head[42..]),
1095 }
1096 }
1097
1098 /// computes a scale factor to produce a font whose "height" is 'pixels'
1099 /// tall. Height is measured as the distance from the highest ascender
1100 /// to the lowest descender; in other words, it's equivalent to calling
1101 /// GetFontVMetrics and computing:
1102 /// scale = pixels / (ascent - descent)
1103 /// so if you prefer to measure height by the ascent only, use a similar
1104 /// calculation.
scale_for_pixel_height(&self, height: f32) -> f321105 pub fn scale_for_pixel_height(&self, height: f32) -> f32 {
1106 let hhea = &self.data[self.hhea as usize..];
1107 let fheight = {
1108 let [a, b] = read_ints!(2, i16, &hhea[4..]);
1109 f32::from(a) - f32::from(b)
1110 };
1111 height / fheight
1112 }
1113
1114 /// Returns the units per EM square of this font.
units_per_em(&self) -> u161115 pub fn units_per_em(&self) -> u16 {
1116 BE::read_u16(&self.data[self.head as usize + 18..])
1117 }
1118
1119 /// computes a scale factor to produce a font whose EM size is mapped to
1120 /// `pixels` tall. This is probably what traditional APIs compute, but
1121 /// I'm not positive.
scale_for_mapping_em_to_pixels(&self, pixels: f32) -> f321122 pub fn scale_for_mapping_em_to_pixels(&self, pixels: f32) -> f32 {
1123 pixels / (self.units_per_em() as f32)
1124 }
1125
1126 /// like `get_codepoint_bitmap_box_subpixel`, but takes a glyph index
1127 /// instead of a codepoint.
get_glyph_bitmap_box_subpixel( &self, glyph: u32, scale_x: f32, scale_y: f32, shift_x: f32, shift_y: f32, ) -> Option<Rect<i32>>1128 pub fn get_glyph_bitmap_box_subpixel(
1129 &self,
1130 glyph: u32,
1131 scale_x: f32,
1132 scale_y: f32,
1133 shift_x: f32,
1134 shift_y: f32,
1135 ) -> Option<Rect<i32>> {
1136 if let Some(glyph_box) = self.get_glyph_box(glyph) {
1137 // move to integral bboxes (treating pixels as little squares, what pixels get
1138 // touched?)
1139 Some(Rect {
1140 x0: (glyph_box.x0 as f32 * scale_x + shift_x).floor() as i32,
1141 y0: (-glyph_box.y1 as f32 * scale_y + shift_y).floor() as i32,
1142 x1: (glyph_box.x1 as f32 * scale_x + shift_x).ceil() as i32,
1143 y1: (-glyph_box.y0 as f32 * scale_y + shift_y).ceil() as i32,
1144 })
1145 } else {
1146 // e.g. space character
1147 None
1148 }
1149 }
1150
1151 /// like `get_codepoint_bitmap_box`, but takes a glyph index instead of a
1152 /// codepoint.
get_glyph_bitmap_box( &self, glyph: u32, scale_x: f32, scale_y: f32, ) -> Option<Rect<i32>>1153 pub fn get_glyph_bitmap_box(
1154 &self,
1155 glyph: u32,
1156 scale_x: f32,
1157 scale_y: f32,
1158 ) -> Option<Rect<i32>> {
1159 self.get_glyph_bitmap_box_subpixel(glyph, scale_x, scale_y, 0.0, 0.0)
1160 }
1161
1162 /// same as get_codepoint_bitmap_box, but you can specify a subpixel
1163 /// shift for the character
get_codepoint_bitmap_box_subpixel( &self, codepoint: u32, scale_x: f32, scale_y: f32, shift_x: f32, shift_y: f32, ) -> Option<Rect<i32>>1164 pub fn get_codepoint_bitmap_box_subpixel(
1165 &self,
1166 codepoint: u32,
1167 scale_x: f32,
1168 scale_y: f32,
1169 shift_x: f32,
1170 shift_y: f32,
1171 ) -> Option<Rect<i32>> {
1172 self.get_glyph_bitmap_box_subpixel(
1173 self.find_glyph_index(codepoint),
1174 scale_x,
1175 scale_y,
1176 shift_x,
1177 shift_y,
1178 )
1179 }
1180
1181 /// get the bounding box of the bitmap centered around the glyph origin; so
1182 /// the bitmap width is x1-x0, height is y1-y0, and location to place
1183 /// the bitmap top left is (left_side_bearing*scale, y0).
1184 /// (Note that the bitmap uses y-increases-down, but the shape uses
1185 /// y-increases-up, so CodepointBitmapBox and CodepointBox are inverted.)
get_codepoint_bitmap_box( &self, codepoint: u32, scale_x: f32, scale_y: f32, ) -> Option<Rect<i32>>1186 pub fn get_codepoint_bitmap_box(
1187 &self,
1188 codepoint: u32,
1189 scale_x: f32,
1190 scale_y: f32,
1191 ) -> Option<Rect<i32>> {
1192 self.get_codepoint_bitmap_box_subpixel(codepoint, scale_x, scale_y, 0.0, 0.0)
1193 }
1194
get_font_name_strings(&self) -> FontNameIter<Data>1195 pub fn get_font_name_strings(&self) -> FontNameIter<Data> {
1196 let nm = self.name as usize;
1197 if nm == 0 {
1198 return FontNameIter {
1199 font_info: &self,
1200 string_offset: 0,
1201 index: 0,
1202 count: 0,
1203 };
1204 }
1205 let count = BE::read_u16(&self.data[nm + 2..]) as usize;
1206 let string_offset = nm + BE::read_u16(&self.data[nm + 4..]) as usize;
1207
1208 FontNameIter {
1209 font_info: &self,
1210 string_offset,
1211 index: 0,
1212 count,
1213 }
1214 }
1215 }
1216
1217 #[derive(Clone, Copy)]
1218 pub struct FontNameIter<'a, Data: 'a + Deref<Target = [u8]>> {
1219 /// Font info.
1220 font_info: &'a FontInfo<Data>,
1221 string_offset: usize,
1222 /// Next index.
1223 index: usize,
1224 /// Number of name strings.
1225 count: usize,
1226 }
1227
1228 impl<'a, Data: 'a + Deref<Target = [u8]>> Iterator for FontNameIter<'a, Data> {
1229 type Item = (&'a [u8], Option<PlatformEncodingLanguageId>, u16);
1230
next(&mut self) -> Option<Self::Item>1231 fn next(&mut self) -> Option<Self::Item> {
1232 if self.index >= self.count {
1233 return None;
1234 }
1235
1236 let loc = self.font_info.name as usize + 6 + 12 * self.index;
1237
1238 let pl_id = platform_id(BE::read_u16(&self.font_info.data[loc..]));
1239 let platform_encoding_language_id = pl_id.map(|pl_id| {
1240 let encoding_id = BE::read_u16(&self.font_info.data[loc + 2..]);
1241 let language_id = BE::read_u16(&self.font_info.data[loc + 4..]);
1242 platform_encoding_id(pl_id, Some(encoding_id), Some(language_id))
1243 });
1244 // @TODO: Define an enum type for Name ID.
1245 // See https://www.microsoft.com/typography/otspec/name.htm, "Name IDs" section.
1246 let name_id = BE::read_u16(&self.font_info.data[loc + 6..]);
1247 let length = BE::read_u16(&self.font_info.data[loc + 8..]) as usize;
1248 let offset = self.string_offset + BE::read_u16(&self.font_info.data[loc + 10..]) as usize;
1249
1250 self.index += 1;
1251
1252 Some((
1253 &self.font_info.data[offset..offset + length],
1254 platform_encoding_language_id,
1255 name_id,
1256 ))
1257 }
1258
size_hint(&self) -> (usize, Option<usize>)1259 fn size_hint(&self) -> (usize, Option<usize>) {
1260 let remaining = self.count - self.index;
1261 (remaining, Some(remaining))
1262 }
1263
count(self) -> usize1264 fn count(self) -> usize {
1265 self.count - self.index
1266 }
1267
last(mut self) -> Option<Self::Item>1268 fn last(mut self) -> Option<Self::Item> {
1269 if self.index >= self.count || self.count == 0 {
1270 return None;
1271 }
1272 self.index = self.count - 1;
1273 self.next()
1274 }
1275
nth(&mut self, n: usize) -> Option<Self::Item>1276 fn nth(&mut self, n: usize) -> Option<Self::Item> {
1277 if n > self.count - self.index {
1278 self.index = self.count;
1279 return None;
1280 }
1281 self.index += n;
1282 self.next()
1283 }
1284 }
1285