xref: /plan9/sys/src/cmd/gs/src/gdevpdtd.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 2002 Aladdin Enterprises.  All rights reserved.
2 
3   This software is provided AS-IS with no warranty, either express or
4   implied.
5 
6   This software is distributed under license and may not be copied,
7   modified or distributed except as expressly authorized under the terms
8   of the license contained in the file LICENSE in this distribution.
9 
10   For more information about licensing, please refer to
11   http://www.ghostscript.com/licensing/. For information on
12   commercial licensing, go to http://www.artifex.com/licensing/ or
13   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15 */
16 
17 /* $Id: gdevpdtd.c,v 1.22 2005/04/05 15:44:44 igor Exp $ */
18 /* FontDescriptor implementation for pdfwrite */
19 #include "math_.h"
20 #include "memory_.h"
21 #include "gx.h"
22 #include "gserrors.h"
23 #include "gsrect.h"		/* for rect_merge */
24 #include "gdevpdfx.h"
25 #include "gdevpdfo.h"		/* for object->written */
26 #include "gdevpdtb.h"
27 #include "gdevpdtd.h"
28 
29 /* ================ Types and structures ================ */
30 
31 /*
32  * There are many different flavors of FontDescriptor.  The first division
33  * is between FontDescriptors for actual fonts, and character class entries
34  * in the FD dictionary of a CID-keyed font.  The latter include metrics and
35  * a FontName but nothing else.  We represent these with a different C
36  * structure (pdf_sub_font_descriptor_t).
37  *
38  * Descriptors for actual fonts have three major orthogonal properties:
39  *
40  *	- Whether they represent a CID-keyed font or a name-keyed
41  *	  (non-CID-keyed) font.  We distinguish this by the FontType
42  *	  of the saved font (see below).
43  *
44  *	- Whether the font they represent is embedded.
45  *
46  *	- Whether the font they represent is a complete font or a subset.
47  *	  We always track which glyphs in a font are used: client code
48  *	  decides whether to treat the font as a subset when the
49  *	  descriptor (and, if embedded, the font) is written.
50  *
51  * Note that non-embedded fonts in the base set of 14 do not have
52  * descriptors, nor do Type 0 or (synthetic bitmap) Type 3 fonts.
53  */
54 /*
55  * Start by defining the elements common to font descriptors and sub-font
56  * (character class) descriptors.
57  */
58 typedef struct pdf_font_descriptor_values_s {
59     /* Required elements */
60     int Ascent, CapHeight, Descent, ItalicAngle, StemV;
61     gs_int_rect FontBBox;
62     gs_string FontName;
63     uint Flags;
64     /* Optional elements (default to 0) */
65     int AvgWidth, Leading, MaxWidth, MissingWidth, StemH, XHeight;
66 } pdf_font_descriptor_values_t;
67 typedef struct pdf_font_descriptor_common_s pdf_font_descriptor_common_t;
68 struct pdf_font_descriptor_common_s {
69     pdf_resource_common(pdf_font_descriptor_common_t);
70     pdf_font_descriptor_values_t values;
71 };
72 /* Flag bits */
73 /*#define FONT_IS_FIXED_WIDTH (1<<0)*/  /* defined in gxfont.h */
74 #define FONT_IS_SERIF (1<<1)
75 #define FONT_IS_SYMBOLIC (1<<2)
76 #define FONT_IS_SCRIPT (1<<3)
77 /*
78  * There is confusion over the meaning of the 1<<5 bit.  According to the
79  * published PDF documentation, in PDF 1.1, it meant "font uses
80  * StandardEncoding", and as of PDF 1.2, it means "font uses (a subset of)
81  * the Adobe standard Latin character set"; however, Acrobat Reader 3 and 4
82  * seem to use the former interpretation, even if the font is embedded and
83  * the file is identified as a PDF 1.2 file.  We have to use the former
84  * interpretation in order to produce output that Acrobat will handle
85  * correctly.
86  */
87 #define FONT_USES_STANDARD_ENCODING (1<<5) /* always used */
88 #define FONT_IS_ADOBE_ROMAN (1<<5) /* never used */
89 #define FONT_IS_ITALIC (1<<6)
90 #define FONT_IS_ALL_CAPS (1<<16)
91 #define FONT_IS_SMALL_CAPS (1<<17)
92 #define FONT_IS_FORCE_BOLD (1<<18)
93 
94 /*
95  * Define a (top-level) FontDescriptor.  CID-keyed vs. non-CID-keyed fonts
96  * are distinguished by their FontType.
97  */
98 #ifndef pdf_base_font_DEFINED
99 #  define pdf_base_font_DEFINED
100 typedef struct pdf_base_font_s pdf_base_font_t;
101 #endif
102 struct pdf_font_descriptor_s {
103     pdf_font_descriptor_common_t common;
104     pdf_base_font_t *base_font;
105     font_type FontType;		/* (copied from base_font) */
106     bool embed;
107     struct cid_ {		/* (CIDFonts only) */
108 	cos_dict_t *Style;
109 	char Lang[3];		/* 2 chars + \0 */
110 	cos_dict_t *FD;		/* value = COS_VALUE_RESOURCE */
111     } cid;
112 };
113 /*
114  * Define a sub-descriptor for a character class (FD dictionary element).
115  */
116 typedef struct pdf_sub_font_descriptor_s {
117     pdf_font_descriptor_common_t common;
118 } pdf_sub_font_descriptor_t;
119 
120 /*
121  * Font descriptors are pseudo-resources, so their GC descriptors
122  * must be public.
123  */
BASIC_PTRS(pdf_font_descriptor_ptrs)124 BASIC_PTRS(pdf_font_descriptor_ptrs) {
125     GC_STRING_ELT(pdf_font_descriptor_t, common.values.FontName),
126     GC_OBJ_ELT(pdf_font_descriptor_t, base_font),
127     GC_OBJ_ELT(pdf_font_descriptor_t, cid.Style),
128     GC_OBJ_ELT(pdf_font_descriptor_t, cid.FD)
129 };
130 gs_public_st_basic_super(st_pdf_font_descriptor, pdf_font_descriptor_t,
131   "pdf_font_descriptor_t", pdf_font_descriptor_ptrs,
132   pdf_font_descriptor_data, &st_pdf_resource, 0);
133 
134 /*
135  * Sub-font descriptors are also pseudo-resources.
136  */
BASIC_PTRS(pdf_sub_font_descriptor_ptrs)137 BASIC_PTRS(pdf_sub_font_descriptor_ptrs) {
138     GC_STRING_ELT(pdf_sub_font_descriptor_t, common.values.FontName)
139 };
140 gs_public_st_basic_super(st_pdf_sub_font_descriptor,
141   pdf_sub_font_descriptor_t, "pdf_sub_font_descriptor_t",
142   pdf_sub_font_descriptor_ptrs, pdf_sub_font_descriptor_data,
143   &st_pdf_resource, 0);
144 
145 /* ================ Procedures ================ */
146 
147 /* ---------------- Private ---------------- */
148 
149 /* Get the ID of font descriptor metrics. */
150 inline private long
pdf_font_descriptor_common_id(const pdf_font_descriptor_common_t * pfdc)151 pdf_font_descriptor_common_id(const pdf_font_descriptor_common_t *pfdc)
152 {
153     return pdf_resource_id((const pdf_resource_t *)pfdc);
154 }
155 
156 /* Write the common part of a FontDescriptor, aside from the final >>. */
157 private int
write_FontDescriptor_common(gx_device_pdf * pdev,const pdf_font_descriptor_common_t * pfd)158 write_FontDescriptor_common(gx_device_pdf *pdev,
159 			    const pdf_font_descriptor_common_t *pfd)
160 {
161     stream *s;
162     int code;
163     param_printer_params_t params;
164     printer_param_list_t rlist;
165     gs_param_list *const plist = (gs_param_list *)&rlist;
166 
167     pdf_open_separate(pdev, pdf_font_descriptor_common_id(pfd));
168     s = pdev->strm;
169     stream_puts(s, "<</Type/FontDescriptor/FontName");
170     pdf_put_name(pdev, pfd->values.FontName.data, pfd->values.FontName.size);
171     pdf_write_font_bbox(pdev, &pfd->values.FontBBox);
172     params = param_printer_params_default;
173     code = s_init_param_printer(&rlist, &params, s);
174     if (code >= 0) {
175 #define DESC_INT(str, memb)\
176  {str, gs_param_type_int, offset_of(pdf_font_descriptor_common_t, values.memb)}
177 	static const gs_param_item_t required_items[] = {
178 	    DESC_INT("Ascent", Ascent),
179 	    DESC_INT("CapHeight", CapHeight),
180 	    DESC_INT("Descent", Descent),
181 	    DESC_INT("ItalicAngle", ItalicAngle),
182 	    DESC_INT("StemV", StemV),
183 	    gs_param_item_end
184 	};
185 	static const gs_param_item_t optional_items[] = {
186 	    DESC_INT("AvgWidth", AvgWidth),
187 	    DESC_INT("Leading", Leading),
188 	    DESC_INT("MaxWidth", MaxWidth),
189 	    DESC_INT("MissingWidth", MissingWidth),
190 	    DESC_INT("StemH", StemH),
191 	    DESC_INT("XHeight", XHeight),
192 	    gs_param_item_end
193 	};
194 #undef DESC_INT
195 	int Flags = pfd->values.Flags;
196 	pdf_font_descriptor_t defaults;
197 
198 	param_write_int(plist, "Flags", &Flags);
199 	gs_param_write_items(plist, pfd, NULL, required_items);
200 	memset(&defaults, 0, sizeof(defaults));
201 	gs_param_write_items(plist, pfd, &defaults, optional_items);
202 	s_release_param_printer(&rlist);
203     }
204     return 0;
205 }
206 
207 /* ---------------- Public ---------------- */
208 
209 /*
210  * Allocate a FontDescriptor, initializing the FontType and rid from the
211  * gs_font.
212  */
213 int
pdf_font_descriptor_alloc(gx_device_pdf * pdev,pdf_font_descriptor_t ** ppfd,gs_font_base * font,bool embed)214 pdf_font_descriptor_alloc(gx_device_pdf *pdev, pdf_font_descriptor_t **ppfd,
215 			  gs_font_base *font, bool embed)
216 {
217     pdf_font_descriptor_t *pfd;
218     pdf_base_font_t *pbfont;
219     int code = pdf_base_font_alloc(pdev, &pbfont, font,
220 		(font->orig_FontMatrix.xx == 0 && font->orig_FontMatrix.xy == 0
221 		    ? &font->FontMatrix : &font->orig_FontMatrix), false, !embed);
222 
223     if (code < 0)
224 	return code;
225     code = pdf_alloc_resource(pdev, resourceFontDescriptor,
226 			      font->id, (pdf_resource_t **)&pfd, 0L);
227     if (code < 0) {
228 	gs_free_object(pdev->pdf_memory, pbfont,
229 		       "pdf_font_descriptor_alloc(base_font)");
230 	return code;
231     }
232     memset(&pfd->common.values, 0,
233 	   sizeof(*pfd) - offset_of(pdf_font_descriptor_t, common.values));
234     pfd->base_font = pbfont;
235     pfd->FontType = font->FontType;
236     pfd->embed = embed;
237     *ppfd = pfd;
238     return 0;
239 }
240 
241 /* Get the object ID of a FontDescriptor. */
242 long
pdf_font_descriptor_id(const pdf_font_descriptor_t * pfd)243 pdf_font_descriptor_id(const pdf_font_descriptor_t *pfd)
244 {
245     return pdf_resource_id((const pdf_resource_t *)pfd);
246 }
247 
248 /*
249  * Get the FontType of a FontDescriptor.
250  */
251 font_type
pdf_font_descriptor_FontType(const pdf_font_descriptor_t * pfd)252 pdf_font_descriptor_FontType(const pdf_font_descriptor_t *pfd)
253 {
254     return pfd->FontType;
255 }
256 
257 /*
258  * Get the embedding status of a FontDescriptor.
259  */
260 bool
pdf_font_descriptor_embedding(const pdf_font_descriptor_t * pfd)261 pdf_font_descriptor_embedding(const pdf_font_descriptor_t *pfd)
262 {
263     return pfd->embed;
264 }
265 
266 /*
267  * Check for subset font.
268  */
269 bool
pdf_font_descriptor_is_subset(const pdf_font_descriptor_t * pfd)270 pdf_font_descriptor_is_subset(const pdf_font_descriptor_t *pfd)
271 {
272     return pdf_base_font_is_subset(pfd->base_font);
273 }
274 
275 /*
276  * Return a reference to the FontName of a FontDescriptor, similar to
277  * pdf_base_font_name.
278  */
pdf_font_descriptor_name(pdf_font_descriptor_t * pfd)279 gs_string *pdf_font_descriptor_name(pdf_font_descriptor_t *pfd)
280 {
281     return &pfd->common.values.FontName;
282 }
283 
284 /*
285  * Return the (copied, subset or complete) font associated with a FontDescriptor.
286  * This procedure probably shouldn't exist....
287  */
288 gs_font_base *
pdf_font_descriptor_font(const pdf_font_descriptor_t * pfd,bool complete)289 pdf_font_descriptor_font(const pdf_font_descriptor_t *pfd, bool complete)
290 {
291     return pdf_base_font_font(pfd->base_font, complete);
292 }
293 
294 /*
295  * Drop the copied complete font associated with a FontDescriptor.
296  */
297 void
pdf_font_descriptor_drop_complete_font(const pdf_font_descriptor_t * pfd)298 pdf_font_descriptor_drop_complete_font(const pdf_font_descriptor_t *pfd)
299 {
300     pdf_base_font_drop_complete(pfd->base_font);
301 }
302 
303 /*
304  * Return a reference to the name of a FontDescriptor's base font, per
305  * pdf_base_font_name.
306  */
pdf_font_descriptor_base_name(const pdf_font_descriptor_t * pfd)307 gs_string *pdf_font_descriptor_base_name(const pdf_font_descriptor_t *pfd)
308 {
309     return pdf_base_font_name(pfd->base_font);
310 }
311 
312 /*
313  * Copy a glyph from a font to the stable copy.  Return 0 if this is a
314  * new glyph, 1 if it was already copied.
315  */
316 int
pdf_font_used_glyph(pdf_font_descriptor_t * pfd,gs_glyph glyph,gs_font_base * font)317 pdf_font_used_glyph(pdf_font_descriptor_t *pfd, gs_glyph glyph,
318 		    gs_font_base *font)
319 {
320     return pdf_base_font_copy_glyph(pfd->base_font, glyph, font);
321 }
322 
323 /* Compute the FontDescriptor metrics for a font. */
324 int
pdf_compute_font_descriptor(pdf_font_descriptor_t * pfd)325 pdf_compute_font_descriptor(pdf_font_descriptor_t *pfd)
326 {
327     gs_font_base *bfont = pdf_base_font_font(pfd->base_font, false);
328     gs_glyph glyph, notdef;
329     int index;
330     int wmode = bfont->WMode;
331     int members = (GLYPH_INFO_WIDTH0 << wmode) |
332 	GLYPH_INFO_BBOX | GLYPH_INFO_NUM_PIECES;
333     pdf_font_descriptor_values_t desc;
334     gs_matrix smat;
335     gs_matrix *pmat = NULL;
336     int fixed_width = 0;
337     int small_descent = 0, small_height = 0;
338     bool small_present = false;
339     int x_height = min_int;
340     int cap_height = 0;
341     gs_rect bbox_colon, bbox_period, bbox_I;
342     bool is_cid = (bfont->FontType == ft_CID_encrypted ||
343 		   bfont->FontType == ft_CID_TrueType);
344     bool have_colon = false, have_period = false, have_I = false;
345     int code;
346 
347     memset(&desc, 0, sizeof(desc));
348     if (is_cid && bfont->FontBBox.p.x != bfont->FontBBox.q.x &&
349 		  bfont->FontBBox.p.y != bfont->FontBBox.q.y) {
350 	int scale = (bfont->FontType == ft_TrueType || bfont->FontType == ft_CID_TrueType ? 1000 : 1);
351 
352 	desc.FontBBox.p.x = (int)(bfont->FontBBox.p.x * scale);
353 	desc.FontBBox.p.y = (int)(bfont->FontBBox.p.y * scale);
354 	desc.FontBBox.p.x = (int)(bfont->FontBBox.p.x * scale);
355 	desc.FontBBox.q.y = (int)(bfont->FontBBox.q.y * scale);
356 	desc.Ascent = desc.FontBBox.q.y;
357 	members &= ~GLYPH_INFO_BBOX;
358     } else {
359 	desc.FontBBox.p.x = desc.FontBBox.p.y = max_int;
360 	desc.FontBBox.q.x = desc.FontBBox.q.y = min_int;
361     }
362     /*
363      * Embedded TrueType fonts use a 1000-unit character space, but the
364      * font itself uses a 1-unit space.  Compensate for this here.
365      */
366     switch (bfont->FontType) {
367     case ft_TrueType:
368     case ft_CID_TrueType:
369 	gs_make_scaling(1000.0, 1000.0, &smat);
370 	pmat = &smat;
371     default:
372 	break;
373     }
374     /*
375      * See the note on FONT_IS_ADOBE_ROMAN / FONT_USES_STANDARD_ENCODING
376      * in gdevpdtd.h for why the following substitution is made.
377      */
378 #if 0
379 #  define CONSIDER_FONT_SYMBOLIC(bfont) font_is_symbolic(bfont)
380 #else
381 #  define CONSIDER_FONT_SYMBOLIC(bfont)\
382   ((bfont)->encoding_index != ENCODING_INDEX_STANDARD)
383 #endif
384     if (CONSIDER_FONT_SYMBOLIC(bfont))
385 	desc.Flags |= FONT_IS_SYMBOLIC;
386     /*
387      * Scan the entire glyph space to compute Ascent, Descent, FontBBox, and
388      * the fixed width if any.  For non-symbolic fonts, also note the
389      * bounding boxes for Latin letters and a couple of other characters,
390      * for computing the remaining descriptor values (CapHeight,
391      * ItalicAngle, StemV, XHeight, and flags SERIF, SCRIPT, ITALIC,
392      * ALL_CAPS, and SMALL_CAPS).  (The algorithms are pretty crude.)
393      */
394     notdef = GS_NO_GLYPH;
395     for (index = 0;
396 	 (code = bfont->procs.enumerate_glyph((gs_font *)bfont, &index,
397 		(is_cid ? GLYPH_SPACE_INDEX : GLYPH_SPACE_NAME), &glyph)) >= 0 &&
398 	     index != 0;
399 	 ) {
400 	gs_glyph_info_t info;
401 	gs_const_string gname;
402 
403 	code = bfont->procs.glyph_info((gs_font *)bfont, glyph, pmat, members, &info);
404 	if (code == gs_error_VMerror)
405 	    return code;
406 	if (code < 0) {
407 	    /*
408 	     * Since this function may be indirtectly called from gx_device_finalize,
409 	     * we are unable to propagate error code to the interpreter.
410 	     * Therefore we skip it here hoping that few errors can be
411 	     * recovered by the integration through entire glyph set.
412 	     */
413 	    continue;
414 	}
415 	if (members & GLYPH_INFO_BBOX) {
416 	    /* rect_merge(desc.FontBBox, info.bbox); Expanding due to type cast :*/
417 	    if (info.bbox.p.x < desc.FontBBox.p.x) desc.FontBBox.p.x = (int)info.bbox.p.x;
418 	    if (info.bbox.q.x > desc.FontBBox.q.x) desc.FontBBox.q.x = (int)info.bbox.q.x;
419 	    if (info.bbox.p.y < desc.FontBBox.p.y) desc.FontBBox.p.y = (int)info.bbox.p.y;
420 	    if (info.bbox.q.y > desc.FontBBox.q.y) desc.FontBBox.q.y = (int)info.bbox.q.y;
421 	    if (!info.num_pieces)
422 		desc.Ascent = max(desc.Ascent, (int)info.bbox.q.y);
423 	}
424 	if (notdef == GS_NO_GLYPH && gs_font_glyph_is_notdef(bfont, glyph)) {
425 	    notdef = glyph;
426 	    desc.MissingWidth = (int)info.width[wmode].x;
427 	}
428 	if (info.width[wmode].y != 0)
429 	    fixed_width = min_int;
430 	else if (fixed_width == 0)
431 	    fixed_width = (int)info.width[wmode].x;
432 	else if (info.width[wmode].x != fixed_width)
433 	    fixed_width = min_int;
434 	if (desc.Flags & FONT_IS_SYMBOLIC)
435 	    continue;		/* skip Roman-only computation */
436 	if (is_cid)
437 	    continue;
438 	code = bfont->procs.glyph_name((gs_font *)bfont, glyph, &gname);
439 	if (code < 0)
440 	    continue;
441 	switch (gname.size) {
442 	case 5:
443 	    if (!memcmp(gname.data, "colon", 5))
444 		bbox_colon = info.bbox, have_colon = true;
445 	    continue;
446 	case 6:
447 	    if (!memcmp(gname.data, "period", 6))
448 		bbox_period = info.bbox, have_period = true;
449 	    continue;
450 	case 1:
451 	    break;
452 	default:
453 	    continue;
454 	}
455 	if (gname.data[0] >= 'A' && gname.data[0] <= 'Z') {
456 	    cap_height = max(cap_height, (int)info.bbox.q.y);
457 	    if (gname.data[0] == 'I')
458 		bbox_I = info.bbox, have_I = true;
459 	} else if (gname.data[0] >= 'a' && gname.data[0] <= 'z') {
460 	    int y0 = (int)(info.bbox.p.y), y1 = (int)(info.bbox.q.y);
461 
462 	    small_present = true;
463 	    switch (gname.data[0]) {
464 	    case 'b': case 'd': case 'f': case 'h':
465 	    case 'k': case 'l': case 't': /* ascender */
466 		small_height = max(small_height, y1);
467 	    case 'i':		/* anomalous ascent */
468 		break;
469 	    case 'j':		/* descender with anomalous ascent */
470 		small_descent = min(small_descent, y0);
471 		break;
472 	    case 'g': case 'p': case 'q': case 'y': /* descender */
473 		small_descent = min(small_descent, y0);
474 	    default:		/* no ascender or descender */
475 		x_height = max(x_height, y1);
476 	    }
477 	}
478     }
479     if (!(desc.Flags & FONT_IS_SYMBOLIC)) {
480 	desc.Flags |= FONT_IS_ADOBE_ROMAN; /* required if not symbolic */
481 	desc.XHeight = (int)x_height;
482 	if (!small_present)
483 	    desc.Flags |= FONT_IS_ALL_CAPS;
484 	desc.CapHeight = cap_height;
485 	/*
486 	 * Look at various glyphs to determine ItalicAngle, StemV,
487 	 * SERIF, SCRIPT, and ITALIC.
488 	 */
489 	if (have_colon && have_period) {
490 	    /* Calculate the dominant angle. */
491 	    int angle =
492 		(int)(atan2((bbox_colon.q.y - bbox_colon.p.y) -
493 			      (bbox_period.q.y - bbox_period.p.y),
494 			    (bbox_colon.q.x - bbox_colon.p.x) -
495 			      (bbox_period.q.x - bbox_period.p.x)) *
496 		      radians_to_degrees) - 90;
497 
498 	    /* Normalize to [-90..90]. */
499 	    while (angle > 90)
500 		angle -= 180;
501 	    while (angle < -90)
502 		angle += 180;
503 	    if (angle < -30)
504 		angle = -30;
505 	    else if (angle > 30)
506 		angle = 30;
507 	    /*
508 	     * For script or embellished fonts, we can get an angle that is
509 	     * slightly off from zero even for non-italic fonts.
510 	     * Compensate for this now.
511 	     */
512 	    if (angle <= 2 && angle >= -2)
513 		angle = 0;
514 	    desc.ItalicAngle = angle;
515 	}
516 	if (desc.ItalicAngle)
517 	    desc.Flags |= FONT_IS_ITALIC;
518 	if (have_I) {
519 	    double wdot = bbox_period.q.x - bbox_period.p.x;
520 	    double wcolon = bbox_I.q.x - bbox_I.p.x;
521 	    double wI = bbox_period.q.x - bbox_period.p.x;
522 
523 	    desc.StemV = (int)wdot;
524 	    if (wI > wcolon * 2.5 || wI > (bbox_period.q.y - bbox_period.p.y) * 0.25)
525 		desc.Flags |= FONT_IS_SERIF;
526 	}
527     }
528     if (desc.Ascent == 0)
529 	desc.Ascent = desc.FontBBox.q.y;
530     desc.Descent = desc.FontBBox.p.y;
531     if (!(desc.Flags & (FONT_IS_SYMBOLIC | FONT_IS_ALL_CAPS)) &&
532 	(small_descent > desc.Descent / 3 || desc.XHeight > small_height * 0.9)
533 	)
534 	desc.Flags |= FONT_IS_SMALL_CAPS;
535     if (fixed_width > 0) {
536 	desc.Flags |= FONT_IS_FIXED_WIDTH;
537 	desc.AvgWidth = desc.MaxWidth = desc.MissingWidth = fixed_width;
538     }
539     if (desc.CapHeight == 0)
540 	desc.CapHeight = desc.Ascent;
541     if (desc.StemV == 0)
542 	desc.StemV = (int)(desc.FontBBox.q.x * 0.15);
543     pfd->common.values = desc;
544     return 0;
545 }
546 
547 /*
548  * Finish a FontDescriptor by computing the metric values, and then
549  * writing the associated embedded font if any.
550  */
551 int
pdf_finish_FontDescriptor(gx_device_pdf * pdev,pdf_font_descriptor_t * pfd)552 pdf_finish_FontDescriptor(gx_device_pdf *pdev, pdf_font_descriptor_t *pfd)
553 {
554     int code = 0;
555     cos_dict_t *pcd = 0;
556 
557     if (!pfd->common.object->written &&
558 	(code = pdf_compute_font_descriptor(pfd)) >= 0 &&
559 	(!pfd->embed ||
560 	 (code = pdf_write_embedded_font(pdev, pfd->base_font,
561 				&pfd->common.values.FontBBox,
562 				pfd->common.rid, &pcd)) >= 0)
563 	) {
564         pdf_set_FontFile_object(pfd->base_font, pcd);
565     }
566     return code;
567 }
568 
569 /* Write a FontDescriptor. */
570 int
pdf_write_FontDescriptor(gx_device_pdf * pdev,pdf_font_descriptor_t * pfd)571 pdf_write_FontDescriptor(gx_device_pdf *pdev, pdf_font_descriptor_t *pfd)
572 {
573     font_type ftype = pfd->FontType;
574     long cidset_id = 0;
575     int code = 0;
576     stream *s;
577 
578     if (pfd->common.object->written)
579 	return 0;
580 
581     /* If this is a CIDFont subset, write the CIDSet now. */
582     switch (ftype) {
583     case ft_CID_encrypted:
584     case ft_CID_TrueType:
585 	if (pdf_do_subset_font(pdev, pfd->base_font, pfd->common.rid)) {
586 	    code = pdf_write_CIDSet(pdev, pfd->base_font, &cidset_id);
587 	    if (code < 0)
588 		return code;
589 	}
590     default:
591 	break;
592     }
593 
594     {
595 	/*
596 	 * Hack: make all embedded subset TrueType fonts "symbolic" to
597 	 * work around undocumented assumptions in Acrobat Reader.
598 	 */
599 	pdf_font_descriptor_common_t fd;
600 
601 	fd = pfd->common;
602 	if (pfd->embed && pfd->FontType == ft_TrueType &&
603 	    pdf_do_subset_font(pdev, pfd->base_font, pfd->common.rid)
604 	    )
605 	    fd.values.Flags =
606 		(fd.values.Flags & ~(FONT_IS_ADOBE_ROMAN)) | FONT_IS_SYMBOLIC;
607 	code = write_FontDescriptor_common(pdev, &fd);
608     }
609     if (code < 0)
610 	return code;
611     s = pdev->strm;
612     if (cidset_id != 0)
613 	pprintld1(s, "/CIDSet %ld 0 R\n", cidset_id);
614     else if (pdf_do_subset_font(pdev, pfd->base_font, pfd->common.rid) &&
615 	     (ftype == ft_encrypted || ftype == ft_encrypted2)
616 	     ) {
617 	stream_puts(s, "/CharSet");
618 	code = pdf_write_CharSet(pdev, pfd->base_font);
619 	if (code < 0)
620 	    return code;
621     }
622     if (pfd->embed) {
623 	code = pdf_write_FontFile_entry(pdev, pfd->base_font);
624 	if (code < 0)
625 	    return code;
626     }
627     if (pfd->cid.Style) {
628 	stream_puts(s, "/Style");
629 	COS_WRITE(pfd->cid.Style, pdev);
630     }
631     if (pfd->cid.Lang[0]) {
632 	pprints1(s, "/Lang(%s)", pfd->cid.Lang);
633     }
634     if (pfd->cid.FD) {
635 	stream_puts(s, "/FD");
636 	COS_WRITE(pfd->cid.FD, pdev);
637     }
638     stream_puts(s, ">>\n");
639     pdf_end_separate(pdev);
640     pfd->common.object->written = true;
641     {	const cos_object_t *pco = (const cos_object_t *)pdf_get_FontFile_object(pfd->base_font);
642 	if (pco != NULL) {
643 	    code = COS_WRITE_OBJECT(pco, pdev);
644 	    if (code < 0)
645 		return code;
646 	}
647     }
648     return 0;
649 }
650 
651 /*
652  * Release a FontDescriptor components.
653  */
654 int
pdf_release_FontDescriptor_components(gx_device_pdf * pdev,pdf_font_descriptor_t * pfd)655 pdf_release_FontDescriptor_components(gx_device_pdf *pdev, pdf_font_descriptor_t *pfd)
656 {
657     gs_free_object(pdev->pdf_memory, pfd->base_font, "pdf_release_FontDescriptor_components");
658     pfd->base_font = NULL;
659     /* fixme: underimplemented. */
660     return 0;
661 }
662