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