📄 cairo-type1-subset.c
字号:
"oslash", "oe", "germandbls", 0, 0, 0, 0};static voiduse_standard_encoding_glyph (cairo_type1_font_subset_t *font, int index){ const char *glyph_name; if (index < 0 || index > 255) return; glyph_name = ps_standard_encoding[index]; if (glyph_name == NULL) return; index = cairo_type1_font_subset_lookup_glyph (font, glyph_name, strlen(glyph_name)); if (index < 0) return; cairo_type1_font_subset_use_glyph (font, index);}#define TYPE1_CHARSTRING_COMMAND_ESCAPE (12)#define TYPE1_CHARSTRING_COMMAND_SEAC (32 + 6)static voidcairo_type1_font_subset_look_for_seac(cairo_type1_font_subset_t *font, const char *name, int name_length, const char *encrypted_charstring, int encrypted_charstring_length){ unsigned char *charstring; const unsigned char *end; const unsigned char *p; int stack[5], sp, value; int command; charstring = malloc (encrypted_charstring_length); if (charstring == NULL) return; cairo_type1_font_subset_decrypt_charstring ((const unsigned char *) encrypted_charstring, encrypted_charstring_length, charstring); end = charstring + encrypted_charstring_length; p = charstring + 4; sp = 0; while (p < end) { if (*p < 32) { command = *p++; if (command == TYPE1_CHARSTRING_COMMAND_ESCAPE) command = 32 + *p++; switch (command) { case TYPE1_CHARSTRING_COMMAND_SEAC: /* The seac command takes five integer arguments. The * last two are glyph indices into the PS standard * encoding give the names of the glyphs that this * glyph is composed from. All we need to do is to * make sure those glyphs are present in the subset * under their standard names. */ use_standard_encoding_glyph (font, stack[3]); use_standard_encoding_glyph (font, stack[4]); sp = 0; break; default: sp = 0; break; } } else { /* integer argument */ p = cairo_type1_font_subset_decode_integer (p, &value); if (sp < 5) stack[sp++] = value; } } free (charstring);}static voidwrite_used_glyphs (cairo_type1_font_subset_t *font, const char *name, int name_length, const char *charstring, int charstring_length){ char buffer[256]; int length; length = snprintf (buffer, sizeof buffer, "/%.*s %d %s ", name_length, name, charstring_length, font->rd); cairo_type1_font_subset_write_encrypted (font, buffer, length); cairo_type1_font_subset_write_encrypted (font, charstring, charstring_length); length = snprintf (buffer, sizeof buffer, "%s\n", font->nd); cairo_type1_font_subset_write_encrypted (font, buffer, length);}typedef void (*glyph_func_t) (cairo_type1_font_subset_t *font, const char *name, int name_length, const char *charstring, int charstring_length);static const char *cairo_type1_font_subset_for_each_glyph (cairo_type1_font_subset_t *font, const char *dict_start, const char *dict_end, glyph_func_t func){ int charstring_length, name_length, glyph_index; const char *p, *charstring, *name; char *end; /* We're looking at '/' in the name of the first glyph. The glyph * definitions are on the form: * * /name 23 RD <23 binary bytes> ND * * or alternatively using -| and |- instead of RD and ND. * * We parse the glyph name and see if it is in the subset. If it * is, we call the specified callback with the glyph name and * glyph data, otherwise we just skip it. We need to parse * through a glyph definition; we can't just find the next '/', * since the binary data could contain a '/'. */ p = dict_start; while (*p == '/') { name = p + 1; p = skip_token (p, dict_end); name_length = p - name; charstring_length = strtol (p, &end, 10); if (p == end) { font->status = CAIRO_INT_STATUS_UNSUPPORTED; return NULL; } /* Skip past -| or RD to binary data. There is exactly one space * between the -| or RD token and the encrypted data, thus '+ 1'. */ charstring = skip_token (end, dict_end) + 1; /* Skip binary data and |- or ND token. */ p = skip_token (charstring + charstring_length, dict_end); while (p < dict_end && isspace(*p)) p++; /* In case any of the skip_token() calls above reached EOF, p will * be equal to dict_end. */ if (p == dict_end) { font->status = CAIRO_INT_STATUS_UNSUPPORTED; return NULL; } glyph_index = cairo_type1_font_subset_lookup_glyph (font, name, name_length); if (font->glyphs[glyph_index].subset_index >= 0) func (font, name, name_length, charstring, charstring_length); } return p;}static const char *cairo_type1_font_subset_write_private_dict (cairo_type1_font_subset_t *font, const char *name){ const char *p, *charstrings, *dict_start; const char *closefile_token; char buffer[32], *glyph_count_end; int num_charstrings, length; /* The private dict holds hint information, common subroutines and * the actual glyph definitions (charstrings). * * FIXME: update this comment. * * What we do here is scan directly the /CharString token, which * marks the beginning of the glyph definitions. Then we parse * through the glyph definitions and weed out the glyphs not in * our subset. Everything else before and after the glyph * definitions is copied verbatim to the output. It might be * worthwile to figure out which of the common subroutines are * used by the glyphs in the subset and get rid of the rest. */ /* FIXME: The /Subrs array contains binary data and could * conceivably have "/CharStrings" in it, so we might need to skip * this more cleverly. */ charstrings = find_token (font->cleartext, font->cleartext_end, "/CharStrings"); if (charstrings == NULL) { font->status = CAIRO_INT_STATUS_UNSUPPORTED; return NULL; } /* Scan past /CharStrings and the integer following it. */ p = charstrings + strlen ("/CharStrings"); num_charstrings = strtol (p, &glyph_count_end, 10); if (p == glyph_count_end) { font->status = CAIRO_INT_STATUS_UNSUPPORTED; return NULL; } /* Look for a '/' which marks the beginning of the first glyph * definition. */ for (p = glyph_count_end; p < font->cleartext_end; p++) if (*p == '/') break; if (p == font->cleartext_end) { font->status = CAIRO_INT_STATUS_UNSUPPORTED; return NULL; } dict_start = p; if (cairo_type1_font_subset_get_glyph_names_and_widths (font)) return NULL; /* Now that we have the private dictionary broken down in * sections, do the first pass through the glyph definitions to * figure out which subrs and othersubrs are use and which extra * glyphs may be required by the seac operator. */ p = cairo_type1_font_subset_for_each_glyph (font, dict_start, font->cleartext_end, cairo_type1_font_subset_look_for_seac); closefile_token = find_token (p, font->cleartext_end, "closefile"); if (closefile_token == NULL) { font->status = CAIRO_INT_STATUS_UNSUPPORTED; return NULL; } if (cairo_type1_font_subset_get_glyph_names_and_widths (font)) return NULL; /* We're ready to start outputting. First write the header, * i.e. the public part of the font dict.*/ if (cairo_type1_font_subset_write_header (font, name)) return NULL; font->base.header_size = _cairo_output_stream_get_position (font->output); /* Start outputting the private dict. First output everything up * to the /CharStrings token. */ cairo_type1_font_subset_write_encrypted (font, font->cleartext, charstrings - font->cleartext); /* Write out new charstring count */ length = snprintf (buffer, sizeof buffer, "/CharStrings %d", font->num_glyphs); cairo_type1_font_subset_write_encrypted (font, buffer, length); /* Write out text between the charstring count and the first * charstring definition */ cairo_type1_font_subset_write_encrypted (font, glyph_count_end, dict_start - glyph_count_end); /* Write out the charstring definitions for each of the glyphs in * the subset. */ p = cairo_type1_font_subset_for_each_glyph (font, dict_start, font->cleartext_end, write_used_glyphs); /* Output what's left between the end of the glyph definitions and * the end of the private dict to the output. */ cairo_type1_font_subset_write_encrypted (font, p, closefile_token - p + strlen ("closefile") + 1); _cairo_output_stream_write (font->output, "\n", 1); return p;}static cairo_status_tcairo_type1_font_subset_write_trailer(cairo_type1_font_subset_t *font){ const char *cleartomark_token; int i; static const char zeros[65] = "0000000000000000000000000000000000000000000000000000000000000000\n"; /* Some fonts have conditional save/restore around the entire font * dict, so we need to retain whatever postscript code that may * come after 'cleartomark'. */ for (i = 0; i < 8; i++) _cairo_output_stream_write (font->output, zeros, sizeof zeros); cleartomark_token = find_token (font->type1_data, font->type1_end, "cleartomark"); if (cleartomark_token == NULL) return font->status = CAIRO_INT_STATUS_UNSUPPORTED; _cairo_output_stream_write (font->output, cleartomark_token, font->type1_end - cleartomark_token); return font->status;}static cairo_status_ttype1_font_write (void *closure, const unsigned char *data, unsigned int length){ cairo_type1_font_subset_t *font = closure; font->status = _cairo_array_append_multiple (&font->contents, data, length); return font->status;}static cairo_status_tcairo_type1_font_subset_write (cairo_type1_font_subset_t *font, const char *name){ if (cairo_type1_font_subset_find_segments (font)) return font->status; if (cairo_type1_font_subset_decrypt_eexec_segment (font)) return font->status; /* Determine which glyph definition delimiters to use. */ if (find_token (font->cleartext, font->cleartext_end, "/-|") != NULL) { font->rd = "-|"; font->nd = "|-"; } else if (find_token (font->cleartext, font->cleartext_end, "/RD") != NULL) { font->rd = "RD"; font->nd = "ND"; } else { /* Don't know *what* kind of font this is... */ return font->status = CAIRO_INT_STATUS_UNSUPPORTED; } font->eexec_key = private_dict_key; font->hex_encode = TRUE; font->hex_column = 0; cairo_type1_font_subset_write_private_dict (font, name); font->base.data_size = _cairo_output_stream_get_position (font->output) - font->base.header_size; cairo_type1_font_subset_write_trailer (font); font->base.trailer_size = _cairo_output_stream_get_position (font->output) - font->base.header_size - font->base.data_size; return font->status;}static cairo_status_tcairo_type1_font_subset_generate (void *abstract_font, const char *name){ cairo_type1_font_subset_t *font = abstract_font; cairo_ft_unscaled_font_t *ft_unscaled_font; unsigned long ret; ft_unscaled_font = (cairo_ft_unscaled_font_t *) font->base.unscaled_font; font->face = _cairo_ft_unscaled_font_lock_face (ft_unscaled_font); /* If anything fails below, it's out of memory. */ font->status = CAIRO_STATUS_NO_MEMORY; font->type1_length = font->face->stream->size; font->type1_data = malloc (font->type1_length); if (font->type1_data == NULL) goto fail; if (font->face->stream->read) { ret = font->face->stream->read (font->face->stream, 0, (unsigned char *) font->type1_data, font->type1_length); if (ret != font->type1_length) goto fail; } else { memcpy (font->type1_data, font->face->stream->base, font->type1_length); } if (_cairo_array_grow_by (&font->contents, 4096) != CAIRO_STATUS_SUCCESS) goto fail; font->output = _cairo_output_stream_create (type1_font_write, NULL, font); if (font->output == NULL) goto fail; font->status = CAIRO_STATUS_SUCCESS; cairo_type1_font_subset_write (font, name); font->base.data = _cairo_array_index (&font->contents, 0); fail: _cairo_ft_unscaled_font_unlock_face (ft_unscaled_font); return font->status;}static voidcairo_type1_font_subset_destroy (void *abstract_font){ cairo_type1_font_subset_t *font = abstract_font; int i; /* If the subset generation failed, some of the pointers below may * be NULL depending on at which point the error occurred. */ _cairo_array_fini (&font->contents); free (font->type1_data); if (font->glyphs != NULL) for (i = 0; i < font->base.num_glyphs; i++) { free (font->glyphs[i].name); } _cairo_unscaled_font_destroy (font->base.unscaled_font); free (font->base.base_font); free (font->glyphs); free (font);}cairo_status_t_cairo_type1_subset_init (cairo_type1_subset_t *type1_subset, const char *name, cairo_scaled_font_subset_t *scaled_font_subset){ cairo_type1_font_subset_t *font; cairo_status_t status; unsigned long parent_glyph, length; int i; cairo_unscaled_font_t *unscaled_font; /* XXX: Need to fix this to work with a general cairo_unscaled_font_t. */ if (!_cairo_scaled_font_is_ft (scaled_font_subset->scaled_font)) return CAIRO_INT_STATUS_UNSUPPORTED; unscaled_font = _cairo_ft_scaled_font_get_unscaled_font (scaled_font_subset->scaled_font); status = _cairo_type1_font_subset_create (unscaled_font, &font); if (status) return status; for (i = 0; i < scaled_font_subset->num_glyphs; i++) { parent_glyph = scaled_font_subset->glyphs[i]; cairo_type1_font_subset_use_glyph (font, parent_glyph); } /* Pull in the .notdef glyph */ cairo_type1_font_subset_use_glyph (font, 0); status = cairo_type1_font_subset_generate (font, name); if (status) goto fail1; type1_subset->base_font = strdup (font->base.base_font); if (type1_subset->base_font == NULL) goto fail1; type1_subset->widths = calloc (sizeof (int), font->num_glyphs); if (type1_subset->widths == NULL) goto fail2; for (i = 0; i < font->base.num_glyphs; i++) { if (font->glyphs[i].subset_index < 0) continue; type1_subset->widths[font->glyphs[i].subset_index] = font->glyphs[i].width; } type1_subset->x_min = font->base.x_min; type1_subset->y_min = font->base.y_min; type1_subset->x_max = font->base.x_max; type1_subset->y_max = font->base.y_max; type1_subset->ascent = font->base.ascent; type1_subset->descent = font->base.descent; length = font->base.header_size + font->base.data_size + font->base.trailer_size; type1_subset->data = malloc (length); if (type1_subset->data == NULL) goto fail3; memcpy (type1_subset->data, _cairo_array_index (&font->contents, 0), length); type1_subset->header_length = font->base.header_size; type1_subset->data_length = font->base.data_size; type1_subset->trailer_length = font->base.trailer_size; cairo_type1_font_subset_destroy (font); return CAIRO_STATUS_SUCCESS; fail3: free (type1_subset->widths); fail2: free (type1_subset->base_font); fail1: cairo_type1_font_subset_destroy (font); return status;}void_cairo_type1_subset_fini (cairo_type1_subset_t *subset){ free (subset->base_font); free (subset->widths); free (subset->data);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -