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

  1. /* Copyright (C) 1990, 1992, 1993 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. /* gxhint2.c */
  20. /* Character level hints for Type 1 fonts. */
  21. #include "gx.h"
  22. #include "gserrors.h"
  23. #include "gxarith.h"
  24. #include "gxfixed.h"
  25. #include "gxmatrix.h"
  26. #include "gzstate.h"
  27. #include "gxdevmem.h"            /* ditto */
  28. #include "gxchar.h"
  29. #include "gxfont.h"
  30. #include "gxfont1.h"
  31. #include "gxtype1.h"
  32. #include "gxop1.h"
  33.  
  34. /* Define the tolerance for testing whether a point is in a zone, */
  35. /* in device pixels.  (Maybe this should be variable?) */
  36. #define stem_tolerance float2fixed(0.05)
  37.  
  38. /* Forward references */
  39.  
  40. private stem_hint *near type1_stem(P3(stem_hint_table *, fixed, fixed));
  41. private fixed near find_snap(P3(fixed, const stem_snap_table *, const pixel_scale *));
  42. private alignment_zone *near find_zone(P3(gs_type1_state *, fixed, fixed));
  43.  
  44. /* Reset the stem hints. */
  45. void
  46. reset_stem_hints(register gs_type1_state *pis)
  47. {    pis->hstem_hints.count = 0;
  48.     pis->vstem_hints.count = 0;
  49.     update_stem_hints(pis);
  50. }
  51.  
  52. /* Update the internal stem hint pointers after moving or copying the state. */
  53. void
  54. update_stem_hints(register gs_type1_state *pis)
  55. {    pis->hstem_hints.current = &pis->hstem_hints.data[0];
  56.     pis->vstem_hints.current = &pis->vstem_hints.data[0];
  57. }
  58.  
  59. /* ------ Add hints ------ */
  60.  
  61. #define c_fixed(d, c) m_fixed(d, c, pis->fc, max_coeff_bits)
  62.  
  63. /* Add a horizontal stem hint. */
  64. void
  65. type1_hstem(register gs_type1_state *pis, fixed y, fixed dy)
  66. {    stem_hint *psh;
  67.     alignment_zone *pz;
  68.     const pixel_scale *psp;
  69.     fixed v, dv, adj_dv;
  70.     fixed vtop, vbot;
  71.     fixed center, diff_v, diff2_dv;
  72.     if ( !pis->fh.use_y_hints ) return;
  73.     y += pis->lsb.y;
  74.     if ( pis->fh.axes_swapped )
  75.         psp = &pis->scale.x,
  76.         v = pis->vs_offset.x + c_fixed(y, yx) +
  77.             pis->pgs->ctm.tx_fixed,
  78.         dv = c_fixed(dy, yx);
  79.     else
  80.         psp = &pis->scale.y,
  81.         v = pis->vs_offset.y + c_fixed(y, yy) +
  82.             pis->pgs->ctm.ty_fixed,
  83.         dv = c_fixed(dy, yy);
  84.     if ( dy < 0 )
  85.         vbot = v + dv, vtop = v;
  86.     else
  87.         vbot = v, vtop = v + dv;
  88.     if ( dv < 0 ) v += dv, dv = -dv;
  89.     psh = type1_stem(&pis->hstem_hints, v, dv);
  90.     if ( psh == 0 ) return;
  91.     adj_dv = find_snap(dv, &pis->fh.snap_h, psp);
  92.     pz = find_zone(pis, vbot, vtop);
  93.     if ( pz != 0 )
  94.     {    /* Use the alignment zone to align the outer stem edge. */
  95.         int inverted =
  96.           (pis->fh.axes_swapped ? pis->fh.x_inverted : pis->fh.y_inverted);
  97.         int adjust_v1 =
  98.           (inverted ? !pz->is_top_zone : pz->is_top_zone);
  99.         fixed flat_v = pz->flat;
  100.         fixed overshoot =
  101.             (pz->is_top_zone ? vtop - flat_v : flat_v - vbot);
  102.         fixed pos_over =
  103.             (inverted ? -overshoot : overshoot);
  104.         fixed ddv = adj_dv - dv;
  105.         fixed shift = scaled_rounded(flat_v, psp) - flat_v;
  106.         if ( pos_over > 0 )
  107.         {
  108.           if ( pos_over < pis->fh.blue_shift || pis->fh.suppress_overshoot )
  109.           {    /* Character is small, suppress overshoot. */
  110.             if_debug0('y', "[y]suppress overshoot\n");
  111.             if ( pz->is_top_zone )
  112.                 shift -= overshoot;
  113.             else
  114.                 shift += overshoot;
  115.           }
  116.           else
  117.           if ( pos_over < psp->unit )
  118.           {    /* Enforce overshoot. */
  119.             if_debug0('y', "[y]enforce overshoot\n");
  120.             if ( overshoot < 0 )
  121.                 overshoot = -psp->unit - overshoot;
  122.             else
  123.                 overshoot = psp->unit - overshoot;
  124.             if ( pz->is_top_zone )
  125.                 shift += overshoot;
  126.             else
  127.                 shift -= overshoot;
  128.           }
  129.         }
  130.         if ( adjust_v1 )
  131.             psh->dv1 = shift, psh->dv0 = shift - ddv;
  132.         else
  133.             psh->dv0 = shift, psh->dv1 = shift + ddv;
  134.         if_debug4('y', "[y]flat_v = %g, overshoot = %g, dv=%g,%g\n",
  135.               fixed2float(flat_v), fixed2float(overshoot),
  136.               fixed2float(psh->dv0), fixed2float(psh->dv1));
  137.         return;
  138.     }
  139.     /* Align the stem so its edges fall on pixel boundaries, */
  140.     /* moving the center as little as possible. */
  141.     center = v + arith_rshift_1(dv);
  142.     if ( adj_dv & psp->unit )
  143.     {    /* Odd width, align center on half-pixel. */
  144.         center += psp->half;
  145.     }
  146.     diff_v = scaled_rounded(center, psp) - center;
  147.     diff2_dv = arith_rshift_1(adj_dv - dv);
  148.     psh->dv0 = diff_v - diff2_dv;
  149.     psh->dv1 = diff_v + diff2_dv;
  150.     if_debug6('y', "[y]hstem %g,%g -> %g,%g ; d = %g,%g\n",
  151.           fixed2float(y), fixed2float(dy),
  152.           fixed2float(v), fixed2float(dv),
  153.           fixed2float(psh->dv0), fixed2float(psh->dv1));
  154. }
  155.  
  156. /* Add a vertical stem hint. */
  157. void
  158. type1_vstem(register gs_type1_state *pis, fixed x, fixed dx)
  159. {    stem_hint *psh;
  160.     const pixel_scale *psp;
  161.     fixed v, dv, adj_dv;
  162.     fixed center, diff_v, diff2_dv;
  163.     if ( !pis->fh.use_x_hints ) return;
  164.     x += pis->lsb.x;
  165.     if ( pis->fh.axes_swapped )
  166.         psp = &pis->scale.y,
  167.         v = pis->vs_offset.y + c_fixed(x, xy) +
  168.             pis->pgs->ctm.ty_fixed,
  169.         dv = c_fixed(dx, xy);
  170.     else
  171.         psp = &pis->scale.x,
  172.         v = pis->vs_offset.x + c_fixed(x, xx) +
  173.             pis->pgs->ctm.tx_fixed,
  174.         dv = c_fixed(dx, xx);
  175.     if ( dv < 0 ) v += dv, dv = -dv;
  176.     psh = type1_stem(&pis->vstem_hints, v, dv);
  177.     if ( psh == 0 ) return;
  178.     adj_dv = find_snap(dv, &pis->fh.snap_v, psp);
  179.     if ( pis->pdata->ForceBold && adj_dv < psp->unit )
  180.         adj_dv = psp->unit;
  181.     /* Align the stem so its edges fall on pixel boundaries, */
  182.     /* moving the center as little as possible. */
  183.     center = v + arith_rshift_1(dv);
  184.     if ( adj_dv & psp->unit )
  185.     {    /* Odd width, align center on half-pixel. */
  186.         center += psp->half;
  187.     }
  188.     diff_v = scaled_rounded(center, psp) - center;
  189.     diff2_dv = arith_rshift_1(adj_dv - dv);
  190.     psh->dv0 = diff_v - diff2_dv;
  191.     psh->dv1 = diff_v + diff2_dv;
  192.     if_debug6('y', "[y]vstem %g,%g -> %g,%g ; d = %g,%g\n",
  193.           fixed2float(x), fixed2float(dx),
  194.           fixed2float(v), fixed2float(dv),
  195.           fixed2float(psh->dv0), fixed2float(psh->dv1));
  196. }
  197.  
  198. /* Adjust the character center for a vstem3. */
  199. /****** NEEDS UPDATING FOR SCALE ******/
  200. void
  201. center_vstem(gs_type1_state *pis, fixed x0, fixed dx)
  202. {    fixed x1 = x0 + dx;
  203.     gs_fixed_point pt0, pt1, width;
  204.     fixed center, int_width;
  205.     fixed *psxy;
  206.     if ( gs_point_transform2fixed(&pis->pgs->ctm,
  207.                       fixed2float(x0), 0.0, &pt0) < 0 ||
  208.          gs_point_transform2fixed(&pis->pgs->ctm,
  209.                       fixed2float(x1), 0.0, &pt1) < 0
  210.        )
  211.       {    /* Punt. */
  212.         return;
  213.       }
  214.     width.x = pt0.x - pt1.x;
  215.     if ( width.x < 0 )
  216.       width.x = - width.x;
  217.     width.y = pt0.y - pt1.y;
  218.     if ( width.y < 0 )
  219.       width.y = - width.y;
  220.     if ( width.y < float2fixed(0.05) )
  221.     {    /* Vertical on device */
  222.         center = arith_rshift_1(pt0.x + pt1.x);
  223.         int_width = fixed_rounded(width.x);
  224.         psxy = &pis->vs_offset.x;
  225.     }
  226.     else
  227.     {    /* Horizontal on device */
  228.         center = arith_rshift_1(pt0.y + pt1.y);
  229.         int_width = fixed_rounded(width.y);
  230.         psxy = &pis->vs_offset.y;
  231.     }
  232.     if ( int_width == fixed_0 || (int_width & fixed_1) == 0 )
  233.     {    /* Odd width, center stem over pixel. */
  234.         *psxy = fixed_floor(center) + fixed_half - center;
  235.     }
  236.     else
  237.     {    /* Even width, center stem between pixels. */
  238.         *psxy = fixed_rounded(center) - center;
  239.     }
  240.     /* We can't fix up the current point here, */
  241.     /* but we can fix up everything else. */
  242.     /****** TO BE COMPLETED ******/
  243. }
  244.  
  245. /* Add a stem hint, keeping the table sorted. */
  246. /* Return the stem hint pointer, or 0 if the table is full. */
  247. private stem_hint *near
  248. type1_stem(stem_hint_table *psht, fixed v0, fixed d)
  249. {    stem_hint *bot = &psht->data[0];
  250.     stem_hint *top = bot + psht->count;
  251.     if ( psht->count >= max_stems ) return 0;
  252.     while ( top > bot && v0 < top[-1].v0 )
  253.        {    *top = top[-1];
  254.         top--;
  255.        }
  256.     /* Add a little fuzz for insideness testing. */
  257.     top->v0 = v0 - stem_tolerance;
  258.     top->v1 = v0 + d + stem_tolerance;
  259.     psht->count++;
  260.     return top;
  261. }
  262.  
  263. /* Compute the adjusted width of a stem. */
  264. /* The value returned is always a multiple of scale.unit. */
  265. private fixed near
  266. find_snap(fixed dv, const stem_snap_table *psst, const pixel_scale *pps)
  267. {    fixed best = pps->half;
  268.     fixed adj_dv;
  269.     int i;
  270.     for ( i = 0; i < psst->count; i++ )
  271.     {    fixed diff = psst->data[i] - dv;
  272.         if ( any_abs(diff) < any_abs(best) )
  273.         {    if_debug3('Y', "[Y]possibly snap %g to [%d]%g\n",
  274.                   fixed2float(dv), i,
  275.                   fixed2float(psst->data[i]));
  276.             best = diff;
  277.         }
  278.     }
  279.     adj_dv = scaled_rounded((any_abs(best) < pps->half ? dv + best : dv),
  280.                 pps);
  281.     if ( adj_dv == 0 )
  282.         adj_dv = pps->unit;
  283. #ifdef DEBUG
  284.     if ( adj_dv == dv )
  285.         if_debug1('Y', "[Y]no snap %g\n", fixed2float(dv));
  286.     else
  287.         if_debug2('Y', "[Y]snap %g to %g\n",
  288.               fixed2float(dv), fixed2float(adj_dv));
  289. #endif
  290.     return adj_dv;
  291. }
  292.  
  293. /* Find the applicable alignment zone for a stem, if any. */
  294. /* vbot and vtop are the bottom and top of the stem, */
  295. /* but without interchanging if the y axis is inverted. */
  296. private alignment_zone *near
  297. find_zone(gs_type1_state *pis, fixed vbot, fixed vtop)
  298. {    alignment_zone *pz;
  299.     for ( pz = &pis->fh.a_zones[pis->fh.a_zone_count];
  300.           --pz >= &pis->fh.a_zones[0];
  301.         )
  302.     {    fixed v = (pz->is_top_zone ? vtop : vbot);
  303.         if ( v >= pz->v0 && v <= pz->v1 )
  304.         {    if_debug2('Y', "[Y]stem crosses %s-zone %d\n",
  305.                   (pz->is_top_zone ? "top" : "bottom"),
  306.                   (int)(pz - &pis->fh.a_zones[0]));
  307.             return pz;
  308.         }
  309.     }
  310.     return 0;
  311. }
  312.  
  313. /* ------ Apply hints ------ */
  314.  
  315. private stem_hint *near search_hints(P2(stem_hint_table *, fixed));
  316.  
  317. /* Adjust a point according to the relevant hints. */
  318. /* x and y are the current point in device space after moving; */
  319. /* dx and dy are the delta components in character space. */
  320. void
  321. find_stem_hints(gs_type1_state *pis, fixed x, fixed y,
  322.   fixed dx, fixed dy, gs_fixed_point *ppt)
  323. {    ppt->x = x, ppt->y = y;
  324.     if ( pis->in_dotsection ) return;
  325.     /* Note that if use_x/y_hints is false, */
  326.     /* no entries ever get made in the stem hint tables, */
  327.     /* so we don't have to check those flags here. */
  328.     /* Check the vertical stem hints. */
  329.     if ( pis->vstem_hints.count )
  330.     {    fixed *pv = (pis->fh.axes_swapped ? &ppt->y : &ppt->x);
  331.         stem_hint *ph = search_hints(&pis->vstem_hints, *pv);
  332.         if ( ph != 0 )
  333.         {    /* Decide which side of the stem we are on. */
  334.             /* If we're moving horizontally, just use the */
  335.             /* x coordinate; otherwise, assume outside */
  336.             /* edges move clockwise and inside edges move */
  337.             /* counter-clockwise.  (This algorithm was */
  338.             /* taken from the IBM X11R5 rasterizer; I'm not */
  339.             /* sure I believe it.) */
  340. #define adjust_stem(pv, dxy, ph, inverted)\
  341.   *pv +=\
  342.     ((/*dxy == 0 ?*/ *pv < arith_rshift_1(ph->v0 +\
  343.       ph->v1) /*: inverted ? dxy < 0 : dxy > 0*/) ?\
  344.      ph->dv0 : ph->dv1)
  345.             if_debug2('Y', "[Y]use vstem %d: %g",
  346.                   (int)(ph - &pis->vstem_hints.data[0]),
  347.                   fixed2float(*pv));
  348.             adjust_stem(pv, dy, ph, pis->fh.y_inverted);
  349.             if_debug1('Y', " -> %g\n", fixed2float(*pv));
  350.         }
  351.     }
  352.     /* Check the horizontal stem hints. */
  353.     if ( pis->hstem_hints.count )
  354.     {    fixed *pv = (pis->fh.axes_swapped ? &ppt->x : &ppt->y);
  355.         stem_hint *ph = search_hints(&pis->hstem_hints, *pv);
  356.         if ( ph != 0 )
  357.         {    if_debug2('Y', "[Y]use hstem %d: %g",
  358.                   (int)(ph - &pis->hstem_hints.data[0]),
  359.                   fixed2float(*pv));
  360.             adjust_stem(pv, dx, ph, pis->fh.x_inverted);
  361.             if_debug1('Y', " -> %g\n", fixed2float(*pv));
  362.         }
  363.     }
  364.     return;
  365. #undef adjust_stem
  366. }
  367.  
  368. /* Search one hint table for an adjustment. */
  369. private stem_hint *near
  370. search_hints(stem_hint_table *psht, fixed v)
  371. {    stem_hint *ph = psht->current;
  372.     if ( v >= ph->v0 && v <= ph->v1 ) return ph;
  373.     /* We don't bother with binary or even up/down search, */
  374.     /* because there won't be very many hints. */
  375.     for ( ph = &psht->data[psht->count]; --ph >= &psht->data[0]; )
  376.       if ( v >= ph->v0 && v <= ph->v1 )
  377.         return (psht->current = ph);
  378.     return 0;
  379. }
  380.  
  381.