Drawing Boxes

From Open Watcom

Revision as of 18:48, 17 September 2013; view current revision
←Older revision | Newer revision→
Jump to: navigation, search

Contents

Introduction

This page explores the box-drawing behavior of wgml 4.0. It includes the device library blocks that are used in the actual drawing as well as the control words and layout/document tags that are used to cause boxes to be drawn.

This initial version records what is known so far. Additional work is needed and will eventually be done.

The Required :BOX Block

The :BOX block, which is a required part of the :DEVICE block, defines the line-drawing characters and the font they are to be taken from.

The :ABSOLUTEADDRESS, :HLINE, :VLINE, and :DBOX Blocks

These blocks are all optional, but that does not mean that they can be used arbitrarily.

While attempting to get wgml 4.0 to interpret the :VLINE block, I discovered that :DRIVER block without an :ABSOLUTEADDRESS block but with the :HLINE, :VLINE, and :DBOX blocks would produce an "Abnormal program termination" -- but only when used to process a document specification which caused :VLINE to be interpreted.

This table shows every occurrence in the source files available to me:

Source File  :ABSOLUTEADDRESS  :HLINE  :VLINE  :DBOX
hpldrv.pcd   Yes
hplpdrv.pcd  Yes               Yes     Yes
hplpldrv.pcd Yes               Yes     Yes
mltdrv.pcd   Yes               Yes     Yes
psdrv.pcd    Yes               Yes     Yes     Yes
x2700drv.pcd Yes               Yes     Yes

No other source file available to me has any of these blocks in it.

Two obvious deductions can be drawn:

  • An :ABSOLUTEADDRESS block is a prerequisite the other three blocks.
  • The :HLINE and :VLINE blocks always appear together.

Section "15.9.15 VLINE Block" of the WGML Reference describes the intended context of :VLINE in this way:

The special symbols %y_size and %thickness are defined prior to 
processing the vline block. The symbol %y_size is set to the height 
of the vertical line, from the top edge to the bottom edge. The 
symbol %thickness is set to the value specified by the vline blocks 
thickness attribute. WATCOM Script/GML positions to the bottom left 
corner of the line before creating the rule line, and assumes the 
current point of the device is set to the top left corner of the 
line when finished.

In other words, a :VLINE block is expected to draw the line in an upward direction. Since a device that does not define :ABSOLUTEADDRESS has no ability to move the print position upwards (negative values of the attribute skip of the :NEWLINE block are not allowed, see the discussion here), it is not surprising that attempting to use :VLINE without :ABSOLUTEADDRESS causes a problem.

An :HLINE block, in contrast, is expected to draw the line from left to right, and so does not require :ABSOLUTEADDRESS -- provided wgml 4.0 always starts it on the correct line and does not attempt to go back up to print out text.

The :DBOX block starts at the bottom left corner and so would, in practice, have to go back up to draw the top and sides of the box, although it does not produce an "Abnormal program termination" in the absense of an :ABSOLUTEADDRESS block.

Clearly, which blocks are present depends on the characteristics of the device. Many devices have none of them, presumably because they produce their output one line at a time.

Control Word BX

This is an example of a four-section box drawn using control word BX:

.in 2
.tb set >
.tb 28
.bx 1 26 62
%binary(3)>the appropriate graphic appears
.br
%binary1(4)>the appropriate graphic appears
.bx
%binary2(5)>the appropriate graphic appears
.br;
%binary4(6)>the appropriate graphic appears
.bx off
.tb set
.tb
.in

Because control word BX only draws the box itself, control words IN and TB are also needed to position the text so that it appears within the box sections. This is quite common. There are, of course, many control words, and this example is not intended to exhaust the number of control words that may be useful in drawing boxes.

Control word BX always used the BOX characters with character devices. With line-drawing devices (or, at least, with PS), these rules apply:

  • The DBOX block is never used; if it is not defined, this has no effect on how the box is drawn.
  • If both of the HLINE and VLINE blocks are defined, they are both used.
  • If the HLINE block is not defined, then the BOX characters are used for the horizontal lines and no vertical lines appear, whether the VLINE block is defined or not.
  • If the HLINE block is defined, but the VLINE block is not defined, then horizontal lines (with no descenders) are drawn using the HLINE block but no vertical lines appear.

Thus, vertical lines only appear when both the HLINE and VLINE blocks are defined.

Box Scope

wgml 4.0 appears to track whether or not a BX box is being processed or not; this gives two states, which will be called inside a box and outside any box.

Processing begins outside of any box. In this state, these BX lines:

BX | BX ON | BX OFF | BX CAN | BX DEL | BX NEW | BX SET | BX CHAR

