1 /* Copyright (C) 2002-2004 artofcode LLC. All rights reserved. 2 3 This software is provided AS-IS with no warranty, either express or 4 implied. 5 6 This software is distributed under license and may not be copied, 7 modified or distributed except as expressly authorized under the terms 8 of the license contained in the file LICENSE in this distribution. 9 10 For more information about licensing, please refer to 11 http://www.ghostscript.com/licensing/. For information on 12 commercial licensing, go to http://www.artifex.com/licensing/ or 13 contact Artifex Software, Inc., 101 Lucas Valley Road #110, 14 San Rafael, CA 94903, U.S.A., +1(415)492-9861. 15 */ 16 17 /* $Id: gdevpdte.c,v 1.70 2005/03/03 13:15:55 igor Exp $ */ 18 /* Encoding-based (Type 1/2/42) text processing for pdfwrite. */ 19 20 #include "math_.h" 21 #include "memory_.h" 22 #include "gx.h" 23 #include "gserrors.h" 24 #include "gsutil.h" 25 #include "gxfcmap.h" 26 #include "gxfcopy.h" 27 #include "gxfont.h" 28 #include "gxfont0.h" 29 #include "gxfont0c.h" 30 #include "gxpath.h" /* for getting current point */ 31 #include "gdevpsf.h" 32 #include "gdevpdfx.h" 33 #include "gdevpdfg.h" 34 #include "gdevpdtx.h" 35 #include "gdevpdtd.h" 36 #include "gdevpdtf.h" 37 #include "gdevpdts.h" 38 #include "gdevpdtt.h" 39 40 private int pdf_char_widths(gx_device_pdf *const pdev, 41 pdf_font_resource_t *pdfont, int ch, 42 gs_font_base *font, 43 pdf_glyph_widths_t *pwidths /* may be NULL */); 44 private int pdf_encode_string(gx_device_pdf *pdev, pdf_text_enum_t *penum, 45 const gs_string *pstr, const gs_glyph *gdata, 46 pdf_font_resource_t **ppdfont); 47 private int pdf_process_string(pdf_text_enum_t *penum, gs_string *pstr, 48 pdf_font_resource_t *pdfont, 49 const gs_matrix *pfmat, 50 pdf_text_process_state_t *ppts); 51 52 /* 53 * Encode and process a string with a simple gs_font. 54 */ 55 int 56 pdf_encode_process_string(pdf_text_enum_t *penum, gs_string *pstr, 57 const gs_glyph *gdata, const gs_matrix *pfmat, 58 pdf_text_process_state_t *ppts) 59 { 60 gx_device_pdf *const pdev = (gx_device_pdf *)penum->dev; 61 pdf_font_resource_t *pdfont; 62 gs_font_base *font; 63 int code = 0; 64 65 switch (penum->current_font->FontType) { 66 case ft_TrueType: 67 case ft_encrypted: 68 case ft_encrypted2: 69 case ft_user_defined: 70 break; 71 default: 72 return_error(gs_error_rangecheck); 73 } 74 font = (gs_font_base *)penum->current_font; 75 76 code = pdf_encode_string(pdev, penum, pstr, gdata, &pdfont); /* Must not change penum. */ 77 if (code < 0) 78 return code; 79 return pdf_process_string(penum, pstr, pdfont, pfmat, ppts); 80 } 81 82 /* 83 * Add char code pair to ToUnicode CMap, 84 * creating the CMap on neccessity. 85 */ 86 int 87 pdf_add_ToUnicode(gx_device_pdf *pdev, gs_font *font, pdf_font_resource_t *pdfont, 88 gs_glyph glyph, gs_char ch) 89 { int code; 90 gs_char unicode; 91 92 if (glyph == GS_NO_GLYPH) 93 return 0; 94 unicode = font->procs.decode_glyph((gs_font *)font, glyph); 95 if (unicode != GS_NO_CHAR) { 96 if (pdfont->cmap_ToUnicode == NULL) { 97 uint num_codes = 256, key_size = 1; 98 99 if (font->FontType == ft_CID_encrypted) { 100 gs_font_cid0 *pfcid = (gs_font_cid0 *)font; 101 102 num_codes = pfcid->cidata.common.CIDCount; 103 key_size = 2; 104 } else if (font->FontType == ft_CID_TrueType) { 105 #if 0 106 gs_font_cid2 *pfcid = (gs_font_cid2 *)font; 107 108 num_codes = pfcid->cidata.common.CIDCount; 109 #else 110 /* Since PScript5.dll creates GlyphNames2Unicode with character codes 111 instead CIDs, and with the WinCharSetFFFF-H2 CMap 112 character codes appears from the range 0-0xFFFF (Bug 687954), 113 we must use the maximal character code value for the ToUnicode 114 code count. */ 115 num_codes = 65536; 116 #endif 117 key_size = 2; 118 } 119 code = gs_cmap_ToUnicode_alloc(pdev->pdf_memory, pdfont->rid, num_codes, key_size, 120 &pdfont->cmap_ToUnicode); 121 if (code < 0) 122 return code; 123 } 124 if (pdfont->cmap_ToUnicode != NULL) 125 gs_cmap_ToUnicode_add_pair(pdfont->cmap_ToUnicode, ch, unicode); 126 } 127 return 0; 128 } 129 130 /* 131 * If the current substream is a charproc, register a font used in it. 132 */ 133 int 134 pdf_register_charproc_resource(gx_device_pdf *pdev, gs_id id, pdf_resource_type_t type) 135 { 136 if (pdev->font3 != 0) { 137 pdf_font_resource_t *pdfont = (pdf_font_resource_t *)pdev->font3; 138 pdf_resource_ref_t *used_resources = pdfont->u.simple.s.type3.used_resources; 139 int i, used_resources_count = pdfont->u.simple.s.type3.used_resources_count; 140 int used_resources_max = pdfont->u.simple.s.type3.used_resources_max; 141 142 for (i = 0; i < used_resources_count; i++) 143 if (used_resources[i].id == id && used_resources[i].type == type) 144 return 0; 145 if (used_resources_count >= used_resources_max) { 146 used_resources_max += 10; 147 used_resources = (pdf_resource_ref_t *)gs_alloc_bytes(pdev->pdf_memory, 148 sizeof(pdf_resource_ref_t) * used_resources_max, 149 "pdf_register_charproc_resource"); 150 if (!used_resources) 151 return_error(gs_error_VMerror); 152 if (used_resources_count) { 153 memcpy(used_resources, pdfont->u.simple.s.type3.used_resources, 154 sizeof(pdf_resource_ref_t) * used_resources_count); 155 gs_free_object(pdev->pdf_memory, pdfont->u.simple.s.type3.used_resources, 156 "pdf_register_charproc_resource"); 157 } 158 pdfont->u.simple.s.type3.used_resources = used_resources; 159 pdfont->u.simple.s.type3.used_resources_max = used_resources_max; 160 } 161 used_resources[used_resources_count].id = id; 162 used_resources[used_resources_count].type = type; 163 pdfont->u.simple.s.type3.used_resources_count = used_resources_count + 1; 164 } 165 return 0; 166 } 167 168 /* 169 * Register charproc fonts with the page or substream. 170 */ 171 int 172 pdf_used_charproc_resources(gx_device_pdf *pdev, pdf_font_resource_t *pdfont) 173 { 174 if (pdfont->where_used & pdev->used_mask) 175 return 0; 176 pdfont->where_used |= pdev->used_mask; 177 if (pdfont->FontType == ft_user_defined) { 178 pdf_resource_ref_t *used_resources = pdfont->u.simple.s.type3.used_resources; 179 int i, used_resources_count = pdfont->u.simple.s.type3.used_resources_count; 180 181 for (i = 0; i < used_resources_count; i++) { 182 pdf_resource_t *pres = 183 pdf_find_resource_by_resource_id(pdev, 184 used_resources[i].type, used_resources[i].id); 185 if (pres == NULL) 186 return_error(gs_error_unregistered); /* Must not happen. */ 187 pres->where_used |= pdev->used_mask; 188 } 189 } 190 return 0; 191 } 192 193 /* 194 * Given a text string and a simple gs_font, return a font resource suitable 195 * for the text string, possibly re-encoding the string. This 196 * may involve creating a font resource and/or adding glyphs and/or Encoding 197 * entries to it. 198 * 199 * Sets *ppdfont. 200 */ 201 private int 202 pdf_encode_string(gx_device_pdf *pdev, pdf_text_enum_t *penum, 203 const gs_string *pstr, const gs_glyph *gdata, 204 pdf_font_resource_t **ppdfont) 205 { 206 gs_font *font = (gs_font *)penum->current_font; 207 pdf_font_resource_t *pdfont = 0; 208 gs_font_base *cfont, *ccfont; 209 int code, i; 210 211 /* 212 * In contradiction with pre-7.20 versions of pdfwrite, 213 * we never re-encode texts due to possible encoding conflict while font merging. 214 */ 215 code = pdf_obtain_font_resource(penum, pstr, &pdfont); 216 if (code < 0) 217 return code; 218 code = pdf_add_resource(pdev, pdev->substream_Resources, "/Font", (pdf_resource_t *)pdfont); 219 if (code < 0) 220 return code; 221 code = pdf_register_charproc_resource(pdev, pdf_resource_id((pdf_resource_t *)pdfont), resourceFont); 222 if (code < 0) 223 return code; 224 cfont = pdf_font_resource_font(pdfont, false); 225 ccfont = pdf_font_resource_font(pdfont, true); 226 for (i = 0; i < pstr->size; ++i) { 227 int ch = pstr->data[i]; 228 pdf_encoding_element_t *pet = &pdfont->u.simple.Encoding[ch]; 229 gs_glyph glyph = (gdata == NULL 230 ? font->procs.encode_char(font, ch, GLYPH_SPACE_NAME) 231 : gdata[i]); 232 233 gs_glyph copied_glyph; 234 gs_const_string gnstr; 235 236 if (glyph == GS_NO_GLYPH || glyph == pet->glyph) 237 continue; 238 if (pet->glyph != GS_NO_GLYPH) { /* encoding conflict */ 239 return_error(gs_error_rangecheck); 240 /* Must not happen because pdf_obtain_font_resource 241 * checks for encoding compatibility. 242 */ 243 } 244 code = font->procs.glyph_name(font, glyph, &gnstr); 245 if (code < 0) 246 return code; /* can't get name of glyph */ 247 if (font->FontType != ft_user_defined) { 248 /* The standard 14 fonts don't have a FontDescriptor. */ 249 code = (pdfont->base_font != 0 ? 250 pdf_base_font_copy_glyph(pdfont->base_font, glyph, (gs_font_base *)font) : 251 pdf_font_used_glyph(pdfont->FontDescriptor, glyph, (gs_font_base *)font)); 252 if (code < 0 && code != gs_error_undefined) 253 return code; 254 if (code == gs_error_undefined) { 255 /* PS font has no such glyph. */ 256 if (bytes_compare(gnstr.data, gnstr.size, (const byte *)".notdef", 7)) { 257 pet->glyph = glyph; 258 pet->str = gnstr; 259 pet->is_difference = true; 260 } 261 } else if (pdfont->base_font == NULL && ccfont != NULL && 262 (gs_copy_glyph_options(font, glyph, (gs_font *)ccfont, COPY_GLYPH_NO_NEW) != 1 || 263 gs_copied_font_add_encoding((gs_font *)ccfont, ch, glyph) < 0)) { 264 /* 265 * The "complete" copy of the font appears incomplete 266 * due to incrementally added glyphs. Drop the "complete" 267 * copy now and continue with subset font only. 268 * 269 * Note that we need to add the glyph to the encoding of the 270 * "complete" font, because "PPI-ProPag 2.6.1.4 (archivePg)" 271 * creates multiple font copies with reduced encodings 272 * (we believe it is poorly designed), 273 * and we can merge the copies back to a single font (see Bug 686875). 274 * We also check whether the encoding is compatible. 275 * It must be compatible here due to the pdf_obtain_font_resource 276 * and ccfont logics, but we want to ensure for safety reason. 277 */ 278 ccfont = NULL; 279 pdf_font_descriptor_drop_complete_font(pdfont->FontDescriptor); 280 } 281 /* 282 * We arbitrarily allow the first encoded character in a given 283 * position to determine the encoding associated with the copied 284 * font. 285 */ 286 copied_glyph = cfont->procs.encode_char((gs_font *)cfont, ch, 287 GLYPH_SPACE_NAME); 288 if (glyph != copied_glyph && 289 gs_copied_font_add_encoding((gs_font *)cfont, ch, glyph) < 0 290 ) 291 pet->is_difference = true; 292 pdfont->used[ch >> 3] |= 0x80 >> (ch & 7); 293 } 294 /* 295 * We always generate ToUnicode for simple fonts, because 296 * we can't detemine in advance, which glyphs the font actually uses. 297 * The decision about writing it out is deferred until pdf_write_font_resource. 298 */ 299 code = pdf_add_ToUnicode(pdev, font, pdfont, glyph, ch); 300 if (code < 0) 301 return code; 302 pet->glyph = glyph; 303 pet->str = gnstr; 304 } 305 *ppdfont = pdfont; 306 return 0; 307 } 308 309 /* 310 * Estimate text bbox. 311 */ 312 private int 313 process_text_estimate_bbox(pdf_text_enum_t *pte, gs_font_base *font, 314 const gs_const_string *pstr, 315 const gs_matrix *pfmat, 316 gs_rect *text_bbox, gs_point *pdpt) 317 { 318 int i; 319 int space_char = 320 (pte->text.operation & TEXT_ADD_TO_SPACE_WIDTH ? 321 pte->text.space.s_char : -1); 322 int WMode = font->WMode; 323 int code = 0; 324 gs_point total = {0, 0}; 325 gs_fixed_point origin; 326 gs_matrix m; 327 int xy_index = pte->xy_index; 328 329 if (font->FontBBox.p.x == font->FontBBox.q.x || 330 font->FontBBox.p.y == font->FontBBox.q.y) 331 return_error(gs_error_undefined); 332 code = gx_path_current_point(pte->path, &origin); 333 if (code < 0) 334 return code; 335 m = ctm_only(pte->pis); 336 m.tx = fixed2float(origin.x); 337 m.ty = fixed2float(origin.y); 338 gs_matrix_multiply(pfmat, &m, &m); 339 for (i = 0; i < pstr->size; ++i) { 340 byte c = pstr->data[i]; 341 gs_rect bbox; 342 gs_point wanted, tpt, p0, p1, p2, p3; 343 gs_glyph glyph = font->procs.encode_char((gs_font *)font, c, 344 GLYPH_SPACE_NAME); 345 gs_glyph_info_t info; 346 int code = font->procs.glyph_info((gs_font *)font, glyph, NULL, 347 GLYPH_INFO_WIDTH0 << WMode, 348 &info); 349 350 if (code < 0) 351 return code; 352 gs_point_transform(font->FontBBox.p.x, font->FontBBox.p.y, &m, &p0); 353 gs_point_transform(font->FontBBox.p.x, font->FontBBox.q.y, &m, &p1); 354 gs_point_transform(font->FontBBox.q.x, font->FontBBox.p.y, &m, &p2); 355 gs_point_transform(font->FontBBox.q.x, font->FontBBox.q.y, &m, &p3); 356 bbox.p.x = min(min(p0.x, p1.x), min(p1.x, p2.x)) + total.x; 357 bbox.p.y = min(min(p0.y, p1.y), min(p1.y, p2.y)) + total.y; 358 bbox.q.x = max(max(p0.x, p1.x), max(p1.x, p2.x)) + total.x; 359 bbox.q.y = max(max(p0.y, p1.y), max(p1.y, p2.y)) + total.y; 360 if (i == 0) 361 *text_bbox = bbox; 362 else 363 rect_merge(*text_bbox, bbox); 364 if (pte->text.operation & TEXT_REPLACE_WIDTHS) { 365 gs_text_replaced_width(&pte->text, xy_index++, &tpt); 366 gs_distance_transform(tpt.x, tpt.y, &ctm_only(pte->pis), &wanted); 367 } else { 368 gs_distance_transform(info.width[WMode].x, 369 info.width[WMode].y, 370 &m, &wanted); 371 if (pte->text.operation & TEXT_ADD_TO_ALL_WIDTHS) { 372 gs_distance_transform(pte->text.delta_all.x, 373 pte->text.delta_all.y, 374 &ctm_only(pte->pis), &tpt); 375 wanted.x += tpt.x; 376 wanted.y += tpt.y; 377 } 378 if (pstr->data[i] == space_char && pte->text.operation & TEXT_ADD_TO_SPACE_WIDTH) { 379 gs_distance_transform(pte->text.delta_space.x, 380 pte->text.delta_space.y, 381 &ctm_only(pte->pis), &tpt); 382 wanted.x += tpt.x; 383 wanted.y += tpt.y; 384 } 385 } 386 total.x += wanted.x; 387 total.y += wanted.y; 388 } 389 *pdpt = total; 390 return 0; 391 } 392 393 private void 394 adjust_first_last_char(pdf_font_resource_t *pdfont, byte *str, int size) 395 { 396 int i; 397 398 for (i = 0; i < size; ++i) { 399 int chr = str[i]; 400 401 if (chr < pdfont->u.simple.FirstChar) 402 pdfont->u.simple.FirstChar = chr; 403 if (chr > pdfont->u.simple.LastChar) 404 pdfont->u.simple.LastChar = chr; 405 } 406 } 407 408 int 409 pdf_shift_text_currentpoint(pdf_text_enum_t *penum, gs_point *wpt) 410 { 411 gs_state *pgs; 412 extern_st(st_gs_state); 413 414 if (gs_object_type(penum->dev->memory, penum->pis) != &st_gs_state) { 415 /* Probably never happens. Not sure though. */ 416 return_error(gs_error_unregistered); 417 } 418 pgs = (gs_state *)penum->pis; 419 return gs_moveto_aux(penum->pis, gx_current_path(pgs), 420 fixed2float(penum->origin.x) + wpt->x, 421 fixed2float(penum->origin.y) + wpt->y); 422 } 423 424 /* 425 * Internal procedure to process a string in a non-composite font. 426 * Doesn't use or set pte->{data,size,index}; may use/set pte->xy_index; 427 * may set penum->returned.total_width. Sets ppts->values. 428 * 429 * Note that the caller is responsible for re-encoding the string, if 430 * necessary; for adding Encoding entries in pdfont; and for copying any 431 * necessary glyphs. penum->current_font provides the gs_font for getting 432 * glyph metrics, but this font's Encoding is not used. 433 */ 434 private int process_text_return_width(const pdf_text_enum_t *pte, 435 gs_font_base *font, 436 pdf_text_process_state_t *ppts, 437 const gs_const_string *pstr, 438 gs_point *pdpt, int *accepted); 439 private int 440 pdf_process_string(pdf_text_enum_t *penum, gs_string *pstr, 441 pdf_font_resource_t *pdfont, const gs_matrix *pfmat, 442 pdf_text_process_state_t *ppts) 443 { 444 gx_device_pdf *const pdev = (gx_device_pdf *)penum->dev; 445 gs_font_base *font = (gs_font_base *)penum->current_font; 446 const gs_text_params_t *text = &penum->text; 447 int code = 0, mask; 448 gs_point width_pt; 449 gs_rect text_bbox; 450 int accepted; 451 452 if (pfmat == 0) 453 pfmat = &font->FontMatrix; 454 if (text->operation & TEXT_RETURN_WIDTH) { 455 code = gx_path_current_point(penum->path, &penum->origin); 456 if (code < 0) 457 return code; 458 } 459 if (text->size == 0) 460 return 0; 461 if (penum->pis->text_rendering_mode != 3 && !(text->operation & TEXT_DO_NONE)) { 462 /* 463 * Acrobat Reader can't handle text with huge coordinates, 464 * so skip the text if it is outside the clip bbox 465 * (Note : it ever fails with type 3 fonts). 466 */ 467 code = process_text_estimate_bbox(penum, font, (gs_const_string *)pstr, pfmat, 468 &text_bbox, &width_pt); 469 if (code == 0) { 470 gs_fixed_rect clip_bbox; 471 gs_rect rect; 472 473 gx_cpath_outer_box(penum->pcpath, &clip_bbox); 474 rect.p.x = fixed2float(clip_bbox.p.x); 475 rect.p.y = fixed2float(clip_bbox.p.y); 476 rect.q.x = fixed2float(clip_bbox.q.x); 477 rect.q.y = fixed2float(clip_bbox.q.y); 478 rect_intersect(rect, text_bbox); 479 if (rect.p.x > rect.q.x || rect.p.y > rect.q.y) { 480 penum->index += pstr->size; 481 goto finish; 482 } 483 } 484 } else { 485 /* We have no penum->pcpath. */ 486 } 487 488 /* 489 * Note that pdf_update_text_state sets all the members of ppts->values 490 * to their current values. 491 */ 492 code = pdf_update_text_state(ppts, penum, pdfont, pfmat); 493 if (code > 0) { 494 /* Try not to emulate ADD_TO_WIDTH if we don't have to. */ 495 if (code & TEXT_ADD_TO_SPACE_WIDTH) { 496 if (!memchr(pstr->data, penum->text.space.s_char, pstr->size)) 497 code &= ~TEXT_ADD_TO_SPACE_WIDTH; 498 } 499 } 500 if (code < 0) 501 return code; 502 mask = code; 503 504 if (text->operation & TEXT_REPLACE_WIDTHS) 505 mask |= TEXT_REPLACE_WIDTHS; 506 507 /* 508 * The only operations left to handle are TEXT_DO_DRAW and 509 * TEXT_RETURN_WIDTH. 510 */ 511 if (mask == 0) { 512 /* 513 * If any character has real_width != Width, we have to process 514 * the string character-by-character. process_text_return_width 515 * will tell us what we need to know. 516 */ 517 if (!(text->operation & (TEXT_DO_DRAW | TEXT_RETURN_WIDTH))) 518 return 0; 519 code = process_text_return_width(penum, font, ppts, 520 (gs_const_string *)pstr, 521 &width_pt, &accepted); 522 if (code < 0) 523 return code; 524 if (code == 0) { 525 /* No characters with redefined widths -- the fast case. */ 526 if (text->operation & TEXT_DO_DRAW || penum->pis->text_rendering_mode == 3) { 527 code = pdf_append_chars(pdev, pstr->data, accepted, 528 width_pt.x, width_pt.y, false); 529 if (code < 0) 530 return code; 531 adjust_first_last_char(pdfont, pstr->data, accepted); 532 penum->index += accepted; 533 } else if (text->operation & TEXT_DO_NONE) 534 penum->index += accepted; 535 } else { 536 /* Use the slow case. Set mask to any non-zero value. */ 537 mask = TEXT_RETURN_WIDTH; 538 } 539 } 540 if (mask) { 541 /* process_text_modify_width destroys text parameters, save them now. */ 542 int index0 = penum->index, xy_index = penum->xy_index; 543 gs_text_params_t text = penum->text; 544 int xy_index_step = (penum->text.x_widths != NULL && /* see gs_text_replaced_width */ 545 penum->text.x_widths == penum->text.y_widths ? 2 : 1); 546 547 if (penum->text.x_widths != NULL) { 548 penum->text.x_widths += xy_index * xy_index_step; 549 } 550 if (penum->text.y_widths != NULL) 551 penum->text.y_widths += xy_index * xy_index_step; 552 penum->xy_index = 0; 553 code = process_text_modify_width(penum, (gs_font *)font, ppts, 554 (gs_const_string *)pstr, 555 &width_pt); 556 if (penum->text.x_widths != NULL) 557 penum->text.x_widths -= xy_index * xy_index_step; 558 if (penum->text.y_widths != NULL) 559 penum->text.y_widths -= xy_index * xy_index_step; 560 penum->xy_index += xy_index; 561 adjust_first_last_char(pdfont, pstr->data, penum->index); 562 penum->text = text; 563 penum->index += index0; 564 if (code < 0) 565 return code; 566 } 567 568 569 finish: 570 /* Finally, return the total width if requested. */ 571 if (!(text->operation & TEXT_RETURN_WIDTH)) 572 return 0; 573 if (text->operation & TEXT_DO_NONE) { 574 /* stringwidth needs to transform to user space. */ 575 gs_point p; 576 577 gs_distance_transform_inverse(width_pt.x, width_pt.y, &ctm_only(penum->pis), &p); 578 penum->returned.total_width.x += p.x; 579 penum->returned.total_width.y += p.y; 580 } else 581 penum->returned.total_width = width_pt; 582 return pdf_shift_text_currentpoint(penum, &width_pt); 583 } 584 585 /* 586 * Get the widths (unmodified and possibly modified) of a given character 587 * in a simple font. May add the widths to the widths cache (pdfont->Widths 588 * and pdf_font_cache_elem::real_widths). Return 1 if the widths were not cached. 589 */ 590 private int 591 pdf_char_widths(gx_device_pdf *const pdev, 592 pdf_font_resource_t *pdfont, int ch, gs_font_base *font, 593 pdf_glyph_widths_t *pwidths /* may be NULL */) 594 { 595 pdf_glyph_widths_t widths; 596 int code; 597 byte *glyph_usage; 598 double *real_widths; 599 int char_cache_size, width_cache_size; 600 pdf_font_resource_t *pdfont1; 601 602 code = pdf_attached_font_resource(pdev, (gs_font *)font, &pdfont1, 603 &glyph_usage, &real_widths, &char_cache_size, &width_cache_size); 604 if (code < 0) 605 return code; 606 if (pdfont1 != pdfont) 607 return_error(gs_error_unregistered); /* Must not happen. */ 608 if (ch < 0 || ch > 255) 609 return_error(gs_error_rangecheck); 610 if (ch >= width_cache_size) 611 return_error(gs_error_unregistered); /* Must not happen. */ 612 if (pwidths == 0) 613 pwidths = &widths; 614 if (font->FontType != ft_user_defined && real_widths[ch] == 0) { 615 /* Might be an unused char, or just not cached. */ 616 gs_glyph glyph = pdfont->u.simple.Encoding[ch].glyph; 617 618 code = pdf_glyph_widths(pdfont, font->WMode, glyph, (gs_font *)font, pwidths, NULL); 619 if (code < 0) 620 return code; 621 if (font->WMode != 0 && code > 0 && !pwidths->replaced_v) { 622 /* 623 * The font has no Metrics2, so it must write 624 * horizontally due to PS spec. 625 * Therefore we need to fill the Widths array, 626 * which is required by PDF spec. 627 * Take it from WMode==0. 628 */ 629 code = pdf_glyph_widths(pdfont, 0, glyph, (gs_font *)font, pwidths, NULL); 630 } 631 if (pwidths->replaced_v) { 632 pdfont->u.simple.v[ch].x = pwidths->real_width.v.x - pwidths->Width.v.x; 633 pdfont->u.simple.v[ch].y = pwidths->real_width.v.y - pwidths->Width.v.y; 634 } else 635 pdfont->u.simple.v[ch].x = pdfont->u.simple.v[ch].y = 0; 636 if (code == 0) { 637 pdfont->Widths[ch] = pwidths->Width.w; 638 real_widths[ch] = pwidths->real_width.w; 639 } 640 } else { 641 if (font->FontType == ft_user_defined) { 642 if (!(pdfont->used[ch >> 3] & 0x80 >> (ch & 7))) 643 return gs_error_undefined; /* The charproc was not accumulated. */ 644 if (!pdev->charproc_just_accumulated && 645 !(pdfont->u.simple.s.type3.cached[ch >> 3] & 0x80 >> (ch & 7))) { 646 /* The charproc uses setcharwidth. 647 Need to accumulate again to check for a glyph variation. */ 648 return gs_error_undefined; 649 } 650 } 651 pwidths->Width.w = pdfont->Widths[ch]; 652 pwidths->Width.v = pdfont->u.simple.v[ch]; 653 if (font->FontType == ft_user_defined) { 654 pwidths->real_width.w = real_widths[ch * 2]; 655 pwidths->Width.xy.x = pwidths->Width.w; 656 pwidths->Width.xy.y = 0; 657 pwidths->real_width.xy.x = real_widths[ch * 2 + 0]; 658 pwidths->real_width.xy.y = real_widths[ch * 2 + 1]; 659 } else if (font->WMode) { 660 pwidths->real_width.w = real_widths[ch]; 661 pwidths->Width.xy.x = 0; 662 pwidths->Width.xy.y = pwidths->Width.w; 663 pwidths->real_width.xy.x = 0; 664 pwidths->real_width.xy.y = pwidths->real_width.w; 665 } else { 666 pwidths->real_width.w = real_widths[ch]; 667 pwidths->Width.xy.x = pwidths->Width.w; 668 pwidths->Width.xy.y = 0; 669 pwidths->real_width.xy.x = pwidths->real_width.w; 670 pwidths->real_width.xy.y = 0; 671 } 672 code = 0; 673 } 674 return code; 675 } 676 677 /* 678 * Compute the total text width (in user space). Return 1 if any 679 * character had real_width != Width, otherwise 0. 680 */ 681 private int 682 process_text_return_width(const pdf_text_enum_t *pte, gs_font_base *font, 683 pdf_text_process_state_t *ppts, 684 const gs_const_string *pstr, 685 gs_point *pdpt, int *accepted) 686 { 687 int i; 688 gs_point w; 689 double scale; 690 gs_point dpt; 691 int num_spaces = 0; 692 int space_char = 693 (pte->text.operation & TEXT_ADD_TO_SPACE_WIDTH ? 694 pte->text.space.s_char : -1); 695 int widths_differ = 0, code; 696 gx_device_pdf *pdev = (gx_device_pdf *)pte->dev; 697 pdf_font_resource_t *pdfont; 698 699 code = pdf_attached_font_resource(pdev, (gs_font *)font, &pdfont, NULL, NULL, NULL, NULL); 700 if (code < 0) 701 return code; 702 if (font->FontType == ft_user_defined) { 703 pdf_font3_scale(pdev, (gs_font *)font, &scale); 704 scale *= ppts->values.size; 705 } else 706 scale = 0.001 * ppts->values.size; 707 for (i = 0, w.x = w.y = 0; i < pstr->size; ++i) { 708 pdf_glyph_widths_t cw; 709 gs_char ch = pstr->data[i]; 710 711 if (font->FontType == ft_user_defined && 712 (i > 0 || !pdev->charproc_just_accumulated) && 713 !(pdfont->u.simple.s.type3.cached[ch >> 3] & (0x80 >> (ch & 7)))) 714 code = gs_error_undefined; 715 else 716 code = pdf_char_widths((gx_device_pdf *)pte->dev, 717 ppts->values.pdfont, ch, font, 718 &cw); 719 if (code < 0) { 720 if (i) 721 break; 722 *accepted = 0; 723 return code; 724 } 725 w.x += cw.real_width.xy.x; 726 w.y += cw.real_width.xy.y; 727 if (cw.real_width.xy.x != cw.Width.xy.x || 728 cw.real_width.xy.y != cw.Width.xy.y 729 ) 730 widths_differ = 1; 731 if (pstr->data[i] == space_char) 732 ++num_spaces; 733 } 734 *accepted = i; 735 gs_distance_transform(w.x * scale, w.y * scale, 736 &ppts->values.matrix, &dpt); 737 if (pte->text.operation & TEXT_ADD_TO_ALL_WIDTHS) { 738 int num_chars = *accepted; 739 gs_point tpt; 740 741 gs_distance_transform(pte->text.delta_all.x, pte->text.delta_all.y, 742 &ctm_only(pte->pis), &tpt); 743 dpt.x += tpt.x * num_chars; 744 dpt.y += tpt.y * num_chars; 745 } 746 if (pte->text.operation & TEXT_ADD_TO_SPACE_WIDTH) { 747 gs_point tpt; 748 749 gs_distance_transform(pte->text.delta_space.x, pte->text.delta_space.y, 750 &ctm_only(pte->pis), &tpt); 751 dpt.x += tpt.x * num_spaces; 752 dpt.y += tpt.y * num_spaces; 753 } 754 *pdpt = dpt; 755 756 return widths_differ; 757 } 758 759 #define RIGHT_SBW 1 /* Old code = 0, new code = 1. */ 760 #if !RIGHT_SBW 761 /* 762 * Retrieve glyph origing shift for WMode = 1 in design units. 763 */ 764 private void 765 pdf_glyph_origin(pdf_font_resource_t *pdfont, int ch, int WMode, gs_point *p) 766 { 767 /* For CID fonts PDF viewers provide glyph origin shift automatically. 768 * Therefore we only need to do for non-CID fonts. 769 */ 770 switch (pdfont->FontType) { 771 case ft_encrypted: 772 case ft_encrypted2: 773 case ft_TrueType: 774 case ft_user_defined: 775 *p = pdfont->u.simple.v[ch]; 776 break; 777 default: 778 p->x = p->y = 0; 779 break; 780 } 781 } 782 #endif 783 784 /* 785 * Emulate TEXT_ADD_TO_ALL_WIDTHS and/or TEXT_ADD_TO_SPACE_WIDTH, 786 * and implement TEXT_REPLACE_WIDTHS if requested. 787 * Uses and updates ppts->values.matrix; uses ppts->values.pdfont. 788 * 789 * Destroys the text parameters in *pte. 790 * The caller must restore them. 791 */ 792 int 793 process_text_modify_width(pdf_text_enum_t *pte, gs_font *font, 794 pdf_text_process_state_t *ppts, 795 const gs_const_string *pstr, 796 gs_point *pdpt) 797 { 798 gx_device_pdf *const pdev = (gx_device_pdf *)pte->dev; 799 double scale; 800 int space_char = 801 (pte->text.operation & TEXT_ADD_TO_SPACE_WIDTH ? 802 pte->text.space.s_char : -1); 803 int code = 0; 804 gs_point start, total; 805 bool composite = (ppts->values.pdfont->FontType == ft_composite); 806 807 if (font->FontType == ft_user_defined) { 808 gx_device_pdf *pdev = (gx_device_pdf *)pte->dev; 809 810 pdf_font3_scale(pdev, font, &scale); 811 scale *= ppts->values.size; 812 } else 813 scale = 0.001 * ppts->values.size; 814 pte->text.data.bytes = pstr->data; 815 pte->text.size = pstr->size; 816 pte->index = 0; 817 pte->text.operation &= ~TEXT_FROM_ANY; 818 pte->text.operation |= TEXT_FROM_STRING; 819 start.x = ppts->values.matrix.tx; 820 start.y = ppts->values.matrix.ty; 821 total.x = total.y = 0; /* user space */ 822 /* 823 * Note that character widths are in design space, but text.delta_* 824 * values and the width value returned in *pdpt are in user space, 825 * and the width values for pdf_append_chars are in device space. 826 */ 827 for (;;) { 828 pdf_glyph_widths_t cw; /* design space */ 829 gs_point did, wanted, tpt; /* user space */ 830 gs_point v = {0, 0}; /* design space */ 831 gs_char chr; 832 gs_glyph glyph; 833 int code, index = pte->index; 834 gs_text_enum_t pte1 = *(gs_text_enum_t *)pte; 835 int FontType; 836 #if RIGHT_SBW 837 bool use_cached_v = true; 838 #endif 839 840 code = pte1.orig_font->procs.next_char_glyph(&pte1, &chr, &glyph); 841 if (code == 2) { /* end of string */ 842 gs_text_enum_copy_dynamic((gs_text_enum_t *)pte, &pte1, true); 843 break; 844 } 845 if (code < 0) 846 return code; 847 if (composite) { /* from process_cmap_text */ 848 gs_font *subfont = pte1.fstack.items[pte1.fstack.depth].font; 849 pdf_font_resource_t *pdsubf = ppts->values.pdfont->u.type0.DescendantFont; 850 851 FontType = pdsubf->FontType; 852 code = pdf_glyph_widths(pdsubf, font->WMode, glyph, subfont, &cw, 853 pte->cdevproc_callout ? pte->cdevproc_result : NULL); 854 } else {/* must be a base font */ 855 FontType = font->FontType; 856 if (chr == GS_NO_CHAR && glyph != GS_NO_GLYPH) { 857 /* glyphshow, we have no char code. Bug 686988.*/ 858 code = pdf_glyph_widths(ppts->values.pdfont, font->WMode, glyph, font, &cw, NULL); 859 use_cached_v = false; /* Since we have no chr and don't call pdf_char_widths. */ 860 } else 861 code = pdf_char_widths((gx_device_pdf *)pte->dev, 862 ppts->values.pdfont, chr, (gs_font_base *)font, 863 &cw); 864 } 865 if (code < 0) { 866 if (index > 0) 867 break; 868 return code; 869 } 870 gs_text_enum_copy_dynamic((gs_text_enum_t *)pte, &pte1, true); 871 #if RIGHT_SBW 872 if (composite || !use_cached_v) { 873 if (cw.replaced_v) { 874 v.x = cw.real_width.v.x - cw.Width.v.x; 875 v.y = cw.real_width.v.y - cw.Width.v.y; 876 } 877 } else 878 v = ppts->values.pdfont->u.simple.v[chr]; 879 if (font->WMode) { 880 /* With WMode 1 v-vector is (WMode 1 origin) - (WMode 0 origin). 881 The glyph shifts in the opposite direction. */ 882 v.x = - v.x; 883 v.y = - v.y; 884 } else { 885 /* With WMode 0 v-vector is (Metrics sb) - (native sb). 886 The glyph shifts in same direction. */ 887 } 888 /* pdf_glyph_origin is not longer used. */ 889 #else 890 if ((pte->text.operation & TEXT_FROM_SINGLE_GLYPH) || 891 (pte->text.operation & TEXT_FROM_GLYPHS)) { 892 v.x = v.y = 0; 893 } else if (composite) { 894 if (cw.replaced_v) { 895 v.x = cw.real_width.v.x - cw.Width.v.x; 896 v.y = cw.real_width.v.y - cw.Width.v.y; 897 } 898 } else 899 pdf_glyph_origin(ppts->values.pdfont, chr, font->WMode, &v); 900 #endif 901 if (v.x != 0 || v.y != 0) { 902 gs_point glyph_origin_shift; 903 double scale0; 904 905 if (FontType == ft_TrueType || FontType == ft_CID_TrueType) 906 scale0 = (float)0.001; 907 else 908 scale0 = 1; 909 #if RIGHT_SBW 910 glyph_origin_shift.x = v.x * scale0; 911 glyph_origin_shift.y = v.y * scale0; 912 #else 913 glyph_origin_shift.x = - v.x * scale0; 914 glyph_origin_shift.y = - v.y * scale0; 915 #endif 916 if (composite) { 917 gs_font *subfont = pte->fstack.items[pte->fstack.depth].font; 918 919 gs_distance_transform(glyph_origin_shift.x, glyph_origin_shift.y, 920 &subfont->FontMatrix, &glyph_origin_shift); 921 } 922 gs_distance_transform(glyph_origin_shift.x, glyph_origin_shift.y, 923 &font->FontMatrix, &glyph_origin_shift); 924 gs_distance_transform(glyph_origin_shift.x, glyph_origin_shift.y, 925 &ctm_only(pte->pis), &glyph_origin_shift); 926 if (glyph_origin_shift.x != 0 || glyph_origin_shift.y != 0) { 927 ppts->values.matrix.tx = start.x + total.x + glyph_origin_shift.x; 928 ppts->values.matrix.ty = start.y + total.y + glyph_origin_shift.y; 929 code = pdf_set_text_state_values(pdev, &ppts->values); 930 if (code < 0) 931 break; 932 } 933 } 934 if (pte->text.operation & TEXT_DO_DRAW) { 935 gs_distance_transform(cw.Width.xy.x * scale, 936 cw.Width.xy.y * scale, 937 &ppts->values.matrix, &did); 938 gs_distance_transform((font->WMode ? 0 : ppts->values.character_spacing), 939 (font->WMode ? ppts->values.character_spacing : 0), 940 &ppts->values.matrix, &tpt); 941 did.x += tpt.x; 942 did.y += tpt.y; 943 if (chr == space_char) { 944 gs_distance_transform((font->WMode ? 0 : ppts->values.word_spacing), 945 (font->WMode ? ppts->values.word_spacing : 0), 946 &ppts->values.matrix, &tpt); 947 did.x += tpt.x; 948 did.y += tpt.y; 949 } 950 code = pdf_append_chars(pdev, pstr->data + index, pte->index - index, did.x, did.y, composite); 951 if (code < 0) 952 break; 953 } else 954 did.x = did.y = 0; 955 if (pte->text.operation & TEXT_REPLACE_WIDTHS) { 956 gs_point dpt; 957 958 code = gs_text_replaced_width(&pte->text, pte->xy_index++, &dpt); 959 if (code < 0) 960 return_error(gs_error_unregistered); 961 gs_distance_transform(dpt.x, dpt.y, &ctm_only(pte->pis), &wanted); 962 } else { 963 gs_distance_transform(cw.real_width.xy.x * scale, 964 cw.real_width.xy.y * scale, 965 &ppts->values.matrix, &wanted); 966 if (pte->text.operation & TEXT_ADD_TO_ALL_WIDTHS) { 967 gs_distance_transform(pte->text.delta_all.x, 968 pte->text.delta_all.y, 969 &ctm_only(pte->pis), &tpt); 970 wanted.x += tpt.x; 971 wanted.y += tpt.y; 972 } 973 if (chr == space_char && pte->text.operation & TEXT_ADD_TO_SPACE_WIDTH) { 974 gs_distance_transform(pte->text.delta_space.x, 975 pte->text.delta_space.y, 976 &ctm_only(pte->pis), &tpt); 977 wanted.x += tpt.x; 978 wanted.y += tpt.y; 979 } 980 } 981 total.x += wanted.x; 982 total.y += wanted.y; 983 if (wanted.x != did.x || wanted.y != did.y) { 984 ppts->values.matrix.tx = start.x + total.x; 985 ppts->values.matrix.ty = start.y + total.y; 986 code = pdf_set_text_state_values(pdev, &ppts->values); 987 if (code < 0) 988 break; 989 } 990 pdev->charproc_just_accumulated = false; 991 } 992 *pdpt = total; 993 return code; 994 } 995 996 /* 997 * Get character code from a glyph code. 998 * An usage of this function is very undesirable, 999 * because a glyph may be unlisted in Encoding. 1000 */ 1001 int 1002 pdf_encode_glyph(gs_font_base *bfont, gs_glyph glyph0, 1003 byte *buf, int buf_size, int *char_code_length) 1004 { 1005 gs_char c; 1006 1007 *char_code_length = 1; 1008 if (*char_code_length > buf_size) 1009 return_error(gs_error_rangecheck); /* Must not happen. */ 1010 for (c = 0; c < 255; c++) { 1011 gs_glyph glyph1 = bfont->procs.encode_char((gs_font *)bfont, c, 1012 GLYPH_SPACE_NAME); 1013 if (glyph1 == glyph0) { 1014 buf[0] = (byte)c; 1015 return 0; 1016 } 1017 } 1018 return_error(gs_error_rangecheck); /* Can't encode. */ 1019 } 1020 1021 /* ---------------- Type 1 or TrueType font ---------------- */ 1022 1023 /* 1024 * Process a text string in a simple font. 1025 */ 1026 int 1027 process_plain_text(gs_text_enum_t *pte, void *vbuf, uint bsize) 1028 { 1029 byte *const buf = vbuf; 1030 uint count; 1031 uint operation = pte->text.operation; 1032 pdf_text_enum_t *penum = (pdf_text_enum_t *)pte; 1033 int code; 1034 gs_string str; 1035 pdf_text_process_state_t text_state; 1036 const gs_glyph *gdata = NULL; 1037 1038 if (operation & (TEXT_FROM_STRING | TEXT_FROM_BYTES)) { 1039 count = pte->text.size - pte->index; 1040 if (bsize < count) 1041 return_error(gs_error_unregistered); /* Must not happen. */ 1042 memcpy(buf, (const byte *)pte->text.data.bytes + pte->index, count); 1043 } else if (operation & (TEXT_FROM_CHARS | TEXT_FROM_SINGLE_CHAR)) { 1044 /* Check that all chars fit in a single byte. */ 1045 const gs_char *cdata; 1046 int i; 1047 1048 if (operation & TEXT_FROM_CHARS) { 1049 cdata = pte->text.data.chars; 1050 count = (pte->text.size - pte->index); 1051 } else { 1052 cdata = &pte->text.data.d_char; 1053 count = 1; 1054 } 1055 if (bsize < count * sizeof(gs_char)) 1056 return_error(gs_error_unregistered); /* Must not happen. */ 1057 for (i = 0; i < count; ++i) { 1058 gs_char chr = cdata[pte->index + i]; 1059 1060 if (chr & ~0xff) 1061 return_error(gs_error_rangecheck); 1062 buf[i] = (byte)chr; 1063 } 1064 } else if (operation & (TEXT_FROM_GLYPHS | TEXT_FROM_SINGLE_GLYPH)) { 1065 /* 1066 * Since PDF has no analogue of 'glyphshow', 1067 * we try to encode glyphs with the current 1068 * font's encoding. If the current font has no encoding, 1069 * or the encoding doesn't contain necessary glyphs, 1070 * the text will be represented with a Type 3 font with 1071 * bitmaps or outlines. 1072 * 1073 * When we fail with encoding (136-01.ps is an example), 1074 * we could locate a PDF font resource or create a new one 1075 * with same outlines and an appropriate encoding. 1076 * Also we could change .notdef entries in the 1077 * copied font (assuming that document designer didn't use 1078 * .notdef for a meanful printing). 1079 * fixme: Not implemented yet. 1080 */ 1081 gs_font *font = pte->current_font; 1082 uint size; 1083 int i; 1084 1085 if (operation & TEXT_FROM_GLYPHS) { 1086 gdata = pte->text.data.glyphs; 1087 size = pte->text.size - pte->index; 1088 } else { 1089 gdata = &pte->text.data.d_glyph; 1090 size = 1; 1091 } 1092 if (!pdf_is_simple_font(font)) 1093 return_error(gs_error_unregistered); /* Must not happen. */ 1094 count = 0; 1095 for (i = 0; i < size; ++i) { 1096 gs_glyph glyph = gdata[pte->index + i]; 1097 int char_code_length; 1098 1099 code = pdf_encode_glyph((gs_font_base *)font, glyph, 1100 buf + count, size - count, &char_code_length); 1101 if (code < 0) 1102 break; 1103 count += char_code_length; 1104 if (operation & TEXT_INTERVENE) 1105 break; /* Just do one character. */ 1106 } 1107 if (i < size) { 1108 pdf_font_resource_t *pdfont; 1109 1110 str.data = buf; 1111 str.size = size; 1112 if (pdf_obtain_font_resource_unencoded(penum, &str, &pdfont, gdata) != 0) { 1113 /* 1114 * pdf_text_process will fall back 1115 * to default implementation. 1116 */ 1117 return code; 1118 } 1119 count = size; 1120 } 1121 /* So far we will use TEXT_FROM_STRING instead 1122 TEXT_FROM_*_GLYPH*. Since we used a single 1123 byte encoding, the character index appears invariant 1124 during this substitution. 1125 */ 1126 } else 1127 return_error(gs_error_rangecheck); 1128 str.data = buf; 1129 if (count > 1 && (operation & TEXT_INTERVENE)) { 1130 /* Just do one character. */ 1131 str.size = 1; 1132 code = pdf_encode_process_string(penum, &str, gdata, NULL, &text_state); 1133 if (code >= 0) { 1134 pte->returned.current_char = buf[0]; 1135 code = TEXT_PROCESS_INTERVENE; 1136 } 1137 } else { 1138 str.size = count; 1139 code = pdf_encode_process_string(penum, &str, gdata, NULL, &text_state); 1140 } 1141 return code; 1142 } 1143