home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1996 February / PCWK0296.iso / sharewar / dos / program / gs300sr1 / gs300sr1.exe / ZCHAR.C < prev    next >
C/C++ Source or Header  |  1994-07-27  |  15KB  |  504 lines

  1. /* Copyright (C) 1989, 1992, 1993, 1994 Aladdin Enterprises.  All rights reserved.
  2.   
  3.   This file is part of Aladdin Ghostscript.
  4.   
  5.   Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author
  6.   or distributor accepts any responsibility for the consequences of using it,
  7.   or for whether it serves any particular purpose or works at all, unless he
  8.   or she says so in writing.  Refer to the Aladdin Ghostscript Free Public
  9.   License (the "License") for full details.
  10.   
  11.   Every copy of Aladdin Ghostscript must include a copy of the License,
  12.   normally in a plain ASCII text file named PUBLIC.  The License grants you
  13.   the right to copy, modify and redistribute Aladdin Ghostscript, but only
  14.   under certain conditions described in the License.  Among other things, the
  15.   License requires that the copyright notice and this notice be preserved on
  16.   all copies.
  17. */
  18.  
  19. /* zchar.c */
  20. /* Character operators */
  21. #include "ghost.h"
  22. #include "errors.h"
  23. #include "oper.h"
  24. #include "gsstruct.h"
  25. #include "gxarith.h"
  26. #include "gxfixed.h"
  27. #include "gxmatrix.h"            /* for ifont.h */
  28. #include "gschar.h"
  29. #include "gxdevice.h"            /* for gxfont.h */
  30. #include "gxfont.h"
  31. #include "gzpath.h"
  32. #include "gzstate.h"
  33. #include "dstack.h"            /* for stack depth */
  34. #include "estack.h"
  35. #include "ialloc.h"
  36. #include "ichar.h"
  37. #include "idict.h"
  38. #include "ifont.h"
  39. #include "igstate.h"
  40. #include "ilevel.h"
  41. #include "iname.h"
  42. #include "store.h"
  43.  
  44. /* Imported operators */
  45. int zend(P1(os_ptr));
  46.  
  47. /* Forward references */
  48. private bool map_glyph_to_char(P3(const ref *, const ref *, ref *));
  49. private int finish_show(P1(os_ptr));
  50. private int finish_stringwidth(P1(os_ptr));
  51. private int op_show_cleanup(P1(os_ptr));
  52.  
  53. /* <string> show - */
  54. int
  55. zshow(register os_ptr op)
  56. {    gs_show_enum *penum;
  57.     int code = op_show_setup(op, &penum);
  58.     if ( code < 0 ) return code;
  59.     if ( (code = gs_show_n_init(penum, igs, (char *)op->value.bytes, r_size(op))) < 0 )
  60.        {    ifree_object(penum, "op_show_enum_setup");
  61.         return code;
  62.        }
  63.     op_show_finish_setup(penum, 1, finish_show);
  64.     return op_show_continue(op - 1);
  65. }
  66.  
  67. /* <ax> <ay> <string> ashow - */
  68. int
  69. zashow(register os_ptr op)
  70. {    gs_show_enum *penum;
  71.     int code;
  72.     float axy[2];
  73.     if (    (code = num_params(op - 1, 2, axy)) < 0 ||
  74.         (code = op_show_setup(op, &penum)) < 0
  75.        )
  76.         return code;
  77.     if ( (code = gs_ashow_n_init(penum, igs, axy[0], axy[1], (char *)op->value.bytes, r_size(op))) < 0 )
  78.        {    ifree_object(penum, "op_show_enum_setup");
  79.         return code;
  80.        }
  81.     op_show_finish_setup(penum, 3, finish_show);
  82.     return op_show_continue(op - 3);
  83. }
  84.  
  85. /* <cx> <cy> <char> <string> widthshow - */
  86. int
  87. zwidthshow(register os_ptr op)
  88. {    gs_show_enum *penum;
  89.     int code;
  90.     float cxy[2];
  91.     check_type(op[-1], t_integer);
  92.     if ( (gs_char)(op[-1].value.intval) != op[-1].value.intval )
  93.         return_error(e_rangecheck);
  94.     if (    (code = num_params(op - 2, 2, cxy)) < 0 ||
  95.         (code = op_show_setup(op, &penum)) < 0
  96.        )
  97.         return code;
  98.     if ( (code = gs_widthshow_n_init(penum, igs, cxy[0], cxy[1],
  99.                      (gs_char)op[-1].value.intval,
  100.                      (char *)op->value.bytes,
  101.                      r_size(op))) < 0 )
  102.        {    ifree_object(penum, "op_show_enum_setup");
  103.         return code;
  104.        }
  105.     op_show_finish_setup(penum, 4, finish_show);
  106.     return op_show_continue(op - 4);
  107. }
  108.  
  109. /* <cx> <cy> <char> <ax> <ay> <string> awidthshow - */
  110. int
  111. zawidthshow(register os_ptr op)
  112. {    gs_show_enum *penum;
  113.     int code;
  114.     float cxy[2], axy[2];
  115.     check_type(op[-3], t_integer);
  116.     if ( (gs_char)(op[-3].value.intval) != op[-3].value.intval )
  117.         return_error(e_rangecheck);
  118.     if (    (code = num_params(op - 4, 2, cxy)) < 0 ||
  119.         (code = num_params(op - 1, 2, axy)) < 0 ||
  120.         (code = op_show_setup(op, &penum)) < 0
  121.        )
  122.         return code;
  123.     if ( (code = gs_awidthshow_n_init(penum, igs, cxy[0], cxy[1],
  124.                       (gs_char)op[-3].value.intval,
  125.                       axy[0], axy[1],
  126.                       (char *)op->value.bytes,
  127.                       r_size(op))) < 0 )
  128.        {    ifree_object(penum, "op_show_enum_setup");
  129.         return code;
  130.        }
  131.     op_show_finish_setup(penum, 6, finish_show);
  132.     return op_show_continue(op - 6);
  133. }
  134.  
  135. /* <proc> <string> kshow - */
  136. int
  137. zkshow(register os_ptr op)
  138. {    gs_show_enum *penum;
  139.     int code;
  140.     check_proc(op[-1]);
  141.     if ( (code = op_show_setup(op, &penum)) < 0 ) return code;
  142.     if ( (code = gs_kshow_n_init(penum, igs, (char *)op->value.bytes, r_size(op))) < 0 )
  143.        {    ifree_object(penum, "op_show_enum_setup");
  144.         return code;
  145.        }
  146.     sslot = op[-1];        /* save kerning proc */
  147.     op_show_finish_setup(penum, 2, finish_show);
  148.     return op_show_continue(op - 2);
  149. }
  150.  
  151. /* Common finish procedure for all show operations. */
  152. /* Doesn't have to do anything. */
  153. private int
  154. finish_show(os_ptr op)
  155. {    return 0;
  156. }
  157.  
  158. /* <string> stringwidth <wx> <wy> */
  159. int
  160. zstringwidth(register os_ptr op)
  161. {    gs_show_enum *penum;
  162.     int code = op_show_setup(op, &penum);
  163.     if ( code < 0 ) return code;
  164.     if ( (code = gs_stringwidth_n_init(penum, igs, (char *)op->value.bytes, r_size(op))) < 0 )
  165.        {    ifree_object(penum, "op_show_enum_setup");
  166.         return code;
  167.        }
  168.     op_show_finish_setup(penum, 1, finish_stringwidth);
  169.     return op_show_continue(op - 1);
  170. }
  171. /* Finishing procedure for stringwidth. */
  172. /* Pushes the accumulated width. */
  173. private int
  174. finish_stringwidth(register os_ptr op)
  175. {    gs_point width;
  176.     gs_show_width(senum, &width);
  177.     push(2);
  178.     make_real(op - 1, width.x);
  179.     make_real(op, width.y);
  180.     return 0;
  181. }
  182.  
  183. /* <string> <outline_bool> charpath - */
  184. int
  185. zcharpath(register os_ptr op)
  186. {    gs_show_enum *penum;
  187.     int code;
  188.     check_type(*op, t_boolean);
  189.     code = op_show_setup(op - 1, &penum);
  190.     if ( code < 0 ) return code;
  191.     if ( (code = gs_charpath_n_init(penum, igs, (char *)op[-1].value.bytes, r_size(op - 1), op->value.boolval)) < 0 )
  192.        {    ifree_object(penum, "op_show_enum_setup");
  193.         return code;
  194.        }
  195.     op_show_finish_setup(penum, 2, finish_show);
  196.     return op_show_continue(op - 2);
  197. }
  198.  
  199. /* <wx> <wy> <llx> <lly> <urx> <ury> setcachedevice - */
  200. int
  201. zsetcachedevice(register os_ptr op)
  202. {    float wbox[6];
  203.     gs_show_enum *penum = op_show_find();
  204.     int code = num_params(op, 6, wbox);
  205.     if ( penum == 0 )
  206.       return_error(e_undefined);
  207.     if ( code < 0 )
  208.       return code;
  209.     if ( gs_show_width_only(penum) )
  210.       return op_show_return_width(op, 6, &wbox[0]);
  211.     code = gs_setcachedevice(penum, igs, wbox);
  212.     if ( code < 0 )
  213.       return code;
  214.     pop(6);
  215.     return 0;
  216. }
  217.  
  218. /* <w0x> <w0y> <llx> <lly> <urx> <ury> <w1x> <w1y> <vx> <vy> setcachedevice2 - */
  219. private int
  220. zsetcachedevice2(os_ptr op)
  221. {    float wbox[10];
  222.     gs_show_enum *penum = op_show_find();
  223.     int code = num_params(op, 10, wbox);
  224.     if ( penum == 0 )
  225.       return_error(e_undefined);
  226.     if ( code < 0 )
  227.       return code;
  228.     if ( gs_show_width_only(penum) )
  229.       return op_show_return_width(op, 10,
  230.                       (gs_rootfont(igs)->WMode ?
  231.                        &wbox[6] : &wbox[0]));
  232.     code = gs_setcachedevice2(penum, igs, wbox);
  233.     if ( code < 0 )
  234.       return code;
  235.     pop(10);
  236.     return 0;
  237. }
  238.  
  239. /* <wx> <wy> setcharwidth - */
  240. int
  241. zsetcharwidth(register os_ptr op)
  242. {    float width[2];
  243.     gs_show_enum *penum = op_show_find();
  244.     int code = num_params(op, 2, width);
  245.     if ( penum == 0 )
  246.       return_error(e_undefined);
  247.     if ( code < 0 )
  248.       return code;
  249.     if ( gs_show_width_only(penum) )
  250.       return op_show_return_width(op, 2, &width[0]);
  251.     code = gs_setcharwidth(penum, igs, width[0], width[1]);
  252.     if ( code < 0 )
  253.       return code;
  254.     pop(2);
  255.     return 0;
  256. }
  257.  
  258. /* ------ Initialization procedure ------ */
  259.  
  260. op_def zchar_op_defs[] = {
  261.     {"3ashow", zashow},
  262.     {"6awidthshow", zawidthshow},
  263.     {"2charpath", zcharpath},
  264.     {"2kshow", zkshow},
  265.     {"6setcachedevice", zsetcachedevice},
  266.     {":setcachedevice2", zsetcachedevice2},
  267.     {"2setcharwidth", zsetcharwidth},
  268.     {"1show", zshow},
  269.     {"1stringwidth", zstringwidth},
  270.     {"4widthshow", zwidthshow},
  271.         /* Internal operators */
  272.     {"0%finish_show", finish_show},
  273.     {"0%finish_stringwidth", finish_stringwidth},
  274.     {"0%op_show_continue", op_show_continue},
  275.     op_def_end(0)
  276. };
  277.  
  278. /* ------ Subroutines ------ */
  279.  
  280. /* Most of these are exported for zchar2.c. */ 
  281.  
  282. /* Prepare to set up for a show operator. */
  283. /* Don't change any state yet. */
  284. int
  285. op_show_setup(os_ptr op, gs_show_enum **ppenum)
  286. {    check_read_type(*op, t_string);
  287.     return op_show_enum_setup(ppenum);
  288. }
  289. int
  290. op_show_enum_setup(gs_show_enum **ppenum)
  291. {    check_estack(snumpush + 2);
  292.     if ( (*ppenum = gs_show_enum_alloc(imemory, "op_show_enum_setup")) == 0 )
  293.         return_error(e_VMerror);
  294.     return 0;
  295. }
  296.  
  297. /* Finish setting up a show operator.  This can't fail. */
  298. void
  299. op_show_finish_setup(gs_show_enum *penum, int npop, op_proc_p endproc /* end procedure */)
  300. {    register es_ptr ep = esp + snumpush;
  301.     esp = ep;
  302.     make_mark_estack(ep - (snumpush - 1), es_show, op_show_cleanup);
  303.     if ( endproc == NULL )
  304.       endproc = finish_show;
  305.     make_null(&esslot(ep));
  306.     make_int(&esodepth(ep), ref_stack_count(&o_stack) - npop);
  307.     make_int(&esddepth(ep), ref_stack_count(&d_stack));
  308.     make_op_estack(&eseproc(ep), endproc);
  309.     make_istruct(ep, 0, penum);
  310. }
  311.  
  312. /* Continuation operator for character rendering. */
  313. int
  314. op_show_continue(os_ptr op)
  315. {    return op_show_continue_dispatch(op, gs_show_next(senum));
  316. }
  317. /* Note that this sets osp = op explicitly iff the dispatch succeeds. */
  318. /* This is so that the show operators don't pop anything from the o-stack */
  319. /* if they don't succeed. */
  320. int
  321. op_show_continue_dispatch(register os_ptr op, int code)
  322. {    gs_show_enum *penum = senum;
  323.     switch ( code )
  324.     {
  325.     case 0:                /* all done */
  326.     {    os_ptr save_osp = osp;
  327.         osp = op;
  328.         code = (*real_opproc(&seproc))(op);
  329.         op_show_free();
  330.         if ( code < 0 )
  331.         {    osp = save_osp;
  332.             return code;
  333.         }
  334.         return o_pop_estack;
  335.     }
  336.     case gs_show_kern:
  337.     {    ref *pslot = &sslot;
  338.         push(2);
  339.         make_int(op - 1, gs_kshow_previous_char(penum));
  340.         make_int(op, gs_kshow_next_char(penum));
  341.         push_op_estack(op_show_continue);        /* continue after kerning */
  342.         *++esp = *pslot;    /* kerning procedure */
  343.     }
  344.         return o_push_estack;
  345.     case gs_show_render:
  346.     {    gs_font *pfont = gs_currentfont(igs);
  347.         font_data *pfdata = pfont_data(pfont);
  348.         gs_char chr = gs_show_current_char(penum);
  349.         gs_glyph glyph = gs_show_current_glyph(penum);
  350.         push(2);
  351.         op[-1] = pfdata->dict;    /* push the font */
  352.         /*
  353.          * For Type 1 fonts, prefer BuildChar to BuildGlyph,
  354.          * so that PostScript procedures appearing in the
  355.          * CharStrings dictionary will receive the character code
  356.          * rather than the character name; for Type 3 fonts,
  357.          * prefer BuildGlyph to BuildChar.
  358.          */
  359.         if ( pfont->FontType == ft_user_defined )
  360.         {    /* Type 3 font, prefer BuildGlyph. */
  361.             if ( level2_enabled &&
  362.                  !r_has_type(&pfdata->BuildGlyph, t_null)
  363.                )
  364.             {    name_index_ref(glyph, op);
  365.                 esp[2] = pfdata->BuildGlyph;
  366.             }
  367.             else if ( r_has_type(&pfdata->BuildChar, t_null) )
  368.                 goto err;
  369.             else if ( chr == gs_no_char )
  370.               {    /* glyphshow, reverse map the character */
  371.                 /* through the Encoding */
  372.                 ref gref;
  373.                 const ref *pencoding = &pfdata->Encoding;
  374.                 name_index_ref(glyph, &gref);
  375.                 if ( !map_glyph_to_char(&gref, pencoding,
  376.                             (ref *)op)
  377.                    )
  378.                   {    /* Not found, try .notdef */
  379.                     name_enter_string(".notdef", &gref);
  380.                     if ( !map_glyph_to_char(&gref,
  381.                                 pencoding,
  382.                                 (ref *)op)
  383.                        )
  384.                       goto err;
  385.                   }
  386.                 esp[2] = pfdata->BuildChar;
  387.               }
  388.             else
  389.             {    make_int(op, chr);
  390.                 esp[2] = pfdata->BuildChar;
  391.             }
  392.         }
  393.         else
  394.         {    /* Type 1 font, prefer BuildChar. */
  395.             /* We know that both BuildChar and BuildGlyph */
  396.             /* are present. */
  397.             if ( chr != gs_no_char )
  398.             {    make_int(op, chr);
  399.                 esp[2] = pfdata->BuildChar;
  400.             }
  401.             else
  402.             {    name_index_ref(glyph, op);
  403.                 esp[2] = pfdata->BuildGlyph;
  404.             }
  405.         }
  406.         push_op_estack(op_show_continue);
  407.         ++esp;        /* skip BuildChar or BuildGlyph proc */
  408.     }
  409.         return o_push_estack;
  410.     default:            /* error */
  411. err:        op_show_free();
  412.         if ( code < 0 )
  413.             return code;
  414.         else
  415.             return_error(e_invalidfont);
  416.     }
  417. }
  418. /* Reverse-map a glyph name to a character code for glyphshow. */
  419. private bool
  420. map_glyph_to_char(const ref *pgref, const ref *pencoding, ref *pch)
  421. {    uint esize = r_size(pencoding);
  422.     uint ch;
  423.     ref eref;
  424.     for ( ch = 0; ch < esize; ch++ )
  425.       {    array_get(pencoding, (long)ch, &eref);
  426.         if ( obj_eq(pgref, &eref) )
  427.           { make_int(pch, ch);
  428.             return true;
  429.           }
  430.       }
  431.     return false;
  432. }
  433.  
  434. /* Find the index of the e-stack mark for the current show enumerator. */
  435. /* Return 0 if we can't find the mark. */
  436. uint
  437. op_show_find_index(void)
  438. {    uint count = 0;
  439.     STACK_LOOP_BEGIN(&e_stack, ep, size)
  440.       for ( ep += size - 1; size != 0; size--, ep--, count++ )
  441.         if ( r_is_estack_mark(ep) && estack_mark_index(ep) == es_show )
  442.           return count;
  443.     STACK_LOOP_END(ep, size)
  444.     return 0;            /* no mark */
  445. }
  446.  
  447. /* Find the current show enumerator on the e-stack. */
  448. gs_show_enum *
  449. op_show_find(void)
  450. {    uint index = op_show_find_index();
  451.     if ( index == 0 )
  452.       return 0;            /* no mark */
  453.     return r_ptr(ref_stack_index(&e_stack, index - (snumpush - 1)),
  454.              gs_show_enum);
  455. }
  456.  
  457. /* Shortcut the BuildChar or BuildGlyph procedure at the point */
  458. /* of the setcharwidth or the setcachedevice[2] if we are in */
  459. /* a stringwidth or cshow, or if we are only collecting the scalable */
  460. /* width for an xfont character. */
  461. int
  462. op_show_return_width(os_ptr op, uint npop, float *pwidth)
  463. {    uint index = op_show_find_index();
  464.     es_ptr ep = (es_ptr)ref_stack_index(&e_stack, index - (snumpush - 1));
  465.     int code = gs_setcharwidth(esenum(ep), igs, pwidth[0], pwidth[1]);
  466.     uint ocount, dsaved, dcount;
  467.     if ( code < 0 )
  468.       return code;
  469.     /* Restore the operand and dictionary stacks. */
  470.     ocount = ref_stack_count(&o_stack) - (uint)esodepth(ep).value.intval;
  471.     if ( ocount < npop )
  472.       return_error(e_stackunderflow);
  473.     dsaved = (uint)esddepth(ep).value.intval;
  474.     dcount = ref_stack_count(&d_stack);
  475.     if ( dcount < dsaved )
  476.       return_error(e_dictstackunderflow);
  477.     while ( dcount > dsaved )
  478.       {    code = zend(op);
  479.         if ( code < 0 )
  480.           return code;
  481.         dcount--;
  482.       }
  483.     ref_stack_pop(&o_stack, ocount);
  484.     /* We don't want to pop the mark or the continuation */
  485.     /* procedure (op_show_continue or cshow_continue). */
  486.     pop_estack(index - snumpush);
  487.     return o_pop_estack;
  488. }
  489.  
  490. /* Discard the show record (after an error, or at the end). */
  491. private int
  492. op_show_cleanup(os_ptr op)
  493. {    register es_ptr ep = esp + snumpush;
  494.     if ( r_is_struct(&esslot(ep)) )
  495.       ifree_object(esslot(ep).value.pstruct, "free_show(stream)");
  496.     ifree_object(esenum(ep), "free_show(enum)");
  497.     return 0;
  498. }
  499. void
  500. op_show_free(void)
  501. {    esp -= snumpush;
  502.     op_show_cleanup(osp);
  503. }
  504.