(with no column list) are all ignored.

When outside of any box, any BX line with a column list changes the state to inside a box. In this state, the BX lines have the effects shown in the next section.

A BX off line terminates the current box and reinstates any prior box if the current box was nested. If the box terminated was not nested, then the state reverts to outside any box.

A BX off line with a column list would, presumably, both start and terminate a box.

A box that is never closed continues to produce vertical lines to the end of the file. An open box from before the TITLEP tag will produce vertical lines all the way through the Index (with two passes). In PS, these lines extend into a top running title, the first footnote on a page, and generate a negative length at the end of the file; in TASA, they interact with a FIG as if the FIG cancelled any columns from the BX box that the FIG used.

This may seem a little odd, but the fact is that the program has no way of knowing where the box ends except by processing a BX OFF line and so must presume that everything else it encounters in part of the box. The extended lines for the PS device and the interaction with FIG for the TASA device are interesting. Treating the box as ending with the section, particularly when the next section starts on a new page, might be worth considering.

This section may be require revision as control word BX is explored further.

The Box Operands

Control word BX has several operands prompting specific actions. Exploring these is a bit of a problem: character strings are needed to see what they do but producing them turned out to be a bit of a problem: the only font that displays the 8-bit line drawing characters is Terminal and testing showed that, when the OUTTRANS block was used to emit the Unicode line drawing characters, the characters were not emitted, just the numeric value.

And copying the result from a text file displayed using font Terminal to this page does not work: instead of

┌────────────────────────┬───────────────────────────────────┐

the result is

ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

which is a bit annoying.

However, the topic is both necessary and interesting.

Empty lines are used between the boxing lines to make it clear what each line contains. In an actual box, there would be text lines (and blank lines) which, for a character device, would have the vertical line embedded at the appropriate positions; for a line-drawing device, vertical lines would be drawn. In both cases, these ascenders should be imagined as connecting the stubs shown.

Using BX with no explicit operator can be regarded as using an implicit operator, with the effects shown below.

This set of commands:

.bx 1 26 62
.bx 1 26 62
.bx off

produces:

┌────────────────────────┬───────────────────────────────────┐

├────────────────────────┼───────────────────────────────────┤

└────────────────────────┴───────────────────────────────────┘

as does this set of commands:

.bx 1 26 62
.bx
.bx off

This example illustrates the use of BX with no operand to establish a set of columns and print out the top line, BX with the same columns or no columns to print out a middle line, and BX OFF to print out a bottom line.

This set of commands:

.bx del
.bx 26
.bx
.bx off

produces:

│

│

│

which would be what what the TSO means by a "box with only one vertical descender".

This set of commands:

.bx 1 26 62
.bx 1
.bx 26
.bx 62
.bx 1 26 62
.bx off 1 26 62

produces:

┌────────────────────────┬───────────────────────────────────┐

├────────────────────────┴───────────────────────────────────┘

└────────────────────────┐

                         └───────────────────────────────────┐

┌────────────────────────┬───────────────────────────────────┤

└────────────────────────┴───────────────────────────────────┘

which illustrates the implicit operator referred to above.

This set of commands:

.bx 1 26 32 62
.bx 3 30 40 65
.bx off

produces:

┌────────────────────────┬─────┬─────────────────────────────┐

└─┬──────────────────────┴───┬─┴──────┬──────────────────────┴──┐

  └──────────────────────────┴────────┴─────────────────────────┘

which provides a more realistic example of the use of the implicit operator to end one box and start another.

This set of commands:

.bx 1 26 /32 62
.bx
.bx off

produces:

┌────────────────────────┐     ┌────────────────────────┐
 
├────────────────────────┤     ├────────────────────────┤

└────────────────────────┘     └────────────────────────┘

as does this set of commands:

.bx 1 26 / 32 62
.bx
.bx off

which illustrates the effect of / and shows that it need not have whitespace on both sides. Further testing shows that it must be preceded by whitespace, and that it cannot be used with the first box position on a BX line, even if it is not the leftmost position on the resulting combined set of box column positions.

This set of commands:

.bx 1 26 
.bx 32 62
.bx off

produces:

┌────────────────────────┐
 
└────────────────────────┴─────┬────────────────────────────────┐

                               └────────────────────────────────┘

while this set of commands:

.bx 1 26 
.bx on 32 62
.bx off

produces:

┌────────────────────────┐
 
└────────────────────────┘     ┌────────────────────────────────┐

                               └────────────────────────────────┘

which shows on BX ON can be used to do. Further testing shows that, for this effect to appear, there must be no overlap at all between the two sets of column positions. If overlasp exists, the effect is the same as that shown above whether ON is used or not.

This set of commands:

.bx 10 20 
.bx 1 30
.bx off
.bx off

produces:

         ┌─────────┐

┌────────┴─────────┴─────────┐

└────────────────────────────┘

which, since the second BX OFF produces no output, verifies that the box has been terminated by the first BX OFF, while this set of commands:

.bx 10 20 
.bx new 1 30
.bx off
.bx off

produces:

         ┌─────────┐

┌────────┴─────────┴─────────┐

└────────┬─────────┬─────────┘

         └─────────┘

which illustrates the "box on box" effect which can be produced by NEW, while this set of commnds:

.bx 1 30
.bx new 10 20 
.bx off
.bx off

produces:

┌────────────────────────────┐

│        ┌─────────┐         │

│        └─────────┘         │

└────────────────────────────┘

which illustrates the "box in box" effect which can be produced with NEW.

Both of the last two examples also illustrate nesting: that is, that BX OFF only closes the current box and then restores the prior box.

Further testing with NEW showed that many strange effects can be produced if it is used inappropriately because it will always emit the ascenders of the "background" box as shown.

BX OFF was also tested with columns following. The effect is to add them to the box column set and then generate a bottom line.

BX SET was tested; it does indeed appear to be treated like BX NEW except for not generating the line.

For a line-drawing device, of course, things work a bit differently: instead of ascenders and ascenders being generated as part of the horizontal line, vertical lines are generated as appropriate.

<note: need to test bx del/can inside a box: does it nest?>

Splitting Boxes Drawn By Control Word BX

Boxes drawn with BX are split vertically in the simplest possible way, keeping in mind that line-drawing devices have some peculiarities of their own.

For character-mode devices, the rules are:

  1. The text lines are split exactly as normal text is split.
  2. Each horizonal line is treated as a line of text (which, for a character device, it is).
  3. Blank lines at the bottom of a page are reduced in number to exactly the number needed to fill up the page; additional blank lines are ignored (that is, they do not appear at the top of the next page).

For line-drawing devices, or at least, for the PS device, things are not that simple.

  1. Vertical lines at the bottom of a page are drawn from the point where the horizontal line would be positioned, even if the first line is text. This means that text can appear slightly lower than the vertical lines. No attempt is made to cover an integral number of blank lines.
  2. Vertical lines at the top of a page are drawn to the point where the horizontal line would be positioned, even if the first line is text. This means that text can appear slightly higher than the vertical lines.
  3. When the last line of the box appears at the top of the page, the normal risers are not drawn, but positional markers do appear to mark where they are.
  4. The criterion for moving most horizontal lines to the next page are not the same as those for text lines.

To clarify that last point:

  1. Text lines are still split exactly as normal text is split.
  2. The first horizontal line is still treated as if it were a line of text.
  3. Intermediate horizontal lines and the final horizontal line must have more than the element-depth (rather than the height of the default font), plus any applicable skip, for that horizontal line to stay on the current page.

Horizontal splits are specified by the use of '/' in the box position list. When done sensibly, the effect is to draw two or more boxes adjacent to each other horizontally.

The Layout/Document Tags

There are three tags which can cause wgml to draw boxes if a particular attribute is given the value "box":

Tag             Type      Attribute
:FIG            Document  frame
:FIG            Layout    default_frame
:IXHEAD         Layout    frame

The :FIG tags pertain to figures; the :IXHEAD tag pertains to index headings.

The observed behavior (so far, with limited testing) is:

  • If :DBOX is present, then it is used.
  • If :DBOX is not present, but :HLINE and :VLINE are present, then :HLINE and :VLINE are used to draw the box for figures but not for index headings (no box appears at all around the index headings in this case). Note that :VLINE, in the limited testing performed, was only used here when it was used with .bx.
  • If neither :DBOX nor :HLINE/:VLINE are present, then the characters specified by :BOX are used for both figures and index headings.

It is surprising that :IXHEAD behaves differently from :FIG when :DBOX is not provided but :HLINE and :VLINE are.

This is the :FIG used for testing:

:FIG frame=box width='6i' place=inline.
%x_address() returns the current horizontal print position
%y_address() returns the current vertical print position
:FIGCAP.Sample caption with multiple words
:eFIG.

There are, of course, many other options possible, all of which the layout code will most likely need to implement. This page, however, is concerned with drawing boxes, not with other options.

Text Line Formatting

While exploring how text lines were output by wgml 4.0, boxing was tested using each of control word BX and tags FIG and IXHEAD. This produced results which turned out to be more generally applicable, and which are discussed to a very limited extent here; however, this section will accumulate more details as they are discovered.

