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