xref: /aosp_15_r20/external/cronet/third_party/rust/chromium_crates_io/vendor/skrifa-0.15.5/src/color/instance.rs (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 //! COLR table instance.
2 
3 use read_fonts::{
4     tables::{
5         colr::*,
6         variations::{
7             DeltaSetIndex, DeltaSetIndexMap, FloatItemDelta, FloatItemDeltaTarget,
8             ItemVariationStore,
9         },
10     },
11     types::{BoundingBox, F2Dot14, GlyphId, Point},
12     ReadError,
13 };
14 
15 use core::ops::{Deref, Range};
16 
17 /// Unique paint identifier used for detecting cycles in the paint graph.
18 pub type PaintId = usize;
19 
20 /// Combination of a `COLR` table and a location in variation space for
21 /// resolving paints.
22 ///
23 /// See [`resolve_paint`], [`ColorStops::resolve`] and [`resolve_clip_box`].
24 #[derive(Clone)]
25 pub struct ColrInstance<'a> {
26     colr: Colr<'a>,
27     index_map: Option<DeltaSetIndexMap<'a>>,
28     var_store: Option<ItemVariationStore<'a>>,
29     coords: &'a [F2Dot14],
30 }
31 
32 impl<'a> ColrInstance<'a> {
33     /// Creates a new instance for the given `COLR` table and normalized variation
34     /// coordinates.
new(colr: Colr<'a>, coords: &'a [F2Dot14]) -> Self35     pub fn new(colr: Colr<'a>, coords: &'a [F2Dot14]) -> Self {
36         let index_map = colr.var_index_map().and_then(|res| res.ok());
37         let var_store = colr.item_variation_store().and_then(|res| res.ok());
38         Self {
39             colr,
40             coords,
41             index_map,
42             var_store,
43         }
44     }
45 
46     /// Computes a sequence of N variation deltas starting at the given
47     /// `var_base` index.
var_deltas<const N: usize>(&self, var_index_base: u32) -> [FloatItemDelta; N]48     fn var_deltas<const N: usize>(&self, var_index_base: u32) -> [FloatItemDelta; N] {
49         // Magic value that indicates deltas should not be applied.
50         const NO_VARIATION_DELTAS: u32 = 0xFFFFFFFF;
51         // Note: FreeType never returns an error for these lookups, so
52         // we do the same and just `unwrap_or_default` on var store
53         // errors.
54         // See <https://gitlab.freedesktop.org/freetype/freetype/-/blob/fc01e7dd/src/sfnt/ttcolr.c#L574>
55         let mut deltas = [FloatItemDelta::ZERO; N];
56         if self.coords.is_empty()
57             || self.var_store.is_none()
58             || var_index_base == NO_VARIATION_DELTAS
59         {
60             return deltas;
61         }
62         let var_store = self.var_store.as_ref().unwrap();
63         if let Some(index_map) = self.index_map.as_ref() {
64             for (i, delta) in deltas.iter_mut().enumerate() {
65                 let var_index = var_index_base + i as u32;
66                 if let Ok(delta_ix) = index_map.get(var_index) {
67                     *delta = var_store
68                         .compute_float_delta(delta_ix, self.coords)
69                         .unwrap_or_default();
70                 }
71             }
72         } else {
73             for (i, delta) in deltas.iter_mut().enumerate() {
74                 let var_index = var_index_base + i as u32;
75                 // If we don't have a var index map, use our index as the inner
76                 // component and set the outer to 0.
77                 let delta_ix = DeltaSetIndex {
78                     outer: 0,
79                     inner: var_index as u16,
80                 };
81                 *delta = var_store
82                     .compute_float_delta(delta_ix, self.coords)
83                     .unwrap_or_default();
84             }
85         }
86         deltas
87     }
88 }
89 
90 impl<'a> Deref for ColrInstance<'a> {
91     type Target = Colr<'a>;
92 
deref(&self) -> &Self::Target93     fn deref(&self) -> &Self::Target {
94         &self.colr
95     }
96 }
97 
98 /// Resolves a clip box, applying variation deltas using the given
99 /// instance.
resolve_clip_box(instance: &ColrInstance, clip_box: &ClipBox) -> BoundingBox<f32>100 pub fn resolve_clip_box(instance: &ColrInstance, clip_box: &ClipBox) -> BoundingBox<f32> {
101     match clip_box {
102         ClipBox::Format1(cbox) => BoundingBox {
103             x_min: cbox.x_min().to_i16() as f32,
104             y_min: cbox.y_min().to_i16() as f32,
105             x_max: cbox.x_max().to_i16() as f32,
106             y_max: cbox.y_max().to_i16() as f32,
107         },
108         ClipBox::Format2(cbox) => {
109             let deltas = instance.var_deltas::<4>(cbox.var_index_base());
110             BoundingBox {
111                 x_min: cbox.x_min().apply_float_delta(deltas[0]),
112                 y_min: cbox.y_min().apply_float_delta(deltas[1]),
113                 x_max: cbox.x_max().apply_float_delta(deltas[2]),
114                 y_max: cbox.y_max().apply_float_delta(deltas[3]),
115             }
116         }
117     }
118 }
119 
120 /// Simplified version of a [`ColorStop`] or [`VarColorStop`] with applied
121 /// variation deltas.
122 #[derive(Clone, Debug)]
123 pub struct ResolvedColorStop {
124     pub offset: f32,
125     pub palette_index: u16,
126     pub alpha: f32,
127 }
128 
129 /// Collection of [`ColorStop`] or [`VarColorStop`].
130 // Note: only one of these fields is used at any given time, but this structure
131 // was chosen over the obvious enum approach for simplicity in generating a
132 // single concrete type for the `impl Iterator` return type of the `resolve`
133 // method.
134 #[derive(Clone)]
135 pub struct ColorStops<'a> {
136     stops: &'a [ColorStop],
137     var_stops: &'a [VarColorStop],
138 }
139 
140 impl<'a> ColorStops<'a> {
len(&self) -> usize141     pub fn len(&self) -> usize {
142         self.stops.len() + self.var_stops.len()
143     }
144 
is_empty(&self) -> bool145     pub fn is_empty(&self) -> bool {
146         self.stops.is_empty() && self.var_stops.is_empty()
147     }
148 }
149 
150 impl<'a> From<ColorLine<'a>> for ColorStops<'a> {
from(value: ColorLine<'a>) -> Self151     fn from(value: ColorLine<'a>) -> Self {
152         Self {
153             stops: value.color_stops(),
154             var_stops: &[],
155         }
156     }
157 }
158 
159 impl<'a> From<VarColorLine<'a>> for ColorStops<'a> {
from(value: VarColorLine<'a>) -> Self160     fn from(value: VarColorLine<'a>) -> Self {
161         Self {
162             stops: &[],
163             var_stops: value.color_stops(),
164         }
165     }
166 }
167 
168 impl<'a> ColorStops<'a> {
169     /// Returns an iterator yielding resolved color stops with variation deltas
170     /// applied.
resolve( &self, instance: &'a ColrInstance<'a>, ) -> impl Iterator<Item = ResolvedColorStop> + 'a171     pub fn resolve(
172         &self,
173         instance: &'a ColrInstance<'a>,
174     ) -> impl Iterator<Item = ResolvedColorStop> + 'a {
175         self.stops
176             .iter()
177             .map(|stop| ResolvedColorStop {
178                 offset: stop.stop_offset().to_f32(),
179                 palette_index: stop.palette_index(),
180                 alpha: stop.alpha().to_f32(),
181             })
182             .chain(self.var_stops.iter().map(|stop| {
183                 let deltas = instance.var_deltas::<2>(stop.var_index_base());
184                 ResolvedColorStop {
185                     offset: stop.stop_offset().apply_float_delta(deltas[0]),
186                     palette_index: stop.palette_index(),
187                     alpha: stop.alpha().apply_float_delta(deltas[1]),
188                 }
189             }))
190     }
191 }
192 
193 /// Simplified version of `Paint` with applied variation deltas.
194 ///
195 /// These are constructed with the [`resolve_paint`] function.
196 ///
197 /// This is roughly equivalent to FreeType's
198 /// [`FT_COLR_Paint`](https://freetype.org/freetype2/docs/reference/ft2-layer_management.html#ft_colr_paint)
199 /// type.
200 pub enum ResolvedPaint<'a> {
201     ColrLayers {
202         range: Range<usize>,
203     },
204     Solid {
205         palette_index: u16,
206         alpha: f32,
207     },
208     LinearGradient {
209         x0: f32,
210         y0: f32,
211         x1: f32,
212         y1: f32,
213         x2: f32,
214         y2: f32,
215         color_stops: ColorStops<'a>,
216         extend: Extend,
217     },
218     RadialGradient {
219         x0: f32,
220         y0: f32,
221         radius0: f32,
222         x1: f32,
223         y1: f32,
224         radius1: f32,
225         color_stops: ColorStops<'a>,
226         extend: Extend,
227     },
228     SweepGradient {
229         center_x: f32,
230         center_y: f32,
231         start_angle: f32,
232         end_angle: f32,
233         color_stops: ColorStops<'a>,
234         extend: Extend,
235     },
236     Glyph {
237         glyph_id: GlyphId,
238         paint: Paint<'a>,
239     },
240     ColrGlyph {
241         glyph_id: GlyphId,
242     },
243     Transform {
244         xx: f32,
245         yx: f32,
246         xy: f32,
247         yy: f32,
248         dx: f32,
249         dy: f32,
250         paint: Paint<'a>,
251     },
252     Translate {
253         dx: f32,
254         dy: f32,
255         paint: Paint<'a>,
256     },
257     Scale {
258         scale_x: f32,
259         scale_y: f32,
260         around_center: Option<Point<f32>>,
261         paint: Paint<'a>,
262     },
263     Rotate {
264         angle: f32,
265         around_center: Option<Point<f32>>,
266         paint: Paint<'a>,
267     },
268     Skew {
269         x_skew_angle: f32,
270         y_skew_angle: f32,
271         around_center: Option<Point<f32>>,
272         paint: Paint<'a>,
273     },
274     Composite {
275         source_paint: Paint<'a>,
276         mode: CompositeMode,
277         backdrop_paint: Paint<'a>,
278     },
279 }
280 
281 /// Resolves this paint with the given instance.
282 ///
283 /// Resolving means that all numeric values are converted to 32-bit floating
284 /// point, variation deltas are applied (also computed fully in floating
285 /// point), and the various transform paints are collapsed into a single value
286 /// for their category (transform, translate, scale, rotate and skew).
287 ///
288 /// This provides a simpler type for consumers that are more interested
289 /// in extracting the semantics of the graph rather than working with the
290 /// raw encoded structures.
resolve_paint<'a>( instance: &ColrInstance<'a>, paint: &Paint<'a>, ) -> Result<ResolvedPaint<'a>, ReadError>291 pub fn resolve_paint<'a>(
292     instance: &ColrInstance<'a>,
293     paint: &Paint<'a>,
294 ) -> Result<ResolvedPaint<'a>, ReadError> {
295     Ok(match paint {
296         Paint::ColrLayers(layers) => {
297             let start = layers.first_layer_index() as usize;
298             ResolvedPaint::ColrLayers {
299                 range: start..start + layers.num_layers() as usize,
300             }
301         }
302         Paint::Solid(solid) => ResolvedPaint::Solid {
303             palette_index: solid.palette_index(),
304             alpha: solid.alpha().to_f32(),
305         },
306         Paint::VarSolid(solid) => {
307             let deltas = instance.var_deltas::<1>(solid.var_index_base());
308             ResolvedPaint::Solid {
309                 palette_index: solid.palette_index(),
310                 alpha: solid.alpha().apply_float_delta(deltas[0]),
311             }
312         }
313         Paint::LinearGradient(gradient) => {
314             let color_line = gradient.color_line()?;
315             let extend = color_line.extend();
316             ResolvedPaint::LinearGradient {
317                 x0: gradient.x0().to_i16() as f32,
318                 y0: gradient.y0().to_i16() as f32,
319                 x1: gradient.x1().to_i16() as f32,
320                 y1: gradient.y1().to_i16() as f32,
321                 x2: gradient.x2().to_i16() as f32,
322                 y2: gradient.y2().to_i16() as f32,
323                 color_stops: color_line.into(),
324                 extend,
325             }
326         }
327         Paint::VarLinearGradient(gradient) => {
328             let color_line = gradient.color_line()?;
329             let extend = color_line.extend();
330             let deltas = instance.var_deltas::<6>(gradient.var_index_base());
331             ResolvedPaint::LinearGradient {
332                 x0: gradient.x0().apply_float_delta(deltas[0]),
333                 y0: gradient.y0().apply_float_delta(deltas[1]),
334                 x1: gradient.x1().apply_float_delta(deltas[2]),
335                 y1: gradient.y1().apply_float_delta(deltas[3]),
336                 x2: gradient.x2().apply_float_delta(deltas[4]),
337                 y2: gradient.y2().apply_float_delta(deltas[5]),
338                 color_stops: color_line.into(),
339                 extend,
340             }
341         }
342         Paint::RadialGradient(gradient) => {
343             let color_line = gradient.color_line()?;
344             let extend = color_line.extend();
345             ResolvedPaint::RadialGradient {
346                 x0: gradient.x0().to_i16() as f32,
347                 y0: gradient.y0().to_i16() as f32,
348                 radius0: gradient.radius0().to_u16() as f32,
349                 x1: gradient.x1().to_i16() as f32,
350                 y1: gradient.y1().to_i16() as f32,
351                 radius1: gradient.radius1().to_u16() as f32,
352                 color_stops: color_line.into(),
353                 extend,
354             }
355         }
356         Paint::VarRadialGradient(gradient) => {
357             let color_line = gradient.color_line()?;
358             let extend = color_line.extend();
359             let deltas = instance.var_deltas::<6>(gradient.var_index_base());
360             ResolvedPaint::RadialGradient {
361                 x0: gradient.x0().apply_float_delta(deltas[0]),
362                 y0: gradient.y0().apply_float_delta(deltas[1]),
363                 radius0: gradient.radius0().apply_float_delta(deltas[2]),
364                 x1: gradient.x1().apply_float_delta(deltas[3]),
365                 y1: gradient.y1().apply_float_delta(deltas[4]),
366                 radius1: gradient.radius1().apply_float_delta(deltas[5]),
367                 color_stops: color_line.into(),
368                 extend,
369             }
370         }
371         Paint::SweepGradient(gradient) => {
372             let color_line = gradient.color_line()?;
373             let extend = color_line.extend();
374             ResolvedPaint::SweepGradient {
375                 center_x: gradient.center_x().to_i16() as f32,
376                 center_y: gradient.center_y().to_i16() as f32,
377                 start_angle: gradient.start_angle().to_f32(),
378                 end_angle: gradient.end_angle().to_f32(),
379                 color_stops: color_line.into(),
380                 extend,
381             }
382         }
383         Paint::VarSweepGradient(gradient) => {
384             let color_line = gradient.color_line()?;
385             let extend = color_line.extend();
386             let deltas = instance.var_deltas::<4>(gradient.var_index_base());
387             ResolvedPaint::SweepGradient {
388                 center_x: gradient.center_x().apply_float_delta(deltas[0]),
389                 center_y: gradient.center_y().apply_float_delta(deltas[1]),
390                 start_angle: gradient.start_angle().apply_float_delta(deltas[2]),
391                 end_angle: gradient.end_angle().apply_float_delta(deltas[3]),
392                 color_stops: color_line.into(),
393                 extend,
394             }
395         }
396         Paint::Glyph(glyph) => ResolvedPaint::Glyph {
397             glyph_id: glyph.glyph_id(),
398             paint: glyph.paint()?,
399         },
400         Paint::ColrGlyph(glyph) => ResolvedPaint::ColrGlyph {
401             glyph_id: glyph.glyph_id(),
402         },
403         Paint::Transform(transform) => {
404             let affine = transform.transform()?;
405             let paint = transform.paint()?;
406             ResolvedPaint::Transform {
407                 xx: affine.xx().to_f32(),
408                 yx: affine.yx().to_f32(),
409                 xy: affine.xy().to_f32(),
410                 yy: affine.yy().to_f32(),
411                 dx: affine.dx().to_f32(),
412                 dy: affine.dy().to_f32(),
413                 paint,
414             }
415         }
416         Paint::VarTransform(transform) => {
417             let affine = transform.transform()?;
418             let paint = transform.paint()?;
419             let deltas = instance.var_deltas::<6>(affine.var_index_base());
420             ResolvedPaint::Transform {
421                 xx: affine.xx().apply_float_delta(deltas[0]),
422                 yx: affine.yx().apply_float_delta(deltas[1]),
423                 xy: affine.xy().apply_float_delta(deltas[2]),
424                 yy: affine.yy().apply_float_delta(deltas[3]),
425                 dx: affine.dx().apply_float_delta(deltas[4]),
426                 dy: affine.dy().apply_float_delta(deltas[5]),
427                 paint,
428             }
429         }
430         Paint::Translate(transform) => ResolvedPaint::Translate {
431             dx: transform.dx().to_i16() as f32,
432             dy: transform.dy().to_i16() as f32,
433             paint: transform.paint()?,
434         },
435         Paint::VarTranslate(transform) => {
436             let deltas = instance.var_deltas::<2>(transform.var_index_base());
437             ResolvedPaint::Translate {
438                 dx: transform.dx().apply_float_delta(deltas[0]),
439                 dy: transform.dy().apply_float_delta(deltas[1]),
440                 paint: transform.paint()?,
441             }
442         }
443         Paint::Scale(transform) => ResolvedPaint::Scale {
444             scale_x: transform.scale_x().to_f32(),
445             scale_y: transform.scale_y().to_f32(),
446             around_center: None,
447             paint: transform.paint()?,
448         },
449         Paint::VarScale(transform) => {
450             let deltas = instance.var_deltas::<2>(transform.var_index_base());
451             ResolvedPaint::Scale {
452                 scale_x: transform.scale_x().apply_float_delta(deltas[0]),
453                 scale_y: transform.scale_y().apply_float_delta(deltas[1]),
454                 around_center: None,
455                 paint: transform.paint()?,
456             }
457         }
458         Paint::ScaleAroundCenter(transform) => ResolvedPaint::Scale {
459             scale_x: transform.scale_x().to_f32(),
460             scale_y: transform.scale_y().to_f32(),
461             around_center: Some(Point::new(
462                 transform.center_x().to_i16() as f32,
463                 transform.center_y().to_i16() as f32,
464             )),
465             paint: transform.paint()?,
466         },
467         Paint::VarScaleAroundCenter(transform) => {
468             let deltas = instance.var_deltas::<4>(transform.var_index_base());
469             ResolvedPaint::Scale {
470                 scale_x: transform.scale_x().apply_float_delta(deltas[0]),
471                 scale_y: transform.scale_y().apply_float_delta(deltas[1]),
472                 around_center: Some(Point::new(
473                     transform.center_x().apply_float_delta(deltas[2]),
474                     transform.center_y().apply_float_delta(deltas[3]),
475                 )),
476                 paint: transform.paint()?,
477             }
478         }
479         Paint::ScaleUniform(transform) => {
480             let scale = transform.scale().to_f32();
481             ResolvedPaint::Scale {
482                 scale_x: scale,
483                 scale_y: scale,
484                 around_center: None,
485                 paint: transform.paint()?,
486             }
487         }
488         Paint::VarScaleUniform(transform) => {
489             let deltas = instance.var_deltas::<1>(transform.var_index_base());
490             let scale = transform.scale().apply_float_delta(deltas[0]);
491             ResolvedPaint::Scale {
492                 scale_x: scale,
493                 scale_y: scale,
494                 around_center: None,
495                 paint: transform.paint()?,
496             }
497         }
498         Paint::ScaleUniformAroundCenter(transform) => {
499             let scale = transform.scale().to_f32();
500             ResolvedPaint::Scale {
501                 scale_x: scale,
502                 scale_y: scale,
503                 around_center: Some(Point::new(
504                     transform.center_x().to_i16() as f32,
505                     transform.center_y().to_i16() as f32,
506                 )),
507                 paint: transform.paint()?,
508             }
509         }
510         Paint::VarScaleUniformAroundCenter(transform) => {
511             let deltas = instance.var_deltas::<3>(transform.var_index_base());
512             let scale = transform.scale().apply_float_delta(deltas[0]);
513             ResolvedPaint::Scale {
514                 scale_x: scale,
515                 scale_y: scale,
516                 around_center: Some(Point::new(
517                     transform.center_x().apply_float_delta(deltas[1]),
518                     transform.center_y().apply_float_delta(deltas[2]),
519                 )),
520                 paint: transform.paint()?,
521             }
522         }
523         Paint::Rotate(transform) => ResolvedPaint::Rotate {
524             angle: transform.angle().to_f32(),
525             around_center: None,
526             paint: transform.paint()?,
527         },
528         Paint::VarRotate(transform) => {
529             let deltas = instance.var_deltas::<1>(transform.var_index_base());
530             ResolvedPaint::Rotate {
531                 angle: transform.angle().apply_float_delta(deltas[0]),
532                 around_center: None,
533                 paint: transform.paint()?,
534             }
535         }
536         Paint::RotateAroundCenter(transform) => ResolvedPaint::Rotate {
537             angle: transform.angle().to_f32(),
538             around_center: Some(Point::new(
539                 transform.center_x().to_i16() as f32,
540                 transform.center_y().to_i16() as f32,
541             )),
542             paint: transform.paint()?,
543         },
544         Paint::VarRotateAroundCenter(transform) => {
545             let deltas = instance.var_deltas::<3>(transform.var_index_base());
546             ResolvedPaint::Rotate {
547                 angle: transform.angle().apply_float_delta(deltas[0]),
548                 around_center: Some(Point::new(
549                     transform.center_x().apply_float_delta(deltas[1]),
550                     transform.center_y().apply_float_delta(deltas[2]),
551                 )),
552                 paint: transform.paint()?,
553             }
554         }
555         Paint::Skew(transform) => ResolvedPaint::Skew {
556             x_skew_angle: transform.x_skew_angle().to_f32(),
557             y_skew_angle: transform.y_skew_angle().to_f32(),
558             around_center: None,
559             paint: transform.paint()?,
560         },
561         Paint::VarSkew(transform) => {
562             let deltas = instance.var_deltas::<2>(transform.var_index_base());
563             ResolvedPaint::Skew {
564                 x_skew_angle: transform.x_skew_angle().apply_float_delta(deltas[0]),
565                 y_skew_angle: transform.y_skew_angle().apply_float_delta(deltas[1]),
566                 around_center: None,
567                 paint: transform.paint()?,
568             }
569         }
570         Paint::SkewAroundCenter(transform) => ResolvedPaint::Skew {
571             x_skew_angle: transform.x_skew_angle().to_f32(),
572             y_skew_angle: transform.y_skew_angle().to_f32(),
573             around_center: Some(Point::new(
574                 transform.center_x().to_i16() as f32,
575                 transform.center_y().to_i16() as f32,
576             )),
577             paint: transform.paint()?,
578         },
579         Paint::VarSkewAroundCenter(transform) => {
580             let deltas = instance.var_deltas::<4>(transform.var_index_base());
581             ResolvedPaint::Skew {
582                 x_skew_angle: transform.x_skew_angle().apply_float_delta(deltas[0]),
583                 y_skew_angle: transform.y_skew_angle().apply_float_delta(deltas[1]),
584                 around_center: Some(Point::new(
585                     transform.center_x().apply_float_delta(deltas[2]),
586                     transform.center_y().apply_float_delta(deltas[3]),
587                 )),
588                 paint: transform.paint()?,
589             }
590         }
591         Paint::Composite(composite) => ResolvedPaint::Composite {
592             source_paint: composite.source_paint()?,
593             mode: composite.composite_mode(),
594             backdrop_paint: composite.backdrop_paint()?,
595         },
596     })
597 }
598