If the box is drawn using BOX block characters then, whether the box is created by control word BX, tag FIG, or tag IXHEAD, each vertical line BOX block character added to the text is placed in its own text_chars instance. Horizontal lines containing no spaces are placed in a single text_chars instance.

The boxes produced by tag IXHEAD only contain a single character which, by necessity, is placed in a single text_chars instance.

When tag FIG is used, the text_line struct for the text itself contains one text_chars instance for each tab in actual use which controls all of the text starting at that tab stop, including the embedded spaces. This text is never right-justified, even when right justification is turned on. Text given with tag FIGCAP is processed normally.

Control word BX, as such, has no effect on output line formatting, as such. Instead, all of the normal factors (concatenation on/off, justification on/off, whether the current word will fit on any line or must be split, and so on). This can produce a variety of effects, which can be confusing; however, commenting out the BX control word lines (so that the box is not drawn) will show that the text is formatted the same way as it is when the box is drawn.

It usually happens that control word TB is used in conjunction with control word BX. This adds all of the effects associated with control word TB:

  1. Control word BR may not be needed, provided user tab stops are created and used in a way that causes a break to be generated without control word BR being present.
  2. Text following a tab character will, when appropriate, continue on the same line even if the right margin or even the right edge of the page is passed. For character devices, this causes the line to wrap; for the PS device (and probably all similar devices), the text is truncated at the right page edge when displayed.

The second point means that an extremely long "word" which contains no tab character is split at the right margin while the same "word", if preceded immediately by a tab character, is not split. It also applies to lines composed of words with spaces in between them.

For a character device, vertical ascenders are inserted into each text line included in the box. Each such ascender is placed in its own text_chars instance. The effect is that ascenders only appear when a space character would otherwise be produced.

However, this is not what is actually happening: instead, text_chars instances containing ascenders are only placed between the existing text_chars instances. If there is no "between" -- that is, if an existing text_chars instance writes anything, even a space character, in the position where a vertical ascender would normally be found, then no vertical ascender appears. This can easily happen when concatenation is turned OFF within the box.

For the PS device, and so presumably for any device using the VLINE block, the vertical line appears even if it ends up running through a text character.

Of course, in actual documents, such as the Open Watcom documents, each box would be designed so that all of the text was displayed in the correct location and none of it overlapped the vertical lines or ascenders.

Drawing Boxes

These section describes generally how boxes are drawn. PS and WHELP are taken as models of two different types of devices: line-drawing devices, which define the ABSOLUTEADDRESS block and at least the HLINE block and character devices, which use the characters and font prescribed by the BOX block, respectively. Since PS is the only line-drawing device available, it is possible that some aspects of the process described are actually PS-specific augmentations. There are several character devices available, and they all appear to work the same way; TASA was, in fact, used for testing as its output is less cluttered and generally clearer than WHELP's output is.

As noted above, for line-drawing devices, while tags FIG and IXHEAD will use the DBOX block if it is available, control word BX will not do so but will instead use the HLINE and VLINE blocks if the HLINE block is available. When control word BX uses the HLINE block, then it either uses the VLINE block (if it is available) or no vertical ascenders appear (if it is not available).

These notes are based on the behavior seen with the sample .bx and sample :FIG shown above.

Reference is made to the minimum left margin, which is computed as discussed here.

The term "insert" is used because, in our wgml, the elements are inserted into the current page, which is not output until it is full.

Using the BOX Characters

Drawing a box with the BOX block characters involves two steps:

  1. Insert any and all elements that are intended to appear in the box, with the vertical ascenders inserted into each line of each element.
  2. Insert the horizontal line.

Elements, such as GRAPHIC, which are replaced by blank lines in a character device will be replaced by blank lines containing the appropriate vertical ascenders, while elements like BINCLUDE will simply insert their data without any ascenders.

Using HLINE and VLINE

Drawing a box with the HLINE and VLINE blocks involves two steps:

  1. Insert any and all elements that are intended to appear in the box.
  2. Insert the horizontal line and vertical lines.

Since the horizontal and vertical lines are drawn independently of the box contents, any element that produces output visible within the box will be enclosed by the lines. GRAPHIC, in particular, will appear to be inside the box if positioned correctly.

Positioning the HLINE Output

The start position used with an HLINE block is adjusted both vertically and horizontally to be within the space occupied by the column or line, rather than at either boundary.

These are the formulas, which are used by wgml 4.0 so long as the default font is "0", which our wgml uses in all cases:

