summaryrefslogtreecommitdiff
path: root/gs/base/write_t2.c
diff options
context:
space:
mode:
Diffstat (limited to 'gs/base/write_t2.c')
-rw-r--r--gs/base/write_t2.c515
1 files changed, 515 insertions, 0 deletions
diff --git a/gs/base/write_t2.c b/gs/base/write_t2.c
new file mode 100644
index 000000000..dfe4738ea
--- /dev/null
+++ b/gs/base/write_t2.c
@@ -0,0 +1,515 @@
+/* Copyright (C) 2001-2012 Artifex Software, Inc.
+ All Rights Reserved.
+
+ This software is provided AS-IS with no warranty, either express or
+ implied.
+
+ This software is distributed under license and may not be copied,
+ modified or distributed except as expressly authorized under the terms
+ of the license contained in the file LICENSE in this distribution.
+
+ Refer to licensing information at http://www.artifex.com or contact
+ Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael,
+ CA 94903, U.S.A., +1(415)492-9861, for further information.
+*/
+
+/*
+Functions to serialize a type 1 font so that it can then be
+passed to FreeType via the FAPI FreeType bridge.
+Started by Graham Asher, 9th August 2002.
+*/
+#include "stdpre.h"
+#include "gzstate.h"
+#include "wrfont.h"
+#include "write_t2.h"
+#include "gxfont.h"
+#include "gxfont1.h"
+
+/*
+Public structures and functions in this file are prefixed with FF_ because they are part of
+the FAPI FreeType implementation.
+*/
+
+static void
+write_4_byte_int(unsigned char *a_output, long a_int)
+{
+ a_output[0] = (unsigned char)(a_int >> 24);
+ a_output[1] = (unsigned char)(a_int >> 16);
+ a_output[2] = (unsigned char)(a_int >> 8);
+ a_output[3] = (unsigned char)(a_int & 0xFF);
+}
+
+static void
+write_type2_int(WRF_output * a_output, long a_int)
+{
+ if (a_int >= -107 && a_int <= 107)
+ WRF_wbyte(a_output, (unsigned char)(a_int + 139));
+ else if (a_int >= -32768 && a_int <= 32767) {
+ if (a_int >= 108 && a_int <= 1131)
+ a_int += 63124;
+ else if (a_int >= -1131 && a_int <= -108)
+ a_int = -a_int + 64148;
+ else
+ WRF_wbyte(a_output, 28);
+ WRF_wbyte(a_output, (unsigned char)(a_int >> 8));
+ WRF_wbyte(a_output, (unsigned char)(a_int & 0xFF));
+ } else {
+ unsigned char buffer[4];
+
+ WRF_wbyte(a_output, 29);
+ write_4_byte_int(buffer, a_int);
+ WRF_wtext(a_output, buffer, 4);
+ }
+}
+
+static void
+write_type2_float(WRF_output * a_output, double a_float)
+{
+ char buffer[32];
+ const char *p = buffer;
+ int high = true;
+ char c = 0;
+
+ sprintf(buffer, "%f", a_float);
+ WRF_wbyte(a_output, 30);
+ for (;;) {
+ char n = 0;
+
+ if (*p >= '0' && *p <= '9')
+ n = (char)(*p - '0');
+ else if (*p == '.')
+ n = 0xA;
+ else if (*p == 'e' || *p == 'E') {
+ if (p[1] == '-') {
+ p++;
+ n = 0xC;
+ } else
+ n = 0xB;
+ } else if (*p == '-')
+ n = 0xE;
+ else if (*p == 0)
+ n = 0xF;
+ if (high) {
+ if (*p == 0)
+ WRF_wbyte(a_output, 0xFF);
+ else
+ c = (char)(n << 4);
+ } else {
+ c |= n;
+ WRF_wbyte(a_output, c);
+ }
+
+ if (*p == 0)
+ break;
+
+ high = !high;
+ p++;
+ }
+}
+
+static void
+write_header(WRF_output * a_output)
+{
+ WRF_wtext(a_output, (const unsigned char *)"\x1\x0\x4\x1", 4);
+}
+
+static void
+write_name_index(WRF_output * a_output)
+{
+ /* Write a dummy name of 'x'. */
+ WRF_wtext(a_output, (const unsigned char *)"\x0\x1\x1\x1\x2" "x", 6);
+}
+
+static void
+write_word_entry(gs_fapi_font * a_fapi_font, WRF_output * a_output,
+ int a_feature_id, int a_feature_count, bool a_two_byte_op,
+ int a_op, int a_divisor)
+{
+ if (a_feature_count > 0) {
+ int i;
+
+ for (i = 0; i < a_feature_count; i++) {
+ /* Get the value and convert it from unsigned to signed. */
+ short x = a_fapi_font->get_word(a_fapi_font, a_feature_id, i);
+
+ /* Divide by the divisor to bring it back to font units. */
+ x = (short)(x / a_divisor);
+ write_type2_int(a_output, x);
+ }
+ if (a_two_byte_op)
+ WRF_wbyte(a_output, 12);
+ WRF_wbyte(a_output, (unsigned char)a_op);
+ }
+}
+
+static void
+write_delta_array_entry(gs_fapi_font * a_fapi_font, WRF_output * a_output,
+ int a_feature_id, bool a_two_byte_op, int a_op,
+ int a_divisor)
+{
+ int i;
+
+ /* NOTE that the feature index (a_feature_id) must be preceded by the count index for this to work. */
+ int count = a_fapi_font->get_word(a_fapi_font, a_feature_id - 1, 0);
+
+ if (count > 0) {
+ short prev_value = 0;
+
+ for (i = 0; i < count; i++) {
+ /* Get the value and convert it from unsigned to signed. */
+ short value = a_fapi_font->get_word(a_fapi_font, a_feature_id, i);
+
+ /* Divide by the divisor to bring it back to font units. */
+ value = (short)(value / a_divisor);
+ write_type2_int(a_output, value - prev_value);
+ prev_value = value;
+ }
+ if (a_two_byte_op)
+ WRF_wbyte(a_output, 12);
+ WRF_wbyte(a_output, (unsigned char)a_op);
+ }
+}
+
+static void
+write_float_entry(gs_fapi_font * a_fapi_font, WRF_output * a_output,
+ int a_feature_id, int a_feature_count, bool a_two_byte_op,
+ int a_op)
+{
+ if (a_feature_count > 0) {
+ int i;
+
+ for (i = 0; i < a_feature_count; i++) {
+ double x = a_fapi_font->get_float(a_fapi_font, a_feature_id, i);
+
+ write_type2_float(a_output, x);
+ }
+ if (a_two_byte_op)
+ WRF_wbyte(a_output, 12);
+ WRF_wbyte(a_output, (unsigned char)a_op);
+ }
+}
+
+static void
+write_font_dict_index(gs_fapi_font * a_fapi_font, WRF_output * a_output,
+ unsigned char **a_charset_offset_ptr,
+ unsigned char **a_charstrings_offset_ptr,
+ unsigned char **a_private_dict_length_ptr)
+{
+ unsigned char *data_start = 0;
+
+ WRF_wtext(a_output, (const unsigned char *)"\x0\x1\x2\x0\x1\x0\x0", 7); /* count = 1, offset size = 2, first offset = 1, last offset = 0 (to be filled in later). */
+ if (a_output->m_pos)
+ data_start = a_output->m_pos;
+ write_word_entry(a_fapi_font, a_output, gs_fapi_font_feature_FontBBox, 4,
+ false, 5, 1);
+ write_float_entry(a_fapi_font, a_output, gs_fapi_font_feature_FontMatrix,
+ 6, true, 7);
+ write_type2_int(a_output, 0); /* 0 = Standard Encoding. */
+ WRF_wbyte(a_output, 16); /* 16 = opcode for 'encoding'. */
+ *a_charset_offset_ptr = a_output->m_pos;
+ WRF_wtext(a_output, (const unsigned char *)"\x1d" "xxxx", 5); /* placeholder for the offset to the charset, which will be a 5-byte integer. */
+ WRF_wbyte(a_output, 15); /* opcode for 'charset' */
+ *a_charstrings_offset_ptr = a_output->m_pos;
+ WRF_wtext(a_output, (const unsigned char *)"\x1d" "xxxx", 5); /* placeholder for the offset to the Charstrings index, which will be a 5-byte integer. */
+ WRF_wbyte(a_output, 17); /* opcode for 'Charstrings' */
+ *a_private_dict_length_ptr = a_output->m_pos;
+ WRF_wtext(a_output, (const unsigned char *)"\x1d" "xxxx\x1d" "yyyy", 10); /* placeholder for size and offset of Private dictionary, which will be 5-byte integers. */
+ WRF_wbyte(a_output, 18); /* opcode for 'Private' */
+ if (a_output->m_pos) {
+ int last_offset = a_output->m_pos - data_start + 1;
+
+ data_start[-2] = (unsigned char)(last_offset >> 8);
+ data_start[-1] = (unsigned char)(last_offset & 0xFF);
+ }
+}
+
+/**
+Write the character set. Return the number of characters.
+For the moment this is always 1. The number cannot be obtained
+via the FAPI interface, and FreeType doesn't need to know anything more
+than the fact that there is at least one character.
+*/
+static int
+write_charset(WRF_output * a_output, unsigned char *a_charset_offset_ptr)
+{
+ const int characters = 1;
+ int i = 0;
+
+ /* Write the offset to the start of the charset to the top dictionary. */
+ if (a_output->m_pos)
+ write_4_byte_int(a_charset_offset_ptr + 1, a_output->m_count);
+
+ /*
+ Write the charset. Write one less than the number of characters,
+ because the first one is assumed to be .notdef. For the moment
+ write all the others as .notdef (SID = 0) because we don't actually
+ need the charset at the moment.
+ */
+ WRF_wbyte(a_output, 0); /* format = 0 */
+ for (i = 1; i < characters; i++) {
+ WRF_wbyte(a_output, 0);
+ WRF_wbyte(a_output, 0);
+ }
+
+ return characters;
+}
+
+/**
+Write a set of empty charstrings. The only reason for the existence of the charstrings index is to tell
+FreeType how many glyphs there are.
+*/
+static void
+write_charstrings_index(WRF_output * a_output, int a_characters,
+ unsigned char *a_charstrings_offset_ptr)
+{
+ /* Write the offset to the charstrings index to the top dictionary. */
+ if (a_output->m_pos)
+ write_4_byte_int(a_charstrings_offset_ptr + 1, a_output->m_count);
+
+ /* Write the index. */
+ WRF_wbyte(a_output, (unsigned char)(a_characters >> 8));
+ WRF_wbyte(a_output, (unsigned char)(a_characters & 0xFF));
+ WRF_wbyte(a_output, 1); /* offset size = 1. */
+ while (a_characters-- >= 0)
+ WRF_wbyte(a_output, 1); /* offset = 1 */
+}
+
+static void
+write_gsubrs_index(gs_fapi_font * a_fapi_font, WRF_output * a_output)
+{
+ unsigned char *cur_offset = 0;
+ unsigned char *data_start = 0;
+ int i;
+ int count = a_fapi_font->get_word(a_fapi_font,
+ gs_fapi_font_feature_GlobalSubrs_count,
+ 0);
+
+ WRF_wbyte(a_output, (unsigned char)(count >> 8));
+ WRF_wbyte(a_output, (unsigned char)(count & 0xFF));
+
+ if (count <= 0)
+ return;
+
+ WRF_wbyte(a_output, 4); /* offset size = 4 bytes */
+ WRF_wtext(a_output, (const unsigned char *)"\x0\x0\x0\x1", 4); /* first offset = 1 */
+
+ if (a_output->m_pos)
+ cur_offset = a_output->m_pos;
+
+ /* Write dummy bytes for the offsets at the end of each data item. */
+ for (i = 0; i < count; i++)
+ WRF_wtext(a_output, (const unsigned char *)"xxxx", 4);
+
+ if (a_output->m_pos)
+ data_start = a_output->m_pos;
+
+ for (i = 0; i < count; i++) {
+ long buffer_size = a_output->m_limit - a_output->m_count;
+ long length = a_fapi_font->get_gsubr(a_fapi_font, i, a_output->m_pos,
+ (ushort) buffer_size);
+
+ if (a_output->m_pos)
+ WRF_wtext(a_output, a_output->m_pos, length);
+ else
+ a_output->m_count += length;
+ if (cur_offset) {
+ long pos = a_output->m_pos - data_start + 1;
+
+ write_4_byte_int(cur_offset, pos);
+ cur_offset += 4;
+ }
+ }
+}
+
+static void
+write_subrs_index(gs_fapi_font * a_fapi_font, WRF_output * a_output)
+{
+ unsigned char *cur_offset = 0;
+ unsigned char *data_start = 0;
+ int i;
+ int count =
+ a_fapi_font->get_word(a_fapi_font, gs_fapi_font_feature_Subrs_count,
+ 0);
+
+ WRF_wbyte(a_output, (unsigned char)(count >> 8));
+ WRF_wbyte(a_output, (unsigned char)(count & 0xFF));
+
+ if (count <= 0)
+ return;
+
+ WRF_wbyte(a_output, 4); /* offset size = 4 bytes */
+ WRF_wtext(a_output, (const unsigned char *)"\x0\x0\x0\x1", 4); /* first offset = 1 */
+
+ if (a_output->m_pos)
+ cur_offset = a_output->m_pos;
+
+ /* Write dummy bytes for the offsets at the end of each data item. */
+ for (i = 0; i < count; i++)
+ WRF_wtext(a_output, (const unsigned char *)"xxxx", 4);
+
+ if (a_output->m_pos)
+ data_start = a_output->m_pos;
+
+ for (i = 0; i < count; i++) {
+ long buffer_size = a_output->m_limit - a_output->m_count;
+ long length = a_fapi_font->get_subr(a_fapi_font, i, a_output->m_pos,
+ (ushort) buffer_size);
+
+ if (a_output->m_pos)
+ WRF_wtext(a_output, a_output->m_pos, length);
+ else
+ a_output->m_count += length;
+ if (cur_offset) {
+ long pos = a_output->m_pos - data_start + 1;
+
+ write_4_byte_int(cur_offset, pos);
+ cur_offset += 4;
+ }
+ }
+}
+
+static void
+write_private_dict(gs_fapi_font * a_fapi_font, WRF_output * a_output,
+ unsigned char *a_private_dict_length_ptr)
+{
+ int count, initial = a_output->m_count;
+
+ /* Write the offset to the start of the private dictionary to the top dictionary. */
+ unsigned char *start = a_output->m_pos;
+
+ if (a_output->m_pos)
+ write_4_byte_int(a_private_dict_length_ptr + 6, a_output->m_count);
+
+ write_word_entry(a_fapi_font, a_output, gs_fapi_font_feature_BlueFuzz, 1,
+ true, 11, 16);
+
+ write_type2_float(a_output,
+ a_fapi_font->get_long(a_fapi_font,
+ gs_fapi_font_feature_BlueScale,
+ 0) / 65536.0);
+ WRF_wbyte(a_output, 12);
+ WRF_wbyte(a_output, 9);
+
+ write_word_entry(a_fapi_font, a_output, gs_fapi_font_feature_BlueShift, 1,
+ true, 10, 16);
+ write_delta_array_entry(a_fapi_font, a_output,
+ gs_fapi_font_feature_BlueValues, false, 6, 16);
+ write_delta_array_entry(a_fapi_font, a_output,
+ gs_fapi_font_feature_OtherBlues, false, 7, 16);
+ write_delta_array_entry(a_fapi_font, a_output,
+ gs_fapi_font_feature_FamilyBlues, false, 8, 16);
+ write_delta_array_entry(a_fapi_font, a_output,
+ gs_fapi_font_feature_FamilyOtherBlues, false, 9,
+ 16);
+ write_word_entry(a_fapi_font, a_output, gs_fapi_font_feature_ForceBold, 1,
+ true, 14, 1);
+ write_word_entry(a_fapi_font, a_output, gs_fapi_font_feature_StdHW, 1,
+ false, 10, 16);
+ write_word_entry(a_fapi_font, a_output, gs_fapi_font_feature_StdVW, 1,
+ false, 11, 16);
+ write_delta_array_entry(a_fapi_font, a_output,
+ gs_fapi_font_feature_StemSnapH, true, 12, 16);
+ write_delta_array_entry(a_fapi_font, a_output,
+ gs_fapi_font_feature_StemSnapV, true, 13, 16);
+
+ /*
+ Write the default width and the nominal width. These values are not available via
+ the FAPI interface so we have to get a pointer to the Type 1 font structure and
+ extract them directly.
+ */
+ {
+ gs_font_type1 *t1 = (gs_font_type1 *) a_fapi_font->client_font_data;
+
+ write_type2_float(a_output, fixed2float(t1->data.defaultWidthX));
+ WRF_wbyte(a_output, 20);
+ write_type2_float(a_output, fixed2float(t1->data.nominalWidthX));
+ WRF_wbyte(a_output, 21);
+ }
+
+ count =
+ a_fapi_font->get_word(a_fapi_font, gs_fapi_font_feature_Subrs_count,
+ 0);
+ /* If we have local /Subrs we need to make a new dict ( see calling routine) and
+ * we also need to add an entry to the Provate dict with an offset to the /Subrs
+ * dict. This is complicated by the fact that the offset includes the data for
+ * the offset (its contained in the Private dict) and the size of the data depends
+ * on its value (because of number representation).
+ */
+ if (count) {
+ int n = 1, n1;
+
+ do {
+ n1 = a_output->m_count - initial + 1 + n; /* one for the operator, plus the size needed for the representation */
+ switch (n) {
+ case 1:
+ if (n1 >= -107 && n1 <= 107) {
+ write_type2_int(a_output, n1);
+ n = 5;
+ }
+ break;
+ case 2:
+ if ((n1 >= 108 && n1 <= 1131)
+ || (n1 >= -1131 && n1 <= -108)) {
+ write_type2_int(a_output, n1);
+ n = 5;
+ }
+ break;
+ case 3:
+ if (n1 >= -32768 && n1 <= 32767) {
+ write_type2_int(a_output, n1);
+ n = 5;
+ }
+ break;
+ case 4:
+ break;
+ case 5:
+ write_type2_int(a_output, n1);
+ break;
+ }
+ n++;
+ }
+ while (n < 5);
+
+ WRF_wbyte(a_output, 19);
+ }
+
+ /* Write the length in bytes of the private dictionary to the top dictionary. */
+ if (a_output->m_pos)
+ write_4_byte_int(a_private_dict_length_ptr + 1,
+ a_output->m_pos - start);
+}
+
+/**
+Write a Type 2 font in binary format and return its length in bytes.
+If a_buffer_size is less than the total length, only a_buffer_size bytes are written, but the total
+length is returned correctly.
+*/
+long
+gs_fapi_serialize_type2_font(gs_fapi_font * a_fapi_font,
+ unsigned char *a_buffer, long a_buffer_size)
+{
+ unsigned char *charset_offset_ptr = NULL;
+ unsigned char *charstrings_offset_ptr = NULL;
+ unsigned char *private_dict_length_ptr = NULL;
+ int characters = 0;
+
+ WRF_output output;
+
+ WRF_init(&output, a_buffer, a_buffer_size);
+
+ write_header(&output);
+ write_name_index(&output);
+ write_font_dict_index(a_fapi_font, &output, &charset_offset_ptr,
+ &charstrings_offset_ptr, &private_dict_length_ptr);
+
+ /* Write an empty string index. */
+ WRF_wtext(&output, (const unsigned char *)"\x0\x0", 2);
+
+ write_gsubrs_index(a_fapi_font, &output);
+ characters = write_charset(&output, charset_offset_ptr);
+ write_charstrings_index(&output, characters, charstrings_offset_ptr);
+ write_private_dict(a_fapi_font, &output, private_dict_length_ptr);
+ write_subrs_index(a_fapi_font, &output);
+
+ return output.m_count;
+}