1use super::geometry::{Bounds, Point, Transform};
2use super::glyph::{Glyph, PathBuilder};
3use super::{cache, data, truetype};
4use pinot::colr::Paint;
5use pinot::types::{Fixed, Tag};
6use pinot::{FontRef, TableProvider};
7use std::collections::{HashMap, HashSet};
8
9pub struct Context {
10 cache: super::cache::Cache,
11 state: State,
12 coords: Vec<i16>,
13}
14
15struct State {
16 truetype: truetype::scale::Scaler,
17 colr_blacklist: HashSet<u16>,
18 colr_map: HashMap<u16, usize>,
19}
20
21impl State {
22 fn new() -> Self {
23 Self {
24 truetype: truetype::scale::Scaler::new(8),
25 colr_blacklist: Default::default(),
26 colr_map: Default::default(),
27 }
28 }
29}
30
31impl Context {
32 pub fn new() -> Self {
33 Self {
34 cache: cache::Cache::new(8),
35 state: State::new(),
36 coords: vec![],
37 }
38 }
39
40 pub fn new_scaler<'a>(&'a mut self, provider: &impl TableProvider<'a>) -> Builder<'a> {
41 let data = data::Data::from_table_provider(provider).unwrap_or_default();
42 self.coords.clear();
43 Builder {
44 ctx: self,
45 id: None,
46 font: data,
47 size: 0.,
48 hint: false,
49 }
50 }
51
52 pub fn new_scaler_with_id<'a>(&'a mut self, font: &FontRef<'a>, font_id: u64) -> Builder<'a> {
53 let data =
54 data::Data::from_cached(font, &self.cache.get(font, font_id)).unwrap_or_default();
55 self.coords.clear();
56 Builder {
57 ctx: self,
58 id: Some(font_id),
59 font: data,
60 size: 0.,
61 hint: false,
62 }
63 }
64}
65
66pub struct Builder<'a> {
67 ctx: &'a mut Context,
68 id: Option<u64>,
69 font: data::Data<'a>,
70 size: f32,
71 hint: bool,
72}
73
74impl<'a> Builder<'a> {
75 pub fn size(mut self, size: f32) -> Self {
76 self.size = size;
77 self
78 }
79
80 pub fn hint(mut self, yes: bool) -> Self {
81 self.hint = yes;
82 self
83 }
84
85 pub fn variations<I>(self, settings: I) -> Self
86 where
87 I: IntoIterator,
88 I::Item: Into<(Tag, f32)>,
89 {
90 if let Some(var) = self.font.var {
91 self.ctx.coords.resize(var.fvar.num_axes() as usize, 0);
92 for setting in settings {
93 let (tag, value) = setting.into();
94 for axis in var.fvar.axes() {
95 if axis.tag == tag {
96 let mut coord = axis.normalize(Fixed::from_f32(value));
97 if let Some(avar) = var.avar {
98 coord = avar
99 .segment_map(axis.index)
100 .map(|map| map.apply(coord))
101 .unwrap_or(coord);
102 }
103 if let Some(c) = self.ctx.coords.get_mut(axis.index as usize) {
104 *c = coord.to_f2dot14();
105 }
106 }
107 }
108 }
109 }
110 self
111 }
112
113 pub fn build(self) -> Scaler<'a> {
114 let upem = self.font.info.upem;
115 let scale = if self.size != 0. && upem != 0 {
116 self.size / upem as f32
117 } else {
118 1.
119 };
120 Scaler {
121 state: &mut self.ctx.state,
122 font: self.font,
123 id: self.id,
124 coords: &self.ctx.coords,
125 size: self.size,
126 scale,
127 hint: self.hint,
128 truetype: None,
129 }
130 }
131}
132
133pub struct Scaler<'a> {
134 state: &'a mut State,
135 font: data::Data<'a>,
136 id: Option<u64>,
137 coords: &'a [i16],
138 size: f32,
139 scale: f32,
140 hint: bool,
141 truetype: Option<truetype::scale::ScalerState<'a>>,
142}
143
144impl<'a> Scaler<'a> {
145 pub fn glyph(&mut self, gid: u16) -> Option<Glyph> {
146 let mut glyph = Glyph::default();
147 if load_glyph(self, gid, &mut glyph) {
148 Some(glyph)
149 } else {
150 None
151 }
152 }
153
154 pub fn color_glyph(&mut self, palette_index: u16, gid: u16) -> Option<Glyph> {
155 if let Some(paint) = self
156 .font
157 .color
158 .and_then(|color| color.colr.find_base_paint(gid))
159 {
160 let mut glyph = Glyph::default();
161 if load_color(self, palette_index, &paint, &mut glyph, 0) {
162 Some(glyph)
163 } else {
164 None
165 }
166 } else {
167 None
168 }
169 }
170}
171
172fn load_color(
173 scaler: &mut Scaler,
174 palette: u16,
175 paint: &Paint,
176 glyph: &mut Glyph,
177 depth: usize,
178) -> bool {
179 if depth > 32 {
180 return false;
181 }
182 use super::color::*;
183 use pinot::cpal::Color;
184 let paint = flatten_transform(paint);
185 let color_data = scaler.font.color.unwrap();
186 let colr = color_data.colr;
187 let cpal = color_data.cpal;
188 let pal = cpal.get(palette).or_else(|| cpal.get(0)).unwrap();
189 const DEFAULT_COLOR: Color = Color {
190 r: 128,
191 g: 128,
192 b: 128,
193 a: 255,
194 };
195 match paint {
196 Paint::Layers { start, end } => {
197 for i in start..end {
198 if let Some(layer) = colr.paint_layer(i) {
199 load_color(scaler, palette, &layer, glyph, depth + 1);
200 }
201 }
202 }
203 Paint::Glyph { paint, id } => {
204 let path_index = glyph.num_paths();
205 if let Some(paint) = paint.get() {
206 if load_glyph(scaler, id, glyph) {
207 if let Some((brush, transform)) = load_leaf(scaler, palette, paint) {
208 glyph.push_command(Command::SimpleFill(path_index, brush, transform));
209 } else {
210 glyph.push_command(Command::PushClip(path_index));
211 load_color(scaler, palette, &paint, glyph, depth + 1);
212 glyph.push_command(Command::PopClip);
213 }
214 }
215 }
216 }
217 Paint::ColorGlyph { id } => {
218 if let Some(paint) = colr.find_base_paint(id) {
219 load_color(scaler, palette, &paint, glyph, depth + 1);
220 }
221 }
222 Paint::Transform {
223 paint,
224 xx,
225 yx,
226 xy,
227 yy,
228 dx,
229 dy,
230 ..
231 } => {
232 if let Some(paint) = paint.get() {
233 glyph.push_command(Command::PushTransform(Transform::new(&[
234 xx, yx, xy, yy, dx, dy,
235 ])));
236 load_color(scaler, palette, &paint, glyph, depth + 1);
237 glyph.push_command(Command::PopTransform);
238 }
239 }
240 Paint::Composite {
241 source,
242 mode,
243 backdrop,
244 } => {
245 if let (Some(source), Some(backdrop)) = (source.get(), backdrop.get()) {
246 glyph.push_command(Command::PushLayer(Bounds::default()));
247 load_color(scaler, palette, &backdrop, glyph, depth + 1);
248 glyph.push_command(Command::BeginBlend(Bounds::default(), mode));
249 load_color(scaler, palette, &source, glyph, depth + 1);
250 glyph.push_command(Command::EndBlend);
251 glyph.push_command(Command::PopLayer);
252 }
253 }
254 Paint::Solid {
255 palette_index,
256 alpha,
257 ..
258 } => {
259 let mut color = pal
260 .colors
261 .get(palette_index as usize)
262 .unwrap_or(DEFAULT_COLOR);
263 if alpha != 1.0 {
264 color.a = (color.a as f32 * alpha) as u8;
265 }
266 glyph.push_command(Command::Fill(Brush::Solid(color), None));
267 }
268 Paint::LinearGradient {
269 color_line,
270 x0,
271 y0,
272 x1,
273 y1,
274 x2,
275 y2,
276 ..
277 } => {
278 let stops = convert_stops(&color_line, &pal);
279 glyph.push_command(Command::Fill(
280 Brush::LinearGradient(LinearGradient {
281 start: Point::new(x0, y0),
282 end: Point::new(x1, y1),
283 stops,
284 extend: color_line.extend(),
285 }),
286 None,
287 ))
288 }
289 Paint::RadialGradient {
290 color_line,
291 x0,
292 y0,
293 radius0,
294 x1,
295 y1,
296 radius1,
297 ..
298 } => {
299 let stops = convert_stops(&color_line, &pal);
300 glyph.push_command(Command::Fill(
301 Brush::RadialGradient(RadialGradient {
302 center0: Point::new(x0, y0),
303 radius0,
304 center1: Point::new(x1, y1),
305 radius1,
306 stops,
307 extend: color_line.extend(),
308 }),
309 None,
310 ))
311 }
312 _ => return true,
313 }
314 true
315}
316
317fn convert_stops(
318 color_line: &pinot::colr::ColorLine,
319 pal: &pinot::cpal::Palette,
320) -> Vec<super::color::ColorStop> {
321 use pinot::cpal::Color;
322 const DEFAULT_COLOR: Color = Color {
323 r: 128,
324 g: 128,
325 b: 128,
326 a: 255,
327 };
328 color_line
329 .stops()
330 .map(|stop| {
331 let mut color = pal
332 .colors
333 .get(stop.palette_index as usize)
334 .unwrap_or(DEFAULT_COLOR);
335 if stop.alpha != 1.0 {
336 color.a = (color.a as f32 * stop.alpha) as u8;
337 }
338 super::color::ColorStop {
339 offset: stop.offset,
340 color,
341 }
342 })
343 .collect()
344}
345
346fn flatten_transform<'a>(paint: &Paint<'a>) -> Paint<'a> {
347 match *paint {
348 Paint::Translate { paint, dx, dy, .. } => Paint::Transform {
349 paint,
350 xx: 1.,
351 yx: 0.,
352 xy: 0.,
353 yy: 1.,
354 dx,
355 dy,
356 var_index: None,
357 },
358 Paint::Scale {
359 paint,
360 scale_x,
361 scale_y,
362 ..
363 } => Paint::Transform {
364 paint,
365 xx: scale_x,
366 yx: 0.,
367 xy: 0.,
368 yy: scale_y,
369 dx: 0.,
370 dy: 0.,
371 var_index: None,
372 },
373 Paint::ScaleAroundCenter {
374 paint,
375 scale_x,
376 scale_y,
377 center_x,
378 center_y,
379 ..
380 } => {
381 let x = Transform::scale(scale_x, scale_y).around_center(center_x, center_y);
382 Paint::Transform {
383 paint,
384 xx: x.xx,
385 yx: x.yx,
386 xy: x.xy,
387 yy: x.yy,
388 dx: x.dx,
389 dy: x.dy,
390 var_index: None,
391 }
392 }
393 Paint::ScaleUniform { paint, scale, .. } => Paint::Transform {
394 paint,
395 xx: scale,
396 yx: 0.,
397 xy: 0.,
398 yy: scale,
399 dx: 0.,
400 dy: 0.,
401 var_index: None,
402 },
403 Paint::ScaleUniformAroundCenter {
404 paint,
405 scale,
406 center_x,
407 center_y,
408 ..
409 } => {
410 let x = Transform::scale(scale, scale).around_center(center_x, center_y);
411 Paint::Transform {
412 paint,
413 xx: x.xx,
414 yx: x.yx,
415 xy: x.xy,
416 yy: x.yy,
417 dx: x.dx,
418 dy: x.dy,
419 var_index: None,
420 }
421 }
422 Paint::Rotate { paint, angle, .. } => {
423 let x = Transform::rotate((angle * 180.0).to_radians());
424 Paint::Transform {
425 paint,
426 xx: x.xx,
427 yx: x.yx,
428 xy: x.xy,
429 yy: x.yy,
430 dx: x.dx,
431 dy: x.dy,
432 var_index: None,
433 }
434 }
435 Paint::RotateAroundCenter {
436 paint,
437 angle,
438 center_x,
439 center_y,
440 ..
441 } => {
442 let x =
443 Transform::rotate((angle * 180.0).to_radians()).around_center(center_x, center_y);
444 Paint::Transform {
445 paint,
446 xx: x.xx,
447 yx: x.yx,
448 xy: x.xy,
449 yy: x.yy,
450 dx: x.dx,
451 dy: x.dy,
452 var_index: None,
453 }
454 }
455 Paint::Skew {
456 paint,
457 x_skew,
458 y_skew,
459 ..
460 } => {
461 let x = Transform::skew((x_skew * 180.0).to_radians(), (y_skew * 180.0).to_radians());
462 Paint::Transform {
463 paint,
464 xx: x.xx,
465 yx: x.yx,
466 xy: x.xy,
467 yy: x.yy,
468 dx: x.dx,
469 dy: x.dy,
470 var_index: None,
471 }
472 }
473 Paint::SkewAroundCenter {
474 paint,
475 x_skew,
476 y_skew,
477 center_x,
478 center_y,
479 ..
480 } => {
481 let x = Transform::skew((x_skew * 180.0).to_radians(), (y_skew * 180.0).to_radians())
482 .around_center(center_x, center_y);
483 Paint::Transform {
484 paint,
485 xx: x.xx,
486 yx: x.yx,
487 xy: x.xy,
488 yy: x.yy,
489 dx: x.dx,
490 dy: x.dy,
491 var_index: None,
492 }
493 }
494 _ => *paint,
495 }
496}
497
498fn is_leaf(paint: &Paint) -> bool {
499 match paint {
500 Paint::Solid { .. }
501 | Paint::LinearGradient { .. }
502 | Paint::RadialGradient { .. }
503 | Paint::SweepGradient { .. } => true,
504 _ => false,
505 }
506}
507
508fn load_leaf(
509 scaler: &mut Scaler,
510 palette: u16,
511 mut leaf_paint: Paint,
512) -> Option<(super::color::Brush, Option<Transform>)> {
513 use super::color::*;
514 use pinot::cpal::Color;
515 let color_data = scaler.font.color.unwrap();
516 let colr = color_data.colr;
517 let cpal = color_data.cpal;
518 let pal = cpal.get(palette).or_else(|| cpal.get(0)).unwrap();
519 const DEFAULT_COLOR: Color = Color {
520 r: 128,
521 g: 128,
522 b: 128,
523 a: 255,
524 };
525 let mut transform = None;
526 leaf_paint = match leaf_paint {
527 Paint::Transform {
528 paint,
529 xx,
530 yx,
531 xy,
532 yy,
533 dx,
534 dy,
535 ..
536 } => {
537 if let Some(paint) = paint.get() {
538 if is_leaf(&paint) {
539 transform = Some(Transform {
540 xx,
541 yx,
542 xy,
543 yy,
544 dx,
545 dy,
546 });
547 paint
548 } else {
549 leaf_paint
550 }
551 } else {
552 leaf_paint
553 }
554 }
555 _ => leaf_paint,
556 };
557 match leaf_paint {
558 Paint::Solid {
559 palette_index,
560 alpha,
561 ..
562 } => {
563 let mut color = pal
564 .colors
565 .get(palette_index as usize)
566 .unwrap_or(DEFAULT_COLOR);
567 if alpha != 1.0 {
568 color.a = (color.a as f32 * alpha) as u8;
569 }
570 Some((Brush::Solid(color), transform))
571 }
572 Paint::LinearGradient {
573 color_line,
574 x0,
575 y0,
576 x1,
577 y1,
578 x2,
579 y2,
580 ..
581 } => {
582 let stops = convert_stops(&color_line, &pal);
583 Some((
584 Brush::LinearGradient(LinearGradient {
585 start: Point::new(x0, y0),
586 end: Point::new(x1, y1),
587 stops,
588 extend: color_line.extend(),
589 }),
590 transform,
591 ))
592 }
593 Paint::RadialGradient {
594 color_line,
595 x0,
596 y0,
597 radius0,
598 x1,
599 y1,
600 radius1,
601 ..
602 } => {
603 let stops = convert_stops(&color_line, &pal);
604 Some((
605 Brush::RadialGradient(RadialGradient {
606 center0: Point::new(x0, y0),
607 radius0,
608 center1: Point::new(x1, y1),
609 radius1,
610 stops,
611 extend: color_line.extend(),
612 }),
613 transform,
614 ))
615 }
616 _ => None,
617 }
618}
619
620fn load_glyph(scaler: &mut Scaler, gid: u16, glyph: &mut Glyph) -> bool {
621 match scaler.font.simple {
622 data::SimpleData::TrueType(data) => {
623 if scaler.truetype.is_none() {
624 scaler.truetype = Some(truetype::scale::ScalerState::new(
625 data,
626 scaler.id,
627 &scaler.coords,
628 scaler.size,
629 scaler.hint,
630 ));
631 }
632 let state = scaler.truetype.as_mut().unwrap();
633 if load_truetype(
634 &mut scaler.state.truetype,
635 state,
636 gid,
637 glyph,
638 scaler.size != 0.,
639 ) {
640 true
641 } else {
642 false
643 }
644 }
645 _ => false,
646 }
647}
648
649fn load_truetype(
650 scaler: &mut truetype::scale::Scaler,
651 state: &mut truetype::scale::ScalerState,
652 gid: u16,
653 outline: &mut Glyph,
654 scaled: bool,
655) -> bool {
656 if scaler.scale(state, gid).is_some() {
657 let mut builder = PathBuilder::new(outline);
658 fill_outline(
659 &mut builder,
660 &scaler.scaled,
661 &scaler.contours,
662 &scaler.tags,
663 scaled,
664 );
665 builder.finish();
666 true
667 } else {
668 false
669 }
670}
671
672fn fill_outline(
673 outline: &mut PathBuilder,
674 points: &[truetype::Point],
675 contours: &[u16],
676 tags: &[u8],
677 scaled: bool,
678) -> Option<()> {
679 use truetype::Point as PointI;
680 #[inline(always)]
681 fn conv(p: truetype::Point, s: f32) -> Point {
682 Point::new(p.x as f32 * s, p.y as f32 * s)
683 }
684 const TAG_MASK: u8 = 0x3;
685 const CONIC: u8 = 0x0;
686 const ON: u8 = 0x1;
687 const CUBIC: u8 = 0x2;
688 let s = if scaled { 1. / 64. } else { 1. };
689 for c in 0..contours.len() {
690 let mut cur = if c > 0 {
691 contours[c - 1] as usize + 1
692 } else {
693 0
694 };
695 let mut last = contours[c] as usize;
696 if last < cur || last >= points.len() {
697 return None;
698 }
699 let mut v_start = points[cur];
700 let v_last = points[last];
701 let mut tag = tags[cur] & TAG_MASK;
702 if tag == CUBIC {
703 return None;
704 }
705 let mut step_point = true;
706 if tag == CONIC {
707 if tags[last] & TAG_MASK == ON {
708 v_start = v_last;
709 last -= 1;
710 } else {
711 v_start.x = (v_start.x + v_last.x) / 2;
712 v_start.y = (v_start.y + v_last.y) / 2;
713 }
714 step_point = false;
715 }
716 outline.move_to(conv(v_start, s));
717 while cur < last {
719 if step_point {
720 cur += 1;
721 }
722 step_point = true;
723 tag = tags[cur] & TAG_MASK;
724 match tag {
725 ON => {
726 outline.line_to(conv(points[cur], s));
727 continue;
728 }
729 CONIC => {
730 let mut do_close_conic = true;
731 let mut v_control = points[cur];
732 while cur < last {
733 cur += 1;
734 let point = points[cur];
735 tag = tags[cur] & TAG_MASK;
736 if tag == ON {
737 outline.quad_to(conv(v_control, s), conv(point, s));
738 do_close_conic = false;
739 break;
740 }
741 if tag != CONIC {
742 return None;
743 }
744 let v_middle =
745 PointI::new((v_control.x + point.x) / 2, (v_control.y + point.y) / 2);
746 outline.quad_to(conv(v_control, s), conv(v_middle, s));
747 v_control = point;
748 }
749 if do_close_conic {
750 outline.quad_to(conv(v_control, s), conv(v_start, s));
751 break;
753 }
754 continue;
755 }
756 _ => {
757 if cur + 1 > last || (tags[cur + 1] & TAG_MASK != CUBIC) {
758 return None;
759 }
760 let v1 = conv(points[cur], s);
761 let v2 = conv(points[cur + 1], s);
762 cur += 2;
763 if cur <= last {
764 outline.curve_to(v1, v2, conv(points[cur], s));
765 continue;
766 }
767 outline.curve_to(v1, v2, conv(v_start, s));
768 break;
770 }
771 }
772 }
773 if true {
774 outline.maybe_close();
775 }
776 }
777 Some(())
778}