1use font_types::{GlyphId, GlyphId16};
3
4use crate::{collections::IntSet, tables::variations::NO_VARIATION_INDEX, ResolveOffset};
5
6use super::{
7 Clip, ClipBox, ClipBoxFormat2, ClipList, ColorLine, ColorStop, Colr, Paint, PaintColrGlyph,
8 PaintColrLayers, PaintComposite, PaintGlyph, PaintLinearGradient, PaintRadialGradient,
9 PaintRotate, PaintRotateAroundCenter, PaintScale, PaintScaleAroundCenter, PaintScaleUniform,
10 PaintScaleUniformAroundCenter, PaintSkew, PaintSkewAroundCenter, PaintSolid,
11 PaintSweepGradient, PaintTransform, PaintTranslate, PaintVarLinearGradient,
12 PaintVarRadialGradient, PaintVarRotate, PaintVarRotateAroundCenter, PaintVarScale,
13 PaintVarScaleAroundCenter, PaintVarScaleUniform, PaintVarScaleUniformAroundCenter,
14 PaintVarSkew, PaintVarSkewAroundCenter, PaintVarSolid, PaintVarSweepGradient,
15 PaintVarTransform, PaintVarTranslate, VarAffine2x3, VarColorLine, VarColorStop,
16};
17
18impl Colr<'_> {
19 pub fn v0_closure_palette_indices(
22 &self,
23 glyph_set: &IntSet<GlyphId>,
24 palette_indices: &mut IntSet<u16>,
25 ) {
26 let Some(Ok(records)) = self.base_glyph_records() else {
27 return;
28 };
29
30 let Some(Ok(layers)) = self.layer_records() else {
31 return;
32 };
33 let num_records = records.len() as u32;
34 let bit_storage = u32::BITS - num_records.leading_zeros();
35 if glyph_set.is_inverted() || num_records <= glyph_set.len() as u32 * bit_storage {
36 for record in records {
37 if !glyph_set.contains(GlyphId::from(record.glyph_id())) {
38 continue;
39 }
40 let start = record.first_layer_index() as usize;
41 let end = start + record.num_layers() as usize;
42 for layer_index in start..end {
43 if let Some(layer) = layers.get(layer_index) {
44 palette_indices.insert(layer.palette_index());
45 }
46 }
47 }
48 } else {
49 for glyph_id in glyph_set.iter() {
50 let Ok(glyph_id) = glyph_id.try_into() else {
51 continue;
52 };
53 let record = match records.binary_search_by(|rec| rec.glyph_id().cmp(&glyph_id)) {
54 Ok(idx) => records[idx],
55 _ => continue,
56 };
57 let start = record.first_layer_index() as usize;
58 let end = start + record.num_layers() as usize;
59 for layer_index in start..end {
60 if let Some(layer) = layers.get(layer_index) {
61 palette_indices.insert(layer.palette_index());
62 }
63 }
64 }
65 }
66 }
67
68 pub fn v1_closure(
70 &self,
71 glyph_set: &mut IntSet<GlyphId>,
72 layer_indices: &mut IntSet<u32>,
73 palette_indices: &mut IntSet<u16>,
74 variation_indices: &mut IntSet<u32>,
75 ) {
76 if self.version() < 1 {
77 return;
78 }
79
80 let mut c =
81 Colrv1ClosureContext::new(layer_indices, palette_indices, variation_indices, self);
82 if let Some(Ok(base_glyph_list)) = self.base_glyph_list() {
83 let base_glyph_records = base_glyph_list.base_glyph_paint_records();
84 let offset_data = base_glyph_list.offset_data();
85 let num_records = base_glyph_records.len() as u32;
86 let bit_storage = u32::BITS - num_records.leading_zeros();
87 if glyph_set.is_inverted() || num_records <= glyph_set.len() as u32 * bit_storage {
88 for record in base_glyph_records {
89 let gid = record.glyph_id();
90 if !glyph_set.contains(GlyphId::from(gid)) {
91 continue;
92 }
93 if let Ok(paint) = record.paint(offset_data) {
94 c.dispatch(&paint);
95 }
96 }
97 } else {
98 for glyph_id in glyph_set.iter() {
99 let Ok(glyph_id) = glyph_id.try_into() else {
100 continue;
101 };
102 let record = match base_glyph_records
103 .binary_search_by(|rec| rec.glyph_id().cmp(&glyph_id))
104 {
105 Ok(idx) => &base_glyph_records[idx],
106 _ => continue,
107 };
108 if record.paint_offset().is_null() {
109 continue;
110 }
111 if let Ok(paint) = record.paint(offset_data) {
112 c.dispatch(&paint);
113 }
114 }
115 }
116 glyph_set.union(&c.glyph_set);
117 }
118
119 if let Some(Ok(clip_list)) = self.clip_list() {
120 c.glyph_set.union(glyph_set);
121 for clip_record in clip_list.clips() {
122 clip_record.v1_closure(&mut c, &clip_list);
123 }
124 }
125 }
126
127 pub fn v0_closure_glyphs(
129 &self,
130 glyph_set: &IntSet<GlyphId>,
131 glyphset_colrv0: &mut IntSet<GlyphId>,
132 ) {
133 glyphset_colrv0.union(glyph_set);
134 let Some(Ok(records)) = self.base_glyph_records() else {
135 return;
136 };
137 let Some(Ok(layers)) = self.layer_records() else {
138 return;
139 };
140 let num_records = records.len() as u32;
141 let bit_storage = u32::BITS - num_records.leading_zeros();
142 if glyph_set.is_inverted() || num_records <= glyph_set.len() as u32 * bit_storage {
143 for record in records {
144 if !glyph_set.contains(GlyphId::from(record.glyph_id())) {
145 continue;
146 }
147 let start = record.first_layer_index() as usize;
148 let end = start + record.num_layers() as usize;
149 for layer_index in start..end {
150 if let Some(layer) = layers.get(layer_index) {
151 glyphset_colrv0.insert(GlyphId::from(layer.glyph_id()));
152 }
153 }
154 }
155 } else {
156 for glyph_id in glyph_set.iter() {
157 let Ok(glyph_id) = glyph_id.try_into() else {
158 continue;
159 };
160 let record = match records.binary_search_by(|rec| rec.glyph_id().cmp(&glyph_id)) {
161 Ok(idx) => records[idx],
162 _ => continue,
163 };
164 let start = record.first_layer_index() as usize;
165 let end = start + record.num_layers() as usize;
166 for layer_index in start..end {
167 if let Some(layer) = layers.get(layer_index) {
168 glyphset_colrv0.insert(GlyphId::from(layer.glyph_id()));
169 }
170 }
171 }
172 }
173 }
174}
175
176struct Colrv1ClosureContext<'a> {
177 glyph_set: IntSet<GlyphId>,
178 layer_indices: &'a mut IntSet<u32>,
179 palette_indices: &'a mut IntSet<u16>,
180 variation_indices: &'a mut IntSet<u32>,
181 colr: &'a Colr<'a>,
182 nesting_level_left: u8,
183 visited_paints: IntSet<u32>,
184 colr_head: usize,
185}
186
187impl<'a> Colrv1ClosureContext<'a> {
188 pub fn new(
189 layer_indices: &'a mut IntSet<u32>,
190 palette_indices: &'a mut IntSet<u16>,
191 variation_indices: &'a mut IntSet<u32>,
192 colr: &'a Colr,
193 ) -> Self {
194 let colr_head = colr.offset_data().as_bytes().as_ptr() as usize;
195 Self {
196 glyph_set: IntSet::empty(),
197 layer_indices,
198 palette_indices,
199 variation_indices,
200 colr,
201 nesting_level_left: 64,
202 visited_paints: IntSet::empty(),
203 colr_head,
204 }
205 }
206
207 fn dispatch(&mut self, paint: &Paint) {
208 if self.nesting_level_left == 0 {
209 return;
210 }
211
212 if self.paint_visited(paint) {
213 return;
214 }
215 self.nesting_level_left -= 1;
216 paint.v1_closure(self);
217 self.nesting_level_left += 1;
218 }
219
220 fn paint_visited(&mut self, paint: &Paint) -> bool {
221 let offset = (paint.offset_data().as_bytes().as_ptr() as usize - self.colr_head) as u32;
222 if self.visited_paints.contains(offset) {
223 return true;
224 }
225
226 self.visited_paints.insert(offset);
227 false
228 }
229
230 fn add_layer_index(&mut self, layer_index: u32) {
231 self.layer_indices.insert(layer_index);
232 }
233
234 fn add_palette_index(&mut self, palette_index: u16) {
235 self.palette_indices.insert(palette_index);
236 }
237
238 fn add_variation_indices(&mut self, var_index_base: u32, num_vars: u8) {
239 if num_vars == 0 || var_index_base == NO_VARIATION_INDEX {
240 return;
241 }
242
243 let last_var_index = var_index_base + num_vars as u32 - 1;
244 self.variation_indices
245 .insert_range(var_index_base..=last_var_index);
246 }
247
248 fn add_glyph_id(&mut self, gid: GlyphId16) {
249 self.glyph_set.insert(GlyphId::from(gid));
250 }
251}
252
253impl ColorStop {
254 fn v1_closure(&self, c: &mut Colrv1ClosureContext) {
255 c.add_palette_index(self.palette_index());
256 }
257}
258
259impl VarColorStop {
260 fn v1_closure(&self, c: &mut Colrv1ClosureContext) {
261 c.add_palette_index(self.palette_index());
262 c.add_variation_indices(self.var_index_base(), 2);
263 }
264}
265
266impl ColorLine<'_> {
267 fn v1_closure(&self, c: &mut Colrv1ClosureContext) {
268 for colorstop in self.color_stops() {
269 colorstop.v1_closure(c);
270 }
271 }
272}
273
274impl VarColorLine<'_> {
275 fn v1_closure(&self, c: &mut Colrv1ClosureContext) {
276 for var_colorstop in self.color_stops() {
277 var_colorstop.v1_closure(c);
278 }
279 }
280}
281
282impl Paint<'_> {
283 fn v1_closure(&self, c: &mut Colrv1ClosureContext) {
284 match self {
285 Self::ColrLayers(item) => item.v1_closure(c),
286 Self::Solid(item) => item.v1_closure(c),
287 Self::VarSolid(item) => item.v1_closure(c),
288 Self::LinearGradient(item) => item.v1_closure(c),
289 Self::VarLinearGradient(item) => item.v1_closure(c),
290 Self::RadialGradient(item) => item.v1_closure(c),
291 Self::VarRadialGradient(item) => item.v1_closure(c),
292 Self::SweepGradient(item) => item.v1_closure(c),
293 Self::VarSweepGradient(item) => item.v1_closure(c),
294 Self::Glyph(item) => item.v1_closure(c),
295 Self::ColrGlyph(item) => item.v1_closure(c),
296 Self::Transform(item) => item.v1_closure(c),
297 Self::VarTransform(item) => item.v1_closure(c),
298 Self::Translate(item) => item.v1_closure(c),
299 Self::VarTranslate(item) => item.v1_closure(c),
300 Self::Scale(item) => item.v1_closure(c),
301 Self::VarScale(item) => item.v1_closure(c),
302 Self::ScaleAroundCenter(item) => item.v1_closure(c),
303 Self::VarScaleAroundCenter(item) => item.v1_closure(c),
304 Self::ScaleUniform(item) => item.v1_closure(c),
305 Self::VarScaleUniform(item) => item.v1_closure(c),
306 Self::ScaleUniformAroundCenter(item) => item.v1_closure(c),
307 Self::VarScaleUniformAroundCenter(item) => item.v1_closure(c),
308 Self::Rotate(item) => item.v1_closure(c),
309 Self::VarRotate(item) => item.v1_closure(c),
310 Self::RotateAroundCenter(item) => item.v1_closure(c),
311 Self::VarRotateAroundCenter(item) => item.v1_closure(c),
312 Self::Skew(item) => item.v1_closure(c),
313 Self::VarSkew(item) => item.v1_closure(c),
314 Self::SkewAroundCenter(item) => item.v1_closure(c),
315 Self::VarSkewAroundCenter(item) => item.v1_closure(c),
316 Self::Composite(item) => item.v1_closure(c),
317 }
318 }
319}
320
321impl PaintColrLayers<'_> {
322 fn v1_closure(&self, c: &mut Colrv1ClosureContext) {
323 let num_layers = self.num_layers();
324 if num_layers == 0 {
325 return;
326 }
327
328 let Some(Ok(layer_list)) = c.colr.layer_list() else {
329 return;
330 };
331 let first_layer_index = self.first_layer_index();
332 let last_layer_index = first_layer_index + num_layers as u32 - 1;
333
334 let offset_data = layer_list.offset_data();
335 let paint_offsets = layer_list.paint_offsets();
336 for layer_index in first_layer_index..=last_layer_index {
337 let Some(paint_offset) = paint_offsets.get(layer_index as usize) else {
338 break;
339 };
340 if let Ok(paint) = paint_offset.get().resolve::<Paint>(offset_data) {
341 c.add_layer_index(layer_index);
342 c.dispatch(&paint);
343 }
344 }
345 }
346}
347
348impl PaintSolid<'_> {
349 fn v1_closure(&self, c: &mut Colrv1ClosureContext) {
350 c.add_palette_index(self.palette_index());
351 }
352}
353
354impl PaintVarSolid<'_> {
355 fn v1_closure(&self, c: &mut Colrv1ClosureContext) {
356 c.add_palette_index(self.palette_index());
357 c.add_variation_indices(self.var_index_base(), 1);
358 }
359}
360
361impl PaintLinearGradient<'_> {
362 fn v1_closure(&self, c: &mut Colrv1ClosureContext) {
363 if let Ok(colorline) = self.color_line() {
364 colorline.v1_closure(c);
365 }
366 }
367}
368
369impl PaintVarLinearGradient<'_> {
370 fn v1_closure(&self, c: &mut Colrv1ClosureContext) {
371 if let Ok(var_colorline) = self.color_line() {
372 var_colorline.v1_closure(c);
373 c.add_variation_indices(self.var_index_base(), 6);
374 }
375 }
376}
377
378impl PaintRadialGradient<'_> {
379 fn v1_closure(&self, c: &mut Colrv1ClosureContext) {
380 if let Ok(colorline) = self.color_line() {
381 colorline.v1_closure(c);
382 }
383 }
384}
385
386impl PaintVarRadialGradient<'_> {
387 fn v1_closure(&self, c: &mut Colrv1ClosureContext) {
388 if let Ok(var_colorline) = self.color_line() {
389 var_colorline.v1_closure(c);
390 c.add_variation_indices(self.var_index_base(), 6);
391 }
392 }
393}
394
395impl PaintSweepGradient<'_> {
396 fn v1_closure(&self, c: &mut Colrv1ClosureContext) {
397 if let Ok(colorline) = self.color_line() {
398 colorline.v1_closure(c);
399 }
400 }
401}
402
403impl PaintVarSweepGradient<'_> {
404 fn v1_closure(&self, c: &mut Colrv1ClosureContext) {
405 if let Ok(var_colorline) = self.color_line() {
406 var_colorline.v1_closure(c);
407 c.add_variation_indices(self.var_index_base(), 4);
408 }
409 }
410}
411
412impl PaintGlyph<'_> {
413 fn v1_closure(&self, c: &mut Colrv1ClosureContext) {
414 if let Ok(paint) = self.paint() {
415 c.add_glyph_id(self.glyph_id());
416 c.dispatch(&paint);
417 }
418 }
419}
420
421impl PaintColrGlyph<'_> {
422 fn v1_closure(&self, c: &mut Colrv1ClosureContext) {
423 let glyph_id = self.glyph_id();
424 let Some(Ok(list)) = c.colr.base_glyph_list() else {
425 return;
426 };
427 let records = list.base_glyph_paint_records();
428 let record = match records.binary_search_by(|rec| rec.glyph_id().cmp(&glyph_id)) {
429 Ok(ix) => &records[ix],
430 _ => return,
431 };
432 if let Ok(paint) = record.paint(list.offset_data()) {
433 c.add_glyph_id(glyph_id);
434 c.dispatch(&paint);
435 }
436 }
437}
438
439impl PaintTransform<'_> {
440 fn v1_closure(&self, c: &mut Colrv1ClosureContext) {
441 if let Ok(paint) = self.paint() {
442 c.dispatch(&paint);
443 }
444 }
445}
446
447impl VarAffine2x3<'_> {
448 fn v1_closure(&self, c: &mut Colrv1ClosureContext) {
449 c.add_variation_indices(self.var_index_base(), 6);
450 }
451}
452
453impl PaintVarTransform<'_> {
454 fn v1_closure(&self, c: &mut Colrv1ClosureContext) {
455 if let Ok(paint) = self.paint() {
456 if let Ok(affine2x3) = self.transform() {
457 c.dispatch(&paint);
458 affine2x3.v1_closure(c);
459 }
460 }
461 }
462}
463
464impl PaintTranslate<'_> {
465 fn v1_closure(&self, c: &mut Colrv1ClosureContext) {
466 if let Ok(paint) = self.paint() {
467 c.dispatch(&paint);
468 }
469 }
470}
471
472impl PaintVarTranslate<'_> {
473 fn v1_closure(&self, c: &mut Colrv1ClosureContext) {
474 if let Ok(paint) = self.paint() {
475 c.dispatch(&paint);
476 c.add_variation_indices(self.var_index_base(), 2);
477 }
478 }
479}
480
481impl PaintScale<'_> {
482 fn v1_closure(&self, c: &mut Colrv1ClosureContext) {
483 if let Ok(paint) = self.paint() {
484 c.dispatch(&paint);
485 }
486 }
487}
488
489impl PaintVarScale<'_> {
490 fn v1_closure(&self, c: &mut Colrv1ClosureContext) {
491 if let Ok(paint) = self.paint() {
492 c.dispatch(&paint);
493 c.add_variation_indices(self.var_index_base(), 2);
494 }
495 }
496}
497
498impl PaintScaleAroundCenter<'_> {
499 fn v1_closure(&self, c: &mut Colrv1ClosureContext) {
500 if let Ok(paint) = self.paint() {
501 c.dispatch(&paint);
502 }
503 }
504}
505
506impl PaintVarScaleAroundCenter<'_> {
507 fn v1_closure(&self, c: &mut Colrv1ClosureContext) {
508 if let Ok(paint) = self.paint() {
509 c.dispatch(&paint);
510 c.add_variation_indices(self.var_index_base(), 4);
511 }
512 }
513}
514
515impl PaintScaleUniform<'_> {
516 fn v1_closure(&self, c: &mut Colrv1ClosureContext) {
517 if let Ok(paint) = self.paint() {
518 c.dispatch(&paint);
519 }
520 }
521}
522
523impl PaintVarScaleUniform<'_> {
524 fn v1_closure(&self, c: &mut Colrv1ClosureContext) {
525 if let Ok(paint) = self.paint() {
526 c.dispatch(&paint);
527 c.add_variation_indices(self.var_index_base(), 1);
528 }
529 }
530}
531
532impl PaintScaleUniformAroundCenter<'_> {
533 fn v1_closure(&self, c: &mut Colrv1ClosureContext) {
534 if let Ok(paint) = self.paint() {
535 c.dispatch(&paint);
536 }
537 }
538}
539
540impl PaintVarScaleUniformAroundCenter<'_> {
541 fn v1_closure(&self, c: &mut Colrv1ClosureContext) {
542 if let Ok(paint) = self.paint() {
543 c.dispatch(&paint);
544 c.add_variation_indices(self.var_index_base(), 3);
545 }
546 }
547}
548
549impl PaintRotate<'_> {
550 fn v1_closure(&self, c: &mut Colrv1ClosureContext) {
551 if let Ok(paint) = self.paint() {
552 c.dispatch(&paint);
553 }
554 }
555}
556
557impl PaintVarRotate<'_> {
558 fn v1_closure(&self, c: &mut Colrv1ClosureContext) {
559 if let Ok(paint) = self.paint() {
560 c.dispatch(&paint);
561 c.add_variation_indices(self.var_index_base(), 1);
562 }
563 }
564}
565
566impl PaintRotateAroundCenter<'_> {
567 fn v1_closure(&self, c: &mut Colrv1ClosureContext) {
568 if let Ok(paint) = self.paint() {
569 c.dispatch(&paint);
570 }
571 }
572}
573
574impl PaintVarRotateAroundCenter<'_> {
575 fn v1_closure(&self, c: &mut Colrv1ClosureContext) {
576 if let Ok(paint) = self.paint() {
577 c.dispatch(&paint);
578 c.add_variation_indices(self.var_index_base(), 3);
579 }
580 }
581}
582
583impl PaintSkew<'_> {
584 fn v1_closure(&self, c: &mut Colrv1ClosureContext) {
585 if let Ok(paint) = self.paint() {
586 c.dispatch(&paint);
587 }
588 }
589}
590
591impl PaintVarSkew<'_> {
592 fn v1_closure(&self, c: &mut Colrv1ClosureContext) {
593 if let Ok(paint) = self.paint() {
594 c.dispatch(&paint);
595 c.add_variation_indices(self.var_index_base(), 2);
596 }
597 }
598}
599
600impl PaintSkewAroundCenter<'_> {
601 fn v1_closure(&self, c: &mut Colrv1ClosureContext) {
602 if let Ok(paint) = self.paint() {
603 c.dispatch(&paint);
604 }
605 }
606}
607
608impl PaintVarSkewAroundCenter<'_> {
609 fn v1_closure(&self, c: &mut Colrv1ClosureContext) {
610 if let Ok(paint) = self.paint() {
611 c.dispatch(&paint);
612 c.add_variation_indices(self.var_index_base(), 4);
613 }
614 }
615}
616
617impl PaintComposite<'_> {
618 fn v1_closure(&self, c: &mut Colrv1ClosureContext) {
619 if let Ok(source_paint) = self.source_paint() {
620 c.dispatch(&source_paint);
621 }
622
623 if let Ok(backdrop_paint) = self.backdrop_paint() {
624 c.dispatch(&backdrop_paint);
625 }
626 }
627}
628
629impl Clip {
630 fn v1_closure(&self, c: &mut Colrv1ClosureContext, clip_list: &ClipList) {
631 let Ok(clip_box) = self.clip_box(clip_list.offset_data()) else {
632 return;
633 };
634 let start_id = GlyphId::from(self.start_glyph_id());
635 let end_id = GlyphId::from(self.end_glyph_id());
636 if c.glyph_set.intersects_range(start_id..=end_id) {
637 clip_box.v1_closure(c);
638 }
639 }
640}
641
642impl ClipBox<'_> {
643 fn v1_closure(&self, c: &mut Colrv1ClosureContext) {
644 if let Self::Format2(item) = self {
645 item.v1_closure(c)
646 }
647 }
648}
649
650impl ClipBoxFormat2<'_> {
651 fn v1_closure(&self, c: &mut Colrv1ClosureContext) {
652 c.add_variation_indices(self.var_index_base(), 4);
653 }
654}
655
656#[cfg(test)]
657mod tests {
658 use super::*;
659 use crate::{FontRef, GlyphId, TableProvider};
660
661 #[test]
662 fn test_colr_v0_closure() {
663 let font = FontRef::new(font_test_data::COLRV0V1_VARIABLE).unwrap();
664 let colr = font.colr().unwrap();
665
666 let mut input_glyph_set = IntSet::empty();
667 input_glyph_set.insert(GlyphId::new(168));
668
669 let mut glyph_set_colred = IntSet::empty();
670
671 colr.v0_closure_glyphs(&input_glyph_set, &mut glyph_set_colred);
672 assert_eq!(glyph_set_colred.len(), 9);
673 assert!(glyph_set_colred.contains(GlyphId::new(5)));
674 assert!(glyph_set_colred.contains(GlyphId::new(168)));
675 assert!(glyph_set_colred.contains(GlyphId::new(170)));
676 assert!(glyph_set_colred.contains(GlyphId::new(171)));
677 assert!(glyph_set_colred.contains(GlyphId::new(172)));
678 assert!(glyph_set_colred.contains(GlyphId::new(173)));
679 assert!(glyph_set_colred.contains(GlyphId::new(174)));
680 assert!(glyph_set_colred.contains(GlyphId::new(175)));
681 assert!(glyph_set_colred.contains(GlyphId::new(176)));
682
683 let mut palette_indices = IntSet::empty();
684 colr.v0_closure_palette_indices(&glyph_set_colred, &mut palette_indices);
685 assert_eq!(palette_indices.len(), 8);
686 assert!(palette_indices.contains(0));
687 assert!(palette_indices.contains(1));
688 assert!(palette_indices.contains(2));
689 assert!(palette_indices.contains(3));
690 assert!(palette_indices.contains(4));
691 assert!(palette_indices.contains(5));
692 assert!(palette_indices.contains(6));
693 assert!(palette_indices.contains(10));
694 }
695
696 #[test]
697 fn test_colr_v0_closure_not_found() {
698 let font = FontRef::new(font_test_data::COLRV0V1_VARIABLE).unwrap();
699 let colr = font.colr().unwrap();
700
701 let mut input_glyph_set = IntSet::empty();
702 input_glyph_set.insert(GlyphId::new(8));
703
704 let mut glyph_set_colred = IntSet::empty();
705
706 colr.v0_closure_glyphs(&input_glyph_set, &mut glyph_set_colred);
707 assert_eq!(glyph_set_colred.len(), 1);
708 assert!(glyph_set_colred.contains(GlyphId::new(8)));
709 }
710
711 #[test]
712 fn test_colr_v1_closure_no_var() {
713 let font = FontRef::new(font_test_data::COLRV0V1_VARIABLE).unwrap();
714 let colr = font.colr().unwrap();
715
716 let mut glyph_set = IntSet::empty();
717 glyph_set.insert(GlyphId::new(220));
718 glyph_set.insert(GlyphId::new(120));
719
720 let mut layer_indices = IntSet::empty();
721 let mut palette_indices = IntSet::empty();
722 let mut variation_indices = IntSet::empty();
723
724 colr.v1_closure(
725 &mut glyph_set,
726 &mut layer_indices,
727 &mut palette_indices,
728 &mut variation_indices,
729 );
730
731 assert_eq!(glyph_set.len(), 6);
732 assert!(glyph_set.contains(GlyphId::new(6)));
733 assert!(glyph_set.contains(GlyphId::new(7)));
734 assert!(glyph_set.contains(GlyphId::new(220)));
735 assert!(glyph_set.contains(GlyphId::new(3)));
736 assert!(glyph_set.contains(GlyphId::new(2)));
737 assert!(glyph_set.contains(GlyphId::new(120)));
738
739 assert_eq!(palette_indices.len(), 5);
740 assert!(palette_indices.contains(0));
741 assert!(palette_indices.contains(4));
742 assert!(palette_indices.contains(10));
743 assert!(palette_indices.contains(11));
744 assert!(palette_indices.contains(12));
745
746 assert_eq!(layer_indices.len(), 2);
747 assert!(layer_indices.contains(0));
748 assert!(layer_indices.contains(1));
749
750 assert!(variation_indices.is_empty());
751 }
752
753 #[test]
754 fn test_colr_v1_closure_w_var() {
755 let font = FontRef::new(font_test_data::COLRV0V1_VARIABLE).unwrap();
756 let colr = font.colr().unwrap();
757
758 let mut glyph_set = IntSet::empty();
759 glyph_set.insert(GlyphId::new(109));
760
761 let mut layer_indices = IntSet::empty();
762 let mut palette_indices = IntSet::empty();
763 let mut variation_indices = IntSet::empty();
764
765 colr.v1_closure(
766 &mut glyph_set,
767 &mut layer_indices,
768 &mut palette_indices,
769 &mut variation_indices,
770 );
771
772 assert_eq!(glyph_set.len(), 2);
773 assert!(glyph_set.contains(GlyphId::new(3)));
774 assert!(glyph_set.contains(GlyphId::new(109)));
775
776 assert_eq!(palette_indices.len(), 2);
777 assert!(palette_indices.contains(1));
778 assert!(palette_indices.contains(4));
779
780 assert!(layer_indices.is_empty());
781
782 assert_eq!(variation_indices.len(), 6);
783 assert!(variation_indices.contains(51));
784 assert!(variation_indices.contains(52));
785 assert!(variation_indices.contains(53));
786 assert!(variation_indices.contains(54));
787 assert!(variation_indices.contains(55));
788 assert!(variation_indices.contains(56));
789 }
790}