vertical-offset = current-font-line-height / 2
if( current-font-line-height % 2 ) {
    vertical-offset++
}
top-skip += vertical-offset
subs-skip += vertical-offset
element-depth = current-font-line-height - vertical-offset

The top-skip and subs-skip which are altered are those which are otherwise appropriate for the current HLINE. The effect is to draw the HLINE inside the space which would be occupied by a text line at the same position.

This is not affected by the LPI setting. Testing with different values of the number of vertical base units per inch did have an effect; however, further testing showed that this effect was actually the result of converting the font height, in points, into vertical base units, and not of the number of vertical base units per inch as such.

The horizontal position (which is based on the first box column only) is computed this way:

horizontal-offset = ((hbus/in)/10)/2

This is, in other words, one-half of what the width of a column is when the CPI is 10. The net horizontal position is then calculated using the formula:

net-horizontal-position = left-margin + box-column-position - horizontal-offset
if( net-horizontal-position < 0 ) {
    net-horizontal-position = horizontal-offset
}

and is then compared with the minimum horizontal position:

min-horizontal-position = left-margin + horizontal-offset

to produce the horizontal position for the HLINE:

horizontal-position = max( net-horizontal-position, min-horizontal-position )

Because the horizontal position used with the VLINE is computed differently, the horizontal and vertical lines drawn by the PS device can fail to meet properly in wgml 4.0, and in our wgml as well.

Positioning the VLINE Output

The start position used with a VLINE block is adjusted both vertically and horizontally to be within the space occupied by the column or line, rather than at either boundary.

The vertical position of a VLINE block is computed exactly the same way as it is for the HLINE block.

The horizontal position of a VLINE block is computed for each box column in turn. The computation is much simpler that that for the HLINE block: the value

net-horizontal-position = left-margin + box-column-position - horizontal-offset

is always used. This can result in a horizontal position that is not only different from that used with the HLINE but also which is less than the minimum left margin; indeed, it can be negative value which, being outside of the PS clipping window defined by the page edges, causes the line to not be drawn although the normal VLINE output appears in the PS file.

The length used by the VLINE blocks is increased by 10 hbus, which appears to be a constant. Examination of how the VLINE block was defined suggested that this was the thickness of the line, but further testing showed that it does not vary with the thickness, or with the CPI, or with the number of horizontal base units per inch.

Using DBOX

For the DBOX block, the sequence noted is very simple:

  1. Use the ABSOLUTEADDRESS block to locate the print head to the lower left corner of the box.
  2. Use the DBOX block to draw the box from that point.

Implementation Notes

Our wgml is intended to be a drop-in replacement for wgml 4.0 in the Open Watcom document build system. As such, it will be used with two devices (PS and WHELP). One of these devices (PS) provides all four of the ABSOLUTEADDRSS, HLINE, VLINE and DBOX blocks, and so boxes requested by tags IXHEAD and FIG appear and are drawn by wgml 4.0 using DBOX and the boxes specified by control word BX are drawn using HLINE and VLINE. The other device (WHELP) provides none of them, and so boxes requested by tags IXHEAD and FIG and the boxes specified by control word BX are drawn by wgml 4.0 using the characters and font prescribed by the BOX block.

Control Word BX

The control word BX is used in the Open Watcom documents with these operands (copied from the TSO):

<h1 </> ... hn>
CAN
NEW <h1 </> ... hn>
OFF <h1 </> ... hn>
ON <h1 </> ... hn>

These operands are not used in the Open Watcom documents but do work in wgml 4.0:

DEL
SET <h1 </> ... hn>

These operands are recognized by wgml 4.0, but nothing happens: the line is treated as if it was a comment:

CHAR <TRM|32T|TNC|38C|GPC|APL>
CHAR HEX

This operand appears in the Open Watcom documents, but only commented out. Since wgml 4.0 does not accept it (nor BEGIN, NO, PURGE, or YES, despite what the TSO says in its introductory sections), this is just as well:

END (commented out)

The implementation should, when finished recognize all the operands that wgml 4.0 does and treat them in the same way that wgml 4.0 does.

Output Patterns: TASA

Character devices use quite simple patterns.

The basic pattern is:

  1. If there are any, insert each line of the the box content, with text_chars instances containing the horizontal line character from the BOX block inserted in the proper positions, into the currnet page.
  2. Insert the horizontal line, in the form of a text_line with a single text_chars instance, into the current page.

When the box is split horizontally, the only change is:

The text_line used for the horzontal line now contains one text_chars instance for each separate 
horizontal line.

When the box is split vertically, the only change is:

