1use super::{traversal::ColorStopVec, Brush, PaintError, Transform};
4use core::ops::{Deref, Range};
5#[cfg(feature = "libm")]
6#[allow(unused_imports)]
7use core_maths::*;
8use read_fonts::{
9 tables::{
10 colr::*,
11 variations::{
12 DeltaSetIndex, DeltaSetIndexMap, FloatItemDelta, FloatItemDeltaTarget,
13 ItemVariationStore,
14 },
15 },
16 types::{BoundingBox, F2Dot14, GlyphId16, Point},
17 ReadError,
18};
19
20pub type PaintId = usize;
22
23#[derive(Clone)]
28pub struct ColrInstance<'a> {
29 colr: Colr<'a>,
30 index_map: Option<DeltaSetIndexMap<'a>>,
31 var_store: Option<ItemVariationStore<'a>>,
32 coords: &'a [F2Dot14],
33}
34
35impl<'a> ColrInstance<'a> {
36 pub fn new(colr: Colr<'a>, coords: &'a [F2Dot14]) -> Self {
39 let index_map = colr.var_index_map().and_then(|res| res.ok());
40 let var_store = colr.item_variation_store().and_then(|res| res.ok());
41 Self {
42 colr,
43 coords,
44 index_map,
45 var_store,
46 }
47 }
48
49 fn var_deltas<const N: usize>(&self, var_index_base: u32) -> [FloatItemDelta; N] {
52 const NO_VARIATION_DELTAS: u32 = 0xFFFFFFFF;
54 let mut deltas = [FloatItemDelta::ZERO; N];
59 if self.coords.is_empty()
60 || self.var_store.is_none()
61 || var_index_base == NO_VARIATION_DELTAS
62 {
63 return deltas;
64 }
65 let actual_count = ((u32::MAX - var_index_base) as usize).min(N);
67 let var_store = self.var_store.as_ref().unwrap();
68 if let Some(index_map) = self.index_map.as_ref() {
69 for (i, delta) in deltas.iter_mut().enumerate().take(actual_count) {
70 let var_index = var_index_base + i as u32;
71 if let Ok(delta_ix) = index_map.get(var_index) {
72 *delta = var_store
73 .compute_float_delta(delta_ix, self.coords)
74 .unwrap_or_default();
75 }
76 }
77 } else {
78 for (i, delta) in deltas.iter_mut().enumerate().take(actual_count) {
79 let var_index = var_index_base + i as u32;
80 let delta_ix = DeltaSetIndex {
83 outer: 0,
84 inner: var_index as u16,
85 };
86 *delta = var_store
87 .compute_float_delta(delta_ix, self.coords)
88 .unwrap_or_default();
89 }
90 }
91 deltas
92 }
93}
94
95impl<'a> Deref for ColrInstance<'a> {
96 type Target = Colr<'a>;
97
98 fn deref(&self) -> &Self::Target {
99 &self.colr
100 }
101}
102
103pub fn resolve_clip_box(instance: &ColrInstance, clip_box: &ClipBox) -> BoundingBox<f32> {
106 match clip_box {
107 ClipBox::Format1(cbox) => BoundingBox {
108 x_min: cbox.x_min().to_i16() as f32,
109 y_min: cbox.y_min().to_i16() as f32,
110 x_max: cbox.x_max().to_i16() as f32,
111 y_max: cbox.y_max().to_i16() as f32,
112 },
113 ClipBox::Format2(cbox) => {
114 let deltas = instance.var_deltas::<4>(cbox.var_index_base());
115 BoundingBox {
116 x_min: cbox.x_min().apply_float_delta(deltas[0]),
117 y_min: cbox.y_min().apply_float_delta(deltas[1]),
118 x_max: cbox.x_max().apply_float_delta(deltas[2]),
119 y_max: cbox.y_max().apply_float_delta(deltas[3]),
120 }
121 }
122 }
123}
124
125#[derive(Clone, Debug)]
128pub struct ResolvedColorStop {
129 pub offset: f32,
130 pub palette_index: u16,
131 pub alpha: f32,
132}
133
134#[derive(Clone)]
140pub struct ColorStops<'a> {
141 stops: &'a [ColorStop],
142 var_stops: &'a [VarColorStop],
143}
144
145impl<'a> From<ColorLine<'a>> for ColorStops<'a> {
146 fn from(value: ColorLine<'a>) -> Self {
147 Self {
148 stops: value.color_stops(),
149 var_stops: &[],
150 }
151 }
152}
153
154impl<'a> From<VarColorLine<'a>> for ColorStops<'a> {
155 fn from(value: VarColorLine<'a>) -> Self {
156 Self {
157 stops: &[],
158 var_stops: value.color_stops(),
159 }
160 }
161}
162
163impl<'a> ColorStops<'a> {
164 pub fn resolve(
167 &self,
168 instance: &'a ColrInstance<'a>,
169 ) -> impl Iterator<Item = ResolvedColorStop> + 'a {
170 self.stops
171 .iter()
172 .map(|stop| ResolvedColorStop {
173 offset: stop.stop_offset().to_f32(),
174 palette_index: stop.palette_index(),
175 alpha: stop.alpha().to_f32(),
176 })
177 .chain(self.var_stops.iter().map(|stop| {
178 let deltas = instance.var_deltas::<2>(stop.var_index_base());
179 ResolvedColorStop {
180 offset: stop.stop_offset().apply_float_delta(deltas[0]),
181 palette_index: stop.palette_index(),
182 alpha: stop.alpha().apply_float_delta(deltas[1]),
183 }
184 }))
185 }
186}
187
188pub(crate) enum MaybeBrush<'a> {
191 Some(Brush<'a>),
192 NonRendering,
194 None,
196}
197
198pub enum ResolvedPaint<'a> {
206 ColrLayers {
207 range: Range<usize>,
208 },
209 Solid {
210 palette_index: u16,
211 alpha: f32,
212 },
213 LinearGradient {
214 x0: f32,
215 y0: f32,
216 x1: f32,
217 y1: f32,
218 x2: f32,
219 y2: f32,
220 color_stops: ColorStops<'a>,
221 extend: Extend,
222 },
223 RadialGradient {
224 x0: f32,
225 y0: f32,
226 radius0: f32,
227 x1: f32,
228 y1: f32,
229 radius1: f32,
230 color_stops: ColorStops<'a>,
231 extend: Extend,
232 },
233 SweepGradient {
234 center_x: f32,
235 center_y: f32,
236 start_angle: f32,
237 end_angle: f32,
238 color_stops: ColorStops<'a>,
239 extend: Extend,
240 },
241 Glyph {
242 glyph_id: GlyphId16,
243 paint: Paint<'a>,
244 },
245 ColrGlyph {
246 glyph_id: GlyphId16,
247 },
248 Transform {
249 xx: f32,
250 yx: f32,
251 xy: f32,
252 yy: f32,
253 dx: f32,
254 dy: f32,
255 paint: Paint<'a>,
256 },
257 Translate {
258 dx: f32,
259 dy: f32,
260 paint: Paint<'a>,
261 },
262 Scale {
263 scale_x: f32,
264 scale_y: f32,
265 around_center: Option<Point<f32>>,
266 paint: Paint<'a>,
267 },
268 Rotate {
269 angle: f32,
270 around_center: Option<Point<f32>>,
271 paint: Paint<'a>,
272 },
273 Skew {
274 x_skew_angle: f32,
275 y_skew_angle: f32,
276 around_center: Option<Point<f32>>,
277 paint: Paint<'a>,
278 },
279 Composite {
280 source_paint: Paint<'a>,
281 mode: CompositeMode,
282 backdrop_paint: Paint<'a>,
283 },
284}
285
286impl<'a> ResolvedPaint<'a> {
287 pub(crate) fn as_transform(&self) -> Option<(Transform, Paint<'a>)> {
288 match self {
289 ResolvedPaint::Rotate {
290 angle,
291 around_center,
292 paint,
293 } => {
294 let sin_v = (angle * 180.0).to_radians().sin();
295 let cos_v = (angle * 180.0).to_radians().cos();
296 let mut out_transform = Transform {
297 xx: cos_v,
298 xy: -sin_v,
299 yx: sin_v,
300 yy: cos_v,
301 ..Default::default()
302 };
303
304 fn scalar_dot_product(a: f32, b: f32, c: f32, d: f32) -> f32 {
305 a * b + c * d
306 }
307
308 if let Some(center) = around_center {
309 out_transform.dx = scalar_dot_product(sin_v, center.y, 1.0 - cos_v, center.x);
310 out_transform.dy = scalar_dot_product(-sin_v, center.x, 1.0 - cos_v, center.y);
311 }
312 Some((out_transform, paint.clone()))
313 }
314 ResolvedPaint::Scale {
315 scale_x,
316 scale_y,
317 around_center,
318 paint,
319 } => {
320 let mut out_transform = Transform {
321 xx: *scale_x,
322 yy: *scale_y,
323 ..Transform::default()
324 };
325
326 if let Some(center) = around_center {
327 out_transform.dx = center.x - scale_x * center.x;
328 out_transform.dy = center.y - scale_y * center.y;
329 }
330 Some((out_transform, paint.clone()))
331 }
332 ResolvedPaint::Skew {
333 x_skew_angle,
334 y_skew_angle,
335 around_center,
336 paint,
337 } => {
338 let tan_x = (x_skew_angle * 180.0).to_radians().tan();
339 let tan_y = (y_skew_angle * 180.0).to_radians().tan();
340 let mut out_transform = Transform {
341 xy: -tan_x,
342 yx: tan_y,
343 ..Transform::default()
344 };
345
346 if let Some(center) = around_center {
347 out_transform.dx = tan_x * center.y;
348 out_transform.dy = -tan_y * center.x;
349 }
350 Some((out_transform, paint.clone()))
351 }
352 ResolvedPaint::Transform {
353 xx,
354 yx,
355 xy,
356 yy,
357 dx,
358 dy,
359 paint,
360 } => Some((
361 Transform {
362 xx: *xx,
363 yx: *yx,
364 xy: *xy,
365 yy: *yy,
366 dx: *dx,
367 dy: *dy,
368 },
369 paint.clone(),
370 )),
371 ResolvedPaint::Translate { dx, dy, paint, .. } => Some((
372 Transform {
373 dx: *dx,
374 dy: *dy,
375 ..Default::default()
376 },
377 paint.clone(),
378 )),
379 _ => None,
380 }
381 }
382
383 pub(crate) fn as_brush<'s>(
384 &self,
385 instance: &ColrInstance,
386 resolved_stops: &'s mut ColorStopVec,
387 ) -> Result<MaybeBrush<'s>, PaintError> {
388 match self {
389 ResolvedPaint::Solid {
390 palette_index,
391 alpha,
392 } => Ok(MaybeBrush::Some(Brush::Solid {
393 palette_index: *palette_index,
394 alpha: *alpha,
395 })),
396 ResolvedPaint::LinearGradient {
397 x0,
398 y0,
399 x1,
400 y1,
401 x2,
402 y2,
403 color_stops,
404 extend,
405 } => {
406 let mut p0 = Point::new(*x0, *y0);
407 let p1 = Point::new(*x1, *y1);
408 let p2 = Point::new(*x2, *y2);
409
410 let dot_product = |a: Point<f32>, b: Point<f32>| -> f32 { a.x * b.x + a.y * b.y };
411 let cross_product = |a: Point<f32>, b: Point<f32>| -> f32 { a.x * b.y - a.y * b.x };
412 let project_onto = |vector: Point<f32>, point: Point<f32>| -> Point<f32> {
413 let length = (point.x * point.x + point.y * point.y).sqrt();
414 if length == 0.0 {
415 return Point::default();
416 }
417 let mut point_normalized = point / length;
418 point_normalized *= dot_product(vector, point) / length;
419 point_normalized
420 };
421
422 make_sorted_resolved_stops(color_stops, instance, resolved_stops);
423
424 if p1 == p0 || p2 == p0 || cross_product(p1 - p0, p2 - p0) == 0.0 {
429 if let Some(stop) = resolved_stops.first() {
430 return Ok(MaybeBrush::Some(Brush::Solid {
431 palette_index: stop.palette_index,
432 alpha: stop.alpha,
433 }));
434 };
435 return Ok(MaybeBrush::NonRendering);
436 }
437
438 let mut perpendicular_to_p2 = p2 - p0;
444 perpendicular_to_p2 = Point::new(perpendicular_to_p2.y, -perpendicular_to_p2.x);
445 let mut p3 = p0 + project_onto(p1 - p0, perpendicular_to_p2);
446
447 match (
448 resolved_stops.first().cloned(),
449 resolved_stops.last().cloned(),
450 ) {
451 (None, _) | (_, None) => {}
452 (Some(first_stop), Some(last_stop)) => {
453 let mut color_stop_range = last_stop.offset - first_stop.offset;
454
455 if color_stop_range == 0.0 && extend != &Extend::Pad {
457 return Ok(MaybeBrush::NonRendering);
458 }
459
460 if color_stop_range == 0.0 && extend == &Extend::Pad {
468 let mut extra_stop = last_stop;
469 extra_stop.offset += 1.0;
470 resolved_stops.push(extra_stop);
471
472 color_stop_range = 1.0;
473 }
474
475 debug_assert!(color_stop_range != 0.0);
476
477 if color_stop_range != 1.0 || first_stop.offset != 0.0 {
478 let p0_p3 = p3 - p0;
479 let p0_offset = p0_p3 * first_stop.offset;
480 let p3_offset = p0_p3 * last_stop.offset;
481
482 p3 = p0 + p3_offset;
483 p0 += p0_offset;
484
485 let scale_factor = 1.0 / color_stop_range;
486 let start_offset = first_stop.offset;
487
488 for stop in resolved_stops.iter_mut() {
489 stop.offset = (stop.offset - start_offset) * scale_factor;
490 }
491 }
492
493 return Ok(MaybeBrush::Some(Brush::LinearGradient {
494 p0,
495 p1: p3,
496 color_stops: resolved_stops.as_slice(),
497 extend: *extend,
498 }));
499 }
500 }
501
502 Ok(MaybeBrush::NonRendering)
503 }
504 ResolvedPaint::RadialGradient {
505 x0,
506 y0,
507 radius0,
508 x1,
509 y1,
510 radius1,
511 color_stops,
512 extend,
513 } => {
514 let mut c0 = Point::new(*x0, *y0);
515 let mut c1 = Point::new(*x1, *y1);
516 let mut radius0 = *radius0;
517 let mut radius1 = *radius1;
518
519 make_sorted_resolved_stops(color_stops, instance, resolved_stops);
520
521 match (
522 resolved_stops.first().cloned(),
523 resolved_stops.last().cloned(),
524 ) {
525 (None, _) | (_, None) => {}
526 (Some(first_stop), Some(last_stop)) => {
527 let mut color_stop_range = last_stop.offset - first_stop.offset;
528 if color_stop_range == 0.0 && extend != &Extend::Pad {
530 return Ok(MaybeBrush::NonRendering);
531 }
532
533 if color_stop_range == 0.0 && extend == &Extend::Pad {
537 let mut extra_stop = last_stop;
538 extra_stop.offset += 1.0;
539 resolved_stops.push(extra_stop);
540 color_stop_range = 1.0;
541 }
542
543 debug_assert!(color_stop_range != 0.0);
544
545 if color_stop_range != 1.0 || first_stop.offset != 0.0 {
550 let c0_to_c1 = c1 - c0;
551 let radius_diff = radius1 - radius0;
552 let scale_factor = 1.0 / color_stop_range;
553
554 let c0_offset = c0_to_c1 * first_stop.offset;
555 let c1_offset = c0_to_c1 * last_stop.offset;
556 let stops_start_offset = first_stop.offset;
557
558 c1 = c0 + c1_offset;
560 c0 += c0_offset;
561 radius1 = radius0 + radius_diff * last_stop.offset;
562 radius0 += radius_diff * first_stop.offset;
563
564 for stop in resolved_stops.iter_mut() {
565 stop.offset = (stop.offset - stops_start_offset) * scale_factor;
566 }
567 }
568
569 return Ok(MaybeBrush::Some(Brush::RadialGradient {
570 c0,
571 r0: radius0,
572 c1,
573 r1: radius1,
574 color_stops: resolved_stops.as_slice(),
575 extend: *extend,
576 }));
577 }
578 }
579 Ok(MaybeBrush::NonRendering)
580 }
581 ResolvedPaint::SweepGradient {
582 center_x,
583 center_y,
584 start_angle,
585 end_angle,
586 color_stops,
587 extend,
588 } => {
589 let sweep_angle_to_degrees = |angle| angle * 180.0 + 180.0;
592
593 let start_angle = sweep_angle_to_degrees(start_angle);
594 let end_angle = sweep_angle_to_degrees(end_angle);
595
596 let sector_angle = end_angle - start_angle;
599
600 make_sorted_resolved_stops(color_stops, instance, resolved_stops);
601 if resolved_stops.is_empty() {
602 return Ok(MaybeBrush::NonRendering);
603 }
604
605 match (
606 resolved_stops.first().cloned(),
607 resolved_stops.last().cloned(),
608 ) {
609 (None, _) | (_, None) => {}
610 (Some(first_stop), Some(last_stop)) => {
611 let mut color_stop_range = last_stop.offset - first_stop.offset;
612
613 let mut start_angle_scaled = start_angle + sector_angle * first_stop.offset;
614 let mut end_angle_scaled = start_angle + sector_angle * last_stop.offset;
615
616 let start_offset = first_stop.offset;
617
618 if color_stop_range == 0.0 && extend != &Extend::Pad {
620 return Ok(MaybeBrush::NonRendering);
621 }
622
623 if color_stop_range == 0.0 && extend == &Extend::Pad {
630 let mut offset_last = last_stop;
631 offset_last.offset += 1.0;
632 resolved_stops.push(offset_last);
633 color_stop_range = 1.0;
634 }
635
636 debug_assert!(color_stop_range != 0.0);
637
638 let scale_factor = 1.0 / color_stop_range;
639
640 for shift_stop in resolved_stops.iter_mut() {
641 shift_stop.offset = (shift_stop.offset - start_offset) * scale_factor;
642 }
643
644 start_angle_scaled = 360.0 - start_angle_scaled;
653 end_angle_scaled = 360.0 - end_angle_scaled;
654
655 if start_angle_scaled >= end_angle_scaled {
656 (start_angle_scaled, end_angle_scaled) =
657 (end_angle_scaled, start_angle_scaled);
658 resolved_stops.reverse();
659 for stop in resolved_stops.iter_mut() {
660 stop.offset = 1.0 - stop.offset;
661 }
662 }
663
664 if start_angle_scaled == end_angle_scaled && extend != &Extend::Pad {
668 return Ok(MaybeBrush::NonRendering);
669 }
670
671 return Ok(MaybeBrush::Some(Brush::SweepGradient {
672 c0: Point::new(*center_x, *center_y),
673 start_angle: start_angle_scaled,
674 end_angle: end_angle_scaled,
675 color_stops: resolved_stops.as_slice(),
676 extend: *extend,
677 }));
678 }
679 }
680 Ok(MaybeBrush::NonRendering)
681 }
682 _ => Ok(MaybeBrush::None),
683 }
684 }
685}
686
687fn make_sorted_resolved_stops(
688 stops: &ColorStops,
689 instance: &ColrInstance,
690 out_stops: &mut ColorStopVec,
691) {
692 let color_stop_iter = stops.resolve(instance).map(|stop| stop.into());
693 out_stops.clear();
694 for stop in color_stop_iter {
695 out_stops.push(stop);
696 }
697 out_stops.sort_by(|a, b| {
698 a.offset
699 .partial_cmp(&b.offset)
700 .unwrap_or(core::cmp::Ordering::Equal)
701 });
702}
703
704pub fn resolve_paint<'a>(
715 instance: &ColrInstance<'a>,
716 paint: &Paint<'a>,
717) -> Result<ResolvedPaint<'a>, ReadError> {
718 Ok(match paint {
719 Paint::ColrLayers(layers) => {
720 let start = layers.first_layer_index() as usize;
721 ResolvedPaint::ColrLayers {
722 range: start..start + layers.num_layers() as usize,
723 }
724 }
725 Paint::Solid(solid) => ResolvedPaint::Solid {
726 palette_index: solid.palette_index(),
727 alpha: solid.alpha().to_f32(),
728 },
729 Paint::VarSolid(solid) => {
730 let deltas = instance.var_deltas::<1>(solid.var_index_base());
731 ResolvedPaint::Solid {
732 palette_index: solid.palette_index(),
733 alpha: solid.alpha().apply_float_delta(deltas[0]),
734 }
735 }
736 Paint::LinearGradient(gradient) => {
737 let color_line = gradient.color_line()?;
738 let extend = color_line.extend();
739 ResolvedPaint::LinearGradient {
740 x0: gradient.x0().to_i16() as f32,
741 y0: gradient.y0().to_i16() as f32,
742 x1: gradient.x1().to_i16() as f32,
743 y1: gradient.y1().to_i16() as f32,
744 x2: gradient.x2().to_i16() as f32,
745 y2: gradient.y2().to_i16() as f32,
746 color_stops: color_line.into(),
747 extend,
748 }
749 }
750 Paint::VarLinearGradient(gradient) => {
751 let color_line = gradient.color_line()?;
752 let extend = color_line.extend();
753 let deltas = instance.var_deltas::<6>(gradient.var_index_base());
754 ResolvedPaint::LinearGradient {
755 x0: gradient.x0().apply_float_delta(deltas[0]),
756 y0: gradient.y0().apply_float_delta(deltas[1]),
757 x1: gradient.x1().apply_float_delta(deltas[2]),
758 y1: gradient.y1().apply_float_delta(deltas[3]),
759 x2: gradient.x2().apply_float_delta(deltas[4]),
760 y2: gradient.y2().apply_float_delta(deltas[5]),
761 color_stops: color_line.into(),
762 extend,
763 }
764 }
765 Paint::RadialGradient(gradient) => {
766 let color_line = gradient.color_line()?;
767 let extend = color_line.extend();
768 ResolvedPaint::RadialGradient {
769 x0: gradient.x0().to_i16() as f32,
770 y0: gradient.y0().to_i16() as f32,
771 radius0: gradient.radius0().to_u16() as f32,
772 x1: gradient.x1().to_i16() as f32,
773 y1: gradient.y1().to_i16() as f32,
774 radius1: gradient.radius1().to_u16() as f32,
775 color_stops: color_line.into(),
776 extend,
777 }
778 }
779 Paint::VarRadialGradient(gradient) => {
780 let color_line = gradient.color_line()?;
781 let extend = color_line.extend();
782 let deltas = instance.var_deltas::<6>(gradient.var_index_base());
783 ResolvedPaint::RadialGradient {
784 x0: gradient.x0().apply_float_delta(deltas[0]),
785 y0: gradient.y0().apply_float_delta(deltas[1]),
786 radius0: gradient.radius0().apply_float_delta(deltas[2]),
787 x1: gradient.x1().apply_float_delta(deltas[3]),
788 y1: gradient.y1().apply_float_delta(deltas[4]),
789 radius1: gradient.radius1().apply_float_delta(deltas[5]),
790 color_stops: color_line.into(),
791 extend,
792 }
793 }
794 Paint::SweepGradient(gradient) => {
795 let color_line = gradient.color_line()?;
796 let extend = color_line.extend();
797 ResolvedPaint::SweepGradient {
798 center_x: gradient.center_x().to_i16() as f32,
799 center_y: gradient.center_y().to_i16() as f32,
800 start_angle: gradient.start_angle().to_f32(),
801 end_angle: gradient.end_angle().to_f32(),
802 color_stops: color_line.into(),
803 extend,
804 }
805 }
806 Paint::VarSweepGradient(gradient) => {
807 let color_line = gradient.color_line()?;
808 let extend = color_line.extend();
809 let deltas = instance.var_deltas::<4>(gradient.var_index_base());
810 ResolvedPaint::SweepGradient {
811 center_x: gradient.center_x().apply_float_delta(deltas[0]),
812 center_y: gradient.center_y().apply_float_delta(deltas[1]),
813 start_angle: gradient.start_angle().apply_float_delta(deltas[2]),
814 end_angle: gradient.end_angle().apply_float_delta(deltas[3]),
815 color_stops: color_line.into(),
816 extend,
817 }
818 }
819 Paint::Glyph(glyph) => ResolvedPaint::Glyph {
820 glyph_id: glyph.glyph_id(),
821 paint: glyph.paint()?,
822 },
823 Paint::ColrGlyph(glyph) => ResolvedPaint::ColrGlyph {
824 glyph_id: glyph.glyph_id(),
825 },
826 Paint::Transform(transform) => {
827 let affine = transform.transform()?;
828 let paint = transform.paint()?;
829 ResolvedPaint::Transform {
830 xx: affine.xx().to_f32(),
831 yx: affine.yx().to_f32(),
832 xy: affine.xy().to_f32(),
833 yy: affine.yy().to_f32(),
834 dx: affine.dx().to_f32(),
835 dy: affine.dy().to_f32(),
836 paint,
837 }
838 }
839 Paint::VarTransform(transform) => {
840 let affine = transform.transform()?;
841 let paint = transform.paint()?;
842 let deltas = instance.var_deltas::<6>(affine.var_index_base());
843 ResolvedPaint::Transform {
844 xx: affine.xx().apply_float_delta(deltas[0]),
845 yx: affine.yx().apply_float_delta(deltas[1]),
846 xy: affine.xy().apply_float_delta(deltas[2]),
847 yy: affine.yy().apply_float_delta(deltas[3]),
848 dx: affine.dx().apply_float_delta(deltas[4]),
849 dy: affine.dy().apply_float_delta(deltas[5]),
850 paint,
851 }
852 }
853 Paint::Translate(transform) => ResolvedPaint::Translate {
854 dx: transform.dx().to_i16() as f32,
855 dy: transform.dy().to_i16() as f32,
856 paint: transform.paint()?,
857 },
858 Paint::VarTranslate(transform) => {
859 let deltas = instance.var_deltas::<2>(transform.var_index_base());
860 ResolvedPaint::Translate {
861 dx: transform.dx().apply_float_delta(deltas[0]),
862 dy: transform.dy().apply_float_delta(deltas[1]),
863 paint: transform.paint()?,
864 }
865 }
866 Paint::Scale(transform) => ResolvedPaint::Scale {
867 scale_x: transform.scale_x().to_f32(),
868 scale_y: transform.scale_y().to_f32(),
869 around_center: None,
870 paint: transform.paint()?,
871 },
872 Paint::VarScale(transform) => {
873 let deltas = instance.var_deltas::<2>(transform.var_index_base());
874 ResolvedPaint::Scale {
875 scale_x: transform.scale_x().apply_float_delta(deltas[0]),
876 scale_y: transform.scale_y().apply_float_delta(deltas[1]),
877 around_center: None,
878 paint: transform.paint()?,
879 }
880 }
881 Paint::ScaleAroundCenter(transform) => ResolvedPaint::Scale {
882 scale_x: transform.scale_x().to_f32(),
883 scale_y: transform.scale_y().to_f32(),
884 around_center: Some(Point::new(
885 transform.center_x().to_i16() as f32,
886 transform.center_y().to_i16() as f32,
887 )),
888 paint: transform.paint()?,
889 },
890 Paint::VarScaleAroundCenter(transform) => {
891 let deltas = instance.var_deltas::<4>(transform.var_index_base());
892 ResolvedPaint::Scale {
893 scale_x: transform.scale_x().apply_float_delta(deltas[0]),
894 scale_y: transform.scale_y().apply_float_delta(deltas[1]),
895 around_center: Some(Point::new(
896 transform.center_x().apply_float_delta(deltas[2]),
897 transform.center_y().apply_float_delta(deltas[3]),
898 )),
899 paint: transform.paint()?,
900 }
901 }
902 Paint::ScaleUniform(transform) => {
903 let scale = transform.scale().to_f32();
904 ResolvedPaint::Scale {
905 scale_x: scale,
906 scale_y: scale,
907 around_center: None,
908 paint: transform.paint()?,
909 }
910 }
911 Paint::VarScaleUniform(transform) => {
912 let deltas = instance.var_deltas::<1>(transform.var_index_base());
913 let scale = transform.scale().apply_float_delta(deltas[0]);
914 ResolvedPaint::Scale {
915 scale_x: scale,
916 scale_y: scale,
917 around_center: None,
918 paint: transform.paint()?,
919 }
920 }
921 Paint::ScaleUniformAroundCenter(transform) => {
922 let scale = transform.scale().to_f32();
923 ResolvedPaint::Scale {
924 scale_x: scale,
925 scale_y: scale,
926 around_center: Some(Point::new(
927 transform.center_x().to_i16() as f32,
928 transform.center_y().to_i16() as f32,
929 )),
930 paint: transform.paint()?,
931 }
932 }
933 Paint::VarScaleUniformAroundCenter(transform) => {
934 let deltas = instance.var_deltas::<3>(transform.var_index_base());
935 let scale = transform.scale().apply_float_delta(deltas[0]);
936 ResolvedPaint::Scale {
937 scale_x: scale,
938 scale_y: scale,
939 around_center: Some(Point::new(
940 transform.center_x().apply_float_delta(deltas[1]),
941 transform.center_y().apply_float_delta(deltas[2]),
942 )),
943 paint: transform.paint()?,
944 }
945 }
946 Paint::Rotate(transform) => ResolvedPaint::Rotate {
947 angle: transform.angle().to_f32(),
948 around_center: None,
949 paint: transform.paint()?,
950 },
951 Paint::VarRotate(transform) => {
952 let deltas = instance.var_deltas::<1>(transform.var_index_base());
953 ResolvedPaint::Rotate {
954 angle: transform.angle().apply_float_delta(deltas[0]),
955 around_center: None,
956 paint: transform.paint()?,
957 }
958 }
959 Paint::RotateAroundCenter(transform) => ResolvedPaint::Rotate {
960 angle: transform.angle().to_f32(),
961 around_center: Some(Point::new(
962 transform.center_x().to_i16() as f32,
963 transform.center_y().to_i16() as f32,
964 )),
965 paint: transform.paint()?,
966 },
967 Paint::VarRotateAroundCenter(transform) => {
968 let deltas = instance.var_deltas::<3>(transform.var_index_base());
969 ResolvedPaint::Rotate {
970 angle: transform.angle().apply_float_delta(deltas[0]),
971 around_center: Some(Point::new(
972 transform.center_x().apply_float_delta(deltas[1]),
973 transform.center_y().apply_float_delta(deltas[2]),
974 )),
975 paint: transform.paint()?,
976 }
977 }
978 Paint::Skew(transform) => ResolvedPaint::Skew {
979 x_skew_angle: transform.x_skew_angle().to_f32(),
980 y_skew_angle: transform.y_skew_angle().to_f32(),
981 around_center: None,
982 paint: transform.paint()?,
983 },
984 Paint::VarSkew(transform) => {
985 let deltas = instance.var_deltas::<2>(transform.var_index_base());
986 ResolvedPaint::Skew {
987 x_skew_angle: transform.x_skew_angle().apply_float_delta(deltas[0]),
988 y_skew_angle: transform.y_skew_angle().apply_float_delta(deltas[1]),
989 around_center: None,
990 paint: transform.paint()?,
991 }
992 }
993 Paint::SkewAroundCenter(transform) => ResolvedPaint::Skew {
994 x_skew_angle: transform.x_skew_angle().to_f32(),
995 y_skew_angle: transform.y_skew_angle().to_f32(),
996 around_center: Some(Point::new(
997 transform.center_x().to_i16() as f32,
998 transform.center_y().to_i16() as f32,
999 )),
1000 paint: transform.paint()?,
1001 },
1002 Paint::VarSkewAroundCenter(transform) => {
1003 let deltas = instance.var_deltas::<4>(transform.var_index_base());
1004 ResolvedPaint::Skew {
1005 x_skew_angle: transform.x_skew_angle().apply_float_delta(deltas[0]),
1006 y_skew_angle: transform.y_skew_angle().apply_float_delta(deltas[1]),
1007 around_center: Some(Point::new(
1008 transform.center_x().apply_float_delta(deltas[2]),
1009 transform.center_y().apply_float_delta(deltas[3]),
1010 )),
1011 paint: transform.paint()?,
1012 }
1013 }
1014 Paint::Composite(composite) => ResolvedPaint::Composite {
1015 source_paint: composite.source_paint()?,
1016 mode: composite.composite_mode(),
1017 backdrop_paint: composite.backdrop_paint()?,
1018 },
1019 })
1020}
1021
1022#[cfg(test)]
1023mod tests {
1024 use super::*;
1025 use raw::{FontRef, TableProvider};
1026
1027 #[test]
1031 fn var_delta_index_overflow() {
1032 let font = FontRef::new(font_test_data::COLRV0V1_VARIABLE).unwrap();
1033 let coords = &[F2Dot14::from_f32(0.5)];
1034 let instance = ColrInstance::new(font.colr().unwrap(), coords);
1035 let _: [FloatItemDelta; 4] = instance.var_deltas(0xFFFFFFFE);
1037 }
1038}