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