1
/* Copyright (C) 2001-2006 Artifex Software, Inc.
4
This software is provided AS-IS with no warranty, either express or
7
This software is distributed under license and may not be copied, modified
8
or distributed except as expressly authorized under the terms of that
9
license. Refer to licensing information at http://www.artifex.com/
10
or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134,
11
San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information.
14
/*$Id: zchar.c 9222 2008-11-16 14:47:49Z leonardo $ */
15
/* Character operators */
22
#include "gxmatrix.h" /* for ifont.h */
23
#include "gxdevice.h" /* for gxfont.h */
28
#include "dstack.h" /* for stack depth */
42
extern bool CPSI_mode;
44
/* Forward references */
45
static bool map_glyph_to_char(const gs_memory_t *mem,
46
const ref *, const ref *, ref *);
47
static int finish_show(i_ctx_t *);
48
static int op_show_cleanup(i_ctx_t *);
49
static int op_show_return_width(i_ctx_t *, uint, double *);
53
zshow(i_ctx_t *i_ctx_p)
56
gs_text_enum_t *penum;
57
int code = op_show_setup(i_ctx_p, op);
60
(code = gs_show_begin(igs, op->value.bytes, r_size(op), imemory, &penum)) < 0)
62
*(op_proc_t *)&penum->enum_client_data = zshow;
63
if ((code = op_show_finish_setup(i_ctx_p, penum, 1, finish_show)) < 0) {
64
ifree_object(penum, "op_show_enum_setup");
67
return op_show_continue_pop(i_ctx_p, 1);
70
/* <ax> <ay> <string> ashow - */
72
zashow(i_ctx_t *i_ctx_p)
75
gs_text_enum_t *penum;
77
int code = num_params(op - 1, 2, axy);
80
(code = op_show_setup(i_ctx_p, op)) != 0 ||
81
(code = gs_ashow_begin(igs, axy[0], axy[1], op->value.bytes, r_size(op), imemory, &penum)) < 0)
83
*(op_proc_t *)&penum->enum_client_data = zashow;
84
if ((code = op_show_finish_setup(i_ctx_p, penum, 3, finish_show)) < 0) {
85
ifree_object(penum, "op_show_enum_setup");
88
return op_show_continue_pop(i_ctx_p, 3);
91
/* <cx> <cy> <char> <string> widthshow - */
93
zwidthshow(i_ctx_t *i_ctx_p)
96
gs_text_enum_t *penum;
100
if ((code = op_show_setup(i_ctx_p, op)) != 0 )
102
check_type(op[-1], t_integer);
103
if (gs_currentfont(igs)->FontType == ft_composite) {
104
if ((gs_char) (op[-1].value.intval) != op[-1].value.intval)
105
return_error(e_rangecheck);
107
if (op[-1].value.intval < 0 || op[-1].value.intval > 255)
108
return_error(e_rangecheck); /* per PLRM and CET 13-26 */
110
if ((code = num_params(op - 2, 2, cxy)) < 0 )
112
if ((code = gs_widthshow_begin(igs, cxy[0], cxy[1],
113
(gs_char) op[-1].value.intval,
114
op->value.bytes, r_size(op),
115
imemory, &penum)) < 0)
117
*(op_proc_t *)&penum->enum_client_data = zwidthshow;
118
if ((code = op_show_finish_setup(i_ctx_p, penum, 4, finish_show)) < 0) {
119
ifree_object(penum, "op_show_enum_setup");
122
return op_show_continue_pop(i_ctx_p, 4);
125
/* <cx> <cy> <char> <ax> <ay> <string> awidthshow - */
127
zawidthshow(i_ctx_t *i_ctx_p)
130
gs_text_enum_t *penum;
131
double cxy[2], axy[2];
134
if ((code = op_show_setup(i_ctx_p, op)) != 0 )
136
if ((code = num_params(op - 1, 2, axy)) < 0 )
138
check_type(op[-3], t_integer);
139
if (gs_currentfont(igs)->FontType == ft_composite) {
140
if ((gs_char) (op[-3].value.intval) != op[-3].value.intval)
141
return_error(e_rangecheck);
143
if (op[-3].value.intval < 0 || op[-3].value.intval > 255)
144
return_error(e_rangecheck); /* per PLRM and CET 13-02 */
146
if ((code = num_params(op - 4, 2, cxy)) < 0 )
148
if ((code = gs_awidthshow_begin(igs, cxy[0], cxy[1],
149
(gs_char) op[-3].value.intval,
151
op->value.bytes, r_size(op),
152
imemory, &penum)) < 0)
154
*(op_proc_t *)&penum->enum_client_data = zawidthshow;
155
if ((code = op_show_finish_setup(i_ctx_p, penum, 6, finish_show)) < 0) {
156
ifree_object(penum, "op_show_enum_setup");
159
return op_show_continue_pop(i_ctx_p, 6);
162
/* <proc> <string> kshow - */
164
zkshow(i_ctx_t *i_ctx_p)
167
gs_text_enum_t *penum;
170
check_read_type(*op, t_string);
173
* Per PLRM Section xx.x, kshow is illegal if the current font is a
174
* composite font. The graphics library does not have this limitation,
175
* so we check for it here.
177
if (gs_currentfont(igs)->FontType == ft_composite)
178
return_error(e_invalidfont);
179
if ((code = op_show_setup(i_ctx_p, op)) != 0 ||
180
(code = gs_kshow_begin(igs, op->value.bytes, r_size(op),
181
imemory, &penum)) < 0)
183
*(op_proc_t *)&penum->enum_client_data = zkshow;
184
if ((code = op_show_finish_setup(i_ctx_p, penum, 2, finish_show)) < 0) {
185
ifree_object(penum, "op_show_enum_setup");
188
sslot = op[-1]; /* save kerning proc */
189
return op_show_continue_pop(i_ctx_p, 2);
192
/* Common finish procedure for all show operations. */
193
/* Doesn't have to do anything. */
195
finish_show(i_ctx_t *i_ctx_p)
200
/* <string> stringwidth <wx> <wy> */
202
zstringwidth(i_ctx_t *i_ctx_p)
205
gs_text_enum_t *penum;
206
int code = op_show_setup(i_ctx_p, op);
209
(code = gs_stringwidth_begin(igs, op->value.bytes, r_size(op),
210
imemory, &penum)) < 0)
212
*(op_proc_t *)&penum->enum_client_data = zstringwidth;
213
if ((code = op_show_finish_setup(i_ctx_p, penum, 1, finish_stringwidth)) < 0) {
214
ifree_object(penum, "op_show_enum_setup");
217
return op_show_continue_pop(i_ctx_p, 1);
219
/* Finishing procedure for stringwidth. */
220
/* Pushes the accumulated width. */
221
/* This is exported for .glyphwidth (in zcharx.c). */
223
finish_stringwidth(i_ctx_t *i_ctx_p)
228
gs_text_total_width(senum, &width);
230
make_real(op - 1, width.x);
231
make_real(op, width.y);
235
/* Common code for charpath and .charboxpath. */
237
zchar_path(i_ctx_t *i_ctx_p, op_proc_t proc,
238
int (*begin)(gs_state *, const byte *, uint,
239
bool, gs_memory_t *, gs_text_enum_t **))
242
gs_text_enum_t *penum;
245
check_type(*op, t_boolean);
246
code = op_show_setup(i_ctx_p, op - 1);
248
(code = begin(igs, op[-1].value.bytes, r_size(op - 1),
249
op->value.boolval, imemory, &penum)) < 0)
251
*(op_proc_t *)&penum->enum_client_data = proc;
252
if ((code = op_show_finish_setup(i_ctx_p, penum, 2, finish_show)) < 0) {
253
ifree_object(penum, "op_show_enum_setup");
256
return op_show_continue_pop(i_ctx_p, 2);
258
/* <string> <outline_bool> charpath - */
260
zcharpath(i_ctx_t *i_ctx_p)
262
return zchar_path(i_ctx_p, zcharpath, gs_charpath_begin);
264
/* <string> <box_bool> .charboxpath - */
266
zcharboxpath(i_ctx_t *i_ctx_p)
268
return zchar_path(i_ctx_p, zcharboxpath, gs_charboxpath_begin);
271
/* <wx> <wy> <llx> <lly> <urx> <ury> setcachedevice - */
273
zsetcachedevice(i_ctx_t *i_ctx_p)
277
gs_text_enum_t *penum = op_show_find(i_ctx_p);
278
int code = num_params(op, 6, wbox);
281
return_error(e_undefined);
284
if (zchar_show_width_only(penum))
285
return op_show_return_width(i_ctx_p, 6, &wbox[0]);
286
code = gs_text_setcachedevice(penum, wbox);
291
clear_pagedevice(istate);
295
/* <w0x> <w0y> <llx> <lly> <urx> <ury> <w1x> <w1y> <vx> <vy> setcachedevice2 - */
297
zsetcachedevice2(i_ctx_t *i_ctx_p)
301
gs_text_enum_t *penum = op_show_find(i_ctx_p);
302
int code = num_params(op, 10, wbox);
305
return_error(e_undefined);
308
if (zchar_show_width_only(penum))
309
return op_show_return_width(i_ctx_p, 10,
310
(gs_rootfont(igs)->WMode ?
311
&wbox[6] : &wbox[0]));
312
code = gs_text_setcachedevice2(penum, wbox);
317
clear_pagedevice(istate);
321
/* <wx> <wy> setcharwidth - */
323
zsetcharwidth(i_ctx_t *i_ctx_p)
327
gs_text_enum_t *penum = op_show_find(i_ctx_p);
328
int code = num_params(op, 2, width);
331
return_error(e_undefined);
334
if (zchar_show_width_only(penum))
335
return op_show_return_width(i_ctx_p, 2, &width[0]);
336
code = gs_text_setcharwidth(penum, width);
343
/* <dict> .fontbbox <llx> <lly> <urx> <ury> -true- */
344
/* <dict> .fontbbox -false- */
346
zfontbbox(i_ctx_t *i_ctx_p)
352
check_type(*op, t_dictionary);
353
check_dict_read(*op);
354
code = font_bbox_param(imemory, op, bbox);
357
if (bbox[0] < bbox[2] && bbox[1] < bbox[3]) {
359
make_reals(op - 4, bbox, 4);
361
} else { /* No bbox, or an empty one. */
367
/* Export in_cachedevice flag for PDF interpreter, which, unlike
368
* PS unterpreter, ignores color operations in the inappropriate context.
370
/* - .incachedevice <bool> */
372
zincachedevice(i_ctx_t *i_ctx_p)
377
make_bool(op, !!igs->in_cachedevice);
382
/* ------ Initialization procedure ------ */
384
const op_def zchar_a_op_defs[] =
387
{"6awidthshow", zawidthshow},
388
{"2charpath", zcharpath},
389
{"2.charboxpath", zcharboxpath},
391
{"6setcachedevice", zsetcachedevice},
392
{":setcachedevice2", zsetcachedevice2},
393
{"2setcharwidth", zsetcharwidth},
395
{"1stringwidth", zstringwidth},
396
{"4widthshow", zwidthshow},
398
{"1.fontbbox", zfontbbox},
399
/* Internal operators */
400
{"0%finish_show", finish_show},
401
{"0%finish_stringwidth", finish_stringwidth},
402
{"0%op_show_continue", op_show_continue},
406
const op_def zchar_b_op_defs[] =
408
{"0.incachedevice", zincachedevice},
412
/* ------ Subroutines ------ */
414
/* Most of these are exported for zchar2.c. */
416
/* Convert a glyph to a ref. */
418
glyph_ref(const gs_memory_t *mem, gs_glyph glyph, ref * gref)
420
if (glyph < gs_min_cid_glyph)
421
name_index_ref(mem, glyph, gref);
423
make_int(gref, glyph - gs_min_cid_glyph);
426
/* Prepare to set up for a text operator. */
427
/* Don't change any state yet. */
429
op_show_setup(i_ctx_t *i_ctx_p, os_ptr op)
431
check_read_type(*op, t_string);
432
return op_show_enum_setup(i_ctx_p);
435
op_show_enum_setup(i_ctx_t *i_ctx_p)
437
check_estack(snumpush + 2);
441
/* Finish setting up a text operator. */
443
op_show_finish_setup(i_ctx_t *i_ctx_p, gs_text_enum_t * penum, int npop,
444
op_proc_t endproc /* end procedure */ )
446
gs_text_enum_t *osenum = op_show_find(i_ctx_p);
447
es_ptr ep = esp + snumpush;
449
extern bool CPSI_mode;
452
/* CET 14-03.PS page 2 emits rangecheck before rendering a character.
453
Early check the text to font compatibility
454
with decomposing the text into characters.*/
455
int code = gs_text_count_chars(igs, gs_get_text_params(penum), imemory);
461
* If we are in the procedure of a cshow for a CID font and this is
462
* a show operator, do something special, per the Red Book.
465
SHOW_IS_ALL_OF(osenum,
466
TEXT_FROM_STRING | TEXT_DO_NONE | TEXT_INTERVENE) &&
467
SHOW_IS_ALL_OF(penum, TEXT_FROM_STRING | TEXT_RETURN_WIDTH) &&
468
(glyph = gs_text_current_glyph(osenum)) != gs_no_glyph &&
469
glyph >= gs_min_cid_glyph &&
471
/* According to PLRM, we don't need to raise a rangecheck error,
472
if currentfont is changed in the proc of the operator 'cshow'. */
473
gs_default_same_font (gs_text_current_font(osenum),
474
gs_text_current_font(penum), true)
476
gs_text_params_t text;
478
if (!(penum->text.size == 1 &&
479
penum->text.data.bytes[0] ==
480
(gs_text_current_char(osenum) & 0xff))
482
return_error(e_rangecheck);
486
~(TEXT_FROM_STRING | TEXT_FROM_BYTES | TEXT_FROM_CHARS |
487
TEXT_FROM_GLYPHS | TEXT_FROM_SINGLE_CHAR)) |
488
TEXT_FROM_SINGLE_GLYPH;
489
text.data.d_glyph = glyph;
491
gs_text_restart(penum, &text);
493
if (osenum && osenum->current_font->FontType == ft_user_defined &&
494
osenum->orig_font->FontType == ft_composite &&
495
((const gs_font_type0 *)osenum->orig_font)->data.FMapType == fmap_CMap) {
496
/* A special behavior defined in PLRM3 section 5.11 page 389. */
497
penum->outer_CID = osenum->returned.current_glyph;
499
if (osenum == NULL && !(penum->text.operation & (TEXT_FROM_GLYPHS | TEXT_FROM_SINGLE_GLYPH))) {
500
int ft = igs->root_font->FontType;
502
if ((ft >= ft_CID_encrypted && ft <= ft_CID_TrueType) || ft == ft_CID_bitmap)
503
return_error(e_typecheck);
505
make_mark_estack(ep - (snumpush - 1), es_show, op_show_cleanup);
507
endproc = finish_show;
508
make_null(&esslot(ep));
509
make_int(&esodepth(ep), ref_stack_count_inline(&o_stack) - npop); /* Save stack depth for */
510
make_int(&esddepth(ep), ref_stack_count_inline(&d_stack)); /* correct interrupt processing */
511
make_int(&esgslevel(ep), igs->level);
512
make_null(&essfont(ep));
513
make_null(&esrfont(ep));
514
make_op_estack(&eseproc(ep), endproc);
515
make_istruct(ep, 0, penum);
520
/* Continuation operator for character rendering. */
522
op_show_continue(i_ctx_t *i_ctx_p)
524
int code = gs_text_update_dev_color(igs, senum);
527
code = op_show_continue_dispatch(i_ctx_p, 0, gs_text_process(senum));
531
op_show_continue_pop(i_ctx_t *i_ctx_p, int npop)
533
return op_show_continue_dispatch(i_ctx_p, npop, gs_text_process(senum));
536
* Note that op_show_continue_dispatch sets osp = op explicitly iff the
537
* dispatch succeeds. This is so that the show operators don't pop anything
538
* from the o-stack if they don't succeed. Note also that if it returns an
539
* error, it has freed the enumerator.
542
op_show_continue_dispatch(i_ctx_t *i_ctx_p, int npop, int code)
544
os_ptr op = osp - npop;
545
gs_text_enum_t *penum = senum;
548
case 0: { /* all done */
549
os_ptr save_osp = osp;
552
code = (*real_opproc(&seproc)) (i_ctx_p);
553
op_show_free(i_ctx_p, code);
560
case TEXT_PROCESS_INTERVENE: {
561
ref *pslot = &sslot; /* only used for kshow */
564
make_int(op - 1, gs_text_current_char(penum)); /* previous char */
565
make_int(op, gs_text_next_char(penum));
566
push_op_estack(op_show_continue); /* continue after kerning */
567
*++esp = *pslot; /* kerning procedure */
568
return o_push_estack;
570
case TEXT_PROCESS_RENDER: {
571
gs_font *pfont = gs_currentfont(igs);
572
font_data *pfdata = pfont_data(pfont);
573
gs_char chr = gs_text_current_char(penum);
574
gs_glyph glyph = gs_text_current_glyph(penum);
577
op[-1] = pfdata->dict; /* push the font */
579
* For Type 1 and Type 4 fonts, prefer BuildChar to BuildGlyph
580
* if there is no glyph, or if there is both a character and a
581
* glyph and the glyph is the one that corresponds to the
582
* character in the Encoding, so that PostScript procedures
583
* appearing in the CharStrings dictionary will receive the
584
* character code rather than the character name; for Type 3
585
* fonts, prefer BuildGlyph to BuildChar. For other font types
586
* (such as CID fonts), only BuildGlyph will be present.
588
if (pfont->FontType == ft_user_defined) {
589
/* Type 3 font, prefer BuildGlyph. */
590
if (level2_enabled &&
591
!r_has_type(&pfdata->BuildGlyph, t_null) &&
594
glyph_ref(imemory, glyph, op);
595
esp[2] = pfdata->BuildGlyph;
596
} else if (r_has_type(&pfdata->BuildChar, t_null))
598
else if (chr == gs_no_char) {
599
/* glyphshow, reverse map the character */
600
/* through the Encoding */
602
const ref *pencoding = &pfdata->Encoding;
604
glyph_ref(imemory, glyph, &gref);
605
if (!map_glyph_to_char(imemory, &gref, pencoding,
607
) { /* Not found, try .notdef */
608
name_enter_string(imemory, ".notdef", &gref);
609
if (!map_glyph_to_char(imemory, &gref,
615
esp[2] = pfdata->BuildChar;
617
make_int(op, chr & 0xff);
618
esp[2] = pfdata->BuildChar;
622
* For a Type 1 or Type 4 font, prefer BuildChar or
623
* BuildGlyph as described above: we know that both
624
* BuildChar and BuildGlyph are present. For other font
625
* types, only BuildGlyph is available.
629
if (chr != gs_no_char &&
630
!r_has_type(&pfdata->BuildChar, t_null) &&
631
(glyph == gs_no_glyph ||
632
(array_get(imemory, &pfdata->Encoding, (long)(chr & 0xff), &eref) >= 0 &&
633
(glyph_ref(imemory, glyph, &gref), obj_eq(imemory, &gref, &eref))))
635
make_int(op, chr & 0xff);
636
esp[2] = pfdata->BuildChar;
638
/* We might not have a glyph: substitute 0. **HACK** */
639
if (glyph == gs_no_glyph)
642
glyph_ref(imemory, glyph, op);
643
esp[2] = pfdata->BuildGlyph;
646
/* Save the stack depths in case we bail out. */
647
sodepth.value.intval = ref_stack_count(&o_stack) - 2;
648
sddepth.value.intval = ref_stack_count(&d_stack);
649
push_op_estack(op_show_continue);
650
++esp; /* skip BuildChar or BuildGlyph proc */
651
return o_push_estack;
653
case TEXT_PROCESS_CDEVPROC:
654
{ gs_font *pfont = penum->current_font;
656
op_proc_t cont = op_show_continue, exec_cont = 0;
657
gs_glyph glyph = penum->returned.current_glyph;
662
glyph_ref(imemory, glyph, &cnref);
663
if (pfont->FontType == ft_CID_TrueType) {
664
gs_font_type42 *pfont42 = (gs_font_type42 *)pfont;
665
uint glyph_index = pfont42->data.get_glyph_index(pfont42, glyph);
667
code = zchar42_set_cache(i_ctx_p, (gs_font_base *)pfont42,
668
&cnref, glyph_index, cont, &exec_cont);
669
} else if (pfont->FontType == ft_CID_encrypted)
670
code = z1_set_cache(i_ctx_p, (gs_font_base *)pfont,
671
&cnref, glyph, cont, &exec_cont);
673
return_error(e_unregistered); /* Unimplemented. */
675
return_error(e_unregistered); /* Must not happen. */
681
code = gs_note_error(e_invalidfont);
682
return op_show_free(i_ctx_p, code);
685
/* Reverse-map a glyph name to a character code for glyphshow. */
687
map_glyph_to_char(const gs_memory_t *mem, const ref * pgref, const ref * pencoding, ref * pch)
689
uint esize = r_size(pencoding);
693
for (ch = 0; ch < esize; ch++) {
694
array_get(mem, pencoding, (long)ch, &eref);
695
if (obj_eq(mem, pgref, &eref)) {
703
/* Find the index of the e-stack mark for the current show enumerator. */
704
/* Return 0 if we can't find the mark. */
706
op_show_find_index(i_ctx_t *i_ctx_p)
708
ref_stack_enum_t rsenum;
711
ref_stack_enum_begin(&rsenum, &e_stack);
713
es_ptr ep = rsenum.ptr;
714
uint size = rsenum.size;
716
for (ep += size - 1; size != 0; size--, ep--, count++)
717
if (r_is_estack_mark(ep) && estack_mark_index(ep) == es_show)
719
} while (ref_stack_enum_next(&rsenum));
720
return 0; /* no mark */
723
/* Find the current show enumerator on the e-stack. */
725
op_show_find(i_ctx_t *i_ctx_p)
727
uint index = op_show_find_index(i_ctx_p);
730
return 0; /* no mark */
731
return r_ptr(ref_stack_index(&e_stack, index - (snumpush - 1)),
736
* Return true if we only need the width from the rasterizer
737
* and can short-circuit the full rendering of the character,
738
* false if we need the actual character bits. This is only safe if
739
* we know the character is well-behaved, i.e., is not defined by an
740
* arbitrary PostScript procedure.
743
zchar_show_width_only(const gs_text_enum_t * penum)
745
if (!gs_text_is_width_only(penum))
747
switch (penum->orig_font->FontType) {
750
case ft_CID_encrypted:
751
case ft_CID_TrueType:
760
/* Shortcut the BuildChar or BuildGlyph procedure at the point */
761
/* of the setcharwidth or the setcachedevice[2] if we are in */
762
/* a stringwidth or cshow, or if we are only collecting the scalable */
763
/* width for an xfont character. */
765
op_show_return_width(i_ctx_t *i_ctx_p, uint npop, double *pwidth)
767
uint index = op_show_find_index(i_ctx_p);
768
es_ptr ep = (es_ptr) ref_stack_index(&e_stack, index - (snumpush - 1));
769
int code = gs_text_setcharwidth(esenum(ep), pwidth);
770
uint ocount, dsaved, dcount;
774
/* Restore the operand and dictionary stacks. */
775
ocount = ref_stack_count(&o_stack) - (uint) esodepth(ep).value.intval;
777
return_error(e_stackunderflow);
778
dsaved = (uint) esddepth(ep).value.intval;
779
dcount = ref_stack_count(&d_stack);
781
return_error(e_dictstackunderflow);
782
while (dcount > dsaved) {
783
code = zend(i_ctx_p);
788
ref_stack_pop(&o_stack, ocount);
789
/* We don't want to pop the mark or the continuation */
790
/* procedure (op_show_continue or cshow_continue). */
791
pop_estack(i_ctx_p, index - snumpush);
796
* Restore state after finishing, or unwinding from an error within, a show
797
* operation. Note that we assume op == osp, and may reset osp.
800
op_show_restore(i_ctx_t *i_ctx_p, bool for_error)
802
register es_ptr ep = esp + snumpush;
803
gs_text_enum_t *penum = esenum(ep);
804
int saved_level = esgslevel(ep).value.intval;
808
#if 0 /* Disabled for CPSI compatibility for 13-12-4.
809
CPSI doesn't remove cshow, kshow proc operands. */
810
uint saved_count = esodepth(ep).value.intval;
811
uint count = ref_stack_count(&o_stack);
813
if (count > saved_count) /* if <, we're in trouble */
814
ref_stack_pop(&o_stack, count - saved_count);
816
if (ep[1].value.opproc == op_show_continue && penum->enum_client_data != NULL) {
817
/* Replace the continuation operaton on estack with the right operator : */
820
*(void **)&proc = penum->enum_client_data;
821
make_op_estack(ep + 1, proc);
824
if (SHOW_IS_STRINGWIDTH(penum) && igs->text_rendering_mode != 3) {
825
/* stringwidth does an extra gsave */
828
if (penum->text.operation & TEXT_REPLACE_WIDTHS) {
829
gs_free_const_object(penum->memory, penum->text.y_widths, "y_widths");
830
if (penum->text.x_widths != penum->text.y_widths)
831
gs_free_const_object(penum->memory, penum->text.x_widths, "x_widths");
834
* We might have been inside a cshow, in which case currentfont was
835
* reset temporarily, as though we were inside a BuildChar/ BuildGlyph
836
* procedure. To handle this case, set currentfont back to its original
837
* state. NOTE: this code previously used fstack[0] in the enumerator
838
* for the root font: we aren't sure that this change is correct.
840
gs_set_currentfont(igs, penum->orig_font);
841
while (igs->level > saved_level && code >= 0) {
842
if (igs->saved == 0 || igs->saved->saved == 0) {
844
* Bad news: we got an error inside a save inside a BuildChar or
845
* BuildGlyph. Don't attempt to recover.
847
code = gs_note_error(e_Fatal);
849
code = gs_grestore(igs);
851
gs_text_release(penum, "op_show_restore");
854
/* Clean up after an error. */
856
op_show_cleanup(i_ctx_t *i_ctx_p)
858
return op_show_restore(i_ctx_p, true);
860
/* Clean up after termination of a show operation. */
862
op_show_free(i_ctx_t *i_ctx_p, int code)
867
rcode = op_show_restore(i_ctx_p, code < 0);
868
return (rcode < 0 ? rcode : code);
871
/* Get a FontBBox parameter from a font dictionary. */
873
font_bbox_param(const gs_memory_t *mem, const ref * pfdict, double bbox[4])
878
* Pre-clear the bbox in case it's invalid. The Red Books say that
879
* FontBBox is required, but old Adobe interpreters don't require
880
* it, and a few user-written fonts don't supply it, or supply one
881
* of the wrong size (!); also, PageMaker 5.0 (an Adobe product!)
882
* sometimes emits an absurd bbox for Type 1 fonts converted from
885
bbox[0] = bbox[1] = bbox[2] = bbox[3] = 0.0;
886
if (dict_find_string(pfdict, "FontBBox", &pbbox) > 0) {
887
if (!r_is_array(pbbox))
888
return_error(e_typecheck);
889
if (r_size(pbbox) == 4) {
890
const ref_packed *pbe = pbbox->value.packed;
895
const float max_ratio = 12; /* From the bug 687594. */
897
for (i = 0; i < 4; i++) {
898
packed_get(mem, pbe, rbe + i);
899
pbe = packed_next(pbe);
901
if ((code = num_params(rbe + 3, 4, bbox)) < 0)
903
/* Require "reasonable" values. */
904
dx = bbox[2] - bbox[0];
905
dy = bbox[3] - bbox[1];
906
if (dx <= 0 || dy <= 0 ||
907
(ratio = dy / dx) < 1 / max_ratio || ratio > max_ratio
909
bbox[0] = bbox[1] = bbox[2] = bbox[3] = 0.0;
911
} else if (CPSI_mode) {
912
return_error(e_invalidfont); /* CPSI requires FontBBox */