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    /// Push a transform.
698    fn push_transform(&mut self, transform: Transform);
699    /// Pop the last transform.
700    fn pop_transform(&mut self);
701}
702
703/// A [Color Table](
704/// https://docs.microsoft.com/en-us/typography/opentype/spec/colr).
705///
706/// Currently, only version 0 is supported.
707#[derive(Clone, Copy, Debug)]
708pub struct Table<'a> {
709    pub(crate) palettes: cpal::Table<'a>,
710    data: &'a [u8],
711    version: u8,
712    // v0
713    base_glyphs: LazyArray16<'a, BaseGlyphRecord>,
714    layers: LazyArray16<'a, LayerRecord>,
715    // v1
716    base_glyph_paints_offset: Offset32,
717    base_glyph_paints: LazyArray32<'a, BaseGlyphPaintRecord>,
718    layer_paint_offsets_offset: Offset32,
719    layer_paint_offsets: LazyArray32<'a, Offset32>,
720    clip_list_offsets_offset: Offset32,
721    clip_list: ClipList<'a>,
722    #[cfg(feature = "variable-fonts")]
723    var_index_map: Option<DeltaSetIndexMap<'a>>,
724    #[cfg(feature = "variable-fonts")]
725    item_variation_store: Option<ItemVariationStore<'a>>,
726}
727
728impl<'a> Table<'a> {
729    /// Parses a table from raw data.
730    pub fn parse(palettes: cpal::Table<'a>, data: &'a [u8]) -> Option<Self> {
731        let mut s = Stream::new(data);
732
733        let version = s.read::<u16>()?;
734        if version > 1 {
735            return None;
736        }
737
738        let num_base_glyphs = s.read::<u16>()?;
739        let base_glyphs_offset = s.read::<Offset32>()?;
740        let layers_offset = s.read::<Offset32>()?;
741        let num_layers = s.read::<u16>()?;
742
743        let base_glyphs = Stream::new_at(data, base_glyphs_offset.to_usize())?
744            .read_array16::<BaseGlyphRecord>(num_base_glyphs)?;
745
746        let layers = Stream::new_at(data, layers_offset.to_usize())?
747            .read_array16::<LayerRecord>(num_layers)?;
748
749        let mut table = Self {
750            version: version as u8,
751            data,
752            palettes,
753            base_glyphs,
754            layers,
755            base_glyph_paints_offset: Offset32(0), // the actual value doesn't matter
756            base_glyph_paints: LazyArray32::default(),
757            layer_paint_offsets_offset: Offset32(0),
758            layer_paint_offsets: LazyArray32::default(),
759            clip_list_offsets_offset: Offset32(0),
760            clip_list: ClipList::default(),
761            #[cfg(feature = "variable-fonts")]
762            item_variation_store: None,
763            #[cfg(feature = "variable-fonts")]
764            var_index_map: None,
765        };
766
767        if version == 0 {
768            return Some(table);
769        }
770
771        table.base_glyph_paints_offset = s.read::<Offset32>()?;
772        let layer_list_offset = s.read::<Option<Offset32>>()?;
773        let clip_list_offset = s.read::<Option<Offset32>>()?;
774        #[cfg(feature = "variable-fonts")]
775        let var_index_map_offset = s.read::<Option<Offset32>>()?;
776        #[cfg(feature = "variable-fonts")]
777        let item_variation_offset = s.read::<Option<Offset32>>()?;
778
779        {
780            let mut s = Stream::new_at(data, table.base_glyph_paints_offset.to_usize())?;
781            let count = s.read::<u32>()?;
782            table.base_glyph_paints = s.read_array32::<BaseGlyphPaintRecord>(count)?;
783        }
784
785        if let Some(offset) = layer_list_offset {
786            table.layer_paint_offsets_offset = offset;
787            let mut s = Stream::new_at(data, offset.to_usize())?;
788            let count = s.read::<u32>()?;
789            table.layer_paint_offsets = s.read_array32::<Offset32>(count)?;
790        }
791
792        if let Some(offset) = clip_list_offset {
793            table.clip_list_offsets_offset = offset;
794            let clip_data = data.get(offset.to_usize()..)?;
795            let mut s = Stream::new(clip_data);
796            s.skip::<u8>(); // Format
797            let count = s.read::<u32>()?;
798            table.clip_list = ClipList {
799                data: clip_data,
800                records: s.read_array32::<ClipRecord>(count)?,
801            };
802        }
803
804        #[cfg(feature = "variable-fonts")]
805        {
806            if let Some(offset) = item_variation_offset {
807                let item_var_data = data.get(offset.to_usize()..)?;
808                let s = Stream::new(item_var_data);
809                let var_store = ItemVariationStore::parse(s)?;
810                table.item_variation_store = Some(var_store);
811            }
812        }
813
814        #[cfg(feature = "variable-fonts")]
815        {
816            if let Some(offset) = var_index_map_offset {
817                let var_index_map_data = data.get(offset.to_usize()..)?;
818                let var_index_map = DeltaSetIndexMap::new(var_index_map_data);
819                table.var_index_map = Some(var_index_map);
820            }
821        }
822
823        Some(table)
824    }
825
826    /// Returns `true` if the current table has version 0.
827    ///
828    /// A simple table can only emit `outline_glyph` and `paint`
829    /// [`Painter`] methods.
830    pub fn is_simple(&self) -> bool {
831        self.version == 0
832    }
833
834    fn get_v0(&self, glyph_id: GlyphId) -> Option<BaseGlyphRecord> {
835        self.base_glyphs
836            .binary_search_by(|base| base.glyph_id.cmp(&glyph_id))
837            .map(|v| v.1)
838    }
839
840    fn get_v1(&self, glyph_id: GlyphId) -> Option<BaseGlyphPaintRecord> {
841        self.base_glyph_paints
842            .binary_search_by(|base| base.glyph_id.cmp(&glyph_id))
843            .map(|v| v.1)
844    }
845
846    #[cfg(feature = "variable-fonts")]
847    fn variation_data(&self) -> VariationData<'a> {
848        VariationData {
849            variation_store: self.item_variation_store,
850            delta_map: self.var_index_map,
851        }
852    }
853
854    /// Whether the table contains a definition for the given glyph.
855    pub fn contains(&self, glyph_id: GlyphId) -> bool {
856        self.get_v1(glyph_id).is_some() || self.get_v0(glyph_id).is_some()
857    }
858
859    /// Returns the clip box for a glyph.
860    pub fn clip_box(
861        &self,
862        glyph_id: GlyphId,
863        #[cfg(feature = "variable-fonts")] coords: &[NormalizedCoordinate],
864    ) -> Option<ClipBox> {
865        self.clip_list.find(
866            glyph_id,
867            #[cfg(feature = "variable-fonts")]
868            &self.variation_data(),
869            #[cfg(feature = "variable-fonts")]
870            coords,
871        )
872    }
873
874    // This method should only be called from outside, not from within `colr.rs`.
875    // From inside, you always should call paint_impl, so that the recursion stack can
876    // be passed on and any kind of recursion can be prevented.
877    /// Paints the color glyph.
878    pub fn paint(
879        &self,
880        glyph_id: GlyphId,
881        palette: u16,
882        painter: &mut dyn Painter<'a>,
883        #[cfg(feature = "variable-fonts")] coords: &[NormalizedCoordinate],
884        foreground_color: RgbaColor,
885    ) -> Option<()> {
886        let mut recursion_stack = RecursionStack {
887            stack: [0; 64],
888            len: 0,
889        };
890
891        self.paint_impl(
892            glyph_id,
893            palette,
894            painter,
895            &mut recursion_stack,
896            #[cfg(feature = "variable-fonts")]
897            coords,
898            foreground_color,
899        )
900    }
901
902    fn paint_impl(
903        &self,
904        glyph_id: GlyphId,
905        palette: u16,
906        painter: &mut dyn Painter<'a>,
907        recursion_stack: &mut RecursionStack,
908        #[cfg(feature = "variable-fonts")] coords: &[NormalizedCoordinate],
909        foreground_color: RgbaColor,
910    ) -> Option<()> {
911        if let Some(base) = self.get_v1(glyph_id) {
912            self.paint_v1(
913                base,
914                palette,
915                painter,
916                recursion_stack,
917                #[cfg(feature = "variable-fonts")]
918                coords,
919                foreground_color,
920            )
921        } else if let Some(base) = self.get_v0(glyph_id) {
922            self.paint_v0(base, palette, painter, foreground_color)
923        } else {
924            None
925        }
926    }
927
928    fn paint_v0(
929        &self,
930        base: BaseGlyphRecord,
931        palette: u16,
932        painter: &mut dyn Painter,
933        foreground_color: RgbaColor,
934    ) -> Option<()> {
935        let start = base.first_layer_index;
936        let end = start.checked_add(base.num_layers)?;
937        let layers = self.layers.slice(start..end)?;
938
939        for layer in layers {
940            if layer.palette_index == 0xFFFF {
941                // A special case.
942                painter.outline_glyph(layer.glyph_id);
943                painter.paint(Paint::Solid(foreground_color));
944            } else {
945                let color = self.palettes.get(palette, layer.palette_index)?;
946                painter.outline_glyph(layer.glyph_id);
947                painter.paint(Paint::Solid(color));
948            }
949        }
950
951        Some(())
952    }
953
954    fn paint_v1(
955        &self,
956        base: BaseGlyphPaintRecord,
957        palette: u16,
958        painter: &mut dyn Painter<'a>,
959        recursion_stack: &mut RecursionStack,
960        #[cfg(feature = "variable-fonts")] coords: &[NormalizedCoordinate],
961        foreground_color: RgbaColor,
962    ) -> Option<()> {
963        let clip_box = self.clip_box(
964            base.glyph_id,
965            #[cfg(feature = "variable-fonts")]
966            coords,
967        );
968        if let Some(clip_box) = clip_box {
969            painter.push_clip_box(clip_box);
970        }
971
972        self.parse_paint(
973            self.base_glyph_paints_offset.to_usize() + base.paint_table_offset.to_usize(),
974            palette,
975            painter,
976            recursion_stack,
977            #[cfg(feature = "variable-fonts")]
978            coords,
979            foreground_color,
980        );
981
982        if clip_box.is_some() {
983            painter.pop_clip();
984        }
985
986        Some(())
987    }
988
989    fn parse_paint(
990        &self,
991        offset: usize,
992        palette: u16,
993        painter: &mut dyn Painter<'a>,
994        recursion_stack: &mut RecursionStack,
995        #[cfg(feature = "variable-fonts")] coords: &[NormalizedCoordinate],
996        foreground_color: RgbaColor,
997    ) -> Option<()> {
998        let mut s = Stream::new_at(self.data, offset)?;
999        let format = s.read::<u8>()?;
1000
1001        // Cycle detected
1002        if recursion_stack.contains(offset) {
1003            return None;
1004        }
1005
1006        recursion_stack.push(offset).ok()?;
1007        let result = self.parse_paint_impl(
1008            offset,
1009            palette,
1010            painter,
1011            recursion_stack,
1012            &mut s,
1013            format,
1014            #[cfg(feature = "variable-fonts")]
1015            coords,
1016            foreground_color,
1017        );
1018        recursion_stack.pop();
1019
1020        result
1021    }
1022
1023    fn parse_paint_impl(
1024        &self,
1025        offset: usize,
1026        palette: u16,
1027        painter: &mut dyn Painter<'a>,
1028        recursion_stack: &mut RecursionStack,
1029        s: &mut Stream,
1030        format: u8,
1031        #[cfg(feature = "variable-fonts")] coords: &[NormalizedCoordinate],
1032        foreground_color: RgbaColor,
1033    ) -> Option<()> {
1034        match format {
1035            1 => {
1036                // PaintColrLayers
1037                let layers_count = s.read::<u8>()?;
1038                let first_layer_index = s.read::<u32>()?;
1039
1040                for i in 0..layers_count {
1041                    let index = first_layer_index.checked_add(u32::from(i))?;
1042                    let paint_offset = self.layer_paint_offsets.get(index)?;
1043                    self.parse_paint(
1044                        self.layer_paint_offsets_offset.to_usize() + paint_offset.to_usize(),
1045                        palette,
1046                        painter,
1047                        recursion_stack,
1048                        #[cfg(feature = "variable-fonts")]
1049                        coords,
1050                        foreground_color,
1051                    );
1052                }
1053            }
1054            2 => {
1055                // PaintSolid
1056                let palette_index = s.read::<u16>()?;
1057                let alpha = s.read::<F2DOT14>()?;
1058
1059                let mut color = if palette_index == u16::MAX {
1060                    foreground_color
1061                } else {
1062                    self.palettes.get(palette, palette_index)?
1063                };
1064
1065                color.apply_alpha(alpha.to_f32());
1066                painter.paint(Paint::Solid(color));
1067            }
1068            #[cfg(feature = "variable-fonts")]
1069            3 => {
1070                // PaintVarSolid
1071                let palette_index = s.read::<u16>()?;
1072                let alpha = s.read::<F2DOT14>()?;
1073                let var_index_base = s.read::<u32>()?;
1074
1075                let deltas = self
1076                    .variation_data()
1077                    .read_deltas::<1>(var_index_base, coords);
1078
1079                let mut color = if palette_index == u16::MAX {
1080                    foreground_color
1081                } else {
1082                    self.palettes.get(palette, palette_index)?
1083                };
1084
1085                color.apply_alpha(alpha.apply_float_delta(deltas[0]));
1086                painter.paint(Paint::Solid(color));
1087            }
1088            4 => {
1089                // PaintLinearGradient
1090                let color_line_offset = s.read::<Offset24>()?;
1091                let color_line =
1092                    self.parse_color_line(offset + color_line_offset.to_usize(), foreground_color)?;
1093
1094                painter.paint(Paint::LinearGradient(LinearGradient {
1095                    x0: s.read::<i16>()? as f32,
1096                    y0: s.read::<i16>()? as f32,
1097                    x1: s.read::<i16>()? as f32,
1098                    y1: s.read::<i16>()? as f32,
1099                    x2: s.read::<i16>()? as f32,
1100                    y2: s.read::<i16>()? as f32,
1101                    extend: color_line.extend,
1102                    #[cfg(feature = "variable-fonts")]
1103                    variation_data: self.variation_data(),
1104                    color_line: ColorLine::NonVarColorLine(color_line),
1105                }))
1106            }
1107            #[cfg(feature = "variable-fonts")]
1108            5 => {
1109                // PaintVarLinearGradient
1110                let var_color_line_offset = s.read::<Offset24>()?;
1111                let color_line = self.parse_var_color_line(
1112                    offset + var_color_line_offset.to_usize(),
1113                    foreground_color,
1114                )?;
1115                let mut var_s = s.clone();
1116                var_s.advance(12);
1117                let var_index_base = var_s.read::<u32>()?;
1118
1119                let deltas = self
1120                    .variation_data()
1121                    .read_deltas::<6>(var_index_base, coords);
1122
1123                painter.paint(Paint::LinearGradient(LinearGradient {
1124                    x0: s.read::<i16>()? as f32 + deltas[0],
1125                    y0: s.read::<i16>()? as f32 + deltas[1],
1126                    x1: s.read::<i16>()? as f32 + deltas[2],
1127                    y1: s.read::<i16>()? as f32 + deltas[3],
1128                    x2: s.read::<i16>()? as f32 + deltas[4],
1129                    y2: s.read::<i16>()? as f32 + deltas[5],
1130                    extend: color_line.extend,
1131                    variation_data: self.variation_data(),
1132                    color_line: ColorLine::VarColorLine(color_line),
1133                }))
1134            }
1135            6 => {
1136                // PaintRadialGradient
1137                let color_line_offset = s.read::<Offset24>()?;
1138                let color_line =
1139                    self.parse_color_line(offset + color_line_offset.to_usize(), foreground_color)?;
1140                painter.paint(Paint::RadialGradient(RadialGradient {
1141                    x0: s.read::<i16>()? as f32,
1142                    y0: s.read::<i16>()? as f32,
1143                    r0: s.read::<u16>()? as f32,
1144                    x1: s.read::<i16>()? as f32,
1145                    y1: s.read::<i16>()? as f32,
1146                    r1: s.read::<u16>()? as f32,
1147                    extend: color_line.extend,
1148                    #[cfg(feature = "variable-fonts")]
1149                    variation_data: self.variation_data(),
1150                    color_line: ColorLine::NonVarColorLine(color_line),
1151                }))
1152            }
1153            #[cfg(feature = "variable-fonts")]
1154            7 => {
1155                // PaintVarRadialGradient
1156                let color_line_offset = s.read::<Offset24>()?;
1157                let color_line = self.parse_var_color_line(
1158                    offset + color_line_offset.to_usize(),
1159                    foreground_color,
1160                )?;
1161
1162                let mut var_s = s.clone();
1163                var_s.advance(12);
1164                let var_index_base = var_s.read::<u32>()?;
1165
1166                let deltas = self
1167                    .variation_data()
1168                    .read_deltas::<6>(var_index_base, coords);
1169
1170                painter.paint(Paint::RadialGradient(RadialGradient {
1171                    x0: s.read::<i16>()? as f32 + deltas[0],
1172                    y0: s.read::<i16>()? as f32 + deltas[1],
1173                    r0: s.read::<u16>()? as f32 + deltas[2],
1174                    x1: s.read::<i16>()? as f32 + deltas[3],
1175                    y1: s.read::<i16>()? as f32 + deltas[4],
1176                    r1: s.read::<u16>()? as f32 + deltas[5],
1177                    extend: color_line.extend,
1178                    variation_data: self.variation_data(),
1179                    color_line: ColorLine::VarColorLine(color_line),
1180                }))
1181            }
1182            8 => {
1183                // PaintSweepGradient
1184                let color_line_offset = s.read::<Offset24>()?;
1185                let color_line =
1186                    self.parse_color_line(offset + color_line_offset.to_usize(), foreground_color)?;
1187                painter.paint(Paint::SweepGradient(SweepGradient {
1188                    center_x: s.read::<i16>()? as f32,
1189                    center_y: s.read::<i16>()? as f32,
1190                    start_angle: s.read::<F2DOT14>()?.to_f32(),
1191                    end_angle: s.read::<F2DOT14>()?.to_f32(),
1192                    extend: color_line.extend,
1193                    color_line: ColorLine::NonVarColorLine(color_line),
1194                    #[cfg(feature = "variable-fonts")]
1195                    variation_data: self.variation_data(),
1196                }))
1197            }
1198            #[cfg(feature = "variable-fonts")]
1199            9 => {
1200                // PaintVarSweepGradient
1201                let color_line_offset = s.read::<Offset24>()?;
1202                let color_line = self.parse_var_color_line(
1203                    offset + color_line_offset.to_usize(),
1204                    foreground_color,
1205                )?;
1206
1207                let mut var_s = s.clone();
1208                var_s.advance(8);
1209                let var_index_base = var_s.read::<u32>()?;
1210
1211                let deltas = self
1212                    .variation_data()
1213                    .read_deltas::<4>(var_index_base, coords);
1214
1215                painter.paint(Paint::SweepGradient(SweepGradient {
1216                    center_x: s.read::<i16>()? as f32 + deltas[0],
1217                    center_y: s.read::<i16>()? as f32 + deltas[1],
1218                    start_angle: s.read::<F2DOT14>()?.apply_float_delta(deltas[2]),
1219                    end_angle: s.read::<F2DOT14>()?.apply_float_delta(deltas[3]),
1220                    extend: color_line.extend,
1221                    color_line: ColorLine::VarColorLine(color_line),
1222                    variation_data: self.variation_data(),
1223                }))
1224            }
1225            10 => {
1226                // PaintGlyph
1227                let paint_offset = s.read::<Offset24>()?;
1228                let glyph_id = s.read::<GlyphId>()?;
1229                painter.outline_glyph(glyph_id);
1230                painter.push_clip();
1231
1232                self.parse_paint(
1233                    offset + paint_offset.to_usize(),
1234                    palette,
1235                    painter,
1236                    recursion_stack,
1237                    #[cfg(feature = "variable-fonts")]
1238                    coords,
1239                    foreground_color,
1240                );
1241
1242                painter.pop_clip();
1243            }
1244            11 => {
1245                // PaintColrGlyph
1246                let glyph_id = s.read::<GlyphId>()?;
1247                self.paint_impl(
1248                    glyph_id,
1249                    palette,
1250                    painter,
1251                    recursion_stack,
1252                    #[cfg(feature = "variable-fonts")]
1253                    coords,
1254                    foreground_color,
1255                );
1256            }
1257            12 => {
1258                // PaintTransform
1259                let paint_offset = s.read::<Offset24>()?;
1260                let ts_offset = s.read::<Offset24>()?;
1261                let mut s = Stream::new_at(self.data, offset + ts_offset.to_usize())?;
1262                let ts = Transform {
1263                    a: s.read::<Fixed>().map(|n| n.0)?,
1264                    b: s.read::<Fixed>().map(|n| n.0)?,
1265                    c: s.read::<Fixed>().map(|n| n.0)?,
1266                    d: s.read::<Fixed>().map(|n| n.0)?,
1267                    e: s.read::<Fixed>().map(|n| n.0)?,
1268                    f: s.read::<Fixed>().map(|n| n.0)?,
1269                };
1270
1271                painter.push_transform(ts);
1272                self.parse_paint(
1273                    offset + paint_offset.to_usize(),
1274                    palette,
1275                    painter,
1276                    recursion_stack,
1277                    #[cfg(feature = "variable-fonts")]
1278                    coords,
1279                    foreground_color,
1280                );
1281                painter.pop_transform();
1282            }
1283            #[cfg(feature = "variable-fonts")]
1284            13 => {
1285                // PaintVarTransform
1286                let paint_offset = s.read::<Offset24>()?;
1287                let ts_offset = s.read::<Offset24>()?;
1288                let mut s = Stream::new_at(self.data, offset + ts_offset.to_usize())?;
1289
1290                let mut var_s = s.clone();
1291                var_s.advance(24);
1292                let var_index_base = var_s.read::<u32>()?;
1293
1294                let deltas = self
1295                    .variation_data()
1296                    .read_deltas::<6>(var_index_base, coords);
1297
1298                let ts = Transform {
1299                    a: s.read::<Fixed>()?.apply_float_delta(deltas[0]),
1300                    b: s.read::<Fixed>()?.apply_float_delta(deltas[1]),
1301                    c: s.read::<Fixed>()?.apply_float_delta(deltas[2]),
1302                    d: s.read::<Fixed>()?.apply_float_delta(deltas[3]),
1303                    e: s.read::<Fixed>()?.apply_float_delta(deltas[4]),
1304                    f: s.read::<Fixed>()?.apply_float_delta(deltas[5]),
1305                };
1306
1307                painter.push_transform(ts);
1308                self.parse_paint(
1309                    offset + paint_offset.to_usize(),
1310                    palette,
1311                    painter,
1312                    recursion_stack,
1313                    coords,
1314                    foreground_color,
1315                );
1316                painter.pop_transform();
1317            }
1318            14 => {
1319                // PaintTranslate
1320                let paint_offset = s.read::<Offset24>()?;
1321                let tx = f32::from(s.read::<i16>()?);
1322                let ty = f32::from(s.read::<i16>()?);
1323
1324                painter.push_transform(Transform::new_translate(tx, ty));
1325                self.parse_paint(
1326                    offset + paint_offset.to_usize(),
1327                    palette,
1328                    painter,
1329                    recursion_stack,
1330                    #[cfg(feature = "variable-fonts")]
1331                    coords,
1332                    foreground_color,
1333                );
1334                painter.pop_transform();
1335            }
1336            #[cfg(feature = "variable-fonts")]
1337            15 => {
1338                // PaintVarTranslate
1339                let paint_offset = s.read::<Offset24>()?;
1340
1341                let mut var_s = s.clone();
1342                var_s.advance(4);
1343                let var_index_base = var_s.read::<u32>()?;
1344
1345                let deltas = self
1346                    .variation_data()
1347                    .read_deltas::<2>(var_index_base, coords);
1348
1349                let tx = f32::from(s.read::<i16>()?) + deltas[0];
1350                let ty = f32::from(s.read::<i16>()?) + deltas[1];
1351
1352                painter.push_transform(Transform::new_translate(tx, ty));
1353                self.parse_paint(
1354                    offset + paint_offset.to_usize(),
1355                    palette,
1356                    painter,
1357                    recursion_stack,
1358                    coords,
1359                    foreground_color,
1360                );
1361                painter.pop_transform();
1362            }
1363            16 => {
1364                // PaintScale
1365                let paint_offset = s.read::<Offset24>()?;
1366                let sx = s.read::<F2DOT14>()?.to_f32();
1367                let sy = s.read::<F2DOT14>()?.to_f32();
1368
1369                painter.push_transform(Transform::new_scale(sx, sy));
1370                self.parse_paint(
1371                    offset + paint_offset.to_usize(),
1372                    palette,
1373                    painter,
1374                    recursion_stack,
1375                    #[cfg(feature = "variable-fonts")]
1376                    coords,
1377                    foreground_color,
1378                );
1379                painter.pop_transform();
1380            }
1381            #[cfg(feature = "variable-fonts")]
1382            17 => {
1383                // PaintVarScale
1384                let paint_offset = s.read::<Offset24>()?;
1385
1386                let mut var_s = s.clone();
1387                var_s.advance(4);
1388                let var_index_base = var_s.read::<u32>()?;
1389
1390                let deltas = self
1391                    .variation_data()
1392                    .read_deltas::<2>(var_index_base, coords);
1393
1394                let sx = s.read::<F2DOT14>()?.apply_float_delta(deltas[0]);
1395                let sy = s.read::<F2DOT14>()?.apply_float_delta(deltas[1]);
1396
1397                painter.push_transform(Transform::new_scale(sx, sy));
1398                self.parse_paint(
1399                    offset + paint_offset.to_usize(),
1400                    palette,
1401                    painter,
1402                    recursion_stack,
1403                    coords,
1404                    foreground_color,
1405                );
1406                painter.pop_transform();
1407            }
1408            18 => {
1409                // PaintScaleAroundCenter
1410                let paint_offset = s.read::<Offset24>()?;
1411                let sx = s.read::<F2DOT14>()?.to_f32();
1412                let sy = s.read::<F2DOT14>()?.to_f32();
1413                let center_x = f32::from(s.read::<i16>()?);
1414                let center_y = f32::from(s.read::<i16>()?);
1415
1416                painter.push_transform(Transform::new_translate(center_x, center_y));
1417                painter.push_transform(Transform::new_scale(sx, sy));
1418                painter.push_transform(Transform::new_translate(-center_x, -center_y));
1419                self.parse_paint(
1420                    offset + paint_offset.to_usize(),
1421                    palette,
1422                    painter,
1423                    recursion_stack,
1424                    #[cfg(feature = "variable-fonts")]
1425                    coords,
1426                    foreground_color,
1427                );
1428                painter.pop_transform();
1429                painter.pop_transform();
1430                painter.pop_transform();
1431            }
1432            #[cfg(feature = "variable-fonts")]
1433            19 => {
1434                // PaintVarScaleAroundCenter
1435                let paint_offset = s.read::<Offset24>()?;
1436
1437                let mut var_s = s.clone();
1438                var_s.advance(8);
1439                let var_index_base = var_s.read::<u32>()?;
1440
1441                let deltas = self
1442                    .variation_data()
1443                    .read_deltas::<4>(var_index_base, coords);
1444
1445                let sx = s.read::<F2DOT14>()?.apply_float_delta(deltas[0]);
1446                let sy = s.read::<F2DOT14>()?.apply_float_delta(deltas[1]);
1447                let center_x = f32::from(s.read::<i16>()?) + deltas[2];
1448                let center_y = f32::from(s.read::<i16>()?) + deltas[3];
1449
1450                painter.push_transform(Transform::new_translate(center_x, center_y));
1451                painter.push_transform(Transform::new_scale(sx, sy));
1452                painter.push_transform(Transform::new_translate(-center_x, -center_y));
1453                self.parse_paint(
1454                    offset + paint_offset.to_usize(),
1455                    palette,
1456                    painter,
1457                    recursion_stack,
1458                    coords,
1459                    foreground_color,
1460                );
1461                painter.pop_transform();
1462                painter.pop_transform();
1463                painter.pop_transform();
1464            }
1465            20 => {
1466                // PaintScaleUniform
1467                let paint_offset = s.read::<Offset24>()?;
1468                let scale = s.read::<F2DOT14>()?.to_f32();
1469
1470                painter.push_transform(Transform::new_scale(scale, scale));
1471                self.parse_paint(
1472                    offset + paint_offset.to_usize(),
1473                    palette,
1474                    painter,
1475                    recursion_stack,
1476                    #[cfg(feature = "variable-fonts")]
1477                    coords,
1478                    foreground_color,
1479                );
1480                painter.pop_transform();
1481            }
1482            #[cfg(feature = "variable-fonts")]
1483            21 => {
1484                // PaintVarScaleUniform
1485                let paint_offset = s.read::<Offset24>()?;
1486
1487                let mut var_s = s.clone();
1488                var_s.advance(2);
1489                let var_index_base = var_s.read::<u32>()?;
1490
1491                let deltas = self
1492                    .variation_data()
1493                    .read_deltas::<1>(var_index_base, coords);
1494
1495                let scale = s.read::<F2DOT14>()?.apply_float_delta(deltas[0]);
1496
1497                painter.push_transform(Transform::new_scale(scale, scale));
1498                self.parse_paint(
1499                    offset + paint_offset.to_usize(),
1500                    palette,
1501                    painter,
1502                    recursion_stack,
1503                    coords,
1504                    foreground_color,
1505                );
1506                painter.pop_transform();
1507            }
1508            22 => {
1509                // PaintScaleUniformAroundCenter
1510                let paint_offset = s.read::<Offset24>()?;
1511                let scale = s.read::<F2DOT14>()?.to_f32();
1512                let center_x = f32::from(s.read::<i16>()?);
1513                let center_y = f32::from(s.read::<i16>()?);
1514
1515                painter.push_transform(Transform::new_translate(center_x, center_y));
1516                painter.push_transform(Transform::new_scale(scale, scale));
1517                painter.push_transform(Transform::new_translate(-center_x, -center_y));
1518                self.parse_paint(
1519                    offset + paint_offset.to_usize(),
1520                    palette,
1521                    painter,
1522                    recursion_stack,
1523                    #[cfg(feature = "variable-fonts")]
1524                    coords,
1525                    foreground_color,
1526                );
1527                painter.pop_transform();
1528                painter.pop_transform();
1529                painter.pop_transform();
1530            }
1531            #[cfg(feature = "variable-fonts")]
1532            23 => {
1533                // PaintVarScaleUniformAroundCenter
1534                let paint_offset = s.read::<Offset24>()?;
1535
1536                let mut var_s = s.clone();
1537                var_s.advance(6);
1538                let var_index_base = var_s.read::<u32>()?;
1539
1540                let deltas = self
1541                    .variation_data()
1542                    .read_deltas::<3>(var_index_base, coords);
1543
1544                let scale = s.read::<F2DOT14>()?.apply_float_delta(deltas[0]);
1545                let center_x = f32::from(s.read::<i16>()?) + deltas[1];
1546                let center_y = f32::from(s.read::<i16>()?) + deltas[2];
1547
1548                painter.push_transform(Transform::new_translate(center_x, center_y));
1549                painter.push_transform(Transform::new_scale(scale, scale));
1550                painter.push_transform(Transform::new_translate(-center_x, -center_y));
1551                self.parse_paint(
1552                    offset + paint_offset.to_usize(),
1553                    palette,
1554                    painter,
1555                    recursion_stack,
1556                    coords,
1557                    foreground_color,
1558                );
1559                painter.pop_transform();
1560                painter.pop_transform();
1561                painter.pop_transform();
1562            }
1563            24 => {
1564                // PaintRotate
1565                let paint_offset = s.read::<Offset24>()?;
1566                let angle = s.read::<F2DOT14>()?.to_f32();
1567
1568                painter.push_transform(Transform::new_rotate(angle));
1569                self.parse_paint(
1570                    offset + paint_offset.to_usize(),
1571                    palette,
1572                    painter,
1573                    recursion_stack,
1574                    #[cfg(feature = "variable-fonts")]
1575                    coords,
1576                    foreground_color,
1577                );
1578                painter.pop_transform();
1579            }
1580            #[cfg(feature = "variable-fonts")]
1581            25 => {
1582                // PaintVarRotate
1583                let paint_offset = s.read::<Offset24>()?;
1584
1585                let mut var_s = s.clone();
1586                var_s.advance(2);
1587                let var_index_base = var_s.read::<u32>()?;
1588
1589                let deltas = self
1590                    .variation_data()
1591                    .read_deltas::<1>(var_index_base, coords);
1592
1593                let angle = s.read::<F2DOT14>()?.apply_float_delta(deltas[0]);
1594
1595                painter.push_transform(Transform::new_rotate(angle));
1596                self.parse_paint(
1597                    offset + paint_offset.to_usize(),
1598                    palette,
1599                    painter,
1600                    recursion_stack,
1601                    coords,
1602                    foreground_color,
1603                );
1604                painter.pop_transform();
1605            }
1606            26 => {
1607                // PaintRotateAroundCenter
1608                let paint_offset = s.read::<Offset24>()?;
1609                let angle = s.read::<F2DOT14>()?.to_f32();
1610                let center_x = f32::from(s.read::<i16>()?);
1611                let center_y = f32::from(s.read::<i16>()?);
1612
1613                painter.push_transform(Transform::new_translate(center_x, center_y));
1614                painter.push_transform(Transform::new_rotate(angle));
1615                painter.push_transform(Transform::new_translate(-center_x, -center_y));
1616                self.parse_paint(
1617                    offset + paint_offset.to_usize(),
1618                    palette,
1619                    painter,
1620                    recursion_stack,
1621                    #[cfg(feature = "variable-fonts")]
1622                    coords,
1623                    foreground_color,
1624                );
1625                painter.pop_transform();
1626                painter.pop_transform();
1627                painter.pop_transform();
1628            }
1629            #[cfg(feature = "variable-fonts")]
1630            27 => {
1631                // PaintVarRotateAroundCenter
1632                let paint_offset = s.read::<Offset24>()?;
1633
1634                let mut var_s = s.clone();
1635                var_s.advance(6);
1636                let var_index_base = var_s.read::<u32>()?;
1637
1638                let deltas = self
1639                    .variation_data()
1640                    .read_deltas::<3>(var_index_base, coords);
1641
1642                let angle = s.read::<F2DOT14>()?.apply_float_delta(deltas[0]);
1643                let center_x = f32::from(s.read::<i16>()?) + deltas[1];
1644                let center_y = f32::from(s.read::<i16>()?) + deltas[2];
1645
1646                painter.push_transform(Transform::new_translate(center_x, center_y));
1647                painter.push_transform(Transform::new_rotate(angle));
1648                painter.push_transform(Transform::new_translate(-center_x, -center_y));
1649                self.parse_paint(
1650                    offset + paint_offset.to_usize(),
1651                    palette,
1652                    painter,
1653                    recursion_stack,
1654                    coords,
1655                    foreground_color,
1656                );
1657                painter.pop_transform();
1658                painter.pop_transform();
1659                painter.pop_transform();
1660            }
1661            28 => {
1662                // PaintSkew
1663                let paint_offset = s.read::<Offset24>()?;
1664                let skew_x = s.read::<F2DOT14>()?.to_f32();
1665                let skew_y = s.read::<F2DOT14>()?.to_f32();
1666
1667                painter.push_transform(Transform::new_skew(skew_x, skew_y));
1668                self.parse_paint(
1669                    offset + paint_offset.to_usize(),
1670                    palette,
1671                    painter,
1672                    recursion_stack,
1673                    #[cfg(feature = "variable-fonts")]
1674                    coords,
1675                    foreground_color,
1676                );
1677                painter.pop_transform();
1678            }
1679            #[cfg(feature = "variable-fonts")]
1680            29 => {
1681                // PaintVarSkew
1682                let paint_offset = s.read::<Offset24>()?;
1683
1684                let mut var_s = s.clone();
1685                var_s.advance(4);
1686                let var_index_base = var_s.read::<u32>()?;
1687
1688                let deltas = self
1689                    .variation_data()
1690                    .read_deltas::<2>(var_index_base, coords);
1691
1692                let skew_x = s.read::<F2DOT14>()?.apply_float_delta(deltas[0]);
1693                let skew_y = s.read::<F2DOT14>()?.apply_float_delta(deltas[1]);
1694
1695                painter.push_transform(Transform::new_skew(skew_x, skew_y));
1696                self.parse_paint(
1697                    offset + paint_offset.to_usize(),
1698                    palette,
1699                    painter,
1700                    recursion_stack,
1701                    coords,
1702                    foreground_color,
1703                );
1704                painter.pop_transform();
1705            }
1706            30 => {
1707                // PaintSkewAroundCenter
1708                let paint_offset = s.read::<Offset24>()?;
1709                let skew_x = s.read::<F2DOT14>()?.to_f32();
1710                let skew_y = s.read::<F2DOT14>()?.to_f32();
1711                let center_x = f32::from(s.read::<i16>()?);
1712                let center_y = f32::from(s.read::<i16>()?);
1713
1714                painter.push_transform(Transform::new_translate(center_x, center_y));
1715                painter.push_transform(Transform::new_skew(skew_x, skew_y));
1716                painter.push_transform(Transform::new_translate(-center_x, -center_y));
1717                self.parse_paint(
1718                    offset + paint_offset.to_usize(),
1719                    palette,
1720                    painter,
1721                    recursion_stack,
1722                    #[cfg(feature = "variable-fonts")]
1723                    coords,
1724                    foreground_color,
1725                );
1726                painter.pop_transform();
1727                painter.pop_transform();
1728                painter.pop_transform();
1729            }
1730            #[cfg(feature = "variable-fonts")]
1731            31 => {
1732                // PaintVarSkewAroundCenter
1733                let paint_offset = s.read::<Offset24>()?;
1734
1735                let mut var_s = s.clone();
1736                var_s.advance(8);
1737                let var_index_base = var_s.read::<u32>()?;
1738
1739                let deltas = self
1740                    .variation_data()
1741                    .read_deltas::<4>(var_index_base, coords);
1742
1743                let skew_x = s.read::<F2DOT14>()?.apply_float_delta(deltas[0]);
1744                let skew_y = s.read::<F2DOT14>()?.apply_float_delta(deltas[1]);
1745                let center_x = f32::from(s.read::<i16>()?) + deltas[2];
1746                let center_y = f32::from(s.read::<i16>()?) + deltas[3];
1747
1748                painter.push_transform(Transform::new_translate(center_x, center_y));
1749                painter.push_transform(Transform::new_skew(skew_x, skew_y));
1750                painter.push_transform(Transform::new_translate(-center_x, -center_y));
1751                self.parse_paint(
1752                    offset + paint_offset.to_usize(),
1753                    palette,
1754                    painter,
1755                    recursion_stack,
1756                    coords,
1757                    foreground_color,
1758                );
1759                painter.pop_transform();
1760                painter.pop_transform();
1761                painter.pop_transform();
1762            }
1763            32 => {
1764                // PaintComposite
1765                let source_paint_offset = s.read::<Offset24>()?;
1766                let composite_mode = s.read::<CompositeMode>()?;
1767                let backdrop_paint_offset = s.read::<Offset24>()?;
1768
1769                painter.push_layer(CompositeMode::SourceOver);
1770                self.parse_paint(
1771                    offset + backdrop_paint_offset.to_usize(),
1772                    palette,
1773                    painter,
1774                    recursion_stack,
1775                    #[cfg(feature = "variable-fonts")]
1776                    coords,
1777                    foreground_color,
1778                );
1779                painter.push_layer(composite_mode);
1780                self.parse_paint(
1781                    offset + source_paint_offset.to_usize(),
1782                    palette,
1783                    painter,
1784                    recursion_stack,
1785                    #[cfg(feature = "variable-fonts")]
1786                    coords,
1787                    foreground_color,
1788                );
1789                painter.pop_layer();
1790                painter.pop_layer();
1791            }
1792            _ => {}
1793        }
1794
1795        Some(())
1796    }
1797
1798    fn parse_color_line(
1799        &self,
1800        offset: usize,
1801        foreground_color: RgbaColor,
1802    ) -> Option<NonVarColorLine<'a>> {
1803        let mut s = Stream::new_at(self.data, offset)?;
1804        let extend = s.read::<GradientExtend>()?;
1805        let count = s.read::<u16>()?;
1806        let colors = s.read_array16::<ColorStopRaw>(count)?;
1807        Some(NonVarColorLine {
1808            extend,
1809            colors,
1810            foreground_color,
1811            palettes: self.palettes,
1812        })
1813    }
1814
1815    #[cfg(feature = "variable-fonts")]
1816    fn parse_var_color_line(
1817        &self,
1818        offset: usize,
1819        foreground_color: RgbaColor,
1820    ) -> Option<VarColorLine<'a>> {
1821        let mut s = Stream::new_at(self.data, offset)?;
1822        let extend = s.read::<GradientExtend>()?;
1823        let count = s.read::<u16>()?;
1824        let colors = s.read_array16::<VarColorStopRaw>(count)?;
1825        Some(VarColorLine {
1826            extend,
1827            colors,
1828            foreground_color,
1829            palettes: self.palettes,
1830        })
1831    }
1832}
1833
1834struct RecursionStack {
1835    // The limit of 64 is chosen arbitrarily and not from the spec. But we have to stop somewhere...
1836    stack: [usize; 64],
1837    len: usize,
1838}
1839
1840impl RecursionStack {
1841    #[inline]
1842    pub fn is_empty(&self) -> bool {
1843        self.len == 0
1844    }
1845
1846    #[inline]
1847    pub fn push(&mut self, offset: usize) -> Result<(), ()> {
1848        if self.len == self.stack.len() {
1849            Err(())
1850        } else {
1851            self.stack[self.len] = offset;
1852            self.len += 1;
1853            Ok(())
1854        }
1855    }
1856
1857    #[inline]
1858    pub fn contains(&self, offset: usize) -> bool {
1859        if let Some(offsets) = self.stack.get(..self.len) {
1860            return offsets.contains(&offset);
1861        }
1862
1863        false
1864    }
1865
1866    #[inline]
1867    pub fn pop(&mut self) {
1868        debug_assert!(!self.is_empty());
1869        self.len -= 1;
1870    }
1871}
1872
1873#[cfg(feature = "variable-fonts")]
1874#[derive(Clone, Copy, Debug, Default)]
1875struct VariationData<'a> {
1876    variation_store: Option<ItemVariationStore<'a>>,
1877    delta_map: Option<DeltaSetIndexMap<'a>>,
1878}
1879
1880#[cfg(feature = "variable-fonts")]
1881impl VariationData<'_> {
1882    // Inspired from `fontations`.
1883    fn read_deltas<const N: usize>(
1884        &self,
1885        var_index_base: u32,
1886        coordinates: &[NormalizedCoordinate],
1887    ) -> [f32; N] {
1888        const NO_VARIATION_DELTAS: u32 = 0xFFFFFFFF;
1889        let mut deltas = [0.0; N];
1890
1891        if coordinates.is_empty()
1892            || self.variation_store.is_none()
1893            || var_index_base == NO_VARIATION_DELTAS
1894        {
1895            return deltas;
1896        }
1897
1898        let variation_store = self.variation_store.as_ref().unwrap();
1899
1900        for (i, delta) in deltas.iter_mut().enumerate() {
1901            *delta = self
1902                .delta_map
1903                .and_then(|d| d.map(var_index_base + i as u32))
1904                .and_then(|d| variation_store.parse_delta(d.0, d.1, coordinates))
1905                .unwrap_or(0.0);
1906        }
1907
1908        deltas
1909    }
1910}