The number of blank lines emitted is reduced, if necessary, to exactly the number needed to fill
up the current page so that the next item, a box content or a horizontal line, will be assigned 
to the next page in the normal manner.

When BX CAN or BX DEL appears inside a box, the only change is:

A blank overprint line (a text_line with no text_chars intances) replaces the horizontal line, and 
it is still an overprint line even if it occurs at the top of a page.

Note that, normally, an overprint line at the top of a page becomes the first line of the page, and does not overprint anything.

Output Patterns: PS

Line drawing devices, or, at least, PS are rather more complicated than character devices.

The actual output consists of the result of interpreting the ABSOLUTEADDRESS, HLINE, and VLINE blocks provided by the device driver. However, the order in which these blocks are interpreted is controlled by the order in which the HLINE and VLINE document elements are inserted into the current page. "HLINE" and "VLINE" will be used to refer to either the blocks or the document elements, or both, as the context requires.

Boxes that fit entirely on a single page will be considered first, as they provide the basic framework for drawing boxes.

For a simple boxes, that is, boxes of the form:

.bx c1 c2 ... cn
.bx
.bx off

the pattern is:

  1. The first BX line produces a single ABSOLUTEADDRESS block followed by an HLINE block.
  2. The second BX line produces these actions:
    1. Output the box content appearing between the current BX line and the prior BX line.
    2. Produce a single ABSOLUTEADDRESS block followed by an HLINE block.
  3. The VLINE blocks are drawn in conjuction with the BX OFF line, and so their height is the entire height of the box, computed as noted above.
  4. The BX OFF line produces these actions:
    1. Output the box content appearing between the current BX line and the prior BX line.
    2. Produce a single ABSOLUTEADDRESS block followed by an HLINE block.
    3. Generate one VLINE block per box column
      1. When the first VLINE block is output, a single ABSOLUTEADDRESS block is output first.
      2. When each subsequent VLINE block is output, two ABSOLUTEADDRESS blocks, both using the same horizontal and vertical positions, are output first.

If all three lines have the same column numbers given explicitly, that is, the box is of the form:

.bx c1 c2 ... cn
.bx c1 c2 ... cn
.bx off c1 c2 ... cn

the pattern is:

  1. The first BX line produces a single ABSOLUTEADDRESS block followed by an HLINE block.
  2. VLINE blocks are drawn in conjuction with both the second BX line and the BX OFF line, and their height is the height to the prior BX line, computed as noted here.
  3. The subsequent BX line produces these actions:
    1. Output the box content appearing between the current BX line and the prior BX line.
    2. Produce two ABSOLUTEADDRESS blocks, both using the same horizontal and vertical positions, followed by one VLINE block; this is done for each box column.
    3. Produce a single ABSOLUTEADDRESS block followed by an HLINE block.
  4. The BX OFF line produces these actions:
    1. Output the box content appearing between the current BX line and the prior BX line.
    2. Produce a single ABSOLUTEADDRESS block followed by an HLINE block.
    3. Generate one VLINE block per box column
      1. When the first VLINE block is output, a single ABSOLUTEADDRESS block is output first.
      2. When each subsequent VLINE block is output, two ABSOLUTEADDRESS blocks, both using the same horizontal and vertical positions, are output first.

For each BX line between the first BX line and the BX OFF line, what happens depends on whether or not that BX line was followed by a column list:

  • If the list is present, then the VLINES are produced followed by the HLINE, and the height is the height to the most immediately preceding BX line which produced VLINEs (or to the top of the box, if no VLINEs have, as yet, been drawn).
  • If the list is not present, then only the HLINE is produced.

However, this is not a very realistic situation, being merely a reduced form of the general case, highlighting what happens to vertical lines that continue across box section boundaries.

The general case, which shows the effect of the default operator, uses boxes of the form:

.bx c1 c2 ... cn
.bx d1 d2 ... dm
.bx off c1 c2 ... cn

