aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPo Lu2023-03-24 10:43:34 +0800
committerPo Lu2023-03-24 10:43:34 +0800
commitb78ef9bcd1bf34bec877b4fd30f2bbb97cb0919c (patch)
tree08edd2217ebdc9d390db0395065e949241c4191d
parentb26b4c537bb031027dafd4dccda6a8cc5874ce4d (diff)
downloademacs-b78ef9bcd1bf34bec877b4fd30f2bbb97cb0919c.tar.gz
emacs-b78ef9bcd1bf34bec877b4fd30f2bbb97cb0919c.zip
Update Android port
* src/sfnt.c (sfnt_table_names): Add fvar, gvar, cvar. (sfnt_read_maxp_table): Call xmalloc, not malloc. (sfnt_read_simple_glyph): Avoid use-after-free if simple is invalid. (sfnt_fill_span): Fix max coverage. (sfnt_normalize_vector): Fail if magnitude is zero. (sfnt_measure_distance): Fix opcode order. (sfnt_dot_fix_14): Fix implementation. (struct sfnt_variation_axis, struct sfnt_instance) (struct sfnt_fvar_table, struct sfnt_gvar_table) (sfnt_read_fvar_table, sfnt_read_gvar_table, struct sfnt_blend) (sfnt_init_blend, sfnt_free_blend, sfnt_normalize_blend) (struct sfnt_tuple_header, struct sfnt_gvar_glyph_header) (sfnt_read_packed_points, sfnt_read_packed_deltas) (sfnt_compute_tuple_scale, sfnt_infer_deltas_1, sfnt_infer_deltas) (sfnt_vary_glyph): Add WIP variation glyph implementation. * src/sfnt.h (enum sfnt_table, struct sfnt_simple_glyph): Likewise.
-rw-r--r--src/sfnt.c1809
-rw-r--r--src/sfnt.h24
2 files changed, 1795 insertions, 38 deletions
diff --git a/src/sfnt.c b/src/sfnt.c
index bdd713aa016..21b2ea96e1c 100644
--- a/src/sfnt.c
+++ b/src/sfnt.c
@@ -150,6 +150,9 @@ static uint32_t sfnt_table_names[] =
150 [SFNT_TABLE_CVT ] = 0x63767420, 150 [SFNT_TABLE_CVT ] = 0x63767420,
151 [SFNT_TABLE_FPGM] = 0x6670676d, 151 [SFNT_TABLE_FPGM] = 0x6670676d,
152 [SFNT_TABLE_PREP] = 0x70726570, 152 [SFNT_TABLE_PREP] = 0x70726570,
153 [SFNT_TABLE_FVAR] = 0x66766172,
154 [SFNT_TABLE_GVAR] = 0x67766172,
155 [SFNT_TABLE_CVAR] = 0x63766172,
153 }; 156 };
154 157
155/* Swap values from TrueType to system byte order. */ 158/* Swap values from TrueType to system byte order. */
@@ -1614,7 +1617,7 @@ sfnt_read_maxp_table (int fd, struct sfnt_offset_subtable *subtable)
1614 directory->length or sizeof *maxp bytes into it, whichever is 1617 directory->length or sizeof *maxp bytes into it, whichever is
1615 smaller. */ 1618 smaller. */
1616 1619
1617 maxp = malloc (sizeof *maxp); 1620 maxp = xmalloc (sizeof *maxp);
1618 size = MIN (directory->length, sizeof *maxp); 1621 size = MIN (directory->length, sizeof *maxp);
1619 rc = read (fd, maxp, size); 1622 rc = read (fd, maxp, size);
1620 1623
@@ -1917,6 +1920,7 @@ sfnt_read_simple_glyph (struct sfnt_glyph *glyph,
1917 { 1920 {
1918 glyph->simple = NULL; 1921 glyph->simple = NULL;
1919 xfree (simple); 1922 xfree (simple);
1923 return;
1920 } 1924 }
1921 1925
1922 /* Repeat the current flag until 1926 /* Repeat the current flag until
@@ -4227,8 +4231,10 @@ sfnt_fill_span (struct sfnt_raster *raster, sfnt_fixed y,
4227 } 4231 }
4228 4232
4229 /* Clear coverage info for first pixel. Compute coverage for center 4233 /* Clear coverage info for first pixel. Compute coverage for center
4230 pixels. */ 4234 pixels. Note that SFNT_POLY_SAMPLE is used and not
4231 w = coverage[SFNT_POLY_MASK]; 4235 SFNT_POLY_MASK, because coverage has a blank column at the
4236 start. */
4237 w = coverage[SFNT_POLY_SAMPLE];
4232 4238
4233 /* Fill pixels between left and right. */ 4239 /* Fill pixels between left and right. */
4234 while (left + SFNT_POLY_MASK < right) 4240 while (left + SFNT_POLY_MASK < right)
@@ -8080,6 +8086,7 @@ sfnt_normalize_vector (sfnt_f26dot6 vx, sfnt_f26dot6 vy,
8080 /* If vx and vy are both zero, then just project 8086 /* If vx and vy are both zero, then just project
8081 horizontally. */ 8087 horizontally. */
8082 8088
8089 fail:
8083 vector->x = 04000; 8090 vector->x = 04000;
8084 vector->y = 0; 8091 vector->y = 0;
8085 return; 8092 return;
@@ -8113,6 +8120,10 @@ sfnt_normalize_vector (sfnt_f26dot6 vx, sfnt_f26dot6 vy,
8113 /* Get hypotenuse of the triangle from vx, 0, to 0, vy. */ 8120 /* Get hypotenuse of the triangle from vx, 0, to 0, vy. */
8114 magnitude = sfnt_sqrt_fixed (n); 8121 magnitude = sfnt_sqrt_fixed (n);
8115 8122
8123 /* Avoid division by zero. */
8124 if (!magnitude)
8125 goto fail;
8126
8116 /* Long division.. eek! */ 8127 /* Long division.. eek! */
8117 vector->x = (sfnt_div_fixed (vx * 1024, magnitude) >> 2); 8128 vector->x = (sfnt_div_fixed (vx * 1024, magnitude) >> 2);
8118 vector->y = (sfnt_div_fixed (vy * 1024, magnitude) >> 2); 8129 vector->y = (sfnt_div_fixed (vy * 1024, magnitude) >> 2);
@@ -8169,8 +8180,8 @@ sfnt_line_to_vector (struct sfnt_interpreter *interpreter,
8169 relative to the projection or dual projection vector. 8180 relative to the projection or dual projection vector.
8170 8181
8171 Return the distance of P1 and P2 relative to their original 8182 Return the distance of P1 and P2 relative to their original
8172 un-instructed positions should OPCODE be 0x49, and to their 8183 un-instructed positions should OPCODE be 0x4A, and to their
8173 instructed positions should OPCODE be 0x4A. */ 8184 instructed positions should OPCODE be 0x49. */
8174 8185
8175static sfnt_f26dot6 8186static sfnt_f26dot6
8176sfnt_measure_distance (struct sfnt_interpreter *interpreter, 8187sfnt_measure_distance (struct sfnt_interpreter *interpreter,
@@ -8188,25 +8199,9 @@ sfnt_measure_distance (struct sfnt_interpreter *interpreter,
8188 sfnt_address_zp1 (interpreter, p2, &p2x, &p2y, 8199 sfnt_address_zp1 (interpreter, p2, &p2x, &p2y,
8189 &p2_original_x, &p2_original_y); 8200 &p2_original_x, &p2_original_y);
8190 8201
8191 if (opcode == 0x49) 8202 if (opcode == 0x4A)
8192 { 8203 return DUAL_PROJECT (sfnt_sub (p1_original_x, p2_original_x),
8193 /* When measuring in the glyph zone, measure the distance using 8204 sfnt_sub (p1_original_y, p2_original_y));
8194 the dual projection vector, relative to the ``original
8195 original outlines''.
8196
8197 This is not written down anywhere, leading you to believe
8198 that the distance is measured using the scaled outline prior
8199 to instructing. */
8200
8201 if (interpreter->state.zp0 == 1
8202 && interpreter->state.zp1 == 1)
8203 return sfnt_div_fixed (DUAL_PROJECT (sfnt_sub (p1x, p2x),
8204 sfnt_sub (p1y, p2y)),
8205 interpreter->scale);
8206
8207 return DUAL_PROJECT (sfnt_sub (p1x, p2x),
8208 sfnt_sub (p1y, p2y));
8209 }
8210 8205
8211 return PROJECT (sfnt_sub (p1x, p2x), 8206 return PROJECT (sfnt_sub (p1x, p2x),
8212 sfnt_sub (p1y, p2y)); 8207 sfnt_sub (p1y, p2y));
@@ -9238,7 +9233,7 @@ sfnt_dot_fix_14 (int32_t ax, int32_t ay, int bx, int by)
9238 yy = xx >> 63; 9233 yy = xx >> 63;
9239 xx += 0x2000 + yy; 9234 xx += 0x2000 + yy;
9240 9235
9241 return (int32_t) (yy / (2 << 14)); 9236 return (int32_t) (xx / (2 << 14));
9242#endif 9237#endif
9243} 9238}
9244 9239
@@ -11454,6 +11449,8 @@ sfnt_interpret_compound_glyph_1 (struct sfnt_glyph *glyph,
11454 struct sfnt_instructed_outline *value; 11449 struct sfnt_instructed_outline *value;
11455 struct sfnt_glyph_metrics sub_metrics; 11450 struct sfnt_glyph_metrics sub_metrics;
11456 11451
11452 error = NULL;
11453
11457 /* Set up the base index. This is the index from where on point 11454 /* Set up the base index. This is the index from where on point
11458 renumbering starts. 11455 renumbering starts.
11459 11456
@@ -12431,6 +12428,1656 @@ sfnt_read_table (int fd, struct sfnt_offset_subtable *subtable,
12431 12428
12432#endif /* !TEST */ 12429#endif /* !TEST */
12433 12430
12431#ifdef TEST
12432
12433
12434
12435/* Glyph variations. Instead of defining separate fonts for each
12436 combination of weight, width and slant (bold, condensed, italic,
12437 etc), some fonts specify a list of ``variation axes'', each of
12438 which determines one delta to apply to each point in every
12439 glyph.
12440
12441 This optional information is specified in the `fvar' (font
12442 variation), `gvar' (glyph variation) and `cvar' (CVT variation)
12443 tables in a font file. */
12444
12445struct sfnt_variation_axis
12446{
12447 /* The axis tag. */
12448 uint32_t axis_tag;
12449
12450 /* The minimum style coordinate for the axis. */
12451 sfnt_fixed min_value;
12452
12453 /* The default style coordinate for the axis. */
12454 sfnt_fixed default_value;
12455
12456 /* The maximum style coordinate for the axis. */
12457 sfnt_fixed max_value;
12458
12459 /* Set to zero. */
12460 uint16_t flags;
12461
12462 /* Identifier under which this axis's name will be found in the
12463 `name' table. */
12464 uint16_t name_id;
12465};
12466
12467struct sfnt_instance
12468{
12469 /* The instance name ID. */
12470 uint16_t name_id;
12471
12472 /* Flags. */
12473 uint16_t flags;
12474
12475 /* Optional PostScript name. */
12476 uint16_t ps_name_id;
12477
12478 /* Coordinates of each defined instance. */
12479 sfnt_fixed *coords;
12480};
12481
12482struct sfnt_fvar_table
12483{
12484 /* Major version; should be 1. */
12485 uint16_t major_version;
12486
12487 /* Minor version; should be 0. */
12488 uint16_t minor_version;
12489
12490 /* Offset in bytes from the beginning of the table to the beginning
12491 of the first axis data. */
12492 uint16_t offset_to_data;
12493
12494 /* Reserved field; always 2. */
12495 uint16_t count_size_pairs;
12496
12497 /* Number of style axes in this font. */
12498 uint16_t axis_count;
12499
12500 /* The number of bytes in each variation axis record. Currently 20
12501 bytes. */
12502 uint16_t axis_size;
12503
12504 /* The number of named instances for the font found in the
12505 instance array. */
12506 uint16_t instance_count;
12507
12508 /* The size of each instance record. */
12509 uint16_t instance_size;
12510
12511 /* Variable length data. */
12512 struct sfnt_variation_axis *axis;
12513 struct sfnt_instance *instance;
12514};
12515
12516/* Read an fvar table from the given font FD. Use the table directory
12517 specified in SUBTABLE.
12518
12519 Return the fvar table upon success, else NULL. */
12520
12521static struct sfnt_fvar_table *
12522sfnt_read_fvar_table (int fd, struct sfnt_offset_subtable *subtable)
12523{
12524 struct sfnt_table_directory *directory;
12525 struct sfnt_fvar_table *fvar;
12526 ssize_t rc;
12527 size_t min_bytes, ps_size, non_ps_size, temp, pad;
12528 off_t offset;
12529 int i, j;
12530 char *buffer;
12531 sfnt_fixed *coords;
12532
12533 /* Find the table in the directory. */
12534
12535 directory = sfnt_find_table (subtable, SFNT_TABLE_FVAR);
12536
12537 if (!directory)
12538 return NULL;
12539
12540 min_bytes = SFNT_ENDOF (struct sfnt_fvar_table,
12541 instance_size, uint16_t);
12542
12543 /* Check that the length is at least min_bytes. */
12544 if (directory->length < min_bytes)
12545 return NULL;
12546
12547 /* Seek to the location given in the directory. */
12548 if (lseek (fd, directory->offset, SEEK_SET) == (off_t) -1)
12549 return NULL;
12550
12551 /* Allocate enough to hold the fvar table header. */
12552 fvar = xmalloc (sizeof *fvar);
12553
12554 /* Read the fvar table header. */
12555 buffer = NULL;
12556 rc = read (fd, fvar, min_bytes);
12557 if (rc != min_bytes)
12558 goto bail;
12559
12560 /* Swap what was read. */
12561 sfnt_swap16 (&fvar->major_version);
12562 sfnt_swap16 (&fvar->minor_version);
12563 sfnt_swap16 (&fvar->offset_to_data);
12564 sfnt_swap16 (&fvar->count_size_pairs);
12565 sfnt_swap16 (&fvar->axis_count);
12566 sfnt_swap16 (&fvar->axis_size);
12567 sfnt_swap16 (&fvar->instance_count);
12568 sfnt_swap16 (&fvar->instance_size);
12569
12570 /* major_version should be 1, and minor_version 0. */
12571
12572 if (fvar->major_version != 1 || fvar->minor_version)
12573 goto bail;
12574
12575 /* count_size_pairs should be more than 2. */
12576
12577 if (fvar->count_size_pairs < 2)
12578 goto bail;
12579
12580 /* Don't try to read tables where the axis format differs. */
12581
12582 if (fvar->axis_size != 20)
12583 goto bail;
12584
12585 /* The instance size must either be 2 * sizeof (uint16_t) +
12586 axisCount * sizeof (sfnt_fixed), meaning there is no PostScript
12587 name identifier, or 3 * sizeof (uint16_t) + axisCount * sizeof
12588 (sfnt_fixed), meaning there is. */
12589
12590 if (INT_MULTIPLY_WRAPV (fvar->axis_count, sizeof (sfnt_fixed),
12591 &temp)
12592 || INT_ADD_WRAPV (2 * sizeof (uint16_t), temp, &non_ps_size))
12593 goto bail;
12594
12595 if (INT_MULTIPLY_WRAPV (fvar->axis_count, sizeof (sfnt_fixed),
12596 &temp)
12597 || INT_ADD_WRAPV (3 * sizeof (uint16_t), temp, &ps_size))
12598 goto bail;
12599
12600 if (fvar->instance_size != non_ps_size
12601 && fvar->instance_size != ps_size)
12602 goto bail;
12603
12604 /* Now compute the offset of the axis data from the start of the
12605 font file. */
12606
12607 if (INT_ADD_WRAPV (fvar->offset_to_data, directory->offset,
12608 &offset))
12609 goto bail;
12610
12611 /* Seek there. */
12612
12613 if (lseek (fd, offset, SEEK_SET) != offset)
12614 goto bail;
12615
12616 min_bytes = sizeof *fvar;
12617
12618 /* Now, read each axis and instance. Calculate how much extra data
12619 needs to be allocated for the axes and instances: this is
12620 fvar->axis_count * sizeof (struct sfnt_variation_axis), some
12621 padding, and finally fvar->instance_count * sizeof (struct
12622 sfnt_instance) + sizeof (sfnt_fixed) * fvar->instance_count *
12623 fvar->axis_count. */
12624
12625 if (INT_MULTIPLY_WRAPV (fvar->axis_count, sizeof *fvar->axis,
12626 &temp)
12627 || INT_ADD_WRAPV (min_bytes, temp, &min_bytes))
12628 goto bail;
12629
12630 pad = alignof (struct sfnt_variation_axis);
12631 pad -= min_bytes & (pad - 1);
12632
12633 if (INT_ADD_WRAPV (min_bytes, pad, &min_bytes))
12634 goto bail;
12635
12636 if (INT_MULTIPLY_WRAPV (fvar->instance_count,
12637 sizeof *fvar->instance,
12638 &temp)
12639 || INT_ADD_WRAPV (min_bytes, temp, &min_bytes))
12640 goto bail;
12641
12642 if (INT_MULTIPLY_WRAPV (fvar->instance_count,
12643 sizeof *fvar->instance->coords,
12644 &temp)
12645 || INT_MULTIPLY_WRAPV (temp, fvar->axis_count, &temp)
12646 || INT_ADD_WRAPV (min_bytes, temp, &min_bytes))
12647 goto bail;
12648
12649 /* Reallocate fvar. */
12650 fvar = xrealloc (fvar, min_bytes);
12651
12652 /* Fill in offsets. */
12653 fvar->axis = (struct sfnt_variation_axis *) (fvar + 1);
12654 fvar->instance
12655 = (struct sfnt_instance *) (((char *) (fvar->axis
12656 + fvar->axis_count))
12657 + pad);
12658
12659 /* Read axes. */
12660
12661 if (directory->length - SFNT_ENDOF (struct sfnt_fvar_table,
12662 instance_size, uint16_t)
12663 < sizeof *fvar->axis * fvar->axis_count)
12664 goto bail;
12665
12666 rc = read (fd, fvar->axis, sizeof *fvar->axis * fvar->axis_count);
12667 if (rc != sizeof *fvar->axis * fvar->axis_count)
12668 goto bail;
12669
12670 /* Swap each axis. */
12671
12672 for (i = 0; i < fvar->axis_count; ++i)
12673 {
12674 sfnt_swap32 (&fvar->axis[i].axis_tag);
12675 sfnt_swap32 (&fvar->axis[i].min_value);
12676 sfnt_swap32 (&fvar->axis[i].default_value);
12677 sfnt_swap32 (&fvar->axis[i].max_value);
12678 sfnt_swap16 (&fvar->axis[i].flags);
12679 sfnt_swap16 (&fvar->axis[i].name_id);
12680 }
12681
12682 /* Read each instance. */
12683
12684 if (fvar->instance_size < 1024 * 16)
12685 buffer = alloca (fvar->instance_size);
12686 else
12687 buffer = xmalloc (fvar->instance_size);
12688
12689 coords = (sfnt_fixed *) (fvar->instance + fvar->instance_count);
12690
12691 for (i = 0; i < fvar->instance_count; ++i)
12692 {
12693 rc = read (fd, buffer, fvar->instance_size);
12694 if (rc != fvar->instance_size)
12695 goto bail;
12696
12697 /* Fill in various fields. */
12698
12699 fvar->instance[i].name_id = *((uint16_t *) buffer);
12700 fvar->instance[i].flags = *((uint16_t *) buffer + 1);
12701 fvar->instance[i].ps_name_id = 0;
12702
12703 sfnt_swap16 (&fvar->instance[i].name_id);
12704 sfnt_swap16 (&fvar->instance[i].flags);
12705
12706 /* Read coordinates. */
12707
12708 fvar->instance[i].coords = coords;
12709 coords += fvar->axis_count;
12710
12711 memcpy (fvar->instance[i].coords, buffer + 4,
12712 sizeof *fvar->instance[i].coords * fvar->axis_count);
12713
12714 /* Swap coordinates. */
12715
12716 for (j = 0; j < fvar->axis_count; ++j)
12717 sfnt_swap32 (&fvar->instance[i].coords[j]);
12718
12719 /* Read the PostScript name ID if necessary. If not, set it to
12720 nil. */
12721
12722 if (fvar->instance_size == ps_size)
12723 {
12724 fvar->instance[i].ps_name_id
12725 = *(uint16_t *) (buffer + 4 + (sizeof *fvar->instance[i].coords
12726 * fvar->axis_count));
12727 sfnt_swap16 (&fvar->instance[i].ps_name_id);
12728 }
12729 }
12730
12731 /* Free the temporary buffer. */
12732 if (buffer && fvar->instance_size >= 1024 * 16)
12733 xfree (buffer);
12734
12735 /* Return the fvar table. */
12736 return fvar;
12737
12738 bail:
12739 if (buffer && fvar->instance_size >= 1024 * 16)
12740 xfree (buffer);
12741
12742 xfree (fvar);
12743 return NULL;
12744}
12745
12746
12747
12748struct sfnt_gvar_table
12749{
12750 /* Version of the glyph variations table. */
12751 uint16_t version;
12752
12753 /* Reserved, currently 0. */
12754 uint16_t reserved;
12755
12756 /* The number of style axes for this font. This must be the same
12757 number as axisCount in the 'fvar' table. */
12758 uint16_t axis_count;
12759
12760 /* The number of shared coordinates. */
12761 uint16_t shared_coord_count;
12762
12763 /* Byte offset from the beginning of this table to the list of
12764 shared style coordinates. */
12765 uint32_t offset_to_coord;
12766
12767 /* The number of glyphs in this font; this should match the number
12768 of the glyphs store elsewhere in the font. */
12769 uint16_t glyph_count;
12770
12771 /* Bit-field that gives the format of the offset array that
12772 follows. If the flag is 0, the type is uint16. If the flag is 1,
12773 the type is unit 32. */
12774 uint16_t flags;
12775
12776 /* Byte offset from the beginning of this table to the first glyph
12777 glyphVariationData. */
12778 uint32_t offset_to_data;
12779
12780 /* Number of bytes in the glyph variation data. */
12781 size_t data_size;
12782
12783 /* Byte offsets from the beginning of the glyphVariationData array
12784 to the glyphVariationData for each glyph in the font. The format
12785 of this field is set by the flags field. */
12786 union {
12787 uint16_t *offset_word;
12788 uint32_t *offset_long;
12789 } u;
12790
12791 /* Other variable length data. */
12792 sfnt_f2dot14 *global_coords;
12793 unsigned char *glyph_variation_data;
12794};
12795
12796/* Read a gvar table from the given font FD. Use the table directory
12797 specified in SUBTABLE.
12798
12799 Return the gvar table upon success, else NULL. */
12800
12801static struct sfnt_gvar_table *
12802sfnt_read_gvar_table (int fd, struct sfnt_offset_subtable *subtable)
12803{
12804 struct sfnt_table_directory *directory;
12805 struct sfnt_gvar_table *gvar;
12806 ssize_t rc;
12807 size_t min_bytes, off_size, coordinate_size, data_size;
12808 int i;
12809 off_t offset;
12810
12811 /* Find the table in the directory. */
12812
12813 directory = sfnt_find_table (subtable, SFNT_TABLE_GVAR);
12814
12815 if (!directory)
12816 return NULL;
12817
12818 min_bytes = SFNT_ENDOF (struct sfnt_gvar_table,
12819 offset_to_data, uint32_t);
12820
12821 /* Check that the length is at least min_bytes. */
12822 if (directory->length < min_bytes)
12823 return NULL;
12824
12825 /* Seek to the location given in the directory. */
12826 if (lseek (fd, directory->offset, SEEK_SET) == (off_t) -1)
12827 return NULL;
12828
12829 /* Allocate enough to hold the gvar table header. */
12830 gvar = xmalloc (sizeof *gvar);
12831
12832 /* Read the gvar table header. */
12833 rc = read (fd, gvar, min_bytes);
12834 if (rc != min_bytes)
12835 goto bail;
12836
12837 /* Swap what was read. */
12838 sfnt_swap16 (&gvar->version);
12839 sfnt_swap16 (&gvar->reserved);
12840 sfnt_swap16 (&gvar->axis_count);
12841 sfnt_swap16 (&gvar->shared_coord_count);
12842 sfnt_swap32 (&gvar->offset_to_coord);
12843 sfnt_swap16 (&gvar->glyph_count);
12844 sfnt_swap16 (&gvar->flags);
12845 sfnt_swap32 (&gvar->offset_to_data);
12846
12847 if (gvar->version != 1)
12848 goto bail;
12849
12850 if (gvar->offset_to_data > directory->length)
12851 goto bail;
12852
12853 /* Figure out the size required for the offset array. Note that
12854 there is one extra offset at the end of the array to mark the
12855 size of the last glyph. */
12856
12857 if (gvar->flags & 1)
12858 /* Offsets are long words. */
12859 off_size = sizeof (uint32_t) * (gvar->glyph_count + 1);
12860 else
12861 /* Offsets are words. */
12862 off_size = sizeof (uint16_t) * (gvar->glyph_count + 1);
12863
12864 /* Now figure out the size of the shared coordinates. */
12865 coordinate_size = (gvar->shared_coord_count * gvar->axis_count
12866 * sizeof (uint16_t));
12867
12868 /* And the size of the glyph variation data. */
12869 data_size = directory->length - gvar->offset_to_data;
12870
12871 /* Wraparound. */
12872 if (data_size > directory->length)
12873 goto bail;
12874
12875 /* Figure out how big gvar needs to be. */
12876 if (INT_ADD_WRAPV (sizeof *gvar, coordinate_size, &min_bytes)
12877 || INT_ADD_WRAPV (min_bytes, off_size, &min_bytes)
12878 || INT_ADD_WRAPV (min_bytes, data_size, &min_bytes))
12879 goto bail;
12880
12881 /* Now allocate enough for all of this extra data. */
12882 gvar = xrealloc (gvar, min_bytes);
12883
12884 /* Start reading offsets. */
12885
12886 if (!(gvar->flags & 1))
12887 {
12888 gvar->u.offset_word = (uint16_t *) (gvar + 1);
12889 rc = read (fd, gvar->u.offset_word, off_size);
12890 if (rc != off_size)
12891 goto bail;
12892
12893 for (i = 0; i <= gvar->glyph_count; ++i)
12894 sfnt_swap16 (&gvar->u.offset_word[i]);
12895 }
12896 else
12897 {
12898 gvar->u.offset_long = (uint32_t *) (gvar + 1);
12899 rc = read (fd, gvar->u.offset_long, off_size);
12900 if (rc != off_size)
12901 goto bail;
12902
12903 for (i = 0; i <= gvar->glyph_count; ++i)
12904 sfnt_swap32 (&gvar->u.offset_long[i]);
12905 }
12906
12907 /* Start reading shared coordinates. */
12908
12909 gvar->global_coords = ((sfnt_f2dot14 *) ((char *) gvar + off_size));
12910
12911 if (gvar->shared_coord_count)
12912 {
12913 if (INT_ADD_WRAPV (gvar->offset_to_coord, directory->offset,
12914 &offset))
12915 goto bail;
12916
12917 if (lseek (fd, offset, SEEK_SET) != offset)
12918 goto bail;
12919
12920 if (read (fd, gvar->global_coords, coordinate_size)
12921 != coordinate_size)
12922 goto bail;
12923
12924 for (i = 0; i <= coordinate_size / sizeof *gvar->global_coords; ++i)
12925 sfnt_swap16 (&gvar->global_coords[i]);
12926 }
12927
12928 /* Finally, read the rest of the glyph variation data. */
12929 gvar->data_size = data_size;
12930 gvar->glyph_variation_data
12931 = (unsigned char *) (gvar->global_coords
12932 + (coordinate_size
12933 / sizeof *gvar->global_coords));
12934
12935 if (gvar->data_size)
12936 {
12937 if (INT_ADD_WRAPV (gvar->offset_to_data, directory->offset,
12938 &offset))
12939 goto bail;
12940
12941 if (lseek (fd, offset, SEEK_SET) != offset)
12942 goto bail;
12943
12944 if (read (fd, gvar->glyph_variation_data,
12945 gvar->data_size) != gvar->data_size)
12946 goto bail;
12947 }
12948
12949 /* Return the read gvar table. */
12950 return gvar;
12951
12952 bail:
12953 xfree (gvar);
12954 return NULL;
12955}
12956
12957
12958
12959/* Structure repesenting a set of axis coordinates and their
12960 normalized equivalents.
12961
12962 To use this structure, call
12963
12964 sfnt_init_blend (&blend, fvar, gvar)
12965
12966 on a `struct sfnt_blend *', with an appropriate fvar and gvar
12967 table.
12968
12969 Then, fill in blend.coords with the un-normalized coordinates,
12970 and call
12971
12972 sfnt_normalize_blend (&blend)
12973
12974 finally, call sfnt_vary_glyph and related functions. */
12975
12976struct sfnt_blend
12977{
12978 /* The fvar table. This determines the number of elements in each
12979 of the arrays below. */
12980 struct sfnt_fvar_table *fvar;
12981
12982 /* The gvar table. This provides the glyph variation data. */
12983 struct sfnt_gvar_table *gvar;
12984
12985 /* Un-normalized coordinates. */
12986 sfnt_fixed *coords;
12987
12988 /* Normalized coordinates. */
12989 sfnt_fixed *norm_coords;
12990};
12991
12992/* Initialize the specified BLEND with the given FVAR and GVAR
12993 tables. */
12994
12995static void
12996sfnt_init_blend (struct sfnt_blend *blend, struct sfnt_fvar_table *fvar,
12997 struct sfnt_gvar_table *gvar)
12998{
12999 size_t size;
13000
13001 blend->fvar = fvar;
13002 blend->gvar = gvar;
13003
13004 /* Allocate a single array to hold both coords and norm_coords. */
13005 size = (fvar->axis_count * sizeof *blend->coords * 2);
13006 blend->coords = xmalloc (size);
13007 blend->norm_coords = blend->coords + fvar->axis_count;
13008}
13009
13010/* Free what was initialized in the specified BLEND. */
13011
13012static void
13013sfnt_free_blend (struct sfnt_blend *blend)
13014{
13015 xfree (blend->coords);
13016}
13017
13018/* Normalize BLEND->fvar->axis_count coordinates in BLEND->coords and
13019 place the result in BLEND->norm_coords. */
13020
13021static void
13022sfnt_normalize_blend (struct sfnt_blend *blend)
13023{
13024 struct sfnt_variation_axis *axis;
13025 int i;
13026 sfnt_fixed coord;
13027
13028 /* For each axis... */
13029 for (i = 0; i < blend->fvar->axis_count; ++i)
13030 {
13031 /* Normalize based on [min, default, max], into [-1, 0, 1]. */
13032 axis = &blend->fvar->axis[i];
13033
13034 /* Load the current design coordinate. */
13035 coord = blend->coords[i];
13036
13037 /* Keep it within bounds. */
13038
13039 if (coord > axis->max_value)
13040 coord = axis->max_value;
13041 else if (coord < axis->min_value)
13042 coord = axis->min_value;
13043
13044 if (coord > axis->default_value)
13045 {
13046 /* Avoid division by 0. */
13047 if (axis->max_value != axis->default_value)
13048 blend->norm_coords[i]
13049 = sfnt_div_fixed (sfnt_sub (coord, axis->default_value),
13050 sfnt_sub (axis->max_value,
13051 axis->default_value));
13052 else
13053 blend->norm_coords[i] = 0;
13054 }
13055 else if (coord < axis->default_value)
13056 {
13057 if (axis->default_value != axis->min_value)
13058 blend->norm_coords[i]
13059 = sfnt_div_fixed (sfnt_sub (coord, axis->default_value),
13060 sfnt_sub (axis->default_value,
13061 axis->min_value));
13062 else
13063 blend->norm_coords[i] = 0;
13064 }
13065 else
13066 blend->norm_coords[i] = 0;
13067 }
13068
13069 /* TODO: process avar tables. */
13070}
13071
13072
13073
13074struct sfnt_tuple_header
13075{
13076 /* The size in bytes of the serialized data for this tuple variation
13077 table. */
13078 uint16_t variation_data_size;
13079
13080 /* A packed field. The high 4 bits are flags (see below). The low 12
13081 bits are an index into a shared tuple records array. */
13082 uint16_t tuple_index;
13083
13084 /* Embedded coordinate tuples, if any. */
13085 sfnt_f2dot14 *embedded_coord;
13086
13087 /* Intermediate coordinate tuples, if any. */
13088 sfnt_f2dot14 *intermediate_coord;
13089
13090 /* Number of points associated with this tuple.
13091 Times two, the number of deltas associated with this tuple. */
13092 uint16_t npoints;
13093
13094 /* Points associated with this tuple. */
13095 uint16_t *points;
13096
13097 /* Deltas associated with this tuple. */
13098 sfnt_fword *deltas;
13099};
13100
13101struct sfnt_gvar_glyph_header
13102{
13103 /* A packed field. The high 4 bits are flags and the low 12 bits are
13104 the number of tuples for this glyph. The number of tuples can be
13105 any number between 1 and 4095. */
13106 uint16_t tuple_count;
13107
13108 /* Offset from the start of the GlyphVariationData table to the
13109 serialized data. */
13110 uint16_t data_offset;
13111};
13112
13113/* Read a sequence of packed points starting from DATA. Return the
13114 number of points read in *NPOINTS_RETURN and the array of unpacked
13115 points, or NULL upon failure.
13116
13117 If non-NULL, set LOCATION to DATA plus the number of bytes read
13118 upon success.
13119
13120 Return (uint16_t *) -1 if there are no points at all.
13121 In this case, deltas will apply to all points in the glyph,
13122 and *NPOINTS_RETURN will be UINT16_MAX.
13123
13124 END is one byte past the last byte in DATA. */
13125
13126static uint16_t *
13127sfnt_read_packed_points (unsigned char *restrict data,
13128 uint16_t *npoints_return,
13129 unsigned char *restrict end,
13130 unsigned char *restrict *location)
13131{
13132 int npoints;
13133 uint16_t *points;
13134 int i, first, control;
13135
13136 points = NULL;
13137 npoints = 0;
13138
13139 if (data >= end)
13140 return NULL;
13141
13142 /* Load the control byte. */
13143 control = *data++;
13144
13145 if (!control)
13146 {
13147 *npoints_return = UINT16_MAX;
13148 *location = data;
13149 return (uint16_t *) -1;
13150 }
13151
13152 /* Now figure out the number of points within. */
13153
13154 if (control & 0x80)
13155 {
13156 npoints = control & 0x7f;
13157 npoints <<= 8;
13158
13159 if (data >= end)
13160 return NULL;
13161
13162 npoints |= *data++;
13163 }
13164 else
13165 npoints = control;
13166
13167 /* Start reading points. */
13168 first = 0;
13169 i = 0;
13170 points = xmalloc (sizeof *points * npoints);
13171
13172 while (i < npoints)
13173 {
13174 if (data >= end)
13175 goto bail;
13176
13177 control = *data++;
13178
13179 if (control & 0x80)
13180 {
13181 /* Next control & 0x7f words are points. */
13182
13183 control &= 0x7f;
13184
13185 while (control != -1 && i < npoints)
13186 {
13187 if (data >= end || data + 1 >= end)
13188 goto bail;
13189
13190 first += *data++ << 8u;
13191 first += *data++;
13192 points[i] = first;
13193 control -= 1, ++i;
13194 }
13195 }
13196 else
13197 {
13198 /* Next control bytes are points. */
13199
13200 while (control != -1 && i < npoints)
13201 {
13202 if (data >= end)
13203 goto bail;
13204
13205 first += *data++;
13206 points[i] = first;
13207 control -= 1, ++i;
13208 }
13209 }
13210 }
13211
13212 /* Return the points read. */
13213 *npoints_return = npoints;
13214 *location = data;
13215 return points;
13216
13217 bail:
13218 xfree (points);
13219 return NULL;
13220}
13221
13222/* Read and return N packed deltas from DATA. Set *DATA_RETURN to
13223 DATA plus the number of bytes read.
13224
13225 END is the end of the glyph variation data. Value is an array of N
13226 deltas upon success, and NULL upon failure. */
13227
13228static sfnt_fword *
13229sfnt_read_packed_deltas (unsigned char *restrict data,
13230 unsigned char *restrict end,
13231 int n,
13232 unsigned char *restrict *data_return)
13233{
13234 sfnt_fword *deltas;
13235 int i, count;
13236 unsigned char control;
13237
13238 if (data >= end)
13239 return NULL;
13240
13241 deltas = xmalloc (sizeof *deltas * n);
13242 i = 0;
13243
13244 while (i < n)
13245 {
13246 if (data >= end)
13247 goto fail;
13248
13249 control = *data++;
13250 count = control & 0x3f;
13251
13252 while (count != -1 && i < n)
13253 {
13254 if (control & 0x80)
13255 deltas[i++] = 0;
13256 else if (control & 0x40)
13257 {
13258 if (data + 1 >= end)
13259 goto fail;
13260
13261 deltas[i] = (signed char) *data++;
13262 deltas[i] *= 65536;
13263 deltas[i++] |= *data++;
13264 }
13265 else
13266 {
13267 if (data >= end)
13268 goto fail;
13269
13270 deltas[i++] = (signed char) *data++;
13271 }
13272
13273 --count;
13274 }
13275 }
13276
13277 *data_return = data;
13278 return deltas;
13279
13280 fail:
13281 xfree (deltas);
13282 return NULL;
13283}
13284
13285/* Given a BLEND containing normalized coordinates, an array of
13286 BLEND->gvar->axis_count tuple coordinates, and, if INTERMEDIATE_P,
13287 a range of tuple coordinates from INTERMEDIATE_START to
13288 INTERMEDIATE_END, return the scaling factor to apply to deltas for
13289 each corresponding point. */
13290
13291static sfnt_fixed
13292sfnt_compute_tuple_scale (struct sfnt_blend *blend, bool intermediate_p,
13293 sfnt_f2dot14 *coords,
13294 sfnt_f2dot14 *intermediate_start,
13295 sfnt_f2dot14 *intermediate_end)
13296{
13297 int i;
13298 sfnt_fixed coord, start, end;
13299 sfnt_fixed scale;
13300
13301 /* scale is initially 1.0. */
13302 scale = 0200000;
13303
13304 for (i = 0; i < blend->gvar->axis_count; ++i)
13305 {
13306 /* Load values for this axis, scaled up to sfnt_fixed. */
13307 coord = coords[i] * 4;
13308
13309 if (intermediate_p)
13310 {
13311 start = intermediate_start[i] * 4;
13312 end = intermediate_start[i] * 4;
13313 }
13314
13315 /* Ignore tuples that can be skipped. */
13316
13317 if (!coord)
13318 continue;
13319
13320 /* If the coordinate is set to 0, then deltas should not be
13321 applied. Return 0. */
13322
13323 if (!blend->norm_coords[i])
13324 return 0;
13325
13326 /* If no scaling need take place, continue. */
13327
13328 if (blend->norm_coords[i] == coord)
13329 continue;
13330
13331 if (!intermediate_p)
13332 {
13333 /* Not an intermediate tuple; if coord is less than 0 and
13334 blend->norm_coords[i] < coord, or coord is more than 0
13335 and blend->norm_coords[i] > coord, then it doesn't fit,
13336 so return. */
13337
13338 if (blend->norm_coords[i] < MIN (0, coord)
13339 || blend->norm_coords[i] > MAX (0, coord))
13340 return 0;
13341
13342 scale = sfnt_multiply_divide_signed (scale,
13343 blend->norm_coords[i],
13344 coord);
13345 }
13346 else
13347 {
13348 /* Otherwise, renormalize between start and end. */
13349
13350 if (blend->norm_coords[i] < start
13351 || blend->norm_coords[i] > end)
13352 return 0;
13353
13354 if (blend->norm_coords[i] < coord)
13355 scale = sfnt_multiply_divide (scale,
13356 blend->norm_coords[i] - start,
13357 coord - start);
13358 else
13359 scale = sfnt_multiply_divide (scale,
13360 end - blend->norm_coords[i],
13361 end - coord);
13362 }
13363 }
13364
13365 return scale;
13366}
13367
13368/* Infer point positions for points that have been partially moved
13369 within the contour in GLYPH denoted by START and END. */
13370
13371static void
13372sfnt_infer_deltas_1 (struct sfnt_glyph *glyph, size_t start,
13373 size_t end, bool *touched, sfnt_fword *x,
13374 sfnt_fword *y)
13375{
13376 size_t i, pair_start, pair_end, pair_first, j;
13377 sfnt_fword min_pos, max_pos, position;
13378 sfnt_fixed ratio, delta;
13379
13380 pair_start = pair_first = -1;
13381
13382 /* Look for pairs of touched points. */
13383
13384 for (i = start; i <= end; ++i)
13385 {
13386 if (!touched[i])
13387 continue;
13388
13389 if (pair_start == -1)
13390 {
13391 pair_first = i;
13392 goto next;
13393 }
13394
13395 pair_end = i;
13396
13397 /* pair_start to pair_end are now a pair of points, where points
13398 in between should be interpolated. */
13399
13400 for (j = pair_start + 1; j < pair_end; ++j)
13401 {
13402 /* Consider the X axis. Set min_pos and max_pos to the
13403 smallest and greatest values along that axis. */
13404 min_pos = MIN (x[pair_start], x[pair_end]);
13405 max_pos = MAX (x[pair_start], x[pair_end]);
13406
13407 /* Now see if the current point lies between min and
13408 max... */
13409 if (x[j] >= min_pos && x[j] <= max_pos)
13410 {
13411 /* If min_pos and max_pos are the same, apply
13412 pair_start's delta if it is identical to that of
13413 pair_end, or apply nothing at all otherwise. */
13414
13415 if (min_pos == max_pos)
13416 {
13417 if ((glyph->simple->x_coordinates[pair_start]
13418 - x[pair_start])
13419 == (glyph->simple->x_coordinates[pair_end]
13420 - x[pair_end]))
13421 glyph->simple->x_coordinates[j]
13422 += (glyph->simple->x_coordinates[pair_start]
13423 - x[pair_start]);
13424
13425 continue;
13426 }
13427
13428 /* Interpolate between min_pos and max_pos. */
13429 ratio = sfnt_div_fixed ((sfnt_sub (x[j], min_pos)
13430 * 65536),
13431 (sfnt_sub (max_pos, min_pos)
13432 * 65536));
13433
13434 /* Load the current positions of pair_start and pair_end
13435 along this axis. */
13436 min_pos = MIN (glyph->simple->x_coordinates[pair_start],
13437 glyph->simple->x_coordinates[pair_end]);
13438 max_pos = MAX (glyph->simple->x_coordinates[pair_start],
13439 glyph->simple->x_coordinates[pair_end]);
13440
13441 /* Lerp in between. */
13442 delta = sfnt_sub (max_pos, min_pos);
13443 delta = sfnt_mul_fixed (ratio, delta);
13444 glyph->simple->x_coordinates[j] = min_pos + delta;
13445 }
13446 else
13447 {
13448 /* ... otheriwse, move point j by the delta of the
13449 nearest touched point. */
13450
13451 if (x[j] >= max_pos)
13452 {
13453 position = MAX (glyph->simple->x_coordinates[pair_start],
13454 glyph->simple->x_coordinates[pair_end]);
13455 delta = position - max_pos;
13456 }
13457 else
13458 {
13459 position = MIN (glyph->simple->x_coordinates[pair_start],
13460 glyph->simple->x_coordinates[pair_end]);
13461 delta = position - min_pos;
13462 }
13463
13464 glyph->simple->x_coordinates[j] = x[j] + delta;
13465 }
13466
13467 /* Now, consider the Y axis. */
13468 min_pos = MIN (y[pair_start], y[pair_end]);
13469 max_pos = MAX (y[pair_start], y[pair_end]);
13470
13471 /* Now see if the current point lies between min and
13472 max... */
13473 if (y[j] >= min_pos && y[j] <= max_pos)
13474 {
13475 /* If min_pos and max_pos are the same, apply
13476 pair_start's delta if it is identical to that of
13477 pair_end, or apply nothing at all otherwise. */
13478
13479 if (min_pos == max_pos)
13480 {
13481 if ((glyph->simple->y_coordinates[pair_start]
13482 - y[pair_start])
13483 == (glyph->simple->y_coordinates[pair_end]
13484 - y[pair_end]))
13485 glyph->simple->y_coordinates[j]
13486 += (glyph->simple->y_coordinates[pair_start]
13487 - y[pair_start]);
13488
13489 continue;
13490 }
13491
13492 /* Interpolate between min_pos and max_pos. */
13493 ratio = sfnt_div_fixed ((sfnt_sub (y[j], min_pos)
13494 * 65536),
13495 (sfnt_sub (max_pos, min_pos)
13496 * 65536));
13497
13498 /* Load the current positions of pair_start and pair_end
13499 along this axis. */
13500 min_pos = MIN (glyph->simple->y_coordinates[pair_start],
13501 glyph->simple->y_coordinates[pair_end]);
13502 max_pos = MAX (glyph->simple->y_coordinates[pair_start],
13503 glyph->simple->y_coordinates[pair_end]);
13504
13505 /* Lerp in between. */
13506 delta = sfnt_sub (max_pos, min_pos);
13507 delta = sfnt_mul_fixed (ratio, delta);
13508 glyph->simple->y_coordinates[j] = min_pos + delta;
13509 }
13510 else
13511 {
13512 /* ... otheriwse, move point j by the delta of the
13513 nearest touched point. */
13514
13515 if (y[j] >= max_pos)
13516 {
13517 position = MAX (glyph->simple->y_coordinates[pair_start],
13518 glyph->simple->y_coordinates[pair_end]);
13519 delta = position - max_pos;
13520 }
13521 else
13522 {
13523 position = MIN (glyph->simple->y_coordinates[pair_start],
13524 glyph->simple->y_coordinates[pair_end]);
13525 delta = position - min_pos;
13526 }
13527
13528 glyph->simple->y_coordinates[j] = y[j] + delta;
13529 }
13530 }
13531
13532 next:
13533 pair_start = i;
13534 }
13535
13536 /* If pair_start is set, then lerp points between it and
13537 pair_first. */
13538
13539 if (pair_start != (size_t) -1)
13540 {
13541 j = pair_start + 1;
13542
13543 if (j > end)
13544 j = start;
13545
13546 pair_end = pair_first;
13547
13548 while (j != pair_first)
13549 {
13550 /* Consider the X axis. Set min_pos and max_pos to the
13551 smallest and greatest values along that axis. */
13552 min_pos = MIN (x[pair_start], x[pair_end]);
13553 max_pos = MAX (x[pair_start], x[pair_end]);
13554
13555 /* Now see if the current point lies between min and
13556 max... */
13557 if (x[j] >= min_pos && x[j] <= max_pos)
13558 {
13559 /* If min_pos and max_pos are the same, apply
13560 pair_start's delta if it is identical to that of
13561 pair_end, or apply nothing at all otherwise. */
13562
13563 if (min_pos == max_pos)
13564 {
13565 if ((glyph->simple->x_coordinates[pair_start]
13566 - x[pair_start])
13567 == (glyph->simple->x_coordinates[pair_end]
13568 - x[pair_end]))
13569 glyph->simple->x_coordinates[j]
13570 += (glyph->simple->x_coordinates[pair_start]
13571 - x[pair_start]);
13572
13573 goto next_1;
13574 }
13575
13576 /* Interpolate between min_pos and max_pos. */
13577 ratio = sfnt_div_fixed ((sfnt_sub (x[j], min_pos)
13578 * 65536),
13579 (sfnt_sub (max_pos, min_pos)
13580 * 65536));
13581
13582 /* Load the current positions of pair_start and pair_end
13583 along this axis. */
13584 min_pos = MIN (glyph->simple->x_coordinates[pair_start],
13585 glyph->simple->x_coordinates[pair_end]);
13586 max_pos = MAX (glyph->simple->x_coordinates[pair_start],
13587 glyph->simple->x_coordinates[pair_end]);
13588
13589 /* Lerp in between. */
13590 delta = sfnt_sub (max_pos, min_pos);
13591 delta = sfnt_mul_fixed (ratio, delta);
13592 glyph->simple->x_coordinates[j] = min_pos + delta;
13593 }
13594 else
13595 {
13596 /* ... otheriwse, move point j by the delta of the
13597 nearest touched point. */
13598
13599 if (x[j] >= max_pos)
13600 {
13601 position = MAX (glyph->simple->x_coordinates[pair_start],
13602 glyph->simple->x_coordinates[pair_end]);
13603 delta = position - max_pos;
13604 }
13605 else
13606 {
13607 position = MIN (glyph->simple->x_coordinates[pair_start],
13608 glyph->simple->x_coordinates[pair_end]);
13609 delta = position - min_pos;
13610 }
13611
13612 glyph->simple->x_coordinates[j] = x[j] + delta;
13613 }
13614
13615 /* Now, consider the Y axis. */
13616 min_pos = MIN (y[pair_start], y[pair_end]);
13617 max_pos = MAX (y[pair_start], y[pair_end]);
13618
13619 /* Now see if the current point lies between min and
13620 max... */
13621 if (y[j] >= min_pos && y[j] <= max_pos)
13622 {
13623 /* If min_pos and max_pos are the same, apply
13624 pair_start's delta if it is identical to that of
13625 pair_end, or apply nothing at all otherwise. */
13626
13627 if (min_pos == max_pos)
13628 {
13629 if ((glyph->simple->y_coordinates[pair_start]
13630 - y[pair_start])
13631 == (glyph->simple->y_coordinates[pair_end]
13632 - y[pair_end]))
13633 glyph->simple->y_coordinates[j]
13634 += (glyph->simple->y_coordinates[pair_start]
13635 - y[pair_start]);
13636
13637 goto next_1;
13638 }
13639
13640 /* Interpolate between min_pos and max_pos. */
13641 ratio = sfnt_div_fixed ((sfnt_sub (y[j], min_pos)
13642 * 65536),
13643 (sfnt_sub (max_pos, min_pos)
13644 * 65536));
13645
13646 /* Load the current positions of pair_start and pair_end
13647 along this axis. */
13648 min_pos = MIN (glyph->simple->y_coordinates[pair_start],
13649 glyph->simple->y_coordinates[pair_end]);
13650 max_pos = MAX (glyph->simple->y_coordinates[pair_start],
13651 glyph->simple->y_coordinates[pair_end]);
13652
13653 /* Lerp in between. */
13654 delta = sfnt_sub (max_pos, min_pos);
13655 delta = sfnt_mul_fixed (ratio, delta);
13656 glyph->simple->y_coordinates[j] = min_pos + delta;
13657 }
13658 else
13659 {
13660 /* ... otheriwse, move point j by the delta of the
13661 nearest touched point. */
13662
13663 if (y[j] >= max_pos)
13664 {
13665 position = MAX (glyph->simple->y_coordinates[pair_start],
13666 glyph->simple->y_coordinates[pair_end]);
13667 delta = position - max_pos;
13668 }
13669 else
13670 {
13671 position = MIN (glyph->simple->y_coordinates[pair_start],
13672 glyph->simple->y_coordinates[pair_end]);
13673 delta = position - min_pos;
13674 }
13675
13676 glyph->simple->y_coordinates[j] = y[j] + delta;
13677 }
13678
13679 next_1:
13680 j++;
13681 if (j > end)
13682 j = start;
13683 }
13684 }
13685}
13686
13687/* Infer point positions for contours that have been partially moved
13688 by variation. For each contour in GLYPH, find pairs of points
13689 which have had deltas applied. For each such pair, interpolate
13690 points between the first point in the pair and the second by
13691 considering each point along every one of the two axes (X and Y)
13692 like so:
13693
13694 - For each point that lies between the first point and the last
13695 on the axis currently being considered, interpolate its
13696 position in that axis so that the ratio between the first
13697 point and the last in the original outline still holds.
13698
13699 - For each point that lies to the left or top of the first point
13700 on the axis being considered, use the delta of the first point.
13701
13702 - And finally, for each point that lies to the right or bottom of
13703 the last point on that axis, use the delta of the last
13704 point.
13705
13706 X and Y contain the original positions positions of each point.
13707 TOUCHED contains whether or not each point has been changed by
13708 an explicitly specified delta.
13709
13710 Apply the inferred deltas back to GLYPH. */
13711
13712static void
13713sfnt_infer_deltas (struct sfnt_glyph *glyph, bool *touched,
13714 sfnt_fword *x, sfnt_fword *y)
13715{
13716 size_t i;
13717 int point, first, end;
13718
13719 point = 0;
13720 for (i = 0; i < glyph->number_of_contours; ++i)
13721 {
13722 first = point;
13723 end = glyph->simple->end_pts_of_contours[i];
13724
13725 /* Return if the glyph is invalid. */
13726
13727 if (first >= glyph->simple->number_of_points
13728 || end >= glyph->simple->number_of_points
13729 || first > end)
13730 return;
13731
13732 sfnt_infer_deltas_1 (glyph, first, end, touched, x, y);
13733 point = end + 1;
13734 }
13735}
13736
13737/* Read the glyph variation data for the specified glyph ID from
13738 BLEND's gvar table. Apply the offsets to each point in the
13739 specified simple GLYPH, based on the specified BLEND.
13740
13741 Value is 0 upon success, else 1.
13742
13743 The glyph variation data consists of a number of elements, each of
13744 which has its own associated point numbers and deltas, and a list
13745 of one or two coordinates for each axis. Each such list is
13746 referred to as a ``tuple''.
13747
13748 The deltas, one for each point, are multipled by the normalized
13749 value of each axis and applied to those points for each tuple that
13750 is found to be applicable.
13751
13752 Each element of the glyph variation data is applicable to an axis
13753 if its list of coordinates:
13754
13755 - contains one element for each axis, and its axis has a value
13756 between 0 and that element.
13757
13758 - contains two elements for each axis, and its axis has a value
13759 between the first element and the second.
13760
13761 After the deltas are applied, any points without deltas must be
13762 interpolated similar to an IUP instruction. In addition, deltas
13763 may also be applied to phantom points within a glyph. */
13764
13765static int
13766sfnt_vary_glyph (struct sfnt_blend *blend, sfnt_glyph id,
13767 struct sfnt_glyph *glyph)
13768{
13769 uint32_t offset;
13770 struct sfnt_gvar_glyph_header header;
13771 uint16_t *points, npoints;
13772 int i, ntuples, j, point_count;
13773 unsigned char *tuple, *end, *data;
13774 uint16_t data_size, index, *glyph_points;
13775 sfnt_f2dot14 *restrict coords;
13776 sfnt_f2dot14 *restrict intermediate_start;
13777 sfnt_f2dot14 *restrict intermediate_end;
13778 sfnt_fword *dx, *dy, fword;
13779 struct sfnt_gvar_table *gvar;
13780 uint16_t *local_points, n_local_points;
13781 sfnt_fixed scale;
13782 ptrdiff_t data_offset;
13783 bool *touched;
13784 sfnt_fword *restrict original_x, *restrict original_y;
13785
13786 gvar = blend->gvar;
13787
13788 if (gvar->axis_count != blend->fvar->axis_count)
13789 return 1;
13790
13791 if (gvar->glyph_count <= id)
13792 return 1;
13793
13794 if (gvar->flags & 1)
13795 offset = gvar->u.offset_long[id];
13796 else
13797 offset = gvar->u.offset_word[id] * 2u;
13798
13799 if (offset >= gvar->data_size)
13800 return 1;
13801
13802 end = gvar->glyph_variation_data + gvar->data_size;
13803
13804 /* Start reading the header. */
13805
13806 if (offset + sizeof header > gvar->data_size)
13807 return 1;
13808
13809 memcpy (&header, gvar->glyph_variation_data + offset,
13810 sizeof header);
13811
13812 /* Swap the header. */
13813 sfnt_swap16 (&header.tuple_count);
13814 sfnt_swap16 (&header.data_offset);
13815
13816 /* Prepare to read each tuple. */
13817 ntuples = header.tuple_count & 0x0fff;
13818
13819 /* Initialize the data offset. This is incremented with each tuple
13820 read. */
13821 data_offset = header.data_offset;
13822
13823 /* If gvar->flags & tuples_share_point_numbers, read the shared
13824 point numbers. */
13825
13826 npoints = 0;
13827
13828 if (header.tuple_count & 0x8000)
13829 {
13830 data = gvar->glyph_variation_data + offset + data_offset;
13831 points = sfnt_read_packed_points (data, &npoints, end,
13832 &tuple);
13833
13834 if (!points)
13835 return 1;
13836
13837 /* Shared point numbers are part of the data after the tuple
13838 array. Thus, increment data_offset by tuple - data. `tuple'
13839 here holds no relation to a pointer to the current part of
13840 the tuple array that is being read later on. */
13841 data_offset += tuple - data;
13842 }
13843 else
13844 points = NULL;
13845
13846 /* Start reading each tuple. */
13847 tuple = gvar->glyph_variation_data + offset + sizeof header;
13848
13849 coords = xmalloc (gvar->axis_count * sizeof *coords * 3);
13850 intermediate_start = coords + gvar->axis_count;
13851 intermediate_end = coords + gvar->axis_count;
13852
13853 /* Allocate arrays of booleans and fwords to keep track of which
13854 points have been touched. */
13855 touched = NULL;
13856 original_x = NULL;
13857 original_y = NULL;
13858
13859 for (i = 0; i < ntuples; ++i)
13860 {
13861 data = gvar->glyph_variation_data + offset + data_offset;
13862
13863 if (tuple + 3 >= end)
13864 goto fail1;
13865
13866 memcpy (&data_size, tuple, sizeof data_size);
13867 tuple += sizeof data_size;
13868 memcpy (&index, tuple, sizeof index);
13869 tuple += sizeof index;
13870 sfnt_swap16 (&data_size);
13871 sfnt_swap16 (&index);
13872
13873 /* Increment the offset to the data by the data size specified
13874 here. */
13875 data_offset += data_size;
13876
13877 if (index & 0x8000)
13878 {
13879 /* Embedded coordinates are present. Read each
13880 coordinate and add it to the tuple. */
13881 for (j = 0; j < gvar->axis_count; ++j)
13882 {
13883 if (tuple + 1 >= end)
13884 goto fail1;
13885
13886 memcpy (&coords[j], tuple, sizeof *coords);
13887 tuple += sizeof *coords;
13888 sfnt_swap16 (&coords[j]);
13889 }
13890 }
13891 else if ((index & 0xfff) > gvar->shared_coord_count)
13892 /* index exceeds the number of shared tuples present. */
13893 goto fail1;
13894 else
13895 /* index points into gvar->axis_count coordinates making up
13896 the tuple. */
13897 memcpy (coords, (gvar->global_coords
13898 + ((index & 0xfff) * gvar->axis_count)),
13899 gvar->axis_count * sizeof *coords);
13900
13901 /* Now read indeterminate tuples if required. */
13902 if (index & 0x1000)
13903 {
13904 for (j = 0; j < gvar->axis_count; ++j)
13905 {
13906 if (tuple + 1 >= end)
13907 goto fail1;
13908
13909 memcpy (&intermediate_start[j], tuple,
13910 sizeof *intermediate_start);
13911 tuple += sizeof *intermediate_start;
13912 sfnt_swap16 (&intermediate_start[j]);
13913 }
13914
13915 for (j = 0; j < gvar->axis_count; ++j)
13916 {
13917 if (tuple + 1 >= end)
13918 goto fail1;
13919
13920 memcpy (&intermediate_end[j], tuple,
13921 sizeof *intermediate_end);
13922 tuple += sizeof *intermediate_end;
13923 sfnt_swap16 (&intermediate_end[j]);
13924 }
13925 }
13926
13927 /* See whether or not the tuple applies to the current variation
13928 configuration, and how much to scale them by. */
13929
13930 scale = sfnt_compute_tuple_scale (blend, index & 0x1000,
13931 coords, intermediate_start,
13932 intermediate_end);
13933
13934 if (!scale)
13935 continue;
13936
13937 local_points = NULL;
13938
13939 /* Finally, read private point numbers.
13940 Set local_points to those numbers; it will be freed
13941 once the loop ends. */
13942
13943 if (index & 0x2000)
13944 {
13945 local_points = sfnt_read_packed_points (data, &n_local_points,
13946 end, &data);
13947 if (!local_points)
13948 goto fail1;
13949
13950 point_count = n_local_points;
13951 glyph_points = local_points;
13952 }
13953 else
13954 {
13955 /* If there are no private point numbers, use global
13956 points. */
13957 point_count = npoints;
13958 glyph_points = points;
13959 }
13960
13961 /* Now, read packed deltas. */
13962
13963 dx = NULL;
13964 dy = NULL;
13965
13966 switch (point_count)
13967 {
13968 case UINT16_MAX:
13969 /* Deltas are provided for all points in the glyph.
13970 No glyph should have more than 65535 points. */
13971
13972 if (glyph->simple->number_of_points > 65535)
13973 abort ();
13974
13975 /* Add 4 phantom points to each end. */
13976 dx = sfnt_read_packed_deltas (data, end,
13977 glyph->simple->number_of_points + 4,
13978 &data);
13979 dy = sfnt_read_packed_deltas (data, end,
13980 glyph->simple->number_of_points + 4,
13981 &data);
13982
13983 if (!dx || !dy)
13984 goto fail3;
13985
13986 /* Apply each delta to the simple glyph. */
13987
13988 for (i = 0; i < glyph->simple->number_of_points; ++i)
13989 {
13990 fword = sfnt_mul_fixed (dx[i], scale);
13991 glyph->simple->x_coordinates[i] += fword;
13992 fword = sfnt_mul_fixed (dy[i], scale);
13993 glyph->simple->y_coordinates[i] += fword;
13994 }
13995
13996 /* TODO: apply metrics variations. */
13997 break;
13998
13999 default:
14000 dx = sfnt_read_packed_deltas (data, end, point_count, &data);
14001 dy = sfnt_read_packed_deltas (data, end, point_count, &data);
14002
14003 if (!dx || !dy)
14004 goto fail3;
14005
14006 /* Deltas are only applied for each point number read. */
14007
14008 if (!original_x)
14009 {
14010 touched = xmalloc (sizeof *touched
14011 * glyph->simple->number_of_points);
14012 original_x = xmalloc (sizeof *original_x * 2
14013 * glyph->simple->number_of_points);
14014 original_y = original_x + glyph->simple->number_of_points;
14015 memcpy (original_x, glyph->simple->x_coordinates,
14016 (sizeof *original_x
14017 * glyph->simple->number_of_points));
14018 memcpy (original_y, glyph->simple->y_coordinates,
14019 (sizeof *original_y
14020 * glyph->simple->number_of_points));
14021 }
14022
14023 memset (touched, 0, (sizeof *touched
14024 * glyph->simple->number_of_points));
14025
14026 for (i = 0; i < point_count; ++i)
14027 {
14028 /* Make sure the point doesn't end up out of bounds. */
14029 if (glyph_points[i] >= glyph->simple->number_of_points)
14030 continue;
14031
14032 fword = sfnt_mul_fixed (dx[i], scale);
14033 glyph->simple->x_coordinates[glyph_points[i]] += fword;
14034 fword = sfnt_mul_fixed (dy[i], scale);
14035 glyph->simple->y_coordinates[glyph_points[i]] += fword;
14036 touched[glyph_points[i]] = true;
14037 }
14038
14039 sfnt_infer_deltas (glyph, touched, original_x,
14040 original_y);
14041
14042 /* TODO: apply metrics variations. */
14043 break;
14044 }
14045
14046 xfree (dx);
14047 xfree (dy);
14048
14049 if (local_points != (uint16_t *) -1)
14050 xfree (local_points);
14051 }
14052
14053 /* Return success. */
14054
14055 xfree (touched);
14056 xfree (coords);
14057 xfree (original_x);
14058
14059 if (points != (uint16_t *) -1)
14060 xfree (points);
14061
14062 return 0;
14063
14064 fail3:
14065 xfree (dx);
14066 xfree (dy);
14067 xfree (local_points);
14068 fail1:
14069 xfree (touched);
14070 xfree (coords);
14071 xfree (original_x);
14072
14073 if (points != (uint16_t *) -1)
14074 xfree (points);
14075
14076 return 1;
14077}
14078
14079#endif /* TEST */
14080
12434 14081
12435 14082
12436#ifdef TEST 14083#ifdef TEST
@@ -16262,15 +17909,22 @@ main (int argc, char **argv)
16262 struct sfnt_prep_table *prep; 17909 struct sfnt_prep_table *prep;
16263 struct sfnt_graphics_state state; 17910 struct sfnt_graphics_state state;
16264 struct sfnt_instructed_outline *value; 17911 struct sfnt_instructed_outline *value;
17912 struct sfnt_fvar_table *fvar;
17913 struct sfnt_gvar_table *gvar;
16265 sfnt_fixed scale; 17914 sfnt_fixed scale;
16266 char *fancy; 17915 char *fancy;
16267 int *advances; 17916 int *advances;
16268 struct sfnt_raster **rasters; 17917 struct sfnt_raster **rasters;
16269 size_t length; 17918 size_t length;
17919 char *axis_name;
17920 struct sfnt_instance *instance;
17921 struct sfnt_blend blend;
16270 17922
16271 if (argc < 2) 17923 if (argc < 2)
16272 return 1; 17924 return 1;
16273 17925
17926 instance = NULL;
17927
16274 if (!strcmp (argv[1], "--check-interpreter")) 17928 if (!strcmp (argv[1], "--check-interpreter"))
16275 { 17929 {
16276 interpreter = sfnt_make_test_interpreter (); 17930 interpreter = sfnt_make_test_interpreter ();
@@ -16324,7 +17978,7 @@ main (int argc, char **argv)
16324 font = sfnt_read_table_directory (fd); 17978 font = sfnt_read_table_directory (fd);
16325 } 17979 }
16326 17980
16327 if (!font) 17981 if (!font || font == (struct sfnt_offset_subtable *) -1)
16328 { 17982 {
16329 close (fd); 17983 close (fd);
16330 return 1; 17984 return 1;
@@ -16375,8 +18029,8 @@ main (int argc, char **argv)
16375 return 1; 18029 return 1;
16376 } 18030 }
16377 18031
16378#define FANCY_PPEM 25 18032#define FANCY_PPEM 12
16379#define EASY_PPEM 25 18033#define EASY_PPEM 12
16380 18034
16381 interpreter = NULL; 18035 interpreter = NULL;
16382 head = sfnt_read_head_table (fd, font); 18036 head = sfnt_read_head_table (fd, font);
@@ -16388,16 +18042,18 @@ main (int argc, char **argv)
16388 cvt = sfnt_read_cvt_table (fd, font); 18042 cvt = sfnt_read_cvt_table (fd, font);
16389 fpgm = sfnt_read_fpgm_table (fd, font); 18043 fpgm = sfnt_read_fpgm_table (fd, font);
16390 prep = sfnt_read_prep_table (fd, font); 18044 prep = sfnt_read_prep_table (fd, font);
18045 fvar = sfnt_read_fvar_table (fd, font);
18046 gvar = sfnt_read_gvar_table (fd, font);
16391 hmtx = NULL; 18047 hmtx = NULL;
16392 18048
16393 exec_prep = prep; 18049 exec_prep = prep;
16394 exec_fpgm = fpgm; 18050 exec_fpgm = fpgm;
16395 18051 fancy = getenv ("SFNT_FANCY_TEST");
16396 if (getenv ("SFNT_FANCY_TEST")) 18052
18053 if (fancy)
16397 { 18054 {
16398 loca_long = NULL; 18055 loca_long = NULL;
16399 loca_short = NULL; 18056 loca_short = NULL;
16400 fancy = getenv ("SFNT_FANCY_TEST");
16401 length = strlen (fancy); 18057 length = strlen (fancy);
16402 scale = sfnt_div_fixed (FANCY_PPEM, head->units_per_em); 18058 scale = sfnt_div_fixed (FANCY_PPEM, head->units_per_em);
16403 18059
@@ -16659,6 +18315,82 @@ main (int argc, char **argv)
16659 (int) hhea->caret_slope_rise, 18315 (int) hhea->caret_slope_rise,
16660 (int) hhea->caret_slope_run); 18316 (int) hhea->caret_slope_run);
16661 18317
18318 if (fvar)
18319 {
18320 fprintf (stderr, "FVAR table found!\n"
18321 "version: %"PRIu16".%"PRIu16"\n"
18322 "axis_count: %"PRIu16"\n"
18323 "axis_size: %"PRIu16"\n"
18324 "instance_count: %"PRIu16"\n"
18325 "instance_size: %"PRIu16"\n",
18326 fvar->major_version,
18327 fvar->minor_version,
18328 fvar->axis_count,
18329 fvar->axis_size,
18330 fvar->instance_count,
18331 fvar->instance_size);
18332
18333 for (i = 0; i < fvar->axis_count; ++i)
18334 {
18335 if (name)
18336 {
18337 axis_name
18338 = (char *) sfnt_find_name (name, fvar->axis[i].name_id,
18339 &record);
18340
18341 if (axis_name)
18342 fprintf (stderr, "axis no: %d; name: %.*s\n",
18343 i, record.length, axis_name);
18344 }
18345
18346 fprintf (stderr, " axis: %"PRIx32" %g %g %g\n",
18347 fvar->axis[i].axis_tag,
18348 sfnt_coerce_fixed (fvar->axis[i].min_value),
18349 sfnt_coerce_fixed (fvar->axis[i].default_value),
18350 sfnt_coerce_fixed (fvar->axis[i].max_value));
18351 }
18352
18353 for (i = 0; i < fvar->instance_count; ++i)
18354 {
18355 if (name)
18356 {
18357 axis_name
18358 = (char *) sfnt_find_name (name, fvar->instance[i].name_id,
18359 &record);
18360
18361 if (axis_name)
18362 fprintf (stderr, "instance no: %d; name: %.*s\n",
18363 i, record.length, axis_name);
18364 }
18365 }
18366
18367 if (fvar->instance_count > 1)
18368 {
18369 printf ("instance? ");
18370
18371 if (scanf ("%d", &i) == EOF)
18372 goto free_lab;
18373
18374 if (i < 0 || i >= fvar->instance_count)
18375 goto free_lab;
18376
18377 instance = &fvar->instance[i];
18378 }
18379 }
18380
18381 if (gvar)
18382 fprintf (stderr, "gvar table found\n");
18383
18384 if (instance && gvar)
18385 {
18386 sfnt_init_blend (&blend, fvar, gvar);
18387
18388 for (i = 0; i < fvar->axis_count; ++i)
18389 blend.coords[i] = instance->coords[i];
18390
18391 sfnt_normalize_blend (&blend);
18392 }
18393
16662 while (true) 18394 while (true)
16663 { 18395 {
16664 printf ("table, character? "); 18396 printf ("table, character? ");
@@ -16696,6 +18428,14 @@ main (int argc, char **argv)
16696 dcontext.loca_short = loca_short; 18428 dcontext.loca_short = loca_short;
16697 dcontext.loca_long = loca_long; 18429 dcontext.loca_long = loca_long;
16698 18430
18431 if (glyph->simple && instance && gvar)
18432 {
18433 printf ("applying variations to simple glyph...\n");
18434
18435 if (sfnt_vary_glyph (&blend, code, glyph))
18436 printf ("variation failed!\n");
18437 }
18438
16699 if (sfnt_decompose_glyph (glyph, sfnt_test_move_to, 18439 if (sfnt_decompose_glyph (glyph, sfnt_test_move_to,
16700 sfnt_test_line_to, 18440 sfnt_test_line_to,
16701 sfnt_test_curve_to, 18441 sfnt_test_curve_to,
@@ -16871,6 +18611,8 @@ main (int argc, char **argv)
16871 } 18611 }
16872 } 18612 }
16873 18613
18614 free_lab:
18615
16874 xfree (font); 18616 xfree (font);
16875 18617
16876 for (i = 0; i < table->num_subtables; ++i) 18618 for (i = 0; i < table->num_subtables; ++i)
@@ -16893,6 +18635,11 @@ main (int argc, char **argv)
16893 xfree (fpgm); 18635 xfree (fpgm);
16894 xfree (interpreter); 18636 xfree (interpreter);
16895 xfree (prep); 18637 xfree (prep);
18638 xfree (fvar);
18639 xfree (gvar);
18640
18641 if (instance && gvar)
18642 sfnt_free_blend (&blend);
16896 18643
16897 return 0; 18644 return 0;
16898} 18645}
diff --git a/src/sfnt.h b/src/sfnt.h
index 83d34bfb757..82fa343f51d 100644
--- a/src/sfnt.h
+++ b/src/sfnt.h
@@ -53,6 +53,9 @@ enum sfnt_table
53 SFNT_TABLE_CVT , 53 SFNT_TABLE_CVT ,
54 SFNT_TABLE_FPGM, 54 SFNT_TABLE_FPGM,
55 SFNT_TABLE_PREP, 55 SFNT_TABLE_PREP,
56 SFNT_TABLE_FVAR,
57 SFNT_TABLE_GVAR,
58 SFNT_TABLE_CVAR,
56 }; 59 };
57 60
58#define SFNT_ENDOF(type, field, type1) \ 61#define SFNT_ENDOF(type, field, type1) \
@@ -61,7 +64,14 @@ enum sfnt_table
61/* Each of these structures must be aligned so that no compiler will 64/* Each of these structures must be aligned so that no compiler will
62 ever generate padding bytes on platforms where the alignment 65 ever generate padding bytes on platforms where the alignment
63 requirements for uint32_t and uint16_t are no larger than 4 and 2 66 requirements for uint32_t and uint16_t are no larger than 4 and 2
64 bytes respectively. */ 67 bytes respectively.
68
69 Pointer types are assumed to impose an alignmnent requirement no
70 less than that of uint32_t.
71
72 If a table has more than one kind of variable-length subtable array
73 at the end, make sure to pad subsequent subtables
74 appropriately. */
65 75
66struct sfnt_offset_subtable 76struct sfnt_offset_subtable
67{ 77{
@@ -568,25 +578,25 @@ struct sfnt_simple_glyph
568 size_t number_of_points; 578 size_t number_of_points;
569 579
570 /* Array containing the last points of each contour. */ 580 /* Array containing the last points of each contour. */
571 uint16_t *end_pts_of_contours; 581 uint16_t *restrict end_pts_of_contours;
572 582
573 /* Total number of bytes needed for instructions. */ 583 /* Total number of bytes needed for instructions. */
574 uint16_t instruction_length; 584 uint16_t instruction_length;
575 585
576 /* Instruction data. */ 586 /* Instruction data. */
577 uint8_t *instructions; 587 uint8_t *restrict instructions;
578 588
579 /* Array of flags. */ 589 /* Array of flags. */
580 uint8_t *flags; 590 uint8_t *restrict flags;
581 591
582 /* Array of X coordinates. */ 592 /* Array of X coordinates. */
583 int16_t *x_coordinates; 593 int16_t *restrict x_coordinates;
584 594
585 /* Array of Y coordinates. */ 595 /* Array of Y coordinates. */
586 int16_t *y_coordinates; 596 int16_t *restrict y_coordinates;
587 597
588 /* Pointer to the end of that array. */ 598 /* Pointer to the end of that array. */
589 int16_t *y_coordinates_end; 599 int16_t *restrict y_coordinates_end;
590}; 600};
591 601
592struct sfnt_compound_glyph_component 602struct sfnt_compound_glyph_component