|
|
Microsoft OS/2 SDK PM 02-24-1989
The Presentation Manager Vector Fonts
by Charles Petzold
Let's begin with a question: What graphics programming
language stores fonts as a lines and curves (rather than
bitmaps), and thus allows fonts to be arbitrarily stretched,
rotated, outlined, filled with different patterns, or even
used as clipping areas?
One answer is obviously PostScript, Adobe Systems' page
composition language implemented on many high-end laser
printers (beginning with the Apple LaserWriter) and Allied
Corporation's Linotronic phototypesetters. Over the past few
years, PostScript has become the language of choice for
computer manipulation of fonts and text.
But an equally valid answer is GPI -- the Graphics
Programming Interface component of the OS/2 Presentation
Manager. As we'll see, GPI has facilities to do virtually
everything with fonts that you can do with PostScript.
The Trouble With Text
The display of text is always the most problematic part of a
graphics programming system. Unlike lines and polygons
(which are merely mathematical constructs), text is rooted
in a long tradition of aesthetic typography. In any computer
graphics system, the goal must always be to display text
that is as pleasing and as easy to read as a well-printed
book.
Yet, most computer output devices (such as video displays
and printers) are digital media. The subtly shaped and
rounded characters that comprise traditional fonts must be
broken down into discrete pixels for storage and then
reassembled on the output device. This often causes
distortions in the appearance of the text.
But one major advantage of using a computer for this job is
versatility: We can use a wide variety of fonts in various
sizes and characteristics, and modify these fonts for
display. The extent to which we can modify fonts is
dependent on the way in which the fonts are stored in
memory.
Images and Vectors
A font is generally stored in computer (or printer) memory
in one of two very different ways:
First, a font can be stored as an "image" or "bitmap." Each
character of the font is simply a rectanglar array of bits.
The 0 bits generally correspond to the background around the
character and the 1 bits correspond to the character itself.
Secondly, a font can be stored in a "vector" or "outline"
format. Each character is defined as a series of lines and
curves that enclose areas. The character is displayed by
drawing the outline on the output device and filling the
enclosed areas.
Image and vector fonts have distinct advantages and
disadvantages. Image font are always created for specific
font sizes and specific device resolutions. The size of a
particular image font cannot easily be changed. (For
example, enlarging an image font by doubling the rows and
columns of pixels often emphasizes the jaggedness of the
characters.) Also, image fonts cannot be rotated except
possibly by 90 degree increments.
Vector fonts are much more malleable. Because they are
defined as a series of lines and curves, vector fonts can be
stretched or compressed to any size and can be rotated to
any angle. Vector fonts are not tied to a particular output
device resolution.
In general, however, image fonts are more legible that
vector fonts. Various techniques are used to design image
fonts so they fool the eye into thinking the characters are
smoother than they actually are. Vector fonts --
particularly when displayed on low resolution devices and
scaled to small font sizes -- can be adjusted only by
mathematical algorithms, which currently are less capable
than human font designers. Another advantage of image fonts
is performance: Vector fonts usually require much more
processing time to draw each character.
Most conventional laser printers store fonts as images,
either within the printer or in font cartridges. The printer
is restricted to specific font sizes and the characters
cannot be arbitrarily rotated. Much more versatile are the
fonts stored in PostScript-based printers. These fonts are
stored as vectors. PostScript fonts can be stretched or
compressed to any size, they can be arbitrarily rotated,
filled with various patterns, and used for clipping.
The GPI Fonts
The Graphics Programming Interface (GPI) of the OS/2
Presentation Manager can, of course, take advantage of fonts
that are stored in and supported by output devices such as
laser printers.
But GPI also includes its own support of both image and
vector fonts. The image fonts are expected, of course,
because they are particularly suited for low resolution
video displays and dot matrix printers. Image fonts are an
important part of most graphics programming systems (such as
Microsoft Windows GDI).
The addition of vector fonts in GPI is a real treat. GPI can
use these vector fonts with any output device. Thus, various
font techniques that previously have been restricted to
PostScript printers are now possible with other laser
printers and even the video display.
This article shows you how to work with vector fonts in GPI
and demonstrates many PostScript-like techniques. Quite
simply, the font support in GPI is nearly as strong as that
in PostScript. However, GPI has a serious deficiency that
I'll discuss at the end of this article.
OS/2 1.1 is shipped with three resource-only dyanamic link
libraries with a .FON extension. These are font files, and
the contents are shown in Figure 1.
In addition, the video display device driver (DISPLAY.DLL)
and printer device drivers may also contain fonts designed
specifically for the device. For example, the default
"System Proportional" font is stored in DISPLAY.DLL.
Important: If you want to use any of the fonts in the .FON
files, you must install the fonts from the Presentation
Manager Control Panel program. It is only necessary to
install one font from each of the three files, and you only
need do this once.
Each font has a face name. This is shown in quotation marks
in Figure 1. Each of the image fonts is available in
several point sizes and for several output devices: the CGA,
EGA, VGA (and 8514/A), and IBM Proprinter. GPI can syntesize
variations of these fonts, such as italic or boldfaced
versions.
Vector fonts, however, need not be designed for a particular
output device and point size because they can be arbitrary
scaled. You'll note that italic and boldface versions of the
vector fonts are also included.
The vector fonts in GPI are equivalent to the Courier,
Helvetica, and Times fonts included in most PostScript
printers. However, because Helvetica and Times are
registered trademarks, these names are not used to identify
the vector fonts in GPI.
A little exploration of the font files will reveal that
vector fonts are encoded as a series of GPI drawing orders.
When drawing text with these fonts, GPI translates the
drawing orders into GPI functions, usually GpiPolyLine to
draw straight lines and GpiPolyFilletSharp to draw curves.
The VECTFONT Program
The VECTFONT program demonstrates the use GPI vector fonts.
For purposes of clarity, I've divided the program into
several modules.
The VECTFONT "Display" menu lists 16 options. The first
option (to display nothing) is the default. The other 15
options correspond to routines in the VF01.C through VF15.C
files (described below). The VF00.C file contains some
"helper" functions used by the routines in VF01.C through
VF15.C.
VECTFONT creates a micro presentation space during the
WM_CREATE message using page units of PU_TWIPS. ("Twips" is
fabricated word standing for "20th of a point." A printer's
point size is 1/72nd inch, so page units correspond to
1/1440 inch.) VECTFONT then modifies the page viewport
rectangle so that a page unit corresponds to 1 point, which
(as you may know) is the default coordinate system in
PostScript.
Although VECTFONT displays output to the screen, vector
fonts are obviously more suited for laser printers. As you
will see, the appearance of the fonts -- even at 24 point
sizes -- is not nearly as good as the image fonts.
You'll also notice that several of the demonstration
routines in VECTFONT requires a few seconds to run. For
anything other than a demonstration program, you'd probably
want to use a second thread of execution so as to not hold
up message processing.
Selecting an Outline Font
To use an outline font in a Presentation Manager program,
you must first create a "logical font" and then select the
font into your presentation space.
The GpiCreateLogFont function creates a logical font and
associates the font with a local ID (a number between 1L and
254L that you select). This function requires a pointer to a
structure of type FATTRS ("font attributes") that specifies
the attributes of the font you want.
To create a vector font, most of the fields in this
structure can be set to zero. The most important fields are
szFacename (which is set to the face name of the font) and
fsFontUse, which is set to the constant identifiers
FATTR_FONTUSE_OUTLINE and FATTR_FONTUSE_TRANSFORMABLE,
combined with the C bitwise OR operator.
You may prefer using the CreateVectorFont function in VF00.C
for creating a vector font. The VF00.C file contains several
other helpful functions that are used by the demonstration
routines in VF01.C through VF15.C.
The CreateVectorFont function requires only the presentation
space handle, the local ID, and the face name:
CreateVectorFont(hps, lcid,
szFacename);
After you create a logical font (using either
GpiCreateLogFont or CreateVectorFont), you can select the
font into the presentation space:
GpiSetCharSet(hps, lcid);
The lcid parameter is the local ID for the font. After the
font is selected in the presentation space, you can alter
the attributes of the font with various functions described
below, obtain information about the font by calling
GpiQueryFontMetrics, GpiQueryWidthTable, and
GpiQueryTextBox, and you can use the font for text output
with one of the text functions such as GpiCharStringAt.
When you no longer need the font, you select the default
font back into the presentation space:
GpiSetCharSet(
hps,
LCID_DEFAULT);
and then delete the local ID associated with the font:
GpiDeleteSetId(hps, lcid);
In VECTFONT, I always use the identifier LCID_MYFONT for the
local ID. This is defined in VECTFONT.H as 1L.
Scaling to a Point Size
When you call GpiSetCharSet to select a vector font into the
prsentation space, the initial width and height of the font
are based on the GPI "character box," which defines a
character width and height in page units. The default
character box is based on the size of the default system
font. You can change the character box size by calling
GpiSetCharBox.
Very important: To get a correctly proportioned vector font,
it is necessary to change the character box size. Do not use
the default Generally you set the height of the character
box to the desired height of the font. If you want the a
vector font to have a normal width, you set the width of the
character box equal to the height. For a skinnier font, set
the width of the character box less than the height; for a
fatter font, set the width greater than the height.
If you're working in page units of PU_PELS, you must also
adjust the character box dimensions to account for
differences in horizontal and vertical resolution of the
output device. For this reason, it's much easier to work
with vector fonts if you use one of the metric page units
(PU_LOENGLISH, PU_HIENGLISH, PU_LOMETRIC, PU_HIMETRIC, or
PU_TWIPS). With these page units, horizontal and vertical
page units are the same.
For example, suppose you're using page units of PU_TWIPS.
This means that one page unit is equal to 1/20 of a point or
1/1440 inch. After selecting a vector font into the
presentation space, you want to scale the font to 24 points.
You first define a structure of type SIZEF:
SIZEF sizfx;
The two fields of this structure are named cx and cy and are
interpreted as 32-bit FIXED numbers, that is, the high 16-
bits are interpreted as an integer, and the low 16-bits are
interpreted as a fraction.
If you want to scale the vector font to a 24 point height,
you can use the MAKEFIXED macro to set to the fields of the
structure like this:
sizfx.cx = MAKEFIXED(
24 * 20, 0);
sizfx.cy = MAKEFIXED(
24 * 20, 0);
Multiplying by 20 is necessary to convert the point size you
want to twips. Then call GpiSetCharBox:
GpiSetCharBox(hps, &sizfx);
After setting the character box, any character or text
dimensions you obtain from GpiQueryFontMetrics,
GpiQueryTextBox, and GpiQueryWidthTable will reflect the new
font size.
The ScaleVectorFont routine in VF00.C can help in scaling a
vector font to a desired point size. The function will work
with any page units, even PU_PELS. The second and third
parameters to ScaleVectorFont specify a point size in units
of 0.1 points. (For example, use 240 for a 24-point size.)
If you want a normally proportioned vector font, set the
third parameter to ScaleVectorFont equal to the second
parameter.
The VF01.C file shows how the functions discussed so far can
be used to display all the available vector fonts in 24
point sizes. You can run the function in VF01.C by selecting
the "24 Point Fonts" option from the VECTFONT "Display"
menu.
Arbitrary Stretching
Besides scaling the vector font to a specific point size,
you can also scale vector fonts to fit within an arbitrary
rectangle. For example, you may want to scale a short text
string to fill the client window.
The function shown in VF02.C shows how this is done. You can
run this function by selecting "Stretched Font" from
VECTFONT's menu. The function in VF02.C displays the word
"Hello!" in the "Tms Rmn Italic" font stretched to the size
of the client window.
The ScaleFontToBox function in VF00.C helps out with this
job. This function first calls GpiQueryTextBox to obtain the
coordinates of a parallelogram that encompasses the text
string. The character box is then scaled based on the size
of this text box and the rectangle to which the font must be
stretched. The QueryStartPointInTextBox function in VF00.C
determines the starting point of the text string (that is,
the point at the baseline of the left side of the first
character) within this rectangle. This point is used in the
GpiCharStringAt function to display the text.
Mirror Images
Besides scaling the font to a particular size, the character
box can also flip the characters around the horizontal or
vertical axis.
If the character box height (the cy field of the SIZEF
structure) is negative, then the characters will be flipped
around the baseline and displayed upside down. If the
character box width (the cx field) is negative, the
individual characters are flipped around the vertical axis.
Moreover, GpiCharStringAt will draw a character string from
right to left. It's as if the whole character string is
flipped around the vertical line at the left side of the
first character.
The function in VF03.C displays the same string four times,
using all possible combinations of negative and positive
character box dimensions. You can run this function by
selecting "Mirrored Font" from the VECTFONT menu.
Vector Fonts and Transformations
Unlike image fonts, vector fonts can be scaled to any size
and sheared and rotated to any angle. The matrix transforms
described in my article "OS/2 Graphics Programming
Interface: An Introduction to Coordinate Spaces" (Microsoft
Systems Journal, Volume 3, Number 4) affect vector fonts in
the same way they affect the display of other graphics
primitives.
In addition, GPI also supports several functions
specifically for performing transforms on vector fonts.
We've already seen how the GpiSetCharBox function allows
font characters to be scaled. The GpiSetCharAngle rotates
the font characters and the GpiSetCharShear performs x-
shear.
Character Angle and Rotation
By default, the baseline of the vector font characters is
parallel to the x axis in world coordinates. You can change
this by calling GpiSetCharAngle. This rotates the vector
fonts characters.
The character angle is specified using a GRADIENTL
structure, which has two fields named x and y of type LONG.
Imagine a line connecting the point (0,0) to the point (x,y)
in world coordinates. The baseline of each character is
parallel to this line. The direction of the text is the same
as the direction from (0,0) to (x,y).
You can also think of this in trigonometric terms. The
baseline of the text is parallel to a line at angle a
measured counterclockwise from the x-axis, where:
a = arctan (y/x)
and y and x are the two fields of the GRADIENTL structure.
The absolute magnitudes of y and x are not important. What's
important are the relative magnitudes and signs. The signs
of x and y determine the direction of the text string as
indicated in the following table:
x y Direction
- - ---------
+ + To upper right
- + To upper left
- - To lower left
+ - To lower right
The function in VF04.C uses the GpiSetCharAngle function to
display eight text strings at 45 degree increments around
the center of the client window. Each string displays the
fields of the GRADIENTL structure that is used in the
GpiSetCharAngle call.
In this example, the text strings begin with a blank
character so as not to make a mess of overlapping characters
in the center of the client window. The character angle does
not affect the interpretation of the starting position of
the string specified in the GpiCharStringAt function. If you
move your head so that a particular string is seen as
running left to right, the starting position still refers to
the point at the baseline of the left side of the first
character.
You can make the characters in a text string follow a curved
path by individually calculating the starting position an
angle of each character and displaying the characters one at
a time. This is what is done in VF05.C to display "Hello,
world!" around the perimeter of a circle.
The text string is scaled based on the circumference of a
circle that is positioned in the center of the window and
has a diameter half the width or height (whichever is less)
of the window. The GpiQueryWidthTable function is used to
obtain the width of individual characters and then space
them around the circle.
Character Shear
It is easy to confuse the character angle and character
shear. Lets look at the difference. The character angle
refers to the orientation of the baseline. Text displayed
with various character angles is rotated but otherwise not
distorted in any way.
The character shear affects the appearance of the characters
themselves apart from any rotation. Character shear by
itself "bends" characters to the left or right, but the
bottom of each character remains parallel to the x-axis. You
can use character shear to create oblique (sometimes
mistakenly called italic) versions of a font.
To set character shear you call the GpiSetCharShear
function. This function requires a pointer to a structure of
type POINTL, which has two fields named x and y. Imagine a
line drawn from (0,0) to the point (x,y) in world
coordinates. The left and right sides of each character are
parallel to this line.
The function shown in in VF06.C displays seven text strings
using different character shears.
You can run this function by selecting "Character Shear"
from the VECTFONT menu. Each string displays the x and y
values used in the POINTL structure to set the character
shear.
The character shear is governed by the relative magnitudes
and signs of the x and y fields of the POINTL structure. If
the signs of both fields are the same, the characters tilt
to the right; if different, the characters tilt to the left.
The character shear does not cause characters to be flipped
upside down. For example, character shear using the point
(100,100) has the same effect as (-100,-100).
The angle of the left and right sides of the characters from
the y axis is sometimes called the shear angle. In theory,
the shear angle can range to just above -180 degrees
(infinite left shear) to just under +180 degrees (infinite
right shear) and is equal to:
a = arctan (x/y)
where x and y are the two fields of the POINTL structure.
When you set a non-default character shear, the
GpiQueryTextBox function returns an array of points that
define a parallelogram rather than a rectangle. However, the
top and bottom sides of this text box are the same width as
for a non-sheared text string, and the distance between the
top and bottom sides also remains the same.
You can use character shear to draw an oblique shadow of a
text string. The function in VF07.C colors the background of
the client window blue, and displays the text string
"Shadow" twice.
The first call to GpiCharStringAt displays the shadow. This
is drawn in dark blue using a positive character shear. The
second call to GpiCharStringAt draws the characters upright
in red with a slightly smaller character box height. You can
run this function by selecting "Font with Shadow" from the
VECTFONT menu.
A Primer on Paths
To explore more capabilities of vector fonts, it's necessary
to become familiar with the GPI "path," which is similar to
a PostScript path. In GPI, you create a path by calling line
drawing functions between calls to the GpiBeginPath and
GpiEndPath functions:
GpiBeginPath(hps, idPath);
<... call line
drawing
functions ... >
GpiEndPath (hps) ;
This is called a "path bracket." In OS/2 1.1, idPath must be
set equal to 1L. The functions that are valid within a path
bracket are listed in the documentation of the Presentation
Manager functions.
The functions you call within the path bracket do not draw
anything. Instead, the lines that make up the path are
retained by the system. Often the lines you draw in a path
will enclose areas, but they don't have to.
After the GpiEndPath call, you can do one of three things
with the path you've created:
* Call GpiStrokePath to draw the lines that comprise
the path. These lines are drawn using the
geometric line width, joins, and ends (discussed
shortly).
* Call GpiFillPath to fill enclosed areas defined by
the path. Any open areas are automatically
closed. The area is filled with the current
pattern.
* Call GpiSetClipPath to make the enclosed areas of
the path a clipping area. Any open areas are
automatically closed. Subsequent GPI calls will
only display output within the enclosed area
defined by the path.
Each of these three functions cause the path to be deleted.
Prior to calling any of these three functions you can call
GpiModifyPath, which I'll describe towards the end of this
article.
Normally, GpiCharStringAt and the other text output
functions are not valid in a path bracket. The exception is
when a vector font is selected in the presentation space.
When called from within a path bracket, GpiCharStringAt does
not draw the text string. Instead, the outlines of the
characters become part of the path.
This facility opens up a whole collection of PostScript-like
stylistic techniques that you can use with vector fonts.
Hollow Characters
Let's begin by calling GpiCharStringAt in a path bracket and
then use GpiStrokePath to draw the lines of the path.
GpiStrokePath has the following syntax:
GpiStrokePath(
hps, idPath, 0L);
In the initial version of the Presentation Manager, the last
parameter of the function must be set to 0L. When used to
stroke a path created by calling GpiCharStringAt, only the
outline is drawn and not the interiors. This creates hollow
characters.
The function in VF08.C uses this technique to display the
outline of the characters in the text string "Hollow." You
can run this function by selecting "Hollow Font" from the
VECTFONT menu.
You may want to display characters in one color with an
outline of another color. In this case, you must call
GpiCharStringAt twice, first to draw the interior in a
specific color, and secondly in a path bracket followed by a
GpiStrokeFont call to draw the outline.
The function in VF09.C does something like this to draw text
with a drop shadow.
The shadow is drawn first using a normal GpiCharStringAt
call. Another GpiCharStringAt functions draws the text again
in the current window background color at a 1/6 inch offset
to the first string. This is surrounded by an outline
created by a third GpiCharStringAt call in a path bracket
followed by GpiStrokeFont.
Quite similar to this is the creation of characters that
look like solid blocks, as shown in the function in VF10.C.
Eighteen character strings are drawn at 1 point offsets
using CLR_DARKGREEN. This is capped by the character string
drawn again in CLR_GREEN and the border in CLR_DARKGREEN.
Geometrically Thick Lines
At first, it may seem as if there is no difference between
drawing a line normally, like this:
GpiMove(hps, &ptlBeg);
GpiLine(hps, &ptlEnd);
and calling these same two functions within a path bracket
and then stroking the path, like this:
GpiBeginPath(hps, idPath);
GpiMove(hps, &ptlBeg);
GpiLine(hps, &ptlEnd);
GpiEndPath(hps)
GpiStrokePath(hps, idPath, 0);
There are, in fact, some very significant differences.
First, the line drawn with the normal GpiLine function has
what is called a "cosmetic" line width. The default width of
the line is based on the resolution of the output device. It
is a device dependent width for a "normal" line. The width
of the line does not change when you use matrix transforms
to set different scaling factors in the coordinate space.
Although GPI provides a function called GpiSetLineWidth to
change the cosmetic line width, this function is not
implemented in OS/2 1.1.
But a line drawn by stroking a path has a "geometric" line
width. This is a line width (in world coordinates) that you
set with the GpiSetLineWidthGeom function. Because this line
width is specified in world coordinates, it is affected by
any scaling that you set using matrix transforms.
Secondly, a line draw with GpiLine can have different line
types that you set with the GpiSetLineType function. These
line types are various combinations of dots and dashes. The
line is drawn with the current line color and the current
line mix.
But a line drawn by stroking a path does not use the line
type. The line is instead treated as an area that follows
the path of the line but which has a geometric width. This
area is filled with the pattern that you set with
GpiSetPattern, colored with the current pattern foreground
and background color, and the current pattern foreground and
background mix.
Third, a line drawn by stroking the path can have various
types of line "joins" and "ends." By calling GpiSetLineJoin
you can specify that lines meet with a rounded, square, or
miter join. GpiSetLineEnd lets you specify rounded, square,
or flat ends to the lines.
The function in the VF11.C file demonstrates the use of
geometrically thick lines filled with patterns to give the
letters a kind of "neon" look.
You can run this function by selecting "Neon Effect" from
the VECTFONT menu. The function strokes the path using
various geometric line widths filled with a PATSYM_HALFTONE
pattern and several colors. The outline of the font is
white, but surrounded with a halo of red.
A better effect could be achieved on devices capable of more
than 16 colors. In this case, you can use a solid pattern
but color each stroke with a different shade of red.
Filling the Path
When introducing paths earlier in this article, I mentioned
that you can do one of three things with a path: stroke it,
fill it, or use it for clipping. Let's move on to the
second: filling the path.
To fill a path, you call:
GpiFillPath(hps,
idPath, lOption);
This fills the path with the current pattern. Any open areas
of the path are automatically closed before being filled.
The lOption parameter can be either FPATH_ALTERNATE or
FPATH_WINDING to fill the path using alternate or winding
modes. For vector fonts, FPATH_WINDING causes the interiors
of some letters (such as "O") to be filled. You'll probably
want to use FPATH_ALTERNATE instead.
If the current area filling pattern is PATSYM_SOLID, then
the code:
GpiBeginPath(hps, idPath);
GpiCharStringAt(hps, &ptl,
cch, szText);
GpiEndPath(hps);
GpiFillPath(hps,
idPath,
FPATH_ALTERNATE);
does roughly the same thing with a vector font as a
GpiCharStringAt by itself. When using GpiFillPath you'll
want to set a pattern other than PATSYM_SOLID. (A bug in
OS/2 1.1 causes the current pattern to be reset to
PATSYM_SOLID during a path bracket in which GpiCharStringAt
is called. You can get around this bug by calling
GpiSetPattern after you end the path.)
The function in VF12.C uses GpiFillPath to display the text
string "Fade" eight times filled with the eight GPI shading
patterns (PATSYM_DENSE1 through PATSYM_DENSE8) and then
finishes by calling GpiCharStringAt outside of a path
bracket. You can run this function by selecting "Fading
Font" from the VECTFONT menu.
Clipping to the Text Characters
The third option after creating a path is to call
GpiSetClipPath:
GpiSetClipPath(hps, idPath,
lOption);
The lOption parameter can be either SCP_RESET (which equals
0L, so it's the default) or SCP_AND. The SCP_RESET option
causes the clipping path to be reset so that no clipping
occurs. The SCP_AND option sets the new clipping path to the
intersection of the old clipping path and the path you've
just defined in a path bracket. Any open areas in the path
are automatically closed.
You can combine the SCP_AND option with either SCP_ALTERNATE
(the default) or SCP_WINDING. As with GpiFillPath, you'll
probably want to use alternate mode when working with paths
created from vector fonts
The function in VF13.C calls GpiCharStringAt with the text
string "WOW" within a path bracket. This is followed by a
call to GpiSetClipPath. The clipping path is now the
interior of the letters. The function draws a series of
colored lines emanating from the center of the client
window.
The function in VF14.C uses a similar technique but draws a
series of areas defined by splines.
Modifying the Path
Between the call to GpiEndPath to end the path and the call
to GpiStrokePath, GpiFillPath, or GpiSetClipPath, you can
call GpiModifyPath. This function uses the current geometric
line width, line join, and line end to convert every line in
the path to a new line that encloses an area around the old
line.
For example, suppose that the path contained a single
straight line. After GpiModifyPath the path would contain a
closed line in the shape of a hotdog. The width of this
hotdog is the geometric line width. The ends of the hotdog
could be round, square, or flat, depending on the current
line end attribute.
Following the creation of a path, these two functions in
succession:
GpiModifyPath(hps, ID_PATH,
MPATH_STROKE);
GpiFillPath(hps, ID_PATH,
FPATH_WINDING) ;
is usually equivalent to:
GpiStrokePath(hps, ID_PATH,
0L);
GpiModifyPath and GpiStrokePath are the only two functions
that use the geometric line width, joins, and ends.
In theory, you can call GpiStrokePath after GpiModifyPath,
like this:
GpiModifyPath(hps, ID_PATH,
MPATH_STROKE);
GpiStrokePath(hps, ID_PATH,
0L);
This should do something, and it should be rather
interesting, but GPI usually reports that it can't create
the path because it's too complex.
Instead, let's look at GpiModifyPath followed by
GpiSetClipPath. The function in VF15.C is almost the same as
the one in VF13.C except that it sets the geometric line
width to 6 (1/12 inch) and calls GpiModifyPath before
calling GpiSetClipPath.
Note that the colored lines are clipped not to the interior
of the characters, but to their original outlines. By the
use of GpiModifyPath, the outlines of the characters have
themselves been made into a path that is 1/12 inch wide.
This is the path that is used for clipping.
Is It Enough?
I think it's clear that the facilities provided by GPI for
working with vector fonts equal -- and sometimes exceed --
those in PostScript. The GPI interface is very powerful and
very versatile.
Is that enough?
No, it's not. The implementation of vector fonts in GPI has
a structural flaw that still leaves PostScript the king.
Take a close look at the display of the "Helv" font. You'll
notice that the two legs of the "H" are different in width
by one pixel when they should be the same width. This is
undoubtedly due to a rounding error. It's obviously more
noticeable on a low-resolution video display than it would
be on a 300 dpi laser printer, but even on a laser printer
such errors will affect the legibility of the text.
Errors such as this do not occur with PostScript fonts.
PostScript fonts are true algorithms that are able to
recognize and correct any anomalies in the rendition of the
characters. In contrast, GPI fonts (which are encoded as a
simple series of polylines and polyfillets) are drawn
blindly without any feedback or correction.
So, while we can rejoice in what we have in GPI, there is
still the need to hope for improvement.
Figure 1
Dynamic Link
Library File Image Fonts Vector Fonts
------------ ----------- ------------
COURIER.FON "Courier" (8, 10, and "Courier"
12 points for CGA, "Courier Bold"
EGA, VGA, and "Courier Italic"
IBM Proprinter) "Courier Bold Italic"
HELV.FON "Helv" (8, 10, 12, 14, "Helv"
18, and 24 points "Helv Bold"
for CGA, EGA, VGA, "Helv Italic"
and IBM Proprinter) "Helv Bold Italic"
TIMES.FON "Tms Rmn" (8, 10, 12, "Tms Rmn"
14, 18, and 24 points "Tms Rmn Bold"
for CGA, EGA, VGA, "Tms Rmn Italic"
and IBM Proprinter) "Tms Rmn Bold Italic"
Caption: The OS/2 1.1 dynamic link library files that
Caption:
contain fonts. The font face names are shown in quotation
marks.
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.