summaryrefslogtreecommitdiff
path: root/devices/vector/gdevpdtw.c
diff options
context:
space:
mode:
Diffstat (limited to 'devices/vector/gdevpdtw.c')
-rw-r--r--devices/vector/gdevpdtw.c895
1 files changed, 895 insertions, 0 deletions
diff --git a/devices/vector/gdevpdtw.c b/devices/vector/gdevpdtw.c
new file mode 100644
index 000000000..e7f64a4c3
--- /dev/null
+++ b/devices/vector/gdevpdtw.c
@@ -0,0 +1,895 @@
+/* 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.
+*/
+
+
+/* Font resource writing for pdfwrite text */
+#include "memory_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gxfcmap.h"
+#include "gxfont.h"
+#include "gxfcopy.h"
+#include "gscencs.h"
+#include "gdevpsf.h"
+#include "gdevpdfx.h"
+#include "gdevpdfo.h" /* for object->written */
+#include "gdevpdtd.h" /* for writing FontDescriptor */
+#include "gdevpdtf.h"
+#include "gdevpdti.h" /* for writing bitmap fonts Encoding */
+#include "gdevpdtw.h"
+#include "gdevpdtv.h"
+#include "sarc4.h"
+
+static const char *const encoding_names[] = {
+ KNOWN_REAL_ENCODING_NAMES
+};
+
+/* ================ Font resource writing ================ */
+
+/* ---------------- Private ---------------- */
+
+/* Write the Widths for a font. */
+static int
+pdf_write_Widths(gx_device_pdf *pdev, int first, int last, const double *widths)
+{
+ stream *s = pdev->strm;
+ int i;
+
+ if (first > last)
+ first = last = 0;
+ pprintd2(s, "/FirstChar %d/LastChar %d/Widths[", first, last);
+ for (i = first; i <= last; ++i)
+ pprintg1(s, (i & 15 ? " %g" : "\n%g"), psdf_round(widths[i], 100, 10));
+ stream_puts(s, "]\n");
+ return 0;
+}
+
+/* Check strings equality. */
+static bool
+strings_equal(const gs_const_string *str0, const gs_const_string *str1)
+{
+ return str0->size == str1->size &&
+ !memcmp(str0->data, str1->data, str0->size);
+}
+
+/* Check if an encoding element differs from a standard one. */
+static int
+pdf_different_encoding_element(const pdf_font_resource_t *pdfont, int ch, int encoding_index)
+{
+ if (pdfont->u.simple.Encoding[ch].is_difference)
+ return 1;
+ else if (encoding_index != ENCODING_INDEX_UNKNOWN) {
+ gs_glyph glyph0 = gs_c_known_encode(ch, encoding_index);
+ gs_glyph glyph1 = pdfont->u.simple.Encoding[ch].glyph;
+ gs_const_string str;
+ int code = gs_c_glyph_name(glyph0, &str);
+
+ if (code < 0)
+ return code; /* Must not happen */
+ if (glyph1 != GS_NO_GLYPH)
+ if (!strings_equal(&str, &pdfont->u.simple.Encoding[ch].str))
+ return 1;
+ }
+ return 0;
+}
+
+/* Find an index of a different encoding element. */
+int
+pdf_different_encoding_index(const pdf_font_resource_t *pdfont, int ch0)
+{
+ gs_encoding_index_t base_encoding = pdfont->u.simple.BaseEncoding;
+ int ch, code;
+
+ for (ch = ch0; ch < 256; ++ch) {
+ code = pdf_different_encoding_element(pdfont, ch, base_encoding);
+ if (code < 0)
+ return code; /* Must not happen */
+ if (code)
+ break;
+ }
+ return ch;
+}
+
+/* Check for unknown encode (simple fonts only). */
+static bool
+pdf_simple_font_needs_ToUnicode(const pdf_font_resource_t *pdfont)
+{
+ int ch;
+ unsigned char mask = (pdfont->FontType == ft_encrypted || pdfont->FontType == ft_encrypted2
+ ? GS_C_PDF_GOOD_GLYPH_MASK : GS_C_PDF_GOOD_NON_SYMBOL_MASK);
+
+ if (pdfont->u.simple.Encoding == NULL)
+ return true; /* Bitmap Type 3 fonts have no pdfont->u.simple.Encoding . */
+ if (pdfont->FontType == ft_TrueType)
+ /*
+ TrueType fonts are always written as symbolic, and so they do not have
+ an Encoding entry (SVN revision 11735, bugs #690744, #691036, #691319).
+ In this circumstance, write the ToUnicode map to get a searchable PDF.
+ */
+ return true;
+ for (ch = 0; ch < 256; ++ch) {
+ pdf_encoding_element_t *pet = &pdfont->u.simple.Encoding[ch];
+ gs_glyph glyph = pet->glyph;
+
+ if (glyph == GS_NO_GLYPH)
+ continue;
+ if (glyph < gs_c_min_std_encoding_glyph || glyph >= GS_MIN_CID_GLYPH) {
+ if (pet->str.size == 0)
+ return true;
+ glyph = gs_c_name_glyph(pet->str.data, pet->str.size);
+ if (glyph == GS_NO_GLYPH)
+ return true;
+ }
+ glyph -= gs_c_min_std_encoding_glyph;
+ if( glyph > GS_C_PDF_MAX_GOOD_GLYPH ||
+ !(gs_c_pdf_glyph_type[glyph >> 2] & (mask << (( glyph & 3 )<<1) )))
+ return true;
+ }
+ return false;
+}
+
+/* Write Encoding differencrs. */
+int
+pdf_write_encoding(gx_device_pdf *pdev, const pdf_font_resource_t *pdfont, long id, int ch)
+{
+ /* Note : this truncates extended glyph names to original names. */
+ stream *s;
+ gs_encoding_index_t base_encoding = pdfont->u.simple.BaseEncoding;
+ const int sl = strlen(gx_extendeg_glyph_name_separator);
+ int prev = 256, code, cnt = 0;
+
+ pdf_open_separate(pdev, id, resourceEncoding);
+ s = pdev->strm;
+ stream_puts(s, "<</Type/Encoding");
+ if (base_encoding < 0 && pdev->ForOPDFRead)
+ base_encoding = ENCODING_INDEX_STANDARD;
+ if (base_encoding > 0)
+ pprints1(s, "/BaseEncoding/%s", encoding_names[base_encoding]);
+ stream_puts(s, "/Differences[");
+ for (; ch < 256; ++ch) {
+ code = pdf_different_encoding_element(pdfont, ch, base_encoding);
+ if (code < 0)
+ return code; /* Must not happen */
+ if (code == 0 && (pdfont->FontType == ft_user_defined ||
+ pdfont->FontType == ft_PCL_user_defined ||
+ pdfont->FontType == ft_MicroType ||
+ pdfont->FontType == ft_GL2_stick_user_defined ||
+ pdfont->FontType == ft_GL2_531)) {
+ /* PDF 1.4 spec Appendix H Note 42 says that
+ * Acrobat 4 can't properly handle Base Encoding.
+ * Enforce writing differences against that.
+ */
+ if (pdfont->used[ch >> 3] & 0x80 >> (ch & 7))
+ if (pdfont->u.simple.Encoding[ch].str.size)
+ code = 1;
+ }
+ if (code) {
+ const byte *d = pdfont->u.simple.Encoding[ch].str.data;
+ int i, l = pdfont->u.simple.Encoding[ch].str.size;
+
+ if (pdev->HavePDFWidths) {
+ for (i = 0; i + sl < l; i++)
+ if (!memcmp(d + i, gx_extendeg_glyph_name_separator, sl)) {
+ l = i;
+ break;
+ }
+ }
+ if (ch != prev + 1) {
+ pprintd1(s, "\n%d", ch);
+ cnt = 1;
+ } else if (!(cnt++ & 15))
+ stream_puts(s, "\n");
+ pdf_put_name(pdev, d, l);
+ prev = ch;
+ }
+ }
+ stream_puts(s, "]>>\n");
+ pdf_end_separate(pdev, resourceEncoding);
+ return 0;
+}
+
+/* Write Encoding reference. */
+int
+pdf_write_encoding_ref(gx_device_pdf *pdev,
+ const pdf_font_resource_t *pdfont, long id)
+{
+ stream *s = pdev->strm;
+
+ if (id != 0) {
+ pprintld1(s, "/Encoding %ld 0 R", id);
+ pdf_record_usage_by_parent(pdev, id, pdfont->object->id);
+ }
+ else if (pdfont->u.simple.BaseEncoding > 0) {
+ gs_encoding_index_t base_encoding = pdfont->u.simple.BaseEncoding;
+ pprints1(s, "/Encoding/%s", encoding_names[base_encoding]);
+ }
+ return 0;
+}
+
+/* Write the Subtype and Encoding for a simple font. */
+static int
+pdf_write_simple_contents(gx_device_pdf *pdev,
+ const pdf_font_resource_t *pdfont)
+{
+ stream *s = pdev->strm;
+ long diff_id = 0;
+ int ch = (pdfont->u.simple.Encoding ? 0 : 256);
+ int code = 0;
+
+ ch = pdf_different_encoding_index(pdfont, ch);
+ if (ch < 256)
+ diff_id = pdf_obj_ref(pdev);
+ code = pdf_write_encoding_ref(pdev, pdfont, diff_id);
+ if (code < 0)
+ return code;
+ pprints1(s, "/Subtype/%s>>\n",
+ (pdfont->FontType == ft_TrueType ? "TrueType" :
+ pdfont->u.simple.s.type1.is_MM_instance ? "MMType1" : "Type1"));
+ pdf_end_separate(pdev, resourceFont);
+ if (diff_id) {
+ mark_font_descriptor_symbolic(pdfont);
+ code = pdf_write_encoding(pdev, pdfont, diff_id, ch);
+ if (code < 0)
+ return code;
+ }
+ return 0;
+}
+
+/*
+ * Write the W[2] entries for a CIDFont. *pdfont is known to be a
+ * CIDFont (type 0 or 2).
+ */
+static bool
+pdf_compute_CIDFont_default_widths(const pdf_font_resource_t *pdfont, int wmode, int *pdw, int *pdv)
+{
+ psf_glyph_enum_t genum;
+ gs_glyph glyph;
+ ushort counts[1500]; /* Some CID fonts use vertical widths 1026 .*/
+ int dw_count = 0, i, dwi = 0, neg_count = 0, pos_count = 0;
+ double *w = (wmode ? pdfont->u.cidfont.Widths2 : pdfont->Widths);
+
+ /* We don't wont to scan for both negative and positive widths,
+ * to save the C stack space.
+ * Doubtly they both are used in same font.
+ * So just count positive and negative widths separately
+ * and use the corresponding sign.
+ * fixme : implement 2 hystograms.
+ */
+ psf_enumerate_bits_begin(&genum, NULL,
+ wmode ? pdfont->u.cidfont.used2 : pdfont->used,
+ pdfont->count, GLYPH_SPACE_INDEX);
+ memset(counts, 0, sizeof(counts));
+ while (!psf_enumerate_glyphs_next(&genum, &glyph)) {
+ int i = glyph - GS_MIN_CID_GLYPH;
+
+ if ( i < pdfont->count) { /* safety */
+ int width = (int)(w[i] + 0.5);
+
+ counts[min(any_abs(width), countof(counts) - 1)]++;
+ if (width > 0)
+ pos_count++;
+ else if (width < 0)
+ neg_count++;
+ }
+ }
+ for (i = 1; i < countof(counts); ++i)
+ if (counts[i] > dw_count)
+ dwi = i, dw_count = counts[i];
+ *pdw = (neg_count > pos_count ? -dwi : dwi);
+ *pdv = 0;
+ if (wmode) {
+ psf_enumerate_glyphs_reset(&genum);
+ while (!psf_enumerate_glyphs_next(&genum, &glyph)) {
+ int i = glyph - GS_MIN_CID_GLYPH;
+
+ if ( i < pdfont->count) { /* safety */
+ int width = (int)(w[i] + 0.5);
+
+ if (min(any_abs(width), countof(counts) - 1) == any_abs(dwi)) {
+ *pdv = (int)(pdfont->u.cidfont.v[i * 2 + 1] + 0.5);
+ break;
+ }
+ }
+ }
+ }
+ return (dw_count + counts[0] > 0);
+}
+
+/*
+ * Write the [D]W[2] entries for a CIDFont. *pdfont is known to be a
+ * CIDFont (type 0 or 2).
+ */
+static int
+pdf_write_CIDFont_widths(gx_device_pdf *pdev,
+ const pdf_font_resource_t *pdfont, int wmode)
+{
+ /*
+ * The values of the CIDFont width keys are as follows:
+ * DW = w (default 0)
+ * W = [{c [w ...] | cfirst clast w}*]
+ * DW2 = [vy w1y] (default [880 -1000])
+ * W2 = [{c [w1y vx vy ...] | cfirst clast w1y vx vy}*]
+ */
+ stream *s = pdev->strm;
+ psf_glyph_enum_t genum;
+ gs_glyph glyph;
+ int dw = 0, dv = 0, prev = -2;
+ const char *Widths_key = (wmode ? "/W2" : "/W");
+ double *w = (wmode ? pdfont->u.cidfont.Widths2 : pdfont->Widths);
+
+ /* Compute and write default width : */
+ if (pdf_compute_CIDFont_default_widths(pdfont, wmode, &dw, &dv)) {
+ if (wmode) {
+ pprintd2(s, "/DW2 [%d %d]\n", dv, dw);
+ } else
+ pprintd1(s, "/DW %d\n", dw);
+ }
+
+ /*
+ * Now write all widths different from the default one. Currently we make no
+ * attempt to optimize this: we write every width individually.
+ */
+ psf_enumerate_bits_begin(&genum, NULL,
+ wmode ? pdfont->u.cidfont.used2 : pdfont->used,
+ pdfont->count, GLYPH_SPACE_INDEX);
+ {
+ while (!psf_enumerate_glyphs_next(&genum, &glyph)) {
+ int cid = glyph - GS_MIN_CID_GLYPH;
+ int width = (int)(w[cid] + 0.5);
+
+#if 0 /* Must write zero widths - see test file of the bug Bug 687681.
+ We don't enumerate unused glyphs here due to pdfont->used. */
+ if (width == 0)
+ continue; /* Don't write for unused glyphs. */
+#else
+ { /* Check whether copied font really have this glyph.
+ debugged with 401-01.ps, which uses undefined CIDs. */
+ gs_font_base *pfont = pdf_font_resource_font(pdfont, false);
+ gs_glyph_info_t info;
+
+ if (pfont->FontType == ft_TrueType) {
+ /* We're converting a Type 42 into CIDFontType2. */
+ /* We know that CIDs equal to char codes. */
+ gs_glyph glyph1;
+ int ch = glyph & 0xff;
+
+ glyph1 = pfont->procs.encode_char((gs_font *)pfont, ch, GLYPH_SPACE_NAME);
+ if (cid == 0 && glyph1 == GS_NO_GLYPH)
+ glyph1 = copied_get_notdef((gs_font *)pdf_font_resource_font(pdfont, false));
+ if (glyph1 == GS_NO_GLYPH)
+ continue;
+ if (pfont->procs.glyph_info((gs_font *)pfont, glyph1, NULL, 0, &info) < 0)
+ continue;
+ } else if (pfont->procs.glyph_info((gs_font *)pfont, glyph, NULL, 0, &info) < 0)
+ continue;
+ }
+#endif
+ if (cid == prev + 1) {
+ if (wmode) {
+ int vx = (int)(pdfont->u.cidfont.v[cid * 2 + 0] + 0.5);
+ int vy = (int)(pdfont->u.cidfont.v[cid * 2 + 1] + 0.5);
+
+ pprintd3(s, "\n%d %d %d", width, vx, vy);
+ } else
+ pprintd1(s, "\n%d", width);
+ } else if (pdev->PDFA == 0 && width == dw &&
+ (!wmode || (int)(pdfont->u.cidfont.v[cid * 2 + 0] + 0.5) ==
+ (int)(pdfont->Widths[cid] / 2 + 0.5)) &&
+ (!wmode || (int)(pdfont->u.cidfont.v[cid * 2 + 1] + 0.5) == dv))
+ continue;
+ else {
+ if (prev >= 0)
+ stream_puts(s, "]\n");
+ else {
+ stream_puts(s, Widths_key);
+ stream_puts(s, "[");
+ }
+ if (wmode) {
+ int vx = (int)(pdfont->u.cidfont.v[cid * 2 + 0] + 0.5);
+ int vy = (int)(pdfont->u.cidfont.v[cid * 2 + 1] + 0.5);
+
+ pprintd4(s, "%d[%d %d %d", cid, width, vx, vy);
+ } else
+ pprintd2(s, "%d[%d", cid, width);
+ }
+ prev = cid;
+ }
+ if (prev >= 0)
+ stream_puts(s, "]]\n");
+ }
+
+ return 0;
+}
+
+/* ---------------- Specific FontTypes ---------------- */
+
+/* Write the contents of a Type 0 font resource. */
+int
+pdf_write_contents_type0(gx_device_pdf *pdev, pdf_font_resource_t *pdfont)
+{
+ stream *s = pdev->strm;
+
+ /*
+ * The Encoding name might be missing if an error occurred when
+ * creating the font resource.
+ */
+ if (pdfont->u.type0.Encoding_name[0])
+ pprints1(s, "/Encoding %s", pdfont->u.type0.Encoding_name);
+ pprintld1(s, "/DescendantFonts[%ld 0 R]",
+ pdf_font_id(pdfont->u.type0.DescendantFont));
+ stream_puts(s, "/Subtype/Type0>>\n");
+ pdf_end_separate(pdev, resourceFont);
+ return 0;
+}
+
+/*
+ * Finish writing the contents of a Type 3 font resource (FontBBox, Widths,
+ * Subtype).
+ */
+int
+pdf_finish_write_contents_type3(gx_device_pdf *pdev,
+ pdf_font_resource_t *pdfont)
+{
+ stream *s = pdev->strm;
+
+ pdf_write_font_bbox_float(pdev, &pdfont->u.simple.s.type3.FontBBox);
+ pdf_write_Widths(pdev, pdfont->u.simple.FirstChar,
+ pdfont->u.simple.LastChar, pdfont->Widths);
+ stream_puts(s, "/Subtype/Type3>>\n");
+ pdf_end_separate(pdev, resourceFont);
+ return 0;
+}
+
+/* Write the contents of a standard (base 14) font resource. */
+int
+pdf_write_contents_std(gx_device_pdf *pdev, pdf_font_resource_t *pdfont)
+{
+ return pdf_write_simple_contents(pdev, pdfont);
+}
+
+/* Write the contents of a simple (Type 1 or Type 42) font resource. */
+int
+pdf_write_contents_simple(gx_device_pdf *pdev, pdf_font_resource_t *pdfont)
+{
+ pdf_write_Widths(pdev, pdfont->u.simple.FirstChar,
+ pdfont->u.simple.LastChar, pdfont->Widths);
+ return pdf_write_simple_contents(pdev, pdfont);
+}
+
+/* Write the contents of a CIDFont resource. */
+static int
+write_contents_cid_common(gx_device_pdf *pdev, pdf_font_resource_t *pdfont,
+ int subtype)
+{
+ /* Write [D]W[2], CIDSystemInfo, and Subtype, and close the object. */
+ stream *s = pdev->strm;
+ int code;
+
+ if (pdfont->Widths != 0) {
+ code = pdf_write_CIDFont_widths(pdev, pdfont, 0);
+ if (code < 0)
+ return code;
+ } else {
+ /* With a vertical font, the viewer uses /DW
+ to determine glyph width to compute its v-vector. */
+ stream_puts(s, "/DW 0\n");
+ }
+ if (pdfont->u.cidfont.Widths2 != 0) {
+ code = pdf_write_CIDFont_widths(pdev, pdfont, 1);
+ if (code < 0)
+ return code;
+ }
+ if (pdfont->u.cidfont.CIDSystemInfo_id)
+ pprintld1(s, "/CIDSystemInfo %ld 0 R",
+ pdfont->u.cidfont.CIDSystemInfo_id);
+ pprintd1(s, "/Subtype/CIDFontType%d>>\n", subtype);
+ pdf_end_separate(pdev, resourceFont);
+ return 0;
+}
+int
+pdf_write_contents_cid0(gx_device_pdf *pdev, pdf_font_resource_t *pdfont)
+{
+ return write_contents_cid_common(pdev, pdfont, 0);
+}
+int
+pdf_write_contents_cid2(gx_device_pdf *pdev, pdf_font_resource_t *pdfont)
+{
+ int count = pdfont->count;
+ long map_id = 0;
+ psf_glyph_enum_t genum;
+ gs_glyph glyph;
+ int code;
+
+ /* Check for the identity CIDMap. */
+ psf_enumerate_bits_begin(&genum, NULL, pdfont->used, count,
+ GLYPH_SPACE_INDEX);
+ while (!psf_enumerate_glyphs_next(&genum, &glyph)) {
+ int cid = glyph - GS_MIN_CID_GLYPH;
+ int gid = pdfont->u.cidfont.CIDToGIDMap[cid];
+
+ if (gid != cid) { /* non-identity map */
+ map_id = pdf_obj_ref(pdev);
+ pprintld1(pdev->strm, "/CIDToGIDMap %ld 0 R\n", map_id);
+ break;
+ }
+ }
+
+ if (map_id == 0 && pdf_font_descriptor_embedding(pdfont->FontDescriptor)) {
+ code = stream_puts(pdev->strm, "/CIDToGIDMap /Identity\n");
+ if (code < 0)
+ return code;
+ }
+
+ code = write_contents_cid_common(pdev, pdfont, 2);
+ if (code < 0)
+ return code;
+
+ if (map_id && pdf_font_descriptor_embedding(pdfont->FontDescriptor)) {
+ pdf_data_writer_t writer;
+ int i;
+
+ pdf_begin_data_stream(pdev, &writer,
+ DATA_STREAM_BINARY | (pdev->CompressFonts ? DATA_STREAM_COMPRESS : 0),
+ /* Don't set DATA_STREAM_ENCRYPT since we write to a temporary file.
+ See comment in pdf_begin_encrypt. */
+ map_id);
+ for (i = 0; i < pdfont->u.cidfont.CIDToGIDMapLength; ++i) {
+ uint gid = pdfont->u.cidfont.CIDToGIDMap[i];
+
+ stream_putc(writer.binary.strm, (byte)(gid >> 8));
+ stream_putc(writer.binary.strm, (byte)(gid));
+ }
+ code = pdf_end_data(&writer);
+ }
+ return code;
+}
+
+/* ---------------- External entries ---------------- */
+
+/* Write a font resource. */
+static int
+pdf_write_font_resource(gx_device_pdf *pdev, pdf_font_resource_t *pdfont)
+{
+ stream *s;
+ cos_dict_t *pcd_Resources = NULL;
+ char *base14_name = NULL;
+ int id;
+
+ if (pdfont->cmap_ToUnicode != NULL && pdfont->res_ToUnicode == NULL)
+ if (pdfont->FontType == ft_composite ||
+ ((pdfont->FontType == ft_encrypted || pdfont->FontType == ft_encrypted2 ||
+ pdfont->FontType == ft_TrueType || pdfont->FontType == ft_user_defined ||
+ pdfont->FontType == ft_GL2_stick_user_defined || pdfont->FontType == ft_PCL_user_defined ||
+ pdfont->FontType == ft_MicroType || pdfont->FontType == ft_GL2_531) &&
+ pdf_simple_font_needs_ToUnicode(pdfont))
+ ) {
+ pdf_resource_t *prcmap;
+ int code = pdf_cmap_alloc(pdev, pdfont->cmap_ToUnicode, &prcmap, -1);
+
+ if (code < 0)
+ return code;
+ pdfont->res_ToUnicode = prcmap;
+ }
+ if (pdev->CompatibilityLevel >= 1.2 &&
+ (pdfont->FontType == ft_user_defined ||
+ pdfont->FontType == ft_PCL_user_defined ||
+ pdfont->FontType == ft_MicroType ||
+ pdfont->FontType == ft_GL2_stick_user_defined ||
+ pdfont->FontType == ft_GL2_531) &&
+ pdfont->u.simple.s.type3.Resources != NULL &&
+ pdfont->u.simple.s.type3.Resources->elements != NULL) {
+ int code;
+
+ pcd_Resources = pdfont->u.simple.s.type3.Resources;
+ pcd_Resources->id = pdf_obj_ref(pdev);
+ pdf_open_separate(pdev, pcd_Resources->id, resourceFont);
+ code = COS_WRITE(pcd_Resources, pdev);
+ if (code < 0)
+ return code;
+ pdf_end_separate(pdev, resourceFont);
+ }
+ pdf_open_separate(pdev, pdf_font_id(pdfont), resourceFont);
+ s = pdev->strm;
+ stream_puts(s, "<<");
+ if (pdfont->BaseFont.size > 0) {
+ stream_puts(s, "/BaseFont");
+ if (pdfont->FontDescriptor && !pdf_font_descriptor_embedding(pdfont->FontDescriptor)
+ && (base14_name = (char *)pdf_find_base14_name((byte *)pdfont->BaseFont.data, (unsigned int)pdfont->BaseFont.size)))
+ pdf_put_name(pdev, (byte *)base14_name, (unsigned int)strlen(base14_name));
+ else
+ pdf_put_name(pdev, (byte *)pdfont->BaseFont.data, pdfont->BaseFont.size);
+ }
+ if (pdfont->FontDescriptor) {
+ id = pdf_font_descriptor_id(pdfont->FontDescriptor);
+ pprintld1(s, "/FontDescriptor %ld 0 R", id);
+ if (pdev->Linearise) {
+ pdf_set_font_descriptor_usage(pdev, pdfont->object->id, pdfont->FontDescriptor);
+ }
+ }
+ if (pdfont->res_ToUnicode) {
+ id = pdf_resource_id((const pdf_resource_t *)pdfont->res_ToUnicode);
+ pprintld1(s, "/ToUnicode %ld 0 R", id);
+ pdf_record_usage_by_parent(pdev, id, pdfont->object->id);
+ }
+ if (pdev->CompatibilityLevel > 1.0)
+ stream_puts(s, "/Type/Font\n");
+ else
+ pprintld1(s, "/Type/Font/Name/R%ld\n", pdf_font_id(pdfont));
+ if (pdev->ForOPDFRead && pdfont->global)
+ stream_puts(s, "/.Global true\n");
+ if (pcd_Resources != NULL) {
+ id = pcd_Resources->id;
+ pprintld1(s, "/Resources %ld 0 R\n", id);
+ pdf_record_usage_by_parent(pdev, id, pdfont->object->id);
+ }
+ return pdfont->write_contents(pdev, pdfont);
+}
+
+/*
+ * Close the text-related parts of a document, including writing out font
+ * and related resources.
+ */
+int
+write_font_resources(gx_device_pdf *pdev, pdf_resource_list_t *prlist)
+{
+ int j;
+ pdf_resource_t *pres;
+
+ for (j = 0; j < NUM_RESOURCE_CHAINS; ++j)
+ for (pres = prlist->chains[j]; pres != 0; pres = pres->next) {
+ pdf_font_resource_t *const pdfont = (pdf_font_resource_t *)pres;
+
+ if (pdf_resource_id(pres) != -1) {
+ int code = pdf_compute_BaseFont(pdev, pdfont, true);
+
+ if (code < 0)
+ return code;
+ code = pdf_write_font_resource(pdev, pdfont);
+ if (code < 0)
+ return code;
+ pdfont->object->written = true;
+ }
+ }
+ return 0;
+}
+int
+pdf_finish_resources(gx_device_pdf *pdev, pdf_resource_type_t type,
+ int (*finish_proc)(gx_device_pdf *,
+ pdf_resource_t *))
+{
+ int j;
+ pdf_resource_t *pres;
+
+ for (j = 0; j < NUM_RESOURCE_CHAINS; ++j)
+ for (pres = pdev->resources[type].chains[j];
+ pres != 0; pres = pres->next
+ ) {
+ int code = finish_proc(pdev, pres);
+
+ if (code < 0)
+ return code;
+ }
+ return 0;
+}
+
+/* ================ CMap resource writing ================ */
+
+/*
+ * Write the CIDSystemInfo for a CIDFont or a CMap.
+ */
+static int
+pdf_write_cid_system_info_to_stream(gx_device_pdf *pdev, stream *s,
+ const gs_cid_system_info_t *pcidsi, gs_id object_id)
+{
+ byte *Registry, *Ordering;
+
+ Registry = gs_alloc_bytes(pdev->pdf_memory, pcidsi->Registry.size, "temporary buffer for Registry");
+ if (!Registry)
+ return(gs_note_error(gs_error_VMerror));
+ Ordering = gs_alloc_bytes(pdev->pdf_memory, pcidsi->Ordering.size, "temporary buffer for Registry");
+ if (!Ordering) {
+ gs_free_object(pdev->pdf_memory, Registry, "free temporary Registry buffer");
+ return(gs_note_error(gs_error_VMerror));
+ }
+ memcpy(Registry, pcidsi->Registry.data, pcidsi->Registry.size);
+ memcpy(Ordering, pcidsi->Ordering.data, pcidsi->Ordering.size);
+ if (pdev->KeyLength && object_id != 0) {
+ stream_arcfour_state sarc4;
+ int code;
+
+ code = pdf_encrypt_init(pdev, object_id, &sarc4);
+ if (code < 0) {
+ gs_free_object(pdev->pdf_memory, Registry, "free temporary Registry buffer");
+ gs_free_object(pdev->pdf_memory, Ordering, "free temporary Ordering buffer");
+ return(gs_note_error(code));
+ }
+ s_arcfour_process_buffer(&sarc4, Registry, pcidsi->Registry.size);
+ code = pdf_encrypt_init(pdev, object_id, &sarc4);
+ if (code < 0) {
+ gs_free_object(pdev->pdf_memory, Registry, "free temporary Registry buffer");
+ gs_free_object(pdev->pdf_memory, Ordering, "free temporary Ordering buffer");
+ return(gs_note_error(code));
+ }
+ s_arcfour_process_buffer(&sarc4, Ordering, pcidsi->Ordering.size);
+ }
+ stream_puts(s, "<<\n/Registry");
+ s_write_ps_string(s, Registry, pcidsi->Registry.size, PRINT_HEX_NOT_OK);
+ stream_puts(s, "\n/Ordering");
+ s_write_ps_string(s, Ordering, pcidsi->Ordering.size, PRINT_HEX_NOT_OK);
+ pprintd1(s, "\n/Supplement %d\n>>\n", pcidsi->Supplement);
+ gs_free_object(pdev->pdf_memory, Registry, "free temporary Registry buffer");
+ gs_free_object(pdev->pdf_memory, Ordering, "free temporary Ordering buffer");
+ return 0;
+}
+
+int
+pdf_write_cid_system_info(gx_device_pdf *pdev,
+ const gs_cid_system_info_t *pcidsi, gs_id object_id)
+{
+ return pdf_write_cid_system_info_to_stream(pdev, pdev->strm, pcidsi, object_id);
+}
+
+int
+pdf_write_cid_systemInfo_separate(gx_device_pdf *pdev, const gs_cid_system_info_t *pcidsi, long *id)
+{
+ int code;
+
+ *id = pdf_begin_separate(pdev, resourceCIDSystemInfo);
+ code = pdf_write_cid_system_info(pdev, pcidsi, *id);
+ pdf_end_separate(pdev, resourceCIDSystemInfo);
+ return code;
+}
+
+/*
+ * Write a CMap resource. We pass the CMap object as well as the resource,
+ * because we write CMaps when they are created.
+ */
+int
+pdf_write_cmap(gx_device_pdf *pdev, const gs_cmap_t *pcmap,
+ pdf_resource_t **ppres /*CMap*/, int font_index_only)
+{
+ int code;
+ pdf_data_writer_t writer;
+ gs_const_string alt_cmap_name;
+ const gs_const_string *cmap_name = &pcmap->CMapName;
+
+ code = pdf_begin_data_stream(pdev, &writer,
+ DATA_STREAM_NOT_BINARY |
+ /* Don't set DATA_STREAM_ENCRYPT since we write to a temporary file.
+ See comment in pdf_begin_encrypt. */
+ (pdev->CompressFonts ?
+ DATA_STREAM_COMPRESS : 0), gs_no_id);
+ if (code < 0)
+ return code;
+ *ppres = writer.pres;
+ writer.pres->where_used = 0; /* CMap isn't a PDF resource. */
+ if (!pcmap->ToUnicode) {
+ byte buf[200];
+ cos_dict_t *pcd = (cos_dict_t *)writer.pres->object;
+ stream s;
+
+ code = cos_dict_put_c_key_int(pcd, "/WMode", pcmap->WMode);
+ if (code < 0)
+ return code;
+ buf[0] = '/';
+ memcpy(buf + 1, pcmap->CMapName.data, pcmap->CMapName.size);
+ code = cos_dict_put_c_key_string(pcd, "/CMapName",
+ buf, pcmap->CMapName.size + 1);
+ if (code < 0)
+ return code;
+ s_init(&s, pdev->memory);
+ swrite_string(&s, buf, sizeof(buf));
+ code = pdf_write_cid_system_info_to_stream(pdev, &s, pcmap->CIDSystemInfo, 0);
+ if (code < 0)
+ return code;
+ code = cos_dict_put_c_key_string(pcd, "/CIDSystemInfo",
+ buf, stell(&s));
+ if (code < 0)
+ return code;
+ code = cos_dict_put_string_copy(pcd, "/Type", "/CMap");
+ if (code < 0)
+ return code;
+ }
+ if (pcmap->CMapName.size == 0) {
+ /* Create an arbitrary name (for ToUnicode CMap). */
+ alt_cmap_name.data = (byte *)(*ppres)->rname;
+ alt_cmap_name.size = strlen((*ppres)->rname);
+ cmap_name = &alt_cmap_name;
+ }
+ code = psf_write_cmap(pdev->memory, writer.binary.strm, pcmap,
+ pdf_put_name_chars_proc(pdev),
+ cmap_name, font_index_only);
+ if (code < 0)
+ return code;
+ code = pdf_end_data(&writer);
+ if (code < 0)
+ return code;
+ return code;
+}
+
+static const char *OneByteIdentityH[] = {
+ "/CIDInit /ProcSet findresource begin",
+ "12 dict begin",
+ "begincmap",
+ "/CIDSystemInfo 3 dict dup begin",
+ "/Registry (Adobe) def",
+ "/Ordering (Identity) def",
+ "/Supplement 0 def",
+ "end def",
+ "/CMapName /OneByteIdentityH def",
+ "/CMapVersion 1.000 def",
+ "/CMapType 1 def",
+ "/UIDOffset 0 def",
+ "/XUID [1 10 25404 9999] def",
+ "/WMode 0 def",
+ "1 begincodespacerange",
+ "<00> <FF>",
+ "endcodespacerange",
+ "1 begincidrange",
+ "<00> <FF> 0",
+ "endcidrange",
+ "endcmap",
+ "CMapName currentdict /CMap defineresource pop",
+ "end",
+ "end",
+NULL};
+
+/*
+ * Write OneByteIdentityH CMap.
+ */
+int
+pdf_write_OneByteIdentityH(gx_device_pdf *pdev)
+{
+ int code, i;
+ pdf_data_writer_t writer;
+ cos_dict_t *pcd;
+ char buf[200];
+ static const gs_cid_system_info_t cidsi = {{(const byte *)"Adobe", 5}, {(const byte *)"Identity", 8}, 0};
+ long id;
+
+ if (pdev->IdentityCIDSystemInfo_id == gs_no_id) {
+ code = pdf_write_cid_systemInfo_separate(pdev, &cidsi, &id);
+ if (code < 0)
+ return code;
+ pdev->IdentityCIDSystemInfo_id = id;
+ }
+ if (pdev->OneByteIdentityH != NULL)
+ return 0;
+ code = pdf_begin_data_stream(pdev, &writer,
+ DATA_STREAM_NOT_BINARY |
+ /* Don't set DATA_STREAM_ENCRYPT since we write to a temporary file.
+ See comment in pdf_begin_encrypt. */
+ (pdev->CompressFonts ?
+ DATA_STREAM_COMPRESS : 0), gs_no_id);
+ if (code < 0)
+ return code;
+ pdev->OneByteIdentityH = writer.pres;
+ pcd = (cos_dict_t *)writer.pres->object;
+ code = cos_dict_put_string_copy(pcd, "/CMapName", "/OneByteIdentityH");
+ if (code < 0)
+ return code;
+ gs_sprintf(buf, "%ld 0 R", pdev->IdentityCIDSystemInfo_id);
+ code = cos_dict_put_string_copy(pcd, "/CIDSystemInfo", buf);
+ if (code < 0)
+ return code;
+ code = cos_dict_put_string_copy(pcd, "/Type", "/CMap");
+ if (code < 0)
+ return code;
+ for (i = 0; OneByteIdentityH[i]; i++) {
+ stream_puts(pdev->strm, OneByteIdentityH[i]);
+ stream_putc(pdev->strm, '\n');
+ }
+ return pdf_end_data(&writer);
+}