summaryrefslogtreecommitdiff
path: root/src/cairo-cff-subset.c
diff options
context:
space:
mode:
authorAdrian Johnson <ajohnson@redneon.com>2007-04-20 22:30:05 +0930
committerAdrian Johnson <ajohnson@redneon.com>2007-04-20 22:30:05 +0930
commitc68a2389f51880b0fa9df6750abdd840258666fc (patch)
tree41d1476d37c8e551c23512c6117df134d3a06987 /src/cairo-cff-subset.c
parent073fce5a85ab90b1bc6915e41d6a420a47e540e6 (diff)
Make CFF Subsetting create CID subsets
OpenType/CFF fonts come in two types: CID and non CID. CFF CID font subsetting was previously disabled in cairo due 1) to the need to embed CFF CID fonts in PDF as a CID fonts and 2) there is no easy way to convert CFF CID to CFF non CID. With the switch to CID fonts cairo-cff-subset.c has been updated to subset CID fonts and to covert non CID fonts to CID. A further advantage of converting non CID CFF fonts to CID is the reduction in size due to not embedding the name of each glyph in the font subset.
Diffstat (limited to 'src/cairo-cff-subset.c')
-rw-r--r--src/cairo-cff-subset.c858
1 files changed, 559 insertions, 299 deletions
diff --git a/src/cairo-cff-subset.c b/src/cairo-cff-subset.c
index b0158fe4..e4c8cfce 100644
--- a/src/cairo-cff-subset.c
+++ b/src/cairo-cff-subset.c
@@ -37,15 +37,20 @@
#include "cairoint.h"
#include "cairo-scaled-font-subsets-private.h"
#include "cairo-truetype-subset-private.h"
+#include <string.h>
/* CFF Dict Operators. If the high byte is 0 the command is encoded
* with a single byte. */
#define BASEFONTNAME_OP 0x0c16
+#define CIDCOUNT_OP 0x0c22
#define CHARSET_OP 0x000f
#define CHARSTRINGS_OP 0x0011
#define COPYRIGHT_OP 0x0c00
#define ENCODING_OP 0x0010
#define FAMILYNAME_OP 0x0003
+#define FDARRAY_OP 0x0c24
+#define FDSELECT_OP 0x0c25
+#define FONTBBOX_OP 0x0005
#define FONTNAME_OP 0x0c26
#define FULLNAME_OP 0x0002
#define LOCAL_SUB_OP 0x0013
@@ -80,13 +85,6 @@ typedef struct _cff_dict_operator {
int operand_offset;
} cff_dict_operator_t;
-typedef struct _cff_charset {
- cairo_bool_t is_builtin;
- const uint16_t *sids;
- const unsigned char *data;
- int length;
-} cff_charset_t;
-
typedef struct _cairo_cff_font {
cairo_scaled_font_subset_t *scaled_font_subset;
@@ -106,14 +104,23 @@ typedef struct _cairo_cff_font {
cairo_array_t global_sub_index;
cairo_array_t local_sub_index;
int num_glyphs;
- cff_charset_t charset;
- int charset_offset;
+ cairo_bool_t is_cid;
+
+ /* CID Font Data */
+ int *fdselect;
+ unsigned int num_fontdicts;
+ cairo_hash_table_t **fd_dict;
+ cairo_hash_table_t **fd_private_dict;
+ cairo_array_t *fd_local_sub_index;
/* Subsetted Font Data */
char *subset_font_name;
cairo_array_t charstrings_subset_index;
cairo_array_t strings_subset_index;
- cairo_array_t charset_subset;
+ int *fdselect_subset;
+ unsigned int num_subset_fontdicts;
+ int *fd_subset_map;
+ int *private_dict_offset;
cairo_array_t output;
/* Subset Metrics */
@@ -345,7 +352,6 @@ cff_index_write (cairo_array_t *index, cairo_array_t *output)
status = _cairo_array_append_multiple (output, buf, offset_size);
if (status)
return status;
-
}
for (i = 0; i < num_elem; i++) {
@@ -372,7 +378,9 @@ cff_index_append (cairo_array_t *index, unsigned char *object , int length)
}
static cairo_status_t
-cff_index_append_copy (cairo_array_t *index, unsigned char *object , int length)
+cff_index_append_copy (cairo_array_t *index,
+ const unsigned char *object,
+ unsigned int length)
{
cff_index_element_t element;
@@ -486,6 +494,21 @@ fail:
return status;
}
+static void
+cff_dict_remove (cairo_hash_table_t *dict, unsigned short operator)
+{
+ cff_dict_operator_t key, *op;
+
+ _cairo_dict_init_key (&key, operator);
+ if (_cairo_hash_table_lookup (dict, &key.base,
+ (cairo_hash_entry_t **) &op))
+ {
+ free (op->operand);
+ _cairo_hash_table_remove (dict, (cairo_hash_entry_t *) op);
+ free (op);
+ }
+}
+
static unsigned char *
cff_dict_get_operands (cairo_hash_table_t *dict,
unsigned short operator,
@@ -561,19 +584,12 @@ typedef struct _dict_write_info {
} dict_write_info_t;
static void
-_cairo_dict_collect (void *entry, void *closure)
+cairo_dict_write_operator (cff_dict_operator_t *op, dict_write_info_t *write_info)
{
- dict_write_info_t *write_info = closure;
- cff_dict_operator_t *op = entry;
unsigned char data;
- if (write_info->status)
- return;
-
op->operand_offset = _cairo_array_num_elements (write_info->output);
- write_info->status = _cairo_array_append_multiple (write_info->output,
- op->operand,
- op->operand_length);
+ write_info->status = _cairo_array_append_multiple (write_info->output, op->operand, op->operand_length);
if (write_info->status)
return;
@@ -587,13 +603,36 @@ _cairo_dict_collect (void *entry, void *closure)
write_info->status = _cairo_array_append (write_info->output, &data);
}
+static void
+_cairo_dict_collect (void *entry, void *closure)
+{
+ dict_write_info_t *write_info = closure;
+ cff_dict_operator_t *op = entry;
+
+ if (write_info->status)
+ return;
+
+ /* The ROS operator is handled separately in cff_dict_write() */
+ if (op->operator != ROS_OP)
+ cairo_dict_write_operator (op, write_info);
+}
+
static cairo_status_t
cff_dict_write (cairo_hash_table_t *dict, cairo_array_t *output)
{
dict_write_info_t write_info;
+ cff_dict_operator_t key, *op;
write_info.output = output;
write_info.status = CAIRO_STATUS_SUCCESS;
+
+ /* The CFF specification requires that the Top Dict of CID fonts
+ * begin with the ROS operator. */
+ _cairo_dict_init_key (&key, ROS_OP);
+ if (_cairo_hash_table_lookup (dict, &key.base,
+ (cairo_hash_entry_t **) &op))
+ cairo_dict_write_operator (op, &write_info);
+
_cairo_hash_table_foreach (dict, _cairo_dict_collect, &write_info);
return write_info.status;
@@ -644,6 +683,8 @@ cairo_cff_font_read_name (cairo_cff_font_t *font)
static cairo_int_status_t
cairo_cff_font_read_private_dict (cairo_cff_font_t *font,
+ cairo_hash_table_t *private_dict,
+ cairo_array_t *local_sub_index,
unsigned char *ptr,
int size)
{
@@ -654,22 +695,141 @@ cairo_cff_font_read_private_dict (cairo_cff_font_t *font,
unsigned char *operand;
unsigned char *p;
- cff_dict_read (font->private_dict, ptr, size);
- operand = cff_dict_get_operands (font->private_dict, LOCAL_SUB_OP, &i);
+ cff_dict_read (private_dict, ptr, size);
+ operand = cff_dict_get_operands (private_dict, LOCAL_SUB_OP, &i);
if (operand) {
decode_integer (operand, &offset);
p = ptr + offset;
- cff_index_read (&font->local_sub_index, &p, font->data_end);
+ cff_index_read (local_sub_index, &p, font->data_end);
/* Use maximum sized encoding to reserve space for later modification. */
end_buf = encode_integer_max (buf, 0);
- cff_dict_set_operands (font->private_dict, LOCAL_SUB_OP, buf, end_buf - buf);
+ cff_dict_set_operands (private_dict, LOCAL_SUB_OP, buf, end_buf - buf);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+cairo_cff_font_read_fdselect (cairo_cff_font_t *font, unsigned char *p)
+{
+ int type, num_ranges, first, last, fd, i, j;
+
+ font->fdselect = calloc (font->num_glyphs, sizeof (int));
+ if (font->fdselect == NULL)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ type = *p++;
+ if (type == 0)
+ {
+ for (i = 0; i < font->num_glyphs; i++)
+ font->fdselect[i] = *p++;
+ } else if (type == 3) {
+ num_ranges = be16_to_cpu( *((uint16_t *)p) );
+ p += 2;
+ for (i = 0; i < num_ranges; i++)
+ {
+ first = be16_to_cpu( *((uint16_t *)p) );
+ p += 2;
+ fd = *p++;
+ last = be16_to_cpu( *((uint16_t *)p) );
+ for (j = first; j < last; j++)
+ font->fdselect[j] = fd;
+ }
+ } else {
+ return CAIRO_INT_STATUS_UNSUPPORTED;
}
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
+cairo_cff_font_read_cid_fontdict (cairo_cff_font_t *font, unsigned char *ptr)
+{
+ cairo_array_t index;
+ cff_index_element_t *element;
+ unsigned int i;
+ int size;
+ unsigned char *operand;
+ int offset;
+ cairo_int_status_t status;
+ unsigned char buf[100];
+ unsigned char *end_buf;
+
+ cff_index_init (&index);
+ status = cff_index_read (&index, &ptr, font->data_end);
+ if (status)
+ goto fail;
+
+ font->num_fontdicts = _cairo_array_num_elements (&index);
+
+ font->fd_dict = calloc (sizeof (cairo_hash_table_t *), font->num_fontdicts);
+ if (font->fd_dict == NULL) {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ font->fd_private_dict = calloc (sizeof (cairo_hash_table_t *), font->num_fontdicts);
+ if (font->fd_private_dict == NULL) {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ font->fd_local_sub_index = calloc (sizeof (cairo_array_t), font->num_fontdicts);
+ if (font->fd_local_sub_index == NULL) {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ for (i = 0; i < font->num_fontdicts; i++) {
+ cff_dict_init (&font->fd_dict[i]);
+ if (font->fd_dict[i] == NULL) {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto fail;
+ }
+ element = _cairo_array_index (&index, i);
+ status = cff_dict_read (font->fd_dict[i], element->data, element->length);
+ if (status)
+ goto fail;
+
+ operand = cff_dict_get_operands (font->fd_dict[i], PRIVATE_OP, &size);
+ if (operand == NULL) {
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ goto fail;
+ }
+ operand = decode_integer (operand, &size);
+ decode_integer (operand, &offset);
+ cff_dict_init (&font->fd_private_dict[i]);
+ if (font->fd_private_dict[i] == NULL) {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto fail;
+ }
+ cff_index_init (&font->fd_local_sub_index[i]);
+ status = cairo_cff_font_read_private_dict (font,
+ font->fd_private_dict[i],
+ &font->fd_local_sub_index[i],
+ font->data + offset,
+ size);
+ if (status)
+ goto fail;
+ /* Set integer operand to max value to use max size encoding to reserve
+ * space for any value later */
+ end_buf = encode_integer_max (buf, 0);
+ end_buf = encode_integer_max (end_buf, 0);
+ status = cff_dict_set_operands (font->fd_dict[i], PRIVATE_OP, buf, end_buf - buf);
+ if (status)
+ goto fail;
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+
+fail:
+ cff_index_fini (&index);
+
+ return status;
+}
+
+static cairo_int_status_t
cairo_cff_font_read_top_dict (cairo_cff_font_t *font)
{
cairo_array_t index;
@@ -688,13 +848,14 @@ cairo_cff_font_read_top_dict (cairo_cff_font_t *font)
goto fail;
element = _cairo_array_index (&index, 0);
- cff_dict_read (font->top_dict, element->data, element->length);
-
- /* CID fonts are NYI */
- if (cff_dict_get_operands (font->top_dict, ROS_OP, &size) != NULL) {
- status = CAIRO_INT_STATUS_UNSUPPORTED;
+ status = cff_dict_read (font->top_dict, element->data, element->length);
+ if (status)
goto fail;
- }
+
+ if (cff_dict_get_operands (font->top_dict, ROS_OP, &size) != NULL)
+ font->is_cid = TRUE;
+ else
+ font->is_cid = FALSE;
operand = cff_dict_get_operands (font->top_dict, CHARSTRINGS_OP, &size);
decode_integer (operand, &offset);
@@ -704,27 +865,34 @@ cairo_cff_font_read_top_dict (cairo_cff_font_t *font)
goto fail;
font->num_glyphs = _cairo_array_num_elements (&font->charstrings_index);
- operand = cff_dict_get_operands (font->top_dict, PRIVATE_OP, &size);
- operand = decode_integer (operand, &size);
- decode_integer (operand, &offset);
- cairo_cff_font_read_private_dict (font, font->data + offset, size);
-
- operand = cff_dict_get_operands (font->top_dict, CHARSET_OP, &size);
- if (!operand)
- font->charset_offset = 0;
- else {
- decode_integer (operand, &offset);
- font->charset_offset = offset;
+ if (font->is_cid) {
+ operand = cff_dict_get_operands (font->top_dict, FDSELECT_OP, &size);
+ decode_integer (operand, &offset);
+ cairo_cff_font_read_fdselect (font, font->data + offset);
+
+ operand = cff_dict_get_operands (font->top_dict, FDARRAY_OP, &size);
+ decode_integer (operand, &offset);
+ cairo_cff_font_read_cid_fontdict (font, font->data + offset);
+ } else {
+ operand = cff_dict_get_operands (font->top_dict, PRIVATE_OP, &size);
+ operand = decode_integer (operand, &size);
+ decode_integer (operand, &offset);
+ cairo_cff_font_read_private_dict (font,
+ font->private_dict,
+ &font->local_sub_index,
+ font->data + offset,
+ size);
}
/* Use maximum sized encoding to reserve space for later modification. */
end_buf = encode_integer_max (buf, 0);
cff_dict_set_operands (font->top_dict, CHARSTRINGS_OP, buf, end_buf - buf);
- cff_dict_set_operands (font->top_dict, ENCODING_OP, buf, end_buf - buf);
+ cff_dict_set_operands (font->top_dict, FDSELECT_OP, buf, end_buf - buf);
+ cff_dict_set_operands (font->top_dict, FDARRAY_OP, buf, end_buf - buf);
cff_dict_set_operands (font->top_dict, CHARSET_OP, buf, end_buf - buf);
- /* Private has two operands - size and offset */
- end_buf = encode_integer_max (end_buf, 0);
- cff_dict_set_operands (font->top_dict, PRIVATE_OP, buf, end_buf - buf);
+
+ cff_dict_remove (font->top_dict, ENCODING_OP);
+ cff_dict_remove (font->top_dict, PRIVATE_OP);
fail:
cff_index_fini (&index);
@@ -744,138 +912,6 @@ cairo_cff_font_read_global_subroutines (cairo_cff_font_t *font)
return cff_index_read (&font->global_sub_index, &font->current_ptr, font->data_end);
}
-static cairo_int_status_t
-cff_charset_read_data (cff_charset_t *charset, const unsigned char *data,
- const unsigned char *data_end, int num_glyphs)
-{
- const unsigned char *p = data;
-
- num_glyphs -= 1; /* do not count .notdef */
-
- if (p + 1 > data_end)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- switch (*p++) {
- case 0:
- if (p + num_glyphs*2 > data_end)
- return CAIRO_INT_STATUS_UNSUPPORTED;
- charset->is_builtin = FALSE;
- charset->data = data;
- charset->length = num_glyphs * 2 + 1;
- break;
- case 1:
- while (num_glyphs > 0) {
- if (p + 3 > data_end)
- return CAIRO_INT_STATUS_UNSUPPORTED;
- num_glyphs -= p[2] + 1;
- p += 3;
- }
- if (num_glyphs < 0)
- return CAIRO_INT_STATUS_UNSUPPORTED;
- charset->is_builtin = FALSE;
- charset->data = data;
- charset->length = p - data;
- break;
- case 2:
- while (num_glyphs > 0) {
- if (p + 4 > data_end)
- return CAIRO_INT_STATUS_UNSUPPORTED;
- num_glyphs -= be16_to_cpu(*(uint16_t *)(p + 2)) + 1;
- p += 4;
- }
- if (num_glyphs < 0)
- return CAIRO_INT_STATUS_UNSUPPORTED;
- charset->is_builtin = FALSE;
- charset->data = data;
- charset->length = p - data;
- break;
- default:
- return CAIRO_INT_STATUS_UNSUPPORTED;
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static const uint16_t ISOAdobe_charset[] = {
- 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
- 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
- 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
- 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58,
- 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72,
- 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86,
- 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100,
- 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
- 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122,
- 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133,
- 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144,
- 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155,
- 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166,
- 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177,
- 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188,
- 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199,
- 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210,
- 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221,
- 222, 223, 224, 225, 226, 227, 228,
-};
-
-static const uint16_t Expert_charset[] = {
- 1, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 13,
- 14, 15, 99, 239, 240, 241, 242, 243, 244, 245, 246, 247,
- 248, 27, 28, 249, 250, 251, 252, 253, 254, 255, 256, 257,
- 258, 259, 260, 261, 262, 263, 264, 265, 266, 109, 110,
- 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277,
- 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288,
- 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299,
- 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310,
- 311, 312, 313, 314, 315, 316, 317, 318, 158, 155, 163,
- 319, 320, 321, 322, 323, 324, 325, 326, 150, 164, 169,
- 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337,
- 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348,
- 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359,
- 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370,
- 371, 372, 373, 374, 375, 376, 377, 378,
-};
-
-static const uint16_t ExpertSubset_charset[] = {
- 1, 231, 232, 235, 236, 237, 238, 13, 14, 15, 99, 239, 240,
- 241, 242, 243, 244, 245, 246, 247, 248, 27, 28, 249, 250,
- 251, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262,
- 263, 264, 265, 266, 109, 110, 267, 268, 269, 270, 272,
- 300, 301, 302, 305, 314, 315, 158, 155, 163, 320, 321,
- 322, 323, 324, 325, 326, 150, 164, 169, 327, 328, 329,
- 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340,
- 341, 342, 343, 344, 345, 346,
-};
-
-static cairo_int_status_t
-cairo_cff_font_read_charset (cairo_cff_font_t *font)
-{
- switch (font->charset_offset) {
- case 0:
- /* ISOAdobe charset */
- font->charset.is_builtin = TRUE;
- font->charset.sids = ISOAdobe_charset;
- font->charset.length = sizeof (ISOAdobe_charset);
- return CAIRO_STATUS_SUCCESS;
- case 1:
- /* Expert charset */
- font->charset.is_builtin = TRUE;
- font->charset.sids = Expert_charset;
- font->charset.length = sizeof (Expert_charset);
- return CAIRO_STATUS_SUCCESS;
- case 2:
- /* ExpertSubset charset */;
- font->charset.is_builtin = TRUE;
- font->charset.sids = ExpertSubset_charset;
- font->charset.length = sizeof (ExpertSubset_charset);
- return CAIRO_STATUS_SUCCESS;
- default:
- break;
- }
- return cff_charset_read_data (&font->charset, font->data + (unsigned)font->charset_offset,
- font->data_end, font->num_glyphs);
-}
-
typedef cairo_int_status_t
(*font_read_t) (cairo_cff_font_t *font);
@@ -885,8 +921,6 @@ static const font_read_t font_read_funcs[] = {
cairo_cff_font_read_top_dict,
cairo_cff_font_read_strings,
cairo_cff_font_read_global_subroutines,
- /* non-contiguous */
- cairo_cff_font_read_charset,
};
static cairo_int_status_t
@@ -904,6 +938,34 @@ cairo_cff_font_read_font (cairo_cff_font_t *font)
return CAIRO_STATUS_SUCCESS;
}
+static void
+cairo_cff_font_set_ros_strings (cairo_cff_font_t *font)
+{
+ unsigned char buf[30];
+ unsigned char *p;
+ int sid1, sid2;
+ const char *registry = "Adobe";
+ const char *ordering = "Identity";
+
+ sid1 = NUM_STD_STRINGS + _cairo_array_num_elements (&font->strings_subset_index);
+ cff_index_append_copy (&font->strings_subset_index,
+ (unsigned char *)registry,
+ strlen(registry));
+
+ sid2 = NUM_STD_STRINGS + _cairo_array_num_elements (&font->strings_subset_index);
+ cff_index_append_copy (&font->strings_subset_index,
+ (unsigned char *)ordering,
+ strlen(ordering));
+
+ p = encode_integer (buf, sid1);
+ p = encode_integer (p, sid2);
+ p = encode_integer (p, 0);
+ cff_dict_set_operands (font->top_dict, ROS_OP, buf, p - buf);
+
+ p = encode_integer (buf, font->scaled_font_subset->num_glyphs);
+ cff_dict_set_operands (font->top_dict, CIDCOUNT_OP, buf, p - buf);
+}
+
static cairo_status_t
cairo_cff_font_subset_dict_string(cairo_cff_font_t *font,
cairo_hash_table_t *dict,
@@ -965,29 +1027,12 @@ cairo_cff_font_subset_dict_strings (cairo_cff_font_t *font,
}
static cairo_status_t
-cairo_cff_font_subset_strings (cairo_cff_font_t *font)
-{
- cairo_status_t status;
-
- status = cairo_cff_font_subset_dict_strings (font, font->top_dict);
- if (status)
- return status;
-
- status = cairo_cff_font_subset_dict_strings (font, font->private_dict);
-
- return status;
-}
-
-static cairo_status_t
cairo_cff_font_subset_charstrings (cairo_cff_font_t *font)
{
cff_index_element_t *element;
unsigned int i;
cairo_status_t status;
- if (status)
- return status;
-
for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) {
element = _cairo_array_index (&font->charstrings_index,
font->scaled_font_subset->glyphs[i]);
@@ -1001,78 +1046,105 @@ cairo_cff_font_subset_charstrings (cairo_cff_font_t *font)
return CAIRO_STATUS_SUCCESS;
}
-static uint16_t
-cff_sid_from_gid (const cff_charset_t *charset, int gid)
+static cairo_status_t
+cairo_cff_font_subset_fontdict (cairo_cff_font_t *font)
{
- const uint16_t *sids;
- const unsigned char *p;
- int prev_glyph;
+ unsigned int i;
+ int fd;
+ int *reverse_map;
- if (charset->is_builtin) {
- if (gid - 1 < charset->length / 2)
- return charset->sids[gid - 1];
- }
- else {
- /* no need to check sizes here, this was done during reading */
- switch (charset->data[0]) {
- case 0:
- sids = (const uint16_t *)(charset->data + 1);
- return be16_to_cpu(sids[gid - 1]);
- case 1:
- prev_glyph = 1;
- for (p = charset->data + 1; p < charset->data + charset->length; p += 3) {
- if (gid <= prev_glyph + p[2]) {
- uint16_t sid = be16_to_cpu(*(const uint16_t *)p);
- return sid + gid - prev_glyph;
- }
- prev_glyph += p[2] + 1;
- }
- break;
- case 2:
- prev_glyph = 1;
- for (p = charset->data + 1; p < charset->data + charset->length; p += 4) {
- uint16_t nLeft = be16_to_cpu(*(const uint16_t *)(p + 2));
- if (gid <= prev_glyph + nLeft) {
- uint16_t sid = be16_to_cpu(*(const uint16_t *)p);
- return sid + gid - prev_glyph;
- }
- prev_glyph += nLeft + 1;
- }
- break;
- default:
- break;
- }
+ font->fdselect_subset = calloc (font->scaled_font_subset->num_glyphs,
+ sizeof (int));
+ if (font->fdselect_subset == NULL)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ font->fd_subset_map = calloc (font->num_fontdicts, sizeof (int));
+ if (font->fd_subset_map == NULL)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ font->private_dict_offset = calloc (font->num_fontdicts, sizeof (int));
+ if (font->private_dict_offset == NULL)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ reverse_map = calloc (font->num_fontdicts, sizeof (int));
+ if (reverse_map == NULL)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ for (i = 0; i < font->num_fontdicts; i++)
+ reverse_map[i] = -1;
+
+ font->num_subset_fontdicts = 0;
+ for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) {
+ fd = font->fdselect[font->scaled_font_subset->glyphs[i]];
+ if (reverse_map[fd] < 0) {
+ font->fd_subset_map[font->num_subset_fontdicts] = fd;
+ reverse_map[fd] = font->num_subset_fontdicts++;
+ }
+ font->fdselect_subset[i] = reverse_map[fd];
}
- return 0;
+
+ free (reverse_map);
+
+ return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
-cairo_cff_font_subset_charset (cairo_cff_font_t *font)
+cairo_cff_font_create_cid_fontdict (cairo_cff_font_t *font)
{
+ unsigned char buf[100];
+ unsigned char *end_buf;
+
+ font->num_fontdicts = 1;
+ font->fd_dict = malloc (sizeof (cairo_hash_table_t *));
+ if (font->fd_dict == NULL)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ cff_dict_init (&font->fd_dict[0]);
+
+ font->fd_subset_map = malloc (sizeof (int));
+ if (font->fd_subset_map == NULL)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ font->private_dict_offset = malloc (sizeof (int));
+ if (font->private_dict_offset == NULL)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ font->fd_subset_map[0] = 0;
+ font->num_subset_fontdicts = 1;
+
+ /* Set integer operand to max value to use max size encoding to reserve
+ * space for any value later */
+ end_buf = encode_integer_max (buf, 0);
+ end_buf = encode_integer_max (end_buf, 0);
+ cff_dict_set_operands (font->fd_dict[0], PRIVATE_OP, buf, end_buf - buf);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+cairo_cff_font_subset_strings (cairo_cff_font_t *font)
+{
+ cairo_status_t status;
unsigned int i;
- for (i = 1; i < font->scaled_font_subset->num_glyphs; i++) {
- int gid = font->scaled_font_subset->glyphs[i];
- uint16_t original_sid = cff_sid_from_gid(&font->charset, gid);
- uint16_t new_sid;
- cff_index_element_t *element;
- cairo_status_t status;
-
- if (original_sid >= NUM_STD_STRINGS) {
- element = _cairo_array_index (&font->strings_index, original_sid - NUM_STD_STRINGS);
- new_sid = NUM_STD_STRINGS + _cairo_array_num_elements (&font->strings_subset_index);
- status = cff_index_append (&font->strings_subset_index, element->data, element->length);
- if (status)
- return status;
- }
- else
- new_sid = original_sid;
-
- status = _cairo_array_append(&font->charset_subset, &new_sid);
- if (status)
- return status;
+ status = cairo_cff_font_subset_dict_strings (font, font->top_dict);
+ if (status)
+ return status;
+ if (font->is_cid) {
+ for (i = 0; i < font->num_subset_fontdicts; i++) {
+ status = cairo_cff_font_subset_dict_strings (font, font->fd_dict[font->fd_subset_map[i]]);
+ if (status)
+ return status;
+
+ status = cairo_cff_font_subset_dict_strings (font, font->fd_private_dict[font->fd_subset_map[i]]);
+ if (status)
+ return status;
+ }
+ } else {
+ status = cairo_cff_font_subset_dict_strings (font, font->private_dict);
}
- return CAIRO_STATUS_SUCCESS;
+
+ return status;
}
static cairo_status_t
@@ -1080,17 +1152,20 @@ cairo_cff_font_subset_font (cairo_cff_font_t *font)
{
cairo_status_t status;
- /* TODO: subset subroutines */
+ cairo_cff_font_set_ros_strings (font);
- status = cairo_cff_font_subset_strings (font);
+ status = cairo_cff_font_subset_charstrings (font);
if (status)
return status;
- status = cairo_cff_font_subset_charstrings (font);
- if (status)
- return status;
+ if (font->is_cid)
+ cairo_cff_font_subset_fontdict (font);
+ else
+ cairo_cff_font_create_cid_fontdict (font);
- status = cairo_cff_font_subset_charset (font);
+ status = cairo_cff_font_subset_strings (font);
+ if (status)
+ return status;
return status;
}
@@ -1205,38 +1280,82 @@ cairo_cff_font_write_global_subrs (cairo_cff_font_t *font)
}
static cairo_status_t
-cairo_cff_font_write_encoding (cairo_cff_font_t *font)
+cairo_cff_font_write_fdselect (cairo_cff_font_t *font)
{
- unsigned char buf[10];
+ unsigned char data;
+ unsigned int i;
+ cairo_int_status_t status;
+
+ cairo_cff_font_set_topdict_operator_to_cur_pos (font, FDSELECT_OP);
+
+ if (font->is_cid) {
+ data = 0;
+ status = _cairo_array_append (&font->output, &data);
+ if (status)
+ return status;
+
+ for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) {
+ data = font->fdselect_subset[i];
+ status = _cairo_array_append (&font->output, &data);
+ if (status)
+ return status;
+ }
+ } else {
+ unsigned char byte;
+ uint16_t word;
+
+ status = _cairo_array_grow_by (&font->output, 9);
+ if (status)
+ return status;
+
+ byte = 3;
+ status = _cairo_array_append (&font->output, &byte);
+ assert (status == CAIRO_STATUS_SUCCESS);
- cairo_cff_font_set_topdict_operator_to_cur_pos (font, ENCODING_OP);
- buf[0] = 1; /* Format 1 */
- buf[1] = 1; /* Number of ranges */
- buf[2] = 0; /* First code in range */
- /* Codes left in range excluding first */
- buf[3] = font->scaled_font_subset->num_glyphs - 1;
+ word = cpu_to_be16 (1);
+ status = _cairo_array_append_multiple (&font->output, &word, 2);
+ assert (status == CAIRO_STATUS_SUCCESS);
- return _cairo_array_append_multiple (&font->output, buf, 4);
+ word = cpu_to_be16 (0);
+ status = _cairo_array_append_multiple (&font->output, &word, 2);
+ assert (status == CAIRO_STATUS_SUCCESS);
+
+ byte = 0;
+ status = _cairo_array_append (&font->output, &byte);
+ assert (status == CAIRO_STATUS_SUCCESS);
+
+ word = cpu_to_be16 (font->scaled_font_subset->num_glyphs);
+ status = _cairo_array_append_multiple (&font->output, &word, 2);
+ assert (status == CAIRO_STATUS_SUCCESS);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
cairo_cff_font_write_charset (cairo_cff_font_t *font)
{
- unsigned char format = 0;
- unsigned int i;
+ unsigned char byte;
+ uint16_t word;
cairo_status_t status;
cairo_cff_font_set_topdict_operator_to_cur_pos (font, CHARSET_OP);
- status = _cairo_array_append (&font->output, &format);
+ status = _cairo_array_grow_by (&font->output, 5);
if (status)
- return status;
+ return status;
+
+ byte = 2;
+ status = _cairo_array_append (&font->output, &byte);
+ assert (status == CAIRO_STATUS_SUCCESS);
+
+ word = cpu_to_be16 (1);
+ status = _cairo_array_append_multiple (&font->output, &word, 2);
+ assert (status == CAIRO_STATUS_SUCCESS);
+
+ word = cpu_to_be16 (font->scaled_font_subset->num_glyphs - 2);
+ status = _cairo_array_append_multiple (&font->output, &word, 2);
+ assert (status == CAIRO_STATUS_SUCCESS);
- for (i = 0; i < (unsigned)_cairo_array_num_elements(&font->charset_subset); i++) {
- uint16_t sid = cpu_to_be16(*(uint16_t *)_cairo_array_index(&font->charset_subset, i));
- status = _cairo_array_append_multiple (&font->output, &sid, sizeof(sid));
- if (status)
- return status;
- }
return CAIRO_STATUS_SUCCESS;
}
@@ -1249,9 +1368,48 @@ cairo_cff_font_write_charstrings (cairo_cff_font_t *font)
}
static cairo_status_t
-cairo_cff_font_write_private_dict_and_local_sub (cairo_cff_font_t *font)
+cairo_cff_font_write_cid_fontdict (cairo_cff_font_t *font)
+{
+ unsigned int i;
+ cairo_int_status_t status;
+ uint32_t *offset_array;
+ int offset_base;
+ uint16_t count;
+ uint8_t offset_size = 4;
+
+ cairo_cff_font_set_topdict_operator_to_cur_pos (font, FDARRAY_OP);
+ count = cpu_to_be16 (font->num_subset_fontdicts);
+ status = _cairo_array_append_multiple (&font->output, &count, sizeof (uint16_t));
+ if (status)
+ return status;
+ status = _cairo_array_append (&font->output, &offset_size);
+ if (status)
+ return status;
+ status = _cairo_array_allocate (&font->output,
+ (font->num_subset_fontdicts + 1)*offset_size,
+ (void **) &offset_array);
+ if (status)
+ return status;
+ offset_base = _cairo_array_num_elements (&font->output) - 1;
+ *offset_array++ = cpu_to_be32(1);
+ for (i = 0; i < font->num_subset_fontdicts; i++) {
+ status = cff_dict_write (font->fd_dict[font->fd_subset_map[i]],
+ &font->output);
+ if (status)
+ return status;
+ *offset_array++ = cpu_to_be32(_cairo_array_num_elements (&font->output) - offset_base);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+cairo_cff_font_write_private_dict (cairo_cff_font_t *font,
+ int dict_num,
+ cairo_hash_table_t *parent_dict,
+ cairo_hash_table_t *private_dict)
{
- int offset, private_dict_offset;
+ int offset;
int size;
unsigned char buf[10];
unsigned char *buf_end;
@@ -1259,30 +1417,46 @@ cairo_cff_font_write_private_dict_and_local_sub (cairo_cff_font_t *font)
cairo_status_t status;
/* Write private dict and update offset and size in top dict */
- private_dict_offset = _cairo_array_num_elements (&font->output);
- status = cff_dict_write (font->private_dict, &font->output);
+ font->private_dict_offset[dict_num] = _cairo_array_num_elements (&font->output);
+ status = cff_dict_write (private_dict, &font->output);
if (status)
return status;
- size = _cairo_array_num_elements (&font->output) - private_dict_offset;
+ size = _cairo_array_num_elements (&font->output) - font->private_dict_offset[dict_num];
/* private entry has two operands - size and offset */
buf_end = encode_integer_max (buf, size);
- buf_end = encode_integer_max (buf_end, private_dict_offset);
- offset = cff_dict_get_location (font->top_dict, PRIVATE_OP, &size);
+ buf_end = encode_integer_max (buf_end, font->private_dict_offset[dict_num]);
+ offset = cff_dict_get_location (parent_dict, PRIVATE_OP, &size);
assert (offset > 0);
p = _cairo_array_index (&font->output, offset);
memcpy (p, buf, buf_end - buf);
- if (_cairo_array_num_elements (&font->local_sub_index) > 0) {
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+cairo_cff_font_write_local_sub (cairo_cff_font_t *font,
+ int dict_num,
+ cairo_hash_table_t *private_dict,
+ cairo_array_t *local_sub_index)
+{
+ int offset;
+ int size;
+ unsigned char buf[10];
+ unsigned char *buf_end;
+ unsigned char *p;
+ cairo_status_t status;
+
+ if (_cairo_array_num_elements (local_sub_index) > 0) {
/* Write local subroutines and update offset in private
* dict. Local subroutines offset is relative to start of
* private dict */
- offset = _cairo_array_num_elements (&font->output) - private_dict_offset;
+ offset = _cairo_array_num_elements (&font->output) - font->private_dict_offset[dict_num];
buf_end = encode_integer_max (buf, offset);
- offset = cff_dict_get_location (font->private_dict, LOCAL_SUB_OP, &size);
+ offset = cff_dict_get_location (private_dict, LOCAL_SUB_OP, &size);
assert (offset > 0);
p = _cairo_array_index (&font->output, offset);
memcpy (p, buf, buf_end - buf);
- status = cff_index_write (&font->local_sub_index, &font->output);
+ status = cff_index_write (local_sub_index, &font->output);
if (status)
return status;
}
@@ -1290,6 +1464,47 @@ cairo_cff_font_write_private_dict_and_local_sub (cairo_cff_font_t *font)
return CAIRO_STATUS_SUCCESS;
}
+
+static cairo_status_t
+cairo_cff_font_write_cid_private_dict_and_local_sub (cairo_cff_font_t *font)
+{
+ unsigned int i;
+ cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
+
+ if (font->is_cid) {
+ for (i = 0; i < font->num_subset_fontdicts; i++) {
+ status = cairo_cff_font_write_private_dict (
+ font,
+ i,
+ font->fd_dict[font->fd_subset_map[i]],
+ font->fd_private_dict[font->fd_subset_map[i]]);
+ if (status)
+ return status;
+ }
+
+ for (i = 0; i < font->num_subset_fontdicts; i++) {
+ status = cairo_cff_font_write_local_sub (
+ font,
+ i,
+ font->fd_private_dict[font->fd_subset_map[i]],
+ &font->fd_local_sub_index[font->fd_subset_map[i]]);
+ if (status)
+ return status;
+ }
+ } else {
+ status = cairo_cff_font_write_private_dict (font,
+ 0,
+ font->fd_dict[0],
+ font->private_dict);
+ status = cairo_cff_font_write_local_sub (font,
+ 0,
+ font->private_dict,
+ &font->local_sub_index);
+ }
+
+ return status;
+}
+
typedef cairo_status_t
(*font_write_t) (cairo_cff_font_t *font);
@@ -1299,10 +1514,11 @@ static const font_write_t font_write_funcs[] = {
cairo_cff_font_write_top_dict,
cairo_cff_font_write_strings,
cairo_cff_font_write_global_subrs,
- cairo_cff_font_write_encoding,
+ cairo_cff_font_write_fdselect,
cairo_cff_font_write_charset,
cairo_cff_font_write_charstrings,
- cairo_cff_font_write_private_dict_and_local_sub,
+ cairo_cff_font_write_cid_fontdict,
+ cairo_cff_font_write_cid_private_dict_and_local_sub,
};
static cairo_status_t
@@ -1548,7 +1764,13 @@ _cairo_cff_font_create (cairo_scaled_font_subset_t *scaled_font_subset,
cff_index_init (&font->local_sub_index);
cff_index_init (&font->charstrings_subset_index);
cff_index_init (&font->strings_subset_index);
- _cairo_array_init (&font->charset_subset, sizeof(uint16_t));
+ font->fdselect = NULL;
+ font->fd_dict = NULL;
+ font->fd_private_dict = NULL;
+ font->fd_local_sub_index = NULL;
+ font->fdselect_subset = NULL;
+ font->fd_subset_map = NULL;
+ font->private_dict_offset = NULL;
free (name);
*font_return = font;
@@ -1575,6 +1797,8 @@ fail1:
static void
cairo_cff_font_destroy (cairo_cff_font_t *font)
{
+ unsigned int i;
+
free (font->widths);
free (font->font_name);
free (font->subset_font_name);
@@ -1587,7 +1811,43 @@ cairo_cff_font_destroy (cairo_cff_font_t *font)
cff_index_fini (&font->local_sub_index);
cff_index_fini (&font->charstrings_subset_index);
cff_index_fini (&font->strings_subset_index);
- _cairo_array_fini (&font->charset_subset);
+
+ /* If we bailed out early as a result of an error some of the
+ * following cairo_cff_font_t members may still be NULL */
+ if (font->fd_dict) {
+ for (i = 0; i < font->num_fontdicts; i++) {
+ if (font->fd_dict[i])
+ cff_dict_fini (font->fd_dict[i]);
+ }
+ free (font->fd_dict);
+ }
+ if (font->fd_subset_map)
+ free (font->fd_subset_map);
+ if (font->private_dict_offset)
+ free (font->private_dict_offset);
+
+ if (font->is_cid) {
+ if (font->fdselect)
+ free (font->fdselect);
+ if (font->fdselect_subset)
+ free (font->fdselect_subset);
+ if (font->fd_private_dict) {
+ for (i = 0; i < font->num_fontdicts; i++) {
+ if (font->fd_private_dict[i])
+ cff_dict_fini (font->fd_private_dict[i]);
+ }
+ free (font->fd_private_dict);
+ }
+ if (font->fd_local_sub_index) {
+ for (i = 0; i < font->num_fontdicts; i++)
+ cff_index_fini (&font->fd_local_sub_index[i]);
+ free (font->fd_local_sub_index);
+ }
+ }
+
+ if (font->data)
+ free (font->data);
+
free (font);
}