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