From 89a30637b32edea461746023717f77bd87bb4b10 Mon Sep 17 00:00:00 2001 From: Po Lu Date: Thu, 30 Mar 2023 11:18:51 +0800 Subject: [PATCH] Update Android port * src/sfnt.c (sfnt_make_interpreter): New argument `fvar'. Set axis count. (SCANCTRL): Implement selector bit 8. (GXAXIS): New instruction. (SFVTPV): Validate graphics state after changing freedom vector. (sfnt_line_to_vector): Implement `original'. (sfnt_move): Remove redundant division. (sfnt_interpret_run): Implement distortable font related GXAXIS instruction (0x91). (sfnt_vary_interpreter): Set naxis and norm_coords. (sfnt_make_test_interpreter, pushb_test_args, pushw_test_args) (sfnt_name_instruction, main): Adjust accordingly. * src/sfnt.h (struct sfnt_interpreter, PROTOTYPE): * src/sfntfont.c (sfntfont_setup_interpreter, sfntfont_open): Set up distortion information. --- src/sfnt.c | 111 ++++++++++++++++++++++++++++++++++++++----------- src/sfnt.h | 7 ++++ src/sfntfont.c | 6 ++- 3 files changed, 98 insertions(+), 26 deletions(-) diff --git a/src/sfnt.c b/src/sfnt.c index 4da0997751d..564f5d883bd 100644 --- a/src/sfnt.c +++ b/src/sfnt.c @@ -5445,10 +5445,10 @@ sfnt_init_graphics_state (struct sfnt_graphics_state *state) } /* Set up an interpreter to be used with a font. Use the resource - limits specified in the MAXP table, the values specified in the CVT - and HEAD tables, the pixel size PIXEL_SIZE, and the point size - POINT_SIZE. CVT may be NULL, in which case the interpreter will - not have access to a control value table. + limits specified in the MAXP table, the values specified in the + CVT, HEAD and FVAR tables, the pixel size PIXEL_SIZE, and the point + size POINT_SIZE. CVT may be NULL, in which case the interpreter + will not have access to a control value table. POINT_SIZE should be PIXEL_SIZE, converted to 1/72ths of an inch. @@ -5459,6 +5459,7 @@ TEST_STATIC struct sfnt_interpreter * sfnt_make_interpreter (struct sfnt_maxp_table *maxp, struct sfnt_cvt_table *cvt, struct sfnt_head_table *head, + struct sfnt_fvar_table *fvar, int pixel_size, int point_size) { size_t size, temp, i, storage_size, pad; @@ -5613,6 +5614,18 @@ sfnt_make_interpreter (struct sfnt_maxp_table *maxp, /* Fill in the current call depth. */ interpreter->call_depth = 0; + /* Clear variation axes. They will be set upon a call to + `sfnt_vary_interpreter'. */ + interpreter->n_axis = 0; + interpreter->norm_coords = NULL; + + /* Set n_axis now if a fvar table was provided. This way, GXAXIS + pushes the correct number of values even if no blend is + provided. */ + + if (fvar) + interpreter->n_axis = fvar->axis_count; + /* Return the interpreter. */ return interpreter; } @@ -6483,16 +6496,25 @@ sfnt_interpret_trap (struct sfnt_interpreter *interpreter, interpreter->state.scan_control = value; \ } +/* Selector bit 8 is undocumented, but present in the Macintosh + rasterizer. 02000 is returned if there is a variation axis in + use. */ + #define GETINFO() \ { \ - uint32_t selector; \ + uint32_t selector, k; \ \ selector = POP (); \ \ + k = 0; \ + \ if (selector & 1) \ - PUSH_UNCHECKED (2) \ - else \ - PUSH_UNCHECKED (0) \ + k |= 02; \ + \ + if (selector & 8 && interpreter->n_axis) \ + k |= 02000; \ + \ + PUSH_UNCHECKED (k); \ } #define IDEF() \ @@ -6563,6 +6585,25 @@ sfnt_interpret_trap (struct sfnt_interpreter *interpreter, |= (1 << s); \ } +/* GXAXIS is undocumented. It seems to return each axis in shortFrac + format. */ + +#define GXAXIS() \ + { \ + uint32_t v; \ + int i; \ + \ + for (i = 0; i < interpreter->n_axis; ++i) \ + { \ + if (interpreter->norm_coords) \ + v = interpreter->norm_coords[i] / 4; \ + else \ + v = 0; \ + \ + PUSH (v); \ + } \ + } + #define PUSHB() \ { \ int b, nbytes, IP; \ @@ -6943,6 +6984,8 @@ sfnt_interpret_trap (struct sfnt_interpreter *interpreter, { \ interpreter->state.freedom_vector \ = interpreter->state.projection_vector; \ + \ + sfnt_validate_gs (&interpreter->state); \ } #define ISECT() \ @@ -8231,6 +8274,16 @@ sfnt_line_to_vector (struct sfnt_interpreter *interpreter, sfnt_address_zp1 (interpreter, p1, &x1, &y1, &original_x1, &original_y1); + /* Use original coordinates if specified. */ + + if (original) + { + x2 = original_x2; + y2 = original_y2; + x1 = original_x1; + y1 = original_y1; + } + /* Calculate the vector between X2, Y2, and X1, Y1. */ a = sfnt_sub (x1, x2); b = sfnt_sub (y1, y2); @@ -9392,7 +9445,7 @@ sfnt_move (sfnt_f26dot6 *restrict x, sfnt_f26dot6 *restrict y, size_t n, struct sfnt_interpreter *interpreter, sfnt_f26dot6 distance, unsigned char *flags) { - sfnt_f26dot6 versor; + sfnt_f26dot6 versor, k; sfnt_f2dot14 dot_product; size_t num; @@ -9412,12 +9465,13 @@ sfnt_move (sfnt_f26dot6 *restrict x, sfnt_f26dot6 *restrict y, /* Move along X axis, converting the distance to the freedom vector. */ num = n; + k = sfnt_multiply_divide_signed (distance, + versor, + dot_product); while (num--) { - *x = sfnt_add (*x, sfnt_multiply_divide_signed (distance, - versor, - dot_product)); + *x = sfnt_add (*x, k); x++; if (flags) @@ -9432,12 +9486,13 @@ sfnt_move (sfnt_f26dot6 *restrict x, sfnt_f26dot6 *restrict y, /* Move along X axis, converting the distance to the freedom vector. */ num = n; + k = sfnt_multiply_divide_signed (distance, + versor, + dot_product); while (num--) { - *y = sfnt_add (*y, sfnt_multiply_divide_signed (distance, - versor, - dot_product)); + *y = sfnt_add (*y, k); y++; if (flags) @@ -10747,6 +10802,10 @@ sfnt_interpret_run (struct sfnt_interpreter *interpreter, NOT_IMPLEMENTED (); break; + case 0x91: /* GXAXIS */ + GXAXIS (); + break; + default: if (opcode >= 0xE0) /* MIRP */ { @@ -14895,7 +14954,8 @@ sfnt_vary_compound_glyph (struct sfnt_blend *blend, sfnt_glyph id, } /* Vary the specified INTERPRETER's control value table using the - variations in BLEND's CVT variations table. + variations in BLEND's CVT variations table, then record the blend's + normalized coordinates and axis count in the interpreter. The CVT table used to create INTERPRETER must be the same used to read BLEND->cvar. If not, behavior is undefined. */ @@ -14953,6 +15013,9 @@ sfnt_vary_interpreter (struct sfnt_interpreter *interpreter, interpreter->cvt[i] += delta; } } + + interpreter->n_axis = blend->fvar->axis_count; + interpreter->norm_coords = blend->norm_coords; } @@ -15443,7 +15506,7 @@ sfnt_make_test_interpreter (void) return sfnt_make_interpreter (&test_interpreter_profile, &test_interpreter_cvt, &test_interpreter_head, - 17, 17); + NULL, 17, 17); } struct sfnt_interpreter_test @@ -15938,7 +16001,7 @@ static struct sfnt_generic_test_args npushw_test_args = static struct sfnt_generic_test_args pushb_test_args = { (uint32_t []) { 1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, - 1U, }, + 1U, }, 9, true, 11, @@ -15947,7 +16010,7 @@ static struct sfnt_generic_test_args pushb_test_args = static struct sfnt_generic_test_args pushw_test_args = { (uint32_t []) { 0x203U, 0x204U, 0x205U, 0x206U, 0x207U, 0x208U, - 0x909U, 0x909U, (uint32_t) -1, }, + 0x909U, 0x909U, (uint32_t) -1, }, 9, true, 20, @@ -18347,7 +18410,7 @@ sfnt_name_instruction (unsigned char opcode) "7 INS_$8F", "7 INS_$90", - "7 INS_$91", + "7 GXAXIS", "7 INS_$92", "7 INS_$93", "7 INS_$94", @@ -18924,8 +18987,8 @@ main (int argc, char **argv) return 1; } -#define FANCY_PPEM 36 -#define EASY_PPEM 36 +#define FANCY_PPEM 19 +#define EASY_PPEM 19 interpreter = NULL; head = sfnt_read_head_table (fd, font); @@ -19085,7 +19148,7 @@ main (int argc, char **argv) loca_short->num_offsets); } - interpreter = sfnt_make_interpreter (maxp, cvt, head, + interpreter = sfnt_make_interpreter (maxp, cvt, head, fvar, FANCY_PPEM, FANCY_PPEM); if (instance && gvar) sfnt_vary_interpreter (interpreter, &blend); @@ -19296,7 +19359,7 @@ main (int argc, char **argv) cvt ? cvt->num_elements : 0ul); interpreter = sfnt_make_interpreter (maxp, cvt, head, - FANCY_PPEM, + fvar, FANCY_PPEM, FANCY_PPEM); state = interpreter->state; diff --git a/src/sfnt.h b/src/sfnt.h index 30c82ad3795..58a6de060f4 100644 --- a/src/sfnt.h +++ b/src/sfnt.h @@ -1860,6 +1860,12 @@ struct sfnt_interpreter /* What was the trap. */ const char *trap_reason; + /* Number of variation axes provided by this distortable font. */ + int n_axis; + + /* Normalized axis coordinates set for this distortable font. */ + sfnt_fixed *norm_coords; + #ifdef TEST /* If non-NULL, function called before each instruction is executed. */ @@ -1918,6 +1924,7 @@ extern struct sfnt_prep_table *sfnt_read_prep_table (PROTOTYPE); #define PROTOTYPE \ struct sfnt_maxp_table *, \ struct sfnt_cvt_table *, \ + struct sfnt_fvar_table *, \ struct sfnt_head_table *, \ int, int diff --git a/src/sfntfont.c b/src/sfntfont.c index c9d48f640af..960abe0d270 100644 --- a/src/sfntfont.c +++ b/src/sfntfont.c @@ -2532,7 +2532,7 @@ sfntfont_probe_widths (struct sfnt_font_info *font_info) /* Initialize the instruction interpreter for INFO. Load the font and preprogram for the pixel size in INFO and its corresponding point - size POINT_SIZE. + size POINT_SIZE. Use the FVAR table in DESC. The font tables in INFO must already have been initialized. @@ -2541,6 +2541,7 @@ sfntfont_probe_widths (struct sfnt_font_info *font_info) static void sfntfont_setup_interpreter (struct sfnt_font_info *info, + struct sfnt_font_desc *desc, int point_size) { struct sfnt_cvt_table *cvt; @@ -2575,6 +2576,7 @@ sfntfont_setup_interpreter (struct sfnt_font_info *info, info->head. CVT can be NULL. */ interpreter = sfnt_make_interpreter (info->maxp, cvt, info->head, + desc->tables->fvar, info->font.pixel_size, point_size); @@ -3110,7 +3112,7 @@ sfntfont_open (struct frame *f, Lisp_Object font_entity, point_size = PIXEL_TO_POINT (pixel_size, (dpyinfo->resx * dpyinfo->resy / 2)); - sfntfont_setup_interpreter (font_info, point_size); + sfntfont_setup_interpreter (font_info, desc, point_size); /* If an instance was specified and the font is distortable, set up the blend. */ -- 2.39.2