This is the pattern seen in the general case:

  1. Each BX line between the first BX line and the BX OFF line that lists columne divides the box into two box sections, the upper box and the lower box.
  2. The first BX line produces a single ABSOLUTEADDRESS block followed by an HLINE block.
  3. VLINE blocks are drawn in conjuction with both the second BX line and the BX OFF line, and their height is the height to the prior BX line, computed as noted here. This may be called normal VLINEs.
  4. VLINE blocks are also drawn in conjunction with both the seoond BX line and the BX OFF line for each column which terminates with the HLINE. These may be called stub VLINEs, as their height is the element-depth.
  5. The subsequent BX line produces these actions to terminate the upper box:
    1. Output the box content appearing between the current BX line and the prior BX line.
    2. Produce two ABSOLUTEADDRESS blocks, both using the same horizontal and vertical positions, followed by one normal VLINE block; this is done for each box column.
    3. Produce a single ABSOLUTEADDRESS block followed by an HLINE block.
  6. Generate an additional stub VLINE for each column which terminates with the HLINE:
    1. When the first stub VLINE block is output, a single ABSOLUTEADDRESS block is output first.
    2. When each subsequent stub VLINE block is output, two ABSOLUTEADDRESS blocks, both using the same horizontal and vertical positions, are output first.
  7. The BX OFF line produces these actions:
    1. Output the box content appearing between the current BX line and the prior BX line.
    2. Produce a single ABSOLUTEADDRESS block followed by an HLINE block.
    3. Generate one VLINE block per box column:
      1. Columns which terminate with the BX OFF line, including columns that would normally continue on, use normal VLINEs.
      2. Columns which start with the BX OFF line produce stub VLINEs which are drawn upwards from the BX OFF HLINE.
      3. These VLINES are intermingled and output in column order as a set:
        1. When the first VLINE block is output, a single ABSOLUTEADDRESS block is output first.
        2. When each subsequent VLINE block is output, two ABSOLUTEADDRESS blocks, both using the same horizontal and vertical positions, are output first.

Except for the case of BX OFF, the VLINEs for any new columns will be drawn when the next BX line is encountered, at which point they will be the normal VLINEs (and stub VLINEs if appropriate) for the upper box. The BX OFF line is an exception both because it draws its new columns' VLINEs in the wrong direction, and because there will be no subsequent BX line.

For a normal VLINE, the height of the VLINE is incremented by 10, as discussed here. For a stub VLINE, this does not happen, so the height seen in the output is:

stub-height = element-depth - thickness

If the box is broken across a page, the effects noted here will be seen. What happens in terms of ABSOLUTEADDRESS blocks, VLINEs, and HLINEs will be discussed next.

First, though, the positional marker must be described. This occurs when a VLINE has a height of zero (0 hbu). It consists of a single ABSOLUTEADDRESS block using the position of the VLINE's column. This is the case even when they are intermingled with the stub VLINEs, which follow the normal pattern of having one ABSOLUTEADDRESS block before the first and two before each of the others: the intermingled positional markers still become a single ABSOLUTEADDRESS block.

The patterns seen when the box is broken across a page (split vertically) are:

  1. When the first HLINE appears at the bottom of the first page, VLINEs are drawn normally from the bottom of the page, all of them preceded by two ABSOLUTEADDRESS blocks setting the same position. When there is no room below the HLINE, then these VLINEs, being of height 0, become positional markers.
  2. When the box is split so that neither the last line on the first page nor the first line on the next page is an HLINE, the VLINEs are drawn as described here. Those at the bottom of the first page are output last, and they are each preceded by two ABSOLUTEADDRESS blocks setting the same position. Those at the top of the next page follow the above patterns for the unbroken box, except, of course, that they end at the top of the page.
  3. When the second HLINE appears at the bottom of the first page, with no room left below it, then, after the normal VLINEs, the HLINE, and the stub VLINEs, the positional markers representing zero-height normal VLINEs are produced. If there is any room left below it, however small, these will be normal VLINEs, all of which are preceded by two ABSOLUTEADDRESS blocks setting the same position.
  4. When the second HLINE appears at the top of the next page, the positional markers (that is, the normal VLINEs with height 0) appear first, followed by the HLINE, followed by the stub VLINES.
  5. When the final HLINE appears at the top of the next page, the normal VLINEs, being of height 0, become positional markers, and are still intermingled with the stub VLINEs.

In general, then, the only changes when a box is split vertically are:

  • How the VLINE heights are computed.
  • How VLINEs with height 0 appear in the output.

When the box is split horizontally, the only change is:

Each horizontal line becomes a separate HLINE doc_element.

Thus, the code must deal with a linked list of doc_elements specifying HLINEs.

In terms of patterns, for the PS device, the effect is:

  1. For BX lines with no operator, all HLINEs are inserted into the page followed by all VLINEs.
  2. For BX OFF lines, each HLINE is followed by the corresponding VLINEs.

These patterns are applied to the result of the patterns given previously.

Additional Details: PS

With all those HLINEs and VLINEs being output in various orders, an interesting sub-problem arose: how to manage the top_skip, subs_skip and depth fields of the doc_element instances involved. The solution is fairly straightforward:

  1. The skips can only be non-zero in the first doc_element in the set.
  2. The depth can only be non-zero in the last doc_element in the set.

