1#[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#[derive(Clone, Copy, Debug)]
20struct BaseGlyphRecord {
21 glyph_id: GlyphId,
22 first_layer_index: u16,
23 num_layers: u16,
24}
25
26pub type ClipBox = RectF;
28
29#[derive(Clone, Debug)]
31pub enum Paint<'a> {
32 Solid(RgbaColor),
34 LinearGradient(LinearGradient<'a>),
36 RadialGradient(RadialGradient<'a>),
38 SweepGradient(SweepGradient<'a>),
40}
41
42#[derive(Clone, Copy, Debug)]
45struct ClipRecord {
46 pub start_glyph_id: GlyphId,
48 pub end_glyph_id: GlyphId,
50 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 pub fn glyphs_range(&self) -> core::ops::RangeInclusive<GlyphId> {
70 self.start_glyph_id..=self.end_glyph_id
71 }
72}
73
74#[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 #[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#[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#[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#[derive(Clone, Copy, Debug, PartialEq)]
195pub enum GradientExtend {
196 Pad,
198 Repeat,
200 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#[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#[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 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 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#[derive(Clone, Copy, Debug)]
337pub struct ColorStop {
338 pub stop_offset: f32,
340 pub color: RgbaColor,
342}
343
344#[derive(Clone)]
346pub struct LinearGradient<'a> {
347 pub x0: f32,
349 pub y0: f32,
351 pub x1: f32,
353 pub y1: f32,
355 pub x2: f32,
357 pub y2: f32,
359 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 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#[derive(Clone)]
410pub struct RadialGradient<'a> {
411 pub x0: f32,
413 pub y0: f32,
415 pub r0: f32,
417 pub r1: f32,
419 pub x1: f32,
421 pub y1: f32,
423 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 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#[derive(Clone)]
474pub struct SweepGradient<'a> {
475 pub center_x: f32,
477 pub center_y: f32,
479 pub start_angle: f32,
481 pub end_angle: f32,
483 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 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#[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#[derive(Clone, Copy, PartialEq, Debug)]
579pub enum CompositeMode {
580 Clear,
582 Source,
584 Destination,
586 SourceOver,
588 DestinationOver,
590 SourceIn,
592 DestinationIn,
594 SourceOut,
596 DestinationOut,
598 SourceAtop,
600 DestinationAtop,
602 Xor,
604 Plus,
606 Screen,
608 Overlay,
610 Darken,
612 Lighten,
614 ColorDodge,
616 ColorBurn,
618 HardLight,
620 SoftLight,
622 Difference,
624 Exclusion,
626 Multiply,
628 Hue,
630 Saturation,
632 Color,
634 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
676pub trait Painter<'a> {
680 fn outline_glyph(&mut self, glyph_id: GlyphId);
682 fn paint(&mut self, paint: Paint<'a>);
684
685 fn push_clip(&mut self);
687
688 fn push_clip_box(&mut self, clipbox: ClipBox);
690 fn pop_clip(&mut self);
692
693 fn push_layer(&mut self, mode: CompositeMode);
695 fn pop_layer(&mut self);
697 fn push_transform(&mut self, transform: Transform);
699 fn pop_transform(&mut self);
701}
702
703#[derive(Clone, Copy, Debug)]
708pub struct Table<'a> {
709 pub(crate) palettes: cpal::Table<'a>,
710 data: &'a [u8],
711 version: u8,
712 base_glyphs: LazyArray16<'a, BaseGlyphRecord>,
714 layers: LazyArray16<'a, LayerRecord>,
715 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 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), 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>(); 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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}