Advanced Search
Apple Developer Connection
Member Login Log In | Not a Member? Contact ADC


How GX does Justification


The justification process in GX is divided into several phases: the factor phase, the assignment phase, and the postcomp phase. Note that some of the justification actions may take place even on unjustified lines of text: for example, if loose tracking is applied to a line, enough letterspacing may be added so that ligatures should be broken apart. Ligature decomposition happens in the postcomp phase, so this phase needs to happen even if the line itself is not justified.

Irrespective of justification, a line of text has a "natural" width, called the unjustified width, which is roughly the sum of the widths of all the glyphs making up the line. I say "roughly" here, since there are other factors taken into account in GX typography which affect this width. For instance, the line may start with a hung punctuation glyph; in this case, the width of that glyph is not counted in the line's unjustified width. Similarly, any kerning, tracking or manual letterspacing the user has specified alter the effective widths of glyphs, and thus the total unjustified width.

The State Table Phase

Before doing any processing on a line, GX first sees if the justification table contains a state table. If it does, then that state table is processed to determine the justification class for each glyph on the line. In all the following phases, this class (which is just a number) is used in addition to the glyphcode to look up values or determine what actions are taken. By allowing a state table to assist with the processing, it becomes possible to make the same glyph have different justification characteristics in different parts of the line.

The Factor Phase

The factor phase begins by computing the unjustified width of the line, and sees what justified width the user has specified. The unjustified width is subtracted from the justified width to get the base gap that needs to be filled. For example if the unjustified width of the line is 300 points, and the justified width is specified as being 450 points, then the base gap is +150 points. When the base gap is positive, it is called the grow case, because the line needs to grow to fill the gap. When the base gap is negative, it is called the shrink case. In this case, the line needs to be squeezed to fit the specified width.

In either the grow or shrink cases, the user may not want all the gap to be filled; an example of this is specifying, say, an 80% ragged right edge. In GX this is done by setting the justification for the line to some value other than 0 or 1. The base gap is adjusted by one minus this value, resulting in the final gap to be filled.

Once the final gap is calculated, GX consults with the justification table in the font, as well as any user overrides, to determine how much distance is available on each side of each glyph for justification purposes. This distance is specified in ems -- that is, in points for one-point text. This gets multiplied by the pointsize of the actual glyphs to get the actual available distance. The resulting numbers (one for the left side of each glyph and one for the right side) are called the justification factors. To take an example, if the font designates a left-side factor of 0.2 and a right-side factor of 0.3 for a particular glyph, then that glyph at 10-point will have available (0.2 times 10) or 2 points on the left and (0.3 times 10) or 3 points on the right. Note that GX doesn't do anything with this distance yet; it represents a potential, a means of helping fill the final gap.

As well as determining the justification factors, the factor phase also determines two other critical pieces of information for each glyph on the line: the justification priority, and the unlimited status. The justification priority controls the order in which glyphs will be changed later in the assignment phase. There are four priorities, called by convention the kashida priority, whitespace priority, intercharacter priority, and the null priority, with kashida priority the highest and null priority the lowest. All glyphs of a higher priority will be adjusted before any glyphs of a lower priority are considered. If a glyph has the unlimited status, then that glyph is permitted to absorb all of the remaining gap, even in excess of its justification factors. If a line contains one or more unlimited glyphs of a given priority level, then any glyphs of lower priority levels won't be touched during the assignment phase.

The Assignment Phase

With these data (the left and right factors, the priority and the unlimited status), the factor phase is finished and the assignment phase begins. The assignment phase is needed to allow for cases where the total justification factors available on the line exceed the needed final gap, or are insufficient to cover that gap. The assignment phase starts at the highest priority present on the line, adds up the total factors at that level, and sees if that amount is enough to satisfy the final gap. If it is then the final gap is apportioned proprtionally to the factors, and the assignment phase is done. If there is still gap left over, then the next lowest priority level is considered, and so on. If all the priority levels are used up, and there is still gap left over (and there were no unlimited glyphs), then the assignment phase goes back to the highest priority that was present on the line and gives the remaining gap to those glyphs; note that this will violate their factors, but this case only happens in extremis.

The Postcomp Phase

Once the factors have been apportioned in this way, the glyph positions are modified accordingly. By positioning the glyphs further apart, whitespace is introduced. In many cases this suffices; however, there are cases (like connected scripts) where whitespace is not permitted between glyphs. These cases are handled by the final phase, the postcomp phase. Here decisions are made about creative alternatives to just separating glyphs by whitespace. For example, an extra glyph can be inserted between two glyphs in order to change the whitespace added into something else. A wider version of a glyph can be substituted for an existing glyph to help swallow some of the space. Ligatures can decompose if needed. A variation axis can be used to change the widths of all the glyphs (called copyfitting).

Change History

    • 7 May 1997: Created by cribbing text from the GXifier documentation

Copyright©1998 by Apple Computer, Inc.
Updated 2/4/98

Get information on Apple products.
Visit the Apple Store online or at retail locations.

Copyright © 2004 Apple Computer, Inc.
All rights reserved. | Terms of use | Privacy Notice