1 /* Copyright (C) 1989, 1995, 1996, 1997, 1998, 1999 Aladdin Enterprises. All rights reserved. 2 3 This software is provided AS-IS with no warranty, either express or 4 implied. 5 6 This software is distributed under license and may not be copied, 7 modified or distributed except as expressly authorized under the terms 8 of the license contained in the file LICENSE in this distribution. 9 10 For more information about licensing, please refer to 11 http://www.ghostscript.com/licensing/. For information on 12 commercial licensing, go to http://www.artifex.com/licensing/ or 13 contact Artifex Software, Inc., 101 Lucas Valley Road #110, 14 San Rafael, CA 94903, U.S.A., +1(415)492-9861. 15 */ 16 17 /* $Id: gxchar.c,v 1.47 2005/07/21 09:53:42 igor Exp $ */ 18 /* Default implementation of text writing */ 19 #include "gx.h" 20 #include "memory_.h" 21 #include "string_.h" 22 #include "gserrors.h" 23 #include "gsstruct.h" 24 #include "gxfixed.h" /* ditto */ 25 #include "gxarith.h" 26 #include "gxmatrix.h" 27 #include "gzstate.h" 28 #include "gxcoord.h" 29 #include "gxdevice.h" 30 #include "gxdevmem.h" 31 #include "gxchar.h" 32 #include "gxfont.h" 33 #include "gxfont0.h" 34 #include "gxfcache.h" 35 #include "gspath.h" 36 #include "gzpath.h" 37 #include "gxfcid.h" 38 39 /* Define whether or not to cache characters rotated by angles other than */ 40 /* multiples of 90 degrees. */ 41 private const bool CACHE_ROTATED_CHARS = true; 42 43 /* Define the maximum size of a full temporary bitmap when rasterizing, */ 44 /* in bits (not bytes). */ 45 private const uint MAX_TEMP_BITMAP_BITS = 80000; 46 47 /* Define whether the show operation uses the character outline data, */ 48 /* as opposed to just needing the width (or nothing). */ 49 #define SHOW_USES_OUTLINE(penum)\ 50 !SHOW_IS(penum, TEXT_DO_NONE | TEXT_DO_CHARWIDTH) 51 52 /* Structure descriptors */ 53 public_st_gs_show_enum(); 54 extern_st(st_gs_text_enum); 55 extern_st(st_gs_state); /* only for testing */ 56 private 57 ENUM_PTRS_BEGIN(show_enum_enum_ptrs) 58 return ENUM_USING(st_gs_text_enum, vptr, size, index - 5); 59 ENUM_PTR(0, gs_show_enum, pgs); 60 ENUM_PTR(1, gs_show_enum, show_gstate); 61 ENUM_PTR3(2, gs_show_enum, dev_cache, dev_cache2, dev_null); 62 ENUM_PTRS_END 63 private RELOC_PTRS_WITH(show_enum_reloc_ptrs, gs_show_enum *eptr) 64 { 65 RELOC_USING(st_gs_text_enum, vptr, size); /* superclass */ 66 RELOC_VAR(eptr->pgs); 67 RELOC_VAR(eptr->show_gstate); 68 RELOC_PTR3(gs_show_enum, dev_cache, dev_cache2, dev_null); 69 } 70 RELOC_PTRS_END 71 72 /* Forward declarations */ 73 private int continue_kshow(gs_show_enum *); 74 private int continue_show(gs_show_enum *); 75 private int continue_show_update(gs_show_enum *); 76 private void show_set_scale(const gs_show_enum *, gs_log2_scale_point *log2_scale); 77 private int show_cache_setup(gs_show_enum *); 78 private int show_state_setup(gs_show_enum *); 79 private int show_origin_setup(gs_state *, fixed, fixed, gs_show_enum * penum); 80 81 /* Accessors for current_char and current_glyph. */ 82 #define CURRENT_CHAR(penum) ((penum)->returned.current_char) 83 #define SET_CURRENT_CHAR(penum, chr)\ 84 ((penum)->returned.current_char = (chr)) 85 #define CURRENT_GLYPH(penum) ((penum)->returned.current_glyph) 86 #define SET_CURRENT_GLYPH(penum, glyph)\ 87 ((penum)->returned.current_glyph = (glyph)) 88 89 /* Allocate a show enumerator. */ 90 gs_show_enum * 91 gs_show_enum_alloc(gs_memory_t * mem, gs_state * pgs, client_name_t cname) 92 { 93 gs_show_enum *penum; 94 95 rc_alloc_struct_1(penum, gs_show_enum, &st_gs_show_enum, mem, 96 return 0, cname); 97 penum->rc.free = rc_free_text_enum; 98 penum->auto_release = true; /* old API */ 99 /* Initialize pointers for GC */ 100 penum->text.operation = 0; /* no pointers relevant */ 101 penum->dev = 0; 102 penum->pgs = pgs; 103 penum->show_gstate = 0; 104 penum->dev_cache = 0; 105 penum->dev_cache2 = 0; 106 penum->fapi_log2_scale.x = penum->fapi_log2_scale.y = -1; 107 penum->fapi_glyph_shift.x = penum->fapi_glyph_shift.y = 0; 108 penum->dev_null = 0; 109 penum->fstack.depth = -1; 110 return penum; 111 } 112 113 /* ------ Driver procedure ------ */ 114 115 private text_enum_proc_resync(gx_show_text_resync); 116 private text_enum_proc_process(gx_show_text_process); 117 private text_enum_proc_is_width_only(gx_show_text_is_width_only); 118 private text_enum_proc_current_width(gx_show_text_current_width); 119 private text_enum_proc_set_cache(gx_show_text_set_cache); 120 private text_enum_proc_retry(gx_show_text_retry); 121 private text_enum_proc_release(gx_show_text_release); /* not default */ 122 123 private const gs_text_enum_procs_t default_text_procs = { 124 gx_show_text_resync, gx_show_text_process, 125 gx_show_text_is_width_only, gx_show_text_current_width, 126 gx_show_text_set_cache, gx_show_text_retry, 127 gx_show_text_release 128 }; 129 130 int 131 gx_default_text_begin(gx_device * dev, gs_imager_state * pis, 132 const gs_text_params_t * text, gs_font * font, 133 gx_path * path, const gx_device_color * pdcolor, 134 const gx_clip_path * pcpath, 135 gs_memory_t * mem, gs_text_enum_t ** ppte) 136 { 137 uint operation = text->operation; 138 bool propagate_charpath = (operation & TEXT_DO_DRAW) != 0; 139 int code; 140 gs_state *pgs = (gs_state *)pis; 141 gs_show_enum *penum; 142 143 /* 144 * For the moment, require pis to be a gs_state *, since all the 145 * procedures for character rendering expect it. 146 */ 147 if (gs_object_type(mem, pis) != &st_gs_state) 148 return_error(gs_error_Fatal); 149 penum = gs_show_enum_alloc(mem, pgs, "gx_default_text_begin"); 150 if (!penum) 151 return_error(gs_error_VMerror); 152 code = gs_text_enum_init((gs_text_enum_t *)penum, &default_text_procs, 153 dev, pis, text, font, path, pdcolor, pcpath, mem); 154 if (code < 0) { 155 gs_free_object(mem, penum, "gx_default_text_begin"); 156 return code; 157 } 158 penum->auto_release = false; /* new API */ 159 penum->level = pgs->level; 160 if (operation & TEXT_DO_ANY_CHARPATH) 161 penum->charpath_flag = 162 (operation & TEXT_DO_FALSE_CHARPATH ? cpm_false_charpath : 163 operation & TEXT_DO_TRUE_CHARPATH ? cpm_true_charpath : 164 operation & TEXT_DO_FALSE_CHARBOXPATH ? cpm_false_charboxpath : 165 operation & TEXT_DO_TRUE_CHARBOXPATH ? cpm_true_charboxpath : 166 operation & TEXT_DO_CHARWIDTH ? cpm_charwidth : 167 cpm_show /* can't happen */ ); 168 else 169 penum->charpath_flag = 170 (propagate_charpath ? pgs->in_charpath : cpm_show); 171 penum->cc = 0; 172 penum->continue_proc = continue_show; 173 /* Note: show_state_setup may reset can_cache. */ 174 switch (penum->charpath_flag) { 175 case cpm_false_charpath: case cpm_true_charpath: 176 penum->can_cache = -1; break; 177 case cpm_false_charboxpath: case cpm_true_charboxpath: 178 penum->can_cache = 0; break; 179 case cpm_charwidth: 180 default: /* cpm_show */ 181 penum->can_cache = 1; break; 182 } 183 code = show_state_setup(penum); 184 if (code < 0) 185 return code; 186 penum->show_gstate = 187 (propagate_charpath && (pgs->in_charpath != 0) ? 188 pgs->show_gstate : pgs); 189 if (!(~operation & (TEXT_DO_NONE | TEXT_RETURN_WIDTH))) { 190 /* This is stringwidth. */ 191 gx_device_null *dev_null = 192 gs_alloc_struct(mem, gx_device_null, &st_device_null, 193 "stringwidth(dev_null)"); 194 195 if (dev_null == 0) 196 return_error(gs_error_VMerror); 197 /* Do an extra gsave and suppress output */ 198 if ((code = gs_gsave(pgs)) < 0) 199 return code; 200 penum->level = pgs->level; /* for level check in show_update */ 201 /* Set up a null device that forwards xfont requests properly. */ 202 gs_make_null_device(dev_null, gs_currentdevice_inline(pgs), mem); 203 pgs->ctm_default_set = false; 204 penum->dev_null = dev_null; 205 /* Retain this device, since it is referenced from the enumerator. */ 206 gx_device_retain((gx_device *)dev_null, true); 207 gs_setdevice_no_init(pgs, (gx_device *) dev_null); 208 /* Establish an arbitrary translation and current point. */ 209 gs_newpath(pgs); 210 gx_translate_to_fixed(pgs, fixed_0, fixed_0); 211 code = gx_path_add_point(pgs->path, fixed_0, fixed_0); 212 if (code < 0) 213 return code; 214 } 215 *ppte = (gs_text_enum_t *)penum; 216 return 0; 217 } 218 219 /* An auxiliary functions for pdfwrite to process type 3 fonts. */ 220 int 221 gx_hld_stringwidth_begin(gs_imager_state * pis, gx_path **path) 222 { 223 gs_state *pgs = (gs_state *)pis; 224 extern_st(st_gs_state); 225 int code; 226 227 if (gs_object_type(pis->memory, pis) != &st_gs_state) 228 return_error(gs_error_unregistered); 229 code = gs_gsave(pgs); 230 if (code < 0) 231 return code; 232 gs_newpath(pgs); 233 *path = pgs->path; 234 gx_translate_to_fixed(pgs, fixed_0, fixed_0); 235 return gx_path_add_point(pgs->path, fixed_0, fixed_0); 236 } 237 238 int 239 gx_default_text_restore_state(gs_text_enum_t *pte) 240 { 241 gs_show_enum *penum; 242 gs_state *pgs; 243 244 if (SHOW_IS(pte, TEXT_DO_NONE)) 245 return 0; 246 penum = (gs_show_enum *)pte; 247 pgs = penum->pgs; 248 return gs_grestore(pgs); 249 } 250 /* ------ Width/cache setting ------ */ 251 252 private int 253 set_cache_device(gs_show_enum *penum, gs_state *pgs, 254 floatp llx, floatp lly, floatp urx, floatp ury); 255 256 /* This is the default implementation of text enumerator set_cache. */ 257 private int 258 gx_show_text_set_cache(gs_text_enum_t *pte, const double *pw, 259 gs_text_cache_control_t control) 260 { 261 gs_show_enum *const penum = (gs_show_enum *)pte; 262 gs_state *pgs = penum->pgs; 263 264 switch (control) { 265 case TEXT_SET_CHAR_WIDTH: 266 return set_char_width(penum, pgs, pw[0], pw[1]); 267 case TEXT_SET_CACHE_DEVICE: { 268 int code = set_char_width(penum, pgs, pw[0], pw[1]); /* default is don't cache */ 269 270 if (code < 0) 271 return code; 272 if (SHOW_IS_ALL_OF(penum, TEXT_DO_NONE | TEXT_INTERVENE)) /* cshow */ 273 return code; 274 return set_cache_device(penum, pgs, pw[2], pw[3], pw[4], pw[5]); 275 } 276 case TEXT_SET_CACHE_DEVICE2: { 277 int code; 278 bool retry = (penum->width_status == sws_retry); 279 280 if (gs_rootfont(pgs)->WMode) { 281 float vx = pw[8], vy = pw[9]; 282 gs_fixed_point pvxy, dvxy; 283 284 gs_fixed_point rewind_pvxy; 285 int rewind_code; 286 287 if ((code = gs_point_transform2fixed(&pgs->ctm, -vx, -vy, &pvxy)) < 0 || 288 (code = gs_distance_transform2fixed(&pgs->ctm, vx, vy, &dvxy)) < 0 289 ) 290 return 0; /* don't cache */ 291 if ((code = set_char_width(penum, pgs, pw[6], pw[7])) < 0) 292 return code; 293 if (SHOW_IS_ALL_OF(penum, TEXT_DO_NONE | TEXT_INTERVENE)) 294 return code; 295 /* Adjust the origin by (vx, vy). */ 296 gx_translate_to_fixed(pgs, pvxy.x, pvxy.y); 297 code = set_cache_device(penum, pgs, pw[2], pw[3], pw[4], pw[5]); 298 if (code != 1) { 299 if (retry) { 300 rewind_code = gs_point_transform2fixed(&pgs->ctm, vx, vy, &rewind_pvxy); 301 if (rewind_code < 0) { 302 /* If the control passes here, something is wrong. */ 303 return_error(gs_error_unregistered); 304 } 305 /* Rewind the origin by (-vx, -vy) if the cache is failed. */ 306 gx_translate_to_fixed(pgs, rewind_pvxy.x, rewind_pvxy.y); 307 } 308 return code; 309 } 310 /* Adjust the character origin too. */ 311 (penum->cc)->offset.x += dvxy.x; 312 (penum->cc)->offset.y += dvxy.y; 313 } else { 314 code = set_char_width(penum, pgs, pw[0], pw[1]); 315 if (code < 0) 316 return code; 317 if (SHOW_IS_ALL_OF(penum, TEXT_DO_NONE | TEXT_INTERVENE)) 318 return code; 319 code = set_cache_device(penum, pgs, pw[2], pw[3], pw[4], pw[5]); 320 } 321 return code; 322 } 323 default: 324 return_error(gs_error_rangecheck); 325 } 326 } 327 328 /* Set the character width. */ 329 /* Note that this returns 1 if the current show operation is */ 330 /* non-displaying (stringwidth or cshow). */ 331 int 332 set_char_width(gs_show_enum *penum, gs_state *pgs, floatp wx, floatp wy) 333 { 334 int code; 335 336 if (penum->width_status != sws_none && penum->width_status != sws_retry) 337 return_error(gs_error_undefined); 338 if (penum->fstack.depth > 0 && 339 penum->fstack.items[penum->fstack.depth].font->FontType == ft_CID_encrypted) { 340 /* We must not convert advance width with a CID font leaf's FontMatrix, 341 because CDevProc is attached to the CID font rather than to its leaf. 342 But show_state_setup sets CTM with the leaf's matrix. 343 Compensate it here with inverse FontMatrix of the leaf. 344 ( We would like to do without an inverse transform, but 345 we don't like to extend general gs_state or gs_show_enum 346 for this particular reason. ) */ 347 const gx_font_stack_item_t *pfsi = &penum->fstack.items[penum->fstack.depth]; 348 gs_point p; 349 350 code = gs_distance_transform_inverse(wx, wy, 351 &gs_cid0_indexed_font(pfsi->font, pfsi->index)->FontMatrix, &p); 352 if (code < 0) 353 return code; 354 wx = p.x; 355 wy = p.y; 356 } 357 if ((code = gs_distance_transform2fixed(&pgs->ctm, wx, wy, &penum->wxy)) < 0) 358 return code; 359 /* Check whether we're setting the scalable width */ 360 /* for a cached xfont character. */ 361 if (penum->cc != 0) { 362 penum->cc->wxy = penum->wxy; 363 penum->width_status = sws_cache_width_only; 364 } else { 365 penum->width_status = sws_no_cache; 366 } 367 if (SHOW_IS_ALL_OF(penum, TEXT_DO_NONE | TEXT_INTERVENE)) /* cshow */ 368 gs_nulldevice(pgs); 369 return !SHOW_IS_DRAWING(penum); 370 } 371 372 void 373 gx_compute_text_oversampling(const gs_show_enum * penum, const gs_font *pfont, 374 int alpha_bits, gs_log2_scale_point *p_log2_scale) 375 { 376 gs_log2_scale_point log2_scale; 377 378 if (alpha_bits == 1) 379 log2_scale.x = log2_scale.y = 0; 380 else if (pfont->PaintType != 0) { 381 /* Don't oversample artificially stroked fonts. */ 382 log2_scale.x = log2_scale.y = 0; 383 } else if (!penum->is_pure_color) { 384 /* Don't oversample characters for rendering in non-pure color. */ 385 log2_scale.x = log2_scale.y = 0; 386 } else { 387 int excess; 388 389 /* Get maximal scale according to cached bitmap size. */ 390 show_set_scale(penum, &log2_scale); 391 /* Reduce the scale to fit into alpha bits. */ 392 excess = log2_scale.x + log2_scale.y - alpha_bits; 393 while (excess > 0) { 394 if (log2_scale.y > 0) { 395 log2_scale.y --; 396 excess--; 397 if (excess == 0) 398 break; 399 } 400 if (log2_scale.x > 0) { 401 log2_scale.x --; 402 excess--; 403 } 404 } 405 } 406 *p_log2_scale = log2_scale; 407 } 408 409 /* Compute glyph raster parameters */ 410 private int 411 compute_glyph_raster_params(gs_show_enum *penum, bool in_setcachedevice, int *alpha_bits, 412 int *depth, 413 gs_fixed_point *subpix_origin, gs_log2_scale_point *log2_scale) 414 { 415 gs_state *pgs = penum->pgs; 416 gx_device *dev = gs_currentdevice_inline(pgs); 417 int code; 418 419 *alpha_bits = (*dev_proc(dev, get_alpha_bits)) (dev, go_text); 420 if (in_setcachedevice) { 421 /* current point should already be in penum->origin */ 422 } else { 423 code = gx_path_current_point_inline(pgs->path, &penum->origin); 424 if (code < 0) { 425 /* For cshow, having no current point is acceptable. */ 426 if (!SHOW_IS(penum, TEXT_DO_NONE)) 427 return code; 428 penum->origin.x = penum->origin.y = 0; /* arbitrary */ 429 } 430 } 431 if (penum->fapi_log2_scale.x != -1) 432 *log2_scale = penum->fapi_log2_scale; 433 else 434 gx_compute_text_oversampling(penum, penum->current_font, *alpha_bits, log2_scale); 435 /* We never oversample over the device alpha_bits, 436 * so that we don't need to scale down. Perhaps it may happen 437 * that we underuse alpha_bits due to a big character raster, 438 * so we must compute log2_depth more accurately : 439 */ 440 *depth = (log2_scale->x + log2_scale->y == 0 ? 441 1 : min(log2_scale->x + log2_scale->y, *alpha_bits)); 442 if (gs_currentaligntopixels(penum->current_font->dir) == 0) { 443 int scx = -1L << (_fixed_shift - log2_scale->x); 444 int rdx = 1L << (_fixed_shift - 1 - log2_scale->x); 445 446 # if 1 /* Ever align Y to pixels to provide an uniform glyph height. */ 447 subpix_origin->y = 0; 448 # else 449 int scy = -1L << (_fixed_shift - log2_scale->y); 450 int rdy = 1L << (_fixed_shift - 1 - log2_scale->y); 451 452 subpix_origin->y = ((penum->origin.y + rdy) & scy) & (fixed_1 - 1); 453 # endif 454 subpix_origin->x = ((penum->origin.x + rdx) & scx) & (fixed_1 - 1); 455 } else 456 subpix_origin->x = subpix_origin->y = 0; 457 return 0; 458 } 459 460 /* Set up the cache device if relevant. */ 461 /* Return 1 if we just set up a cache device. */ 462 /* Used by setcachedevice and setcachedevice2. */ 463 private int 464 set_cache_device(gs_show_enum * penum, gs_state * pgs, floatp llx, floatp lly, 465 floatp urx, floatp ury) 466 { 467 gs_glyph glyph; 468 469 /* See if we want to cache this character. */ 470 if (pgs->in_cachedevice) /* no recursion! */ 471 return 0; 472 if (SHOW_IS_ALL_OF(penum, TEXT_DO_NONE | TEXT_INTERVENE)) { /* cshow */ 473 int code; 474 if_debug0('k', "[k]no cache: cshow"); 475 code = gs_nulldevice(pgs); 476 if (code < 0) 477 return code; 478 return 0; 479 } 480 pgs->in_cachedevice = CACHE_DEVICE_NOT_CACHING; /* disable color/gray/image operators */ 481 /* We can only use the cache if we know the glyph. */ 482 glyph = CURRENT_GLYPH(penum); 483 if (glyph == gs_no_glyph) 484 return 0; 485 /* We can only use the cache if ctm is unchanged */ 486 /* (aside from a possible translation). */ 487 if (penum->can_cache <= 0 || !pgs->char_tm_valid) { 488 if_debug2('k', "[k]no cache: can_cache=%d, char_tm_valid=%d\n", 489 penum->can_cache, (int)pgs->char_tm_valid); 490 return 0; 491 } { 492 const gs_font *pfont = pgs->font; 493 gs_font_dir *dir = pfont->dir; 494 int alpha_bits, depth; 495 gs_log2_scale_point log2_scale; 496 gs_fixed_point subpix_origin; 497 static const fixed max_cdim[3] = 498 { 499 #define max_cd(n)\ 500 (fixed_1 << (arch_sizeof_short * 8 - n)) - (fixed_1 >> n) * 3 501 max_cd(0), max_cd(1), max_cd(2) 502 #undef max_cd 503 }; 504 ushort iwidth, iheight; 505 cached_char *cc; 506 gs_fixed_rect clip_box; 507 int code; 508 509 /* Compute the bounding box of the transformed character. */ 510 /* Since we accept arbitrary transformations, the extrema */ 511 /* may occur in any order; however, we can save some work */ 512 /* by observing that opposite corners before transforming */ 513 /* are still opposite afterwards. */ 514 gs_fixed_point cll, clr, cul, cur, cdim; 515 516 if ((code = gs_distance_transform2fixed(&pgs->ctm, llx, lly, &cll)) < 0 || 517 (code = gs_distance_transform2fixed(&pgs->ctm, llx, ury, &clr)) < 0 || 518 (code = gs_distance_transform2fixed(&pgs->ctm, urx, lly, &cul)) < 0 || 519 (code = gs_distance_transform2fixed(&pgs->ctm, urx, ury, &cur)) < 0 520 ) 521 return 0; /* don't cache */ 522 { 523 fixed ctemp; 524 525 #define swap(a, b) ctemp = a, a = b, b = ctemp 526 #define make_min(a, b) if ( (a) > (b) ) swap(a, b) 527 528 make_min(cll.x, cur.x); 529 make_min(cll.y, cur.y); 530 make_min(clr.x, cul.x); 531 make_min(clr.y, cul.y); 532 #undef make_min 533 #undef swap 534 } 535 /* Now take advantage of symmetry. */ 536 if (clr.x < cll.x) 537 cll.x = clr.x, cur.x = cul.x; 538 if (clr.y < cll.y) 539 cll.y = clr.y, cur.y = cul.y; 540 /* Now cll and cur are the extrema of the box. */ 541 code = compute_glyph_raster_params(penum, true, &alpha_bits, &depth, 542 &subpix_origin, &log2_scale); 543 if (code < 0) 544 return code; 545 #ifdef DEBUG 546 if (gs_debug_c('k')) { 547 dlprintf6("[k]cbox=[%g %g %g %g] scale=%dx%d\n", 548 fixed2float(cll.x), fixed2float(cll.y), 549 fixed2float(cur.x), fixed2float(cur.y), 550 1 << log2_scale.x, 1 << log2_scale.y); 551 dlprintf6("[p] ctm=[%g %g %g %g %g %g]\n", 552 pgs->ctm.xx, pgs->ctm.xy, pgs->ctm.yx, pgs->ctm.yy, 553 pgs->ctm.tx, pgs->ctm.ty); 554 } 555 #endif 556 cdim.x = cur.x - cll.x; 557 cdim.y = cur.y - cll.y; 558 if (cdim.x > max_cdim[log2_scale.x] || 559 cdim.y > max_cdim[log2_scale.y] 560 ) 561 return 0; /* much too big */ 562 iwidth = ((ushort) fixed2int_var(cdim.x) + 2) << log2_scale.x; 563 iheight = ((ushort) fixed2int_var(cdim.y) + 2) << log2_scale.y; 564 if_debug3('k', "[k]iwidth=%u iheight=%u dev_cache %s\n", 565 (uint) iwidth, (uint) iheight, 566 (penum->dev_cache == 0 ? "not set" : "set")); 567 if (penum->dev_cache == 0) { 568 code = show_cache_setup(penum); 569 if (code < 0) 570 return code; 571 } 572 /* 573 * If we're oversampling (i.e., the temporary bitmap is 574 * larger than the final monobit or alpha array) and the 575 * temporary bitmap is large, use incremental conversion 576 * from oversampled bitmap strips to alpha values instead of 577 * full oversampling with compression at the end. 578 */ 579 cc = gx_alloc_char_bits(dir, penum->dev_cache, 580 (iwidth > MAX_TEMP_BITMAP_BITS / iheight && 581 log2_scale.x + log2_scale.y > alpha_bits ? 582 penum->dev_cache2 : NULL), 583 iwidth, iheight, &log2_scale, depth); 584 if (cc == 0) { 585 /* too big for cache or no cache */ 586 gx_path box_path; 587 588 if (penum->current_font->FontType != ft_user_defined && 589 penum->current_font->FontType != ft_CID_user_defined) { 590 /* Most fonts don't paint outside bbox, 591 so render with no clipping. */ 592 return 0; 593 } 594 /* Render with a clip. */ 595 /* show_proceed already did gsave. */ 596 pgs->in_cachedevice = CACHE_DEVICE_NONE; /* Provide a correct grestore on error. */ 597 clip_box.p.x = penum->origin.x - fixed_ceiling(-cll.x); 598 clip_box.p.y = penum->origin.y - fixed_ceiling(-cll.y); 599 clip_box.q.x = clip_box.p.x + int2fixed(iwidth); 600 clip_box.q.y = clip_box.p.y + int2fixed(iheight); 601 gx_path_init_local(&box_path, pgs->memory); 602 code = gx_path_add_rectangle(&box_path, clip_box.p.x, clip_box.p.y, 603 clip_box.q.x, clip_box.q.y); 604 if (code < 0) 605 return code; 606 code = gx_cpath_clip(pgs, pgs->clip_path, &box_path, gx_rule_winding_number); 607 gx_path_free(&box_path, "set_cache_device"); 608 pgs->in_cachedevice = CACHE_DEVICE_NONE_AND_CLIP; 609 return 0; 610 } 611 /* The mins handle transposed coordinate systems.... */ 612 /* Truncate the offsets to avoid artifacts later. */ 613 cc->offset.x = fixed_ceiling(-cll.x); 614 cc->offset.y = fixed_ceiling(-cll.y); 615 if_debug4('k', "[k]width=%u, height=%u, offset=[%g %g]\n", 616 (uint) iwidth, (uint) iheight, 617 fixed2float(cc->offset.x), 618 fixed2float(cc->offset.y)); 619 pgs->in_cachedevice = CACHE_DEVICE_NONE; /* Provide correct grestore */ 620 if ((code = gs_gsave(pgs)) < 0) { 621 gx_free_cached_char(dir, cc); 622 return code; 623 } 624 /* Nothing can go wrong now.... */ 625 penum->cc = cc; 626 cc->code = glyph; 627 cc->wmode = gs_rootfont(pgs)->WMode; 628 cc->wxy = penum->wxy; 629 cc->subpix_origin = subpix_origin; 630 if (penum->pair != 0) 631 cc_set_pair(cc, penum->pair); 632 else 633 cc->pair = 0; 634 /* Install the device */ 635 gx_set_device_only(pgs, (gx_device *) penum->dev_cache); 636 pgs->ctm_default_set = false; 637 /* Adjust the transformation in the graphics context */ 638 /* so that the character lines up with the cache. */ 639 gx_translate_to_fixed(pgs, 640 (cc->offset.x + subpix_origin.x) << log2_scale.x, 641 (cc->offset.y + subpix_origin.y) << log2_scale.y); 642 if ((log2_scale.x | log2_scale.y) != 0) 643 gx_scale_char_matrix(pgs, 1 << log2_scale.x, 644 1 << log2_scale.y); 645 /* Set the initial matrix for the cache device. */ 646 penum->dev_cache->initial_matrix = ctm_only(pgs); 647 /* Set the oversampling factor. */ 648 penum->log2_scale.x = log2_scale.x; 649 penum->log2_scale.y = log2_scale.y; 650 /* Reset the clipping path to match the metrics. */ 651 clip_box.p.x = clip_box.p.y = 0; 652 clip_box.q.x = int2fixed(iwidth); 653 clip_box.q.y = int2fixed(iheight); 654 if ((code = gx_clip_to_rectangle(pgs, &clip_box)) < 0) 655 return code; 656 gx_set_device_color_1(pgs); /* write 1's */ 657 pgs->in_cachedevice = CACHE_DEVICE_CACHING; 658 } 659 penum->width_status = sws_cache; 660 return 1; 661 } 662 663 /* Return the cache device status. */ 664 gs_in_cache_device_t 665 gs_incachedevice(const gs_state *pgs) 666 { 667 return pgs->in_cachedevice; 668 } 669 670 /* ------ Enumerator ------ */ 671 672 /* 673 * Set the encode_char procedure in an enumerator. 674 */ 675 private void 676 show_set_encode_char(gs_show_enum * penum) 677 { 678 penum->encode_char = 679 (SHOW_IS(penum, TEXT_FROM_GLYPHS | TEXT_FROM_SINGLE_GLYPH) ? 680 gs_no_encode_char : 681 gs_show_current_font(penum)->procs.encode_char); 682 } 683 684 /* 685 * Resync a text operation with a different set of parameters. 686 * Currently this is implemented only for changing the data source. 687 */ 688 private int 689 gx_show_text_resync(gs_text_enum_t *pte, const gs_text_enum_t *pfrom) 690 { 691 gs_show_enum *const penum = (gs_show_enum *)pte; 692 int old_index = pte->index; 693 694 if ((pte->text.operation ^ pfrom->text.operation) & ~TEXT_FROM_ANY) 695 return_error(gs_error_rangecheck); 696 pte->text = pfrom->text; 697 if (pte->index == old_index) { 698 show_set_encode_char(penum); 699 return 0; 700 } else 701 return show_state_setup(penum); 702 } 703 704 /* Do the next step of a show (or stringwidth) operation */ 705 private int 706 gx_show_text_process(gs_text_enum_t *pte) 707 { 708 gs_show_enum *const penum = (gs_show_enum *)pte; 709 710 return (*penum->continue_proc)(penum); 711 } 712 713 /* Continuation procedures */ 714 private int show_update(gs_show_enum * penum); 715 private int show_move(gs_show_enum * penum); 716 private int show_proceed(gs_show_enum * penum); 717 private int show_finish(gs_show_enum * penum); 718 private int 719 continue_show_update(gs_show_enum * penum) 720 { 721 int code = show_update(penum); 722 723 if (code < 0) 724 return code; 725 code = show_move(penum); 726 if (code != 0) 727 return code; 728 return show_proceed(penum); 729 } 730 private int 731 continue_show(gs_show_enum * penum) 732 { 733 return show_proceed(penum); 734 } 735 /* For kshow, the CTM or font may have changed, so we have to reestablish */ 736 /* the cached values in the enumerator. */ 737 private int 738 continue_kshow(gs_show_enum * penum) 739 { int code; 740 gs_state *pgs = penum->pgs; 741 742 if (pgs->font != penum->orig_font) 743 gs_setfont(pgs, penum->orig_font); 744 745 code = show_state_setup(penum); 746 747 if (code < 0) 748 return code; 749 return show_proceed(penum); 750 } 751 752 /* Update position */ 753 private int 754 show_update(gs_show_enum * penum) 755 { 756 gs_state *pgs = penum->pgs; 757 cached_char *cc = penum->cc; 758 int code; 759 760 /* Update position for last character */ 761 switch (penum->width_status) { 762 case sws_none: 763 case sws_retry: 764 /* Adobe interpreters assume a character width of 0, */ 765 /* even though the documentation says this is an error.... */ 766 penum->wxy.x = penum->wxy.y = 0; 767 break; 768 case sws_cache: 769 /* Finish installing the cache entry. */ 770 /* If the BuildChar/BuildGlyph procedure did a save and a */ 771 /* restore, it already undid the gsave in setcachedevice. */ 772 /* We have to check for this by comparing levels. */ 773 switch (pgs->level - penum->level) { 774 default: 775 return_error(gs_error_invalidfont); /* WRONG */ 776 case 2: 777 code = gs_grestore(pgs); 778 if (code < 0) 779 return code; 780 case 1: 781 ; 782 } 783 { cached_fm_pair *pair; 784 785 code = gx_lookup_fm_pair(pgs->font, &char_tm_only(pgs), 786 &penum->log2_scale, penum->charpath_flag != cpm_show, &pair); 787 if (code < 0) 788 return code; 789 gx_add_cached_char(pgs->font->dir, penum->dev_cache, 790 cc, pair, &penum->log2_scale); 791 } 792 if (!SHOW_USES_OUTLINE(penum) || 793 penum->charpath_flag != cpm_show 794 ) 795 break; 796 /* falls through */ 797 case sws_cache_width_only: 798 /* Copy the bits to the real output device. */ 799 code = gs_grestore(pgs); 800 if (code < 0) 801 return code; 802 code = gs_state_color_load(pgs); 803 if (code < 0) 804 return code; 805 return gx_image_cached_char(penum, cc); 806 case sws_no_cache: 807 ; 808 } 809 if (penum->charpath_flag != cpm_show) { 810 /* Move back to the character origin, so that */ 811 /* show_move will get us to the right place. */ 812 code = gx_path_add_point(pgs->show_gstate->path, 813 penum->origin.x, penum->origin.y); 814 if (code < 0) 815 return code; 816 } 817 return gs_grestore(pgs); 818 } 819 820 /* Move to next character */ 821 private int 822 show_fast_move(gs_state * pgs, gs_fixed_point * pwxy) 823 { 824 return gs_moveto_aux((gs_imager_state *)pgs, pgs->path, 825 pgs->current_point.x + fixed2float(pwxy->x), 826 pgs->current_point.y + fixed2float(pwxy->y)); 827 } 828 829 /* Get the current character code. */ 830 int gx_current_char(const gs_text_enum_t * pte) 831 { 832 const gs_show_enum *penum = (const gs_show_enum *)pte; 833 gs_char chr = CURRENT_CHAR(penum) & 0xff; 834 int fdepth = penum->fstack.depth; 835 836 if (fdepth > 0) { 837 /* Add in the shifted font number. */ 838 uint fidx = penum->fstack.items[fdepth].index; 839 840 switch (((gs_font_type0 *) (penum->fstack.items[fdepth - 1].font))->data.FMapType) { 841 case fmap_1_7: 842 case fmap_9_7: 843 chr += fidx << 7; 844 break; 845 case fmap_CMap: 846 chr = CURRENT_CHAR(penum); /* the full character */ 847 if (!penum->cmap_code) 848 break; 849 /* falls through */ 850 default: 851 chr += fidx << 8; 852 } 853 } 854 return chr; 855 } 856 857 private int 858 show_move(gs_show_enum * penum) 859 { 860 gs_state *pgs = penum->pgs; 861 862 if (SHOW_IS(penum, TEXT_REPLACE_WIDTHS)) { 863 gs_point dpt; 864 865 gs_text_replaced_width(&penum->text, penum->xy_index - 1, &dpt); 866 gs_distance_transform2fixed(&pgs->ctm, dpt.x, dpt.y, &penum->wxy); 867 } else { 868 double dx = 0, dy = 0; 869 870 if (SHOW_IS_ADD_TO_SPACE(penum)) { 871 gs_char chr = gx_current_char((const gs_text_enum_t *)penum); 872 873 if (chr == penum->text.space.s_char) { 874 dx = penum->text.delta_space.x; 875 dy = penum->text.delta_space.y; 876 } 877 } 878 if (SHOW_IS_ADD_TO_ALL(penum)) { 879 dx += penum->text.delta_all.x; 880 dy += penum->text.delta_all.y; 881 } 882 if (!is_fzero2(dx, dy)) { 883 gs_fixed_point dxy; 884 885 gs_distance_transform2fixed(&pgs->ctm, dx, dy, &dxy); 886 penum->wxy.x += dxy.x; 887 penum->wxy.y += dxy.y; 888 } 889 } 890 if (SHOW_IS_ALL_OF(penum, TEXT_DO_NONE | TEXT_INTERVENE)) { 891 /* HACK for cshow */ 892 penum->continue_proc = continue_kshow; 893 return TEXT_PROCESS_INTERVENE; 894 } 895 /* wxy is in device coordinates */ 896 { 897 int code = show_fast_move(pgs, &penum->wxy); 898 899 if (code < 0) 900 return code; 901 } 902 /* Check for kerning, but not on the last character. */ 903 if (SHOW_IS_DO_KERN(penum) && penum->index < penum->text.size) { 904 penum->continue_proc = continue_kshow; 905 return TEXT_PROCESS_INTERVENE; 906 } 907 return 0; 908 } 909 /* Process next character */ 910 private int 911 show_proceed(gs_show_enum * penum) 912 { 913 gs_state *pgs = penum->pgs; 914 gs_font *pfont; 915 cached_fm_pair *pair = 0; 916 gs_font *rfont = 917 (penum->fstack.depth < 0 ? pgs->font : penum->fstack.items[0].font); 918 int wmode = rfont->WMode; 919 font_proc_next_char_glyph((*next_char_glyph)) = 920 rfont->procs.next_char_glyph; 921 #define get_next_char_glyph(pte, pchr, pglyph)\ 922 (++(penum->xy_index), next_char_glyph(pte, pchr, pglyph)) 923 gs_char chr; 924 gs_glyph glyph; 925 int code; 926 cached_char *cc; 927 gs_log2_scale_point log2_scale; 928 929 if (penum->charpath_flag == cpm_show && SHOW_USES_OUTLINE(penum)) { 930 code = gs_state_color_load(pgs); 931 if (code < 0) 932 return code; 933 } 934 more: /* Proceed to next character */ 935 pfont = (penum->fstack.depth < 0 ? pgs->font : 936 penum->fstack.items[penum->fstack.depth].font); 937 penum->current_font = pfont; 938 /* can_cache >= 0 allows us to use cached characters, */ 939 /* even if we can't make new cache entries. */ 940 if (penum->can_cache >= 0) { 941 /* Loop with cache */ 942 for (;;) { 943 switch ((code = get_next_char_glyph((gs_text_enum_t *)penum, 944 &chr, &glyph)) 945 ) { 946 default: /* error */ 947 return code; 948 case 2: /* done */ 949 return show_finish(penum); 950 case 1: /* font change */ 951 pfont = penum->fstack.items[penum->fstack.depth].font; 952 penum->current_font = pfont; 953 pgs->char_tm_valid = false; 954 show_state_setup(penum); 955 pair = 0; 956 penum->pair = 0; 957 /* falls through */ 958 case 0: /* plain char */ 959 /* 960 * We don't need to set penum->current_char in the 961 * normal cases, but it's needed for widthshow, 962 * kshow, and one strange client, so we may as well 963 * do it here. 964 */ 965 SET_CURRENT_CHAR(penum, chr); 966 /* 967 * Store glyph now, because pdfwrite needs it while 968 * synthezising bitmap fonts (see assign_char_code). 969 */ 970 if (glyph == gs_no_glyph) { 971 glyph = (*penum->encode_char)(pfont, chr, 972 GLYPH_SPACE_NAME); 973 SET_CURRENT_GLYPH(penum, glyph); 974 } else 975 SET_CURRENT_GLYPH(penum, glyph); 976 penum->is_pure_color = gs_color_writes_pure(penum->pgs); /* Save 977 this data for compute_glyph_raster_params to work 978 independently on the color change in BuildChar. 979 Doing it here because cshow proc may modify 980 the graphic state. 981 */ 982 { 983 int alpha_bits, depth; 984 gs_fixed_point subpix_origin; 985 986 code = compute_glyph_raster_params(penum, false, 987 &alpha_bits, &depth, &subpix_origin, &log2_scale); 988 if (code < 0) 989 return code; 990 if (pair == 0) { 991 code = gx_lookup_fm_pair(pfont, &char_tm_only(pgs), &log2_scale, 992 penum->charpath_flag != cpm_show, &pair); 993 if (code < 0) 994 return code; 995 } 996 penum->pair = pair; 997 if (glyph == gs_no_glyph) { 998 cc = 0; 999 goto no_cache; 1000 } 1001 cc = gx_lookup_cached_char(pfont, pair, glyph, wmode, 1002 depth, &subpix_origin); 1003 } 1004 if (cc == 0) { 1005 /* Character is not in cache. */ 1006 /* If possible, try for an xfont before */ 1007 /* rendering from the outline. */ 1008 1009 /* If antialiasing is in effect, don't use xfont */ 1010 if (log2_scale.x + log2_scale.y > 0) 1011 goto no_cache; 1012 if (pfont->ExactSize == fbit_use_outlines || 1013 pfont->PaintType == 2 1014 ) 1015 goto no_cache; 1016 if (pfont->BitmapWidths) { 1017 cc = gx_lookup_xfont_char(pgs, pair, chr, 1018 glyph, wmode); 1019 if (cc == 0) 1020 goto no_cache; 1021 } else { 1022 if (!SHOW_USES_OUTLINE(penum) || 1023 (penum->charpath_flag != cpm_show && 1024 penum->charpath_flag != cpm_charwidth) 1025 ) 1026 goto no_cache; 1027 /* We might have an xfont, but we still */ 1028 /* want the scalable widths. */ 1029 cc = gx_lookup_xfont_char(pgs, pair, chr, 1030 glyph, wmode); 1031 /* Render up to the point of */ 1032 /* setcharwidth or setcachedevice, */ 1033 /* just as for stringwidth. */ 1034 /* This is the only case in which we can */ 1035 /* to go no_cache with cc != 0. */ 1036 goto no_cache; 1037 } 1038 } 1039 /* Character is in cache. */ 1040 /* We might be doing .charboxpath or stringwidth; */ 1041 /* check for these now. */ 1042 if (penum->charpath_flag == cpm_charwidth) { 1043 /* This is charwidth. Just move by the width. */ 1044 DO_NOTHING; 1045 } else if (penum->charpath_flag != cpm_show) { 1046 /* This is .charboxpath. Get the bounding box */ 1047 /* and append it to a path. */ 1048 gx_path box_path; 1049 gs_fixed_point pt; 1050 fixed llx, lly, urx, ury; 1051 1052 code = gx_path_current_point(pgs->path, &pt); 1053 if (code < 0) 1054 return code; 1055 llx = fixed_rounded(pt.x - cc->offset.x) + 1056 int2fixed(penum->ftx); 1057 lly = fixed_rounded(pt.y - cc->offset.y) + 1058 int2fixed(penum->fty); 1059 urx = llx + int2fixed(cc->width), 1060 ury = lly + int2fixed(cc->height); 1061 gx_path_init_local(&box_path, pgs->memory); 1062 code = 1063 gx_path_add_rectangle(&box_path, llx, lly, 1064 urx, ury); 1065 if (code >= 0) 1066 code = 1067 gx_path_add_char_path(pgs->show_gstate->path, 1068 &box_path, 1069 penum->charpath_flag); 1070 if (code >= 0) 1071 code = gx_path_add_point(pgs->path, pt.x, pt.y); 1072 gx_path_free(&box_path, "show_proceed(box path)"); 1073 if (code < 0) 1074 return code; 1075 } else if (SHOW_IS_DRAWING(penum)) { 1076 code = gx_image_cached_char(penum, cc); 1077 if (code < 0) 1078 return code; 1079 else if (code > 0) { 1080 cc = 0; 1081 goto no_cache; 1082 } 1083 } 1084 if (SHOW_IS_SLOW(penum)) { 1085 /* Split up the assignment so that the */ 1086 /* Watcom compiler won't reserve esi/edi. */ 1087 penum->wxy.x = cc->wxy.x; 1088 penum->wxy.y = cc->wxy.y; 1089 code = show_move(penum); 1090 } else 1091 code = show_fast_move(pgs, &cc->wxy); 1092 if (code) { 1093 /* Might be kshow, glyph is stored above. */ 1094 return code; 1095 } 1096 } 1097 } 1098 } else { 1099 /* Can't use cache */ 1100 switch ((code = get_next_char_glyph((gs_text_enum_t *)penum, 1101 &chr, &glyph)) 1102 ) { 1103 default: 1104 return code; 1105 case 2: 1106 return show_finish(penum); 1107 case 1: 1108 pfont = penum->fstack.items[penum->fstack.depth].font; 1109 penum->current_font = pfont; 1110 show_state_setup(penum); 1111 pair = 0; 1112 case 0: 1113 { int alpha_bits, depth; 1114 gs_log2_scale_point log2_scale; 1115 gs_fixed_point subpix_origin; 1116 1117 code = compute_glyph_raster_params(penum, false, &alpha_bits, &depth, &subpix_origin, &log2_scale); 1118 if (code < 0) 1119 return code; 1120 if (pair == 0) { 1121 code = gx_lookup_fm_pair(pfont, &char_tm_only(pgs), &log2_scale, 1122 penum->charpath_flag != cpm_show, &pair); 1123 if (code < 0) 1124 return code; 1125 } 1126 penum->pair = pair; 1127 } 1128 } 1129 SET_CURRENT_CHAR(penum, chr); 1130 if (glyph == gs_no_glyph) { 1131 glyph = (*penum->encode_char)(pfont, chr, GLYPH_SPACE_NAME); 1132 } 1133 SET_CURRENT_GLYPH(penum, glyph); 1134 cc = 0; 1135 } 1136 no_cache: 1137 /* 1138 * We must call the client's rendering code. Normally, 1139 * we only do this if the character is not cached (cc = 0); 1140 * however, we also must do this if we have an xfont but 1141 * are using scalable widths. In this case, and only this case, 1142 * we get here with cc != 0. penum->current_char and penum->current_glyph 1143 * has already been set. 1144 */ 1145 if ((code = gs_gsave(pgs)) < 0) 1146 return code; 1147 /* Set the font to the current descendant font. */ 1148 pgs->font = pfont; 1149 /* Reset the in_cachedevice flag, so that a recursive show */ 1150 /* will use the cache properly. */ 1151 pgs->in_cachedevice = CACHE_DEVICE_NONE; 1152 /* Set the charpath data in the graphics context if necessary, */ 1153 /* so that fill and stroke will add to the path */ 1154 /* rather than having their usual effect. */ 1155 pgs->in_charpath = penum->charpath_flag; 1156 pgs->show_gstate = 1157 (penum->show_gstate == pgs ? pgs->saved : penum->show_gstate); 1158 pgs->stroke_adjust = false; /* per specification */ 1159 { 1160 gs_fixed_point cpt; 1161 gx_path *ppath = pgs->path; 1162 1163 if ((code = gx_path_current_point_inline(ppath, &cpt)) < 0) { 1164 /* For cshow, having no current point is acceptable. */ 1165 if (!SHOW_IS(penum, TEXT_DO_NONE)) 1166 goto rret; 1167 cpt.x = cpt.y = 0; /* arbitrary */ 1168 } 1169 penum->origin.x = cpt.x; 1170 penum->origin.y = cpt.y; 1171 /* Normally, char_tm is valid because of show_state_setup, */ 1172 /* but if we're in a cshow, it may not be. */ 1173 gs_currentcharmatrix(pgs, NULL, true); 1174 #if 1 /*USE_FPU <= 0 */ 1175 if (pgs->ctm.txy_fixed_valid && pgs->char_tm.txy_fixed_valid) { 1176 fixed tx = pgs->ctm.tx_fixed; 1177 fixed ty = pgs->ctm.ty_fixed; 1178 1179 gs_settocharmatrix(pgs); 1180 cpt.x += pgs->ctm.tx_fixed - tx; 1181 cpt.y += pgs->ctm.ty_fixed - ty; 1182 } else 1183 #endif 1184 { 1185 double tx = pgs->ctm.tx; 1186 double ty = pgs->ctm.ty; 1187 double fpx, fpy; 1188 1189 gs_settocharmatrix(pgs); 1190 fpx = fixed2float(cpt.x) + (pgs->ctm.tx - tx); 1191 fpy = fixed2float(cpt.y) + (pgs->ctm.ty - ty); 1192 #define f_fits_in_fixed(f) f_fits_in_bits(f, fixed_int_bits) 1193 if (!(f_fits_in_fixed(fpx) && f_fits_in_fixed(fpy))) { 1194 gs_note_error(code = gs_error_limitcheck); 1195 goto rret; 1196 } 1197 cpt.x = float2fixed(fpx); 1198 cpt.y = float2fixed(fpy); 1199 } 1200 gs_newpath(pgs); 1201 code = show_origin_setup(pgs, cpt.x, cpt.y, penum); 1202 if (code < 0) 1203 goto rret; 1204 } 1205 penum->width_status = sws_none; 1206 penum->continue_proc = continue_show_update; 1207 /* Reset the sampling scale. */ 1208 penum->log2_scale.x = penum->log2_scale.y = 0; 1209 /* Try using the build procedure in the font. */ 1210 /* < 0 means error, 0 means success, 1 means failure. */ 1211 penum->cc = cc; /* set this now for build procedure */ 1212 code = (*pfont->procs.build_char)((gs_text_enum_t *)penum, pgs, pfont, 1213 chr, glyph); 1214 if (code < 0) { 1215 discard(gs_note_error(code)); 1216 goto rret; 1217 } 1218 if (code == 0) { 1219 code = show_update(penum); 1220 if (code < 0) 1221 goto rret; 1222 /* Note that show_update does a grestore.... */ 1223 code = show_move(penum); 1224 if (code) 1225 return code; /* ... so don't go to rret here. */ 1226 goto more; 1227 } 1228 /* 1229 * Some BuildChar procedures do a save before the setcachedevice, 1230 * and a restore at the end. If we waited to allocate the cache 1231 * device until the setcachedevice, we would attempt to free it 1232 * after the restore. Therefore, allocate it now. 1233 */ 1234 if (penum->dev_cache == 0) { 1235 code = show_cache_setup(penum); 1236 if (code < 0) 1237 goto rret; 1238 } 1239 return TEXT_PROCESS_RENDER; 1240 /* If we get an error while setting up for BuildChar, */ 1241 /* we must undo the partial setup. */ 1242 rret:gs_grestore(pgs); 1243 return code; 1244 #undef get_next_char_glyph 1245 } 1246 1247 /* 1248 * Prepare to retry rendering of the current character. (This is only used 1249 * in one place in zchar1.c; a different approach may be better.) 1250 */ 1251 private int 1252 gx_show_text_retry(gs_text_enum_t *pte) 1253 { 1254 gs_show_enum *const penum = (gs_show_enum *)pte; 1255 1256 if (penum->cc) { 1257 gs_font *pfont = penum->current_font; 1258 1259 gx_free_cached_char(pfont->dir, penum->cc); 1260 penum->cc = 0; 1261 } 1262 gs_grestore(penum->pgs); 1263 penum->width_status = sws_retry; 1264 penum->log2_scale.x = penum->log2_scale.y = 0; 1265 penum->pair = 0; 1266 return 0; 1267 } 1268 1269 /* Finish show or stringwidth */ 1270 private int 1271 show_finish(gs_show_enum * penum) 1272 { 1273 gs_state *pgs = penum->pgs; 1274 int code, rcode; 1275 1276 if (penum->auto_release) 1277 penum->procs->release((gs_text_enum_t *)penum, "show_finish"); 1278 if (!SHOW_IS_STRINGWIDTH(penum)) 1279 return 0; 1280 /* Save the accumulated width before returning, */ 1281 /* and undo the extra gsave. */ 1282 code = gs_currentpoint(pgs, &penum->returned.total_width); 1283 rcode = gs_grestore(pgs); 1284 return (code < 0 ? code : rcode); 1285 } 1286 1287 /* Release the structure. */ 1288 private void 1289 gx_show_text_release(gs_text_enum_t *pte, client_name_t cname) 1290 { 1291 gs_show_enum *const penum = (gs_show_enum *)pte; 1292 1293 penum->cc = 0; 1294 if (penum->dev_cache2) { 1295 gx_device_retain((gx_device *)penum->dev_cache2, false); 1296 penum->dev_cache2 = 0; 1297 } 1298 if (penum->dev_cache) { 1299 gx_device_retain((gx_device *)penum->dev_cache, false); 1300 penum->dev_cache = 0; 1301 } 1302 if (penum->dev_null) { 1303 gx_device_retain((gx_device *)penum->dev_null, false); 1304 penum->dev_null = 0; 1305 } 1306 gx_default_text_release(pte, cname); 1307 } 1308 1309 /* ------ Miscellaneous accessors ------ */ 1310 1311 /* Return the charpath mode. */ 1312 gs_char_path_mode 1313 gs_show_in_charpath(const gs_show_enum * penum) 1314 { 1315 return penum->charpath_flag; 1316 } 1317 1318 /* Return true if we only need the width from the rasterizer */ 1319 /* and can short-circuit the full rendering of the character, */ 1320 /* false if we need the actual character bits. */ 1321 /* This is only meaningful just before calling gs_setcharwidth or */ 1322 /* gs_setcachedevice[2]. */ 1323 /* Note that we can't do this if the procedure has done any extra [g]saves. */ 1324 private bool 1325 gx_show_text_is_width_only(const gs_text_enum_t *pte) 1326 { 1327 const gs_show_enum *const penum = (const gs_show_enum *)pte; 1328 1329 /* penum->cc will be non-zero iff we are calculating */ 1330 /* the scalable width for an xfont character. */ 1331 return ((!SHOW_USES_OUTLINE(penum) || penum->cc != 0) && 1332 penum->pgs->level == penum->level + 1); 1333 } 1334 1335 /* Return the width of the just-enumerated character (for cshow). */ 1336 private int 1337 gx_show_text_current_width(const gs_text_enum_t *pte, gs_point *pwidth) 1338 { 1339 const gs_show_enum *const penum = (const gs_show_enum *)pte; 1340 1341 return gs_idtransform(penum->pgs, 1342 fixed2float(penum->wxy.x), 1343 fixed2float(penum->wxy.y), pwidth); 1344 } 1345 1346 /* Return the current font for cshow. */ 1347 gs_font * 1348 gs_show_current_font(const gs_show_enum * penum) 1349 { 1350 return (penum->fstack.depth < 0 ? penum->pgs->font : 1351 penum->fstack.items[penum->fstack.depth].font); 1352 } 1353 1354 /* ------ Internal routines ------ */ 1355 1356 private inline bool 1357 is_matrix_good_for_caching(const gs_matrix_fixed *m) 1358 { 1359 /* Skewing or non-rectangular rotation are not supported, 1360 but we ignore a small noise skew. */ 1361 const float axx = any_abs(m->xx), axy = any_abs(m->xy); 1362 const float ayx = any_abs(m->yx), ayy = any_abs(m->yy); 1363 const float thr = 5000; /* examples/alphabet.ps */ 1364 1365 if (ayx * thr < axx || axy * thr < ayy) 1366 return true; 1367 if (axx * thr < ayx || ayy * thr < axy) 1368 return true; 1369 return false; 1370 } 1371 1372 /* Initialize the gstate-derived parts of a show enumerator. */ 1373 /* We do this both when starting the show operation, */ 1374 /* and when returning from the kshow callout. */ 1375 /* Uses only penum->pgs, penum->fstack. */ 1376 private int 1377 show_state_setup(gs_show_enum * penum) 1378 { 1379 gs_state *pgs = penum->pgs; 1380 gx_clip_path *pcpath; 1381 gs_font *pfont; 1382 1383 if (penum->fstack.depth <= 0) { 1384 pfont = pgs->font; 1385 gs_currentcharmatrix(pgs, NULL, 1); /* make char_tm valid */ 1386 } else { 1387 /* We have to concatenate the parent's FontMatrix as well. */ 1388 gs_matrix mat; 1389 const gx_font_stack_item_t *pfsi = 1390 &penum->fstack.items[penum->fstack.depth]; 1391 1392 pfont = pfsi->font; 1393 gs_matrix_multiply(&pfont->FontMatrix, 1394 &pfsi[-1].font->FontMatrix, &mat); 1395 if (pfont->FontType == ft_CID_encrypted) { 1396 /* concatenate the Type9 leaf's matrix */ 1397 gs_matrix_multiply(&mat, 1398 &(gs_cid0_indexed_font(pfont, pfsi->index)->FontMatrix), &mat); 1399 } 1400 gs_setcharmatrix(pgs, &mat); 1401 } 1402 penum->current_font = pfont; 1403 /* Skewing or non-rectangular rotation are not supported. */ 1404 if (!CACHE_ROTATED_CHARS && is_matrix_good_for_caching(&pgs->char_tm)) 1405 penum->can_cache = 0; 1406 if (penum->can_cache >= 0 && 1407 gx_effective_clip_path(pgs, &pcpath) >= 0 1408 ) { 1409 gs_fixed_rect cbox; 1410 1411 gx_cpath_inner_box(pcpath, &cbox); 1412 /* Since characters occupy an integral number of pixels, */ 1413 /* we can (and should) round the inner clipping box */ 1414 /* outward rather than inward. */ 1415 penum->ibox.p.x = fixed2int_var(cbox.p.x); 1416 penum->ibox.p.y = fixed2int_var(cbox.p.y); 1417 penum->ibox.q.x = fixed2int_var_ceiling(cbox.q.x); 1418 penum->ibox.q.y = fixed2int_var_ceiling(cbox.q.y); 1419 gx_cpath_outer_box(pcpath, &cbox); 1420 penum->obox.p.x = fixed2int_var(cbox.p.x); 1421 penum->obox.p.y = fixed2int_var(cbox.p.y); 1422 penum->obox.q.x = fixed2int_var_ceiling(cbox.q.x); 1423 penum->obox.q.y = fixed2int_var_ceiling(cbox.q.y); 1424 #if 1 /*USE_FPU <= 0 */ 1425 if (pgs->ctm.txy_fixed_valid && pgs->char_tm.txy_fixed_valid) { 1426 penum->ftx = (int)fixed2long(pgs->char_tm.tx_fixed - 1427 pgs->ctm.tx_fixed); 1428 penum->fty = (int)fixed2long(pgs->char_tm.ty_fixed - 1429 pgs->ctm.ty_fixed); 1430 } else { 1431 #endif 1432 double fdx = pgs->char_tm.tx - pgs->ctm.tx; 1433 double fdy = pgs->char_tm.ty - pgs->ctm.ty; 1434 1435 #define int_bits (arch_sizeof_int * 8 - 1) 1436 if (!(f_fits_in_bits(fdx, int_bits) && 1437 f_fits_in_bits(fdy, int_bits)) 1438 ) 1439 return_error(gs_error_limitcheck); 1440 #undef int_bits 1441 penum->ftx = (int)fdx; 1442 penum->fty = (int)fdy; 1443 } 1444 } 1445 show_set_encode_char(penum); 1446 return 0; 1447 } 1448 1449 /* Set the suggested oversampling scale for character rendering. */ 1450 private void 1451 show_set_scale(const gs_show_enum * penum, gs_log2_scale_point *log2_scale) 1452 { 1453 /* 1454 * Decide whether to oversample. 1455 * We have to decide this each time setcachedevice is called. 1456 */ 1457 const gs_state *pgs = penum->pgs; 1458 1459 if ((penum->charpath_flag == cpm_show || 1460 penum->charpath_flag == cpm_charwidth) && 1461 SHOW_USES_OUTLINE(penum) && 1462 /* gx_path_is_void_inline(pgs->path) && */ 1463 /* Oversampling rotated characters doesn't work well. */ 1464 is_matrix_good_for_caching(&pgs->char_tm) 1465 ) { 1466 const gs_font_base *pfont = (const gs_font_base *)penum->current_font; 1467 gs_fixed_point extent; 1468 int code = gs_distance_transform2fixed(&pgs->char_tm, 1469 pfont->FontBBox.q.x - pfont->FontBBox.p.x, 1470 pfont->FontBBox.q.y - pfont->FontBBox.p.y, 1471 &extent); 1472 1473 if (code >= 0) { 1474 int sx = 1475 (any_abs(extent.x) < int2fixed(60) ? 2 : 1476 any_abs(extent.x) < int2fixed(200) ? 1 : 1477 0); 1478 int sy = 1479 (any_abs(extent.y) < int2fixed(60) ? 2 : 1480 any_abs(extent.y) < int2fixed(200) ? 1 : 1481 0); 1482 1483 /* If we oversample at all, make sure we do it */ 1484 /* in both X and Y. */ 1485 if (sx == 0 && sy != 0) 1486 sx = 1; 1487 else if (sy == 0 && sx != 0) 1488 sy = 1; 1489 log2_scale->x = sx; 1490 log2_scale->y = sy; 1491 return; 1492 } 1493 } 1494 /* By default, don't scale. */ 1495 log2_scale->x = log2_scale->y = 0; 1496 } 1497 1498 /* Set up the cache device and related information. */ 1499 /* Note that we always allocate both cache devices, */ 1500 /* even if we only use one of them. */ 1501 private int 1502 show_cache_setup(gs_show_enum * penum) 1503 { 1504 gs_state *pgs = penum->pgs; 1505 gs_memory_t *mem = penum->memory; 1506 gx_device_memory *dev = 1507 gs_alloc_struct(mem, gx_device_memory, &st_device_memory, 1508 "show_cache_setup(dev_cache)"); 1509 gx_device_memory *dev2 = 1510 gs_alloc_struct(mem, gx_device_memory, &st_device_memory, 1511 "show_cache_setup(dev_cache2)"); 1512 1513 if (dev == 0 || dev2 == 0) { 1514 gs_free_object(mem, dev2, "show_cache_setup(dev_cache2)"); 1515 gs_free_object(mem, dev, "show_cache_setup(dev_cache)"); 1516 return_error(gs_error_VMerror); 1517 } 1518 /* 1519 * We only initialize the devices for the sake of the GC, 1520 * (since we have to re-initialize dev as either a mem_mono 1521 * or a mem_abuf device before actually using it) and also 1522 * to set its memory pointer. 1523 */ 1524 gs_make_mem_mono_device(dev, mem, gs_currentdevice_inline(pgs)); 1525 penum->dev_cache = dev; 1526 gs_make_mem_mono_device(dev2, mem, gs_currentdevice_inline(pgs)); 1527 penum->dev_cache2 = dev2; 1528 /* Retain these devices, since they are referenced from the enumerator. */ 1529 gx_device_retain((gx_device *)dev, true); 1530 gx_device_retain((gx_device *)dev2, true); 1531 return 0; 1532 } 1533 1534 /* Set the character origin as the origin of the coordinate system. */ 1535 /* Used before rendering characters, and for moving the origin */ 1536 /* in setcachedevice2 when WMode=1. */ 1537 private int 1538 show_origin_setup(gs_state * pgs, fixed cpt_x, fixed cpt_y, gs_show_enum * penum) 1539 { 1540 if (penum->charpath_flag == cpm_show) { 1541 /* Round the translation in the graphics state. */ 1542 /* This helps prevent rounding artifacts later. */ 1543 if (gs_currentaligntopixels(penum->current_font->dir) == 0) { 1544 int scx = -1L << (_fixed_shift - penum->log2_scale.x); 1545 int scy = -1L << (_fixed_shift - penum->log2_scale.y); 1546 int rdx = 1L << (_fixed_shift - 1 - penum->log2_scale.x); 1547 int rdy = 1L << (_fixed_shift - 1 - penum->log2_scale.y); 1548 1549 cpt_x = (cpt_x + rdx) & scx; 1550 cpt_y = (cpt_y + rdy) & scy; 1551 } else { 1552 cpt_x = fixed_rounded(cpt_x); 1553 cpt_y = fixed_rounded(cpt_y); 1554 } 1555 } 1556 /* 1557 * BuildChar procedures expect the current point to be undefined, 1558 * so we omit the gx_path_add_point with ctm.t*_fixed. 1559 */ 1560 return gx_translate_to_fixed(pgs, cpt_x, cpt_y); 1561 } 1562