📄 cairo-type1-subset.c
字号:
/* cairo - a vector graphics library with display and print output * * Copyright © 2006 Red Hat, Inc * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * (the "LGPL") or, at your option, under the terms of the Mozilla * Public License Version 1.1 (the "MPL"). If you do not alter this * notice, a recipient may use your version of this file under either * the MPL or the LGPL. * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * * The contents of this file are subject to the Mozilla Public License * Version 1.1 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY * OF ANY KIND, either express or implied. See the LGPL or the MPL for * the specific language governing rights and limitations. * * The Original Code is the cairo graphics library. * * The Initial Developer of the Original Code is Red Hat, Inc. * * Contributor(s): * Kristian Høgsberg <krh@redhat.com> */#include "cairoint.h"#include "cairo-scaled-font-subsets-private.h"#include "cairo-output-stream-private.h"/* XXX: Eventually, we need to handle other font backends */#include "cairo-ft-private.h"#include <ft2build.h>#include FT_FREETYPE_H#include FT_OUTLINE_H#include FT_TYPE1_TABLES_Htypedef struct _cairo_type1_font_subset { cairo_scaled_font_subset_t *scaled_font_subset; struct { cairo_unscaled_font_t *unscaled_font; unsigned int font_id; char *base_font; int num_glyphs; long x_min, y_min, x_max, y_max; long ascent, descent; const char *data; unsigned long header_size; unsigned long data_size; unsigned long trailer_size; } base; FT_Face face; int num_glyphs; struct { int subset_index; int width; char *name; } *glyphs; cairo_output_stream_t *output; cairo_array_t contents; const char *rd, *nd; char *type1_data; unsigned int type1_length; char *type1_end; char *header_segment; int header_segment_size; char *eexec_segment; int eexec_segment_size; cairo_bool_t eexec_segment_is_ascii; char *cleartext; char *cleartext_end; int header_size; unsigned short eexec_key; cairo_bool_t hex_encode; int hex_column; cairo_status_t status;} cairo_type1_font_subset_t;static cairo_status_t_cairo_type1_font_subset_create (cairo_unscaled_font_t *unscaled_font, cairo_type1_font_subset_t **subset_return){ cairo_ft_unscaled_font_t *ft_unscaled_font; FT_Face face; PS_FontInfoRec font_info; cairo_type1_font_subset_t *font; int i, j; ft_unscaled_font = (cairo_ft_unscaled_font_t *) unscaled_font; face = _cairo_ft_unscaled_font_lock_face (ft_unscaled_font); if (FT_Get_PS_Font_Info(face, &font_info) != 0) return CAIRO_INT_STATUS_UNSUPPORTED; font = calloc (sizeof (cairo_type1_font_subset_t), 1); if (font == NULL) return CAIRO_STATUS_NO_MEMORY; font->base.unscaled_font = _cairo_unscaled_font_reference (unscaled_font); font->base.num_glyphs = face->num_glyphs; font->base.x_min = face->bbox.xMin; font->base.y_min = face->bbox.yMin; font->base.x_max = face->bbox.xMax; font->base.y_max = face->bbox.yMax; font->base.ascent = face->ascender; font->base.descent = face->descender; font->base.base_font = strdup (face->family_name); if (font->base.base_font == NULL) goto fail1; for (i = 0, j = 0; font->base.base_font[j]; j++) { if (font->base.base_font[j] == ' ') continue; font->base.base_font[i++] = font->base.base_font[j]; } font->base.base_font[i] = '\0'; font->glyphs = calloc (face->num_glyphs, sizeof font->glyphs[0]); if (font->glyphs == NULL) goto fail2; font->num_glyphs = 0; for (i = 0; i < face->num_glyphs; i++) font->glyphs[i].subset_index = -1; _cairo_array_init (&font->contents, sizeof (char)); _cairo_ft_unscaled_font_unlock_face (ft_unscaled_font); *subset_return = font; return CAIRO_STATUS_SUCCESS; fail2: free (font->base.base_font); fail1: free (font); return CAIRO_STATUS_NO_MEMORY;}static intcairo_type1_font_subset_use_glyph (cairo_type1_font_subset_t *font, int glyph){ if (font->glyphs[glyph].subset_index >= 0) return font->glyphs[glyph].subset_index; font->glyphs[glyph].subset_index = font->num_glyphs; font->num_glyphs++; return font->glyphs[glyph].subset_index;}/* Magic constants for the type1 eexec encryption */static const unsigned short c1 = 52845, c2 = 22719;static const unsigned short private_dict_key = 55665;static const unsigned short charstring_key = 4330;static cairo_bool_tis_ps_delimiter(int c){ const static char delimiters[] = "()[]{}<>/% \t\r\n"; return strchr (delimiters, c) != NULL;}static const char *find_token (const char *buffer, const char *end, const char *token){ int i, length; /* FIXME: find substring really must be find_token */ length = strlen (token); for (i = 0; buffer + i < end - length + 1; i++) if (memcmp (buffer + i, token, length) == 0) if ((i == 0 || token[0] == '/' || is_ps_delimiter(buffer[i - 1])) && (buffer + i == end - length || is_ps_delimiter(buffer[i + length]))) return buffer + i; return NULL;}static cairo_status_tcairo_type1_font_subset_find_segments (cairo_type1_font_subset_t *font){ unsigned char *p; const char *eexec_token; int size; p = (unsigned char *) font->type1_data; font->type1_end = font->type1_data + font->type1_length; if (p[0] == 0x80 && p[1] == 0x01) { font->header_segment_size = p[2] | (p[3] << 8) | (p[4] << 16) | (p[5] << 24); font->header_segment = (char *) p + 6; p += 6 + font->header_segment_size; font->eexec_segment_size = p[2] | (p[3] << 8) | (p[4] << 16) | (p[5] << 24); font->eexec_segment = (char *) p + 6; font->eexec_segment_is_ascii = (p[1] == 1); p += 6 + font->eexec_segment_size; while (p < (unsigned char *) (font->type1_end) && p[1] != 0x03) { size = p[2] | (p[3] << 8) | (p[4] << 16) | (p[5] << 24); p += 6 + size; } font->type1_end = (char *) p; } else { eexec_token = find_token ((char *) p, font->type1_end, "eexec"); if (eexec_token == NULL) return font->status = CAIRO_INT_STATUS_UNSUPPORTED; font->header_segment_size = eexec_token - (char *) p + strlen ("eexec\n"); font->header_segment = (char *) p; font->eexec_segment_size = font->type1_length - font->header_segment_size; font->eexec_segment = (char *) p + font->header_segment_size; font->eexec_segment_is_ascii = TRUE; } return CAIRO_STATUS_SUCCESS;}static cairo_status_tcairo_type1_font_subset_write_header (cairo_type1_font_subset_t *font, const char *name){ const char *start, *end, *segment_end; int i; segment_end = font->header_segment + font->header_segment_size; start = find_token (font->header_segment, segment_end, "/FontName"); if (start == NULL) return font->status = CAIRO_INT_STATUS_UNSUPPORTED; _cairo_output_stream_write (font->output, font->header_segment, start - font->header_segment); _cairo_output_stream_printf (font->output, "/FontName /%s def", name); end = find_token (start, segment_end, "def"); if (end == NULL) return font->status = CAIRO_INT_STATUS_UNSUPPORTED; end += 3; start = find_token (end, segment_end, "/Encoding"); if (start == NULL) return font->status = CAIRO_INT_STATUS_UNSUPPORTED; _cairo_output_stream_write (font->output, end, start - end); _cairo_output_stream_printf (font->output, "/Encoding 256 array\n" "0 1 255 {1 index exch /.notdef put} for\n"); for (i = 0; i < font->base.num_glyphs; i++) { if (font->glyphs[i].subset_index < 0) continue; _cairo_output_stream_printf (font->output, "dup %d /%s put\n", font->glyphs[i].subset_index, font->glyphs[i].name); } _cairo_output_stream_printf (font->output, "readonly def"); end = find_token (start, segment_end, "def"); if (end == NULL) return font->status = CAIRO_INT_STATUS_UNSUPPORTED; end += 3; _cairo_output_stream_write (font->output, end, segment_end - end); return font->status;}static inthex_to_int (int ch){ if (ch <= '9') return ch - '0'; else if (ch <= 'F') return ch - 'A' + 10; else return ch - 'a' + 10;}static voidcairo_type1_font_subset_write_encrypted (cairo_type1_font_subset_t *font, const char *data, unsigned int length){ const unsigned char *in, *end; int c, p; static const char hex_digits[16] = "0123456789abcdef"; char digits[3]; in = (const unsigned char *) data; end = (const unsigned char *) data + length; while (in < end) { p = *in++; c = p ^ (font->eexec_key >> 8); font->eexec_key = (c + font->eexec_key) * c1 + c2; if (font->hex_encode) { digits[0] = hex_digits[c >> 4]; digits[1] = hex_digits[c & 0x0f]; digits[2] = '\n'; font->hex_column += 2; if (font->hex_column == 78) { _cairo_output_stream_write (font->output, digits, 3); font->hex_column = 0; } else { _cairo_output_stream_write (font->output, digits, 2); } } else { digits[0] = c; _cairo_output_stream_write (font->output, digits, 1); } }}static cairo_status_tcairo_type1_font_subset_decrypt_eexec_segment (cairo_type1_font_subset_t *font){ unsigned short r = private_dict_key; unsigned char *in, *end; char *out; int c, p; in = (unsigned char *) font->eexec_segment; end = (unsigned char *) in + font->eexec_segment_size; font->cleartext = malloc (font->eexec_segment_size); if (font->cleartext == NULL) return font->status = CAIRO_STATUS_NO_MEMORY; out = font->cleartext; while (in < end) { if (font->eexec_segment_is_ascii) { c = *in++; if (isspace (c)) continue; c = (hex_to_int (c) << 4) | hex_to_int (*in++); } else { c = *in++; } p = c ^ (r >> 8); r = (c + r) * c1 + c2; *out++ = p; } font->cleartext_end = out; return font->status;}static const char *skip_token (const char *p, const char *end){ while (p < end && isspace(*p)) p++; while (p < end && !isspace(*p)) p++; if (p == end) return NULL; return p;}static intcairo_type1_font_subset_lookup_glyph (cairo_type1_font_subset_t *font, const char *glyph_name, int length){ int i; for (i = 0; i < font->base.num_glyphs; i++) { if (font->glyphs[i].name && strncmp (font->glyphs[i].name, glyph_name, length) == 0 && font->glyphs[i].name[length] == '\0') return i; } return -1;}static cairo_status_tcairo_type1_font_subset_get_glyph_names_and_widths (cairo_type1_font_subset_t *font){ int i; char buffer[256]; FT_Error error; /* Get glyph names and width using the freetype API */ for (i = 0; i < font->base.num_glyphs; i++) { if (font->glyphs[i].name != NULL) continue; error = FT_Load_Glyph (font->face, i, FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_TRANSFORM); if (error != 0) { printf ("could not load glyph %d\n", i); return font->status = CAIRO_STATUS_NO_MEMORY; } font->glyphs[i].width = font->face->glyph->metrics.horiAdvance; error = FT_Get_Glyph_Name(font->face, i, buffer, sizeof buffer); if (error != 0) { printf ("could not get glyph name for glyph %d\n", i); return font->status = CAIRO_STATUS_NO_MEMORY; } font->glyphs[i].name = strdup (buffer); if (font->glyphs[i].name == NULL) return font->status = CAIRO_STATUS_NO_MEMORY; } return CAIRO_STATUS_SUCCESS;}static voidcairo_type1_font_subset_decrypt_charstring (const unsigned char *in, int size, unsigned char *out){ unsigned short r = charstring_key; int c, p, i; for (i = 0; i < size; i++) { c = *in++; p = c ^ (r >> 8); r = (c + r) * c1 + c2; *out++ = p; }}static const unsigned char *cairo_type1_font_subset_decode_integer (const unsigned char *p, int *integer){ if (*p <= 246) { *integer = *p++ - 139; } else if (*p <= 250) { *integer = (p[0] - 247) * 256 + p[1] + 108; p += 2; } else if (*p <= 254) { *integer = -(p[0] - 251) * 256 - p[1] - 108; p += 2; } else { *integer = (p[1] << 24) | (p[2] << 16) | (p[3] << 8) | p[4]; p += 5; } return p;}static const char *ps_standard_encoding[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16 */ "space", "exclam", "quotedbl", "numbersign", /* 32 */ "dollar", "percent", "ampersand", "quoteright", "parenleft", "parenright", "asterisk", "plus", "comma", "hyphen", "period", "slash", "zero", "one", "two", "three", /* 48 */ "four", "five", "six", "seven", "eight", "nine", "colon", "semicolon", "less", "equal", "greater", "question", "at", "A", "B", "C", "D", "E", "F", "G", "H", /* 64 */ "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", /* 80 */ "Y", "Z", "bracketleft", "backslash", "bracketright", "asciicircum", "underscore", "quoteleft", "a", "b", "c", "d", "e", "f", "g", "h", /* 96 */ "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", /* 112 */ "y", "z", "braceleft", "bar", "braceright", "asciitilde", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 144 */ "exclamdown", "cent", "sterling", "fraction", "yen", "florin", "section", "currency", "quotesingle", "quotedblleft", "guillemotleft", "guilsinglleft", "guilsinglright", "fi", "fl", NULL, "endash", "dagger", "daggerdbl", "periodcentered", /* 160 */ NULL, "paragraph", "bullet", "quotesinglbase", "quotedblbase", "quotedblright", "guillemotright", "ellipsis", "perthousand", NULL, "questiondown", NULL, "grave", "acute", "circumflex", "tilde", /* 176 */ "macron", "breve", "dotaccent", "dieresis", NULL, "ring", "cedilla", NULL, "hungarumlaut", "ogonek", "caron", "emdash", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 192 */ "AE", 0, "ordfeminine", 0, 0, 0, 0, "Lslash", /* 208 */ "Oslash", "OE", "ordmasculine", 0, 0, 0, 0, 0, "ae", 0, 0, 0, "dotlessi", 0, 0, "lslash", /* 224 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -