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