summaryrefslogtreecommitdiff
path: root/devices/vector/gdevpdtd.c
diff options
context:
space:
mode:
Diffstat (limited to 'devices/vector/gdevpdtd.c')
-rw-r--r--devices/vector/gdevpdtd.c869
1 files changed, 869 insertions, 0 deletions
diff --git a/devices/vector/gdevpdtd.c b/devices/vector/gdevpdtd.c
new file mode 100644
index 000000000..200786f6a
--- /dev/null
+++ b/devices/vector/gdevpdtd.c
@@ -0,0 +1,869 @@
+/* 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.
+*/
+
+
+/* FontDescriptor implementation for pdfwrite */
+#include "math_.h"
+#include "memory_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsrect.h" /* for rect_merge */
+#include "gscencs.h"
+#include "gxfcopy.h"
+#include "gdevpdfx.h"
+#include "gdevpdfo.h" /* for object->written */
+#include "gdevpdtb.h"
+#include "gdevpdtd.h"
+#include "gdevpdtf.h"
+
+/* ================ Types and structures ================ */
+
+/*
+ * There are many different flavors of FontDescriptor. The first division
+ * is between FontDescriptors for actual fonts, and character class entries
+ * in the FD dictionary of a CID-keyed font. The latter include metrics and
+ * a FontName but nothing else. We represent these with a different C
+ * structure (pdf_sub_font_descriptor_t).
+ *
+ * Descriptors for actual fonts have three major orthogonal properties:
+ *
+ * - Whether they represent a CID-keyed font or a name-keyed
+ * (non-CID-keyed) font. We distinguish this by the FontType
+ * of the saved font (see below).
+ *
+ * - Whether the font they represent is embedded.
+ *
+ * - Whether the font they represent is a complete font or a subset.
+ * We always track which glyphs in a font are used: client code
+ * decides whether to treat the font as a subset when the
+ * descriptor (and, if embedded, the font) is written.
+ *
+ * Note that non-embedded fonts in the base set of 14 do not have
+ * descriptors, nor do Type 0 or (synthetic bitmap) Type 3 fonts.
+ */
+/*
+ * Start by defining the elements common to font descriptors and sub-font
+ * (character class) descriptors.
+ */
+typedef struct pdf_font_descriptor_values_s {
+ /* Required elements */
+ int Ascent, CapHeight, Descent, ItalicAngle, StemV;
+ gs_int_rect FontBBox;
+ gs_string FontName;
+ uint Flags;
+ /* Optional elements (default to 0) */
+ int AvgWidth, Leading, MaxWidth, MissingWidth, StemH, XHeight;
+} pdf_font_descriptor_values_t;
+typedef struct pdf_font_descriptor_common_s pdf_font_descriptor_common_t;
+struct pdf_font_descriptor_common_s {
+ pdf_resource_common(pdf_font_descriptor_common_t);
+ pdf_font_descriptor_values_t values;
+};
+/* Flag bits */
+/*#define FONT_IS_FIXED_WIDTH (1<<0)*/ /* defined in gxfont.h */
+#define FONT_IS_SERIF (1<<1)
+#define FONT_IS_SYMBOLIC (1<<2)
+#define FONT_IS_SCRIPT (1<<3)
+/*
+ * There is confusion over the meaning of the 1<<5 bit. According to the
+ * published PDF documentation, in PDF 1.1, it meant "font uses
+ * StandardEncoding", and as of PDF 1.2, it means "font uses (a subset of)
+ * the Adobe standard Latin character set"; however, Acrobat Reader 3 and 4
+ * seem to use the former interpretation, even if the font is embedded and
+ * the file is identified as a PDF 1.2 file. We have to use the former
+ * interpretation in order to produce output that Acrobat will handle
+ * correctly.
+ */
+#define FONT_USES_STANDARD_ENCODING (1<<5) /* always used */
+#define FONT_IS_ADOBE_ROMAN (1<<5) /* never used */
+#define FONT_IS_ITALIC (1<<6)
+#define FONT_IS_ALL_CAPS (1<<16)
+#define FONT_IS_SMALL_CAPS (1<<17)
+#define FONT_IS_FORCE_BOLD (1<<18)
+
+/*
+ * Define a (top-level) FontDescriptor. CID-keyed vs. non-CID-keyed fonts
+ * are distinguished by their FontType.
+ */
+#ifndef pdf_base_font_DEFINED
+# define pdf_base_font_DEFINED
+typedef struct pdf_base_font_s pdf_base_font_t;
+#endif
+struct pdf_font_descriptor_s {
+ pdf_font_descriptor_common_t common;
+ pdf_base_font_t *base_font;
+ font_type FontType; /* (copied from base_font) */
+ bool embed;
+ struct cid_ { /* (CIDFonts only) */
+ cos_dict_t *Style;
+ char Lang[3]; /* 2 chars + \0 */
+ cos_dict_t *FD; /* value = COS_VALUE_RESOURCE */
+ } cid;
+};
+/*
+ * Define a sub-descriptor for a character class (FD dictionary element).
+ */
+typedef struct pdf_sub_font_descriptor_s {
+ pdf_font_descriptor_common_t common;
+} pdf_sub_font_descriptor_t;
+
+/*
+ * Font descriptors are pseudo-resources, so their GC descriptors
+ * must be public.
+ */
+BASIC_PTRS(pdf_font_descriptor_ptrs) {
+ GC_STRING_ELT(pdf_font_descriptor_t, common.values.FontName),
+ GC_OBJ_ELT(pdf_font_descriptor_t, base_font),
+ GC_OBJ_ELT(pdf_font_descriptor_t, cid.Style),
+ GC_OBJ_ELT(pdf_font_descriptor_t, cid.FD)
+};
+gs_public_st_basic_super(st_pdf_font_descriptor, pdf_font_descriptor_t,
+ "pdf_font_descriptor_t", pdf_font_descriptor_ptrs,
+ pdf_font_descriptor_data, &st_pdf_resource, 0);
+
+/*
+ * Sub-font descriptors are also pseudo-resources.
+ */
+BASIC_PTRS(pdf_sub_font_descriptor_ptrs) {
+ GC_STRING_ELT(pdf_sub_font_descriptor_t, common.values.FontName)
+};
+gs_public_st_basic_super(st_pdf_sub_font_descriptor,
+ pdf_sub_font_descriptor_t, "pdf_sub_font_descriptor_t",
+ pdf_sub_font_descriptor_ptrs, pdf_sub_font_descriptor_data,
+ &st_pdf_resource, 0);
+
+/* ================ Procedures ================ */
+
+/* ---------------- Private ---------------- */
+
+/* Get the ID of font descriptor metrics. */
+static inline long
+pdf_font_descriptor_common_id(const pdf_font_descriptor_common_t *pfdc)
+{
+ return pdf_resource_id((const pdf_resource_t *)pfdc);
+}
+
+/* Write the common part of a FontDescriptor, aside from the final >>. */
+static int
+write_FontDescriptor_common(gx_device_pdf *pdev,
+ const pdf_font_descriptor_common_t *pfd, bool embed)
+{
+ stream *s;
+ int code;
+ param_printer_params_t params;
+ printer_param_list_t rlist;
+ gs_param_list *const plist = (gs_param_list *)&rlist;
+ char *base14_name = NULL;
+
+ pdf_open_separate(pdev, pdf_font_descriptor_common_id(pfd), resourceFontDescriptor);
+ s = pdev->strm;
+ stream_puts(s, "<</Type/FontDescriptor/FontName");
+ if (!embed) {
+ base14_name = (char *)pdf_find_base14_name(pfd->values.FontName.data, pfd->values.FontName.size);
+ if(base14_name)
+ pdf_put_name(pdev, (byte *)base14_name, strlen(base14_name));
+ else
+ pdf_put_name(pdev, pfd->values.FontName.data, pfd->values.FontName.size);
+ } else
+ pdf_put_name(pdev, pfd->values.FontName.data, pfd->values.FontName.size);
+
+ pdf_write_font_bbox(pdev, &pfd->values.FontBBox);
+ params = param_printer_params_default;
+ code = s_init_param_printer(&rlist, &params, s);
+ if (code >= 0) {
+#define DESC_INT(str, memb)\
+ {str, gs_param_type_int, offset_of(pdf_font_descriptor_common_t, values.memb)}
+ static const gs_param_item_t required_items[] = {
+ DESC_INT("Ascent", Ascent),
+ DESC_INT("CapHeight", CapHeight),
+ DESC_INT("Descent", Descent),
+ DESC_INT("ItalicAngle", ItalicAngle),
+ DESC_INT("StemV", StemV),
+ gs_param_item_end
+ };
+ static const gs_param_item_t optional_items[] = {
+ DESC_INT("AvgWidth", AvgWidth),
+ DESC_INT("Leading", Leading),
+ DESC_INT("MaxWidth", MaxWidth),
+ DESC_INT("MissingWidth", MissingWidth),
+ DESC_INT("StemH", StemH),
+ DESC_INT("XHeight", XHeight),
+ gs_param_item_end
+ };
+#undef DESC_INT
+ int Flags = pfd->values.Flags;
+ pdf_font_descriptor_t defaults;
+
+ if (base14_name)
+ Flags |=FONT_USES_STANDARD_ENCODING;
+
+ code = param_write_int(plist, "Flags", &Flags);
+ if (code < 0)
+ return code;
+ code = gs_param_write_items(plist, pfd, NULL, required_items);
+ if (code < 0)
+ return code;
+ memset(&defaults, 0, sizeof(defaults));
+ code = gs_param_write_items(plist, pfd, &defaults, optional_items);
+ if (code < 0)
+ return code;
+ s_release_param_printer(&rlist);
+ }
+ return 0;
+}
+
+/* ---------------- Public ---------------- */
+
+/*
+ * Allocate a FontDescriptor, initializing the FontType and rid from the
+ * gs_font.
+ */
+int
+pdf_font_descriptor_alloc(gx_device_pdf *pdev, pdf_font_descriptor_t **ppfd,
+ gs_font_base *font, bool embed)
+{
+ pdf_font_descriptor_t *pfd;
+ pdf_base_font_t *pbfont;
+ int code = pdf_base_font_alloc(pdev, &pbfont, font,
+ (font->orig_FontMatrix.xx == 0 && font->orig_FontMatrix.xy == 0
+ ? &font->FontMatrix : &font->orig_FontMatrix), false);
+
+ if (code < 0)
+ return code;
+ code = pdf_alloc_resource(pdev, resourceFontDescriptor,
+ font->id, (pdf_resource_t **)&pfd, -1L);
+ if (code < 0) {
+ gs_free_object(pdev->pdf_memory, pbfont,
+ "pdf_font_descriptor_alloc(base_font)");
+ return code;
+ }
+ memset(&pfd->common.values, 0,
+ sizeof(*pfd) - offset_of(pdf_font_descriptor_t, common.values));
+ pfd->base_font = pbfont;
+ pfd->FontType = font->FontType;
+ pfd->embed = embed;
+ *ppfd = pfd;
+ return 0;
+}
+
+int pdf_font_descriptor_free(gx_device_pdf *pdev, pdf_resource_t *pres)
+{
+ pdf_font_descriptor_t *pfd = (pdf_font_descriptor_t *)pres;
+ pdf_base_font_t *pbfont = pfd->base_font;
+ gs_font *copied = (gs_font *)pbfont->copied, *complete = (gs_font *)pbfont->complete;
+
+ if (complete && copied != complete)
+ gs_free_copied_font(complete);
+
+ if (copied)
+ gs_free_copied_font(copied);
+
+ if (pbfont) {
+ if (pbfont->font_name.size) {
+ gs_free_string(pdev->pdf_memory, pbfont->font_name.data, pbfont->font_name.size, "Free BaseFont FontName string");
+ pbfont->font_name.data = (byte *)0L;
+ pbfont->font_name.size = 0;
+ }
+ gs_free_object(cos_object_memory(pres->object), pbfont, "Free base font from FontDescriptor)");
+ pfd->base_font = 0;
+ }
+ if (pres->object) {
+ gs_free_object(pdev->pdf_memory, pres->object, "free FontDescriptor object");
+ pres->object = NULL;
+ }
+ return 0;
+}
+
+/* Get the object ID of a FontDescriptor. */
+long
+pdf_font_descriptor_id(const pdf_font_descriptor_t *pfd)
+{
+ return pdf_resource_id((const pdf_resource_t *)pfd);
+}
+
+long pdf_set_font_descriptor_usage(gx_device_pdf *pdev, int parent_id, const pdf_font_descriptor_t *pfd)
+{
+ int id = pdf_resource_id((const pdf_resource_t *)pfd);
+
+ pdf_record_usage_by_parent(pdev, id, parent_id);
+ if (pfd->base_font->FontFile) {
+ id = pfd->base_font->FontFile->id;
+ pdf_record_usage_by_parent(pdev, id, parent_id);
+ }
+ return 0;
+}
+
+/*
+ * Get the FontType of a FontDescriptor.
+ */
+font_type
+pdf_font_descriptor_FontType(const pdf_font_descriptor_t *pfd)
+{
+ return pfd->FontType;
+}
+
+/*
+ * Get the embedding status of a FontDescriptor.
+ */
+bool
+pdf_font_descriptor_embedding(const pdf_font_descriptor_t *pfd)
+{
+ return pfd->embed;
+}
+
+/*
+ * Check for subset font.
+ */
+bool
+pdf_font_descriptor_is_subset(const pdf_font_descriptor_t *pfd)
+{
+ return pdf_base_font_is_subset(pfd->base_font);
+}
+
+/*
+ * Return a reference to the FontName of a FontDescriptor, similar to
+ * pdf_base_font_name.
+ */
+gs_string *pdf_font_descriptor_name(pdf_font_descriptor_t *pfd)
+{
+ return &pfd->common.values.FontName;
+}
+
+char *pdf_fontfile_hash(void *pfd)
+{
+ pdf_font_descriptor_t *fd = (pdf_font_descriptor_t *)pfd;
+ cos_dict_t *pcd;
+
+ if (fd->base_font && fd->base_font->FontFile) {
+ pcd = (cos_dict_t *)fd->base_font->FontFile;
+ if (pcd->stream_md5_valid)
+ return ((char *)pcd->stream_hash);
+ else
+ return 0;
+ } else
+ return 0;
+}
+
+/*
+ * Return the (copied, subset or complete) font associated with a FontDescriptor.
+ * This procedure probably shouldn't exist....
+ */
+gs_font_base *
+pdf_font_descriptor_font(const pdf_font_descriptor_t *pfd, bool complete)
+{
+ return pdf_base_font_font(pfd->base_font, complete);
+}
+
+/*
+ * Drop the copied complete font associated with a FontDescriptor.
+ */
+void
+pdf_font_descriptor_drop_complete_font(const pdf_font_descriptor_t *pfd)
+{
+ pdf_base_font_drop_complete(pfd->base_font);
+}
+
+/*
+ * Return a reference to the name of a FontDescriptor's base font, per
+ * pdf_base_font_name.
+ */
+gs_string *pdf_font_descriptor_base_name(const pdf_font_descriptor_t *pfd)
+{
+ return pdf_base_font_name(pfd->base_font);
+}
+
+/*
+ * Copy a glyph from a font to the stable copy. Return 0 if this is a
+ * new glyph, 1 if it was already copied.
+ */
+int
+pdf_font_used_glyph(pdf_font_descriptor_t *pfd, gs_glyph glyph,
+ gs_font_base *font)
+{
+ return pdf_base_font_copy_glyph(pfd->base_font, glyph, font);
+}
+
+/* Compute the FontDescriptor metrics for a font. */
+int
+pdf_compute_font_descriptor(gx_device_pdf *pdev, pdf_font_descriptor_t *pfd)
+{
+ gs_font_base *bfont = pdf_base_font_font(pfd->base_font, false);
+ gs_glyph glyph, notdef;
+ int index;
+ int wmode = bfont->WMode;
+ int members = (GLYPH_INFO_WIDTH0 << wmode) |
+ GLYPH_INFO_BBOX | GLYPH_INFO_NUM_PIECES;
+ pdf_font_descriptor_values_t desc;
+ gs_matrix smat;
+ gs_matrix *pmat = NULL;
+ int fixed_width = 0;
+ int small_descent = 0, small_height = 0;
+ bool small_present = false;
+ int x_height = 0;
+ int cap_height = 0;
+ gs_rect bbox_colon, bbox_period, bbox_I;
+ bool is_cid = (bfont->FontType == ft_CID_encrypted ||
+ bfont->FontType == ft_CID_TrueType);
+ bool have_colon = false, have_period = false, have_I = false;
+ int code;
+
+ memset(&bbox_colon, 0, sizeof(bbox_colon)); /* quiet gcc warnings. */
+ memset(&bbox_period, 0, sizeof(bbox_period)); /* quiet gcc warnings. */
+ memset(&bbox_I, 0, sizeof(bbox_I)); /* quiet gcc warnings. */
+ memset(&desc, 0, sizeof(desc));
+ if (is_cid && bfont->FontBBox.p.x != bfont->FontBBox.q.x &&
+ bfont->FontBBox.p.y != bfont->FontBBox.q.y) {
+ int scale = (bfont->FontType == ft_TrueType || bfont->FontType == ft_CID_TrueType ? 1000 : 1);
+
+ desc.FontBBox.p.x = (int)(bfont->FontBBox.p.x * scale);
+ desc.FontBBox.p.y = (int)(bfont->FontBBox.p.y * scale);
+ desc.FontBBox.q.x = (int)(bfont->FontBBox.q.x * scale);
+ desc.FontBBox.q.y = (int)(bfont->FontBBox.q.y * scale);
+ desc.Ascent = desc.FontBBox.q.y;
+ members &= ~GLYPH_INFO_BBOX;
+ } else {
+ desc.FontBBox.p.x = desc.FontBBox.p.y = max_int;
+ desc.FontBBox.q.x = desc.FontBBox.q.y = min_int;
+ }
+ /*
+ * Embedded TrueType fonts use a 1000-unit character space, but the
+ * font itself uses a 1-unit space. Compensate for this here.
+ */
+ switch (bfont->FontType) {
+ case ft_TrueType:
+ case ft_CID_TrueType:
+ gs_make_scaling(1000.0, 1000.0, &smat);
+ pmat = &smat;
+ /* Type 3 fonts may use a FontMatrix in PDF, so we don't
+ * need to deal with non-standard matrices
+ */
+ case ft_GL2_531:
+ case ft_PCL_user_defined:
+ case ft_GL2_stick_user_defined:
+ case ft_MicroType:
+ case ft_user_defined:
+ break;
+ /* Other font types may use a non-standard (not 1000x1000) design grid
+ * The FontMatrix is used to map to the unit square. However PDF files
+ * don't allow FontMatrix entries, all fonts are nominally 1000x1000.
+ * If we have a font with a non-standard matrix we must account for that
+ * here by scaling the font outline.
+ */
+ default:
+ gs_matrix_scale(&bfont->FontMatrix, 1000.0, 1000.0, &smat);
+ pmat = &smat;
+ break;
+ }
+
+ /*
+ * Scan the entire glyph space to compute Ascent, Descent, FontBBox, and
+ * the fixed width if any. For non-symbolic fonts, also note the
+ * bounding boxes for Latin letters and a couple of other characters,
+ * for computing the remaining descriptor values (CapHeight,
+ * ItalicAngle, StemV, XHeight, and flags SERIF, SCRIPT, ITALIC,
+ * ALL_CAPS, and SMALL_CAPS). (The algorithms are pretty crude.)
+ */
+ notdef = GS_NO_GLYPH;
+ for (index = 0;
+ (bfont->procs.enumerate_glyph((gs_font *)bfont, &index,
+ (is_cid ? GLYPH_SPACE_INDEX : GLYPH_SPACE_NAME), &glyph)) >= 0 &&
+ index != 0;
+ ) {
+ gs_glyph_info_t info;
+ gs_const_string gname;
+ gs_glyph glyph_known_enc;
+ gs_char position=0;
+
+ code = bfont->procs.glyph_info((gs_font *)bfont, glyph, pmat, members, &info);
+ if (code == gs_error_VMerror)
+ return code;
+ if (code < 0) {
+ /*
+ * Since this function may be indirtectly called from gx_device_finalize,
+ * we are unable to propagate error code to the interpreter.
+ * Therefore we skip it here hoping that few errors can be
+ * recovered by the integration through entire glyph set.
+ */
+ continue;
+ }
+ if (members & GLYPH_INFO_BBOX) {
+ /* rect_merge(desc.FontBBox, info.bbox); Expanding due to type cast :*/
+ if (info.bbox.p.x < desc.FontBBox.p.x) desc.FontBBox.p.x = (int)info.bbox.p.x;
+ if (info.bbox.q.x > desc.FontBBox.q.x) desc.FontBBox.q.x = (int)info.bbox.q.x;
+ if (info.bbox.p.y < desc.FontBBox.p.y) desc.FontBBox.p.y = (int)info.bbox.p.y;
+ if (info.bbox.q.y > desc.FontBBox.q.y) desc.FontBBox.q.y = (int)info.bbox.q.y;
+ if (!info.num_pieces)
+ desc.Ascent = max(desc.Ascent, (int)info.bbox.q.y);
+ }
+ if (notdef == GS_NO_GLYPH && gs_font_glyph_is_notdef(bfont, glyph)) {
+ notdef = glyph;
+ desc.MissingWidth = (int)info.width[wmode].x;
+ }
+ if (info.width[wmode].y != 0)
+ fixed_width = min_int;
+ else if (fixed_width == 0)
+ fixed_width = (int)info.width[wmode].x;
+ else if (info.width[wmode].x != fixed_width)
+ fixed_width = min_int;
+ if (desc.Flags & FONT_IS_SYMBOLIC)
+ continue; /* skip Roman-only computation */
+ if (is_cid)
+ continue;
+ code = bfont->procs.glyph_name((gs_font *)bfont, glyph, &gname);
+ if (code < 0) {
+ /* If we fail to get the glyph name, best assume this is a symbolic font */
+ desc.Flags |= FONT_IS_SYMBOLIC;
+ continue;
+ }
+ /* See if the glyph name is in any of the known encodings */
+ glyph_known_enc = gs_c_name_glyph(gname.data, gname.size);
+ if (glyph_known_enc == gs_no_glyph) {
+ desc.Flags |= FONT_IS_SYMBOLIC;
+ continue;
+ }
+ /* Finally check if the encoded glyph is in Standard Encoding */
+ /* gs_c_decode always fails to find .notdef, its always present so
+ * don't worry about it
+ */
+ if(strncmp(".notdef", (const char *)gname.data, gname.size)) {
+ position = gs_c_decode(glyph_known_enc, 0);
+ if (position == GS_NO_CHAR) {
+ desc.Flags |= FONT_IS_SYMBOLIC;
+ continue;
+ }
+ }
+ switch (gname.size) {
+ case 5:
+ if (!memcmp(gname.data, "colon", 5))
+ bbox_colon = info.bbox, have_colon = true;
+ continue;
+ case 6:
+ if (!memcmp(gname.data, "period", 6))
+ bbox_period = info.bbox, have_period = true;
+ continue;
+ case 1:
+ break;
+ default:
+ continue;
+ }
+
+ if (gname.data[0] >= 'A' && gname.data[0] <= 'Z') {
+ cap_height = max(cap_height, (int)info.bbox.q.y);
+ if (gname.data[0] == 'I')
+ bbox_I = info.bbox, have_I = true;
+ } else if (gname.data[0] >= 'a' && gname.data[0] <= 'z') {
+ int y0 = (int)(info.bbox.p.y), y1 = (int)(info.bbox.q.y);
+
+ small_present = true;
+ switch (gname.data[0]) {
+ case 'b': case 'd': case 'f': case 'h':
+ case 'k': case 'l': case 't': /* ascender */
+ small_height = max(small_height, y1);
+ case 'i': /* anomalous ascent */
+ break;
+ case 'j': /* descender with anomalous ascent */
+ small_descent = min(small_descent, y0);
+ break;
+ case 'g': case 'p': case 'q': case 'y': /* descender */
+ small_descent = min(small_descent, y0);
+ default: /* no ascender or descender */
+ x_height = max(x_height, y1);
+ }
+ }
+ }
+ if (!(desc.Flags & FONT_IS_SYMBOLIC)) {
+ desc.Flags |= FONT_IS_ADOBE_ROMAN; /* required if not symbolic */
+ desc.XHeight = (int)x_height;
+ if (!small_present && (!pdev->PDFA != 0 || bfont->FontType != ft_TrueType))
+ desc.Flags |= FONT_IS_ALL_CAPS;
+ desc.CapHeight = cap_height;
+ /*
+ * Look at various glyphs to determine ItalicAngle, StemV,
+ * SERIF, SCRIPT, and ITALIC.
+ */
+ if (have_colon && have_period) {
+ /* Calculate the dominant angle. */
+ int angle =
+ (int)(atan2((bbox_colon.q.y - bbox_colon.p.y) -
+ (bbox_period.q.y - bbox_period.p.y),
+ (bbox_colon.q.x - bbox_colon.p.x) -
+ (bbox_period.q.x - bbox_period.p.x)) *
+ radians_to_degrees) - 90;
+
+ /* Normalize to [-90..90]. */
+ while (angle > 90)
+ angle -= 180;
+ while (angle < -90)
+ angle += 180;
+ if (angle < -30)
+ angle = -30;
+ else if (angle > 30)
+ angle = 30;
+ /*
+ * For script or embellished fonts, we can get an angle that is
+ * slightly off from zero even for non-italic fonts.
+ * Compensate for this now.
+ */
+ if (angle <= 2 && angle >= -2)
+ angle = 0;
+ desc.ItalicAngle = angle;
+ }
+ if (desc.ItalicAngle)
+ desc.Flags |= FONT_IS_ITALIC;
+ if (have_I) {
+ double wdot = bbox_period.q.x - bbox_period.p.x;
+ double wcolon = bbox_I.q.x - bbox_I.p.x;
+ double wI = bbox_period.q.x - bbox_period.p.x;
+
+ desc.StemV = (int)wdot;
+ if (wI > wcolon * 2.5 || wI > (bbox_period.q.y - bbox_period.p.y) * 0.25)
+ desc.Flags |= FONT_IS_SERIF;
+ }
+ }
+ if (desc.Ascent == 0)
+ desc.Ascent = desc.FontBBox.q.y;
+ desc.Descent = desc.FontBBox.p.y;
+ if (!(desc.Flags & (FONT_IS_SYMBOLIC | FONT_IS_ALL_CAPS)) &&
+ (small_descent > desc.Descent / 3 || desc.XHeight > small_height * 0.9) &&
+ (!pdev->PDFA != 0 || bfont->FontType != ft_TrueType)
+ )
+ desc.Flags |= FONT_IS_SMALL_CAPS;
+ if (fixed_width > 0 && (!pdev->PDFA != 0 || bfont->FontType != ft_TrueType)) {
+ desc.Flags |= FONT_IS_FIXED_WIDTH;
+ desc.AvgWidth = desc.MaxWidth = desc.MissingWidth = fixed_width;
+ }
+ if (desc.CapHeight == 0)
+ desc.CapHeight = desc.Ascent;
+ if (desc.StemV == 0)
+ desc.StemV = (int)(desc.FontBBox.q.x * 0.15);
+ pfd->common.values = desc;
+ return 0;
+}
+
+/*
+ * Finish a FontDescriptor by computing the metric values, and then
+ * writing the associated embedded font if any.
+ */
+int
+pdf_finish_FontDescriptor(gx_device_pdf *pdev, pdf_resource_t *pres)
+{
+ pdf_font_descriptor_t *pfd = (pdf_font_descriptor_t *)pres;
+ int code = 0;
+ cos_dict_t *pcd = 0;
+ if (pfd->common.object->id == -1)
+ return 0;
+ if (!pfd->common.object->written &&
+ (code = pdf_compute_font_descriptor(pdev, pfd)) >= 0 &&
+ (!pfd->embed ||
+ (code = pdf_write_embedded_font(pdev, pfd->base_font,
+ pfd->FontType,
+ &pfd->common.values.FontBBox,
+ pfd->common.rid, &pcd)) >= 0)
+ ) {
+ pdf_set_FontFile_object(pfd->base_font, pcd);
+ }
+ return code;
+}
+
+/* Write a FontDescriptor. */
+int
+pdf_write_FontDescriptor(gx_device_pdf *pdev, pdf_resource_t *pres)
+{
+ pdf_font_descriptor_t *pfd = (pdf_font_descriptor_t *)pres;
+ font_type ftype = pfd->FontType;
+ long cidset_id = 0;
+ int code = 0;
+ stream *s;
+
+ if (pfd->common.object->written)
+ return 0;
+ if (pfd->common.object->id == -1)
+ return 0;
+
+ /* If this is a CIDFont subset, write the CIDSet now. */
+ switch (ftype) {
+ case ft_CID_encrypted:
+ case ft_CID_TrueType:
+ if (pdf_do_subset_font(pdev, pfd->base_font, pfd->common.rid)) {
+ if (pdev->PDFA < 2) {
+ code = pdf_write_CIDSet(pdev, pfd->base_font, &cidset_id);
+ if (code < 0)
+ return code;
+ }
+ }
+ default:
+ break;
+ }
+
+ {
+ /*
+ * Hack: make all embedded TrueType fonts "symbolic" to
+ * work around undocumented assumptions in Acrobat Reader.
+ */
+ /* See the comments in pdf_make_font_resource(). If we are embedding a font, its
+ * a TrueType font, we are not subsetting it, *and* the original font was not symbolic,
+ * then force the font to be non-symbolic. Otherwise, yes, force it symbolic.
+ */
+ pdf_font_descriptor_common_t fd;
+
+ fd = pfd->common;
+ if (pfd->embed && pfd->FontType == ft_TrueType) {
+ fd.values.Flags =
+ (fd.values.Flags & ~(FONT_IS_ADOBE_ROMAN)) | FONT_IS_SYMBOLIC;
+
+ if (pfd->base_font->do_subset == DO_SUBSET_NO && ((const gs_font_base *)pfd->base_font)->nearest_encoding_index != ENCODING_INDEX_UNKNOWN) {
+ fd.values.Flags =
+ (fd.values.Flags & ~(FONT_IS_SYMBOLIC)) | FONT_IS_ADOBE_ROMAN;
+ }
+ }
+ code = write_FontDescriptor_common(pdev, &fd, pfd->embed);
+ }
+ if (code < 0)
+ return code;
+ s = pdev->strm;
+ if (cidset_id != 0)
+ pprintld1(s, "/CIDSet %ld 0 R\n", cidset_id);
+ else if (pdf_do_subset_font(pdev, pfd->base_font, pfd->common.rid) &&
+ (ftype == ft_encrypted || ftype == ft_encrypted2)
+ ) {
+ stream_puts(s, "/CharSet");
+ code = pdf_write_CharSet(pdev, pfd->base_font);
+ if (code < 0)
+ return code;
+ }
+ if (pfd->embed && pfd->base_font->FontFile) {
+ code = pdf_write_FontFile_entry(pdev, pfd->base_font);
+ if (code < 0)
+ return code;
+ }
+ if (pfd->cid.Style) {
+ stream_puts(s, "/Style");
+ COS_WRITE(pfd->cid.Style, pdev);
+ }
+ if (pfd->cid.Lang[0]) {
+ pprints1(s, "/Lang(%s)", pfd->cid.Lang);
+ }
+ if (pfd->cid.FD) {
+ stream_puts(s, "/FD");
+ COS_WRITE(pfd->cid.FD, pdev);
+ }
+ stream_puts(s, ">>\n");
+ pdf_end_separate(pdev, resourceFontDescriptor);
+ pfd->common.object->written = true;
+ { const cos_object_t *pco = (const cos_object_t *)pdf_get_FontFile_object(pfd->base_font);
+ if (pco != NULL) {
+ code = COS_WRITE_OBJECT(pco, pdev, resourceFontFile);
+ if (code < 0)
+ return code;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Release a FontDescriptor components.
+ */
+int
+pdf_release_FontDescriptor_components(gx_device_pdf *pdev, pdf_resource_t *pres)
+{
+ pdf_font_descriptor_t *pfd = (pdf_font_descriptor_t *) pres;
+
+ gs_free_object(pdev->pdf_memory, pfd->base_font, "pdf_release_FontDescriptor_components");
+ pfd->base_font = NULL;
+ /* fixme: underimplemented. */
+ return 0;
+}
+
+/*
+ * Mark a FontDescriptor used in a text.
+ */
+int
+pdf_mark_font_descriptor_used(gx_device_pdf *pdev, pdf_font_descriptor_t *pfd)
+{
+ if (pfd != NULL && pfd->common.object->id == -1)
+ pdf_reserve_object_id(pdev, (pdf_resource_t *)&pfd->common, 0);
+ return 0;
+}
+
+/*
+ * Convert True Type font descriptor into CID font descriptor for PDF/A.
+ */
+int
+pdf_convert_truetype_font_descriptor(gx_device_pdf *pdev, pdf_font_resource_t *pdfont)
+{
+ pdf_font_descriptor_t *pfd = pdfont->FontDescriptor;
+ pdf_base_font_t *pbfont = pfd->base_font;
+ gs_font *pfont = (gs_font *)pbfont->copied;
+ gs_char ch;
+ /* Save the simple font descriptor data because CID font data overlap them. */
+ int FirstChar = pdfont->u.simple.FirstChar, LastChar = pdfont->u.simple.LastChar;
+ pdf_encoding_element_t *Encoding = pdfont->u.simple.Encoding;
+ int length_CIDSet = (pbfont->num_glyphs > LastChar ? (pbfont->num_glyphs + 7) / 8 : ((LastChar + 1) + 7 / 8));
+ int length_CIDToGIDMap = (pbfont->num_glyphs > LastChar ? (pbfont->num_glyphs + 1) * sizeof(ushort) : (LastChar + 1) * sizeof(ushort));
+
+ pfd->FontType = ft_CID_TrueType;
+ pdfont->u.simple.Encoding = NULL; /* Drop due to overlapping against a garbager problem. */
+ pbfont->CIDSet = gs_alloc_bytes(pdev->pdf_memory, length_CIDSet,
+ "pdf_convert_truetype_font_descriptor");
+ if (pbfont->CIDSet == NULL)
+ return_error(gs_error_VMerror);
+ memset(pbfont->CIDSet, 0, length_CIDSet);
+ pdfont->u.cidfont.CIDToGIDMap = (ushort *)gs_alloc_bytes(pdev->pdf_memory,
+ length_CIDToGIDMap, "pdf_convert_truetype_font_descriptor");
+ if (pdfont->u.cidfont.CIDToGIDMap == NULL)
+ return_error(gs_error_VMerror);
+ memset(pdfont->u.cidfont.CIDToGIDMap, 0, length_CIDToGIDMap);
+ if(pdev->PDFA) {
+ for (ch = FirstChar; ch <= LastChar; ch++) {
+ if (Encoding[ch].glyph != GS_NO_GLYPH) {
+ gs_glyph glyph = pfont->procs.encode_char(pfont, ch, GLYPH_SPACE_INDEX);
+
+ pbfont->CIDSet[ch / 8] |= 0x80 >> (ch % 8);
+ pdfont->u.cidfont.CIDToGIDMap[ch] = glyph - GS_MIN_GLYPH_INDEX;
+ }
+ }
+ /* Set the CIDSet bit for CID 0 (the /.notdef) which must always be present */
+ pbfont->CIDSet[0] |= 0x80;
+ } else {
+ for (ch = 0; ch <= pbfont->num_glyphs; ch++) {
+ gs_glyph glyph = pfont->procs.encode_char(pfont, ch, GLYPH_SPACE_INDEX);
+
+ pbfont->CIDSet[ch / 8] |= 0x80 >> (ch % 8);
+ pdfont->u.cidfont.CIDToGIDMap[ch] = glyph - GS_MIN_GLYPH_INDEX;
+ }
+ }
+ pbfont->CIDSetLength = length_CIDSet;
+ pdfont->u.cidfont.CIDToGIDMapLength = length_CIDToGIDMap / sizeof(ushort);
+ pdfont->u.cidfont.Widths2 = NULL;
+ pdfont->u.cidfont.used2 = NULL;
+ pdfont->u.cidfont.v = NULL;
+ return 0;
+}
+
+int mark_font_descriptor_symbolic(const pdf_font_resource_t *pdfont)
+{
+ pdf_font_descriptor_values_t *desc;
+
+ if(!pdfont || !pdfont->FontDescriptor)
+ return 0;
+
+ desc = &pdfont->FontDescriptor->common.values;
+
+ if (!(desc->Flags & FONT_IS_SYMBOLIC)) {
+ desc->Flags |= FONT_IS_SYMBOLIC;
+ desc->Flags &= ~FONT_IS_ADOBE_ROMAN;
+ }
+ return 1;
+}