home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / APPS / lout2.lzh / LOUT2 / DOC / TR.IMPL / s5.2 < prev    next >
Text File  |  1994-01-25  |  14KB  |  373 lines

  1. @SubSection
  2.     @Tag { flushing }
  3.     @Title { The galley flushing algorithm }
  4. @Begin
  5. @PP
  6. Galley components are promoted one by one into the point of appearance in
  7. the dynamic parent galley, then carried along with it, ultimately to the
  8. root galley and the output file.  This process is called @I galley
  9. {@I flushing}: the galleys are rivers running together to the sea, and
  10. each component is a drop of water.
  11. @PP
  12. Here is a snapshot of a small dynamic tree, based on the @Code "@PageList"
  13. definitions of Section {@NumberOf recursion}:
  14. @ID @Fig {
  15.  
  16. @I 10p @Font { output file } A:: @Box linestyle { noline } margin { 0c }
  17.  
  18. ||2c
  19.  
  20. {
  21. @I 10p @Font { root galley }
  22. //0.2c
  23. B:: @Box margin { 0c } linestyle { noline }
  24. //
  25. @LittlePage {
  26. |0.5rt - 1 -
  27. //1.2vx &2m A small
  28. //1.2vx @Code "@Galley" * C:: @Box margin { 0.01c } linestyle { noline }
  29. //1rt @Code "@FootSect"
  30. }
  31. //
  32. @Box margin { 0.3c } 2.8c @Wide 8p @Font @Code "@PageList 2"
  33. }
  34.  
  35. ||2c
  36.  
  37. {
  38. //0.9c  @I 10p @Font { body text }
  39. //0.2c  D:: @Box margin { 0.3c } 2.8c @Wide 8p @Font paragraph
  40. //      @Box margin { 0.3c } 2.8c @Wide 8p @Font { of text. }
  41. //      @Box margin { 0.3c } 2.8c @Wide @Code 8p @Font "@Input"
  42. }
  43.  
  44. // @Arrow from { B@W } to { A@E }
  45. // @Arrow from { D@W } to { C@E }
  46.  
  47. }
  48. The components of the body text galley are lines, except for the special
  49. receptive symbol @Code "@Input" which is a placeholder for as yet unread
  50. input (Section {@NumberOf lookahead}).  The components of the root galley are
  51. pages, except for the concluding unexpanded invocation of {@Code "@PageList"},
  52. which is an inexhaustible source of more pages, expanded on demand.
  53. @PP
  54. The concrete data structure used by Basser Lout permits the galley
  55. flushing algorithm to navigate the dynamic tree and find significant
  56. features quickly:
  57. @ID 10p @Font @Fig maxlabels { 100 } {
  58.  
  59. A:: @Ellipse @I { HEAD }
  60.  
  61. ||1.5c
  62.  
  63. @OneCol @OneRow {
  64. B:: @Ellipse @I { RECEIVING * }
  65. // @Arrow from { A@CTR ++ {A@CTR @Angle B@W  A@CIRCUM} } to { B@W  }
  66. //0.6c
  67. C:: @Ellipse @I { RECEPTIVE }
  68. // @Arrow from { A@CTR ++ {A@CTR @Angle C@W  A@CIRCUM} } to { C@W  }
  69. //0.6c
  70. D:: @Box margin { 0c } linestyle { noline }
  71. // @Arrow from { A@CTR ++ {A@CTR @Angle D@NW  A@CIRCUM} } to { D@NW  }
  72. //
  73. @LittlePage {
  74. |0.5rt - 1 -
  75. //1.2vx &2m A small
  76. //1.2vx  E:: @Box margin { 0c } linestyle { noline } @Code "@Galley "
  77. //1rt    F:: @Box margin { 0c } linestyle { noline } @Code "@FootSect "
  78. }
  79. // @FunnyArrow arrow { forward } from { B@E } to { E@E }
  80. // @FunnyArrow arrow { forward } from { C@E } to { F@E }
  81. //0.6c
  82. C:: @Ellipse @I { GAP }
  83. // @Arrow from { A@CTR ++ {A@CTR @Angle C@W  A@CIRCUM} } to { C@W  }
  84. //0.6c
  85. C:: @Ellipse @I { RECEPTIVE }
  86. // @Arrow from { A@CTR ++ {A@CTR @Angle C@W  A@CIRCUM} } to { C@W  }
  87. //0.6c
  88. D:: @Box margin { 0.3c } 2.8c @Wide 8p @Font @Code "@PageList 2"
  89. //  @Arrow from { A@CTR ++ {A@CTR @Angle D@NW  A@CIRCUM} } to { D@NW  }
  90. //  @FunnyArrow from { C@E } to { D@W ++ { 1.8 cm 0 } }
  91. }
  92.  
  93. ||1.0c
  94.  
  95. A:: @Ellipse @I { HEAD }
  96. & @Arrow from { B@E } to { A@W }
  97.  
  98. ||1.5c
  99.  
  100. @OneCol @OneRow {
  101. B:: @Box margin { 0.3c } 2.8c @Wide 8p @Font paragraph
  102. // @Arrow from { A@CTR ++ {A@CTR @Angle B@W A@CIRCUM} } to { B@W }
  103. //0.6c
  104. B:: @Ellipse @I { GAP }
  105. // @Arrow from { A@CTR ++ {A@CTR @Angle B@W A@CIRCUM} } to { B@W }
  106. //0.6c
  107. B:: @Box margin { 0.3c } 2.8c @Wide 8p @Font { of text. }
  108. // @Arrow from { A@CTR ++ {A@CTR @Angle B@NW A@CIRCUM} } to { B@NW }
  109. //0.6c
  110. B:: @Ellipse @I { GAP }
  111. // @Arrow from { A@CTR ++ {A@CTR @Angle B@W A@CIRCUM} } to { B@W }
  112. //0.6c
  113. B:: @Ellipse @I { RECEPTIVE }
  114. // @Arrow from { A@CTR ++ {A@CTR @Angle B@W A@CIRCUM} } to { B@W }
  115. //0.6c
  116. C:: @Box margin { 0.3c } 2.8c @Wide 8p @Font @Code "@Input"
  117. // @Arrow from { A@CTR ++ {A@CTR @Angle C@NW A@CIRCUM} } to { C@NW }
  118. // @FunnyArrow from { B@E } to { C@W ++ { 1.2 cm 0 } }
  119. }
  120.  
  121. }
  122. Each galley has a @Eq { HEAD } node whose children are its component
  123. objects, separated by @Eq { GAP } nodes recording the inter-component
  124. gaps.
  125. @PP
  126. Each component is preceded by zero or more @I {galley index nodes} of
  127. various types.  Every receptive symbol has a @Eq { RECEPTIVE } index pointing
  128. to it, so that it can be found without searching through its
  129. component.  If the symbol is currently the target of a galley, it has a
  130. @Eq { RECEIVING } index instead which is also linked to the incoming
  131. galley.  Galleys that are currently without a target are linked to the
  132. dynamic tree by @Eq { UNATTACHED } galley indexes, either just after their
  133. most recent target if there has been one, or else at their point of
  134. invocation.
  135. @PP
  136. Each galley should be thought of as a concurrent process, although the
  137. implementation in C uses coroutines implemented by procedures.  A galley
  138. may promote its first component only if it has a target, sufficient space
  139. is available at the target to receive the component, and the component
  140. contains no receptive symbols.  This last condition seems to be the key
  141. to galley synchronization:  it forces a bottom-up promotion regime,
  142. preventing pages from flushing to output before text flushes into them,
  143. for example.
  144. @PP
  145. Each galley contains a number of binary semaphores, shown as asterisks
  146. in our snapshots when set.  At any given moment, a galley process is
  147. either running or else is suspended on one of its own semaphores.  The
  148. @Eq { HEAD } node contains a semaphore which is set when the galley has tried
  149. to find a target and failed.  Each receptive symbol has a semaphore
  150. which is set when that symbol is preventing the first component from
  151. being promoted.
  152. @PP
  153. For example, in the snapshot at the beginning of this section, the root
  154. galley is suspended on the @Code "@Galley" symbol, but the text galley
  155. is running.  It will suspend on the @Code "@Input" symbol after the
  156. first two components are promoted.
  157. @PP
  158. Every galley {@I G}, be it a list of pages, body text, a footnote, or
  159. whatever, executes the following algorithm in parallel with every other
  160. galley:
  161. @DP
  162. 1.  Initially @I G is unattached.  Search forwards or backwards from its
  163. @Eq { UNATTACHED } index as required, to find a receptive symbol @I S which
  164. can expand to reveal a target for {@I G}.
  165. @DP
  166. 2.  If no @I S can be found, suspend on the attachment semaphore.  Resume
  167. later from step 1.
  168. @DP
  169. 3.  Expand @I S to reveal the target of {@I G}.  Preserve {@I S}'s
  170. semaphore by moving it to the first receptive symbol within the
  171. expansion of {@I S}.
  172. @DP
  173. 4.  Calculate the available width and height at the target, and if
  174. @I G is still a pure parse tree, use the environment attached to @I G
  175. and the style information from the target to evaluate @I G as in
  176. Section {@NumberOf functional}.
  177. @DP
  178. 5.  Examine the components of @I G one by one.  For each component there
  179. are three possibilities:
  180. @PP
  181. @I ACCEPT.  If the component fits into the available space, and has
  182. no other problems, then promote it into the target.  If this is the
  183. first component promoted into this target, and @I G is a forcing
  184. galley (Section {@NumberOf lookahead}), delete every receptive symbol
  185. preceding the target in the parent galley.  If @I G is the root galley,
  186. render the component on the output file and dispose it;
  187. @PP
  188. @I REJECT.  If the component is too large for the available space, or a
  189. @Eq { FOLLOWS } index (described below) forbids its promotion into this
  190. target, then detach @I G from the target.  If this was the first component
  191. at this target, @I S has been a complete failure, so undo step 3 (Basser
  192. Lout is not able to undo step 4); otherwise delete the target.  Return to
  193. step 1 and continue immediately;
  194. @PP
  195. @I SUSPEND.  If the component contains a receptive symbol, it cannot be
  196. promoted yet.  If this symbol is the target of a galley that was written
  197. to an auxiliary file on a previous run, read in that galley and flush
  198. it.  Otherwise suspend on the receptive symbol's semaphore; resume later
  199. from step 4.
  200. @DP
  201. 6.  Terminate when the galley is empty.
  202. @DP
  203. At various points in this algorithm, receptive symbols (and their
  204. semaphores) are deleted in the dynamic parent galley, possibly
  205. permitting it to resume flushing.  When this happens, Basser Lout resumes
  206. the parent immediately after @I G suspends or terminates.  Also,
  207. whenever a component is promoted, any child galleys connected to
  208. it by @Eq { UNATTACHED } indexes must be resumed, since these
  209. galleys may be able to find a target now.  A good example of this
  210. situation occurs when a line of body text with one or more footnotes
  211. is promoted onto a page.  Basser Lout gives priority to such children,
  212. suspending @I G while each is given a chance to flush.
  213. @PP
  214. Basser Lout searches for the first target of @I G only in regions of the
  215. dynamic tree that will clearly precede or follow {@I G}'s invocation
  216. point in the final printed document, whichever is specified in the
  217. @Code into clause; subsequent targets are sought later in the same
  218. galley as the first.  An exception to this rule, whose necessity will
  219. be made clear later, is that a first @Code following target will be
  220. sought within a dynamic sibling galley preceding {@I G}'s invocation
  221. point:
  222. @ID 10p @Font @Fig {
  223.  
  224. {
  225. @I { dynamic parent }
  226. //0.2c
  227. @Box 2.8c @Wide 4.5c @High
  228. {
  229.    //0.5c A:: @Box margin { 0c } linestyle { noline } @Code "@XTarget"
  230.    //1.0c C:: @Box margin { 0c } linestyle { noline } @Eq { UNATTACHED }
  231.    //1.3c @Code "@XTarget"
  232. }
  233. }
  234.  
  235. ||1.5c
  236.  
  237. {
  238. //0.6c
  239. B:: @Box margin {0c} linestyle {noline} @Code "X into { @XTarget&&following }"
  240. //0.2c
  241. @Box 2.8c @Wide 1.5c @High { //0.8c @Code "@GTarget" }
  242. //1.0c
  243. D:: @Box margin {0c} linestyle {noline} @Code "G into { @GTarget&&following }"
  244. //0.2c
  245. @Box 2.8c @Wide 2.5c @High {}
  246. }
  247.  
  248. // @Arrow from { A@E ++ {0.2 cm 0} } to { B@W -- {0.2 cm 0} }
  249. // @Arrow from { C@E ++ {0.2 cm 0} } to { D@W -- {0.2 cm 0} }
  250.  
  251. }
  252. Here @I G will find the @Code "@GTarget" target within {@I X}.  This is
  253. dangerous, since if the first component of @I G is then promoted via
  254. @I X into the first {@Code "@XTarget"} rather than into the second,
  255. {@I G}'s target will not appear later in the final printed document than
  256. its invocation point, as required by the @Code into clause.
  257. @PP
  258. Accordingly, when such a target is chosen, two special galley indexes
  259. are inserted and linked together: a @Eq { PRECEDES } index at {@I G}'s
  260. invocation point, and a @Eq { FOLLOWS } index at the first component of
  261. {@I G}.  The algorithm checks before promoting any @Eq { FOLLOWS } index
  262. that its promotion would not place it earlier than the corresponding
  263. @Eq { PRECEDES } index in the same galley, and rejects the component if
  264. it would.  Since @Eq { PRECEDES } and @Eq { FOLLOWS } indexes are rarely used,
  265. this check can be implemented by linear search.
  266. @PP
  267. When two components are separated by {@Code "/"}, as opposed to the more
  268. usual {@Code "//"}, each influences the horizontal position of the
  269. other.  Because of this, the @I SUSPEND action is in fact taken if a
  270. receptive symbol occurs in any component separated from the first by
  271. {@Code "/"} operators only.  Again, linear search forwards to the first
  272. {@Code "//"} suffices for this check.
  273. @PP
  274. A good illustration of these unusual cases is afforded by the
  275. @Code "@Align" symbols from the standard DocumentLayout package.  These
  276. are used to produce displayed equations, aligned on their equals signs
  277. despite being separated by arbitrary body text.
  278. @PP
  279. The @Code "@Align" symbols are packaged neatly for the convenience of
  280. the non-expert user, but we will show just the essence of the
  281. implementation here.  First, an @Code "@AlignList" galley is created
  282. which contains an infinite supply of @Code "@AlignPlace" receptive
  283. symbols separated by @Code "/" operators:
  284. @ID @Fig {
  285.  
  286. {
  287. @I { body text galley }
  288. //0.2c
  289. @Box 2.8c @Wide 4.0c @High
  290. { //1.5c
  291.   A:: @Box margin { 0c } linestyle { noline } @Code "@Galley"
  292. }
  293. }
  294.  
  295. ||1.5c
  296.  
  297. {
  298. //2.4c
  299. B:: @Box margin { 0c } linestyle { noline } @Code "@AlignList"
  300. //0.2c
  301. @Box {
  302.       @Code "@AlignPlace"
  303. //1vx @Code "@AlignPlace"
  304. //1vx @Code "..."
  305. //1vx @Code "@EndAlignList"
  306. }
  307.  
  308. }
  309.  
  310. // @Arrow from { A@E ++ {0.2 cm 0} } to { B@W -- {0.2 cm 0} }
  311. }
  312. Then equations like
  313. @ID @ShowMarks @Eq { f(x) ^= g(x) + 2 }
  314. are created and sent to @Code "@AlignPlace&&following" targets.  They
  315. collect in the @Code "@AlignList" galley and are aligned there:
  316. @ID @Fig {
  317.  
  318. {
  319. @I { body text galley }
  320. //0.2c
  321. @Box 2.8c @Wide 4.0c @High
  322. { //1.5c
  323.   A:: @Box margin { 0c } linestyle { noline } @Code "@Galley"
  324. }
  325. }
  326.  
  327. ||1.5c
  328.  
  329. {
  330. //2.4c
  331. B:: @Box margin { 0c } linestyle { noline } @Code "@AlignList"
  332. //0.2c
  333. @Box {
  334.    @Line linestyle { dashed } from { xmark ysize } to { xmark 0 }
  335.    {
  336.          @Eq { f(x) ^= g(x) + 2 }
  337.     /1vx @Eq { f(x) - g(x) ^= 2 }
  338.     /1vx @Code "..."
  339.     /1vx @Code "@EndAlignList"
  340.    }
  341. }
  342.  
  343. }
  344.  
  345. // @Arrow from { A@E ++ {0.2 cm 0} } to { B@W -- {0.2 cm 0} }
  346. }
  347. The @Code "@AlignList" galley does not flush, because its first
  348. component is connected to a receptive symbol by @Code "/" operators.
  349. @PP
  350. After the last equation, an empty forcing galley is sent to
  351. {@Code "@EndAlignList"}, deleting the two remaining receptive symbols from
  352. the @Code "@AlignList" galley and permitting it to flush.  @Eq { FOLLOWS }
  353. indexes ensure that each equation finds a target placed in the body text
  354. just after its point of invocation, so the equations return, aligned, to
  355. approximately the points where they were invoked.  Notice that the flushing
  356. of body text is suspended until the list of equations is completed, as it
  357. must be, since the horizontal position of the first equation cannot
  358. be known until the last equation is added to the list.
  359. @PP
  360. Layout quality can occasionally be improved by rejecting a component
  361. that could be promoted -- for example, a component of body text that
  362. carries a footnote too large to fit on the current page.  Since Lout
  363. does not specify how breaking decisions are made, beyond the basic
  364. constraints imposed by available space and @Code into clauses, in
  365. principle such high quality breaking could be added to the
  366. implementation with no change to the language.  However, the
  367. generality of the galley flushing algorithm, and its already
  368. considerable complexity, make this a daunting problem in practice,
  369. although a fascinating one.  @TeX [9], with its unnested
  370. set of `floating insertions' clearly identifiable as each page is begun,
  371. has the advantage in this respect.
  372. @End @SubSection
  373.