summaryrefslogtreecommitdiff
path: root/gs/base/gdevpdtf.c
diff options
context:
space:
mode:
Diffstat (limited to 'gs/base/gdevpdtf.c')
-rw-r--r--gs/base/gdevpdtf.c1080
1 files changed, 1080 insertions, 0 deletions
diff --git a/gs/base/gdevpdtf.c b/gs/base/gdevpdtf.c
new file mode 100644
index 000000000..a8459715a
--- /dev/null
+++ b/gs/base/gdevpdtf.c
@@ -0,0 +1,1080 @@
+/* Copyright (C) 2001-2006 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 that
+ license. 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.
+*/
+
+/* $Id$ */
+/* Font and CMap resource implementation for pdfwrite text */
+#include "memory_.h"
+#include "string_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsutil.h" /* for bytes_compare */
+#include "gxfcache.h" /* for orig_fonts list */
+#include "gxfcid.h"
+#include "gxfcmap.h"
+#include "gxfcopy.h"
+#include "gxfont.h"
+#include "gxfont1.h"
+#include "gdevpsf.h"
+#include "gdevpdfx.h"
+#include "gdevpdtb.h"
+#include "gdevpdtd.h"
+#include "gdevpdtf.h"
+#include "gdevpdtw.h"
+#include "gdevpdti.h"
+
+/* GC descriptors */
+public_st_pdf_font_resource();
+private_st_pdf_encoding1();
+private_st_pdf_encoding_element();
+private_st_pdf_standard_font();
+private_st_pdf_standard_font_element();
+private_st_pdf_outline_fonts();
+
+static
+ENUM_PTRS_WITH(pdf_font_resource_enum_ptrs, pdf_font_resource_t *pdfont)
+ENUM_PREFIX(st_pdf_resource, 12);
+case 0: return ENUM_STRING(&pdfont->BaseFont);
+case 1: ENUM_RETURN(pdfont->FontDescriptor);
+case 2: ENUM_RETURN(pdfont->base_font);
+case 3: ENUM_RETURN(pdfont->Widths);
+case 4: ENUM_RETURN(pdfont->used);
+case 5: ENUM_RETURN(pdfont->res_ToUnicode);
+case 6: ENUM_RETURN(pdfont->cmap_ToUnicode);
+case 7: switch (pdfont->FontType) {
+ case ft_composite:
+ ENUM_RETURN(pdfont->u.type0.DescendantFont);
+ case ft_CID_encrypted:
+ case ft_CID_TrueType:
+ ENUM_RETURN(pdfont->u.cidfont.Widths2);
+ default:
+ pdf_mark_glyph_names(pdfont, mem);
+ ENUM_RETURN(pdfont->u.simple.Encoding);
+}
+case 8: switch (pdfont->FontType) {
+ case ft_composite:
+ return (pdfont->u.type0.cmap_is_standard ? ENUM_OBJ(0) :
+ ENUM_CONST_STRING(&pdfont->u.type0.CMapName));
+ case ft_encrypted:
+ case ft_encrypted2:
+ case ft_TrueType:
+ case ft_user_defined:
+ ENUM_RETURN(pdfont->u.simple.v);
+ case ft_CID_encrypted:
+ case ft_CID_TrueType:
+ ENUM_RETURN(pdfont->u.cidfont.v);
+ default:
+ ENUM_RETURN(0);
+}
+case 9: switch (pdfont->FontType) {
+ case ft_user_defined:
+ ENUM_RETURN(pdfont->u.simple.s.type3.char_procs);
+ case ft_CID_encrypted:
+ case ft_CID_TrueType:
+ ENUM_RETURN(pdfont->u.cidfont.CIDToGIDMap);
+ default:
+ ENUM_RETURN(0);
+}
+case 10: switch (pdfont->FontType) {
+ case ft_user_defined:
+ ENUM_RETURN(pdfont->u.simple.s.type3.cached);
+ case ft_CID_encrypted:
+ case ft_CID_TrueType:
+ ENUM_RETURN(pdfont->u.cidfont.parent);
+ default:
+ ENUM_RETURN(0);
+}
+case 11: switch (pdfont->FontType) {
+ case ft_user_defined:
+ ENUM_RETURN(pdfont->u.simple.s.type3.Resources);
+ case ft_CID_encrypted:
+ case ft_CID_TrueType:
+ ENUM_RETURN(pdfont->u.cidfont.used2);
+ default:
+ ENUM_RETURN(0);
+}
+ENUM_PTRS_END
+static
+RELOC_PTRS_WITH(pdf_font_resource_reloc_ptrs, pdf_font_resource_t *pdfont)
+{
+ RELOC_PREFIX(st_pdf_resource);
+ RELOC_STRING_VAR(pdfont->BaseFont);
+ RELOC_VAR(pdfont->FontDescriptor);
+ RELOC_VAR(pdfont->base_font);
+ RELOC_VAR(pdfont->Widths);
+ RELOC_VAR(pdfont->used);
+ RELOC_VAR(pdfont->res_ToUnicode);
+ RELOC_VAR(pdfont->cmap_ToUnicode);
+ switch (pdfont->FontType) {
+ case ft_composite:
+ if (!pdfont->u.type0.cmap_is_standard)
+ RELOC_CONST_STRING_VAR(pdfont->u.type0.CMapName);
+ RELOC_VAR(pdfont->u.type0.DescendantFont);
+ break;
+ case ft_user_defined:
+ RELOC_VAR(pdfont->u.simple.Encoding);
+ RELOC_VAR(pdfont->u.simple.v);
+ RELOC_VAR(pdfont->u.simple.s.type3.char_procs);
+ RELOC_VAR(pdfont->u.simple.s.type3.cached);
+ RELOC_VAR(pdfont->u.simple.s.type3.Resources);
+ break;
+ case ft_CID_encrypted:
+ case ft_CID_TrueType:
+ RELOC_VAR(pdfont->u.cidfont.Widths2);
+ RELOC_VAR(pdfont->u.cidfont.v);
+ RELOC_VAR(pdfont->u.cidfont.CIDToGIDMap);
+ RELOC_VAR(pdfont->u.cidfont.parent);
+ RELOC_VAR(pdfont->u.cidfont.used2);
+ break;
+ default:
+ RELOC_VAR(pdfont->u.simple.Encoding);
+ RELOC_VAR(pdfont->u.simple.v);
+ break;
+ }
+}
+RELOC_PTRS_END
+
+/* ---------------- Standard fonts ---------------- */
+
+/* ------ Private ------ */
+
+/* Define the 14 standard built-in fonts. */
+#define PDF_NUM_STANDARD_FONTS 14
+typedef struct pdf_standard_font_info_s {
+ const char *fname;
+ int size;
+ gs_encoding_index_t base_encoding;
+} pdf_standard_font_info_t;
+static const pdf_standard_font_info_t standard_font_info[] = {
+ {"Courier", 7, ENCODING_INDEX_STANDARD},
+ {"Courier-Bold", 12, ENCODING_INDEX_STANDARD},
+ {"Courier-Oblique", 15, ENCODING_INDEX_STANDARD},
+ {"Courier-BoldOblique", 19, ENCODING_INDEX_STANDARD},
+ {"Helvetica", 9, ENCODING_INDEX_STANDARD},
+ {"Helvetica-Bold", 14, ENCODING_INDEX_STANDARD},
+ {"Helvetica-Oblique", 17, ENCODING_INDEX_STANDARD},
+ {"Helvetica-BoldOblique", 21, ENCODING_INDEX_STANDARD},
+ {"Symbol", 6, ENCODING_INDEX_SYMBOL},
+ {"Times-Roman", 11, ENCODING_INDEX_STANDARD},
+ {"Times-Bold", 10, ENCODING_INDEX_STANDARD},
+ {"Times-Italic", 12, ENCODING_INDEX_STANDARD},
+ {"Times-BoldItalic", 16, ENCODING_INDEX_STANDARD},
+ {"ZapfDingbats", 12, ENCODING_INDEX_DINGBATS},
+ {0}
+};
+
+/* Return the index of a standard font name, or -1 if missing. */
+static int
+pdf_find_standard_font_name(const byte *str, uint size)
+{
+ const pdf_standard_font_info_t *ppsf;
+
+ for (ppsf = standard_font_info; ppsf->fname; ++ppsf)
+ if (ppsf->size == size &&
+ !memcmp(ppsf->fname, (const char *)str, size)
+ )
+ return ppsf - standard_font_info;
+ return -1;
+}
+
+/*
+ * If there is a standard font with the same appearance (CharStrings,
+ * Private, WeightVector) as the given font, set *psame to the mask of
+ * identical properties, and return the standard-font index; otherwise,
+ * set *psame to 0 and return -1.
+ */
+static int
+find_std_appearance(const gx_device_pdf *pdev, gs_font_base *bfont,
+ int mask, pdf_char_glyph_pair_t *pairs, int num_glyphs)
+{
+ bool has_uid = uid_is_UniqueID(&bfont->UID) && bfont->UID.id != 0;
+ const pdf_standard_font_t *psf = pdf_standard_fonts(pdev);
+ int i;
+
+ switch (bfont->FontType) {
+ case ft_encrypted:
+ case ft_encrypted2:
+ case ft_TrueType:
+ break;
+ default:
+ return -1;
+ }
+
+ mask |= FONT_SAME_OUTLINES;
+ for (i = 0; i < PDF_NUM_STANDARD_FONTS; ++psf, ++i) {
+ gs_font_base *cfont;
+ int code;
+
+ if (!psf->pdfont)
+ continue;
+ cfont = pdf_font_resource_font(psf->pdfont, false);
+ if (has_uid) {
+ /*
+ * Require the UIDs to match. The PostScript spec says this
+ * is the case iff the outlines are the same.
+ */
+ if (!uid_equal(&bfont->UID, &cfont->UID))
+ continue;
+ }
+ /*
+ * Require the actual outlines to match (within the given subset).
+ */
+ code = gs_copied_can_copy_glyphs((const gs_font *)cfont,
+ (const gs_font *)bfont,
+ &pairs[0].glyph, num_glyphs,
+ sizeof(pdf_char_glyph_pair_t), true);
+ if (code == gs_error_unregistered) /* Debug purpose only. */
+ return code;
+ /* Note: code < 0 means an error. Skip it here. */
+ if (code > 0)
+ return i;
+ }
+ return -1;
+}
+
+/*
+ * Scan a font directory for standard fonts. Return true if any new ones
+ * were found. A font is recognized as standard if it was loaded as a
+ * resource, it has a UniqueId, and it has a standard name.
+ */
+static bool
+scan_for_standard_fonts(gx_device_pdf *pdev, const gs_font_dir *dir)
+{
+ bool found = false;
+ gs_font *orig = dir->orig_fonts;
+
+ for (; orig; orig = orig->next) {
+ gs_font_base *obfont;
+
+ if (orig->FontType == ft_composite || !orig->is_resource)
+ continue;
+ obfont = (gs_font_base *)orig;
+ if (uid_is_UniqueID(&obfont->UID)) {
+ /* Is it one of the standard fonts? */
+ int i = pdf_find_standard_font_name(orig->key_name.chars,
+ orig->key_name.size);
+
+ if (i >= 0 && pdf_standard_fonts(pdev)[i].pdfont == 0) {
+ pdf_font_resource_t *pdfont;
+ int code = pdf_font_std_alloc(pdev, &pdfont, true, orig->id, obfont,
+ i);
+
+ if (code < 0)
+ continue;
+ found = true;
+ }
+ }
+ }
+ return found;
+}
+
+/* ---------------- Initialization ---------------- */
+
+/*
+ * Allocate and initialize bookkeeping for outline fonts.
+ */
+pdf_outline_fonts_t *
+pdf_outline_fonts_alloc(gs_memory_t *mem)
+{
+ pdf_outline_fonts_t *pofs =
+ gs_alloc_struct(mem, pdf_outline_fonts_t, &st_pdf_outline_fonts,
+ "pdf_outline_fonts_alloc(outline_fonts)");
+ pdf_standard_font_t *ppsf =
+ gs_alloc_struct_array(mem, PDF_NUM_STANDARD_FONTS,
+ pdf_standard_font_t,
+ &st_pdf_standard_font_element,
+ "pdf_outline_fonts_alloc(standard_fonts)");
+
+ if (pofs == 0 || ppsf == 0)
+ return 0;
+ memset(ppsf, 0, PDF_NUM_STANDARD_FONTS * sizeof(*ppsf));
+ memset(pofs, 0, sizeof(*pofs));
+ pofs->standard_fonts = ppsf;
+ return pofs;
+}
+
+/*
+ * Return the standard fonts array.
+ */
+pdf_standard_font_t *
+pdf_standard_fonts(const gx_device_pdf *pdev)
+{
+ return pdev->text->outline_fonts->standard_fonts;
+}
+
+/*
+ * Clean the standard fonts array.
+ */
+void
+pdf_clean_standard_fonts(const gx_device_pdf *pdev)
+{
+ pdf_standard_font_t *ppsf = pdf_standard_fonts(pdev);
+
+ memset(ppsf, 0, PDF_NUM_STANDARD_FONTS * sizeof(*ppsf));
+}
+
+
+/* ---------------- Font resources ---------------- */
+
+/* ------ Private ------ */
+
+
+static int
+pdf_resize_array(gs_memory_t *mem, void **p, int elem_size, int old_size, int new_size)
+{
+ void *q = gs_alloc_byte_array(mem, new_size, elem_size, "pdf_resize_array");
+
+ if (q == NULL)
+ return_error(gs_error_VMerror);
+ memset((char *)q + elem_size * old_size, 0, elem_size * (new_size - old_size));
+ memcpy(q, *p, elem_size * old_size);
+ gs_free_object(mem, *p, "pdf_resize_array");
+ *p = q;
+ return 0;
+}
+
+/*
+ * Allocate and (minimally) initialize a font resource.
+ */
+static int
+font_resource_alloc(gx_device_pdf *pdev, pdf_font_resource_t **ppfres,
+ pdf_resource_type_t rtype, gs_id rid, font_type ftype,
+ int chars_count,
+ pdf_font_write_contents_proc_t write_contents)
+{
+ gs_memory_t *mem = pdev->pdf_memory;
+ pdf_font_resource_t *pfres;
+ double *widths = 0;
+ byte *used = 0;
+ int code;
+ bool is_CID_font = (ftype == ft_CID_encrypted || ftype == ft_CID_TrueType);
+
+ if (chars_count != 0) {
+ uint size = (chars_count + 7) / 8;
+
+ if (!is_CID_font) {
+ widths = (void *)gs_alloc_byte_array(mem, chars_count, sizeof(*widths),
+ "font_resource_alloc(Widths)");
+ } else {
+ /* Delay allocation because we don't know which WMode will be used. */
+ }
+ used = gs_alloc_bytes(mem, size, "font_resource_alloc(used)");
+ if ((!is_CID_font && widths == 0) || used == 0) {
+ code = gs_note_error(gs_error_VMerror);
+ goto fail;
+ }
+ if (!is_CID_font)
+ memset(widths, 0, chars_count * sizeof(*widths));
+ memset(used, 0, size);
+ }
+ code = pdf_alloc_resource(pdev, rtype, rid, (pdf_resource_t **)&pfres, -1L);
+ if (code < 0)
+ goto fail;
+ memset((byte *)pfres + sizeof(pdf_resource_t), 0,
+ sizeof(*pfres) - sizeof(pdf_resource_t));
+ pfres->FontType = ftype;
+ pfres->count = chars_count;
+ pfres->Widths = widths;
+ pfres->used = used;
+ pfres->write_contents = write_contents;
+ pfres->res_ToUnicode = NULL;
+ pfres->cmap_ToUnicode = NULL;
+ pfres->mark_glyph = 0;
+ pfres->mark_glyph_data = 0;
+ *ppfres = pfres;
+ return 0;
+ fail:
+ gs_free_object(mem, used, "font_resource_alloc(used)");
+ gs_free_object(mem, widths, "font_resource_alloc(Widths)");
+ return code;
+}
+
+int
+pdf_assign_font_object_id(gx_device_pdf *pdev, pdf_font_resource_t *pdfont)
+{
+ if (pdf_resource_id((pdf_resource_t *)pdfont) == -1) {
+ int code;
+
+ pdf_reserve_object_id(pdev, (pdf_resource_t *)pdfont, 0);
+ code = pdf_mark_font_descriptor_used(pdev, pdfont->FontDescriptor);
+ if (code < 0)
+ return code;
+ if (pdfont->FontType == 0) {
+ pdf_font_resource_t *pdfont1 = pdfont->u.type0.DescendantFont;
+
+ if (pdf_font_id(pdfont1) == -1) {
+ pdf_reserve_object_id(pdev, (pdf_resource_t *)pdfont1, 0);
+ code = pdf_mark_font_descriptor_used(pdev, pdfont1->FontDescriptor);
+ if (code < 0)
+ return code;
+ }
+ }
+ }
+ return 0;
+}
+
+static int
+font_resource_simple_alloc(gx_device_pdf *pdev, pdf_font_resource_t **ppfres,
+ gs_id rid, font_type ftype, int chars_count,
+ pdf_font_write_contents_proc_t write_contents)
+{
+ pdf_font_resource_t *pfres;
+ int code = font_resource_alloc(pdev, &pfres, resourceFont, rid, ftype,
+ chars_count, write_contents);
+
+ if (code < 0)
+ return code;
+ pfres->u.simple.FirstChar = 256;
+ pfres->u.simple.LastChar = -1;
+ pfres->u.simple.BaseEncoding = -1;
+ pfres->u.simple.preferred_encoding_index = -1;
+ pfres->u.simple.last_reserved_char = -1;
+ *ppfres = pfres;
+ return 0;
+}
+int
+font_resource_encoded_alloc(gx_device_pdf *pdev, pdf_font_resource_t **ppfres,
+ gs_id rid, font_type ftype,
+ pdf_font_write_contents_proc_t write_contents)
+{
+ pdf_encoding_element_t *Encoding =
+ gs_alloc_struct_array(pdev->pdf_memory, 256, pdf_encoding_element_t,
+ &st_pdf_encoding_element,
+ "font_resource_encoded_alloc");
+ gs_point *v = (gs_point *)gs_alloc_byte_array(pdev->pdf_memory,
+ 256, sizeof(gs_point), "pdf_font_simple_alloc");
+ pdf_font_resource_t *pdfont;
+ int code, i;
+
+
+ if (v == 0 || Encoding == 0) {
+ gs_free_object(pdev->pdf_memory, Encoding,
+ "font_resource_encoded_alloc");
+ gs_free_object(pdev->pdf_memory, v,
+ "font_resource_encoded_alloc");
+ return_error(gs_error_VMerror);
+ }
+ code = font_resource_simple_alloc(pdev, &pdfont, rid, ftype,
+ 256, write_contents);
+ if (code < 0) {
+ gs_free_object(pdev->pdf_memory, Encoding,
+ "font_resource_encoded_alloc");
+ gs_free_object(pdev->pdf_memory, v,
+ "font_resource_encoded_alloc");
+ return_error(gs_error_VMerror);
+ }
+ if (code < 0) {
+ return code;
+ }
+ memset(v, 0, 256 * sizeof(*v));
+ memset(Encoding, 0, 256 * sizeof(*Encoding));
+ for (i = 0; i < 256; ++i)
+ Encoding[i].glyph = GS_NO_GLYPH;
+ pdfont->u.simple.Encoding = Encoding;
+ pdfont->u.simple.v = v;
+ *ppfres = pdfont;
+ return 0;
+}
+
+/*
+ * Record whether a Type 1 or Type 2 font is a Multiple Master instance.
+ */
+static void
+set_is_MM_instance(pdf_font_resource_t *pdfont, const gs_font_base *pfont)
+{
+ switch (pfont->FontType) {
+ case ft_encrypted:
+ case ft_encrypted2:
+ pdfont->u.simple.s.type1.is_MM_instance =
+ ((const gs_font_type1 *)pfont)->data.WeightVector.count > 0;
+ default:
+ break;
+ }
+}
+
+/* ------ Generic public ------ */
+
+/* Resize font resource arrays. */
+int
+pdf_resize_resource_arrays(gx_device_pdf *pdev, pdf_font_resource_t *pfres, int chars_count)
+{
+ /* This function fixes CID fonts that provide a lesser CIDCount than
+ CIDs used in a document. Rather PS requires to print CID=0,
+ we need to provide a bigger CIDCount since we don't
+ re-encode the text. The text should look fine if the
+ viewer application substitutes the font. */
+ gs_memory_t *mem = pdev->pdf_memory;
+ int code;
+
+ if (chars_count < pfres->count)
+ return 0;
+ if (pfres->Widths != NULL) {
+ code = pdf_resize_array(mem, (void **)&pfres->Widths, sizeof(*pfres->Widths),
+ pfres->count, chars_count);
+ if (code < 0)
+ return code;
+ }
+ code = pdf_resize_array(mem, (void **)&pfres->used, sizeof(*pfres->used),
+ (pfres->count + 7) / 8, (chars_count + 7) / 8);
+ if (code < 0)
+ return code;
+ if (pfres->FontType == ft_CID_encrypted || pfres->FontType == ft_CID_TrueType) {
+ if (pfres->u.cidfont.v != NULL) {
+ code = pdf_resize_array(mem, (void **)&pfres->u.cidfont.v,
+ sizeof(*pfres->u.cidfont.v), pfres->count * 2, chars_count * 2);
+ if (code < 0)
+ return code;
+ }
+ if (pfres->u.cidfont.Widths2 != NULL) {
+ code = pdf_resize_array(mem, (void **)&pfres->u.cidfont.Widths2,
+ sizeof(*pfres->u.cidfont.Widths2), pfres->count, chars_count);
+ if (code < 0)
+ return code;
+ }
+ }
+ if (pfres->FontType == ft_CID_TrueType) {
+ if (pfres->u.cidfont.CIDToGIDMap != NULL) {
+ code = pdf_resize_array(mem, (void **)&pfres->u.cidfont.CIDToGIDMap,
+ sizeof(*pfres->u.cidfont.CIDToGIDMap), pfres->count, chars_count);
+ if (code < 0)
+ return code;
+ }
+ }
+ if (pfres->FontType == ft_CID_encrypted || pfres->FontType == ft_CID_TrueType) {
+ if (pfres->u.cidfont.used2 != NULL) {
+ code = pdf_resize_array(mem, (void **)&pfres->u.cidfont.used2,
+ sizeof(*pfres->u.cidfont.used2),
+ (pfres->count + 7) / 8, (chars_count + 7) / 8);
+ if (code < 0)
+ return code;
+ }
+ }
+ pfres->count = chars_count;
+ return 0;
+}
+
+/* Get the object ID of a font resource. */
+long
+pdf_font_id(const pdf_font_resource_t *pdfont)
+{
+ return pdf_resource_id((const pdf_resource_t *)pdfont);
+}
+
+/*
+ * Return the (copied, subset) font associated with a font resource.
+ * If this font resource doesn't have one (Type 0 or Type 3), return 0.
+ */
+gs_font_base *
+pdf_font_resource_font(const pdf_font_resource_t *pdfont, bool complete)
+{
+ if (pdfont->base_font != NULL)
+ return pdf_base_font_font(pdfont->base_font, complete);
+ if (pdfont->FontDescriptor == 0)
+ return 0;
+ return pdf_font_descriptor_font(pdfont->FontDescriptor, complete);
+}
+
+/*
+ * Determine the embedding status of a font. If the font is in the base
+ * 14, store its index (0..13) in *pindex and its similarity to the base
+ * font (as determined by the font's same_font procedure) in *psame.
+ */
+static bool
+font_is_symbolic(const gs_font *font)
+{
+ if (font->FontType == ft_composite)
+ return true; /* arbitrary */
+ switch (((const gs_font_base *)font)->nearest_encoding_index) {
+ case ENCODING_INDEX_STANDARD:
+ case ENCODING_INDEX_ISOLATIN1:
+ case ENCODING_INDEX_WINANSI:
+ case ENCODING_INDEX_MACROMAN:
+ return false;
+ default:
+ return true;
+ }
+}
+static bool
+embed_list_includes(const gs_param_string_array *psa, const byte *chars,
+ uint size)
+{
+ uint i;
+
+ for (i = 0; i < psa->size; ++i)
+ if (!bytes_compare(psa->data[i].data, psa->data[i].size, chars, size))
+ return true;
+ return false;
+}
+static bool
+embed_as_standard(gx_device_pdf *pdev, gs_font *font, int index,
+ pdf_char_glyph_pair_t *pairs, int num_glyphs)
+{
+ if (font->is_resource) {
+ return true;
+ }
+ if (find_std_appearance(pdev, (gs_font_base *)font, -1,
+ pairs, num_glyphs) == index)
+ return true;
+ if (!scan_for_standard_fonts(pdev, font->dir))
+ return false;
+ return (find_std_appearance(pdev, (gs_font_base *)font, -1,
+ pairs, num_glyphs) == index);
+}
+static bool
+has_extension_glyphs(gs_font *pfont)
+{
+ psf_glyph_enum_t genum;
+ gs_glyph glyph;
+ gs_const_string str;
+ int code, j, l;
+ const int sl = strlen(gx_extendeg_glyph_name_separator);
+
+ psf_enumerate_glyphs_begin(&genum, (gs_font *)pfont, NULL, 0, GLYPH_SPACE_NAME);
+ for (glyph = gs_no_glyph; (code = psf_enumerate_glyphs_next(&genum, &glyph)) != 1; ) {
+ code = pfont->procs.glyph_name(pfont, glyph, &str);
+ if (code < 0)
+ return code;
+ l = str.size - sl, j;
+ for (j = 0; j < l; j ++)
+ if (!memcmp(gx_extendeg_glyph_name_separator, str.data + j, sl))
+ return true;
+ }
+ psf_enumerate_glyphs_reset(&genum);
+ return false;
+}
+
+pdf_font_embed_t
+pdf_font_embed_status(gx_device_pdf *pdev, gs_font *font, int *pindex,
+ pdf_char_glyph_pair_t *pairs, int num_glyphs)
+{
+ const gs_font_name *fn = &font->font_name;
+ const byte *chars = fn->chars;
+ uint size = fn->size;
+ int index = pdf_find_standard_font_name(chars, size);
+ bool embed_as_standard_called = false;
+ bool do_embed_as_standard = false; /* Quiet compiler. */
+ int code;
+ gs_font_info_t info;
+
+ memset(&info, 0x00, sizeof(gs_font_info_t));
+ code = font->procs.font_info(font, NULL, FONT_INFO_EMBEDDING_RIGHTS, &info);
+ if (code == 0 && (info.members & FONT_INFO_EMBEDDING_RIGHTS)) {
+ if ((info.EmbeddingRights == 0x0002) || (info.EmbeddingRights & 0x0200)) {
+ /* See the OpenType specification, "The 'OS/2' and Windows Metrics Table" for details
+ of the fstype parameter. This is a bitfield, currently we forbid embedding of fonts
+ with these bits set:
+ bit 1 0x0002 Fonts that have only this bit set must not be modified, embedded or
+ exchanged in any manner.
+ bit 9 0x0200 Bitmap embedding only.
+
+ Note for Restricted License embedding (bit 1), this must be the only level of embedding
+ selected (see the OpenType spec).
+ */
+ char name[gs_font_name_max + 1];
+ int len;
+
+ len = min(gs_font_name_max, font->font_name.size);
+ memcpy(name, font->font_name.chars, len);
+ name[len] = 0;
+ eprintf1("\nWarning: %s cannot be embedded because of licensing restrictions\n", name);
+ return FONT_EMBED_NO;
+ }
+ }
+ /*
+ * The behavior of Acrobat Distiller changed between 3.0 (PDF 1.2),
+ * which will never embed the base 14 fonts, and 4.0 (PDF 1.3), which
+ * doesn't treat them any differently from any other fonts. However,
+ * if any of the base 14 fonts is not embedded, it still requires
+ * special treatment.
+ */
+ if (pindex)
+ *pindex = index;
+ if (pdev->PDFX || pdev->PDFA)
+ return FONT_EMBED_YES;
+ if (pdev->CompatibilityLevel < 1.3) {
+ if (index >= 0 &&
+ (embed_as_standard_called = true,
+ do_embed_as_standard = embed_as_standard(pdev, font, index, pairs, num_glyphs))) {
+ if (pdev->ForOPDFRead && has_extension_glyphs(font))
+ return FONT_EMBED_YES;
+ return FONT_EMBED_STANDARD;
+ }
+ }
+ /* Check the Embed lists. */
+ if (!embed_list_includes(&pdev->params.NeverEmbed, chars, size) ||
+ (index >= 0 &&
+ !(embed_as_standard_called ? do_embed_as_standard :
+ (embed_as_standard_called = true,
+ (do_embed_as_standard = embed_as_standard(pdev, font, index, pairs, num_glyphs)))))
+ /* Ignore NeverEmbed for a non-standard font with a standard name */
+ ) {
+ if (pdev->params.EmbedAllFonts || font_is_symbolic(font) ||
+ embed_list_includes(&pdev->params.AlwaysEmbed, chars, size))
+ return FONT_EMBED_YES;
+ }
+ if (index >= 0 &&
+ (embed_as_standard_called ? do_embed_as_standard :
+ embed_as_standard(pdev, font, index, pairs, num_glyphs)))
+ return FONT_EMBED_STANDARD;
+ return FONT_EMBED_NO;
+}
+
+/*
+ * Compute the BaseFont of a font according to the algorithm described
+ * in gdevpdtf.h.
+ */
+int
+pdf_compute_BaseFont(gx_device_pdf *pdev, pdf_font_resource_t *pdfont, bool finish)
+{
+ pdf_font_resource_t *pdsubf = pdfont;
+ gs_string fname;
+ uint size, extra = 0;
+ byte *data;
+
+ if (pdfont->FontType == ft_composite) {
+ int code;
+
+ pdsubf = pdfont->u.type0.DescendantFont;
+ code = pdf_compute_BaseFont(pdev, pdsubf, finish);
+ if (code < 0)
+ return code;
+ fname = pdsubf->BaseFont;
+ if (pdsubf->FontType == ft_CID_encrypted || pdsubf->FontType == ft_CID_TrueType)
+ extra = 1 + pdfont->u.type0.CMapName.size;
+ }
+ else if (pdfont->FontDescriptor == 0) {
+ /* Type 3 font, or has its BaseFont computed in some other way. */
+ return 0;
+ } else
+ fname = *pdf_font_descriptor_base_name(pdsubf->FontDescriptor);
+ size = fname.size;
+ data = gs_alloc_string(pdev->pdf_memory, size + extra,
+ "pdf_compute_BaseFont");
+ if (data == 0)
+ return_error(gs_error_VMerror);
+ memcpy(data, fname.data, size);
+ switch (pdfont->FontType) {
+ case ft_composite:
+ if (extra) {
+ data[size] = '-';
+ memcpy(data + size + 1, pdfont->u.type0.CMapName.data, extra - 1);
+ size += extra;
+ }
+ break;
+ case ft_encrypted:
+ case ft_encrypted2:
+ if (pdfont->u.simple.s.type1.is_MM_instance &&
+ !pdf_font_descriptor_embedding(pdfont->FontDescriptor)
+ ) {
+ /* Replace spaces by underscores in the base name. */
+ uint i;
+
+ for (i = 0; i < size; ++i)
+ if (data[i] == ' ')
+ data[i] = '_';
+ }
+ break;
+ case ft_TrueType:
+ case ft_CID_TrueType: {
+ /* Remove spaces from the base name. */
+ uint i, j;
+
+ for (i = j = 0; i < size; ++i)
+ if (data[i] != ' ')
+ data[j++] = data[i];
+ data = gs_resize_string(pdev->pdf_memory, data, i, j,
+ "pdf_compute_BaseFont");
+ size = j;
+ break;
+ }
+ default:
+ break;
+ }
+ pdfont->BaseFont.data = fname.data = data;
+ pdfont->BaseFont.size = fname.size = size;
+ /* Compute names for subset fonts. */
+ if (finish && pdfont->FontDescriptor != NULL &&
+ pdf_font_descriptor_is_subset(pdfont->FontDescriptor) &&
+ !pdf_has_subset_prefix(fname.data, fname.size) &&
+ pdf_font_descriptor_embedding(pdfont->FontDescriptor)
+ ) {
+ int code = pdf_add_subset_prefix(pdev, &fname, pdfont->used, pdfont->count);
+
+ if (code < 0)
+ return code;
+ pdfont->BaseFont = fname;
+ /* Don't write a UID for subset fonts. */
+ uid_set_invalid(&pdf_font_resource_font(pdfont, false)->UID);
+ }
+ if (pdfont->FontType != ft_composite && pdsubf->FontDescriptor)
+ *pdf_font_descriptor_name(pdsubf->FontDescriptor) = fname;
+ return 0;
+}
+
+/* ------ Type 0 ------ */
+
+/* Allocate a Type 0 font resource. */
+int
+pdf_font_type0_alloc(gx_device_pdf *pdev, pdf_font_resource_t **ppfres,
+ gs_id rid, pdf_font_resource_t *DescendantFont,
+ const gs_const_string *CMapName)
+{
+ int code = font_resource_alloc(pdev, ppfres, resourceFont, rid,
+ ft_composite, 0, pdf_write_contents_type0);
+
+ if (code >= 0) {
+ (*ppfres)->u.type0.DescendantFont = DescendantFont;
+ (*ppfres)->u.type0.CMapName = *CMapName;
+ (*ppfres)->u.type0.font_index = 0;
+ code = pdf_compute_BaseFont(pdev, *ppfres, false);
+ }
+ return code;
+}
+
+/* ------ Type 3 ------ */
+
+/* Allocate a Type 3 font resource for sinthesyzed bitmap fonts. */
+int
+pdf_font_type3_alloc(gx_device_pdf *pdev, pdf_font_resource_t **ppfres,
+ pdf_font_write_contents_proc_t write_contents)
+{
+ return font_resource_simple_alloc(pdev, ppfres, gs_no_id, ft_user_defined,
+ 256, write_contents);
+}
+
+/* ------ Standard (base 14) Type 1 or TrueType ------ */
+
+/* Allocate a standard (base 14) font resource. */
+int
+pdf_font_std_alloc(gx_device_pdf *pdev, pdf_font_resource_t **ppfres,
+ bool is_original, gs_id rid, gs_font_base *pfont, int index)
+{
+ pdf_font_resource_t *pdfont;
+ int code = font_resource_encoded_alloc(pdev, &pdfont, rid, pfont->FontType,
+ pdf_write_contents_std);
+ const pdf_standard_font_info_t *psfi = &standard_font_info[index];
+ pdf_standard_font_t *psf = &pdf_standard_fonts(pdev)[index];
+ gs_matrix *orig_matrix = (is_original ? &pfont->FontMatrix : &psf->orig_matrix);
+
+ if (code < 0 ||
+ (code = pdf_base_font_alloc(pdev, &pdfont->base_font, pfont, orig_matrix, true)) < 0
+ )
+ return code;
+ pdfont->BaseFont.data = (byte *)psfi->fname; /* break const */
+ pdfont->BaseFont.size = strlen(psfi->fname);
+ pdfont->mark_glyph = pfont->dir->ccache.mark_glyph;
+ set_is_MM_instance(pdfont, pfont);
+ if (is_original) {
+ psf->pdfont = pdfont;
+ psf->orig_matrix = pfont->FontMatrix;
+ }
+ *ppfres = pdfont;
+ return 0;
+}
+
+/* ------ Other Type 1 or TrueType ------ */
+
+/* Allocate a Type 1 or TrueType font resource. */
+int
+pdf_font_simple_alloc(gx_device_pdf *pdev, pdf_font_resource_t **ppfres,
+ gs_id rid, pdf_font_descriptor_t *pfd)
+{
+ pdf_font_resource_t *pdfont;
+ int code;
+
+ code = font_resource_encoded_alloc(pdev, &pdfont, rid,
+ pdf_font_descriptor_FontType(pfd),
+ pdf_write_contents_simple);
+
+ pdfont->FontDescriptor = pfd;
+ set_is_MM_instance(pdfont, pdf_font_descriptor_font(pfd, false));
+ *ppfres = pdfont;
+ return pdf_compute_BaseFont(pdev, pdfont, false);
+}
+
+/* ------ CID-keyed ------ */
+
+/* Allocate a CIDFont resource. */
+int
+pdf_font_cidfont_alloc(gx_device_pdf *pdev, pdf_font_resource_t **ppfres,
+ gs_id rid, pdf_font_descriptor_t *pfd)
+{
+ font_type FontType = pdf_font_descriptor_FontType(pfd);
+ gs_font_base *font = pdf_font_descriptor_font(pfd, false);
+ int chars_count;
+ int code;
+ pdf_font_write_contents_proc_t write_contents;
+ const gs_cid_system_info_t *pcidsi;
+ ushort *map = 0;
+ pdf_font_resource_t *pdfont;
+
+ switch (FontType) {
+ case ft_CID_encrypted:
+ chars_count = ((const gs_font_cid0 *)font)->cidata.common.CIDCount;
+ pcidsi = &((const gs_font_cid0 *)font)->cidata.common.CIDSystemInfo;
+ write_contents = pdf_write_contents_cid0;
+ break;
+ case ft_CID_TrueType:
+ chars_count = ((const gs_font_cid2 *)font)->cidata.common.CIDCount;
+ pcidsi = &((const gs_font_cid2 *)font)->cidata.common.CIDSystemInfo;
+ map = (void *)gs_alloc_byte_array(pdev->pdf_memory, chars_count,
+ sizeof(*map), "CIDToGIDMap");
+ if (map == 0)
+ return_error(gs_error_VMerror);
+ memset(map, 0, chars_count * sizeof(*map));
+ write_contents = pdf_write_contents_cid2;
+ break;
+ default:
+ return_error(gs_error_rangecheck);
+ }
+ code = font_resource_alloc(pdev, &pdfont, resourceCIDFont, rid, FontType,
+ chars_count, write_contents);
+ if (code < 0)
+ return code;
+ pdfont->FontDescriptor = pfd;
+ pdfont->u.cidfont.CIDToGIDMap = map;
+ /* fixme : Likely pdfont->u.cidfont.CIDToGIDMap duplicates
+ pdfont->FontDescriptor->base_font->copied->client_data->CIDMap.
+ Only difference is 0xFFFF designates unmapped CIDs.
+ */
+ pdfont->u.cidfont.Widths2 = NULL;
+ pdfont->u.cidfont.v = NULL;
+ pdfont->u.cidfont.parent = NULL;
+ /* Don' know whether the font will use WMode 1,
+ so reserve it now. */
+ pdfont->u.cidfont.used2 = gs_alloc_bytes(pdev->pdf_memory,
+ (chars_count + 7) / 8, "pdf_font_cidfont_alloc");
+ if (pdfont->u.cidfont.used2 == NULL)
+ return_error(gs_error_VMerror);
+ memset(pdfont->u.cidfont.used2, 0, (chars_count + 7) / 8);
+ /*
+ * Write the CIDSystemInfo now, so we don't try to access it after
+ * the font may no longer be available.
+ */
+ code = pdf_write_cid_systemInfo_separate(pdev, pcidsi, &pdfont->u.cidfont.CIDSystemInfo_id);
+ if (code < 0)
+ return code;
+ *ppfres = pdfont;
+ return pdf_compute_BaseFont(pdev, pdfont, false);
+}
+
+int
+pdf_obtain_cidfont_widths_arrays(gx_device_pdf *pdev, pdf_font_resource_t *pdfont,
+ int wmode, double **w, double **w0, double **v)
+{
+ gs_memory_t *mem = pdev->pdf_memory;
+ double *ww, *vv = 0, *ww0 = 0;
+ int chars_count = pdfont->count;
+
+ *w0 = (wmode ? pdfont->Widths : NULL);
+ *v = (wmode ? pdfont->u.cidfont.v : NULL);
+ *w = (wmode ? pdfont->u.cidfont.Widths2 : pdfont->Widths);
+ if (*w == NULL) {
+ ww = (double *)gs_alloc_byte_array(mem, chars_count, sizeof(*ww),
+ "pdf_obtain_cidfont_widths_arrays");
+ if (wmode) {
+ vv = (double *)gs_alloc_byte_array(mem, chars_count, sizeof(*vv) * 2,
+ "pdf_obtain_cidfont_widths_arrays");
+ if (pdfont->Widths == 0) {
+ ww0 = (double *)gs_alloc_byte_array(mem, chars_count, sizeof(*ww0),
+ "pdf_obtain_cidfont_widths_arrays");
+ pdfont->Widths = *w0 = ww0;
+ if (ww0 != 0)
+ memset(ww0, 0, chars_count * sizeof(*ww));
+ } else
+ *w0 = ww0 = pdfont->Widths;
+ }
+ if (ww == 0 || (wmode && vv == 0) || (wmode && ww0 == 0)) {
+ gs_free_object(mem, ww, "pdf_obtain_cidfont_widths_arrays");
+ gs_free_object(mem, vv, "pdf_obtain_cidfont_widths_arrays");
+ gs_free_object(mem, ww0, "pdf_obtain_cidfont_widths_arrays");
+ return_error(gs_error_VMerror);
+ }
+ if (wmode)
+ memset(vv, 0, chars_count * 2 * sizeof(*vv));
+ memset(ww, 0, chars_count * sizeof(*ww));
+ if (wmode) {
+ pdfont->u.cidfont.Widths2 = *w = ww;
+ pdfont->u.cidfont.v = *v = vv;
+ } else {
+ pdfont->Widths = *w = ww;
+ *v = NULL;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Convert True Type fonts into CID fonts for PDF/A.
+ */
+int
+pdf_convert_truetype_font(gx_device_pdf *pdev, pdf_resource_t *pres)
+{
+ if (!pdev->PDFA)
+ return 0;
+ else {
+ pdf_font_resource_t *pdfont = (pdf_font_resource_t *)pres;
+
+ if (pdfont->FontType != ft_TrueType)
+ return 0;
+ else if (pdf_resource_id(pres) == -1)
+ return 0; /* An unused font. */
+ else {
+ int code = pdf_different_encoding_index(pdfont, 0);
+
+ if (code < 0)
+ return code;
+ if (code == 256)
+ return 0;
+ { /* The encoding have a difference - do convert. */
+ pdf_font_resource_t *pdfont0;
+ gs_const_string CMapName = {(const byte *)"OneByteIdentityH", 16};
+
+ code = pdf_convert_truetype_font_descriptor(pdev, pdfont);
+ if (code < 0)
+ return code;
+ code = pdf_font_type0_alloc(pdev, &pdfont0, pres->rid + 1, pdfont, &CMapName);
+ if (code < 0)
+ return code;
+ /* Pass the font object ID to the type 0 font resource. */
+ pdf_reserve_object_id(pdev, (pdf_resource_t *)pdfont0, pdf_resource_id(pres));
+ pdf_reserve_object_id(pdev, (pdf_resource_t *)pdfont, gs_no_id);
+ /* Set Encoding_name because we won't call attach_cmap_resource for it : */
+ code = pdf_write_OneByteIdentityH(pdev);
+ if (code < 0)
+ return 0;
+ pdfont->u.cidfont.CIDSystemInfo_id = pdev->IdentityCIDSystemInfo_id;
+ sprintf(pdfont0->u.type0.Encoding_name, "%ld 0 R", pdf_resource_id(pdev->OneByteIdentityH));
+ /* Move ToUnicode : */
+ pdfont0->res_ToUnicode = pdfont->res_ToUnicode; pdfont->res_ToUnicode = 0;
+ pdfont0->cmap_ToUnicode = pdfont->cmap_ToUnicode; pdfont->cmap_ToUnicode = 0;
+ /* Change the font type to CID font : */
+ pdfont->FontType = ft_CID_TrueType;
+ pdfont->write_contents = pdf_write_contents_cid2;
+ return 0;
+ }
+ }
+ }
+}
+
+/* ---------------- CMap resources ---------------- */
+
+/*
+ * Allocate a CMap resource.
+ */
+int
+pdf_cmap_alloc(gx_device_pdf *pdev, const gs_cmap_t *pcmap,
+ pdf_resource_t **ppres, int font_index_only)
+{
+ return pdf_write_cmap(pdev, pcmap, ppres, font_index_only);
+}
+