1
/* Copyright (C) 2001-2012 Artifex Software, Inc.
4
This software is provided AS-IS with no warranty, either express or
7
This software is distributed under license and may not be copied,
8
modified or distributed except as expressly authorized under the terms
9
of the license contained in the file LICENSE in this distribution.
11
Refer to licensing information at http://www.artifex.com or contact
12
Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael,
13
CA 94903, U.S.A., +1(415)492-9861, for further information.
17
/* Composite and CID-based text processing for pdfwrite. */
35
/* ---------------- Non-CMap-based composite font ---------------- */
38
* Process a text string in a composite font with FMapType != 9 (CMap).
41
process_composite_text(gs_text_enum_t *pte, void *vbuf, uint bsize)
43
byte *const buf = vbuf;
44
pdf_text_enum_t *const penum = (pdf_text_enum_t *)pte;
47
pdf_text_process_state_t text_state;
48
pdf_text_enum_t curr, prev, out;
50
const gs_matrix *psmat = 0;
51
gs_font *prev_font = 0;
52
gs_char chr, char_code = 0x0badf00d, space_char = GS_NO_CHAR;
54
bool return_width = (penum->text.operation & TEXT_RETURN_WIDTH);
58
code = gx_path_current_point(penum->path, &penum->origin);
62
if (pte->text.operation &
63
(TEXT_FROM_ANY - (TEXT_FROM_STRING | TEXT_FROM_BYTES))
65
return_error(gs_error_rangecheck);
66
if (pte->text.operation & TEXT_INTERVENE) {
67
/* Not implemented. (PostScript doesn't even allow this case.) */
68
return_error(gs_error_rangecheck);
70
total_width.x = total_width.y = 0;
75
/* Scan runs of characters in the same leaf font. */
78
gs_font *new_font = 0;
80
gs_text_enum_copy_dynamic((gs_text_enum_t *)&out,
81
(gs_text_enum_t *)&curr, false);
85
gs_text_enum_copy_dynamic((gs_text_enum_t *)&prev,
86
(gs_text_enum_t *)&curr, false);
87
font_code = pte->orig_font->procs.next_char_glyph
88
((gs_text_enum_t *)&curr, &chr, &glyph);
90
* We check for a font change by comparing the current
91
* font, rather than testing the return code, because
92
* it makes the control structure a little simpler.
95
case 0: /* no font change */
96
case 1: /* font change */
97
curr.returned.current_char = chr;
98
char_code = gx_current_char((gs_text_enum_t *)&curr);
99
new_font = curr.fstack.items[curr.fstack.depth].font;
100
if (new_font != prev_font)
102
if (chr != (byte)chr) /* probably can't happen */
103
return_error(gs_error_rangecheck);
104
if (buf_index >= bsize)
105
return_error(gs_error_unregistered); /* Must not happen. */
106
buf[buf_index] = (byte)chr;
108
prev_font = new_font;
109
psmat = &curr.fstack.items[curr.fstack.depth - 1].font->FontMatrix;
110
if ((pte->text.operation & TEXT_ADD_TO_SPACE_WIDTH) &&
111
pte->text.space.s_char == char_code)
114
case 2: /* end of string */
121
str.size = buf_index;
123
/* buf_index == 0 is only possible the very first time. */
125
* The FontMatrix of leaf descendant fonts is not updated
126
* by scalefont. Compute the effective FontMatrix now.
130
/* set up the base font : */
131
out.fstack.depth = 0;
132
out.fstack.items[out.fstack.depth].font = out.current_font = prev_font;
133
pte->current_font = prev_font;
135
/* Provide the decoded space character : */
136
out.text.space.s_char = space_char;
138
gs_matrix_multiply(&prev_font->FontMatrix, psmat, &fmat);
139
out.index = 0; /* Note : we don't reset out.xy_index here. */
140
code = pdf_process_string_aux(&out, &str, NULL, &fmat, &text_state);
143
curr.xy_index = out.xy_index; /* pdf_encode_process_string advanced it. */
144
if (out.index < str.size) {
147
/* Advance *pte exactly for out.index chars,
148
because above we stored bytes into buf. */
150
pte->orig_font->procs.next_char_glyph(pte, &chr, &glyph);
151
font_code = 2; /* force exiting the loop */
153
/* advance *pte past the current substring */
154
gs_text_enum_copy_dynamic(pte, (gs_text_enum_t *)&prev, true);
156
pte->xy_index = out.xy_index;
158
/* This is silly, but its a consequence of the way pdf_process_string
159
* works. When we have TEXT_DO_NONE (stringwidth) we add the width of the
160
* glyph(s) to the enumerator 'returned.total_width' so we keep track
161
* of the total width as we go. However when we are returning the width
162
* but its NOT for a stringwidth, we set the enumerator 'retuerned'
163
* value to just the width of the glyph(s) processed. So when we are *not*
164
* handling a stringwidth we need to keep track of the total width
165
* ourselves. I'd have preferred to alter pdf_process_string, but that
166
* is used in many other places, and those places rely on this behaviour.
168
if (pte->text.operation & TEXT_DO_NONE) {
169
pte->returned.total_width.x = total_width.x = out.returned.total_width.x;
170
pte->returned.total_width.y = total_width.y = out.returned.total_width.y;
172
pte->returned.total_width.x = total_width.x +=
173
out.returned.total_width.x;
174
pte->returned.total_width.y = total_width.y +=
175
out.returned.total_width.y;
178
pdf_text_release_cgp(penum);
184
space_char = ((pte->text.operation & TEXT_ADD_TO_SPACE_WIDTH) &&
185
pte->text.space.s_char == char_code ? chr : ~0);
186
psmat = &curr.fstack.items[curr.fstack.depth - 1].font->FontMatrix;
187
prev_font = new_font;
191
return pdf_shift_text_currentpoint(penum, &total_width);
194
/* ---------------- CMap-based composite font ---------------- */
197
* Process a text string in a composite font with FMapType == 9 (CMap).
199
static const char *const standard_cmap_names[] = {
200
/* The following were added in PDF 1.5. */
202
"UniGB-UTF16-H", "UniGB-UTF16-V",
204
"GBKp-EUC-H", "GBKp-EUC-V",
205
"HKscs-B5-H", "HKscs-B5-V",
206
"UniCNS-UTF16-H", "UniCNS-UTF16-V",
207
"UniJIS-UTF16-H", "UniJIS-UTF16-V",
208
"UniKS-UTF16-H", "UniKS-UTF16-V",
209
#define END_PDF15_CMAP_NAMES_INDEX 12
210
/* The following were added in PDF 1.4. */
211
"GBKp-EUC-H", "GBKp-EUC-V",
212
"GBK2K-H", "GBK2K-V",
213
"HKscs-B5-H", "HKscs-B5-V",
214
#define END_PDF14_CMAP_NAMES_INDEX 18
215
/* The following were added in PDF 1.3. */
218
"GBK-EUC-H", "GBK-EUC-V",
219
"UniGB-UCS2-H", "UniGB-UCS2-V",
221
"ETenms-B5-H", "ETenms-B5-V",
223
"UniCNS-UCS2-H", "UniCNS-UCS2-V",
225
"90msp-RKSJ-H", "90msp-RKSJ-V",
227
"UniJIS-UCS2-H", "UniJIS-UCS2-V",
228
"UniJIS-UCS2-HW-H", "UniJIS-UCS2-HW-V",
230
"KSCms-UHC-HW-H", "KSCms-UHC-HW-V",
231
"UniKS-UCS2-H", "UniKS-UCS2-V",
233
#define END_PDF13_CMAP_NAMES_INDEX 39
234
/* The following were added in PDF 1.2. */
236
"GB-EUC-H", "GB-EUC-V",
240
"ETen-B5-H", "ETen-B5-V",
241
"CNS-EUC-H", "CNS-EUC-V",
244
"90ms-RKSJ-H", "90ms-RKSJ-V",
246
"Add-RKSJ-H", "Add-RKSJ-V",
247
"Ext-RKSJ-H", "Ext-RKSJ-V",
250
"KSC-EUC-H", "KSC-EUC-V",
251
"KSCms-UHC-H", "KSCms-UHC-V",
254
"Identity-H", "Identity-V",
260
attach_cmap_resource(gx_device_pdf *pdev, pdf_font_resource_t *pdfont,
261
const gs_cmap_t *pcmap, int font_index_only)
263
const char *const *pcmn =
264
standard_cmap_names +
265
(pdev->CompatibilityLevel < 1.3 ? END_PDF13_CMAP_NAMES_INDEX :
266
pdev->CompatibilityLevel < 1.4 ? END_PDF14_CMAP_NAMES_INDEX :
267
pdev->CompatibilityLevel < 1.5 ? END_PDF15_CMAP_NAMES_INDEX : 0);
268
bool is_identity = false;
269
pdf_resource_t *pcmres = 0; /* CMap */
272
/* Make sure cmap names is properly initialised. Silences Coverity warning */
274
return_error(gs_error_unknownerror);
277
* If the CMap isn't standard, write it out if necessary.
279
for (; *pcmn != 0; ++pcmn)
280
if (pcmap->CMapName.size == strlen(*pcmn) &&
281
!memcmp(*pcmn, pcmap->CMapName.data, pcmap->CMapName.size))
285
* PScript5.dll Version 5.2 creates identity CMaps with
286
* instandard name. Check this specially here
287
* and later replace with a standard name.
288
* This is a temporary fix for SF bug #615994 "CMAP is corrupt".
290
is_identity = gs_cmap_is_identity(pcmap, font_index_only);
292
if (*pcmn == 0 && !is_identity) { /* not standard */
293
pcmres = pdf_find_resource_by_gs_id(pdev, resourceCMap, pcmap->id + font_index_only);
295
/* Create and write the CMap object. */
296
code = pdf_cmap_alloc(pdev, pcmap, &pcmres, font_index_only);
301
if (pcmap->from_Unicode) {
302
gs_cmap_ranges_enum_t renum;
304
gs_cmap_ranges_enum_init(pcmap, &renum);
305
if (gs_cmap_enum_next_range(&renum) == 0 && renum.range.size == 2 &&
306
gs_cmap_enum_next_range(&renum) == 1) {
308
* Exactly one code space range, of size 2. Add an identity
311
if (!pdev->Identity_ToUnicode_CMaps[pcmap->WMode]) {
312
/* Create and write an identity ToUnicode CMap now. */
315
code = gs_cmap_create_char_identity(&pidcmap, 2, pcmap->WMode,
319
pidcmap->CMapType = 2; /* per PDF Reference */
320
pidcmap->ToUnicode = true;
321
code = pdf_cmap_alloc(pdev, pidcmap,
322
&pdev->Identity_ToUnicode_CMaps[pcmap->WMode], -1);
326
pdfont->res_ToUnicode = pdev->Identity_ToUnicode_CMaps[pcmap->WMode];
329
if (pcmres || is_identity) {
330
uint size = pcmap->CMapName.size;
331
byte *chars = gs_alloc_string(pdev->pdf_memory, size,
332
"pdf_font_resource_t(CMapName)");
335
return_error(gs_error_VMerror);
336
memcpy(chars, pcmap->CMapName.data, size);
338
strcpy(pdfont->u.type0.Encoding_name,
339
(pcmap->WMode ? "/Identity-V" : "/Identity-H"));
341
sprintf(pdfont->u.type0.Encoding_name, "%ld 0 R",
342
pdf_resource_id(pcmres));
343
pdfont->u.type0.CMapName.data = chars;
344
pdfont->u.type0.CMapName.size = size;
347
/* Should not be possible, if *pcmn is NULL then either
348
* is_identity is true or we create pcmres.
350
return_error(gs_error_invalidfont);
352
sprintf(pdfont->u.type0.Encoding_name, "/%s", *pcmn);
353
pdfont->u.type0.CMapName.data = (const byte *)*pcmn;
354
pdfont->u.type0.CMapName.size = strlen(*pcmn);
355
pdfont->u.type0.cmap_is_standard = true;
357
pdfont->u.type0.WMode = pcmap->WMode;
361
/* Record widths and CID => GID mappings. */
363
scan_cmap_text(pdf_text_enum_t *pte, void *vbuf)
365
gx_device_pdf *pdev = (gx_device_pdf *)pte->dev;
366
/* gs_font_type0 *const font = (gs_font_type0 *)pte->current_font;*/ /* Type 0, fmap_CMap */
367
gs_font_type0 *const font = (gs_font_type0 *)pte->orig_font; /* Type 0, fmap_CMap */
368
/* Not sure. Changed for CDevProc callout. Was pte->current_font */
369
gs_text_enum_t scan = *(gs_text_enum_t *)pte;
370
int wmode = font->WMode, code, rcode = 0;
371
pdf_font_resource_t *pdsubf0 = NULL;
372
gs_font *subfont0 = NULL, *saved_subfont = NULL;
373
uint index = scan.index, xy_index = scan.xy_index, start_index = index;
374
uint font_index0 = 0x7badf00d;
376
pdf_char_glyph_pairs_t p;
377
gs_glyph *type1_glyphs = (gs_glyph *)vbuf;
378
int num_type1_glyphs = 0;
381
p.num_unused_chars = 1;
383
pte->returned.total_width.x = pte->returned.total_width.y = 0;;
385
uint break_index, break_xy_index;
386
uint font_index = 0x7badf00d;
388
pdf_text_process_state_t text_state;
389
pdf_font_resource_t *pdsubf;
390
gs_font *subfont = NULL;
392
bool font_change = 0;
394
code = gx_path_current_point(pte->path, &pte->origin);
400
pdf_font_descriptor_t *pfd;
402
double *real_widths, *w, *v, *w0;
403
int char_cache_size, width_cache_size;
406
break_index = scan.index;
407
break_xy_index = scan.xy_index;
408
code = font->procs.next_char_glyph(&scan, &chr, &glyph);
409
if (code == 2) { /* end of string */
415
subfont = scan.fstack.items[scan.fstack.depth].font;
416
font_index = scan.fstack.items[scan.fstack.depth - 1].index;
418
if (glyph == GS_NO_GLYPH)
419
glyph = GS_MIN_CID_GLYPH;
420
cid = glyph - GS_MIN_CID_GLYPH;
421
switch (subfont->FontType) {
424
if (glyph == GS_MIN_CID_GLYPH) {
425
glyph = subfont->procs.encode_char(subfont, chr, GLYPH_SPACE_NAME);
427
type1_glyphs[num_type1_glyphs] = glyph;
431
case ft_CID_encrypted:
432
case ft_CID_TrueType: {
433
p.s[0].glyph = glyph;
435
code = pdf_obtain_cidfont_resource(pdev, subfont, &pdsubf, &p);
440
case ft_user_defined: {
445
pte->current_font = subfont;
446
code = pdf_obtain_font_resource(pte, &str1, &pdsubf);
449
cid = pdf_find_glyph(pdsubf, glyph);
450
if (cid == GS_NO_CHAR) {
451
code = pdf_make_font3_resource(pdev, subfont, &pdsubf);
454
code = pdf_attach_font_resource(pdev, subfont, pdsubf);
462
/* An unsupported case, fall back to default implementation. */
463
return_error(gs_error_rangecheck);
465
code = pdf_attached_font_resource(pdev, (gs_font *)subfont, &pdsubf,
466
&glyph_usage, &real_widths, &char_cache_size, &width_cache_size);
469
if (break_index > start_index && pdev->charproc_just_accumulated)
471
if (subfont->FontType == ft_user_defined &&
472
(break_index > start_index || !pdev->charproc_just_accumulated) &&
473
!(pdsubf->u.simple.s.type3.cached[cid >> 3] & (0x80 >> (cid & 7)))) {
474
pte->current_font = subfont;
475
return gs_error_undefined;
477
if (subfont->FontType == ft_encrypted || subfont->FontType == ft_encrypted2) {
478
font_change = (subfont != subfont0 && subfont0 != NULL);
480
saved_subfont = subfont;
485
font_change = (pdsubf != pdsubf0 && pdsubf0 != NULL);
488
font_index0 = font_index;
491
if (subfont->FontType != ft_encrypted && subfont->FontType != ft_encrypted2) {
492
pfd = pdsubf->FontDescriptor;
493
code = pdf_resize_resource_arrays(pdev, pdsubf, cid + 1);
496
if (subfont->FontType == ft_CID_encrypted || subfont->FontType == ft_CID_TrueType) {
497
if (cid >=width_cache_size) {
498
/* fixme: we add the CID=0 glyph as CID=cid glyph to the output font.
499
Really it must not add and leave the CID undefined. */
500
cid = 0; /* notdef. */
503
if (cid >= char_cache_size || cid >= width_cache_size)
504
return_error(gs_error_unregistered); /* Must not happen */
505
if (pdsubf->FontType == ft_user_defined || pdsubf->FontType == ft_encrypted ||
506
pdsubf->FontType == ft_encrypted2) {
508
pdf_font_resource_t *pdfont;
509
bool notdef_subst = false;
511
code = pdf_obtain_cidfont_widths_arrays(pdev, pdsubf, wmode, &w, &w0, &v);
514
code = pdf_obtain_parent_type0_font_resource(pdev, pdsubf, font_index,
515
&font->data.CMap->CMapName, &pdfont);
518
if (pdf_is_CID_font(subfont)) {
519
if (subfont->procs.decode_glyph((gs_font *)subfont, glyph, -1) != GS_NO_CHAR) {
520
/* Since PScript5.dll creates GlyphNames2Unicode with character codes
521
instead CIDs, and with the WinCharSetFFFF-H2 CMap
522
character codes appears different than CIDs (Bug 687954),
523
pass the character code intead the CID. */
524
code = pdf_add_ToUnicode(pdev, subfont, pdfont,
525
chr + GS_MIN_CID_GLYPH, chr, NULL);
527
/* If we interpret a PDF document, ToUnicode
528
CMap may be attached to the Type 0 font. */
529
code = pdf_add_ToUnicode(pdev, pte->orig_font, pdfont,
530
chr + GS_MIN_CID_GLYPH, chr, NULL);
533
code = pdf_add_ToUnicode(pdev, subfont, pdfont, glyph, cid, NULL);
536
/* We can't check pdsubf->used[cid >> 3] here,
537
because it mixed data for different values of WMode.
538
Perhaps pdf_font_used_glyph returns fast with reused glyphs.
540
code = pdf_font_used_glyph(pfd, glyph, (gs_font_base *)subfont);
541
if (code == gs_error_rangecheck) {
542
if (!(pdsubf->used[cid >> 3] & (0x80 >> (cid & 7)))) {
543
char buf[gs_font_name_max + 1];
544
int l = min(sizeof(buf) - 1, subfont->font_name.size);
546
memcpy(buf, subfont->font_name.chars, l);
548
emprintf3(pdev->memory,
549
"Missing glyph CID=%d, glyph=%04x in the font %s . The output PDF may fail with some viewers.\n",
551
(unsigned int)(glyph - GS_MIN_CID_GLYPH),
553
pdsubf->used[cid >> 3] |= 0x80 >> (cid & 7);
555
cid = 0, code = 1; /* undefined glyph. */
557
/* If this is the first use of CID=0, get its width */
558
if (pdsubf->Widths[cid] == 0) {
559
pdf_glyph_widths_t widths;
561
code = pdf_glyph_widths(pdsubf, wmode, glyph, (gs_font *)subfont, &widths,
562
pte->cdevproc_callout ? pte->cdevproc_result : NULL);
566
if ((code == 0 /* just copied */ || pdsubf->Widths[cid] == 0) && !notdef_subst) {
567
pdf_glyph_widths_t widths;
569
code = pdf_glyph_widths(pdsubf, wmode, glyph, (gs_font *)subfont, &widths,
570
pte->cdevproc_callout ? pte->cdevproc_result : NULL);
573
if (code == TEXT_PROCESS_CDEVPROC) {
574
pte->returned.current_glyph = glyph;
575
pte->current_font = subfont;
576
rcode = TEXT_PROCESS_CDEVPROC;
580
if (cid > pdsubf->count)
581
return_error(gs_error_unregistered); /* Must not happen. */
582
w[cid] = widths.Width.w;
584
v[cid * 2 + 0] = widths.Width.v.x;
585
v[cid * 2 + 1] = widths.Width.v.y;
587
real_widths[cid] = widths.real_width.w;
590
/* Since AR5 use W or DW to compute the x-coordinate of
591
v-vector, comupte and store the glyph width for WMode 0. */
592
/* fixme : skip computing real_width here. */
593
code = pdf_glyph_widths(pdsubf, 0, glyph, (gs_font *)subfont, &widths,
594
pte->cdevproc_callout ? pte->cdevproc_result : NULL);
597
w0[cid] = widths.Width.w;
599
if (pdsubf->u.cidfont.CIDToGIDMap != 0) {
600
gs_font_cid2 *subfont2 = (gs_font_cid2 *)subfont;
602
pdsubf->u.cidfont.CIDToGIDMap[cid] =
603
subfont2->cidata.CIDMap_proc(subfont2, glyph);
607
pdsubf->u.cidfont.used2[cid >> 3] |= 0x80 >> (cid & 7);
609
pdsubf->used[cid >> 3] |= 0x80 >> (cid & 7);
611
if (pte->cdevproc_callout) {
612
/* Only handle a single character because its width is stored
613
into pte->cdevproc_result, and process_text_modify_width neds it.
614
fixme: next time take from w, v, real_widths. */
615
break_index = scan.index;
616
break_xy_index = scan.xy_index;
619
} while (!font_change);
620
if (break_index > index) {
621
pdf_font_resource_t *pdfont;
623
int xy_index_step = (!(pte->text.operation & TEXT_REPLACE_WIDTHS) ? 0 :
624
pte->text.x_widths == pte->text.y_widths ? 2 : 1);
625
gs_text_params_t save_text;
627
if (!subfont && num_type1_glyphs != 0)
629
if (subfont && (subfont->FontType == ft_encrypted || subfont->FontType == ft_encrypted2)) {
630
int save_op = pte->text.operation;
631
gs_font *save_font = pte->current_font;
632
const gs_glyph *save_data = pte->text.data.glyphs;
634
pte->current_font = subfont;
635
pte->text.operation |= TEXT_FROM_GLYPHS;
636
pte->text.data.glyphs = type1_glyphs;
637
str.data = ((const byte *)vbuf) + ((pte->text.size - pte->index) * sizeof(gs_glyph));
638
str.size = num_type1_glyphs;
639
code = pdf_obtain_font_resource_unencoded(pte, (const gs_string *)&str, &pdsubf0,
642
/* Replace the modified values, fall back to default implementation
643
* (type 3 bitmap image font)
645
pte->current_font = save_font;
646
pte->text.operation |= save_op;
647
pte->text.data.glyphs = save_data;
650
memcpy((void *)scan.text.data.bytes, (void *)str.data, str.size);
651
str.data = scan.text.data.bytes;
653
pte->text.operation = save_op;
655
pte->current_font = subfont0;
656
if (!subfont0 || !pdsubf0)
657
/* This should be impossible */
658
return_error(gs_error_invalidfont);
660
code = gs_matrix_multiply(&subfont0->FontMatrix, &font->FontMatrix, &m3);
661
/* We thought that it should be gs_matrix_multiply(&font->FontMatrix, &subfont0->FontMatrix, &m3); */
664
if (pdsubf0->FontType == ft_user_defined || pdsubf->FontType == ft_encrypted ||
665
pdsubf->FontType == ft_encrypted2)
668
code = pdf_obtain_parent_type0_font_resource(pdev, pdsubf0, font_index0,
669
&font->data.CMap->CMapName, &pdfont);
672
if (!pdfont->u.type0.Encoding_name[0]) {
674
* If pdfont->u.type0.Encoding_name is set,
675
* a CMap resource is already attached.
676
* See attach_cmap_resource.
678
code = attach_cmap_resource(pdev, pdfont, font->data.CMap, font_index0);
683
pdf_set_text_wmode(pdev, font->WMode);
684
code = pdf_update_text_state(&text_state, (pdf_text_enum_t *)pte, pdfont, &m3);
687
/* process_text_modify_width breaks text parameters.
688
We would like to improve it someday.
689
Now save them locally and restore after the call. */
690
save_text = pte->text;
691
if (subfont && (subfont->FontType != ft_encrypted &&
692
subfont->FontType != ft_encrypted2)) {
693
/* If we are a type 1 descendant, we already sorted this out above */
694
str.data = scan.text.data.bytes + index;
695
str.size = break_index - index;
697
if (pte->text.operation & TEXT_REPLACE_WIDTHS) {
698
if (pte->text.x_widths != NULL)
699
pte->text.x_widths += xy_index * xy_index_step;
700
if (pte->text.y_widths != NULL)
701
pte->text.y_widths += xy_index * xy_index_step;
704
if (subfont && (subfont->FontType == ft_encrypted ||
705
subfont->FontType == ft_encrypted2)) {
706
gs_font *f = pte->orig_font;
708
adjust_first_last_char(pdfont, (byte *)str.data, str.size);
710
/* Make sure we use the descendant font, not the original type 0 ! */
711
pte->orig_font = subfont;
712
code = process_text_modify_width((pdf_text_enum_t *)pte,
713
(gs_font *)subfont, &text_state, &str, &wxy, type1_glyphs, false);
717
type1_glyphs[0] = type1_glyphs[num_type1_glyphs];
718
num_type1_glyphs = 1;
719
subfont = saved_subfont;
721
num_type1_glyphs = 0;
725
code = process_text_modify_width((pdf_text_enum_t *)pte, (gs_font *)font,
726
&text_state, &str, &wxy, NULL, true);
728
if (pte->text.operation & TEXT_REPLACE_WIDTHS) {
729
if (pte->text.x_widths != NULL)
730
pte->text.x_widths -= xy_index * xy_index_step;
731
if (pte->text.y_widths != NULL)
732
pte->text.y_widths -= xy_index * xy_index_step;
734
pte->text = save_text;
735
pte->cdevproc_callout = false;
738
pte->xy_index = xy_index;
741
pte->index = break_index;
742
pte->xy_index = break_xy_index;
743
code = pdf_shift_text_currentpoint(pte, &wxy);
747
pdf_text_release_cgp(pte);
749
xy_index = break_xy_index;
750
if (done || rcode != 0)
753
font_index0 = font_index;
757
pte->xy_index = xy_index;
762
process_cmap_text(gs_text_enum_t *penum, void *vbuf, uint bsize)
765
pdf_text_enum_t *pte = (pdf_text_enum_t *)penum;
767
if (pte->text.operation &
768
(TEXT_FROM_ANY - (TEXT_FROM_STRING | TEXT_FROM_BYTES))
770
return_error(gs_error_rangecheck);
771
if (pte->text.operation & TEXT_INTERVENE) {
772
/* Not implemented. (PostScript doesn't allow TEXT_INTERVENE.) */
773
return_error(gs_error_rangecheck);
775
code = scan_cmap_text(pte, vbuf);
776
if (code == TEXT_PROCESS_CDEVPROC)
777
pte->cdevproc_callout = true;
779
pte->cdevproc_callout = false;
783
/* ---------------- CIDFont ---------------- */
786
* Process a text string in a CIDFont. (Only glyphshow is supported.)
789
process_cid_text(gs_text_enum_t *pte, void *vbuf, uint bsize)
791
pdf_text_enum_t *penum = (pdf_text_enum_t *)pte;
792
uint operation = pte->text.operation;
794
gs_font *scaled_font = pte->current_font; /* CIDFont */
795
gs_font *font; /* unscaled font (CIDFont) */
796
const gs_glyph *glyphs;
797
gs_matrix scale_matrix;
798
pdf_font_resource_t *pdsubf; /* CIDFont */
799
gs_font_type0 *font0 = NULL;
803
if (operation & TEXT_FROM_GLYPHS) {
804
glyphs = pte->text.data.glyphs;
805
size = pte->text.size - pte->index;
806
} else if (operation & TEXT_FROM_SINGLE_GLYPH) {
807
glyphs = &pte->text.data.d_glyph;
809
} else if (operation & TEXT_FROM_STRING) {
810
glyphs = &pte->outer_CID;
813
return_error(gs_error_rangecheck);
816
* PDF doesn't support glyphshow directly: we need to create a Type 0
817
* font with an Identity CMap. Make sure all the glyph numbers fit
818
* into 16 bits. (Eventually we should support wider glyphs too,
819
* but this would require a different CMap.)
821
if (bsize < size * 2)
822
return_error(gs_error_unregistered); /* Must not happen. */
827
for (i = 0; i < size; ++i) {
828
ulong gnum = glyphs[i] - GS_MIN_CID_GLYPH;
831
return_error(gs_error_rangecheck);
832
*pchars++ = (byte)(gnum >> 8);
833
*pchars++ = (byte)gnum;
837
/* Find the original (unscaled) version of this font. */
839
for (font = scaled_font; font->base != font; )
841
/* Compute the scaling matrix. */
842
gs_matrix_invert(&font->FontMatrix, &scale_matrix);
843
gs_matrix_multiply(&scale_matrix, &scaled_font->FontMatrix, &scale_matrix);
845
/* Find or create the CIDFont resource. */
847
code = pdf_obtain_font_resource(penum, NULL, &pdsubf);
851
/* Create the CMap and Type 0 font if they don't exist already. */
853
if (pdsubf->u.cidfont.glyphshow_font_id != 0)
854
font0 = (gs_font_type0 *)gs_find_font_by_id(font->dir,
855
pdsubf->u.cidfont.glyphshow_font_id, &scaled_font->FontMatrix);
857
code = gs_font_type0_from_cidfont(&font0, font, font->WMode,
858
&scale_matrix, font->memory);
861
pdsubf->u.cidfont.glyphshow_font_id = font0->id;
864
/* Now handle the glyphshow as a show in the Type 0 font. */
867
pte->current_font = pte->orig_font = (gs_font *)font0;
868
/* Patch the operation temporarily for init_fstack. */
869
pte->text.operation = (operation & ~TEXT_FROM_ANY) | TEXT_FROM_BYTES;
870
/* Patch the data for process_cmap_text. */
871
pte->text.data.bytes = vbuf;
872
pte->text.size = size * 2;
874
gs_type0_init_fstack(pte, pte->current_font);
875
code = process_cmap_text(pte, vbuf, bsize);
876
pte->current_font = scaled_font;
877
pte->orig_font = save.orig_font;
878
pte->text = save.text;
879
pte->index = save.index + pte->index / 2;
880
pte->fstack = save.fstack;