moscato/
scaler.rs

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        // let mut do_close = true;
718        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                        //                        do_close = false;
752                        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                    // do_close = false;
769                    break;
770                }
771            }
772        }
773        if true {
774            outline.maybe_close();
775        }
776    }
777    Some(())
778}