makepad_ttf_parser/tables/
colr.rs

1//! A [Color Table](
2//! https://docs.microsoft.com/en-us/typography/opentype/spec/colr) implementation.
3
4// NOTE: Parts of the implementation have been inspired by
5// [skrifa](https://github.com/googlefonts/fontations/tree/main/skrifa).
6
7#[cfg(feature = "variable-fonts")]
8use crate::delta_set::DeltaSetIndexMap;
9use crate::parser::{FromData, LazyArray16, Offset, Offset24, Offset32, Stream, F2DOT14};
10#[cfg(feature = "variable-fonts")]
11use crate::var_store::ItemVariationStore;
12#[cfg(feature = "variable-fonts")]
13use crate::NormalizedCoordinate;
14use crate::{cpal, Fixed, LazyArray32, RectF, Transform};
15use crate::{GlyphId, RgbaColor};
16
17/// A [base glyph](
18/// https://learn.microsoft.com/en-us/typography/opentype/spec/colr#baseglyph-and-layer-records).
19#[derive(Clone, Copy, Debug)]
20struct BaseGlyphRecord {
21    glyph_id: GlyphId,
22    first_layer_index: u16,
23    num_layers: u16,
24}
25
26/// A [ClipBox](https://learn.microsoft.com/en-us/typography/opentype/spec/colr#baseglyphlist-layerlist-and-cliplist).
27pub type ClipBox = RectF;
28
29/// A paint.
30#[derive(Clone, Debug)]
31pub enum Paint<'a> {
32    /// A paint with a solid color.
33    Solid(RgbaColor),
34    /// A paint with a linear gradient.
35    LinearGradient(LinearGradient<'a>),
36    /// A paint with a radial gradient.
37    RadialGradient(RadialGradient<'a>),
38    /// A paint with a sweep gradient.
39    SweepGradient(SweepGradient<'a>),
40}
41
42/// A [clip record](
43/// https://learn.microsoft.com/en-us/typography/opentype/spec/colr#baseglyphlist-layerlist-and-cliplist).
44#[derive(Clone, Copy, Debug)]
45struct ClipRecord {
46    /// The first glyph ID for the range covered by this record.
47    pub start_glyph_id: GlyphId,
48    /// The last glyph ID, *inclusive*, for the range covered by this record.
49    pub end_glyph_id: GlyphId,
50    /// The offset to the clip box.
51    pub clip_box_offset: Offset24,
52}
53
54impl FromData for ClipRecord {
55    const SIZE: usize = 7;
56
57    fn parse(data: &[u8]) -> Option<Self> {
58        let mut s = Stream::new(data);
59        Some(ClipRecord {
60            start_glyph_id: s.read::<GlyphId>()?,
61            end_glyph_id: s.read::<GlyphId>()?,
62            clip_box_offset: s.read::<Offset24>()?,
63        })
64    }
65}
66
67impl ClipRecord {
68    /// Returns the glyphs range.
69    pub fn glyphs_range(&self) -> core::ops::RangeInclusive<GlyphId> {
70        self.start_glyph_id..=self.end_glyph_id
71    }
72}
73
74/// A [clip list](
75/// https://learn.microsoft.com/en-us/typography/opentype/spec/colr#baseglyphlist-layerlist-and-cliplist).
76#[derive(Clone, Copy, Debug, Default)]
77struct ClipList<'a> {
78    data: &'a [u8],
79    records: LazyArray32<'a, ClipRecord>,
80}
81
82impl<'a> ClipList<'a> {
83    pub fn get(
84        &self,
85        index: u32,
86        #[cfg(feature = "variable-fonts")] variation_data: &VariationData,
87        #[cfg(feature = "variable-fonts")] coords: &[NormalizedCoordinate],
88    ) -> Option<ClipBox> {
89        let record = self.records.get(index)?;
90        let offset = record.clip_box_offset.to_usize();
91        self.data.get(offset..).and_then(|data| {
92            let mut s = Stream::new(data);
93            let format = s.read::<u8>()?;
94
95            #[cfg(not(feature = "variable-fonts"))]
96            let deltas = [0.0, 0.0, 0.0, 0.0];
97            #[cfg(feature = "variable-fonts")]
98            let deltas = if format == 2 {
99                let mut var_s = s.clone();
100                var_s.advance(8);
101                let var_index_base = var_s.read::<u32>()?;
102
103                variation_data.read_deltas::<4>(var_index_base, coords)
104            } else {
105                [0.0, 0.0, 0.0, 0.0]
106            };
107
108            Some(ClipBox {
109                x_min: s.read::<i16>()? as f32 + deltas[0],
110                y_min: s.read::<i16>()? as f32 + deltas[1],
111                x_max: s.read::<i16>()? as f32 + deltas[2],
112                y_max: s.read::<i16>()? as f32 + deltas[3],
113            })
114        })
115    }
116
117    /// Returns a ClipBox by glyph ID.
118    #[inline]
119    pub fn find(
120        &self,
121        glyph_id: GlyphId,
122        #[cfg(feature = "variable-fonts")] variation_data: &VariationData,
123        #[cfg(feature = "variable-fonts")] coords: &[NormalizedCoordinate],
124    ) -> Option<ClipBox> {
125        let index = self
126            .records
127            .into_iter()
128            .position(|v| v.glyphs_range().contains(&glyph_id))?;
129        self.get(
130            index as u32,
131            #[cfg(feature = "variable-fonts")]
132            variation_data,
133            #[cfg(feature = "variable-fonts")]
134            coords,
135        )
136    }
137}
138
139impl FromData for BaseGlyphRecord {
140    const SIZE: usize = 6;
141
142    fn parse(data: &[u8]) -> Option<Self> {
143        let mut s = Stream::new(data);
144        Some(Self {
145            glyph_id: s.read::<GlyphId>()?,
146            first_layer_index: s.read::<u16>()?,
147            num_layers: s.read::<u16>()?,
148        })
149    }
150}
151
152/// A [layer](
153/// https://learn.microsoft.com/en-us/typography/opentype/spec/colr#baseglyph-and-layer-records).
154#[derive(Clone, Copy, Debug)]
155struct LayerRecord {
156    glyph_id: GlyphId,
157    palette_index: u16,
158}
159
160impl FromData for LayerRecord {
161    const SIZE: usize = 4;
162
163    fn parse(data: &[u8]) -> Option<Self> {
164        let mut s = Stream::new(data);
165        Some(Self {
166            glyph_id: s.read::<GlyphId>()?,
167            palette_index: s.read::<u16>()?,
168        })
169    }
170}
171
172/// A [BaseGlyphPaintRecord](
173/// https://learn.microsoft.com/en-us/typography/opentype/spec/colr#baseglyphlist-layerlist-and-cliplist).
174#[derive(Clone, Copy, Debug)]
175struct BaseGlyphPaintRecord {
176    glyph_id: GlyphId,
177    paint_table_offset: Offset32,
178}
179
180impl FromData for BaseGlyphPaintRecord {
181    const SIZE: usize = 6;
182
183    fn parse(data: &[u8]) -> Option<Self> {
184        let mut s = Stream::new(data);
185        Some(Self {
186            glyph_id: s.read::<GlyphId>()?,
187            paint_table_offset: s.read::<Offset32>()?,
188        })
189    }
190}
191
192/// A [gradient extend](
193/// https://learn.microsoft.com/en-us/typography/opentype/spec/colr#baseglyphlist-layerlist-and-cliplist).
194#[derive(Clone, Copy, Debug, PartialEq)]
195pub enum GradientExtend {
196    /// The `Pad` gradient extend mode.
197    Pad,
198    /// The `Repeat` gradient extend mode.
199    Repeat,
200    /// The `Reflect` gradient extend mode.
201    Reflect,
202}
203
204impl FromData for GradientExtend {
205    const SIZE: usize = 1;
206
207    fn parse(data: &[u8]) -> Option<Self> {
208        match data[0] {
209            0 => Some(Self::Pad),
210            1 => Some(Self::Repeat),
211            2 => Some(Self::Reflect),
212            _ => None,
213        }
214    }
215}
216
217/// A [color stop](
218/// https://learn.microsoft.com/en-us/typography/opentype/spec/colr#color-references-colorstop-and-colorline).
219#[derive(Clone, Copy, Debug)]
220struct ColorStopRaw {
221    stop_offset: F2DOT14,
222    palette_index: u16,
223    alpha: F2DOT14,
224}
225
226impl FromData for ColorStopRaw {
227    const SIZE: usize = 6;
228
229    fn parse(data: &[u8]) -> Option<Self> {
230        let mut s = Stream::new(data);
231        Some(Self {
232            stop_offset: s.read::<F2DOT14>()?,
233            palette_index: s.read::<u16>()?,
234            alpha: s.read::<F2DOT14>()?,
235        })
236    }
237}
238
239/// A [var color stop](
240/// https://learn.microsoft.com/en-us/typography/opentype/spec/colr#color-references-colorstop-and-colorline).
241#[cfg(feature = "variable-fonts")]
242#[derive(Clone, Copy, Debug)]
243struct VarColorStopRaw {
244    stop_offset: F2DOT14,
245    palette_index: u16,
246    alpha: F2DOT14,
247    var_index_base: u32,
248}
249
250#[cfg(feature = "variable-fonts")]
251impl FromData for VarColorStopRaw {
252    const SIZE: usize = 10;
253
254    fn parse(data: &[u8]) -> Option<Self> {
255        let mut s = Stream::new(data);
256        Some(Self {
257            stop_offset: s.read::<F2DOT14>()?,
258            palette_index: s.read::<u16>()?,
259            alpha: s.read::<F2DOT14>()?,
260            var_index_base: s.read::<u32>()?,
261        })
262    }
263}
264
265#[derive(Clone)]
266struct NonVarColorLine<'a> {
267    extend: GradientExtend,
268    colors: LazyArray16<'a, ColorStopRaw>,
269    palettes: cpal::Table<'a>,
270    foreground_color: RgbaColor,
271}
272
273impl NonVarColorLine<'_> {
274    // TODO: Color stops should be sorted, but hard to do without allocations
275    fn get(&self, palette: u16, index: u16) -> Option<ColorStop> {
276        let info = self.colors.get(index)?;
277
278        let mut color = if info.palette_index == u16::MAX {
279            self.foreground_color
280        } else {
281            self.palettes.get(palette, info.palette_index)?
282        };
283
284        color.apply_alpha(info.alpha.to_f32());
285        Some(ColorStop {
286            stop_offset: info.stop_offset.to_f32(),
287            color,
288        })
289    }
290}
291
292#[cfg(feature = "variable-fonts")]
293impl VarColorLine<'_> {
294    // TODO: Color stops should be sorted, but hard to do without allocations
295    fn get(
296        &self,
297        palette: u16,
298        index: u16,
299        #[cfg(feature = "variable-fonts")] variation_data: VariationData,
300        #[cfg(feature = "variable-fonts")] coordinates: &[NormalizedCoordinate],
301    ) -> Option<ColorStop> {
302        let info = self.colors.get(index)?;
303
304        let mut color = if info.palette_index == u16::MAX {
305            self.foreground_color
306        } else {
307            self.palettes.get(palette, info.palette_index)?
308        };
309
310        let deltas = variation_data.read_deltas::<2>(info.var_index_base, coordinates);
311        let stop_offset = info.stop_offset.apply_float_delta(deltas[0]);
312        color.apply_alpha(info.alpha.apply_float_delta(deltas[1]));
313
314        Some(ColorStop { stop_offset, color })
315    }
316}
317
318#[cfg(feature = "variable-fonts")]
319#[derive(Clone)]
320struct VarColorLine<'a> {
321    extend: GradientExtend,
322    colors: LazyArray16<'a, VarColorStopRaw>,
323    palettes: cpal::Table<'a>,
324    foreground_color: RgbaColor,
325}
326
327#[derive(Clone)]
328enum ColorLine<'a> {
329    #[cfg(feature = "variable-fonts")]
330    VarColorLine(VarColorLine<'a>),
331    NonVarColorLine(NonVarColorLine<'a>),
332}
333
334/// A [gradient extend](
335/// https://learn.microsoft.com/en-us/typography/opentype/spec/colr#baseglyphlist-layerlist-and-cliplist).
336#[derive(Clone, Copy, Debug)]
337pub struct ColorStop {
338    /// The offset of the color stop.
339    pub stop_offset: f32,
340    /// The color of the color stop.
341    pub color: RgbaColor,
342}
343
344/// A [linear gradient](https://learn.microsoft.com/en-us/typography/opentype/spec/colr#formats-4-and-5-paintlineargradient-paintvarlineargradient)
345#[derive(Clone)]
346pub struct LinearGradient<'a> {
347    /// The `x0` value.
348    pub x0: f32,
349    /// The `y0` value.
350    pub y0: f32,
351    /// The `x1` value.
352    pub x1: f32,
353    /// The `y1` value.
354    pub y1: f32,
355    /// The `x2` value.
356    pub x2: f32,
357    /// The `y2` value.
358    pub y2: f32,
359    /// The extend.
360    pub extend: GradientExtend,
361    #[cfg(feature = "variable-fonts")]
362    variation_data: VariationData<'a>,
363    color_line: ColorLine<'a>,
364}
365
366impl<'a> core::fmt::Debug for LinearGradient<'a> {
367    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
368        f.debug_struct("LinearGradient")
369            .field("x0", &self.x0)
370            .field("y0", &self.y0)
371            .field("x1", &self.x1)
372            .field("y1", &self.y1)
373            .field("x2", &self.x2)
374            .field("y2", &self.y2)
375            .field("extend", &self.extend)
376            .field(
377                "stops",
378                &self.stops(
379                    0,
380                    #[cfg(feature = "variable-fonts")]
381                    &[],
382                ),
383            )
384            .finish()
385    }
386}
387
388impl<'a> LinearGradient<'a> {
389    /// Returns an iterator over the stops of the linear gradient. Stops need to be sorted
390    /// manually by the caller.
391    pub fn stops<'b>(
392        &'b self,
393        palette: u16,
394        #[cfg(feature = "variable-fonts")] coords: &'b [NormalizedCoordinate],
395    ) -> GradientStopsIter<'a, 'b> {
396        GradientStopsIter {
397            color_line: &self.color_line,
398            palette,
399            index: 0,
400            #[cfg(feature = "variable-fonts")]
401            variation_data: self.variation_data,
402            #[cfg(feature = "variable-fonts")]
403            coords,
404        }
405    }
406}
407
408/// A [radial gradient](https://learn.microsoft.com/en-us/typography/opentype/spec/colr#formats-6-and-7-paintradialgradient-paintvarradialgradient)
409#[derive(Clone)]
410pub struct RadialGradient<'a> {
411    /// The `x0` value.
412    pub x0: f32,
413    /// The `y0` value.
414    pub y0: f32,
415    /// The `r0` value.
416    pub r0: f32,
417    /// The `r1` value.
418    pub r1: f32,
419    /// The `x1` value.
420    pub x1: f32,
421    /// The `y1` value.
422    pub y1: f32,
423    /// The extend.
424    pub extend: GradientExtend,
425    #[cfg(feature = "variable-fonts")]
426    variation_data: VariationData<'a>,
427    color_line: ColorLine<'a>,
428}
429
430impl<'a> core::fmt::Debug for RadialGradient<'a> {
431    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
432        f.debug_struct("RadialGradient")
433            .field("x0", &self.x0)
434            .field("y0", &self.y0)
435            .field("r0", &self.r0)
436            .field("r1", &self.r1)
437            .field("x1", &self.x1)
438            .field("y1", &self.y1)
439            .field("extend", &self.extend)
440            .field(
441                "stops",
442                &self.stops(
443                    0,
444                    #[cfg(feature = "variable-fonts")]
445                    &[],
446                ),
447            )
448            .finish()
449    }
450}
451
452impl<'a> RadialGradient<'a> {
453    /// Returns an iterator over the stops of the radial gradient. Stops need to be sorted
454    /// manually by the caller.
455    pub fn stops<'b>(
456        &'b self,
457        palette: u16,
458        #[cfg(feature = "variable-fonts")] coords: &'a [NormalizedCoordinate],
459    ) -> GradientStopsIter<'a, 'b> {
460        GradientStopsIter {
461            color_line: &self.color_line,
462            palette,
463            index: 0,
464            #[cfg(feature = "variable-fonts")]
465            variation_data: self.variation_data,
466            #[cfg(feature = "variable-fonts")]
467            coords,
468        }
469    }
470}
471
472/// A [sweep gradient](https://learn.microsoft.com/en-us/typography/opentype/spec/colr#formats-8-and-9-paintsweepgradient-paintvarsweepgradient)
473#[derive(Clone)]
474pub struct SweepGradient<'a> {
475    /// The x of the center.
476    pub center_x: f32,
477    /// The y of the center.
478    pub center_y: f32,
479    /// The start angle.
480    pub start_angle: f32,
481    /// The end angle.
482    pub end_angle: f32,
483    /// The extend.
484    pub extend: GradientExtend,
485    #[cfg(feature = "variable-fonts")]
486    variation_data: VariationData<'a>,
487    color_line: ColorLine<'a>,
488}
489
490impl<'a> core::fmt::Debug for SweepGradient<'a> {
491    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
492        f.debug_struct("SweepGradient")
493            .field("center_x", &self.center_x)
494            .field("center_y", &self.center_y)
495            .field("start_angle", &self.start_angle)
496            .field("end_angle", &self.end_angle)
497            .field("extend", &self.extend)
498            .field(
499                "stops",
500                &self.stops(
501                    0,
502                    #[cfg(feature = "variable-fonts")]
503                    &[],
504                ),
505            )
506            .finish()
507    }
508}
509
510impl<'a> SweepGradient<'a> {
511    // TODO: Make API nicer so that variable coordinates don't
512    // need to be passed by the caller (same for radial and linear gradient)
513    /// Returns an iterator over the stops of the sweep gradient. Stops need to be sorted
514    /// manually by the caller.
515    pub fn stops<'b>(
516        &'b self,
517        palette: u16,
518        #[cfg(feature = "variable-fonts")] coords: &'a [NormalizedCoordinate],
519    ) -> GradientStopsIter<'a, 'b> {
520        GradientStopsIter {
521            color_line: &self.color_line,
522            palette,
523            index: 0,
524            #[cfg(feature = "variable-fonts")]
525            variation_data: self.variation_data,
526            #[cfg(feature = "variable-fonts")]
527            coords,
528        }
529    }
530}
531
532/// An iterator over stops of a gradient.
533#[derive(Clone, Copy)]
534pub struct GradientStopsIter<'a, 'b> {
535    color_line: &'b ColorLine<'a>,
536    palette: u16,
537    index: u16,
538    #[cfg(feature = "variable-fonts")]
539    variation_data: VariationData<'a>,
540    #[cfg(feature = "variable-fonts")]
541    coords: &'b [NormalizedCoordinate],
542}
543
544impl Iterator for GradientStopsIter<'_, '_> {
545    type Item = ColorStop;
546
547    fn next(&mut self) -> Option<Self::Item> {
548        let len = match self.color_line {
549            #[cfg(feature = "variable-fonts")]
550            ColorLine::VarColorLine(vcl) => vcl.colors.len(),
551            ColorLine::NonVarColorLine(nvcl) => nvcl.colors.len(),
552        };
553
554        if self.index == len {
555            return None;
556        }
557
558        let index = self.index;
559        self.index = self.index.checked_add(1)?;
560
561        match self.color_line {
562            #[cfg(feature = "variable-fonts")]
563            ColorLine::VarColorLine(vcl) => {
564                vcl.get(self.palette, index, self.variation_data, self.coords)
565            }
566            ColorLine::NonVarColorLine(nvcl) => nvcl.get(self.palette, index),
567        }
568    }
569}
570
571impl core::fmt::Debug for GradientStopsIter<'_, '_> {
572    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
573        f.debug_list().entries(*self).finish()
574    }
575}
576
577/// A [composite mode](https://learn.microsoft.com/en-us/typography/opentype/spec/colr#format-32-paintcomposite)
578#[derive(Clone, Copy, PartialEq, Debug)]
579pub enum CompositeMode {
580    /// The composite mode 'Clear'.
581    Clear,
582    /// The composite mode 'Source'.
583    Source,
584    /// The composite mode 'Destination'.
585    Destination,
586    /// The composite mode 'SourceOver'.
587    SourceOver,
588    /// The composite mode 'DestinationOver'.
589    DestinationOver,
590    /// The composite mode 'SourceIn'.
591    SourceIn,
592    /// The composite mode 'DestinationIn'.
593    DestinationIn,
594    /// The composite mode 'SourceOut'.
595    SourceOut,
596    /// The composite mode 'DestinationOut'.
597    DestinationOut,
598    /// The composite mode 'SourceAtop'.
599    SourceAtop,
600    /// The composite mode 'DestinationAtop'.
601    DestinationAtop,
602    /// The composite mode 'Xor'.
603    Xor,
604    /// The composite mode 'Plus'.
605    Plus,
606    /// The composite mode 'Screen'.
607    Screen,
608    /// The composite mode 'Overlay'.
609    Overlay,
610    /// The composite mode 'Darken'.
611    Darken,
612    /// The composite mode 'Lighten'.
613    Lighten,
614    /// The composite mode 'ColorDodge'.
615    ColorDodge,
616    /// The composite mode 'ColorBurn'.
617    ColorBurn,
618    /// The composite mode 'HardLight'.
619    HardLight,
620    /// The composite mode 'SoftLight'.
621    SoftLight,
622    /// The composite mode 'Difference'.
623    Difference,
624    /// The composite mode 'Exclusion'.
625    Exclusion,
626    /// The composite mode 'Multiply'.
627    Multiply,
628    /// The composite mode 'Hue'.
629    Hue,
630    /// The composite mode 'Saturation'.
631    Saturation,
632    /// The composite mode 'Color'.
633    Color,
634    /// The composite mode 'Luminosity'.
635    Luminosity,
636}
637
638impl FromData for CompositeMode {
639    const SIZE: usize = 1;
640
641    fn parse(data: &[u8]) -> Option<Self> {
642        match data[0] {
643            0 => Some(Self::Clear),
644            1 => Some(Self::Source),
645            2 => Some(Self::Destination),
646            3 => Some(Self::SourceOver),
647            4 => Some(Self::DestinationOver),
648            5 => Some(Self::SourceIn),
649            6 => Some(Self::DestinationIn),
650            7 => Some(Self::SourceOut),
651            8 => Some(Self::DestinationOut),
652            9 => Some(Self::SourceAtop),
653            10 => Some(Self::DestinationAtop),
654            11 => Some(Self::Xor),
655            12 => Some(Self::Plus),
656            13 => Some(Self::Screen),
657            14 => Some(Self::Overlay),
658            15 => Some(Self::Darken),
659            16 => Some(Self::Lighten),
660            17 => Some(Self::ColorDodge),
661            18 => Some(Self::ColorBurn),
662            19 => Some(Self::HardLight),
663            20 => Some(Self::SoftLight),
664            21 => Some(Self::Difference),
665            22 => Some(Self::Exclusion),
666            23 => Some(Self::Multiply),
667            24 => Some(Self::Hue),
668            25 => Some(Self::Saturation),
669            26 => Some(Self::Color),
670            27 => Some(Self::Luminosity),
671            _ => None,
672        }
673    }
674}
675
676/// A trait for color glyph painting.
677///
678/// See [COLR](https://learn.microsoft.com/en-us/typography/opentype/spec/colr) for details.
679pub trait Painter<'a> {
680    /// Outline a glyph and store it.
681    fn outline_glyph(&mut self, glyph_id: GlyphId);
682    /// Paint the stored outline using the provided color.
683    fn paint(&mut self, paint: Paint<'a>);
684
685    /// Push a new clip path using the currently stored outline.
686    fn push_clip(&mut self);
687
688    /// Push a new clip path using the clip box.
689    fn push_clip_box(&mut self, clipbox: ClipBox);
690    /// Pop the last clip path.
691    fn pop_clip(&mut self);
692
693    /// Push a new layer with the given composite mode.
694    fn push_layer(&mut self, mode: CompositeMode);
695    /// Pop the last layer.
696    fn pop_layer(&mut self);
697
698    // TODO: Unify transforms into one callback.
699    /// Push a translation transform.
700    fn push_translate(&mut self, tx: f32, ty: f32);
701    /// Push a scaling transform.
702    fn push_scale(&mut self, sx: f32, sy: f32);
703    /// Push a rotation transform.
704    fn push_rotate(&mut self, angle: f32);
705    /// Push a skewing transform.
706    fn push_skew(&mut self, skew_x: f32, skew_y: f32);
707    /// Push a transform.
708    fn push_transform(&mut self, transform: Transform);
709    /// Pop the last transform.
710    fn pop_transform(&mut self);
711}
712
713/// A [Color Table](
714/// https://docs.microsoft.com/en-us/typography/opentype/spec/colr).
715///
716/// Currently, only version 0 is supported.
717#[derive(Clone, Copy, Debug)]
718pub struct Table<'a> {
719    pub(crate) palettes: cpal::Table<'a>,
720    data: &'a [u8],
721    version: u8,
722    // v0
723    base_glyphs: LazyArray16<'a, BaseGlyphRecord>,
724    layers: LazyArray16<'a, LayerRecord>,
725    // v1
726    base_glyph_paints_offset: Offset32,
727    base_glyph_paints: LazyArray32<'a, BaseGlyphPaintRecord>,
728    layer_paint_offsets_offset: Offset32,
729    layer_paint_offsets: LazyArray32<'a, Offset32>,
730    clip_list_offsets_offset: Offset32,
731    clip_list: ClipList<'a>,
732    #[cfg(feature = "variable-fonts")]
733    var_index_map: Option<DeltaSetIndexMap<'a>>,
734    #[cfg(feature = "variable-fonts")]
735    item_variation_store: Option<ItemVariationStore<'a>>,
736}
737
738impl<'a> Table<'a> {
739    /// Parses a table from raw data.
740    pub fn parse(palettes: cpal::Table<'a>, data: &'a [u8]) -> Option<Self> {
741        let mut s = Stream::new(data);
742
743        let version = s.read::<u16>()?;
744        if version > 1 {
745            return None;
746        }
747
748        let num_base_glyphs = s.read::<u16>()?;
749        let base_glyphs_offset = s.read::<Offset32>()?;
750        let layers_offset = s.read::<Offset32>()?;
751        let num_layers = s.read::<u16>()?;
752
753        let base_glyphs = Stream::new_at(data, base_glyphs_offset.to_usize())?
754            .read_array16::<BaseGlyphRecord>(num_base_glyphs)?;
755
756        let layers = Stream::new_at(data, layers_offset.to_usize())?
757            .read_array16::<LayerRecord>(num_layers)?;
758
759        let mut table = Self {
760            version: version as u8,
761            data,
762            palettes,
763            base_glyphs,
764            layers,
765            base_glyph_paints_offset: Offset32(0), // the actual value doesn't matter
766            base_glyph_paints: LazyArray32::default(),
767            layer_paint_offsets_offset: Offset32(0),
768            layer_paint_offsets: LazyArray32::default(),
769            clip_list_offsets_offset: Offset32(0),
770            clip_list: ClipList::default(),
771            #[cfg(feature = "variable-fonts")]
772            item_variation_store: None,
773            #[cfg(feature = "variable-fonts")]
774            var_index_map: None,
775        };
776
777        if version == 0 {
778            return Some(table);
779        }
780
781        table.base_glyph_paints_offset = s.read::<Offset32>()?;
782        let layer_list_offset = s.read::<Option<Offset32>>()?;
783        let clip_list_offset = s.read::<Option<Offset32>>()?;
784        #[cfg(feature = "variable-fonts")]
785        let var_index_map_offset = s.read::<Option<Offset32>>()?;
786        #[cfg(feature = "variable-fonts")]
787        let item_variation_offset = s.read::<Option<Offset32>>()?;
788
789        {
790            let mut s = Stream::new_at(data, table.base_glyph_paints_offset.to_usize())?;
791            let count = s.read::<u32>()?;
792            table.base_glyph_paints = s.read_array32::<BaseGlyphPaintRecord>(count)?;
793        }
794
795        if let Some(offset) = layer_list_offset {
796            table.layer_paint_offsets_offset = offset;
797            let mut s = Stream::new_at(data, offset.to_usize())?;
798            let count = s.read::<u32>()?;
799            table.layer_paint_offsets = s.read_array32::<Offset32>(count)?;
800        }
801
802        if let Some(offset) = clip_list_offset {
803            table.clip_list_offsets_offset = offset;
804            let clip_data = data.get(offset.to_usize()..)?;
805            let mut s = Stream::new(clip_data);
806            s.skip::<u8>(); // Format
807            let count = s.read::<u32>()?;
808            table.clip_list = ClipList {
809                data: clip_data,
810                records: s.read_array32::<ClipRecord>(count)?,
811            };
812        }
813
814        #[cfg(feature = "variable-fonts")]
815        {
816            if let Some(offset) = item_variation_offset {
817                let item_var_data = data.get(offset.to_usize()..)?;
818                let s = Stream::new(item_var_data);
819                let var_store = ItemVariationStore::parse(s)?;
820                table.item_variation_store = Some(var_store);
821            }
822        }
823
824        #[cfg(feature = "variable-fonts")]
825        {
826            if let Some(offset) = var_index_map_offset {
827                let var_index_map_data = data.get(offset.to_usize()..)?;
828                let var_index_map = DeltaSetIndexMap::new(var_index_map_data);
829                table.var_index_map = Some(var_index_map);
830            }
831        }
832
833        Some(table)
834    }
835
836    /// Returns `true` if the current table has version 0.
837    ///
838    /// A simple table can only emit `outline_glyph` and `paint`
839    /// [`Painter`] methods.
840    pub fn is_simple(&self) -> bool {
841        self.version == 0
842    }
843
844    fn get_v0(&self, glyph_id: GlyphId) -> Option<BaseGlyphRecord> {
845        self.base_glyphs
846            .binary_search_by(|base| base.glyph_id.cmp(&glyph_id))
847            .map(|v| v.1)
848    }
849
850    fn get_v1(&self, glyph_id: GlyphId) -> Option<BaseGlyphPaintRecord> {
851        self.base_glyph_paints
852            .binary_search_by(|base| base.glyph_id.cmp(&glyph_id))
853            .map(|v| v.1)
854    }
855
856    #[cfg(feature = "variable-fonts")]
857    fn variation_data(&self) -> VariationData<'a> {
858        VariationData {
859            variation_store: self.item_variation_store,
860            delta_map: self.var_index_map,
861        }
862    }
863
864    /// Whether the table contains a definition for the given glyph.
865    pub fn contains(&self, glyph_id: GlyphId) -> bool {
866        self.get_v1(glyph_id).is_some() || self.get_v0(glyph_id).is_some()
867    }
868
869    // This method should only be called from outside, not from within `colr.rs`.
870    // From inside, you always should call paint_impl, so that the recursion stack can
871    // be passed on and any kind of recursion can be prevented.
872    /// Paints the color glyph.
873    pub fn paint(
874        &self,
875        glyph_id: GlyphId,
876        palette: u16,
877        painter: &mut dyn Painter<'a>,
878        #[cfg(feature = "variable-fonts")] coords: &[NormalizedCoordinate],
879        foreground_color: RgbaColor,
880    ) -> Option<()> {
881        let mut recursion_stack = RecursionStack {
882            stack: [0; 64],
883            len: 0,
884        };
885
886        self.paint_impl(
887            glyph_id,
888            palette,
889            painter,
890            &mut recursion_stack,
891            #[cfg(feature = "variable-fonts")]
892            coords,
893            foreground_color,
894        )
895    }
896
897    fn paint_impl(
898        &self,
899        glyph_id: GlyphId,
900        palette: u16,
901        painter: &mut dyn Painter<'a>,
902        recusion_stack: &mut RecursionStack,
903        #[cfg(feature = "variable-fonts")] coords: &[NormalizedCoordinate],
904        foreground_color: RgbaColor,
905    ) -> Option<()> {
906        if let Some(base) = self.get_v1(glyph_id) {
907            self.paint_v1(
908                base,
909                palette,
910                painter,
911                recusion_stack,
912                #[cfg(feature = "variable-fonts")]
913                coords,
914                foreground_color,
915            )
916        } else if let Some(base) = self.get_v0(glyph_id) {
917            self.paint_v0(base, palette, painter, foreground_color)
918        } else {
919            None
920        }
921    }
922
923    fn paint_v0(
924        &self,
925        base: BaseGlyphRecord,
926        palette: u16,
927        painter: &mut dyn Painter,
928        foreground_color: RgbaColor,
929    ) -> Option<()> {
930        let start = base.first_layer_index;
931        let end = start.checked_add(base.num_layers)?;
932        let layers = self.layers.slice(start..end)?;
933
934        for layer in layers {
935            if layer.palette_index == 0xFFFF {
936                // A special case.
937                painter.outline_glyph(layer.glyph_id);
938                painter.paint(Paint::Solid(foreground_color));
939            } else {
940                let color = self.palettes.get(palette, layer.palette_index)?;
941                painter.outline_glyph(layer.glyph_id);
942                painter.paint(Paint::Solid(color));
943            }
944        }
945
946        Some(())
947    }
948
949    fn paint_v1(
950        &self,
951        base: BaseGlyphPaintRecord,
952        palette: u16,
953        painter: &mut dyn Painter<'a>,
954        recursion_stack: &mut RecursionStack,
955        #[cfg(feature = "variable-fonts")] coords: &[NormalizedCoordinate],
956        foreground_color: RgbaColor,
957    ) -> Option<()> {
958        let clip_box = self.clip_list.find(
959            base.glyph_id,
960            #[cfg(feature = "variable-fonts")]
961            &self.variation_data(),
962            #[cfg(feature = "variable-fonts")]
963            coords,
964        );
965        if let Some(clip_box) = clip_box {
966            painter.push_clip_box(clip_box);
967        }
968
969        self.parse_paint(
970            self.base_glyph_paints_offset.to_usize() + base.paint_table_offset.to_usize(),
971            palette,
972            painter,
973            recursion_stack,
974            #[cfg(feature = "variable-fonts")]
975            coords,
976            foreground_color,
977        );
978
979        if clip_box.is_some() {
980            painter.pop_clip();
981        }
982
983        Some(())
984    }
985
986    fn parse_paint(
987        &self,
988        offset: usize,
989        palette: u16,
990        painter: &mut dyn Painter<'a>,
991        recursion_stack: &mut RecursionStack,
992        #[cfg(feature = "variable-fonts")] coords: &[NormalizedCoordinate],
993        foreground_color: RgbaColor,
994    ) -> Option<()> {
995        let mut s = Stream::new_at(self.data, offset)?;
996        let format = s.read::<u8>()?;
997
998        // Cycle detected
999        if recursion_stack.contains(offset) {
1000            return None;
1001        }
1002
1003        recursion_stack.push(offset).ok()?;
1004        let result = self.parse_paint_impl(
1005            offset,
1006            palette,
1007            painter,
1008            recursion_stack,
1009            &mut s,
1010            format,
1011            #[cfg(feature = "variable-fonts")]
1012            coords,
1013            foreground_color,
1014        );
1015        recursion_stack.pop();
1016
1017        result
1018    }
1019
1020    fn parse_paint_impl(
1021        &self,
1022        offset: usize,
1023        palette: u16,
1024        painter: &mut dyn Painter<'a>,
1025        recursion_stack: &mut RecursionStack,
1026        s: &mut Stream,
1027        format: u8,
1028        #[cfg(feature = "variable-fonts")] coords: &[NormalizedCoordinate],
1029        foreground_color: RgbaColor,
1030    ) -> Option<()> {
1031        match format {
1032            1 => {
1033                // PaintColrLayers
1034                let layers_count = s.read::<u8>()?;
1035                let first_layer_index = s.read::<u32>()?;
1036
1037                for i in 0..layers_count {
1038                    let index = first_layer_index.checked_add(u32::from(i))?;
1039                    let paint_offset = self.layer_paint_offsets.get(index)?;
1040                    self.parse_paint(
1041                        self.layer_paint_offsets_offset.to_usize() + paint_offset.to_usize(),
1042                        palette,
1043                        painter,
1044                        recursion_stack,
1045                        #[cfg(feature = "variable-fonts")]
1046                        coords,
1047                        foreground_color,
1048                    );
1049                }
1050            }
1051            2 => {
1052                // PaintSolid
1053                let palette_index = s.read::<u16>()?;
1054                let alpha = s.read::<F2DOT14>()?;
1055
1056                let mut color = if palette_index == u16::MAX {
1057                    foreground_color
1058                } else {
1059                    self.palettes.get(palette, palette_index)?
1060                };
1061
1062                color.apply_alpha(alpha.to_f32());
1063                painter.paint(Paint::Solid(color));
1064            }
1065            #[cfg(feature = "variable-fonts")]
1066            3 => {
1067                // PaintVarSolid
1068                let palette_index = s.read::<u16>()?;
1069                let alpha = s.read::<F2DOT14>()?;
1070                let var_index_base = s.read::<u32>()?;
1071
1072                let deltas = self
1073                    .variation_data()
1074                    .read_deltas::<1>(var_index_base, coords);
1075
1076                let mut color = if palette_index == u16::MAX {
1077                    foreground_color
1078                } else {
1079                    self.palettes.get(palette, palette_index)?
1080                };
1081
1082                color.apply_alpha(alpha.apply_float_delta(deltas[0]));
1083                painter.paint(Paint::Solid(color));
1084            }
1085            4 => {
1086                // PaintLinearGradient
1087                let color_line_offset = s.read::<Offset24>()?;
1088                let color_line =
1089                    self.parse_color_line(offset + color_line_offset.to_usize(), foreground_color)?;
1090
1091                painter.paint(Paint::LinearGradient(LinearGradient {
1092                    x0: s.read::<i16>()? as f32,
1093                    y0: s.read::<i16>()? as f32,
1094                    x1: s.read::<i16>()? as f32,
1095                    y1: s.read::<i16>()? as f32,
1096                    x2: s.read::<i16>()? as f32,
1097                    y2: s.read::<i16>()? as f32,
1098                    extend: color_line.extend,
1099                    #[cfg(feature = "variable-fonts")]
1100                    variation_data: self.variation_data(),
1101                    color_line: ColorLine::NonVarColorLine(color_line),
1102                }))
1103            }
1104            #[cfg(feature = "variable-fonts")]
1105            5 => {
1106                // PaintVarLinearGradient
1107                let var_color_line_offset = s.read::<Offset24>()?;
1108                let color_line = self.parse_var_color_line(
1109                    offset + var_color_line_offset.to_usize(),
1110                    foreground_color,
1111                )?;
1112                let mut var_s = s.clone();
1113                var_s.advance(12);
1114                let var_index_base = var_s.read::<u32>()?;
1115
1116                let deltas = self
1117                    .variation_data()
1118                    .read_deltas::<6>(var_index_base, coords);
1119
1120                painter.paint(Paint::LinearGradient(LinearGradient {
1121                    x0: s.read::<i16>()? as f32 + deltas[0],
1122                    y0: s.read::<i16>()? as f32 + deltas[1],
1123                    x1: s.read::<i16>()? as f32 + deltas[2],
1124                    y1: s.read::<i16>()? as f32 + deltas[3],
1125                    x2: s.read::<i16>()? as f32 + deltas[4],
1126                    y2: s.read::<i16>()? as f32 + deltas[5],
1127                    extend: color_line.extend,
1128                    variation_data: self.variation_data(),
1129                    color_line: ColorLine::VarColorLine(color_line),
1130                }))
1131            }
1132            6 => {
1133                // PaintRadialGradient
1134                let color_line_offset = s.read::<Offset24>()?;
1135                let color_line =
1136                    self.parse_color_line(offset + color_line_offset.to_usize(), foreground_color)?;
1137                painter.paint(Paint::RadialGradient(RadialGradient {
1138                    x0: s.read::<i16>()? as f32,
1139                    y0: s.read::<i16>()? as f32,
1140                    r0: s.read::<u16>()? as f32,
1141                    x1: s.read::<i16>()? as f32,
1142                    y1: s.read::<i16>()? as f32,
1143                    r1: s.read::<u16>()? as f32,
1144                    extend: color_line.extend,
1145                    #[cfg(feature = "variable-fonts")]
1146                    variation_data: self.variation_data(),
1147                    color_line: ColorLine::NonVarColorLine(color_line),
1148                }))
1149            }
1150            #[cfg(feature = "variable-fonts")]
1151            7 => {
1152                // PaintVarRadialGradient
1153                let color_line_offset = s.read::<Offset24>()?;
1154                let color_line = self.parse_var_color_line(
1155                    offset + color_line_offset.to_usize(),
1156                    foreground_color,
1157                )?;
1158
1159                let mut var_s = s.clone();
1160                var_s.advance(12);
1161                let var_index_base = var_s.read::<u32>()?;
1162
1163                let deltas = self
1164                    .variation_data()
1165                    .read_deltas::<6>(var_index_base, coords);
1166
1167                painter.paint(Paint::RadialGradient(RadialGradient {
1168                    x0: s.read::<i16>()? as f32 + deltas[0],
1169                    y0: s.read::<i16>()? as f32 + deltas[1],
1170                    r0: s.read::<u16>()? as f32 + deltas[2],
1171                    x1: s.read::<i16>()? as f32 + deltas[3],
1172                    y1: s.read::<i16>()? as f32 + deltas[4],
1173                    r1: s.read::<u16>()? as f32 + deltas[5],
1174                    extend: color_line.extend,
1175                    variation_data: self.variation_data(),
1176                    color_line: ColorLine::VarColorLine(color_line),
1177                }))
1178            }
1179            8 => {
1180                // PaintSweepGradient
1181                let color_line_offset = s.read::<Offset24>()?;
1182                let color_line =
1183                    self.parse_color_line(offset + color_line_offset.to_usize(), foreground_color)?;
1184                painter.paint(Paint::SweepGradient(SweepGradient {
1185                    center_x: s.read::<i16>()? as f32,
1186                    center_y: s.read::<i16>()? as f32,
1187                    start_angle: s.read::<F2DOT14>()?.to_f32(),
1188                    end_angle: s.read::<F2DOT14>()?.to_f32(),
1189                    extend: color_line.extend,
1190                    color_line: ColorLine::NonVarColorLine(color_line),
1191                    #[cfg(feature = "variable-fonts")]
1192                    variation_data: self.variation_data(),
1193                }))
1194            }
1195            #[cfg(feature = "variable-fonts")]
1196            9 => {
1197                // PaintVarSweepGradient
1198                let color_line_offset = s.read::<Offset24>()?;
1199                let color_line = self.parse_var_color_line(
1200                    offset + color_line_offset.to_usize(),
1201                    foreground_color,
1202                )?;
1203
1204                let mut var_s = s.clone();
1205                var_s.advance(8);
1206                let var_index_base = var_s.read::<u32>()?;
1207
1208                let deltas = self
1209                    .variation_data()
1210                    .read_deltas::<4>(var_index_base, coords);
1211
1212                painter.paint(Paint::SweepGradient(SweepGradient {
1213                    center_x: s.read::<i16>()? as f32 + deltas[0],
1214                    center_y: s.read::<i16>()? as f32 + deltas[1],
1215                    start_angle: s.read::<F2DOT14>()?.apply_float_delta(deltas[2]),
1216                    end_angle: s.read::<F2DOT14>()?.apply_float_delta(deltas[3]),
1217                    extend: color_line.extend,
1218                    color_line: ColorLine::VarColorLine(color_line),
1219                    variation_data: self.variation_data(),
1220                }))
1221            }
1222            10 => {
1223                // PaintGlyph
1224                let paint_offset = s.read::<Offset24>()?;
1225                let glyph_id = s.read::<GlyphId>()?;
1226                painter.outline_glyph(glyph_id);
1227                painter.push_clip();
1228
1229                self.parse_paint(
1230                    offset + paint_offset.to_usize(),
1231                    palette,
1232                    painter,
1233                    recursion_stack,
1234                    #[cfg(feature = "variable-fonts")]
1235                    coords,
1236                    foreground_color,
1237                );
1238
1239                painter.pop_clip();
1240            }
1241            11 => {
1242                // PaintColrGlyph
1243                let glyph_id = s.read::<GlyphId>()?;
1244                self.paint_impl(
1245                    glyph_id,
1246                    palette,
1247                    painter,
1248                    recursion_stack,
1249                    #[cfg(feature = "variable-fonts")]
1250                    coords,
1251                    foreground_color,
1252                );
1253            }
1254            12 => {
1255                // PaintTransform
1256                let paint_offset = s.read::<Offset24>()?;
1257                let ts_offset = s.read::<Offset24>()?;
1258                let mut s = Stream::new_at(self.data, offset + ts_offset.to_usize())?;
1259                let ts = Transform {
1260                    a: s.read::<Fixed>().map(|n| n.0)?,
1261                    b: s.read::<Fixed>().map(|n| n.0)?,
1262                    c: s.read::<Fixed>().map(|n| n.0)?,
1263                    d: s.read::<Fixed>().map(|n| n.0)?,
1264                    e: s.read::<Fixed>().map(|n| n.0)?,
1265                    f: s.read::<Fixed>().map(|n| n.0)?,
1266                };
1267
1268                painter.push_transform(ts);
1269                self.parse_paint(
1270                    offset + paint_offset.to_usize(),
1271                    palette,
1272                    painter,
1273                    recursion_stack,
1274                    #[cfg(feature = "variable-fonts")]
1275                    coords,
1276                    foreground_color,
1277                );
1278                painter.pop_transform();
1279            }
1280            #[cfg(feature = "variable-fonts")]
1281            13 => {
1282                // PaintVarTransform
1283                let paint_offset = s.read::<Offset24>()?;
1284                let ts_offset = s.read::<Offset24>()?;
1285                let mut s = Stream::new_at(self.data, offset + ts_offset.to_usize())?;
1286
1287                let mut var_s = s.clone();
1288                var_s.advance(24);
1289                let var_index_base = var_s.read::<u32>()?;
1290
1291                let deltas = self
1292                    .variation_data()
1293                    .read_deltas::<6>(var_index_base, coords);
1294
1295                let ts = Transform {
1296                    a: s.read::<Fixed>()?.apply_float_delta(deltas[0]),
1297                    b: s.read::<Fixed>()?.apply_float_delta(deltas[1]),
1298                    c: s.read::<Fixed>()?.apply_float_delta(deltas[2]),
1299                    d: s.read::<Fixed>()?.apply_float_delta(deltas[3]),
1300                    e: s.read::<Fixed>()?.apply_float_delta(deltas[4]),
1301                    f: s.read::<Fixed>()?.apply_float_delta(deltas[5]),
1302                };
1303
1304                painter.push_transform(ts);
1305                self.parse_paint(
1306                    offset + paint_offset.to_usize(),
1307                    palette,
1308                    painter,
1309                    recursion_stack,
1310                    coords,
1311                    foreground_color,
1312                );
1313                painter.pop_transform();
1314            }
1315            14 => {
1316                // PaintTranslate
1317                let paint_offset = s.read::<Offset24>()?;
1318                let tx = f32::from(s.read::<i16>()?);
1319                let ty = f32::from(s.read::<i16>()?);
1320
1321                painter.push_translate(tx, ty);
1322                self.parse_paint(
1323                    offset + paint_offset.to_usize(),
1324                    palette,
1325                    painter,
1326                    recursion_stack,
1327                    #[cfg(feature = "variable-fonts")]
1328                    coords,
1329                    foreground_color,
1330                );
1331                painter.pop_transform();
1332            }
1333            #[cfg(feature = "variable-fonts")]
1334            15 => {
1335                // PaintVarTranslate
1336                let paint_offset = s.read::<Offset24>()?;
1337
1338                let mut var_s = s.clone();
1339                var_s.advance(4);
1340                let var_index_base = var_s.read::<u32>()?;
1341
1342                let deltas = self
1343                    .variation_data()
1344                    .read_deltas::<2>(var_index_base, coords);
1345
1346                let tx = f32::from(s.read::<i16>()?) + deltas[0];
1347                let ty = f32::from(s.read::<i16>()?) + deltas[1];
1348
1349                painter.push_translate(tx, ty);
1350                self.parse_paint(
1351                    offset + paint_offset.to_usize(),
1352                    palette,
1353                    painter,
1354                    recursion_stack,
1355                    coords,
1356                    foreground_color,
1357                );
1358                painter.pop_transform();
1359            }
1360            16 => {
1361                // PaintScale
1362                let paint_offset = s.read::<Offset24>()?;
1363                let sx = s.read::<F2DOT14>()?.to_f32();
1364                let sy = s.read::<F2DOT14>()?.to_f32();
1365
1366                painter.push_scale(sx, sy);
1367                self.parse_paint(
1368                    offset + paint_offset.to_usize(),
1369                    palette,
1370                    painter,
1371                    recursion_stack,
1372                    #[cfg(feature = "variable-fonts")]
1373                    coords,
1374                    foreground_color,
1375                );
1376                painter.pop_transform();
1377            }
1378            #[cfg(feature = "variable-fonts")]
1379            17 => {
1380                // PaintVarScale
1381                let paint_offset = s.read::<Offset24>()?;
1382
1383                let mut var_s = s.clone();
1384                var_s.advance(4);
1385                let var_index_base = var_s.read::<u32>()?;
1386
1387                let deltas = self
1388                    .variation_data()
1389                    .read_deltas::<2>(var_index_base, coords);
1390
1391                let sx = s.read::<F2DOT14>()?.apply_float_delta(deltas[0]);
1392                let sy = s.read::<F2DOT14>()?.apply_float_delta(deltas[1]);
1393
1394                painter.push_scale(sx, sy);
1395                self.parse_paint(
1396                    offset + paint_offset.to_usize(),
1397                    palette,
1398                    painter,
1399                    recursion_stack,
1400                    coords,
1401                    foreground_color,
1402                );
1403                painter.pop_transform();
1404            }
1405            18 => {
1406                // PaintScaleAroundCenter
1407                let paint_offset = s.read::<Offset24>()?;
1408                let sx = s.read::<F2DOT14>()?.to_f32();
1409                let sy = s.read::<F2DOT14>()?.to_f32();
1410                let center_x = f32::from(s.read::<i16>()?);
1411                let center_y = f32::from(s.read::<i16>()?);
1412
1413                painter.push_translate(center_x, center_y);
1414                painter.push_scale(sx, sy);
1415                painter.push_translate(-center_x, -center_y);
1416                self.parse_paint(
1417                    offset + paint_offset.to_usize(),
1418                    palette,
1419                    painter,
1420                    recursion_stack,
1421                    #[cfg(feature = "variable-fonts")]
1422                    coords,
1423                    foreground_color,
1424                );
1425                painter.pop_transform();
1426                painter.pop_transform();
1427                painter.pop_transform();
1428            }
1429            #[cfg(feature = "variable-fonts")]
1430            19 => {
1431                // PaintVarScaleAroundCenter
1432                let paint_offset = s.read::<Offset24>()?;
1433
1434                let mut var_s = s.clone();
1435                var_s.advance(8);
1436                let var_index_base = var_s.read::<u32>()?;
1437
1438                let deltas = self
1439                    .variation_data()
1440                    .read_deltas::<4>(var_index_base, coords);
1441
1442                let sx = s.read::<F2DOT14>()?.apply_float_delta(deltas[0]);
1443                let sy = s.read::<F2DOT14>()?.apply_float_delta(deltas[1]);
1444                let center_x = f32::from(s.read::<i16>()?) + deltas[2];
1445                let center_y = f32::from(s.read::<i16>()?) + deltas[3];
1446
1447                painter.push_translate(center_x, center_y);
1448                painter.push_scale(sx, sy);
1449                painter.push_translate(-center_x, -center_y);
1450                self.parse_paint(
1451                    offset + paint_offset.to_usize(),
1452                    palette,
1453                    painter,
1454                    recursion_stack,
1455                    coords,
1456                    foreground_color,
1457                );
1458                painter.pop_transform();
1459                painter.pop_transform();
1460                painter.pop_transform();
1461            }
1462            20 => {
1463                // PaintScaleUniform
1464                let paint_offset = s.read::<Offset24>()?;
1465                let scale = s.read::<F2DOT14>()?.to_f32();
1466
1467                painter.push_scale(scale, scale);
1468                self.parse_paint(
1469                    offset + paint_offset.to_usize(),
1470                    palette,
1471                    painter,
1472                    recursion_stack,
1473                    #[cfg(feature = "variable-fonts")]
1474                    coords,
1475                    foreground_color,
1476                );
1477                painter.pop_transform();
1478            }
1479            #[cfg(feature = "variable-fonts")]
1480            21 => {
1481                // PaintVarScaleUniform
1482                let paint_offset = s.read::<Offset24>()?;
1483
1484                let mut var_s = s.clone();
1485                var_s.advance(2);
1486                let var_index_base = var_s.read::<u32>()?;
1487
1488                let deltas = self
1489                    .variation_data()
1490                    .read_deltas::<1>(var_index_base, coords);
1491
1492                let scale = s.read::<F2DOT14>()?.apply_float_delta(deltas[0]);
1493
1494                painter.push_scale(scale, scale);
1495                self.parse_paint(
1496                    offset + paint_offset.to_usize(),
1497                    palette,
1498                    painter,
1499                    recursion_stack,
1500                    coords,
1501                    foreground_color,
1502                );
1503                painter.pop_transform();
1504            }
1505            22 => {
1506                // PaintScaleUniformAroundCenter
1507                let paint_offset = s.read::<Offset24>()?;
1508                let scale = s.read::<F2DOT14>()?.to_f32();
1509                let center_x = f32::from(s.read::<i16>()?);
1510                let center_y = f32::from(s.read::<i16>()?);
1511
1512                painter.push_translate(center_x, center_y);
1513                painter.push_scale(scale, scale);
1514                painter.push_translate(-center_x, -center_y);
1515                self.parse_paint(
1516                    offset + paint_offset.to_usize(),
1517                    palette,
1518                    painter,
1519                    recursion_stack,
1520                    #[cfg(feature = "variable-fonts")]
1521                    coords,
1522                    foreground_color,
1523                );
1524                painter.pop_transform();
1525                painter.pop_transform();
1526                painter.pop_transform();
1527            }
1528            #[cfg(feature = "variable-fonts")]
1529            23 => {
1530                // PaintVarScaleUniformAroundCenter
1531                let paint_offset = s.read::<Offset24>()?;
1532
1533                let mut var_s = s.clone();
1534                var_s.advance(6);
1535                let var_index_base = var_s.read::<u32>()?;
1536
1537                let deltas = self
1538                    .variation_data()
1539                    .read_deltas::<3>(var_index_base, coords);
1540
1541                let scale = s.read::<F2DOT14>()?.apply_float_delta(deltas[0]);
1542                let center_x = f32::from(s.read::<i16>()?) + deltas[1];
1543                let center_y = f32::from(s.read::<i16>()?) + deltas[2];
1544
1545                painter.push_translate(center_x, center_y);
1546                painter.push_scale(scale, scale);
1547                painter.push_translate(-center_x, -center_y);
1548                self.parse_paint(
1549                    offset + paint_offset.to_usize(),
1550                    palette,
1551                    painter,
1552                    recursion_stack,
1553                    coords,
1554                    foreground_color,
1555                );
1556                painter.pop_transform();
1557                painter.pop_transform();
1558                painter.pop_transform();
1559            }
1560            24 => {
1561                // PaintRotate
1562                let paint_offset = s.read::<Offset24>()?;
1563                let angle = s.read::<F2DOT14>()?.to_f32();
1564
1565                painter.push_rotate(angle);
1566                self.parse_paint(
1567                    offset + paint_offset.to_usize(),
1568                    palette,
1569                    painter,
1570                    recursion_stack,
1571                    #[cfg(feature = "variable-fonts")]
1572                    coords,
1573                    foreground_color,
1574                );
1575                painter.pop_transform();
1576            }
1577            #[cfg(feature = "variable-fonts")]
1578            25 => {
1579                // PaintVarRotate
1580                let paint_offset = s.read::<Offset24>()?;
1581
1582                let mut var_s = s.clone();
1583                var_s.advance(2);
1584                let var_index_base = var_s.read::<u32>()?;
1585
1586                let deltas = self
1587                    .variation_data()
1588                    .read_deltas::<1>(var_index_base, coords);
1589
1590                let angle = s.read::<F2DOT14>()?.apply_float_delta(deltas[0]);
1591
1592                painter.push_rotate(angle);
1593                self.parse_paint(
1594                    offset + paint_offset.to_usize(),
1595                    palette,
1596                    painter,
1597                    recursion_stack,
1598                    coords,
1599                    foreground_color,
1600                );
1601                painter.pop_transform();
1602            }
1603            26 => {
1604                // PaintRotateAroundCenter
1605                let paint_offset = s.read::<Offset24>()?;
1606                let angle = s.read::<F2DOT14>()?.to_f32();
1607                let center_x = f32::from(s.read::<i16>()?);
1608                let center_y = f32::from(s.read::<i16>()?);
1609
1610                painter.push_translate(center_x, center_y);
1611                painter.push_rotate(angle);
1612                painter.push_translate(-center_x, -center_y);
1613                self.parse_paint(
1614                    offset + paint_offset.to_usize(),
1615                    palette,
1616                    painter,
1617                    recursion_stack,
1618                    #[cfg(feature = "variable-fonts")]
1619                    coords,
1620                    foreground_color,
1621                );
1622                painter.pop_transform();
1623                painter.pop_transform();
1624                painter.pop_transform();
1625            }
1626            #[cfg(feature = "variable-fonts")]
1627            27 => {
1628                // PaintVarRotateAroundCenter
1629                let paint_offset = s.read::<Offset24>()?;
1630
1631                let mut var_s = s.clone();
1632                var_s.advance(6);
1633                let var_index_base = var_s.read::<u32>()?;
1634
1635                let deltas = self
1636                    .variation_data()
1637                    .read_deltas::<3>(var_index_base, coords);
1638
1639                let angle = s.read::<F2DOT14>()?.apply_float_delta(deltas[0]);
1640                let center_x = f32::from(s.read::<i16>()?) + deltas[1];
1641                let center_y = f32::from(s.read::<i16>()?) + deltas[2];
1642
1643                painter.push_translate(center_x, center_y);
1644                painter.push_rotate(angle);
1645                painter.push_translate(-center_x, -center_y);
1646                self.parse_paint(
1647                    offset + paint_offset.to_usize(),
1648                    palette,
1649                    painter,
1650                    recursion_stack,
1651                    coords,
1652                    foreground_color,
1653                );
1654                painter.pop_transform();
1655                painter.pop_transform();
1656                painter.pop_transform();
1657            }
1658            28 => {
1659                // PaintSkew
1660                let paint_offset = s.read::<Offset24>()?;
1661                let skew_x = s.read::<F2DOT14>()?.to_f32();
1662                let skew_y = s.read::<F2DOT14>()?.to_f32();
1663
1664                painter.push_skew(skew_x, skew_y);
1665                self.parse_paint(
1666                    offset + paint_offset.to_usize(),
1667                    palette,
1668                    painter,
1669                    recursion_stack,
1670                    #[cfg(feature = "variable-fonts")]
1671                    coords,
1672                    foreground_color,
1673                );
1674                painter.pop_transform();
1675            }
1676            #[cfg(feature = "variable-fonts")]
1677            29 => {
1678                // PaintVarSkew
1679                let paint_offset = s.read::<Offset24>()?;
1680
1681                let mut var_s = s.clone();
1682                var_s.advance(4);
1683                let var_index_base = var_s.read::<u32>()?;
1684
1685                let deltas = self
1686                    .variation_data()
1687                    .read_deltas::<2>(var_index_base, coords);
1688
1689                let skew_x = s.read::<F2DOT14>()?.apply_float_delta(deltas[0]);
1690                let skew_y = s.read::<F2DOT14>()?.apply_float_delta(deltas[1]);
1691
1692                painter.push_skew(skew_x, skew_y);
1693                self.parse_paint(
1694                    offset + paint_offset.to_usize(),
1695                    palette,
1696                    painter,
1697                    recursion_stack,
1698                    coords,
1699                    foreground_color,
1700                );
1701                painter.pop_transform();
1702            }
1703            30 => {
1704                // PaintSkewAroundCenter
1705                let paint_offset = s.read::<Offset24>()?;
1706                let skew_x = s.read::<F2DOT14>()?.to_f32();
1707                let skew_y = s.read::<F2DOT14>()?.to_f32();
1708                let center_x = f32::from(s.read::<i16>()?);
1709                let center_y = f32::from(s.read::<i16>()?);
1710
1711                painter.push_translate(center_x, center_y);
1712                painter.push_skew(skew_x, skew_y);
1713                painter.push_translate(-center_x, -center_y);
1714                self.parse_paint(
1715                    offset + paint_offset.to_usize(),
1716                    palette,
1717                    painter,
1718                    recursion_stack,
1719                    #[cfg(feature = "variable-fonts")]
1720                    coords,
1721                    foreground_color,
1722                );
1723                painter.pop_transform();
1724                painter.pop_transform();
1725                painter.pop_transform();
1726            }
1727            #[cfg(feature = "variable-fonts")]
1728            31 => {
1729                // PaintVarSkewAroundCenter
1730                let paint_offset = s.read::<Offset24>()?;
1731
1732                let mut var_s = s.clone();
1733                var_s.advance(8);
1734                let var_index_base = var_s.read::<u32>()?;
1735
1736                let deltas = self
1737                    .variation_data()
1738                    .read_deltas::<4>(var_index_base, coords);
1739
1740                let skew_x = s.read::<F2DOT14>()?.apply_float_delta(deltas[0]);
1741                let skew_y = s.read::<F2DOT14>()?.apply_float_delta(deltas[1]);
1742                let center_x = f32::from(s.read::<i16>()?) + deltas[2];
1743                let center_y = f32::from(s.read::<i16>()?) + deltas[3];
1744
1745                painter.push_translate(center_x, center_y);
1746                painter.push_skew(skew_x, skew_y);
1747                painter.push_translate(-center_x, -center_y);
1748                self.parse_paint(
1749                    offset + paint_offset.to_usize(),
1750                    palette,
1751                    painter,
1752                    recursion_stack,
1753                    coords,
1754                    foreground_color,
1755                );
1756                painter.pop_transform();
1757                painter.pop_transform();
1758                painter.pop_transform();
1759            }
1760            32 => {
1761                // PaintComposite
1762                let source_paint_offset = s.read::<Offset24>()?;
1763                let composite_mode = s.read::<CompositeMode>()?;
1764                let backdrop_paint_offset = s.read::<Offset24>()?;
1765
1766                painter.push_layer(CompositeMode::SourceOver);
1767                self.parse_paint(
1768                    offset + backdrop_paint_offset.to_usize(),
1769                    palette,
1770                    painter,
1771                    recursion_stack,
1772                    #[cfg(feature = "variable-fonts")]
1773                    coords,
1774                    foreground_color,
1775                );
1776                painter.push_layer(composite_mode);
1777                self.parse_paint(
1778                    offset + source_paint_offset.to_usize(),
1779                    palette,
1780                    painter,
1781                    recursion_stack,
1782                    #[cfg(feature = "variable-fonts")]
1783                    coords,
1784                    foreground_color,
1785                );
1786                painter.pop_layer();
1787                painter.pop_layer();
1788            }
1789            _ => {}
1790        }
1791
1792        Some(())
1793    }
1794
1795    fn parse_color_line(
1796        &self,
1797        offset: usize,
1798        foreground_color: RgbaColor,
1799    ) -> Option<NonVarColorLine<'a>> {
1800        let mut s = Stream::new_at(self.data, offset)?;
1801        let extend = s.read::<GradientExtend>()?;
1802        let count = s.read::<u16>()?;
1803        let colors = s.read_array16::<ColorStopRaw>(count)?;
1804        Some(NonVarColorLine {
1805            extend,
1806            colors,
1807            foreground_color,
1808            palettes: self.palettes,
1809        })
1810    }
1811
1812    #[cfg(feature = "variable-fonts")]
1813    fn parse_var_color_line(
1814        &self,
1815        offset: usize,
1816        foreground_color: RgbaColor,
1817    ) -> Option<VarColorLine<'a>> {
1818        let mut s = Stream::new_at(self.data, offset)?;
1819        let extend = s.read::<GradientExtend>()?;
1820        let count = s.read::<u16>()?;
1821        let colors = s.read_array16::<VarColorStopRaw>(count)?;
1822        Some(VarColorLine {
1823            extend,
1824            colors,
1825            foreground_color,
1826            palettes: self.palettes,
1827        })
1828    }
1829}
1830
1831struct RecursionStack {
1832    // The limit of 64 is chosen arbitrarily and not from the spec. But we have to stop somewhere...
1833    stack: [usize; 64],
1834    len: usize,
1835}
1836
1837impl RecursionStack {
1838    #[inline]
1839    pub fn is_empty(&self) -> bool {
1840        self.len == 0
1841    }
1842
1843    #[inline]
1844    pub fn push(&mut self, offset: usize) -> Result<(), ()> {
1845        if self.len == self.stack.len() {
1846            Err(())
1847        } else {
1848            self.stack[self.len] = offset;
1849            self.len += 1;
1850            Ok(())
1851        }
1852    }
1853
1854    #[inline]
1855    pub fn contains(&self, offset: usize) -> bool {
1856        if let Some(offsets) = self.stack.get(..self.len) {
1857            return offsets.contains(&offset);
1858        }
1859
1860        false
1861    }
1862
1863    #[inline]
1864    pub fn pop(&mut self) {
1865        debug_assert!(!self.is_empty());
1866        self.len -= 1;
1867    }
1868}
1869
1870#[cfg(feature = "variable-fonts")]
1871#[derive(Clone, Copy, Debug, Default)]
1872struct VariationData<'a> {
1873    variation_store: Option<ItemVariationStore<'a>>,
1874    delta_map: Option<DeltaSetIndexMap<'a>>,
1875}
1876
1877#[cfg(feature = "variable-fonts")]
1878impl VariationData<'_> {
1879    // Inspired from `fontations`.
1880    fn read_deltas<const N: usize>(
1881        &self,
1882        var_index_base: u32,
1883        coordinates: &[NormalizedCoordinate],
1884    ) -> [f32; N] {
1885        const NO_VARIATION_DELTAS: u32 = 0xFFFFFFFF;
1886        let mut deltas = [0.0; N];
1887
1888        if coordinates.is_empty()
1889            || self.variation_store.is_none()
1890            || var_index_base == NO_VARIATION_DELTAS
1891        {
1892            return deltas;
1893        }
1894
1895        let variation_store = self.variation_store.as_ref().unwrap();
1896
1897        for i in 0..N {
1898            deltas[i] = self
1899                .delta_map
1900                .and_then(|d| d.map(var_index_base + i as u32))
1901                .and_then(|d| variation_store.parse_delta(d.0, d.1, coordinates))
1902                .unwrap_or(0.0);
1903        }
1904
1905        deltas
1906    }
1907}