This positions the entire set of HLINE and VLINE doc_elements properly initially, and then positions whatever follows properly, while keeping all of the HLINE and VLINE doc_elements at the same vertical position.

This led to the interesting practice of using the ProcFlags member group_elements and t_doc_el_group to accumulate (or add to the end, since it is also used to accumulate box contents) the HLINEs/VLINEs, so that the depth could be added after the set was completed, which turned out to be very much easier than trying to determine beforehand what the final doc_element might be. This could not be done directly on t_page because the depth might impact whether the final doc_element was moved to the next page or not and so had to be set before it was submitted to t_page itself.

As noted above, the length used by the VLINE blocks is increased by 10 hbus. However, this had to be suppressed for the positional marker VLINE blocks, that is, those of length "0", so that they would be output properly.

Known Discrepancies

This section documents areas in which our wgml and wgml 4.0 do not, and, quite possibly, will never, do things the same way.

Use of BOX Characters

Because the Open Watcom documents only use two devices, PS and TASA, our wgml follows this simplified pattern:

  • If the HLINE block is defined, then the HLINE and VLINE blocks are used.
  • If no HLINE block is provided, then the characters defined by the BOX block are used.

This differs from wgml 4.0 in that, if no HLINE block is defined, then the BOX block characters will be used for vertical as well as horizontal lines. The case where an HLINE block is defined but no VLINE block was provided has not been accomodated, and can be expected to cause a GP-fault.

Default Font Not "0"

The formulas given above are used at all times in our wgml.

While testing, a curious discovery was made: despite the documentation, which our wgml follows, wgml 4.0 always uses font "0" as the font for the PREFACE section, not the font specified by attribute "font" in the DEFAULT LAYOUT section. It is not known, at this time, what other sections, if any, are affected by this.

Moving the test box to the BODY section, I confirmed that wgml 4.0 does use the font specified by the "font" attribute of the DEFAULT LAYOUT section for the BODY section. Using this to make different font numbers the default font for the box revealed some interesting problems.

Under these conditions:

  1. It is not the first page of the document.
  2. The HLINE will appear at the top of the page.
  3. The default font has a line height which is less than the line height of font 0.

the vertical position is offset and the skips and depth of the HLINE are computed by wgml 4.0 in this way:

vertical-offset = font0-line-height / 4
if( font0-line-height % 4 ) {
    vertical-offset++
}
top-skip += vertical-offset
subs-skip += vertical-offset
element-depth = font0-line-height - 2 * vertical-offset

Fonts with a line height greater than that of font 0 were also tested, but the behavior shown by wgml 4.0 could not be reproduced and, indeed, did not make much sense. Then again, the behavior shown doesn't make much sense either, and that is why our wgml uses the formulas shown above at all times.

When the left margin is set to "0", and the default font is not "0", two things happen:

  1. wgml 4.0 emits an empty text_chars instance at the very start of the file after the font change from font 0 to the default font, at least if the specified default font is used in that first section.
  2. The minimum horizontal position is 250 for the PS device; this is the normal minimum left margin for that device plus the horizontal-offset computed above.

If the value of the x_start attribute of the PAGESTART block of the DEVICE block is set to "0" in the PS device, then the net-horizontal-position is less than "0" and the minimum becomes "50". Our wgml certainly does not emit an empty text_chars at the start of the file. If may or may not compute the same value for the minimum horizontal position under the conditions given, depending on whether or not that is the normal result.

For some unexplored reason, when there are 800 horizontal base units per inch, wgml 4.0 shifts 10 horizontal base units to the right; at least the HLINE and the items inside the box are shifted. Since the only affected device, PS, has 1000 horizontal base units per inch, this was not investigated further.

The intended tests, with fonts using different metrics, were carried out by using the FONT command-line operator to change the metrics of font "0". This was helpful in confirming, for example, when a discrepancy of "+1" was from rounding (that is, the difference between vertical-offset and element-depth when the line-height is odd) or an actual, but inexplicable, incrementation.

Aberrant BX OFF Horizontal Lines

Under some conditions, wgml 4.0 will merge different horizontally-separated boxes.

Details will follow, but, in the relevant case, at the top of a page, using dots for spaces to produce the correct alignment, our BX OFF was producing

─┴                             ───────      ┴─

while wgml 4.0 was producing

─┴────────────────────────────────────   ───┴─

That is, it was merging the first two horizontally-separated lines but not the third.

Actually, looking above, this may not be quite the problem I originally thought it was, and more research will be needed on BX ON versus BX in certain situations. This behavior might even be correct, in the sense of resulting naturally from the difference between BX and BX ON.

Personal tools