1use read_fonts::{
4 tables::{
5 colr::*,
6 variations::{
7 DeltaSetIndex, DeltaSetIndexMap, FloatItemDelta, FloatItemDeltaTarget,
8 ItemVariationStore,
9 },
10 },
11 types::{BoundingBox, F2Dot14, GlyphId16, Point},
12 ReadError,
13};
14
15use core::ops::{Deref, Range};
16
17pub type PaintId = usize;
19
20#[derive(Clone)]
25pub 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
32impl<'a> ColrInstance<'a> {
33 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 fn var_deltas<const N: usize>(&self, var_index_base: u32) -> [FloatItemDelta; N] {
49 const NO_VARIATION_DELTAS: u32 = 0xFFFFFFFF;
51 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 actual_count = ((u32::MAX - var_index_base) as usize).min(N);
64 let var_store = self.var_store.as_ref().unwrap();
65 if let Some(index_map) = self.index_map.as_ref() {
66 for (i, delta) in deltas.iter_mut().enumerate().take(actual_count) {
67 let var_index = var_index_base + i as u32;
68 if let Ok(delta_ix) = index_map.get(var_index) {
69 *delta = var_store
70 .compute_float_delta(delta_ix, self.coords)
71 .unwrap_or_default();
72 }
73 }
74 } else {
75 for (i, delta) in deltas.iter_mut().enumerate().take(actual_count) {
76 let var_index = var_index_base + i as u32;
77 let delta_ix = DeltaSetIndex {
80 outer: 0,
81 inner: var_index as u16,
82 };
83 *delta = var_store
84 .compute_float_delta(delta_ix, self.coords)
85 .unwrap_or_default();
86 }
87 }
88 deltas
89 }
90}
91
92impl<'a> Deref for ColrInstance<'a> {
93 type Target = Colr<'a>;
94
95 fn deref(&self) -> &Self::Target {
96 &self.colr
97 }
98}
99
100pub fn resolve_clip_box(instance: &ColrInstance, clip_box: &ClipBox) -> BoundingBox<f32> {
103 match clip_box {
104 ClipBox::Format1(cbox) => BoundingBox {
105 x_min: cbox.x_min().to_i16() as f32,
106 y_min: cbox.y_min().to_i16() as f32,
107 x_max: cbox.x_max().to_i16() as f32,
108 y_max: cbox.y_max().to_i16() as f32,
109 },
110 ClipBox::Format2(cbox) => {
111 let deltas = instance.var_deltas::<4>(cbox.var_index_base());
112 BoundingBox {
113 x_min: cbox.x_min().apply_float_delta(deltas[0]),
114 y_min: cbox.y_min().apply_float_delta(deltas[1]),
115 x_max: cbox.x_max().apply_float_delta(deltas[2]),
116 y_max: cbox.y_max().apply_float_delta(deltas[3]),
117 }
118 }
119 }
120}
121
122#[derive(Clone, Debug)]
125pub struct ResolvedColorStop {
126 pub offset: f32,
127 pub palette_index: u16,
128 pub alpha: f32,
129}
130
131#[derive(Clone)]
137pub struct ColorStops<'a> {
138 stops: &'a [ColorStop],
139 var_stops: &'a [VarColorStop],
140}
141
142impl ColorStops<'_> {
143 pub fn len(&self) -> usize {
144 self.stops.len() + self.var_stops.len()
145 }
146
147 pub fn is_empty(&self) -> bool {
148 self.stops.is_empty() && self.var_stops.is_empty()
149 }
150}
151
152impl<'a> From<ColorLine<'a>> for ColorStops<'a> {
153 fn from(value: ColorLine<'a>) -> Self {
154 Self {
155 stops: value.color_stops(),
156 var_stops: &[],
157 }
158 }
159}
160
161impl<'a> From<VarColorLine<'a>> for ColorStops<'a> {
162 fn from(value: VarColorLine<'a>) -> Self {
163 Self {
164 stops: &[],
165 var_stops: value.color_stops(),
166 }
167 }
168}
169
170impl<'a> ColorStops<'a> {
171 pub fn resolve(
174 &self,
175 instance: &'a ColrInstance<'a>,
176 ) -> impl Iterator<Item = ResolvedColorStop> + 'a {
177 self.stops
178 .iter()
179 .map(|stop| ResolvedColorStop {
180 offset: stop.stop_offset().to_f32(),
181 palette_index: stop.palette_index(),
182 alpha: stop.alpha().to_f32(),
183 })
184 .chain(self.var_stops.iter().map(|stop| {
185 let deltas = instance.var_deltas::<2>(stop.var_index_base());
186 ResolvedColorStop {
187 offset: stop.stop_offset().apply_float_delta(deltas[0]),
188 palette_index: stop.palette_index(),
189 alpha: stop.alpha().apply_float_delta(deltas[1]),
190 }
191 }))
192 }
193}
194
195pub enum ResolvedPaint<'a> {
203 ColrLayers {
204 range: Range<usize>,
205 },
206 Solid {
207 palette_index: u16,
208 alpha: f32,
209 },
210 LinearGradient {
211 x0: f32,
212 y0: f32,
213 x1: f32,
214 y1: f32,
215 x2: f32,
216 y2: f32,
217 color_stops: ColorStops<'a>,
218 extend: Extend,
219 },
220 RadialGradient {
221 x0: f32,
222 y0: f32,
223 radius0: f32,
224 x1: f32,
225 y1: f32,
226 radius1: f32,
227 color_stops: ColorStops<'a>,
228 extend: Extend,
229 },
230 SweepGradient {
231 center_x: f32,
232 center_y: f32,
233 start_angle: f32,
234 end_angle: f32,
235 color_stops: ColorStops<'a>,
236 extend: Extend,
237 },
238 Glyph {
239 glyph_id: GlyphId16,
240 paint: Paint<'a>,
241 },
242 ColrGlyph {
243 glyph_id: GlyphId16,
244 },
245 Transform {
246 xx: f32,
247 yx: f32,
248 xy: f32,
249 yy: f32,
250 dx: f32,
251 dy: f32,
252 paint: Paint<'a>,
253 },
254 Translate {
255 dx: f32,
256 dy: f32,
257 paint: Paint<'a>,
258 },
259 Scale {
260 scale_x: f32,
261 scale_y: f32,
262 around_center: Option<Point<f32>>,
263 paint: Paint<'a>,
264 },
265 Rotate {
266 angle: f32,
267 around_center: Option<Point<f32>>,
268 paint: Paint<'a>,
269 },
270 Skew {
271 x_skew_angle: f32,
272 y_skew_angle: f32,
273 around_center: Option<Point<f32>>,
274 paint: Paint<'a>,
275 },
276 Composite {
277 source_paint: Paint<'a>,
278 mode: CompositeMode,
279 backdrop_paint: Paint<'a>,
280 },
281}
282
283pub fn resolve_paint<'a>(
294 instance: &ColrInstance<'a>,
295 paint: &Paint<'a>,
296) -> Result<ResolvedPaint<'a>, ReadError> {
297 Ok(match paint {
298 Paint::ColrLayers(layers) => {
299 let start = layers.first_layer_index() as usize;
300 ResolvedPaint::ColrLayers {
301 range: start..start + layers.num_layers() as usize,
302 }
303 }
304 Paint::Solid(solid) => ResolvedPaint::Solid {
305 palette_index: solid.palette_index(),
306 alpha: solid.alpha().to_f32(),
307 },
308 Paint::VarSolid(solid) => {
309 let deltas = instance.var_deltas::<1>(solid.var_index_base());
310 ResolvedPaint::Solid {
311 palette_index: solid.palette_index(),
312 alpha: solid.alpha().apply_float_delta(deltas[0]),
313 }
314 }
315 Paint::LinearGradient(gradient) => {
316 let color_line = gradient.color_line()?;
317 let extend = color_line.extend();
318 ResolvedPaint::LinearGradient {
319 x0: gradient.x0().to_i16() as f32,
320 y0: gradient.y0().to_i16() as f32,
321 x1: gradient.x1().to_i16() as f32,
322 y1: gradient.y1().to_i16() as f32,
323 x2: gradient.x2().to_i16() as f32,
324 y2: gradient.y2().to_i16() as f32,
325 color_stops: color_line.into(),
326 extend,
327 }
328 }
329 Paint::VarLinearGradient(gradient) => {
330 let color_line = gradient.color_line()?;
331 let extend = color_line.extend();
332 let deltas = instance.var_deltas::<6>(gradient.var_index_base());
333 ResolvedPaint::LinearGradient {
334 x0: gradient.x0().apply_float_delta(deltas[0]),
335 y0: gradient.y0().apply_float_delta(deltas[1]),
336 x1: gradient.x1().apply_float_delta(deltas[2]),
337 y1: gradient.y1().apply_float_delta(deltas[3]),
338 x2: gradient.x2().apply_float_delta(deltas[4]),
339 y2: gradient.y2().apply_float_delta(deltas[5]),
340 color_stops: color_line.into(),
341 extend,
342 }
343 }
344 Paint::RadialGradient(gradient) => {
345 let color_line = gradient.color_line()?;
346 let extend = color_line.extend();
347 ResolvedPaint::RadialGradient {
348 x0: gradient.x0().to_i16() as f32,
349 y0: gradient.y0().to_i16() as f32,
350 radius0: gradient.radius0().to_u16() as f32,
351 x1: gradient.x1().to_i16() as f32,
352 y1: gradient.y1().to_i16() as f32,
353 radius1: gradient.radius1().to_u16() as f32,
354 color_stops: color_line.into(),
355 extend,
356 }
357 }
358 Paint::VarRadialGradient(gradient) => {
359 let color_line = gradient.color_line()?;
360 let extend = color_line.extend();
361 let deltas = instance.var_deltas::<6>(gradient.var_index_base());
362 ResolvedPaint::RadialGradient {
363 x0: gradient.x0().apply_float_delta(deltas[0]),
364 y0: gradient.y0().apply_float_delta(deltas[1]),
365 radius0: gradient.radius0().apply_float_delta(deltas[2]),
366 x1: gradient.x1().apply_float_delta(deltas[3]),
367 y1: gradient.y1().apply_float_delta(deltas[4]),
368 radius1: gradient.radius1().apply_float_delta(deltas[5]),
369 color_stops: color_line.into(),
370 extend,
371 }
372 }
373 Paint::SweepGradient(gradient) => {
374 let color_line = gradient.color_line()?;
375 let extend = color_line.extend();
376 ResolvedPaint::SweepGradient {
377 center_x: gradient.center_x().to_i16() as f32,
378 center_y: gradient.center_y().to_i16() as f32,
379 start_angle: gradient.start_angle().to_f32(),
380 end_angle: gradient.end_angle().to_f32(),
381 color_stops: color_line.into(),
382 extend,
383 }
384 }
385 Paint::VarSweepGradient(gradient) => {
386 let color_line = gradient.color_line()?;
387 let extend = color_line.extend();
388 let deltas = instance.var_deltas::<4>(gradient.var_index_base());
389 ResolvedPaint::SweepGradient {
390 center_x: gradient.center_x().apply_float_delta(deltas[0]),
391 center_y: gradient.center_y().apply_float_delta(deltas[1]),
392 start_angle: gradient.start_angle().apply_float_delta(deltas[2]),
393 end_angle: gradient.end_angle().apply_float_delta(deltas[3]),
394 color_stops: color_line.into(),
395 extend,
396 }
397 }
398 Paint::Glyph(glyph) => ResolvedPaint::Glyph {
399 glyph_id: glyph.glyph_id(),
400 paint: glyph.paint()?,
401 },
402 Paint::ColrGlyph(glyph) => ResolvedPaint::ColrGlyph {
403 glyph_id: glyph.glyph_id(),
404 },
405 Paint::Transform(transform) => {
406 let affine = transform.transform()?;
407 let paint = transform.paint()?;
408 ResolvedPaint::Transform {
409 xx: affine.xx().to_f32(),
410 yx: affine.yx().to_f32(),
411 xy: affine.xy().to_f32(),
412 yy: affine.yy().to_f32(),
413 dx: affine.dx().to_f32(),
414 dy: affine.dy().to_f32(),
415 paint,
416 }
417 }
418 Paint::VarTransform(transform) => {
419 let affine = transform.transform()?;
420 let paint = transform.paint()?;
421 let deltas = instance.var_deltas::<6>(affine.var_index_base());
422 ResolvedPaint::Transform {
423 xx: affine.xx().apply_float_delta(deltas[0]),
424 yx: affine.yx().apply_float_delta(deltas[1]),
425 xy: affine.xy().apply_float_delta(deltas[2]),
426 yy: affine.yy().apply_float_delta(deltas[3]),
427 dx: affine.dx().apply_float_delta(deltas[4]),
428 dy: affine.dy().apply_float_delta(deltas[5]),
429 paint,
430 }
431 }
432 Paint::Translate(transform) => ResolvedPaint::Translate {
433 dx: transform.dx().to_i16() as f32,
434 dy: transform.dy().to_i16() as f32,
435 paint: transform.paint()?,
436 },
437 Paint::VarTranslate(transform) => {
438 let deltas = instance.var_deltas::<2>(transform.var_index_base());
439 ResolvedPaint::Translate {
440 dx: transform.dx().apply_float_delta(deltas[0]),
441 dy: transform.dy().apply_float_delta(deltas[1]),
442 paint: transform.paint()?,
443 }
444 }
445 Paint::Scale(transform) => ResolvedPaint::Scale {
446 scale_x: transform.scale_x().to_f32(),
447 scale_y: transform.scale_y().to_f32(),
448 around_center: None,
449 paint: transform.paint()?,
450 },
451 Paint::VarScale(transform) => {
452 let deltas = instance.var_deltas::<2>(transform.var_index_base());
453 ResolvedPaint::Scale {
454 scale_x: transform.scale_x().apply_float_delta(deltas[0]),
455 scale_y: transform.scale_y().apply_float_delta(deltas[1]),
456 around_center: None,
457 paint: transform.paint()?,
458 }
459 }
460 Paint::ScaleAroundCenter(transform) => ResolvedPaint::Scale {
461 scale_x: transform.scale_x().to_f32(),
462 scale_y: transform.scale_y().to_f32(),
463 around_center: Some(Point::new(
464 transform.center_x().to_i16() as f32,
465 transform.center_y().to_i16() as f32,
466 )),
467 paint: transform.paint()?,
468 },
469 Paint::VarScaleAroundCenter(transform) => {
470 let deltas = instance.var_deltas::<4>(transform.var_index_base());
471 ResolvedPaint::Scale {
472 scale_x: transform.scale_x().apply_float_delta(deltas[0]),
473 scale_y: transform.scale_y().apply_float_delta(deltas[1]),
474 around_center: Some(Point::new(
475 transform.center_x().apply_float_delta(deltas[2]),
476 transform.center_y().apply_float_delta(deltas[3]),
477 )),
478 paint: transform.paint()?,
479 }
480 }
481 Paint::ScaleUniform(transform) => {
482 let scale = transform.scale().to_f32();
483 ResolvedPaint::Scale {
484 scale_x: scale,
485 scale_y: scale,
486 around_center: None,
487 paint: transform.paint()?,
488 }
489 }
490 Paint::VarScaleUniform(transform) => {
491 let deltas = instance.var_deltas::<1>(transform.var_index_base());
492 let scale = transform.scale().apply_float_delta(deltas[0]);
493 ResolvedPaint::Scale {
494 scale_x: scale,
495 scale_y: scale,
496 around_center: None,
497 paint: transform.paint()?,
498 }
499 }
500 Paint::ScaleUniformAroundCenter(transform) => {
501 let scale = transform.scale().to_f32();
502 ResolvedPaint::Scale {
503 scale_x: scale,
504 scale_y: scale,
505 around_center: Some(Point::new(
506 transform.center_x().to_i16() as f32,
507 transform.center_y().to_i16() as f32,
508 )),
509 paint: transform.paint()?,
510 }
511 }
512 Paint::VarScaleUniformAroundCenter(transform) => {
513 let deltas = instance.var_deltas::<3>(transform.var_index_base());
514 let scale = transform.scale().apply_float_delta(deltas[0]);
515 ResolvedPaint::Scale {
516 scale_x: scale,
517 scale_y: scale,
518 around_center: Some(Point::new(
519 transform.center_x().apply_float_delta(deltas[1]),
520 transform.center_y().apply_float_delta(deltas[2]),
521 )),
522 paint: transform.paint()?,
523 }
524 }
525 Paint::Rotate(transform) => ResolvedPaint::Rotate {
526 angle: transform.angle().to_f32(),
527 around_center: None,
528 paint: transform.paint()?,
529 },
530 Paint::VarRotate(transform) => {
531 let deltas = instance.var_deltas::<1>(transform.var_index_base());
532 ResolvedPaint::Rotate {
533 angle: transform.angle().apply_float_delta(deltas[0]),
534 around_center: None,
535 paint: transform.paint()?,
536 }
537 }
538 Paint::RotateAroundCenter(transform) => ResolvedPaint::Rotate {
539 angle: transform.angle().to_f32(),
540 around_center: Some(Point::new(
541 transform.center_x().to_i16() as f32,
542 transform.center_y().to_i16() as f32,
543 )),
544 paint: transform.paint()?,
545 },
546 Paint::VarRotateAroundCenter(transform) => {
547 let deltas = instance.var_deltas::<3>(transform.var_index_base());
548 ResolvedPaint::Rotate {
549 angle: transform.angle().apply_float_delta(deltas[0]),
550 around_center: Some(Point::new(
551 transform.center_x().apply_float_delta(deltas[1]),
552 transform.center_y().apply_float_delta(deltas[2]),
553 )),
554 paint: transform.paint()?,
555 }
556 }
557 Paint::Skew(transform) => ResolvedPaint::Skew {
558 x_skew_angle: transform.x_skew_angle().to_f32(),
559 y_skew_angle: transform.y_skew_angle().to_f32(),
560 around_center: None,
561 paint: transform.paint()?,
562 },
563 Paint::VarSkew(transform) => {
564 let deltas = instance.var_deltas::<2>(transform.var_index_base());
565 ResolvedPaint::Skew {
566 x_skew_angle: transform.x_skew_angle().apply_float_delta(deltas[0]),
567 y_skew_angle: transform.y_skew_angle().apply_float_delta(deltas[1]),
568 around_center: None,
569 paint: transform.paint()?,
570 }
571 }
572 Paint::SkewAroundCenter(transform) => ResolvedPaint::Skew {
573 x_skew_angle: transform.x_skew_angle().to_f32(),
574 y_skew_angle: transform.y_skew_angle().to_f32(),
575 around_center: Some(Point::new(
576 transform.center_x().to_i16() as f32,
577 transform.center_y().to_i16() as f32,
578 )),
579 paint: transform.paint()?,
580 },
581 Paint::VarSkewAroundCenter(transform) => {
582 let deltas = instance.var_deltas::<4>(transform.var_index_base());
583 ResolvedPaint::Skew {
584 x_skew_angle: transform.x_skew_angle().apply_float_delta(deltas[0]),
585 y_skew_angle: transform.y_skew_angle().apply_float_delta(deltas[1]),
586 around_center: Some(Point::new(
587 transform.center_x().apply_float_delta(deltas[2]),
588 transform.center_y().apply_float_delta(deltas[3]),
589 )),
590 paint: transform.paint()?,
591 }
592 }
593 Paint::Composite(composite) => ResolvedPaint::Composite {
594 source_paint: composite.source_paint()?,
595 mode: composite.composite_mode(),
596 backdrop_paint: composite.backdrop_paint()?,
597 },
598 })
599}
600
601#[cfg(test)]
602mod tests {
603 use super::*;
604 use raw::{FontRef, TableProvider};
605
606 #[test]
610 fn var_delta_index_overflow() {
611 let font = FontRef::new(font_test_data::COLRV0V1_VARIABLE).unwrap();
612 let coords = &[F2Dot14::from_f32(0.5)];
613 let instance = ColrInstance::new(font.colr().unwrap(), coords);
614 let _: [FloatItemDelta; 4] = instance.var_deltas(0xFFFFFFFE);
616 }
617}