queue.cc (5717B)
1 #include "misc.h" 2 #include "slug.h" 3 #include "range.h" 4 #include "page.h" 5 6 queue squeue; 7 queue bfqueue; 8 queue ufqueue; 9 10 // We use the stream function current() to access a queue's head. 11 // Thus, queue member curr should always point to its first range. 12 void queue::check(char *whence) 13 { 14 if (dbg & 8) { 15 char *p; 16 if (this == &squeue) 17 p = "squeue"; 18 else if (this == &bfqueue) 19 p = "bfqueue"; 20 else if (this == &ufqueue) 21 p = "ufqueue"; 22 else 23 p = "weird queue"; 24 printf("#checking %s\n", p); 25 } 26 if (first != curr) 27 ERROR "check(%s): first != curr, line %d\n", whence, curr->rp->lineno() FATAL; 28 } 29 30 // When ranges are told to enqueue themselves, they are being rejected from the 31 // stage back onto their original queues. 32 // They reset any parameters that may have been altered by staging or trial 33 // composition. 34 35 void range::enqueue(int block) 36 { 37 squeue.enqueue(this); 38 if (block) 39 squeue.block(); 40 } 41 42 void ufrange::enqueue(int block) 43 { 44 restore(); // both goal positions 45 ufqueue.enqueue(this); 46 if (block) 47 ufqueue.block(); 48 } 49 50 void bfrange::enqueue(int block) 51 { 52 restore(); // both goal positions 53 bfqueue.enqueue(this); 54 if (block) 55 bfqueue.block(); 56 } 57 58 int anymore() 59 { 60 return !(squeue.empty() && ufqueue.empty() && bfqueue.empty()); 61 } 62 63 void mergestream::unblock() 64 { 65 squeue.unblock(); 66 bfqueue.unblock(); 67 ufqueue.unblock(); 68 } 69 70 // Fill the staging area with a minimal chunk of input ranges. 71 int mergestream::prime() 72 { 73 if (dbg & 4) 74 printf("#entering mergestream::prime()\n"); 75 if (!empty()) 76 return 1; 77 int brkok = 1; // is it OK to break after the last 78 // VBOX that was added to the stage? 79 int needheight = -1; // minimum acceptable height of the 80 // chunk being constructed on stage 81 // If the range at the head of any queue is breaking, 82 // deal with it first. 83 if (squeue.more() && squeue.current()->breaking()) 84 enqueue(squeue.dequeue()); 85 else if (bfqueue.more() && (bfqueue.current()->breaking() || 86 (bfqueue.serialno() < squeue.serialno()))) 87 enqueue(bfqueue.dequeue()); 88 else if (ufqueue.more() && (ufqueue.current()->breaking() || 89 (ufqueue.serialno() < squeue.serialno()))) 90 enqueue(ufqueue.dequeue()); 91 else while (squeue.more()) { 92 // Fill the stage with enough ranges to be a valid chunk. 93 range *r = squeue.dequeue(); 94 if (r->isvbox()) { // VBOX 95 if (dbg & 16) 96 printf("#VBOX: !empty: %d; brkok: %d; vsince: %d\n", 97 !empty(), brkok, currpage->vsince); 98 if (!empty() // there's something there 99 && brkok 100 // it's OK to break here 101 && currpage->vsince >= 2 102 // enough stream has gone onto this page 103 && rawht() >= needheight 104 // current need has been satisfied 105 ) { 106 // the stage already contains enough 107 // ranges, so this one can wait 108 r->enqueue(); 109 break; 110 } else { 111 if (r->rawht() > 0) { 112 ++currpage->vsince; 113 brkok = r->brkafter(); 114 } 115 enqueue(r); 116 } 117 } else if (r->isnested() || r->issp()) { // US, SP 118 if (!empty() && rawht() >= needheight) { 119 // enough already, wait 120 r->enqueue(); 121 break; 122 } 123 currpage->vsince = 0; 124 enqueue(r); 125 if (height() >= needheight) 126 break; 127 } else if (r->isneed()) { // NE 128 if (!empty() && rawht() >= needheight) { 129 // not currently working on an unsatisfied NEed 130 r->enqueue(); 131 break; 132 } 133 // deal with overlapping NEeds 134 needheight = rawht() + max(needheight - rawht(), r->needht()); 135 enqueue(r); 136 } else if (r->forceflush() == NO) { 137 enqueue(r); 138 } else if (r->forceflush() == YES) { 139 currpage->vsince = 0; 140 if (!empty()) { 141 // ready or not, r must wait 142 r->enqueue(); 143 break; 144 } 145 enqueue(r); 146 break; 147 } else 148 ERROR "unexpected %s[%s] in prime(), line %d\n", 149 r->typename(), r->headstr(), r->lineno() FATAL; 150 } 151 return more(); // 0 if nothing was staged 152 } 153 154 void page::cmdproc() 155 { 156 if (stage->next()) 157 ERROR "more than a single command on bsqueue\n" FATAL; 158 switch (stage->current()->cmdtype()) { 159 case FC: // freeze the current 2-column range and start a new one 160 adddef(stage->dequeue()); 161 twocol->compose(FINAL); 162 adddef(twocol); 163 twocol = new multicol(this); 164 break; 165 case BP: // force a page break 166 adddef(stage->dequeue()); 167 squeue.block(); 168 break; 169 case FL: // flush out all floatables that precede this range: 170 // no more stream input allowed until they're past 171 if (stage->serialno() > ufqueue.serialno() || 172 stage->serialno() > bfqueue.serialno()) { 173 range *r = stage->dequeue(); 174 r->enqueue(ANDBLOCK); 175 } else 176 adddef(stage->dequeue()); 177 break; 178 default: 179 stage->current()->dump(); 180 ERROR "unknown command\n" FATAL; 181 } 182 } 183 184 void page::parmproc() 185 { 186 if (stage->next()) 187 ERROR "more than a single parameter on bsqueue\n" FATAL; 188 switch (stage->current()->parmtype()) { 189 case NP: // page top margin 190 if (blank()) 191 pagetop = stage->current()->parm(); 192 pagesize = pagebot - pagetop; 193 break; 194 case FO: 195 if (blank()) 196 pagebot = stage->current()->parm(); 197 pagesize = pagebot - pagetop; 198 break; 199 case PL: 200 if (blank()) 201 physbot = stage->current()->parm(); 202 break; 203 case MF: 204 minfull = 0.01*stage->current()->parm(); 205 break; 206 case CT: 207 coltol = 0.01*stage->current()->parm(); 208 break; 209 case WARN: 210 wantwarn = stage->current()->parm(); 211 break; 212 case DBG: 213 dbg = stage->current()->parm(); 214 break; 215 default: 216 stage->current()->dump(); 217 ERROR "unknown parameter\n" FATAL; 218 } 219 adddef(stage->dequeue()); 220 } 221 222 // Process the contents of the staging area; a relic that used to do more. 223 void mergestream::pend() 224 { 225 if (dbg & 4) 226 printf("#entering mergestream::pend()\n"); 227 if (!more()) 228 return; 229 if (current()->iscmd()) 230 currpage->cmdproc(); 231 else if (current()->isparm()) 232 currpage->parmproc(); 233 else 234 currpage->tryout(); 235 }