1 /*
2  *   Main page drawing procedure.  Interprets the page commands.  A simple
3  *   (if lengthy) case statement interpreter.
4  */
5 #include "dvips.h" /* The copyright notice in that file is included too! */
6 #include <math.h>
7 /*
8  *   The external declarations:
9  */
10 #include "protos_add.h"
11 
12 #if defined(XENIX) || defined(__THINK__)
13 #define PixRound(x) ((integer)(x + (iconv >> 1)) / iconv)
14 #define VPixRound(x) ((integer)(x + (viconv >> 1)) / viconv)
15 #else
16 #define PixRound(x) ((integer)(floor(((x) * conv) + 0.5)))
17 #define VPixRound(x) ((integer)(floor(((x) * vconv) + 0.5)))
18 #endif
19 /*
20  *   Now we have the dopage procedure.
21  *   Most error checking is suppressed because the prescan has already
22  *   verified that the DVI data is OK....except for stack over/underflow.
23  */
24 struct dvistack stack[STACKSIZE];
25 integer dir;
26 #ifdef HPS
27 integer hhmem, vvmem;
28 integer pushcount = 0;
29 Boolean PAGEUS_INTERUPPTUS = 0;
30 Boolean NEED_NEW_BOX = 0;
31 integer H_BREAK; /* An empirical parameter for guessing line breaks; needs
32                      dpi dependence */
33 #endif
34 
35 void
dopage(void)36 dopage(void)
37 {
38    register shalfword cmd;
39    register integer p;
40    register chardesctype *cd;
41    register integer h;
42    register fontmaptype *cfnt;
43    register frametype *frp = frames;
44    integer fnt;
45    integer mychar;
46    int charmove;
47    struct dvistack *sp = stack;
48    integer v, w, x, y, z;
49    integer roundpos;
50    integer thinspace;
51    integer vertsmallspace;
52 #if defined(XENIX) || defined(__THINK__)
53    integer iconv;
54    integer viconv;
55 
56    iconv = (integer)(1.0 / conv + 0.5);
57    viconv = (integer)(1.0 / vconv + 0.5);
58 #endif
59 #ifdef EMTEX
60    emclear();
61 #endif
62    pageinit();
63 
64    bopcolor(1);
65    thinspace =  (integer)(0.025*DPI/conv); /* 0.025 inches */
66    vertsmallspace = (integer)(0.025*VDPI/vconv); /* 0.025 inches */
67 #ifdef HPS
68    if (HPS_FLAG) pagecounter++;
69    H_BREAK = (30 * DPI / 400 ); /* 30 seems to have worked well at 400 dpi */
70 #endif
71    w = x = y = z = dir = rdir = fdir = 0;
72    h = (integer) (DPI / conv * hoff / 4736286.72);
73    v = (integer) (DPI / conv * voff / 4736286.72);
74    hh = PixRound(h);
75    vv = PixRound(v);
76    curfnt = NULL;
77    curpos = NULL;
78    charmove = 0;
79 beginloop:
80    switch (cmd=dvibyte()) {
81 case 138: goto beginloop; /* nop command does nuttin */
82 /*
83  *   For put1 commands, we subtract the width of the character before
84  *   dropping through to the normal character setting routines.  This
85  */
86 case 135: /* put3 */
87    if (noptex) error("! synch");
88    mychar = dvibyte();
89    mychar = (mychar << 8) + dvibyte();
90    mychar = (mychar << 8) + dvibyte();
91    charmove = 0;
92    goto dochar;
93 case 130: /* set3 */
94    if (noptex) error("! synch");
95    mychar = dvibyte();
96    mychar = (mychar << 8) + dvibyte();
97    mychar = (mychar << 8) + dvibyte();
98    charmove = 1;
99    goto dochar;
100 case 134: /* put2 */
101    if (noomega && noptex) error("! synch");
102    mychar = dvibyte();
103    mychar = (mychar << 8) + dvibyte();
104    charmove = 0;
105    goto dochar;
106 case 129: /* set2 */
107    if (noomega && noptex) error("! synch");
108    mychar = dvibyte();
109    mychar = (mychar << 8) + dvibyte();
110    charmove = 1;
111    goto dochar;
112 case 133: /* put1 */
113    mychar = dvibyte();
114    charmove = 0;
115    goto dochar;
116 case 128: cmd = dvibyte(); /* set1 command drops through to setchar */
117 default: /* these are commands 0 (setchar0) thru 127 (setchar127) */
118    mychar = cmd;
119    charmove = 1;
120 dochar:
121 #ifdef HPS
122    if (HPS_FLAG && PAGEUS_INTERUPPTUS) {
123      HREF_COUNT--;
124      start_new_box();
125      PAGEUS_INTERUPPTUS = 0;
126      }
127    if (HPS_FLAG && NEED_NEW_BOX) {
128        vertical_in_hps();
129        NEED_NEW_BOX = 0;
130        }
131 #endif
132    cd = &(curfnt->chardesc[mychar]);
133    if (cd->flags & EXISTS) {
134       if (curfnt->loaded == 2) { /* virtual character being typeset */
135          if (charmove) {
136             if (!dir) {
137                sp->hh = hh + cd->pixelwidth;
138                sp->h = h + cd->TFMwidth;
139             } else {
140                sp->v = v + cd->TFMwidth;
141                sp->vv = PixRound(sp->v);
142             }
143          } else {
144             if (!dir) {
145                sp->hh = hh; sp->h = h;
146             } else {
147                sp->vv = vv; sp->v = v;
148             }
149          }
150          if (!dir) {
151             sp->vv = vv; sp->v = v;
152          } else {
153             sp->hh = hh; sp->h = h;
154          }
155          sp->w = w; sp->x = x; sp->y = y; sp->z = z; sp->dir = dir;
156          if (++sp >= &stack[STACKSIZE]) error("! Out of stack space");
157          w = x = y = z = 0; /* will be in relative units at new stack level */
158          frp->curp = curpos;
159          frp->curl = curlim;
160          frp->ff = ffont;
161          frp->curf = curfnt;
162          if (++frp == &frames[MAXFRAME] )
163             error("! virtual recursion stack overflow");
164          curpos = cd->packptr + 2;
165          curlim = curpos + (256*(long)(*cd->packptr)+(*(cd->packptr+1)));
166          ffont = curfnt->localfonts;
167          if (ffont) {
168             curfnt = ffont->desc;
169             thinspace = curfnt->thinspace;
170          } else {
171             curfnt = NULL;
172             thinspace = vertsmallspace;
173          }
174          goto beginloop;
175       }
176       drawchar(cd, mychar);
177    }
178    if (charmove) {
179       if (!dir) {
180          h += cd->TFMwidth;
181          hh += cd->pixelwidth;
182       } else {
183          v += cd->TFMwidth;
184          vv += cd->pixelwidth;
185       }
186    }
187    goto setmotion;
188 case 255: /* pTeX's dir or undefined */
189    if (!noptex) {
190       dir = dvibyte();
191       cmddir();
192       goto beginloop;
193    }
194 /* illegal commands */
195 case 131: case 136: case 139: /* set4, put4, bop */
196 case 247: case 248: case 249: /* pre, post, post_post */
197 case 250: case 251: case 252: case 253: case 254: /* undefined */
198    error("! synch");
199 case 132: case 137: /* rules */
200  { integer ry, rx , rxx, ryy;
201    ry = signedquad(); rx = signedquad();
202    if (rx>0 && ry>0) {
203       if (curpos) {
204          rx = scalewidth(rx, (frp-1)->curf->scaledsize);
205          ry = scalewidth(ry, (frp-1)->curf->scaledsize);
206       }
207       if (!dir) {
208         rxx = (int)(conv * rx + 0.9999999);
209         ryy = (int)(vconv * ry + 0.9999999);
210       }
211       else {
212         rxx = (int)(vconv * rx + 0.9999999);
213         ryy = (int)(conv * ry + 0.9999999);
214       }
215       /* Heiko Oberdiek 2001/06/03: synchronisation added for vertical rules
216          because of alignment reasons.
217       */
218       if (ry > rx) {
219         hh = PixRound(h);
220       }
221       drawrule(rxx, ryy);
222    } else
223       rxx = 0;
224    if (cmd == 137) goto beginloop;
225    if (!dir) {
226      h += rx; hh += rxx;
227    }
228    else {
229      v += rx; vv += rxx;
230    }
231    goto setmotion;
232  }
233 case 141: /* push */
234 #ifdef HPS
235     if (HPS_FLAG) pushcount++;
236   /*  if (HPS_FLAG && PAGEUS_INTERUPPTUS) {
237       HREF_COUNT--;
238       start_new_box();
239       PAGEUS_INTERUPPTUS = 0;
240      } */
241     if (HPS_FLAG && NEED_NEW_BOX) {
242        vertical_in_hps();
243        NEED_NEW_BOX = 0;
244        }
245     /* printf("push %i, %i\n", pushcount, inHTMLregion); */
246 #endif
247    sp->hh = hh; sp->vv = vv; sp->h = h; sp->v = v;
248    sp->w = w; sp->x = x; sp->y = y; sp->z = z; sp->dir = dir;
249    if (++sp >= &stack[STACKSIZE]) error("! Out of stack space");
250    goto beginloop;
251 case 140: /* eop or end of virtual character */
252    if (curpos == NULL) { /* eop */
253 #ifdef HPS
254      if (HPS_FLAG && inHTMLregion) PAGEUS_INTERUPPTUS = 1;
255     /* printf("Page interrupted"); */
256 #endif
257      break;
258    }
259    --frp;
260    curfnt = frp->curf;
261    thinspace = (curfnt) ? curfnt->thinspace : vertsmallspace;
262    ffont = frp->ff;
263    curlim = frp->curl;
264    curpos = frp->curp;
265    if (hh < (sp-1)->hh+2 && hh > (sp-1)->hh-2)
266       (sp-1)->hh = hh; /* retain `intelligence' of pixel width, if close */
267    /* falls through */
268 case 142: /* pop */
269 #ifdef HPS
270    pushcount--;
271   /* printf("pop %i\n", pushcount); */
272 #endif
273    if (--sp < stack) error("! More pops than pushes");
274 #ifdef HPS
275    if (HPS_FLAG) {
276       hhmem = hh; vvmem = vv;
277      }
278 #endif
279    hh = sp->hh; vv = sp->vv; h = sp->h; v = sp->v;
280    w = sp->w; x = sp->x; y = sp->y; z = sp->z; dir = sp->dir;
281 #ifdef HPS
282    if (HPS_FLAG && inHTMLregion && (hhmem - hh > H_BREAK) && (pushcount > 0) &&
283        (pushcount < current_pushcount))
284      end_current_box();
285 #endif
286    cmddir();
287    goto beginloop;
288 case 143: /* right1 */
289    p = signedbyte(); goto horizontalmotion;
290 case 144: /* right2 */
291    p = signedpair(); goto horizontalmotion;
292 case 145: /* right3 */
293    p = signedtrio(); goto horizontalmotion;
294 case 146: /* right4 */
295    p = signedquad(); goto horizontalmotion;
296 case 147: /* w0 */
297    p = w; goto horizontalmotion;
298 case 148: /* w1 */
299    p = w = signedbyte(); goto horizontalmotion;
300 case 149: /* w2 */
301    p = w = signedpair(); goto horizontalmotion;
302 case 150: /* w3 */
303    p = w = signedtrio(); goto horizontalmotion;
304 case 151: /* w4 */
305    p = w = signedquad(); goto horizontalmotion;
306 case 152: /* x0 */
307    p = x; goto horizontalmotion;
308 case 153: /* x1 */
309    p = x = signedbyte(); goto horizontalmotion;
310 case 154: /* x2 */
311    p = x = signedpair(); goto horizontalmotion;
312 case 155: /* x3 */
313    p = x = signedtrio(); goto horizontalmotion;
314 case 156: /* x4 */
315    p = x = signedquad(); goto horizontalmotion;
316 case 157: /* down1 */
317    p = signedbyte(); goto verticalmotion;
318 case 158: /* down2 */
319    p = signedpair(); goto verticalmotion;
320 case 159: /* down3 */
321    p = signedtrio(); goto verticalmotion;
322 case 160: /* down4 */
323    p = signedquad(); goto verticalmotion;
324 case 161: /* y0 */
325    p = y; goto verticalmotion;
326 case 162: /* y1 */
327    p = y = signedbyte(); goto verticalmotion;
328 case 163: /* y2 */
329    p = y = signedpair(); goto verticalmotion;
330 case 164: /* y3 */
331    p = y = signedtrio(); goto verticalmotion;
332 case 165: /* y4 */
333    p = y = signedquad(); goto verticalmotion;
334 case 166: /* z0 */
335    p = z; goto verticalmotion;
336 case 167: /* z1 */
337    p = z = signedbyte(); goto verticalmotion;
338 case 168: /* z2 */
339    p = z = signedpair(); goto verticalmotion;
340 case 169: /* z3 */
341    p = z = signedtrio(); goto verticalmotion;
342 case 170: /* z4 */
343    p = z = signedquad(); goto verticalmotion;
344 case 171: case 172: case 173: case 174: case 175: case 176: case 177:
345 case 178: case 179: case 180: case 181: case 182: case 183: case 184:
346 case 185: case 186: case 187: case 188: case 189: case 190: case 191:
347 case 192: case 193: case 194: case 195: case 196: case 197: case 198:
348 case 199: case 200: case 201: case 202: case 203: case 204: case 205:
349 case 206: case 207: case 208: case 209: case 210: case 211: case 212:
350 case 213: case 214: case 215: case 216: case 217: case 218: case 219:
351 case 220: case 221: case 222: case 223: case 224: case 225: case 226:
352 case 227: case 228: case 229: case 230: case 231: case 232: case 233:
353 case 234: case 235: case 236: case 237: case 238: /* font selection commands */
354    if (cmd < 235) fnt = cmd - 171; /* fntnum0 thru fntnum63 */
355    else {
356       fnt = dvibyte();
357       while (cmd-- > 235)
358          fnt = (fnt << 8) + dvibyte();
359    }
360    for (cfnt=ffont; cfnt; cfnt = cfnt->next)
361       if (cfnt->fontnum == fnt) break;
362    curfnt = cfnt->desc;
363    thinspace = curfnt->thinspace;
364    goto beginloop;
365 case 243: case 244: case 245: case 246: /*fntdef1 */
366    skipover(cmd - 230);
367    skipover(dvibyte() + dvibyte());
368    goto beginloop;
369 case 239: /* xxx1 */
370    p = dvibyte();
371    dospecial(p);
372    goto beginloop;
373 case 240: /* xxx2 */
374    p = twobytes();
375    dospecial(p);
376    goto beginloop;
377 case 241: /* xxx3 */
378    p = threebytes();
379    dospecial(p);
380    goto beginloop;
381 case 242: /* xxx4 */
382    p = signedquad();
383    dospecial(p);
384    goto beginloop;
385 
386 /*
387  *   The calculations here are crucial to the appearance of the document.
388  *   If the motion is small, we round the amount of relative motion; otherwise,
389  *   we update the position and round the new position.  Then we check to
390  *   insure that the rounded position didn't accumulate an error that was
391  *   greater than maxdrift.
392  */
393 verticalmotion:
394 /* vertical motion cases */
395       if (curpos)
396          p = scalewidth(p, (frp-1)->curf->scaledsize);
397       if (!dir) {
398          v += p;
399          if (p >= vertsmallspace) vv = VPixRound(v);
400          else if (p <= -vertsmallspace) vv = VPixRound(v);
401          else
402          { vv += VPixRound(p);
403            roundpos = VPixRound(v);
404            if (roundpos - vv > vmaxdrift) vv = roundpos - vmaxdrift;
405            else if (vv - roundpos > vmaxdrift) vv = roundpos + vmaxdrift;
406          }
407       } else {
408          h -= p;
409          if (p >= vertsmallspace) hh = VPixRound(h);
410          else if (p <= -vertsmallspace) hh = VPixRound(h);
411          else
412          { hh -= VPixRound(p);
413            roundpos = VPixRound(h);
414            if (roundpos - hh > vmaxdrift) hh = roundpos - vmaxdrift;
415            else if (hh - roundpos > vmaxdrift) hh = roundpos + vmaxdrift;
416          }
417       }
418 #ifdef HPS
419    /* printf("Doing vertical motion: p = %i, v = %i, vv = %i\n",p,v,vv); */
420 		/* printf("inHTMLregion %i\n", inHTMLregion); */
421      if (HPS_FLAG && inHTMLregion) NEED_NEW_BOX = 1 /* vertical_in_hps() */;
422 #endif
423       goto beginloop;
424 /*
425  *   Horizontal motion is analogous. We know the exact width of each
426  *   character in pixels. Kerning is distinguished from space between
427  *   words if it's less than a thinspace and not more negative than would
428  *   occur when an accent is being positioned by backspacing.
429  */
430 horizontalmotion:
431 /* horizontal motion cases */
432       if (curpos)
433          p = scalewidth(p, (frp-1)->curf->scaledsize);
434       if (!dir) {
435          h += p;
436          if (p >= thinspace || p <= -6 * thinspace) {
437             hh = PixRound(h); goto beginloop;
438          }
439          else hh += PixRound(p);
440       } else {
441          v += p;
442          if (p >= thinspace || p <= -6 * thinspace) {
443             vv = PixRound(v); goto beginloop;
444          }
445          else vv += PixRound(p);
446       }
447 #ifdef HPS
448     /* printf("Doing horizontal motion: p = %i, h = %i, hh = %i\n",p,h,hh); */
449 #endif
450 setmotion:
451       if (!dir) {
452          roundpos = PixRound(h);
453          if (roundpos - hh > maxdrift) { hh = roundpos - maxdrift; }
454          else if (hh - roundpos > maxdrift) { hh = roundpos + maxdrift; }
455       } else {
456          roundpos = PixRound(v);
457          if (roundpos - vv > maxdrift) { vv = roundpos - maxdrift; }
458          else if (vv - roundpos > maxdrift) { vv = roundpos + maxdrift; }
459       }
460 goto beginloop;
461 
462    } /* end of the big switch */
463    pageend();
464 }
465