/src/ghostpdl/devices/vector/gdevpdte.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2001-2022 Artifex Software, Inc. |
2 | | All Rights Reserved. |
3 | | |
4 | | This software is provided AS-IS with no warranty, either express or |
5 | | implied. |
6 | | |
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. |
10 | | |
11 | | Refer to licensing information at http://www.artifex.com or contact |
12 | | Artifex Software, Inc., 1305 Grant Avenue - Suite 200, Novato, |
13 | | CA 94945, U.S.A., +1(415)492-9861, for further information. |
14 | | */ |
15 | | |
16 | | |
17 | | /* Encoding-based (Type 1/2/42) text processing for pdfwrite. */ |
18 | | |
19 | | #include "math_.h" |
20 | | #include "memory_.h" |
21 | | #include "gx.h" |
22 | | #include "gserrors.h" |
23 | | #include "gsutil.h" |
24 | | #include "gxfcmap.h" |
25 | | #include "gxfcopy.h" |
26 | | #include "gxfont.h" |
27 | | #include "gxfont0.h" |
28 | | #include "gxfont0c.h" |
29 | | #include "gxpath.h" /* for getting current point */ |
30 | | #include "gxchar.h" /* for gx_compute_text_oversampling & gx_lookup_cached_char */ |
31 | | #include "gxfcache.h" /* for gx_lookup_fm_pair */ |
32 | | #include "gdevpsf.h" |
33 | | #include "gdevpdfx.h" |
34 | | #include "gdevpdfg.h" |
35 | | #include "gdevpdfo.h" |
36 | | #include "gdevpdtx.h" |
37 | | #include "gdevpdtd.h" |
38 | | #include "gdevpdtf.h" |
39 | | #include "gdevpdts.h" |
40 | | #include "gdevpdtt.h" |
41 | | |
42 | | #include "gximage.h" |
43 | | #include "gxcpath.h" |
44 | | |
45 | | #include "gsfcmap.h" |
46 | | #include "tessocr.h" |
47 | | |
48 | | static int pdf_char_widths(gx_device_pdf *const pdev, |
49 | | pdf_font_resource_t *pdfont, int ch, |
50 | | gs_font_base *font, |
51 | | pdf_glyph_widths_t *pwidths /* may be NULL */); |
52 | | static int pdf_process_string(pdf_text_enum_t *penum, gs_string *pstr, |
53 | | const gs_matrix *pfmat, |
54 | | pdf_text_process_state_t *ppts, |
55 | | const gs_glyph *gdata); |
56 | | |
57 | | /* |
58 | | * Process a string with a simple gs_font. |
59 | | */ |
60 | | int |
61 | | pdf_process_string_aux(pdf_text_enum_t *penum, gs_string *pstr, |
62 | | const gs_glyph *gdata, const gs_matrix *pfmat, |
63 | | pdf_text_process_state_t *ppts) |
64 | 1.49M | { |
65 | 1.49M | gs_font_base *font = (gs_font_base *)penum->current_font; |
66 | | |
67 | 1.49M | switch (font->FontType) { |
68 | 268k | case ft_TrueType: |
69 | 1.30M | case ft_encrypted: |
70 | 1.49M | case ft_encrypted2: |
71 | 1.49M | case ft_user_defined: |
72 | 1.49M | case ft_PDF_user_defined: |
73 | 1.49M | case ft_PCL_user_defined: |
74 | 1.49M | case ft_GL2_stick_user_defined: |
75 | 1.49M | case ft_GL2_531: |
76 | 1.49M | case ft_MicroType: |
77 | 1.49M | break; |
78 | 0 | default: |
79 | 0 | return_error(gs_error_rangecheck); |
80 | 1.49M | } |
81 | 1.49M | return pdf_process_string(penum, pstr, pfmat, ppts, gdata); |
82 | 1.49M | } |
83 | | |
84 | | static int OCRText(gx_device_pdf *pdev, gs_glyph glyph, gs_char ch, gs_char *length, byte **unicode) |
85 | 0 | { |
86 | | #if OCR_VERSION > 0 |
87 | | int code = 0; |
88 | | |
89 | | if(pdev->OCRStage == OCR_Rendered) { |
90 | | int llx, lly, urx, ury, char_count = 0, returned_count = 0, *returned; |
91 | | ocr_glyph_t *next_glyph = pdev->ocr_glyphs; |
92 | | int rows, stride, row, column; |
93 | | byte *bitmap = NULL, *src, *dest, *rowptr, srcmask, destmask; |
94 | | void *state; |
95 | | const char *language = pdev->ocr_language; |
96 | | gp_file *DbgFile; |
97 | | |
98 | | if(language == NULL || language[0] == 0) |
99 | | language = "eng"; |
100 | | |
101 | | /* We should alredy have rendered a bitmap for all the glyphs in the |
102 | | * text operation, so this shuld be redundant, but best to be safe. |
103 | | */ |
104 | | if(next_glyph == NULL) |
105 | | return_error(gs_error_unknownerror); |
106 | | |
107 | | /* Identify the bounding box of the returned glyphs by examing the bounds and position |
108 | | * of each glyph. At the same time count the number of expected returned characters. |
109 | | * We treat any empty bitmap (all 0x00 bytes) as a space because, obviously, the |
110 | | * OCR engine can't tell differentiate between a space character and no character at all. |
111 | | */ |
112 | | llx = next_glyph->x; |
113 | | lly = next_glyph->y; |
114 | | urx = llx + next_glyph->width; |
115 | | ury = lly + next_glyph->height; |
116 | | if(next_glyph != NULL && !next_glyph->is_space) |
117 | | char_count++; |
118 | | next_glyph = (ocr_glyph_t *)next_glyph->next; |
119 | | while(next_glyph) { |
120 | | if(!next_glyph->is_space) |
121 | | char_count++; |
122 | | if(next_glyph->x < llx) |
123 | | llx = next_glyph->x; |
124 | | if(next_glyph->y < lly) |
125 | | lly = next_glyph->y; |
126 | | if(next_glyph->x + next_glyph->width > urx) |
127 | | urx = next_glyph->x + next_glyph->width; |
128 | | if(next_glyph->y + next_glyph->height > ury) |
129 | | ury = next_glyph->y + next_glyph->height; |
130 | | next_glyph = next_glyph->next; |
131 | | } |
132 | | |
133 | | /* Allocate and initialise the 'strip' bitmap which will receive all the |
134 | | * individual glyph bitmaps. |
135 | | */ |
136 | | rows = ury - lly; |
137 | | stride = (((urx - llx) + 7) / 8) + 1; |
138 | | bitmap = gs_alloc_bytes(pdev->memory, rows * stride, "working OCR memory"); |
139 | | if(bitmap == NULL) |
140 | | return_error(gs_error_VMerror); |
141 | | memset(bitmap, 0x00, rows * stride); |
142 | | |
143 | | /* Allocate a buffer for the OCR engine to return the Unicode code points. This needs work, |
144 | | * we might want more information returned (bounding boxes and confidence levels) and we |
145 | | * need to think about the possibility that the OCR engine finds more character than we |
146 | | * expected (eg fi ligatures returned as 'f' and 'i'. |
147 | | */ |
148 | | returned = (int *)gs_alloc_bytes(pdev->memory, char_count * sizeof(int), "returned unicodes"); |
149 | | if(returned == NULL) { |
150 | | gs_free_object(pdev->memory, bitmap, "working OCR memory"); |
151 | | return_error(gs_error_VMerror); |
152 | | } |
153 | | memset(returned, 0x00, char_count * sizeof(int)); |
154 | | |
155 | | /* Now copy each glyph bitmap to the correct position in the strip. This is complicated |
156 | | * by the fact that bitmaps are monochrome pcaked into bytes and so the destination |
157 | | * may not be aligned on a byte boundary. |
158 | | */ |
159 | | next_glyph = (ocr_glyph_t *)pdev->ocr_glyphs; |
160 | | while(next_glyph) { |
161 | | rowptr = bitmap + ((next_glyph->y - lly) * stride) + (int)floor((next_glyph->x - llx) / 8); |
162 | | for(row = 0;row < next_glyph->height;row++) { |
163 | | dest = rowptr + row * stride; |
164 | | src = next_glyph->data + (row * next_glyph->raster); |
165 | | destmask = 0x80 >> (next_glyph->x - llx) % 8; |
166 | | srcmask = 0x80; |
167 | | for(column = 0; column < next_glyph->width;column++) { |
168 | | if(*src & srcmask) { |
169 | | *dest = *dest | destmask; |
170 | | } |
171 | | srcmask = srcmask >> 1; |
172 | | if(srcmask == 0) { |
173 | | srcmask = 0x80; |
174 | | src++; |
175 | | } |
176 | | destmask = destmask >> 1; |
177 | | if(destmask == 0) { |
178 | | destmask = 0x80; |
179 | | dest++; |
180 | | } |
181 | | } |
182 | | } |
183 | | next_glyph = next_glyph->next; |
184 | | } |
185 | | |
186 | | #if 0 |
187 | | DbgFile = gp_fopen(pdev->memory, "d:/temp/bits.txt", "wb+"); |
188 | | for(row = 0;row < rows;row++) { |
189 | | for(column = 0;column < stride;column++) { |
190 | | dest = bitmap + (row * stride); |
191 | | gp_fprintf(DbgFile, "%02x", dest[column]); |
192 | | } |
193 | | gp_fprintf(DbgFile, "\n"); |
194 | | } |
195 | | gp_fclose(DbgFile); |
196 | | #endif |
197 | | /* Initialise the OCR engine */ |
198 | | code = ocr_init_api(pdev->memory->non_gc_memory, language, |
199 | | pdev->ocr_engine, &state); |
200 | | if(code < 0) { |
201 | | gs_free_object(pdev->memory, bitmap, "working OCR memory"); |
202 | | gs_free_object(pdev->memory, returned, "returned unicodes"); |
203 | | return 0; |
204 | | } |
205 | | returned_count = char_count; |
206 | | |
207 | | /* Pass our strip to the OCR engine */ |
208 | | code = ocr_bitmap_to_unicodes(state, |
209 | | bitmap, 0, stride * 8, rows, stride, |
210 | | (int)pdev->HWResolution[0], |
211 | | (int)pdev->HWResolution[1], |
212 | | returned, &returned_count); |
213 | | |
214 | | /* and close the engine back down again */ |
215 | | ocr_fin_api(pdev->memory->non_gc_memory, state); |
216 | | gs_free_object(pdev->memory, bitmap, "working OCR memory"); |
217 | | |
218 | | if(code < 0) { |
219 | | pdev->OCRStage = OCR_Failed; |
220 | | gs_free_object(pdev->memory, returned, "returned unicodes"); |
221 | | return code; |
222 | | } |
223 | | |
224 | | /* Future enhancement we should fall back to trying the individual bitmap here */ |
225 | | if(returned_count != char_count) { |
226 | | pdev->OCRStage = OCR_Failed; |
227 | | gs_free_object(pdev->memory, returned, "returned unicodes"); |
228 | | return 0; |
229 | | } |
230 | | pdev->OCRUnicode = returned; |
231 | | |
232 | | /* Actually perform OCR on the stored bitmaps */ |
233 | | pdev->OCRStage = OCR_UnicodeAvailable; |
234 | | } |
235 | | |
236 | | if(pdev->OCRStage == OCR_UnicodeAvailable) { |
237 | | /* We've OCR'ed the bitmaps already, find the unicode value */ |
238 | | ocr_glyph_t *new_glyph = (ocr_glyph_t *)pdev->ocr_glyphs; |
239 | | int ocr_index = 0; |
240 | | uint mask = 0xFF; |
241 | | int ix; |
242 | | char *u; |
243 | | |
244 | | /* Find the bitmap which matches the character/glyph we are processing */ |
245 | | while(new_glyph) { |
246 | | if(new_glyph->char_code == ch || new_glyph->glyph == glyph) { |
247 | | ocr_glyph_t *g1 = pdev->ocr_glyphs; |
248 | | |
249 | | /* Spaces are handled specially, so just jump out now */ |
250 | | if(new_glyph->is_space) |
251 | | break; |
252 | | |
253 | | /* Otherwise, find all the bitmaps which lie to the left of the |
254 | | * one we found (we are assuming for now that the returned |
255 | | * Unicode values are left to right) |
256 | | */ |
257 | | while(g1) { |
258 | | if(!g1->is_space) { |
259 | | if(g1->x < new_glyph->x) |
260 | | ocr_index++; |
261 | | } |
262 | | g1 = g1->next; |
263 | | } |
264 | | break; |
265 | | } |
266 | | new_glyph = new_glyph->next; |
267 | | } |
268 | | |
269 | | /* If we found a matching bitmap, get the corresponding unicode code point from |
270 | | * the stored values returned by the OCR engine. |
271 | | */ |
272 | | if(new_glyph) { |
273 | | *unicode = (byte *)gs_alloc_bytes(pdev->memory, 2 * sizeof(ushort), "temporary Unicode array"); |
274 | | if(*unicode == NULL) |
275 | | return_error(gs_error_VMerror); |
276 | | u = (char *)(*unicode); |
277 | | if(new_glyph->is_space) { |
278 | | memset(u, 0x00, 3); |
279 | | u[3] = 0x20; |
280 | | } |
281 | | else { |
282 | | for(ix = 0;ix < 4;ix++) { |
283 | | u[3 - ix] = (pdev->OCRUnicode[ocr_index] & mask) >> (8 * ix); |
284 | | mask = mask << 8; |
285 | | } |
286 | | } |
287 | | *length = 4; |
288 | | } |
289 | | } |
290 | | #endif |
291 | 0 | return 0; |
292 | 0 | } |
293 | | |
294 | | /* |
295 | | * Add char code pair to ToUnicode CMap, |
296 | | * creating the CMap on neccessity. |
297 | | */ |
298 | | int |
299 | | pdf_add_ToUnicode(gx_device_pdf *pdev, gs_font *font, pdf_font_resource_t *pdfont, |
300 | | gs_glyph glyph, gs_char ch, const gs_const_string *gnstr) |
301 | 320k | { int code = 0; |
302 | 320k | gs_char length = 0; |
303 | 320k | ushort *unicode = 0; |
304 | | |
305 | 320k | if (glyph == GS_NO_GLYPH) |
306 | 0 | return 0; |
307 | 320k | if(pdev->UseOCR == UseOCRAlways) { |
308 | 0 | code = OCRText(pdev, glyph, ch, &length, (byte **)&unicode); |
309 | 0 | if(code < 0) |
310 | 0 | return code; |
311 | 0 | } |
312 | 320k | else { |
313 | 320k | length = font->procs.decode_glyph((gs_font *)font, glyph, ch, NULL, 0); |
314 | 320k | if(length == 0 || length == GS_NO_CHAR) { |
315 | 281k | if(gnstr != NULL && gnstr->size == 7) { |
316 | 4.09k | if(!memcmp(gnstr->data, "uni", 3)) { |
317 | 47 | static const char *hexdigits = "0123456789ABCDEF"; |
318 | 47 | char *d0 = strchr(hexdigits, gnstr->data[3]); |
319 | 47 | char *d1 = strchr(hexdigits, gnstr->data[4]); |
320 | 47 | char *d2 = strchr(hexdigits, gnstr->data[5]); |
321 | 47 | char *d3 = strchr(hexdigits, gnstr->data[6]); |
322 | | |
323 | 47 | unicode = (ushort *)gs_alloc_bytes(pdev->memory, sizeof(ushort), "temporary Unicode array"); |
324 | 47 | if(d0 != NULL && d1 != NULL && d2 != NULL && d3 != NULL) { |
325 | 47 | char *u = (char *)unicode; |
326 | 47 | u[0] = ((d0 - hexdigits) << 4) + ((d1 - hexdigits)); |
327 | 47 | u[1] = ((d2 - hexdigits) << 4) + ((d3 - hexdigits)); |
328 | 47 | length = 2; |
329 | 47 | } |
330 | 47 | } |
331 | 4.09k | } |
332 | 277k | else { |
333 | 277k | if(pdev->UseOCR != UseOCRNever) { |
334 | 0 | code = OCRText(pdev, glyph, ch, &length, (byte **)&unicode); |
335 | 0 | if(code < 0) |
336 | 0 | return code; |
337 | 0 | } |
338 | 277k | } |
339 | 281k | } |
340 | 320k | } |
341 | | |
342 | 320k | if (length != 0 && length != GS_NO_CHAR) { |
343 | 38.6k | if (pdfont->cmap_ToUnicode == NULL) { |
344 | | /* ToUnicode CMaps are always encoded with two byte keys. See |
345 | | * Technical Note 5411, 'ToUnicode Mapping File Tutorial' |
346 | | * page 3. |
347 | | */ |
348 | | /* Unfortunately, the above is not true. See the PDF Reference (version 1.7 |
349 | | * p 472 'ToUnicode CMaps'. Even that documentation is incorrect as it |
350 | | * describes codespaceranges, in fact for Acrobat this is irrelevant, |
351 | | * but the bfranges must be one byte for simple fonts. By altering the |
352 | | * key size for CID fonts we can write both consistently correct. |
353 | | */ |
354 | 964 | uint num_codes = 256, key_size = 1; |
355 | | |
356 | 964 | if (font->FontType == ft_CID_encrypted) { |
357 | 0 | gs_font_cid0 *pfcid = (gs_font_cid0 *)font; |
358 | |
|
359 | 0 | num_codes = pfcid->cidata.common.CIDCount; |
360 | 0 | key_size = 2; |
361 | 964 | } else if (font->FontType == ft_CID_TrueType || font->FontType == ft_composite) { |
362 | 126 | key_size = 2; |
363 | | /* Since PScript5.dll creates GlyphNames2Unicode with character codes |
364 | | instead CIDs, and with the WinCharSetFFFF-H2 CMap |
365 | | character codes appears from the range 0-0xFFFF (Bug 687954), |
366 | | we must use the maximal character code value for the ToUnicode |
367 | | code count. */ |
368 | 126 | num_codes = 65536; |
369 | 126 | } |
370 | 964 | code = gs_cmap_ToUnicode_alloc(pdev->pdf_memory, pdfont->rid, num_codes, key_size, length, |
371 | 964 | &pdfont->cmap_ToUnicode); |
372 | 964 | if (code < 0) { |
373 | 0 | if (unicode) |
374 | 0 | gs_free_object(pdev->memory, unicode, "temporary Unicode array"); |
375 | 0 | return code; |
376 | 0 | } |
377 | 37.7k | } else { |
378 | 37.7k | if (((gs_cmap_ToUnicode_t *)pdfont->cmap_ToUnicode)->value_size < length){ |
379 | 7 | gs_cmap_ToUnicode_realloc(pdev->pdf_memory, length, &pdfont->cmap_ToUnicode); |
380 | 7 | } |
381 | 37.7k | } |
382 | | |
383 | 38.6k | if (!unicode) { |
384 | 38.6k | unicode = (ushort *)gs_alloc_bytes(pdev->memory, length * sizeof(short), "temporary Unicode array"); |
385 | 38.6k | if (unicode == NULL) |
386 | 0 | return_error(gs_error_VMerror); |
387 | 38.6k | length = font->procs.decode_glyph((gs_font *)font, glyph, ch, unicode, length); |
388 | 38.6k | } |
389 | | |
390 | 38.6k | if (pdfont->cmap_ToUnicode != NULL) |
391 | 38.6k | gs_cmap_ToUnicode_add_pair(pdfont->cmap_ToUnicode, ch, unicode, length); |
392 | 38.6k | if (length > 2 && pdfont->u.simple.Encoding != NULL) |
393 | 33 | pdfont->TwoByteToUnicode = 0; |
394 | 38.6k | } |
395 | | |
396 | 320k | if (unicode) |
397 | 38.6k | gs_free_object(pdev->memory, unicode, "temporary Unicode array"); |
398 | 320k | return 0; |
399 | 320k | } |
400 | | |
401 | | typedef struct { |
402 | | gx_device_pdf *pdev; |
403 | | pdf_resource_type_t rtype; |
404 | | } pdf_resource_enum_data_t; |
405 | | |
406 | | static int |
407 | | process_resources2(void *client_data, const byte *key_data, uint key_size, const cos_value_t *v) |
408 | 0 | { |
409 | 0 | pdf_resource_enum_data_t *data = (pdf_resource_enum_data_t *)client_data; |
410 | 0 | pdf_resource_t *pres = pdf_find_resource_by_resource_id(data->pdev, data->rtype, v->contents.object->id); |
411 | |
|
412 | 0 | if (pres == NULL) |
413 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
414 | 0 | pres->where_used |= data->pdev->used_mask; |
415 | 0 | return 0; |
416 | 0 | } |
417 | | |
418 | | static int |
419 | | process_resources1(void *client_data, const byte *key_data, uint key_size, const cos_value_t *v) |
420 | 0 | { |
421 | 0 | pdf_resource_enum_data_t *data = (pdf_resource_enum_data_t *)client_data; |
422 | 0 | static const char *rn[] = {PDF_RESOURCE_TYPE_NAMES}; |
423 | 0 | int i; |
424 | |
|
425 | 0 | for (i = 0; i < count_of(rn); i++) { |
426 | 0 | if (rn[i] != NULL && !bytes_compare((const byte *)rn[i], strlen(rn[i]), key_data, key_size)) |
427 | 0 | break; |
428 | 0 | } |
429 | 0 | if (i >= count_of(rn)) |
430 | 0 | return 0; |
431 | 0 | data->rtype = i; |
432 | 0 | return cos_dict_forall((cos_dict_t *)v->contents.object, data, process_resources2); |
433 | 0 | } |
434 | | |
435 | | /* |
436 | | * Register charproc fonts with the page or substream. |
437 | | */ |
438 | | int |
439 | | pdf_used_charproc_resources(gx_device_pdf *pdev, pdf_font_resource_t *pdfont) |
440 | 114k | { |
441 | 114k | if (pdfont->where_used & pdev->used_mask) |
442 | 110k | return 0; |
443 | 3.70k | pdfont->where_used |= pdev->used_mask; |
444 | 3.70k | if (pdev->CompatibilityLevel >= 1.2) |
445 | 3.70k | return 0; |
446 | 0 | if (pdfont->FontType == ft_user_defined || |
447 | 0 | pdfont->FontType == ft_PDF_user_defined || |
448 | 0 | pdfont->FontType == ft_PCL_user_defined || |
449 | 0 | pdfont->FontType == ft_MicroType || |
450 | 0 | pdfont->FontType == ft_GL2_stick_user_defined || |
451 | 0 | pdfont->FontType == ft_GL2_531) { |
452 | 0 | pdf_resource_enum_data_t data; |
453 | |
|
454 | 0 | data.pdev = pdev; |
455 | 0 | return cos_dict_forall(pdfont->u.simple.s.type3.Resources, &data, process_resources1); |
456 | 0 | } |
457 | 0 | return 0; |
458 | 0 | } |
459 | | |
460 | | /* |
461 | | * Given a text string and a simple gs_font, return a font resource suitable |
462 | | * for the text string, possibly re-encoding the string. This |
463 | | * may involve creating a font resource and/or adding glyphs and/or Encoding |
464 | | * entries to it. |
465 | | * |
466 | | * Sets *ppdfont. |
467 | | */ |
468 | | static int |
469 | | pdf_encode_string_element(gx_device_pdf *pdev, gs_font *font, pdf_font_resource_t *pdfont, |
470 | | gs_char ch, const gs_glyph *gdata) |
471 | 5.97M | { |
472 | 5.97M | gs_font_base *cfont, *ccfont; |
473 | 5.97M | int code; |
474 | 5.97M | gs_glyph copied_glyph; |
475 | 5.97M | gs_const_string gnstr; |
476 | 5.97M | pdf_encoding_element_t *pet; |
477 | 5.97M | gs_glyph glyph; |
478 | | |
479 | | /* |
480 | | * In contradiction with pre-7.20 versions of pdfwrite, |
481 | | * we never re-encode texts due to possible encoding conflict while font merging. |
482 | | */ |
483 | 5.97M | cfont = pdf_font_resource_font(pdfont, false); |
484 | 5.97M | ccfont = pdf_font_resource_font(pdfont, true); |
485 | 5.97M | pet = &pdfont->u.simple.Encoding[ch]; |
486 | 5.97M | glyph = (gdata == NULL ? font->procs.encode_char(font, ch, GLYPH_SPACE_NAME) |
487 | 5.97M | : *gdata); |
488 | 5.97M | if (glyph == GS_NO_GLYPH || glyph == pet->glyph) { |
489 | 5.68M | if((pdfont->cmap_ToUnicode == NULL || !gs_cmap_ToUnicode_check_pair(pdfont->cmap_ToUnicode, ch)) && pdev->UseOCR != UseOCRNever) |
490 | 0 | (void)pdf_add_ToUnicode(pdev, font, pdfont, glyph, ch, NULL); |
491 | 5.68M | return 0; |
492 | 5.68M | } |
493 | 294k | if (pet->glyph != GS_NO_GLYPH) { /* encoding conflict */ |
494 | 0 | return_error(gs_error_rangecheck); |
495 | | /* Must not happen because pdf_obtain_font_resource |
496 | | * checks for encoding compatibility. |
497 | | */ |
498 | 0 | } |
499 | 294k | code = font->procs.glyph_name(font, glyph, &gnstr); |
500 | 294k | if (code < 0) |
501 | 0 | return code; /* can't get name of glyph */ |
502 | 294k | if (font->FontType != ft_user_defined && |
503 | 294k | font->FontType != ft_PDF_user_defined && |
504 | 294k | font->FontType != ft_PCL_user_defined && |
505 | 294k | font->FontType != ft_MicroType && |
506 | 294k | font->FontType != ft_GL2_stick_user_defined && |
507 | 294k | font->FontType != ft_GL2_531) { |
508 | | /* The standard 14 fonts don't have a FontDescriptor. */ |
509 | 292k | code = (pdfont->base_font != 0 ? |
510 | 34.9k | pdf_base_font_copy_glyph(pdfont->base_font, glyph, (gs_font_base *)font) : |
511 | 292k | pdf_font_used_glyph(pdfont->FontDescriptor, glyph, (gs_font_base *)font)); |
512 | 292k | if (code < 0 && code != gs_error_undefined) |
513 | 260 | return code; |
514 | 292k | if (code == gs_error_undefined) { |
515 | 2.08k | if (pdev->PDFA != 0 || pdev->PDFX) { |
516 | 0 | switch (pdev->PDFACompatibilityPolicy) { |
517 | 0 | case 0: |
518 | 0 | emprintf(pdev->memory, |
519 | 0 | "Requested glyph not present in source font,\n not permitted in PDF/A, reverting to normal PDF output\n"); |
520 | 0 | pdev->AbortPDFAX = true; |
521 | 0 | pdev->PDFA = 0; |
522 | 0 | break; |
523 | 0 | case 1: |
524 | 0 | emprintf(pdev->memory, |
525 | 0 | "Requested glyph not present in source font,\n not permitted in PDF/A, glyph will not be present in output file\n\n"); |
526 | | /* Returning an error causees text processing to try and |
527 | | * handle the glyph by rendering to a bitmap instead of |
528 | | * as a glyph in a font. This will eliminate the problem |
529 | | * and the fiel should appear the same as the original. |
530 | | */ |
531 | 0 | return_error(gs_error_unknownerror); |
532 | 0 | break; |
533 | 0 | case 2: |
534 | 0 | emprintf(pdev->memory, |
535 | 0 | "Requested glyph not present in source font,\n not permitted in PDF/A, aborting conversion\n"); |
536 | | /* Careful here, only certain errors will bubble up |
537 | | * through the text processing. |
538 | | */ |
539 | 0 | return_error(gs_error_invalidfont); |
540 | 0 | break; |
541 | 0 | default: |
542 | 0 | emprintf(pdev->memory, |
543 | 0 | "Requested glyph not present in source font,\n not permitted in PDF/A, unrecognised PDFACompatibilityLevel,\nreverting to normal PDF output\n"); |
544 | 0 | pdev->AbortPDFAX = true; |
545 | 0 | pdev->PDFA = 0; |
546 | 0 | break; |
547 | 0 | } |
548 | 0 | } |
549 | | /* PS font has no such glyph. */ |
550 | 2.08k | if (bytes_compare(gnstr.data, gnstr.size, (const byte *)".notdef", 7)) { |
551 | 2.08k | pet->glyph = glyph; |
552 | 2.08k | pdf_copy_string_to_encoding(pdev, &gnstr, pet); |
553 | 2.08k | pet->is_difference = true; |
554 | 2.08k | } |
555 | 290k | } else if (pdfont->base_font == NULL && ccfont != NULL && |
556 | 290k | (gs_copy_glyph_options(font, glyph, (gs_font *)ccfont, COPY_GLYPH_NO_NEW) != 1 || |
557 | 253k | gs_copied_font_add_encoding((gs_font *)ccfont, ch, glyph) < 0)) { |
558 | | /* |
559 | | * The "complete" copy of the font appears incomplete |
560 | | * due to incrementally added glyphs. Drop the "complete" |
561 | | * copy now and continue with subset font only. |
562 | | * |
563 | | * Note that we need to add the glyph to the encoding of the |
564 | | * "complete" font, because "PPI-ProPag 2.6.1.4 (archivePg)" |
565 | | * creates multiple font copies with reduced encodings |
566 | | * (we believe it is poorly designed), |
567 | | * and we can merge the copies back to a single font (see Bug 686875). |
568 | | * We also check whether the encoding is compatible. |
569 | | * It must be compatible here due to the pdf_obtain_font_resource |
570 | | * and ccfont logics, but we want to ensure for safety reason. |
571 | | */ |
572 | 116 | ccfont = NULL; |
573 | 116 | pdf_font_descriptor_drop_complete_font(pdfont->FontDescriptor); |
574 | 116 | } |
575 | | /* |
576 | | * We arbitrarily allow the first encoded character in a given |
577 | | * position to determine the encoding associated with the copied |
578 | | * font. |
579 | | */ |
580 | 292k | copied_glyph = cfont->procs.encode_char((gs_font *)cfont, ch, |
581 | 292k | GLYPH_SPACE_NAME); |
582 | 292k | if (glyph != copied_glyph && |
583 | 292k | gs_copied_font_add_encoding((gs_font *)cfont, ch, glyph) < 0 |
584 | 292k | ) |
585 | 2.08k | pet->is_difference = true; |
586 | 292k | pdfont->used[ch >> 3] |= 0x80 >> (ch & 7); |
587 | 292k | } |
588 | | /* |
589 | | * We always generate ToUnicode for simple fonts, because |
590 | | * we can't detemine in advance, which glyphs the font actually uses. |
591 | | * The decision about writing it out is deferred until pdf_write_font_resource. |
592 | | */ |
593 | 294k | code = pdf_add_ToUnicode(pdev, font, pdfont, glyph, ch, &gnstr); |
594 | 294k | if(code < 0) |
595 | 0 | return code; |
596 | 294k | pet->glyph = glyph; |
597 | 294k | return pdf_copy_string_to_encoding(pdev, &gnstr, pet); |
598 | 294k | } |
599 | | |
600 | | /* |
601 | | * Estimate text bbox. |
602 | | */ |
603 | | static int |
604 | | process_text_estimate_bbox(pdf_text_enum_t *pte, gs_font_base *font, |
605 | | const gs_const_string *pstr, |
606 | | const gs_matrix *pfmat, |
607 | | gs_rect *text_bbox, gs_point *pdpt) |
608 | 1.32M | { |
609 | 1.32M | int i; |
610 | 1.32M | int space_char = |
611 | 1.32M | (pte->text.operation & TEXT_ADD_TO_SPACE_WIDTH ? |
612 | 1.02M | pte->text.space.s_char : -1); |
613 | 1.32M | int WMode = font->WMode; |
614 | 1.32M | int code = 0; |
615 | 1.32M | gs_point total = {0, 0}; |
616 | 1.32M | gs_point p0, p1, p2, p3; |
617 | 1.32M | gs_fixed_point origin; |
618 | 1.32M | gs_matrix m; |
619 | 1.32M | int xy_index = pte->xy_index, info_flags = 0; |
620 | 1.32M | gx_path *path = gs_text_enum_path(pte); |
621 | | |
622 | 1.32M | code = gx_path_current_point(path, &origin); |
623 | 1.32M | if (code < 0) |
624 | 0 | return code; |
625 | 1.32M | m = ctm_only(pte->pgs); |
626 | 1.32M | m.tx = fixed2float(origin.x); |
627 | 1.32M | m.ty = fixed2float(origin.y); |
628 | 1.32M | gs_matrix_multiply(pfmat, &m, &m); |
629 | | |
630 | | /* If the FontBBox is all 0, then its clearly wrong, so determine the text width |
631 | | * accurately by processing the glyph program. |
632 | | */ |
633 | 1.32M | if (font->FontBBox.p.x == font->FontBBox.q.x || |
634 | 1.32M | font->FontBBox.p.y == font->FontBBox.q.y) { |
635 | 17.0k | info_flags = GLYPH_INFO_BBOX | GLYPH_INFO_WIDTH0 << WMode; |
636 | 1.30M | } else { |
637 | 1.30M | double width, height; |
638 | | |
639 | | /* This is a heuristic for Bug #700124. We try to determine whether a given glyph |
640 | | * is used in a string by using the current point, glyph width and advance width |
641 | | * to see if the glyph is fully clipped out, if it is we don't include it in the |
642 | | * output, or in subset fonts. |
643 | | * |
644 | | * Previously we used the FontBBox to determine a quick glyph width, but |
645 | | * in bug #699454 and bug #699571 we saw that OneVision EPSExport could construct |
646 | | * fonts with a wildly incorrect BBox ([0 0 2 1]) and then draw the text without |
647 | | * an advance width, leading us to conclude the glyph was clipped out and eliding it. |
648 | | * |
649 | | * To solve this we added code to process the glyph program and extract an accurate |
650 | | * width of the glyph. However, this proved slow. So here we attempt to decide if |
651 | | * the FontBBox is sensible by applying the FontMatrix to it, and looking to see |
652 | | * if that results in a reasonable number of co-ordinates in font space. If it |
653 | | * does then we use the FontBBox for speed, otherwise we carefully process the |
654 | | * glyphs in the font and extract their accurate widths. |
655 | | */ |
656 | 1.30M | gs_point_transform(font->FontBBox.p.x, font->FontBBox.p.y, &font->FontMatrix, &p0); |
657 | 1.30M | gs_point_transform(font->FontBBox.p.x, font->FontBBox.q.y, &font->FontMatrix, &p1); |
658 | 1.30M | gs_point_transform(font->FontBBox.q.x, font->FontBBox.p.y, &font->FontMatrix, &p2); |
659 | 1.30M | gs_point_transform(font->FontBBox.q.x, font->FontBBox.q.y, &font->FontMatrix, &p3); |
660 | 1.30M | width = max(fabs(p2.x), fabs(p3.x)) - p0.x; |
661 | 1.30M | height = max(fabs(p1.y), fabs(p3.y)) - p0.y; |
662 | | |
663 | | /* Yes, this is a magic number. There's no reasoning here, its just a guess, we may |
664 | | * need to adjust this in future. Or possibly do away with it altogether if it proves |
665 | | * unreliable. |
666 | | */ |
667 | 1.30M | if (fabs(width) < 0.1 || fabs(height) < 0.1) { |
668 | 2.22k | info_flags = GLYPH_INFO_BBOX | GLYPH_INFO_WIDTH0 << WMode; |
669 | 1.30M | } else { |
670 | 1.30M | gs_point_transform(font->FontBBox.p.x, font->FontBBox.p.y, &m, &p0); |
671 | 1.30M | gs_point_transform(font->FontBBox.p.x, font->FontBBox.q.y, &m, &p1); |
672 | 1.30M | gs_point_transform(font->FontBBox.q.x, font->FontBBox.p.y, &m, &p2); |
673 | 1.30M | gs_point_transform(font->FontBBox.q.x, font->FontBBox.q.y, &m, &p3); |
674 | 1.30M | info_flags = GLYPH_INFO_WIDTH0 << WMode; |
675 | 1.30M | } |
676 | 1.30M | } |
677 | | |
678 | 6.94M | for (i = 0; i < pstr->size; ++i) { |
679 | 5.72M | byte c = pstr->data[i]; |
680 | 5.72M | gs_rect bbox; |
681 | 5.72M | gs_point wanted, tpt; |
682 | 5.72M | gs_glyph glyph = font->procs.encode_char((gs_font *)font, c, |
683 | 5.72M | GLYPH_SPACE_NAME); |
684 | 5.72M | gs_glyph_info_t info; |
685 | 5.72M | int code; |
686 | | |
687 | 5.72M | if (glyph == GS_NO_GLYPH) |
688 | 8 | return_error (gs_error_invalidfont); |
689 | | |
690 | 5.72M | memset(&info, 0x00, sizeof(gs_glyph_info_t)); |
691 | 5.72M | code = font->procs.glyph_info((gs_font *)font, glyph, NULL, |
692 | 5.72M | info_flags, |
693 | 5.72M | &info); |
694 | | |
695 | | /* If we got an undefined error, and its a type 1/CFF font, try to |
696 | | * find the /.notdef glyph and use its width instead (as this is the |
697 | | * glyph which will be rendered). We don't do this for other font types |
698 | | * as it seems Acrobat/Distiller may not do so either. |
699 | | */ |
700 | | /* The GL/2 stick font does not supply the enumerate_glyphs method, |
701 | | * *and* leaves it uninitialised. But it should not be possible to |
702 | | * get an undefiend error with this font anyway. |
703 | | */ |
704 | 5.72M | if (code < 0) { |
705 | 101k | if ((font->FontType == ft_encrypted || |
706 | 101k | font->FontType == ft_encrypted2)) { |
707 | 95.3k | int index; |
708 | | |
709 | 95.3k | for (index = 0; |
710 | 95.3k | (font->procs.enumerate_glyph((gs_font *)font, &index, |
711 | 95.3k | (GLYPH_SPACE_NAME), &glyph)) >= 0 && |
712 | 95.3k | index != 0;) { |
713 | | |
714 | 95.3k | if (gs_font_glyph_is_notdef(font, glyph)) { |
715 | 12 | code = font->procs.glyph_info((gs_font *)font, glyph, NULL, |
716 | 12 | info_flags, |
717 | 12 | &info); |
718 | | |
719 | 12 | if (code < 0) |
720 | 0 | return code; |
721 | 12 | } |
722 | 95.3k | break; |
723 | 95.3k | } |
724 | 95.3k | } |
725 | 101k | if (code < 0) |
726 | 101k | return code; |
727 | 101k | } |
728 | 5.62M | if (pte->text.operation & TEXT_REPLACE_WIDTHS) { |
729 | 3.44M | code = gs_text_replaced_width(&pte->text, xy_index++, &tpt); |
730 | 3.44M | if (code < 0) |
731 | 0 | return code; |
732 | | |
733 | 3.44M | gs_distance_transform(tpt.x, tpt.y, &ctm_only(pte->pgs), &wanted); |
734 | 3.44M | } else { |
735 | 2.17M | gs_distance_transform(info.width[WMode].x, |
736 | 2.17M | info.width[WMode].y, |
737 | 2.17M | &m, &wanted); |
738 | 2.17M | if (pte->text.operation & TEXT_ADD_TO_ALL_WIDTHS) { |
739 | 352k | gs_distance_transform(pte->text.delta_all.x, |
740 | 352k | pte->text.delta_all.y, |
741 | 352k | &ctm_only(pte->pgs), &tpt); |
742 | 352k | wanted.x += tpt.x; |
743 | 352k | wanted.y += tpt.y; |
744 | 352k | } |
745 | 2.17M | if (pstr->data[i] == space_char && pte->text.operation & TEXT_ADD_TO_SPACE_WIDTH) { |
746 | 9.62k | gs_distance_transform(pte->text.delta_space.x, |
747 | 9.62k | pte->text.delta_space.y, |
748 | 9.62k | &ctm_only(pte->pgs), &tpt); |
749 | 9.62k | wanted.x += tpt.x; |
750 | 9.62k | wanted.y += tpt.y; |
751 | 9.62k | } |
752 | 2.17M | } |
753 | | |
754 | 5.62M | if (info_flags & GLYPH_INFO_BBOX) { |
755 | 36.5k | gs_point_transform(info.bbox.p.x, info.bbox.p.x, &m, &p0); |
756 | 36.5k | gs_point_transform(info.bbox.p.x, info.bbox.q.y, &m, &p1); |
757 | 36.5k | gs_point_transform(info.bbox.q.x, info.bbox.p.y, &m, &p2); |
758 | 36.5k | gs_point_transform(info.bbox.q.x, info.bbox.q.y, &m, &p3); |
759 | 36.5k | } |
760 | | |
761 | 5.62M | bbox.p.x = min(min(p0.x, p1.x), min(p2.x, p3.x)); |
762 | 5.62M | bbox.p.y = min(min(p0.y, p1.y), min(p2.y, p3.y)); |
763 | 5.62M | bbox.q.x = max(max(p0.x, p1.x), max(p2.x, p3.x)); |
764 | 5.62M | bbox.q.y = max(max(p0.y, p1.y), max(p2.y, p3.y)); |
765 | | |
766 | 5.62M | bbox.q.x = bbox.p.x + max(bbox.q.x - bbox.p.x, wanted.x); |
767 | 5.62M | bbox.q.y = bbox.p.y + max(bbox.q.y - bbox.p.y, wanted.y); |
768 | 5.62M | bbox.p.x += total.x; |
769 | 5.62M | bbox.p.y += total.y; |
770 | 5.62M | bbox.q.x += total.x; |
771 | 5.62M | bbox.q.y += total.y; |
772 | | |
773 | 5.62M | total.x += wanted.x; |
774 | 5.62M | total.y += wanted.y; |
775 | | |
776 | 5.62M | if (i == 0) |
777 | 1.23M | *text_bbox = bbox; |
778 | 4.38M | else |
779 | 5.62M | rect_merge(*text_bbox, bbox); |
780 | 5.62M | } |
781 | 1.22M | *pdpt = total; |
782 | 1.22M | return 0; |
783 | 1.32M | } |
784 | | |
785 | | void |
786 | | adjust_first_last_char(pdf_font_resource_t *pdfont, byte *str, int size) |
787 | 1.32M | { |
788 | 1.32M | int i; |
789 | | |
790 | 7.26M | for (i = 0; i < size; ++i) { |
791 | 5.93M | int chr = str[i]; |
792 | | |
793 | 5.93M | if (chr < pdfont->u.simple.FirstChar) |
794 | 29.7k | pdfont->u.simple.FirstChar = chr; |
795 | 5.93M | if (chr > pdfont->u.simple.LastChar) |
796 | 70.3k | pdfont->u.simple.LastChar = chr; |
797 | 5.93M | } |
798 | 1.32M | } |
799 | | |
800 | | int |
801 | | pdf_shift_text_currentpoint(pdf_text_enum_t *penum, gs_point *wpt) |
802 | 1.34M | { |
803 | 1.34M | return gs_moveto_aux(penum->pgs, gx_current_path(penum->pgs), |
804 | 1.34M | fixed2float(penum->origin.x) + wpt->x, |
805 | 1.34M | fixed2float(penum->origin.y) + wpt->y); |
806 | 1.34M | } |
807 | | |
808 | | /* |
809 | | * Internal procedure to process a string in a non-composite font. |
810 | | * Doesn't use or set pte->{data,size,index}; may use/set pte->xy_index; |
811 | | * may set penum->returned.total_width. Sets ppts->values. |
812 | | * |
813 | | * Note that the caller is responsible for re-encoding the string, if |
814 | | * necessary; for adding Encoding entries in pdfont; and for copying any |
815 | | * necessary glyphs. penum->current_font provides the gs_font for getting |
816 | | * glyph metrics, but this font's Encoding is not used. |
817 | | */ |
818 | | static int process_text_return_width(const pdf_text_enum_t *pte, |
819 | | gs_font_base *font, |
820 | | pdf_text_process_state_t *ppts, |
821 | | const gs_const_string *pstr, const gs_glyph *gdata, |
822 | | gs_point *pdpt, int *accepted, gs_rect *bbox); |
823 | | static int |
824 | | pdf_process_string(pdf_text_enum_t *penum, gs_string *pstr, |
825 | | const gs_matrix *pfmat, |
826 | | pdf_text_process_state_t *ppts, const gs_glyph *gdata) |
827 | 1.49M | { |
828 | 1.49M | gx_device_pdf *const pdev = (gx_device_pdf *)penum->dev; |
829 | 1.49M | gs_font_base *font = (gs_font_base *)penum->current_font; |
830 | 1.49M | pdf_font_resource_t *pdfont; |
831 | 1.49M | gs_text_params_t *text = &penum->text; |
832 | 1.49M | int code = 0, mask; |
833 | 1.49M | gs_point width_pt; |
834 | 1.49M | int accepted; |
835 | 1.49M | gs_rect text_bbox = {{0, 0}, {0, 0}}, glyphs_bbox = {{10000,10000}, {0,0}}; |
836 | 1.49M | unsigned int operation = text->operation; |
837 | 1.49M | gx_path *path = gs_text_enum_path(penum); |
838 | | |
839 | 1.49M | code = pdf_obtain_font_resource(penum, pstr, &pdfont); |
840 | 1.49M | if (code < 0) |
841 | 165k | return code; |
842 | 1.33M | if (pfmat == 0) |
843 | 1.33M | pfmat = &font->FontMatrix; |
844 | 1.33M | if (text->operation & TEXT_RETURN_WIDTH) { |
845 | 1.33M | code = gx_path_current_point(path, &penum->origin); |
846 | 1.33M | if (code < 0) |
847 | 0 | return code; |
848 | 1.33M | } |
849 | 1.33M | if (text->size == 0) |
850 | 1.27k | return 0; |
851 | 1.33M | if (penum->pgs->text_rendering_mode != 3 && !(text->operation & TEXT_DO_NONE)) { |
852 | | /* |
853 | | * Acrobat Reader can't handle text with huge coordinates, |
854 | | * so don't emit the text if it is outside the clip bbox |
855 | | * (Note : it ever fails with type 3 fonts). |
856 | | */ |
857 | | |
858 | 1.32M | code = process_text_estimate_bbox(penum, font, (gs_const_string *)pstr, pfmat, |
859 | 1.32M | &text_bbox, &width_pt); |
860 | 1.32M | if (code == 0) { |
861 | 1.22M | gs_fixed_rect clip_bbox; |
862 | 1.22M | gs_rect rect; |
863 | | |
864 | 1.22M | if (penum->pcpath) { |
865 | 1.22M | gx_cpath_outer_box(penum->pcpath, &clip_bbox); |
866 | 1.22M | rect.p.x = fixed2float(clip_bbox.p.x); |
867 | 1.22M | rect.p.y = fixed2float(clip_bbox.p.y); |
868 | 1.22M | rect.q.x = fixed2float(clip_bbox.q.x); |
869 | 1.22M | rect.q.y = fixed2float(clip_bbox.q.y); |
870 | 1.22M | rect_intersect(rect, text_bbox); |
871 | 1.22M | if (rect.p.x > rect.q.x || rect.p.y > rect.q.y) { |
872 | 4.54k | penum->index += pstr->size; |
873 | 4.54k | text->operation &= ~TEXT_DO_DRAW; |
874 | 4.54k | } |
875 | 1.22M | } |
876 | 1.22M | } else { |
877 | 101k | gs_matrix m; |
878 | 101k | gs_fixed_point origin; |
879 | 101k | gs_point p0, p1, p2, p3; |
880 | | |
881 | 101k | code = gx_path_current_point(path, &origin); |
882 | 101k | if (code < 0) |
883 | 0 | goto done; |
884 | | |
885 | 101k | m = ctm_only(penum->pgs); |
886 | 101k | m.tx = fixed2float(origin.x); |
887 | 101k | m.ty = fixed2float(origin.y); |
888 | 101k | gs_matrix_multiply(pfmat, &m, &m); |
889 | | |
890 | 101k | if (font->FontBBox.p.x != font->FontBBox.q.x) { |
891 | 96.6k | text_bbox.p.x = font->FontBBox.p.x; |
892 | 96.6k | text_bbox.q.x = font->FontBBox.q.x; |
893 | 96.6k | } else { |
894 | 4.45k | text_bbox.p.x = 0; |
895 | 4.45k | text_bbox.q.x = 1000; |
896 | 4.45k | } |
897 | 101k | if (font->FontBBox.p.y != font->FontBBox.q.y) { |
898 | 96.6k | text_bbox.p.y = font->FontBBox.p.y; |
899 | 96.6k | text_bbox.q.y = font->FontBBox.q.y; |
900 | 96.6k | } else { |
901 | 4.45k | text_bbox.p.y = 0; |
902 | 4.45k | text_bbox.q.y = 1000; |
903 | 4.45k | } |
904 | 101k | gs_point_transform(text_bbox.p.x, text_bbox.p.y, &m, &p0); |
905 | 101k | gs_point_transform(text_bbox.p.x, text_bbox.q.y, &m, &p1); |
906 | 101k | gs_point_transform(text_bbox.q.x, text_bbox.p.y, &m, &p2); |
907 | 101k | gs_point_transform(text_bbox.q.x, text_bbox.q.y, &m, &p3); |
908 | 101k | text_bbox.p.x = min(min(p0.x, p1.x), min(p1.x, p2.x)); |
909 | 101k | text_bbox.p.y = min(min(p0.y, p1.y), min(p1.y, p2.y)); |
910 | 101k | text_bbox.q.x = max(max(p0.x, p1.x), max(p1.x, p2.x)); |
911 | 101k | text_bbox.q.y = max(max(p0.y, p1.y), max(p1.y, p2.y)); |
912 | 101k | } |
913 | 1.32M | } else { |
914 | | /* We have no penum->pcpath. */ |
915 | 5.41k | } |
916 | | |
917 | | /* |
918 | | * Note that pdf_update_text_state sets all the members of ppts->values |
919 | | * to their current values. |
920 | | */ |
921 | 1.33M | code = pdf_update_text_state(ppts, penum, pdfont, pfmat); |
922 | 1.33M | if (code > 0) { |
923 | | /* Try not to emulate ADD_TO_WIDTH if we don't have to. */ |
924 | 0 | if (code & TEXT_ADD_TO_SPACE_WIDTH) { |
925 | 0 | if (!memchr(pstr->data, penum->text.space.s_char, pstr->size)) |
926 | 0 | code &= ~TEXT_ADD_TO_SPACE_WIDTH; |
927 | 0 | } |
928 | 0 | } |
929 | 1.33M | if (code < 0) |
930 | 0 | goto done; |
931 | 1.33M | mask = code; |
932 | | |
933 | 1.33M | if (text->operation & TEXT_REPLACE_WIDTHS) |
934 | 1.07M | mask |= TEXT_REPLACE_WIDTHS; |
935 | | |
936 | | /* |
937 | | * The only operations left to handle are TEXT_DO_DRAW and |
938 | | * TEXT_RETURN_WIDTH. |
939 | | */ |
940 | 1.33M | if (mask == 0) { |
941 | | /* |
942 | | * If any character has real_width != Width, we have to process |
943 | | * the string character-by-character. process_text_return_width |
944 | | * will tell us what we need to know. |
945 | | */ |
946 | 259k | if (!(text->operation & (TEXT_DO_DRAW | TEXT_RETURN_WIDTH))) { |
947 | 0 | code = 0; |
948 | 0 | goto done; |
949 | 0 | } |
950 | 259k | code = process_text_return_width(penum, font, ppts, |
951 | 259k | (gs_const_string *)pstr, gdata, |
952 | 259k | &width_pt, &accepted, &glyphs_bbox); |
953 | 259k | if (code < 0) |
954 | 303 | goto done; |
955 | 258k | if (code == 0) { |
956 | | /* No characters with redefined widths -- the fast case. */ |
957 | 258k | if (text->operation & TEXT_DO_DRAW || penum->pgs->text_rendering_mode == 3) { |
958 | 256k | code = pdf_append_chars(pdev, pstr->data, accepted, |
959 | 256k | width_pt.x, width_pt.y, false); |
960 | 256k | if (code < 0) |
961 | 0 | goto done; |
962 | 256k | adjust_first_last_char(pdfont, pstr->data, accepted); |
963 | 256k | penum->index += accepted; |
964 | 256k | } else if (text->operation & TEXT_DO_NONE) |
965 | 3 | penum->index += accepted; |
966 | 258k | } else { |
967 | | /* Use the slow case. Set mask to any non-zero value. */ |
968 | 0 | mask = TEXT_RETURN_WIDTH; |
969 | 0 | } |
970 | 258k | } |
971 | 1.33M | if (mask) { |
972 | | /* process_text_modify_width destroys text parameters, save them now. */ |
973 | 1.07M | int index0 = penum->index, xy_index = penum->xy_index; |
974 | 1.07M | gs_text_params_t text = penum->text; |
975 | 1.07M | int xy_index_step = (!(penum->text.operation & TEXT_REPLACE_WIDTHS) ? 0 : |
976 | 1.07M | penum->text.x_widths == penum->text.y_widths ? 2 : 1); |
977 | | /* A glyphshow takes a shortcut by storing the single glyph directly into |
978 | | * penum->text.data.d_glyph. However, process_text_modify_width |
979 | | * replaces pte->text.data.bytes (these two are part of a union) with |
980 | | * pstr->data, which is not valid for a glyphshow because it alters |
981 | | * the glyph value store there. If we make a copy of the single glyph, |
982 | | * it all works correctly.then |
983 | | */ |
984 | 1.07M | gs_glyph gdata_i, *gdata_p = (gs_glyph *)gdata; |
985 | 1.07M | if (penum->text.operation & TEXT_FROM_SINGLE_GLYPH) { |
986 | 0 | gdata_i = *gdata; |
987 | 0 | gdata_p = &gdata_i; |
988 | 0 | } |
989 | | |
990 | 1.07M | if (penum->text.operation & TEXT_REPLACE_WIDTHS) { |
991 | 1.07M | if (penum->text.x_widths != NULL) |
992 | 1.07M | penum->text.x_widths += xy_index * xy_index_step; |
993 | 1.07M | if (penum->text.y_widths != NULL) |
994 | 1.07M | penum->text.y_widths += xy_index * xy_index_step; |
995 | 1.07M | } |
996 | 1.07M | penum->xy_index = 0; |
997 | 1.07M | code = process_text_modify_width(penum, (gs_font *)font, ppts, |
998 | 1.07M | (gs_const_string *)pstr, |
999 | 1.07M | &width_pt, (const gs_glyph *)gdata_p, false, 1); |
1000 | 1.07M | if (penum->text.operation & TEXT_REPLACE_WIDTHS) { |
1001 | 1.07M | if (penum->text.x_widths != NULL) |
1002 | 1.07M | penum->text.x_widths -= xy_index * xy_index_step; |
1003 | 1.07M | if (penum->text.y_widths != NULL) |
1004 | 1.07M | penum->text.y_widths -= xy_index * xy_index_step; |
1005 | 1.07M | } |
1006 | 1.07M | penum->xy_index += xy_index; |
1007 | 1.07M | adjust_first_last_char(pdfont, pstr->data, penum->index); |
1008 | 1.07M | penum->text = text; |
1009 | 1.07M | penum->index += index0; |
1010 | 1.07M | if (code < 0) |
1011 | 571 | goto done; |
1012 | 1.07M | } |
1013 | | |
1014 | | /* Finally, return the total width if requested. */ |
1015 | 1.32M | if (pdev->Eps2Write && penum->pcpath) { |
1016 | 495k | gx_device_clip cdev; |
1017 | 495k | gx_drawing_color devc; |
1018 | 495k | fixed x0, y0, bx2, by2; |
1019 | | |
1020 | 495k | if (glyphs_bbox.p.x != 10000 && glyphs_bbox.q.x != 0){ |
1021 | 0 | gs_matrix m; |
1022 | 0 | gs_fixed_point origin; |
1023 | 0 | gs_point p0, p1, p2, p3; |
1024 | |
|
1025 | 0 | code = gx_path_current_point(path, &origin); |
1026 | 0 | if (code < 0) |
1027 | 0 | return code; |
1028 | | |
1029 | 0 | m = ctm_only(penum->pgs); |
1030 | 0 | m.tx = fixed2float(origin.x); |
1031 | 0 | m.ty = fixed2float(origin.y); |
1032 | 0 | gs_matrix_multiply(pfmat, &m, &m); |
1033 | |
|
1034 | 0 | gs_point_transform(glyphs_bbox.p.x, glyphs_bbox.p.y, &m, &p0); |
1035 | 0 | gs_point_transform(glyphs_bbox.p.x, glyphs_bbox.q.y, &m, &p1); |
1036 | 0 | gs_point_transform(glyphs_bbox.q.x, glyphs_bbox.p.y, &m, &p2); |
1037 | 0 | gs_point_transform(glyphs_bbox.q.x, glyphs_bbox.q.y, &m, &p3); |
1038 | 0 | glyphs_bbox.p.x = min(min(p0.x, p1.x), min(p1.x, p2.x)); |
1039 | 0 | glyphs_bbox.p.y = min(min(p0.y, p1.y), min(p1.y, p2.y)); |
1040 | 0 | glyphs_bbox.q.x = max(max(p0.x, p1.x), max(p1.x, p2.x)); |
1041 | 0 | glyphs_bbox.q.y = max(max(p0.y, p1.y), max(p1.y, p2.y)); |
1042 | 0 | if (glyphs_bbox.p.y > text_bbox.p.y) |
1043 | 0 | text_bbox.p.y = glyphs_bbox.p.y; |
1044 | 0 | if (glyphs_bbox.q.y < text_bbox.q.y) |
1045 | 0 | text_bbox.q.y = glyphs_bbox.q.y; |
1046 | 0 | } |
1047 | | /* removed this section for bug #695671, where the rotated text |
1048 | | * doesn't contribute the 'height' of the text to the x dimension |
1049 | | * of the bounding box if this code is present. I can't see why |
1050 | | * this clamping was done, if it turns out to be required then |
1051 | | * we will need to revisit this and bug #695671. |
1052 | | text_bbox.p.x = fixed2float(penum->origin.x); |
1053 | | text_bbox.q.x = text_bbox.p.x + width_pt.x; |
1054 | | */ |
1055 | | |
1056 | 495k | x0 = float2fixed(text_bbox.p.x); |
1057 | 495k | y0 = float2fixed(text_bbox.p.y); |
1058 | 495k | bx2 = float2fixed(text_bbox.q.x) - x0; |
1059 | 495k | by2 = float2fixed(text_bbox.q.y) - y0; |
1060 | | |
1061 | 495k | pdev->AccumulatingBBox++; |
1062 | 495k | gx_make_clip_device_on_stack(&cdev, penum->pcpath, (gx_device *)pdev); |
1063 | 495k | set_nonclient_dev_color(&devc, gx_device_black((gx_device *)pdev)); /* any non-white color will do */ |
1064 | 495k | gx_default_fill_triangle((gx_device *) pdev, x0, y0, |
1065 | 495k | float2fixed(text_bbox.p.x) - x0, |
1066 | 495k | float2fixed(text_bbox.q.y) - y0, |
1067 | 495k | bx2, by2, &devc, lop_default); |
1068 | 495k | gx_default_fill_triangle((gx_device *) & cdev, x0, y0, |
1069 | 495k | float2fixed(text_bbox.q.x) - x0, |
1070 | 495k | float2fixed(text_bbox.p.y) - y0, |
1071 | 495k | bx2, by2, &devc, lop_default); |
1072 | 495k | pdev->AccumulatingBBox--; |
1073 | 495k | } |
1074 | 1.32M | if (!(operation & TEXT_RETURN_WIDTH)) { |
1075 | 0 | code = 0; |
1076 | 0 | goto done; |
1077 | 0 | } |
1078 | 1.32M | if (operation & TEXT_DO_NONE) { |
1079 | | /* stringwidth needs to transform to user space. */ |
1080 | 5.41k | gs_point p; |
1081 | | |
1082 | 5.41k | gs_distance_transform_inverse(width_pt.x, width_pt.y, &ctm_only(penum->pgs), &p); |
1083 | 5.41k | penum->returned.total_width.x += p.x; |
1084 | 5.41k | penum->returned.total_width.y += p.y; |
1085 | 5.41k | } else |
1086 | 1.32M | penum->returned.total_width = width_pt; |
1087 | 1.32M | code = pdf_shift_text_currentpoint(penum, &width_pt); |
1088 | | |
1089 | 1.33M | done: |
1090 | 1.33M | text->operation = operation; |
1091 | 1.33M | return code; |
1092 | 1.32M | } |
1093 | | |
1094 | | /* |
1095 | | * Get the widths (unmodified and possibly modified) of a given character |
1096 | | * in a simple font. May add the widths to the widths cache (pdfont->Widths |
1097 | | * and pdf_font_cache_elem::real_widths). Return 1 if the widths were not cached. |
1098 | | */ |
1099 | | static int |
1100 | | pdf_char_widths(gx_device_pdf *const pdev, |
1101 | | pdf_font_resource_t *pdfont, int ch, gs_font_base *font, |
1102 | | pdf_glyph_widths_t *pwidths /* may be NULL */) |
1103 | 5.97M | { |
1104 | 5.97M | pdf_glyph_widths_t widths; |
1105 | 5.97M | int code; |
1106 | 5.97M | byte *glyph_usage; |
1107 | 5.97M | double *real_widths; |
1108 | 5.97M | int char_cache_size, width_cache_size; |
1109 | 5.97M | pdf_font_resource_t *pdfont1; |
1110 | | |
1111 | 5.97M | code = pdf_attached_font_resource(pdev, (gs_font *)font, &pdfont1, |
1112 | 5.97M | &glyph_usage, &real_widths, &char_cache_size, &width_cache_size); |
1113 | 5.97M | if (code < 0) |
1114 | 0 | return code; |
1115 | 5.97M | if (pdfont1 != pdfont) |
1116 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
1117 | 5.97M | if (ch < 0 || ch > 255) |
1118 | 0 | return_error(gs_error_rangecheck); |
1119 | 5.97M | if (ch >= width_cache_size) |
1120 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
1121 | 5.97M | if (pwidths == 0) |
1122 | 0 | pwidths = &widths; |
1123 | 5.97M | if ((font->FontType != ft_user_defined && |
1124 | 5.97M | font->FontType != ft_PDF_user_defined && |
1125 | 5.97M | font->FontType != ft_PCL_user_defined && |
1126 | 5.97M | font->FontType != ft_MicroType && |
1127 | 5.97M | font->FontType != ft_GL2_stick_user_defined && |
1128 | 5.97M | font->FontType != ft_GL2_531) && real_widths[ch] == 0) { |
1129 | | /* Might be an unused char, or just not cached. */ |
1130 | 414k | gs_glyph glyph = pdfont->u.simple.Encoding[ch].glyph; |
1131 | | |
1132 | 414k | code = pdf_glyph_widths(pdfont, font->WMode, glyph, (gs_font *)font, pwidths, NULL); |
1133 | 414k | if (code < 0) |
1134 | 0 | return code; |
1135 | 414k | pwidths->BBox.p.x = pwidths->BBox.p.y = pwidths->BBox.q.x = pwidths->BBox.q.y = 0; |
1136 | 414k | if (font->WMode != 0 && code > 0 && !pwidths->replaced_v) { |
1137 | | /* |
1138 | | * The font has no Metrics2, so it must write |
1139 | | * horizontally due to PS spec. |
1140 | | * Therefore we need to fill the Widths array, |
1141 | | * which is required by PDF spec. |
1142 | | * Take it from WMode==0. |
1143 | | */ |
1144 | 0 | code = pdf_glyph_widths(pdfont, 0, glyph, (gs_font *)font, pwidths, NULL); |
1145 | 0 | } |
1146 | 414k | if (pwidths->replaced_v) { |
1147 | 393k | pdfont->u.simple.v[ch].x = pwidths->real_width.v.x - pwidths->Width.v.x; |
1148 | 393k | pdfont->u.simple.v[ch].y = pwidths->real_width.v.y - pwidths->Width.v.y; |
1149 | 393k | } else |
1150 | 20.4k | pdfont->u.simple.v[ch].x = pdfont->u.simple.v[ch].y = 0; |
1151 | 414k | if (code == 0) { |
1152 | 414k | pdfont->Widths[ch] = pwidths->Width.w; |
1153 | 414k | real_widths[ch] = pwidths->real_width.w; |
1154 | 414k | } else { |
1155 | 31 | if ((font->WMode == 0 || pwidths->ignore_wmode) && !pwidths->replaced_v) |
1156 | 31 | pdfont->Widths[ch] = pwidths->real_width.w; |
1157 | 31 | } |
1158 | 5.55M | } else { |
1159 | 5.55M | if (font->FontType == ft_user_defined || font->FontType == ft_PCL_user_defined || |
1160 | 5.55M | font->FontType == ft_MicroType || font->FontType == ft_GL2_stick_user_defined || |
1161 | 5.55M | font->FontType == ft_GL2_531 || font->FontType == ft_PDF_user_defined ) { |
1162 | 8.32k | if (!(pdfont->used[ch >> 3] & 0x80 >> (ch & 7))) |
1163 | 896 | return_error(gs_error_undefined); /* The charproc was not accumulated. */ |
1164 | 7.42k | if (!pdev->charproc_just_accumulated && |
1165 | 7.42k | !(pdfont->u.simple.s.type3.cached[ch >> 3] & 0x80 >> (ch & 7))) { |
1166 | | /* The charproc uses setcharwidth. |
1167 | | Need to accumulate again to check for a glyph variation. */ |
1168 | 419 | return_error(gs_error_undefined); |
1169 | 419 | } |
1170 | 7.42k | } |
1171 | 5.55M | if (pdev->charproc_just_accumulated && (font->FontType == ft_user_defined || font->FontType == ft_PDF_user_defined)) { |
1172 | 4.45k | pwidths->BBox.p.x = pdev->charproc_BBox.p.x; |
1173 | 4.45k | pwidths->BBox.p.y = pdev->charproc_BBox.p.y; |
1174 | 4.45k | pwidths->BBox.q.x = pdev->charproc_BBox.q.x; |
1175 | 4.45k | pwidths->BBox.q.y = pdev->charproc_BBox.q.y; |
1176 | 4.45k | } |
1177 | 5.55M | pwidths->Width.w = pdfont->Widths[ch]; |
1178 | 5.55M | pwidths->Width.v = pdfont->u.simple.v[ch]; |
1179 | 5.55M | pwidths->real_width.v.x = pwidths->real_width.v.y = 0; |
1180 | 5.55M | pwidths->ignore_wmode = false; |
1181 | 5.55M | if (font->FontType == ft_user_defined || font->FontType == ft_PCL_user_defined || |
1182 | 5.55M | font->FontType == ft_MicroType || font->FontType == ft_GL2_stick_user_defined || |
1183 | 5.55M | font->FontType == ft_GL2_531 || font->FontType == ft_PDF_user_defined) { |
1184 | 7.01k | pwidths->real_width.w = real_widths[ch * 2]; |
1185 | 7.01k | pwidths->Width.xy.x = pwidths->Width.w; |
1186 | 7.01k | pwidths->Width.xy.y = 0; |
1187 | 7.01k | pwidths->real_width.xy.x = real_widths[ch * 2 + 0]; |
1188 | 7.01k | pwidths->real_width.xy.y = real_widths[ch * 2 + 1]; |
1189 | 7.01k | pwidths->replaced_v = 0; |
1190 | 5.54M | } else if (font->WMode) { |
1191 | 0 | pwidths->real_width.w = real_widths[ch]; |
1192 | 0 | pwidths->Width.xy.x = 0; |
1193 | 0 | pwidths->Width.xy.y = pwidths->Width.w; |
1194 | 0 | pwidths->real_width.xy.x = 0; |
1195 | 0 | pwidths->real_width.xy.y = pwidths->real_width.w; |
1196 | 5.54M | } else { |
1197 | 5.54M | pwidths->real_width.w = real_widths[ch]; |
1198 | 5.54M | pwidths->Width.xy.x = pwidths->Width.w; |
1199 | 5.54M | pwidths->Width.xy.y = 0; |
1200 | 5.54M | pwidths->real_width.xy.x = pwidths->real_width.w; |
1201 | 5.54M | pwidths->real_width.xy.y = 0; |
1202 | 5.54M | } |
1203 | 5.55M | code = 0; |
1204 | 5.55M | } |
1205 | 5.97M | return code; |
1206 | 5.97M | } |
1207 | | |
1208 | | /* |
1209 | | * Convert glyph widths (.Width.xy and .real_widths.xy) from design to PDF text space |
1210 | | * Zero-out one of Width.xy.x/y per PDF Ref 5.3.3 "Text Space Details" |
1211 | | */ |
1212 | | static void |
1213 | | pdf_char_widths_to_uts(pdf_font_resource_t *pdfont /* may be NULL for non-Type3 */, |
1214 | | pdf_glyph_widths_t *pwidths) |
1215 | 5.99M | { |
1216 | 5.99M | if (pdfont && (pdfont->FontType == ft_user_defined || |
1217 | 2.22M | pdfont->FontType == ft_PDF_user_defined || |
1218 | 2.22M | pdfont->FontType == ft_PCL_user_defined || |
1219 | 2.22M | pdfont->FontType == ft_MicroType || |
1220 | 2.22M | pdfont->FontType == ft_GL2_stick_user_defined || |
1221 | 2.22M | pdfont->FontType == ft_GL2_531)) { |
1222 | 7.01k | gs_matrix *pmat = &pdfont->u.simple.s.type3.FontMatrix; |
1223 | | |
1224 | 7.01k | pwidths->Width.xy.x *= pmat->xx; /* formula simplified based on wy in glyph space == 0 */ |
1225 | 7.01k | pwidths->Width.xy.y = 0.0; /* WMode == 0 for PDF Type 3 fonts */ |
1226 | 7.01k | gs_distance_transform(pwidths->real_width.xy.x, pwidths->real_width.xy.y, pmat, &pwidths->real_width.xy); |
1227 | 5.98M | } else { |
1228 | | /* |
1229 | | * For other font types: |
1230 | | * - PDF design->text space is a simple scaling by 0.001. |
1231 | | * - The Width.xy.x/y that should be zeroed-out per 5.3.3 "Text Space Details" is already 0. |
1232 | | */ |
1233 | 5.98M | pwidths->Width.xy.x /= 1000.0; |
1234 | 5.98M | pwidths->Width.xy.y /= 1000.0; |
1235 | 5.98M | pwidths->real_width.xy.x /= 1000.0; |
1236 | 5.98M | pwidths->real_width.xy.y /= 1000.0; |
1237 | 5.98M | } |
1238 | 5.99M | } |
1239 | | |
1240 | | /* |
1241 | | * Compute the total text width (in user space). Return 1 if any |
1242 | | * character had real_width != Width, otherwise 0. |
1243 | | */ |
1244 | | static int |
1245 | | process_text_return_width(const pdf_text_enum_t *pte, gs_font_base *font, |
1246 | | pdf_text_process_state_t *ppts, |
1247 | | const gs_const_string *pstr, const gs_glyph *gdata, |
1248 | | gs_point *pdpt, int *accepted, gs_rect *bbox) |
1249 | 259k | { |
1250 | 259k | int i; |
1251 | 259k | gs_point w; |
1252 | 259k | gs_point dpt; |
1253 | 259k | int num_spaces = 0; |
1254 | 259k | int space_char = |
1255 | 259k | (pte->text.operation & TEXT_ADD_TO_SPACE_WIDTH ? |
1256 | 212k | pte->text.space.s_char : -1); |
1257 | 259k | int widths_differ = 0, code; |
1258 | 259k | gx_device_pdf *pdev = (gx_device_pdf *)pte->dev; |
1259 | 259k | pdf_font_resource_t *pdfont; |
1260 | | |
1261 | 259k | code = pdf_attached_font_resource(pdev, (gs_font *)font, &pdfont, NULL, NULL, NULL, NULL); |
1262 | 259k | if (code < 0) |
1263 | 0 | return code; |
1264 | 2.47M | for (i = 0, w.x = w.y = 0; i < pstr->size; ++i) { |
1265 | 2.22M | pdf_glyph_widths_t cw; /* in PDF text space */ |
1266 | 2.22M | gs_char ch = pstr->data[i]; |
1267 | | |
1268 | | /* Initialise some variables */ |
1269 | 2.22M | cw.real_width.xy.x = cw.real_width.xy.y = cw.Width.xy.x = cw.Width.xy.y = 0; |
1270 | 2.22M | cw.BBox.p.x = cw.BBox.p.y = cw.BBox.q.x = cw.BBox.q.y = 0; |
1271 | | |
1272 | 2.22M | { const gs_glyph *gdata_i = (gdata != NULL ? gdata + i : 0); |
1273 | | |
1274 | 2.22M | code = pdf_encode_string_element(pdev, (gs_font *)font, pdfont, ch, gdata_i); |
1275 | | |
1276 | 2.22M | if (code < 0) |
1277 | 0 | return code; |
1278 | 2.22M | } |
1279 | 2.22M | if ((font->FontType == ft_user_defined || |
1280 | 2.22M | font->FontType == ft_PDF_user_defined || |
1281 | 2.22M | font->FontType == ft_PCL_user_defined || |
1282 | 2.22M | font->FontType == ft_GL2_stick_user_defined || |
1283 | 2.22M | font->FontType == ft_MicroType || |
1284 | 2.22M | font->FontType == ft_GL2_531) && |
1285 | 2.22M | (i > 0 || !pdev->charproc_just_accumulated) && |
1286 | 2.22M | !(pdfont->u.simple.s.type3.cached[ch >> 3] & (0x80 >> (ch & 7)))){ |
1287 | 3.15k | code = gs_error_undefined; |
1288 | 3.15k | } |
1289 | 2.21M | else { |
1290 | 2.21M | if (font->FontType == ft_PCL_user_defined) { |
1291 | | /* Check the cache, if the glyph has been flushed, assume that |
1292 | | * it has been redefined, and do not use the current glyph. |
1293 | | * Additional code in pdf_text_process will also spot this |
1294 | | * condition and will not capture the glyph in this font. |
1295 | | */ |
1296 | | /* Cache checking code copied from gxchar.c, show_proceed, |
1297 | | * case 0, 'plain char'. |
1298 | | */ |
1299 | 0 | gs_font *rfont = (pte->fstack.depth < 0 ? pte->current_font : pte->fstack.items[0].font); |
1300 | 0 | gs_font *pfont = (pte->fstack.depth < 0 ? pte->current_font : |
1301 | 0 | pte->fstack.items[pte->fstack.depth].font); |
1302 | 0 | int wmode = rfont->WMode; |
1303 | 0 | gs_log2_scale_point log2_scale = {0,0}; |
1304 | 0 | gs_fixed_point subpix_origin = {0,0}; |
1305 | 0 | cached_fm_pair *pair; |
1306 | |
|
1307 | 0 | code = gx_lookup_fm_pair(pfont, &ctm_only(pte->pgs), &log2_scale, |
1308 | 0 | false, &pair); |
1309 | 0 | if (code < 0) |
1310 | 0 | return code; |
1311 | 0 | if (gx_lookup_cached_char(pfont, pair, ch, wmode, |
1312 | 0 | 1, &subpix_origin) == 0) { |
1313 | | /* Character is not in cache, must have been redefined. */ |
1314 | 0 | code = gs_error_undefined; |
1315 | 0 | } |
1316 | 0 | else { |
1317 | | /* Character is in cache, go ahead and use it */ |
1318 | 0 | code = pdf_char_widths((gx_device_pdf *)pte->dev, |
1319 | 0 | ppts->values.pdfont, ch, font, &cw); |
1320 | 0 | } |
1321 | 0 | } else |
1322 | | /* Not a PCL bitmap font, we don't need to worry about redefined glyphs */ |
1323 | 2.21M | code = pdf_char_widths((gx_device_pdf *)pte->dev, |
1324 | 2.21M | ppts->values.pdfont, ch, font, &cw); |
1325 | 2.21M | } |
1326 | 2.22M | if (code < 0) { |
1327 | 3.15k | if (i) |
1328 | 2.85k | break; |
1329 | 303 | *accepted = 0; |
1330 | 303 | return code; |
1331 | 3.15k | } |
1332 | 2.21M | pdf_char_widths_to_uts(pdfont, &cw); |
1333 | 2.21M | w.x += cw.real_width.xy.x; |
1334 | 2.21M | w.y += cw.real_width.xy.y; |
1335 | 2.21M | if (cw.real_width.xy.x != cw.Width.xy.x || |
1336 | 2.21M | cw.real_width.xy.y != cw.Width.xy.y |
1337 | 2.21M | ) |
1338 | 0 | widths_differ = 1; |
1339 | 2.21M | if (pstr->data[i] == space_char) |
1340 | 9.62k | ++num_spaces; |
1341 | 2.21M | if (cw.BBox.p.x != 0 && cw.BBox.q.x != 0){ |
1342 | 0 | if (cw.BBox.p.x < bbox->p.x) |
1343 | 0 | bbox->p.x = cw.BBox.p.x; |
1344 | 0 | if (cw.BBox.p.y < bbox->p.y) |
1345 | 0 | bbox->p.y = cw.BBox.p.y; |
1346 | 0 | if (cw.BBox.q.x > bbox->q.x) |
1347 | 0 | bbox->q.x = cw.BBox.q.x; |
1348 | 0 | if (cw.BBox.q.y > bbox->q.y) |
1349 | 0 | bbox->q.y = cw.BBox.q.y; |
1350 | 0 | } |
1351 | 2.21M | } |
1352 | 258k | *accepted = i; |
1353 | 258k | gs_distance_transform(w.x * ppts->values.size, w.y * ppts->values.size, |
1354 | 258k | &ppts->values.matrix, &dpt); |
1355 | 258k | if (pte->text.operation & TEXT_ADD_TO_ALL_WIDTHS) { |
1356 | 139k | int num_chars = *accepted; |
1357 | 139k | gs_point tpt; |
1358 | | |
1359 | 139k | gs_distance_transform(pte->text.delta_all.x, pte->text.delta_all.y, |
1360 | 139k | &ctm_only(pte->pgs), &tpt); |
1361 | 139k | dpt.x += tpt.x * num_chars; |
1362 | 139k | dpt.y += tpt.y * num_chars; |
1363 | 139k | } |
1364 | 258k | if (pte->text.operation & TEXT_ADD_TO_SPACE_WIDTH) { |
1365 | 46.1k | gs_point tpt; |
1366 | | |
1367 | 46.1k | gs_distance_transform(pte->text.delta_space.x, pte->text.delta_space.y, |
1368 | 46.1k | &ctm_only(pte->pgs), &tpt); |
1369 | 46.1k | dpt.x += tpt.x * num_spaces; |
1370 | 46.1k | dpt.y += tpt.y * num_spaces; |
1371 | 46.1k | } |
1372 | 258k | *pdpt = dpt; |
1373 | | |
1374 | 258k | return widths_differ; |
1375 | 259k | } |
1376 | | |
1377 | | /* |
1378 | | * Emulate TEXT_ADD_TO_ALL_WIDTHS and/or TEXT_ADD_TO_SPACE_WIDTH, |
1379 | | * and implement TEXT_REPLACE_WIDTHS if requested. |
1380 | | * Uses and updates ppts->values.matrix; uses ppts->values.pdfont. |
1381 | | * |
1382 | | * Destroys the text parameters in *pte. |
1383 | | * The caller must restore them. |
1384 | | */ |
1385 | | int |
1386 | | process_text_modify_width(pdf_text_enum_t *pte, gs_font *font, |
1387 | | pdf_text_process_state_t *ppts, |
1388 | | const gs_const_string *pstr, |
1389 | | gs_point *pdpt, const gs_glyph *gdata, bool composite, int decoded_bytes) |
1390 | 1.08M | { |
1391 | 1.08M | gx_device_pdf *const pdev = (gx_device_pdf *)pte->dev; |
1392 | 1.08M | int space_char = |
1393 | 1.08M | (pte->text.operation & TEXT_ADD_TO_SPACE_WIDTH ? |
1394 | 827k | pte->text.space.s_char : -1); |
1395 | 1.08M | gs_point start, total; |
1396 | 1.08M | pdf_font_resource_t *pdfont3 = NULL; |
1397 | 1.08M | int code; |
1398 | | |
1399 | 1.08M | if (font->FontType == ft_user_defined || |
1400 | 1.08M | font->FontType == ft_PDF_user_defined || |
1401 | 1.08M | font->FontType == ft_PCL_user_defined || |
1402 | 1.08M | font->FontType == ft_MicroType || |
1403 | 1.08M | font->FontType == ft_GL2_stick_user_defined || |
1404 | 1.08M | font->FontType == ft_GL2_531) { |
1405 | 2.28k | code = pdf_attached_font_resource(pdev, font, &pdfont3, NULL, NULL, NULL, NULL); |
1406 | 2.28k | if (code < 0) |
1407 | 0 | return code; |
1408 | | |
1409 | 2.28k | } |
1410 | 1.08M | pte->text.data.bytes = pstr->data; |
1411 | 1.08M | pte->text.size = pstr->size; |
1412 | 1.08M | pte->index = 0; |
1413 | 1.08M | pte->text.operation &= ~TEXT_FROM_ANY; |
1414 | 1.08M | pte->text.operation |= TEXT_FROM_STRING; |
1415 | 1.08M | start.x = ppts->values.matrix.tx; |
1416 | 1.08M | start.y = ppts->values.matrix.ty; |
1417 | 1.08M | total.x = total.y = 0; /* user space */ |
1418 | | /* |
1419 | | * Note that character widths are in design space, but text.delta_* |
1420 | | * values and the width value returned in *pdpt are in user space, |
1421 | | * and the width values for pdf_append_chars are in device space. |
1422 | | */ |
1423 | 4.86M | for (;;) { |
1424 | 4.86M | pdf_glyph_widths_t cw; /* design space, then converted to PDF text space */ |
1425 | 4.86M | gs_point did, wanted, tpt; /* user space */ |
1426 | 4.86M | gs_point v = {0, 0}; /* design space */ |
1427 | 4.86M | gs_char chr; |
1428 | 4.86M | gs_glyph glyph; |
1429 | 4.86M | int index = pte->index; |
1430 | 4.86M | gs_text_enum_t pte1 = *(gs_text_enum_t *)pte; |
1431 | 4.86M | int FontType; |
1432 | 4.86M | bool use_cached_v = true; |
1433 | 4.86M | byte composite_type3_text[1]; |
1434 | | |
1435 | 4.86M | code = pte1.orig_font->procs.next_char_glyph(&pte1, &chr, &glyph); |
1436 | 4.86M | if (code == 2) { /* end of string */ |
1437 | 1.08M | gs_text_enum_copy_dynamic((gs_text_enum_t *)pte, &pte1, true); |
1438 | 1.08M | break; |
1439 | 1.08M | } |
1440 | 3.77M | if (code < 0) |
1441 | 0 | return code; |
1442 | 3.77M | if (composite) { /* from process_cmap_text */ |
1443 | 23.8k | gs_font *subfont = pte1.fstack.items[pte1.fstack.depth].font; |
1444 | | |
1445 | 23.8k | if (subfont->FontType == ft_user_defined || subfont->FontType == ft_PDF_user_defined ) { |
1446 | 0 | pdf_font_resource_t *pdfont; |
1447 | |
|
1448 | 0 | FontType = subfont->FontType; |
1449 | 0 | code = pdf_attached_font_resource(pdev, subfont, |
1450 | 0 | &pdfont, NULL, NULL, NULL, NULL); |
1451 | 0 | if (code < 0) |
1452 | 0 | return code; |
1453 | 0 | chr = pdf_find_glyph(pdfont, glyph); |
1454 | 0 | composite_type3_text[0] = (byte)chr; |
1455 | 0 | code = pdf_char_widths((gx_device_pdf *)pte->dev, |
1456 | 0 | ppts->values.pdfont, chr, (gs_font_base *)subfont, |
1457 | 0 | &cw); |
1458 | 23.8k | } else { |
1459 | 23.8k | pdf_font_resource_t *pdsubf = ppts->values.pdfont->u.type0.DescendantFont; |
1460 | | |
1461 | 23.8k | FontType = pdsubf->FontType; |
1462 | 23.8k | code = pdf_glyph_widths(pdsubf, font->WMode, glyph, subfont, &cw, |
1463 | 23.8k | pte->cdevproc_callout ? pte->cdevproc_result : NULL); |
1464 | 23.8k | } |
1465 | 3.75M | } else {/* must be a base font */ |
1466 | 3.75M | const gs_glyph *gdata_i = (gdata != NULL ? gdata + pte->index : 0); |
1467 | | |
1468 | | /* gdata is NULL when composite == true, or the text isn't a single byte. */ |
1469 | 3.75M | code = pdf_encode_string_element(pdev, font, ppts->values.pdfont, chr, gdata_i); |
1470 | 3.75M | FontType = font->FontType; |
1471 | 3.75M | if (code >= 0) { |
1472 | 3.75M | if (chr == GS_NO_CHAR && glyph != GS_NO_GLYPH) { |
1473 | | /* glyphshow, we have no char code. Bug 686988.*/ |
1474 | 0 | code = pdf_glyph_widths(ppts->values.pdfont, font->WMode, glyph, font, &cw, NULL); |
1475 | 0 | use_cached_v = false; /* Since we have no chr and don't call pdf_char_widths. */ |
1476 | 3.75M | } else { |
1477 | 3.75M | code = pdf_char_widths((gx_device_pdf *)pte->dev, |
1478 | 3.75M | ppts->values.pdfont, chr, (gs_font_base *)font, |
1479 | 3.75M | &cw); |
1480 | 3.75M | if (code == 0 && font->FontType == ft_PCL_user_defined) { |
1481 | | /* Check the cache, if the glyph has been flushed, assume that |
1482 | | * it has been redefined, and do not use the current glyph. |
1483 | | * Additional code in pdf_text_process will also spot this |
1484 | | * condition and will not capture the glyph in this font. |
1485 | | */ |
1486 | | /* Cache checking code copied from gxchar.c, show_proceed, |
1487 | | * case 0, 'plain char'. |
1488 | | */ |
1489 | 0 | gs_font *rfont = (pte->fstack.depth < 0 ? pte->current_font : pte->fstack.items[0].font); |
1490 | 0 | gs_font *pfont = (pte->fstack.depth < 0 ? pte->current_font : |
1491 | 0 | pte->fstack.items[pte->fstack.depth].font); |
1492 | 0 | int wmode = rfont->WMode; |
1493 | 0 | gs_log2_scale_point log2_scale = {0,0}; |
1494 | 0 | gs_fixed_point subpix_origin = {0,0}; |
1495 | 0 | cached_fm_pair *pair; |
1496 | |
|
1497 | 0 | code = gx_lookup_fm_pair(pfont, &ctm_only(pte->pgs), &log2_scale, |
1498 | 0 | false, &pair); |
1499 | 0 | if (code < 0) |
1500 | 0 | return code; |
1501 | 0 | if (gx_lookup_cached_char(pfont, pair, chr, wmode, |
1502 | 0 | 1, &subpix_origin) == 0) { |
1503 | | /* Character is not in cache, must have been redefined. */ |
1504 | 0 | code = gs_error_undefined; |
1505 | 0 | } |
1506 | 0 | } |
1507 | 3.75M | } |
1508 | 3.75M | } |
1509 | 3.75M | } |
1510 | 3.77M | if (code < 0) { |
1511 | 1.57k | if (index > 0) |
1512 | 1.00k | break; |
1513 | 571 | return code; |
1514 | 1.57k | } |
1515 | | /* TrueType design grid is 2048x2048 against the nominal PS/PDF grid of |
1516 | | * 1000x1000. This can lead to rounding errors when converting to text space |
1517 | | * and comparing against any entries in /W or /Widths arrays. We fix the |
1518 | | * TrueType widths to the nearest integer here to avoid this. |
1519 | | * See Bug #693825 |
1520 | | */ |
1521 | 3.77M | if (FontType == ft_CID_TrueType || FontType == ft_TrueType) { |
1522 | 515k | cw.Width.w = floor(cw.Width.w + 0.5); |
1523 | 515k | cw.Width.xy.x = floor(cw.Width.xy.x + 0.5); |
1524 | 515k | cw.Width.xy.y = floor(cw.Width.xy.y + 0.5); |
1525 | 515k | cw.Width.v.x = floor(cw.Width.v.x + 0.5); |
1526 | 515k | cw.Width.v.y = floor(cw.Width.v.y + 0.5); |
1527 | 515k | cw.real_width.w = floor(cw.real_width.w + 0.5); |
1528 | 515k | cw.real_width.xy.x = floor(cw.real_width.xy.x + 0.5); |
1529 | 515k | cw.real_width.xy.y = floor(cw.real_width.xy.y + 0.5); |
1530 | 515k | cw.real_width.v.x = floor(cw.real_width.v.x + 0.5); |
1531 | 515k | cw.real_width.v.y = floor(cw.real_width.v.y + 0.5); |
1532 | 515k | } |
1533 | | |
1534 | 3.77M | gs_text_enum_copy_dynamic((gs_text_enum_t *)pte, &pte1, true); |
1535 | 3.77M | if (composite || !use_cached_v) { |
1536 | 23.8k | if (cw.replaced_v) { |
1537 | 23.6k | v.x = cw.real_width.v.x - cw.Width.v.x; |
1538 | 23.6k | v.y = cw.real_width.v.y - cw.Width.v.y; |
1539 | 23.6k | } |
1540 | 23.8k | } else |
1541 | 3.75M | v = ppts->values.pdfont->u.simple.v[chr]; |
1542 | 3.77M | if (font->WMode && !cw.ignore_wmode) { |
1543 | | /* With WMode 1 v-vector is (WMode 1 origin) - (WMode 0 origin). |
1544 | | The glyph shifts in the opposite direction. */ |
1545 | 191 | v.x = - v.x; |
1546 | 191 | v.y = - v.y; |
1547 | 3.77M | } else { |
1548 | | /* With WMode 0 v-vector is (Metrics sb) - (native sb). |
1549 | | The glyph shifts in same direction. */ |
1550 | 3.77M | } |
1551 | | /* pdf_glyph_origin is not longer used. */ |
1552 | 3.77M | if (v.x != 0 || v.y != 0) { |
1553 | 8.60k | gs_point glyph_origin_shift; |
1554 | 8.60k | double scale0; |
1555 | | |
1556 | 8.60k | if (FontType == ft_TrueType || FontType == ft_CID_TrueType) |
1557 | 8.45k | scale0 = (float)0.001; |
1558 | 153 | else |
1559 | 153 | scale0 = 1; |
1560 | 8.60k | glyph_origin_shift.x = v.x * scale0; |
1561 | 8.60k | glyph_origin_shift.y = v.y * scale0; |
1562 | 8.60k | if (composite) { |
1563 | 925 | gs_font *subfont = pte->fstack.items[pte->fstack.depth].font; |
1564 | | |
1565 | 925 | gs_distance_transform(glyph_origin_shift.x, glyph_origin_shift.y, |
1566 | 925 | &subfont->FontMatrix, &glyph_origin_shift); |
1567 | 925 | } |
1568 | 8.60k | gs_distance_transform(glyph_origin_shift.x, glyph_origin_shift.y, |
1569 | 8.60k | &font->FontMatrix, &glyph_origin_shift); |
1570 | 8.60k | gs_distance_transform(glyph_origin_shift.x, glyph_origin_shift.y, |
1571 | 8.60k | &ctm_only(pte->pgs), &glyph_origin_shift); |
1572 | 8.60k | if (glyph_origin_shift.x != 0 || glyph_origin_shift.y != 0) { |
1573 | 8.60k | ppts->values.matrix.tx = start.x + total.x + glyph_origin_shift.x; |
1574 | 8.60k | ppts->values.matrix.ty = start.y + total.y + glyph_origin_shift.y; |
1575 | 8.60k | code = pdf_set_text_state_values(pdev, &ppts->values); |
1576 | 8.60k | if (code < 0) |
1577 | 0 | break; |
1578 | 8.60k | } |
1579 | 8.60k | } |
1580 | 3.77M | pdf_char_widths_to_uts(pdfont3, &cw); /* convert design->text space */ |
1581 | 3.77M | if (pte->text.operation & (TEXT_DO_DRAW | TEXT_RENDER_MODE_3)) { |
1582 | 3.75M | gs_distance_transform(cw.Width.xy.x * ppts->values.size, |
1583 | 3.75M | cw.Width.xy.y * ppts->values.size, |
1584 | 3.75M | &ppts->values.matrix, &did); |
1585 | 3.75M | gs_distance_transform(((font->WMode && !cw.ignore_wmode) ? 0 : ppts->values.character_spacing), |
1586 | 3.75M | ((font->WMode && !cw.ignore_wmode) ? ppts->values.character_spacing : 0), |
1587 | 3.75M | &ppts->values.matrix, &tpt); |
1588 | 3.75M | did.x += tpt.x; |
1589 | 3.75M | did.y += tpt.y; |
1590 | | /* If pte->single_byte_space == 0 then we had a widthshow or awidthshow from |
1591 | | * PostScript, so we apply the PostScript rules. Otherwise it was from PDF |
1592 | | * in which case if the number of bytes in the character code was 1 we apply |
1593 | | * word spacing. If it was PDF and we had a multi-byte decode, do not apply |
1594 | | * word spacing (how ugly!). Note tht its important this is applied the same to |
1595 | | * both the 'did' and 'wanted' calculations (see below). |
1596 | | */ |
1597 | 3.75M | if (chr == space_char && (!pte->single_byte_space || decoded_bytes == 1)) { |
1598 | 52.0k | gs_distance_transform(((font->WMode && !cw.ignore_wmode)? 0 : ppts->values.word_spacing), |
1599 | 52.0k | ((font->WMode && !cw.ignore_wmode) ? ppts->values.word_spacing : 0), |
1600 | 52.0k | &ppts->values.matrix, &tpt); |
1601 | 52.0k | did.x += tpt.x; |
1602 | 52.0k | did.y += tpt.y; |
1603 | 52.0k | } |
1604 | 3.75M | if (composite && (FontType == ft_user_defined || FontType == ft_PDF_user_defined)) |
1605 | 0 | code = pdf_append_chars(pdev, composite_type3_text, 1, did.x, did.y, composite); |
1606 | 3.75M | else |
1607 | 3.75M | code = pdf_append_chars(pdev, pstr->data + index, pte->index - index, did.x, did.y, composite); |
1608 | 3.75M | if (code < 0) |
1609 | 0 | break; |
1610 | 3.75M | } else |
1611 | 17.1k | did.x = did.y = 0; |
1612 | 3.77M | if (pte->text.operation & TEXT_REPLACE_WIDTHS) { |
1613 | 3.75M | gs_point dpt; |
1614 | | |
1615 | | /* We are applying a width override, from x/y/xyshow. This coudl be from |
1616 | | * a PostScript file, or it could be from a PDF file where we have a font |
1617 | | * with a FontMatrix which is neither horizontal nor vertical. If we use TJ |
1618 | | * for that, then we end up applying the displacement twice, once here where |
1619 | | * we add a TJ, and once when we actually draw the glyph (TJ is added *after* |
1620 | | * the glyph is drawn, unlike xshow). So in this case we don't want to try |
1621 | | * and use a TJ, we need to position the glyphs using text positioning |
1622 | | * operators. |
1623 | | */ |
1624 | 3.75M | if(cw.Width.xy.x != cw.real_width.xy.x || cw.Width.xy.y != cw.real_width.xy.y) |
1625 | 0 | pdev->text->text_state->can_use_TJ = false; |
1626 | | |
1627 | 3.75M | code = gs_text_replaced_width(&pte->text, pte->xy_index++, &dpt); |
1628 | 3.75M | if (code < 0) |
1629 | 0 | return_error(gs_error_unregistered); |
1630 | 3.75M | gs_distance_transform(dpt.x, dpt.y, &ctm_only(pte->pgs), &wanted); |
1631 | | |
1632 | 3.75M | gs_distance_transform(((font->WMode && !cw.ignore_wmode) ? 0 : ppts->values.character_spacing), |
1633 | 3.75M | ((font->WMode && !cw.ignore_wmode) ? ppts->values.character_spacing : 0), |
1634 | 3.75M | &ppts->values.matrix, &tpt); |
1635 | 3.75M | wanted.x += tpt.x; |
1636 | 3.75M | wanted.y += tpt.y; |
1637 | | |
1638 | 3.75M | if (chr == space_char && (!pte->single_byte_space || decoded_bytes == 1)) { |
1639 | 52.0k | gs_distance_transform(((font->WMode && !cw.ignore_wmode)? 0 : ppts->values.word_spacing), |
1640 | 52.0k | ((font->WMode && !cw.ignore_wmode) ? ppts->values.word_spacing : 0), |
1641 | 52.0k | &ppts->values.matrix, &tpt); |
1642 | 52.0k | wanted.x += tpt.x; |
1643 | 52.0k | wanted.y += tpt.y; |
1644 | 52.0k | } |
1645 | 3.75M | } else { |
1646 | 23.8k | pdev->text->text_state->can_use_TJ = true; |
1647 | 23.8k | gs_distance_transform(cw.real_width.xy.x * ppts->values.size, |
1648 | 23.8k | cw.real_width.xy.y * ppts->values.size, |
1649 | 23.8k | &ppts->values.matrix, &wanted); |
1650 | 23.8k | if (pte->text.operation & TEXT_ADD_TO_ALL_WIDTHS) { |
1651 | 986 | gs_distance_transform(pte->text.delta_all.x, |
1652 | 986 | pte->text.delta_all.y, |
1653 | 986 | &ctm_only(pte->pgs), &tpt); |
1654 | 986 | wanted.x += tpt.x; |
1655 | 986 | wanted.y += tpt.y; |
1656 | 986 | } |
1657 | | /* See comment above for 'did' calculations, the application of word spacing must |
1658 | | * be the same for did and wanted. |
1659 | | */ |
1660 | 23.8k | if (chr == space_char && (!pte->single_byte_space || decoded_bytes == 1)) { |
1661 | 0 | gs_distance_transform(pte->text.delta_space.x, |
1662 | 0 | pte->text.delta_space.y, |
1663 | 0 | &ctm_only(pte->pgs), &tpt); |
1664 | 0 | wanted.x += tpt.x; |
1665 | 0 | wanted.y += tpt.y; |
1666 | 0 | } |
1667 | 23.8k | } |
1668 | 3.77M | total.x += wanted.x; |
1669 | 3.77M | total.y += wanted.y; |
1670 | 3.77M | if (wanted.x != did.x || wanted.y != did.y) { |
1671 | 3.73M | ppts->values.matrix.tx = start.x + total.x; |
1672 | 3.73M | ppts->values.matrix.ty = start.y + total.y; |
1673 | 3.73M | code = pdf_set_text_state_values(pdev, &ppts->values); |
1674 | 3.73M | if (code < 0) |
1675 | 0 | break; |
1676 | 3.73M | } |
1677 | 3.77M | pdev->charproc_just_accumulated = false; |
1678 | 3.77M | } |
1679 | 1.08M | *pdpt = total; |
1680 | 1.08M | return 0; |
1681 | 1.08M | } |
1682 | | |
1683 | | /* |
1684 | | * Get character code from a glyph code. |
1685 | | * An usage of this function is very undesirable, |
1686 | | * because a glyph may be unlisted in Encoding. |
1687 | | */ |
1688 | | int |
1689 | | pdf_encode_glyph(gs_font_base *bfont, gs_glyph glyph0, |
1690 | | byte *buf, int buf_size, int *char_code_length) |
1691 | 0 | { |
1692 | 0 | gs_char c; |
1693 | |
|
1694 | 0 | *char_code_length = 1; |
1695 | 0 | if (*char_code_length > buf_size) |
1696 | 0 | return_error(gs_error_rangecheck); /* Must not happen. */ |
1697 | 0 | for (c = 0; c < 255; c++) { |
1698 | 0 | gs_glyph glyph1 = bfont->procs.encode_char((gs_font *)bfont, c, |
1699 | 0 | GLYPH_SPACE_NAME); |
1700 | 0 | if (glyph1 == glyph0) { |
1701 | 0 | buf[0] = (byte)c; |
1702 | 0 | return 0; |
1703 | 0 | } |
1704 | 0 | } |
1705 | 0 | return_error(gs_error_rangecheck); /* Can't encode. */ |
1706 | 0 | } |
1707 | | |
1708 | | /* ---------------- Type 1 or TrueType font ---------------- */ |
1709 | | |
1710 | | /* |
1711 | | * Process a text string in a simple font. |
1712 | | */ |
1713 | | int |
1714 | | process_plain_text(gs_text_enum_t *pte, void *vbuf, uint bsize) |
1715 | 1.49M | { |
1716 | 1.49M | byte *const buf = vbuf; |
1717 | 1.49M | uint count; |
1718 | 1.49M | uint operation = pte->text.operation; |
1719 | 1.49M | pdf_text_enum_t *penum = (pdf_text_enum_t *)pte; |
1720 | 1.49M | int code; |
1721 | 1.49M | gs_string str; |
1722 | 1.49M | pdf_text_process_state_t text_state; |
1723 | 1.49M | const gs_glyph *gdata = NULL; |
1724 | | |
1725 | 1.49M | if (operation & (TEXT_FROM_STRING | TEXT_FROM_BYTES)) { |
1726 | 1.49M | count = pte->text.size - pte->index; |
1727 | 1.49M | if (bsize < count) |
1728 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
1729 | 1.49M | memcpy(buf, (const byte *)pte->text.data.bytes + pte->index, count); |
1730 | 1.49M | } else if (operation & (TEXT_FROM_CHARS | TEXT_FROM_SINGLE_CHAR)) { |
1731 | | /* Check that all chars fit in a single byte. */ |
1732 | 2.32k | const gs_char *cdata; |
1733 | 2.32k | int i; |
1734 | | |
1735 | 2.32k | if (operation & TEXT_FROM_CHARS) { |
1736 | 2.32k | cdata = pte->text.data.chars; |
1737 | 2.32k | count = (pte->text.size - pte->index); |
1738 | 2.32k | } else { |
1739 | 0 | cdata = &pte->text.data.d_char; |
1740 | 0 | count = 1; |
1741 | 0 | } |
1742 | 2.32k | if (bsize < count * sizeof(gs_char)) |
1743 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
1744 | 19.8k | for (i = 0; i < count; ++i) { |
1745 | 17.5k | gs_char chr = cdata[pte->index + i]; |
1746 | | |
1747 | 17.5k | if (chr & ~0xff) |
1748 | 0 | return_error(gs_error_rangecheck); |
1749 | 17.5k | buf[i] = (byte)chr; |
1750 | 17.5k | } |
1751 | 2.32k | } else if (operation & (TEXT_FROM_GLYPHS | TEXT_FROM_SINGLE_GLYPH)) { |
1752 | | /* |
1753 | | * Since PDF has no analogue of 'glyphshow', |
1754 | | * we try to encode glyphs with the current |
1755 | | * font's encoding. If the current font has no encoding, |
1756 | | * or the encoding doesn't contain necessary glyphs, |
1757 | | * the text will be represented with a Type 3 font with |
1758 | | * bitmaps or outlines. |
1759 | | * |
1760 | | * When we fail with encoding (136-01.ps is an example), |
1761 | | * we could locate a PDF font resource or create a new one |
1762 | | * with same outlines and an appropriate encoding. |
1763 | | * Also we could change .notdef entries in the |
1764 | | * copied font (assuming that document designer didn't use |
1765 | | * .notdef for a meanful printing). |
1766 | | * fixme: Not implemented yet. |
1767 | | */ |
1768 | 0 | gs_font *font = pte->current_font; |
1769 | 0 | uint size; |
1770 | 0 | int i; |
1771 | |
|
1772 | 0 | if (operation & TEXT_FROM_GLYPHS) { |
1773 | 0 | gdata = pte->text.data.glyphs; |
1774 | 0 | size = pte->text.size - pte->index; |
1775 | 0 | } else { |
1776 | 0 | gdata = &pte->text.data.d_glyph; |
1777 | 0 | size = 1; |
1778 | 0 | } |
1779 | 0 | if (!pdf_is_simple_font(font)) |
1780 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
1781 | 0 | count = 0; |
1782 | 0 | for (i = 0; i < size; ++i) { |
1783 | 0 | pdf_font_resource_t *pdfont; |
1784 | 0 | gs_glyph glyph = gdata[pte->index + i]; |
1785 | 0 | int char_code_length; |
1786 | |
|
1787 | 0 | code = pdf_encode_glyph((gs_font_base *)font, glyph, |
1788 | 0 | buf + count, size - count, &char_code_length); |
1789 | 0 | if (code < 0) |
1790 | 0 | break; |
1791 | | /* Even if we already have a glyph encoded at this position in the font |
1792 | | * it may not be the *right* glyph. We effectively use the first byte of |
1793 | | * the glyph name as the index when using glyphshow which means that |
1794 | | * /o and /omicron would be encoded at the same index. So we need |
1795 | | * to check the actual glyph to see if they are the same. To do |
1796 | | * that we need the PDF font resource which is attached to the font (if any). |
1797 | | * cf bugs #695259 and #695168 |
1798 | | */ |
1799 | 0 | code = pdf_attached_font_resource((gx_device_pdf *)penum->dev, font, |
1800 | 0 | &pdfont, NULL, NULL, NULL, NULL); |
1801 | 0 | if (code >= 0 && pdfont && pdfont->u.simple.Encoding[*(buf + count)].glyph != glyph) |
1802 | | /* the glyph doesn't match the glyph already encoded at this position. |
1803 | | * Breaking out here will start a new PDF font resource in the code below. |
1804 | | */ |
1805 | 0 | break; |
1806 | 0 | count += char_code_length; |
1807 | 0 | if (operation & TEXT_INTERVENE) |
1808 | 0 | break; /* Just do one character. */ |
1809 | 0 | } |
1810 | 0 | if (i < size) { |
1811 | 0 | pdf_font_resource_t *pdfont; |
1812 | |
|
1813 | 0 | str.data = buf; |
1814 | 0 | str.size = size; |
1815 | 0 | code = pdf_obtain_font_resource_unencoded(penum, &str, &pdfont, gdata); |
1816 | 0 | if (code < 0) { |
1817 | | /* |
1818 | | * pdf_text_process will fall back |
1819 | | * to default implementation. |
1820 | | */ |
1821 | 0 | return code; |
1822 | 0 | } |
1823 | 0 | count = size; |
1824 | 0 | } |
1825 | | /* So far we will use TEXT_FROM_STRING instead |
1826 | | TEXT_FROM_*_GLYPH*. Since we used a single |
1827 | | byte encoding, the character index appears invariant |
1828 | | during this substitution. |
1829 | | */ |
1830 | 0 | } else |
1831 | 0 | return_error(gs_error_rangecheck); |
1832 | 1.49M | str.data = buf; |
1833 | 1.49M | if (count > 1 && (operation & TEXT_INTERVENE)) { |
1834 | | /* Just do one character. */ |
1835 | 0 | str.size = 1; |
1836 | 0 | code = pdf_process_string_aux(penum, &str, gdata, NULL, &text_state); |
1837 | 0 | if (code >= 0) { |
1838 | 0 | pte->returned.current_char = buf[0]; |
1839 | 0 | code = TEXT_PROCESS_INTERVENE; |
1840 | 0 | } |
1841 | 1.49M | } else { |
1842 | 1.49M | str.size = count; |
1843 | 1.49M | code = pdf_process_string_aux(penum, &str, gdata, NULL, &text_state); |
1844 | 1.49M | } |
1845 | 1.49M | return code; |
1846 | 1.49M | } |