This chapter describes the commands used to draw things on a display. the Graphics Environment chapter, explains how to set up the display necessary to use these commands.
You must have read the previous chapter; in particular, you should be familiar with GStates. To use certain commands, you should also be familiar with the GEOS fixed point number formats.
1 Drawing Goals
2 Shapes
2.1 Dots
2.2 Lines
2.3 Rectangles
2.4 Ellipses
2.5 Elliptical Arcs
2.6 Three-Point Arcs
2.7 Rounded Rectangles
2.8 Polylines and Polygons
2.9 Bézier Curves and Splines
2.10 Drawing Bitmaps
2.11 Paths
2.12 Regions
2.13 Text
3 Shape Attributes
3.1 Color
3.2 Patterns and Hatching
3.3 Mix Mode
3.4 Masks
3.5 Line-Specific Attributes
The graphics system has a set of graphic commands capable of describing anything that might ever be drawn; at the same time, the command set should not be overwhelming. Common routines must be heavily optimized: if the line or text drawing routines are slow, the system will be slowed by a similar amount. Commands for drawing the various shapes must exist for all the contexts discussed in the previous chapter. In GEOS, you use the same graphics commands whether you are drawing to a display, describing a GString (which can be sent to a printer), drawing to a bitmap, or describing a path. This simplifies graphics programming a great deal.
Depending on how much experience you have with the GEOS graphics system, you may have some idea already about what sorts of shapes can be drawn and the ways to draw them. Most of these commands have names like
GrDrawShape()
or
GrFillShape()
(e.g.
GrDrawRect()
,
GrFillEllipse()
). Normally, a command of the form
GrDrawShape()
draws the outline of a shape, while
GrFillShape()
fills in the interior of the shape. Commands with names like
GrSetAttribute()
(e.g.
GrSetAreaColor()
) change the color, fill pattern, and other attributes of shapes to be drawn. Most of these commands are passed a GState. The drawing commands are also passed coordinates at which to draw.
For many of these commands, there are GString opcodes which represent the command in a GString. Also, the arguments used when drawing these shapes often correspond to instance data specific to the Graphic Object which draws that shape.
Most of these routines work with standard coordinates, measured in typographer's points. For geodes that need to make drawings which are precise to a fraction of a point, four routines have been set up to use WWFixed coordinates, and are thus accurate to a fraction of a point. These routines are
GrDrawRelLineTo()
,
GrRelMoveTo()
,
GrDrawRelCurveTo()
, and
GrDrawRelArc3PointTo()
. Geodes may use these routines to draw the outline of any conceivable two-dimensional shape. To create a precise, filled shape, use these routines to describe a path and then fill the path.
GrDrawPoint(), GrDrawPointAtCP()
A point is the smallest thing drawable; it will always appear as a single pixel. The point's position is defined by a standard coordinate pair. Points are drawn using line attributes. After drawing a point, the pen position will be at the point's coordinates.
GrDrawPoint()
draws a point at the passed coordinate pair.
GrDrawPointAtCP()
draws a point at the current pen position.
GrDrawLine(), GrDrawLineTo(), GrDrawRelLineTo(), GrDrawHLine(), GrDrawHLineTo(), GrDrawVLine(), GrDrawVLineTo()
A line is simply a line segment that connects two points. Lines are drawn using the current line attributes stored with the GState. The new pen position becomes the last passed coordinate pair.
GrDrawLine()
draws a line between points.
GrDrawLineTo()
draws a line from the current pen position to the passed point.
GrDrawHLine()
draws a horizontal line between two points. These two points share the same
y
coordinate (thus the line is horizontal).
GrDrawHLineTo()
draws a horizontal line from the current pen position to a passed
x
coordinate.
GrDrawVLine()
draws a vertical line between two points which share a common
x
coordinate.
GrDrawVLineTo()
draws a vertical line from the current pen position to a passed
y
coordinate. The
GrDrawH...()
and
GrDrawV...()
routines save space compared to
GrDrawLine()
or
GrDrawLineTo()
, since fewer coordinates are necessary to define the line.
GrDrawRelLineTo()
draws a line from the current pen position to the point at the specified
x
and
y
offset from the starting position. This routine takes very precise coordinates, and is useful for describing paths.
GrDrawRect(), GrDrawRectTo(), GrFillRect(), GrFillRectTo()
Rectangles are defined by four coordinates which can be thought of as either defining the rectangle's left, top, right, and bottom bounds or as specifying two opposite corners of the rectangle.
GrDrawRect()
draws the outline of a rectangle using the passed coordinates.
GrDrawRectTo()
draws the outline of a rectangle using the current pen position as one of the defining points; the pen position is unchanged by this operation. These functions draw the rectangle outline using the current line attributes.
GrFillRect()
draws a filled rectangle defined by the passed coordinates.
GrFillRectTo()
fills a rectangle of which the pen position is one corner.
GrFillRect()
and
GrFillRectTo()
use the GState's area attributes. They do not draw a border around the rectangle; if you want a bordered rectangle, call
GrFillRect()
and follow it with
GrDrawRect()
. Note that if the order of these operations if reversed, the fill may obscure the draw.
GrDrawEllipse(), GrFillEllipse()
Ellipses are defined by their bounding rectangles. The pen position becomes the first coordinate pair passed. Circles are ellipses with heights equal to their widths.
GrDrawEllipse()
draws the outline of an ellipse using the current line drawing attributes.
GrFillEllipse()
fills the ellipse's area using the current area attributes.
GrDrawArc(), GrFillArc()
An arc is a partial ellipse. An arc is defined in terms of its base ellipse, the angle at which to start drawing the arc, and the angle at which to stop drawing. Angles are counted in degrees counter-clockwise with 0° corresponding to the positive x axis (i.e., "3 o'clock").
GrDrawArc()
draws the outline of an elliptical arc, a curved line. It does so using the GState's current line attributes.
GrFillArc()
fills the arc. There are two ways to fill an arc: you can fill in the wedge described by the arc, or you can fill just the region between the arc and its chord; set the style with an
ArcCloseType
value.
GrDrawArc3Point(), GrDrawArc3PointTo(), GrFillArc3Point(), GrFillArc3PointTo(), GrDrawRelArc3PointTo()
The graphics system allows another way to specify arcs. Given two endpoints and one arbitrary point, there is a unique circular arc which has those endpoints and passes through that arbitrary point. The closer the arbitrary point is to the line connecting the endpoints, the shallower the described arc.
GrDrawArc3Point()
draws the three-point arc corresponding to the passed points. The second endpoint passed becomes the new pen position.
GrDrawArc3PointTo()
draws a three-point arc using the present pen position as one of the endpoints; the other endpoint becomes the new pen position.
GrFillArc3Point()
fills a three-point arc.
GrFillArc3PointTo()
fills an arc that has the present pen position as an endpoint.
The
GrDrawRelArc3PointTo()
routine draws a three-point arc where the pen position is the first point and the other two points are specified as offsets from that position. This routine takes WWFixed coordinates for precision drawing.
One time when programmers might especially want to use three point arcs is in the construction of paths. An important consideration when constructing paths is making sure that the various segments of the path are connected; that is, that they share endpoints. When specifying elliptical arcs, the endpoints are never explicitly defined. Thus, it is ambiguous in some cases whether an arc is supposed to be connected to something else. Because three-point arcs include their endpoints with their definition, there is no such ambiguity.
GrDrawRoundRect(), GrDrawRoundRectTo(), GrFillRoundRect(), GrFillRoundRectTo()
Rounded rectangles are defined in terms of their bounding rectangle and the radius of the circle used to compute the rounded corners. The smaller the corner circle is, the sharper the rectangle's corners will be. A larger corner circle results in a more rounded corner with more area taken away.
GrDrawRoundRect()
draws the outline of a rounded rectangle with the passed bounding rectangle and corner circle dimensions. The drawing position is set to the first passed coordinate pair.
GrDrawRoundRectTo()
draws the outline of the rounded rectangle for which the current position is one corner of the bounding rectangle. The current position is unaffected by this operation.
GrDrawRoundRect()
and
GrDrawRoundRectTo()
use the current line drawing attributes.
GrFillRoundRect()
fills a rounded rectangle with passed bounding rectangle and corner radius using the current area attributes.
GrFillRoundRectTo()
fills a rounded rectangle that has the current position as one corner of the bounding rectangle.
GrDrawPolyline(), GrDrawPolygon(), GrFillPolygon(), GrBrushPolyline(), GrTestPointInPolygon()
Polylines and polygons are drawings made up of chains of connected lines. They are defined as lists of points, or corners. After drawing a polyline or polygon, the pen position will be at the last point of the shape.
GrDrawPolyline()
draws a polyline using the current line attributes.
GrDrawPolygon()
draws a polygon using the current line attributes.
To draw a closed figure with
GrDrawPolyline()
, the first and last point must have the same coordinates.
GrDrawPolygon()
draws figures as closed automatically; having the same beginning and ending point is unnecessary.
GrFillPolygon()
fills the interior of a polygon. It does so using the current area attributes. It also uses a fill rule, describing how the polygon should be filled. The odd/even fill rule decides whether a point is within a polygon by seeing how many times a ray drawn from the point to the exterior of the polygon crosses an edge of that polygon. If the result is odd, the point is considered to be in the interior and is filled. If the result is even, the point is outside the polygon and is left alone. The winding rule works in a similar manner, but whenever the ray crosses an edge, the rule looks at the direction of that edge: if it crosses the ray left to right, an accumulator is incremented; if it crosses the ray right to left, the accumulator is decremented. Those points for which the ray's accumulator is non-zero are considered inside the region.
GrBrushPolyline()
is an optimized routine. It provides a fast, simple way to draw thick polylines. Instead of specifying a line width in points, the caller passes the dimensions of a rectangle of pixels. This rectangle will be used as a sort of brush, dragged along the course of the polyline. The result is a polyline drawn very quickly. However, this function is not display-independent, and is therefore not WYSIWYG. Because the rectangle dimensions are specified in pixels instead of points, the polyline will be thicker or thinner depending on the display's resolution. In the system software, this routine provides the "ink" feedback for pen-based systems, where speed is a top priority.
To find out whether a given point falls within a polygon, call
GrTestPointInPolygon()
.
GrDrawCurve(), GrDrawCurveTo(), GrDrawSpline(), GrDrawSplineTo(), GrDrawRelCurveTo()
Bézier curves are mathematical constructs which provide a cheap and easy way to define smooth curves in a manner that computers can understand. There are other ways to define curves to computers, but the Bézier was chosen for the GEOS kernel because it is used in many standard font description formats. Splines, as implemented in GEOS, are created by drawing curves in sequence.
Bézier curves are defined in terms of four points. Two of these points are the endpoints, known as anchor points. The other two points are known as control points, one associated with each anchor point. The curve extends from anchor point to anchor point. The line between an anchor point and its control point determines the slope, or derivative, of the curve at the anchor point. The further the control point is from the anchor point, the further the curve wants to go along the straight line before curving off towards the other anchor point. A control point at zero distance from its anchor point won't affect the curve; if both control points are at zero distance from their anchors, the result will be a straight line segment.
GrDrawCurve()
draws a Bézier curve. It takes four points as arguments, using the first and last as anchor points and the middle two as control points.
GrDrawCurveTo()
draws a curve but uses the current pen position as the first anchor point, setting the pen position to the second anchor point after drawing.
It would be possible to draw splines by drawing a number of curves which had common endpoints, but the graphics system provides the
GrDrawSpline()
routine by which a spline with an arbitrary number of spline segments may be drawn with one call.
GrDrawSplineTo()
draws a spline with the current position as the first anchor point. The spline drawing routines require the application to set up an array of points. When calling
GrDrawSpline()
, these points should be in the order: anchor, control, control, anchor, control, control,..., anchor. The total number of points should be equal to 3n+1, where n is equal to the number of spline segments. Since
GrDrawSplineTo()
uses the current position as the first anchor point, for this function the array should start with the first control point, and there should be 3n points passed.
For most programmers, that's probably enough to know. Those programmers who want to know more and don't mind a bit of math may feel free to continue this section.
A curve is defined in terms of four points. There is a formula to determine the coordinates of all points on a spline in terms of these four points. The formula uses two parameterized cubic equations. These equations determine the x and y coordinates of a point on the curve. By finding the points corresponding to various parameters, it is possible to approximate the spline as closely as necessary. See below for the equations.
Splines may be created by drawing curves which share endpoints. Given an anchor point which two curves of a spline share, if the control point of one lies in the exact opposite direction of the other control point, the resulting spline will be smooth. If the control points are not only in the exact opposite directions but are also the same distance from the anchor point, then not only will the resulting spline be smooth, but its derivative will be smooth as well.
We call smooth splines with smooth derivatives "very smooth," and this condition is analogous to C'
continuity in functions. Smooth splines with non-smooth derivatives are called "semi smooth", analogous to G' continuity.
GrDrawBitmap(), GrDrawBitmapAtCP, GrFillBitmap(), GrFillBitmapAtCP(), GrDrawHugeBitmap(), GrDrawHugeBitmapAtCP(), GrDrawImage()
In this section only drawing bitmaps will be discussed. For information on creating and modifying bitmaps, see the Graphics Environment chapter.
GrDrawBitmap()
draws a bitmap. This routine is very versatile. It can draw simple and complex bitmaps. It can draw compacted or uncompacted bitmaps, can use a bitmap-specific palette, handles strange resolutions intelligently, and generally does the right thing. If you're working with a large bitmap and want to manage its storage, you may provide a routine to pass in part of the bitmap at a time. If the bitmap is stored in a huge array (true of all bitmaps created with
GrCreateBitmap()
) use
GrDrawHugeBitmap()
instead of
GrDrawBitmap()
, and it will manage memory for you.
GrDrawBitmapAtCP()
draws a bitmap at the current position.
If you just want to draw a monochrome bitmap, consider using the
GrFillBitmap()
command. This routine treats the bitmap like a mask, coloring the "on" pixels with the present area color, and leaving the "off" pixels alone so that whatever is underneath the bitmap can show through. This routine is heavily optimized and very fast.
GrFillBitmapAtCP()
works the same way, filling the bitmap at the current position.
Use
GrDrawHugeBitmap()
to draw a bitmap that has been stored in a HugeArray data structure. Remember that any bitmaps created by
GrCreateBitmap()
are stored in a
HugeArray
.
GrDrawHugeBitmap()
will automatically take care of memory management.
GrDrawHugeBitmapAtCP()
works the same way, drawing the bitmap at the current position.
GrFillHugeBitmap()
and
GrFillHugeBitmapAtCP()
fill huge bitmaps.
GrDrawImage()
is less adaptable but faster than
GrDrawBitmap()
.
GrDrawImage()
has its own kind of scaling which doesn't work in the standard GEOS fashion. This routine ignores the resolutions of both device and bitmap and displays the bitmap so that each pixel of the bitmap corresponds to one pixel of the display. If the coordinate system has been scaled or rotated,
GrDrawImage()
will ignore the scale and rotation when drawing the bitmap. The bitmap may be magnified, but this is not quite the same as normal scaling: The bitmap's resolution is still ignored, but each pixel of the bitmap will receive a square of pixels on the display.
GrDrawHugeImage()
draws the image of a bitmap stored in a
HugeArray
.
The image-drawing routines take an
ImageFlags
structure which holds a flag to specify whether borders should be drawn between the pixels of the bitmap and a bit size field which specifies the magnification to use.
GrDrawPath(), GrFillPath()
GrDrawPath()
draws a path using the current line attributes.
GrFillPath()
fills a path using the current area attributes.
GrFillPath()
can fill the path using either an odd/even or winding fill rule. If the path is to be filled using the winding fill rule, the path must have been defined so that the segments forming the border of each region go around the region so that the interior of the region is to the left. That is, on convex parts of the border, edges should be in the counterclockwise direction. On concave parts of the border edges should go clockwise. For an illustration of a path following this rule, see the figure above. The fill rule is specified by means of a
RegionFillRule
value, which may be one of
ODD_EVEN or
WINDING.
When you define a path by combining two other paths, the result might not be exactly what you would expect.
GrGetPathRegion(), GrDrawRegion(), GrDrawRegionAtCP(), GrMoveReg(), GrGetPtrRegBounds(), GrTestPointInReg(), GrTestRectInReg()
Sometimes it's useful to be able to describe an arbitrary area of a display. Regions provide a mechanism for doing so. Regions are ideal for delimiting large, blobby areas which are relatively free of detail. They are used by the system to describe many "filled shapes."
While it is possible to define a region directly, writers familiar with paths may define a path and then call the
GrGetPathRegion()
routine. To find out how to define a region directly, see below.
GrDrawRegion()
draws a region at the passed position using the current area drawing attributes.
GrDrawRegionAtCP()
draws a region at the current pen position.
GrMoveReg()
changes the coordinates stored within a region data structure by the specified
x
and
y
offsets.
GrGetPtrRegBounds()
returns the coordinates of the passed region's bounding rectangle.
GrTestPointInReg()
sees if the passed point falls within a region.
GrTestRectInReg()
tests to see whether the passed rectangle falls entirely or partially within a region; it returns a value of type
TestRectReturnType
specifying the degree of overlap. These two functions are very useful when using regions for clipping purposes; if a given point or rectangle is discovered to be outside the clipping region, there's no need to draw the point or rectangle.
Some application writers may wish to define regions directly without describing a path. Regions are described in terms of a rectangular array (thus the similarity to bitmaps). Instead of specifying an on/off value for each pixel, however, regions assume that the region will be fairly undetailed and that the data structure can thus be treated in the manner of a sparse array. Only the cells in which the color value of a row changes are recorded. The tricky part here is keeping in mind that when figuring out whether or not a row is the same as a previous row, the system works its way up from the bottom, so that you should compare each row with the row beneath it to determine whether it needs an entry.
The easiest region to describe is the null region, which is a special case described by a single word with the value EOREGREC (a constant whose name stands for E nd Of REG ion REC ord value). Describing a non-null region requires several numbers.
The first four numbers of the region description give the bounds of the region. (You may encounter certain visual objects which use region structures to describe their bounds. These regions do not contain any bounds numbers. The object's drawing bounds will be used instead.)
Next come one or more series of numbers. Each series describes a row, specifying which pixels of that row are part of the region. The only rows which need to be described are those which are different from the row below. The first number of each row description is the row number, its y coordinate. The last number of each series is a special token, EOREGREC, which lets the kernel know that the next number of the description will be the start of another row. Between the row number and EOREGREC are the column numbers where the pixels toggle on and off. The first number after the row number corresponds to the first column in which the pixel is on; the next number is the first subsequent column in which the pixel is off; and so on.
The figure below shows a simple region, along with the numbers used to define it. Those rows which are the same as the rows beneath them have no entry in this structure. Notice that rows four through seven, being the same as row eight, have no entries.
It is possible to customize a region by taking advantage of a feature of the coordinate system. Graphics routines take word-sized (16-bit) coordinate arguments. Normal coordinates only require 15 bits. When working with regions, the graphics system uses the extra bit to allow for coordinates that are described in terms of "parameters."
When you create a region you can specify coordinates as an offset from a parameter . When the region is initialized, up to four parameters may be defined. Coordinates may then be specified as 13-bit offsets from any one of these four parameters. When drawing the construct, new values may be passed for the parameters. In this way, it is possible to use a single region to describe a variety of shapes, just by changing the parameters.
Coordinates with the values shown below will be interpreted as offsets.
Thus, if a coordinate in a GString were 5000h, and the region were drawn with parameter zero equal to 72, then that drawing would take place at the coordinate 72. The coordinate 4FFFh would be interpreted as 71. Use the following constants to clarify parameterized coordinates:
/* Constants for DrawRegion */ #define PARAM_0 0x5000 #define PARAM_1 0x7000 #define PARAM_2 0x9000 #define PARAM_3 0xb000
Some or all coordinates of a region description may incorporate parameters. Note that the region code doesn't check regions for correctness. If the bounds of a region are set incorrectly, the rows are given out of order, or an incorrect (odd) number of on/off points is given for a row, the results are undefined.
Programs normally display text with UI gadgetry such as GenText, VisText, and GenGlyph objects. For those times when a geode will display text as part of a graphical display, sometimes it's best to display text using direct calls to the graphics system.
GrDrawText(), GrDrawTextAtCP(), GrDrawChar(), GrDrawCharAtCP(), GrDrawTextField()
There are several functions that display text. The
GrDrawText()
routine displays a text string. The passed
y
position, adjusted by the text mode (see below), determines the vertical position. The passed
x
position determines where the text will start printing, as normal.
GrDrawText()
draws a text string at the desired position using the GState's current text attributes. This text string should contain no carriage returns, line feeds, tabs, or other non-printing characters.
GrDrawTextAtCP()
draws a text string at the current position.
GrDrawChar()
and
GrDrawCharAtCP()
draw a single character, which should not be a non-printing character.
GrDrawTextField()
draws a field of text--however, this routine is only available in Assembly language.
GrGetTextStyle(), GrSetTextStyle(), GrGetTextMode(), GrSetTextMode(), GrGetTextSpacePad(), GrSetTextSpacePad(), GrGetFont(), GrSetFont(), GrGetTrackKern() GrSetTrackKern(), GrGetFontWeight(), GrSetFontWeight(), GrGetFontWidth(), GrSetFontWidth(), GrGetSuperscriptAttr(), GrSetSuperScriptAttr(), GrGetSubscriptAttr(), GrGetSubscriptAttr()
Applications can display text in a number of ways. Thus the GState has many attributes it keeps track of solely for drawing text.
Text style is a collective set of attributes (bold, italic, etc.) that affects how the text is drawn by the graphics system.
GrGetTextStyle()
gets the current text style,
and
GrSetTextStyle()
allows a new style to be specified. Styles are expressed as a
TextStyle
record. Note that some complicated styles which are offered by the text objects are not available here: these styles are available only from the text objects; if you wish to offer these styles without using a text object, you'll have to do the artwork yourself.
Depending on the text mode attribute, text may either be drawn from the bottom of the font box, top of the font box, baseline, or accent line.
GrGetTextMode()
gets the text mode, returning information about which offset to use when drawing text.
GrSetTextMode()
allows this information to be reset. The information is stored in a
TextMode
record. Note that if you will be drawing characters of more than one size or font, and if you want those characters to line up by baseline, you should use
GrSetTextMode()
to use the TM_DRAW_BASE text mode.
GrSetTextSpacePad()
sets the special amount used to pad space characters;
GrGetTextSpacePad()
retrieves the current space padding.
GrGetFont()
returns the current font and type size. The font is identified by its
FontID
; the default font has the ID
DEFAULT_FONT_ID and size DEFAULT_FONT_SIZE
; these are the values which new GStates will start with.
GrSetFont()
sets a new font to use. The font's point size may be between
MIN_POINT_SIZE and MAX_POINT_SIZE
.
Track kerning adjusts the space between characters. A negative kerning value means that characters will be drawn closer together. A large negative kerning value can make characters draw overlapped. A positive kerning value causes characters to draw with more space between them.
GrGetTrackKern()
returns the present track kerning value.
GrSetTrackKern()
changes this value. The kerning value must be between MIN_TRACK_KERNING
and
MAX_TRACK_KERNING; values greater than MAX_TRACK_KERNING will be replaced by MAX_TRACK_KERNING, values less that MIN_TRACK_KERNING will result in MIN_TRACK_KERNING being used. The kerning value will be multiplied as a percentage by the font size to get a number of points to use for kerning; if this multiplied value is greater than the
BBFixed
(byte-byte fixed point) number
MAX_KERN_VALUE or less than
MIN_KERN_VALUE then it will be adjusted to fall at the end of this range.
A font's weight determines its boldness. For many fonts, there will be only two weights defined: plain and bold. However, some fonts allow for finer control of weight. To find out the current font weight, call
GrGetFontWeight()
. To use a different font weight, call
GrSetFontWeight()
. Some useful weight values are stored in the
FontWeight
enumerated type. The weight should definitely be between FW_MINIMUM and FW_MAXIMUM.
To make characters draw wider or narrower, adjust the font width. Some fonts come in wide or narrow versions. If the font does not support the requested width, GEOS will simulate the width as best it can. The
GrGetFontWidth()
routine retrieves the current width;
GrSetFontWidth()
changes it. Some helpful width values are stored in the
FontWidth
enumerated type. The width should definitely be between FWI_MINIMUM and FWI_MAXIMUM.
Geodes can control how text will be drawn in superscript and subscript styles. The super- and subscript attributes determine how to scale the characters and how far they should be displaced. There are several standard super- and subscript attributes available, including values for footnote numbers, and chemical inferiors. Typesetting enthusiasts who wish to adjust the width of these characters differently than the height (as in some standard super- and sub- script layouts) should work with the font width. Use
GrGetSuperscriptAttr()
and
GrGetSubscriptAttr()
to find out what the present values are.
Use
GrSetSuperscriptAttr()
and
GrSetSubscriptAttr()
to change these values. Each of these routines works with a word sized value: the top byte is a percentage of the font size to offset sub- or superscript characters; the low byte is the percentage of font size to use for the sub- or superscript character 0x0064 (decimal 100) would be full-sized with no displacement.
GrEnumFonts(), GrCheckFontAvail(), GrFindNearestPointsize(), GrGetDefFontID(), GrGetFontName()
To find out which fonts are available in the user's environment, use the
GrEnumFonts()
command. You specify what sorts of fonts you're interested in by setting a number of flags, and the routine will fill a buffer with the available fonts with their
FontID
s and names.
The
FontEnumFlags
record determines which fonts will be returned. At least one of the FEF_OUTLINES and FEF_BITMAPS flags must be set to determine whether outline, bitmap, or both kinds of fonts should be returned.Keep in mind that only outline fonts will result in true WYSIWYG printer output. The FEF_ALPHABETIZE flag will force the returned buffer of fonts to appear in lexical order. The FEF_DOWNCASE flag requests that the font names appear all in lowercase.
The FEF_FAMILY flag asks that the search be limited to a font family. To specify what sort of family you want, use the
FontFamily
enumerated type.
GrEnumFonts()
ignores the FEF__STRING flag; other routines will use this flag to find out whether the font is specified by a
FontID
or its ASCII name.
The other flags narrow the search: if you set the FEF_FIXED_WIDTH flag, then only fixed-width fonts will be returned. If you set the FEF_USEFUL flag, only those fonts marked as "useful" will be returned.
The font information will be returned as an array of
FontEnumStruct
structures. Each of these structures will contain a
FontID
and the ASCII name of the associated font.
There may be up to MAX_FONTS available on the system. If you're not prepared to handle an array large enough to hold this many fonts, be sure to pass an argument specifying how large an array is being provided.
To find out if a given font is available in the user's environment, call either
GrCheckFontAvailID()
or
GrCheckFontAvailName()
, depending on whether the font is being identified by its
FontID
or its ASCII name. If programming in assembly language, use the
GrCheckFontAvail()
routine no matter how you're identifying the font. You may narrow the search by passing the appropriate
FontEnumFlags
. Make sure that the FEF_STRING bit is clear when searching by ID and set when searching by name.
Some fonts are available only in certain sizes and styles. Bitmap fonts are examples of this. The
GrFindNearestPointsize()
routine takes a typeface, size, and style set. It returns the closest available size and style (or returns FID_INVALID if the passed font isn't available).
To get the font which the Generic UI will use by default, call
GrGetDefFontID()
. This also returns the font size to use, useful if you wish to respect the user's choice of type size.
To find out the ASCII name of a string for which you have the
FontID
, call
GrGetFontName()
. If the font isn't available, this function will return
false
; otherwise it will fill a passed buffer with the name of the font. The passed buffer should be FID_NAME_LEN bytes long.
GrTextWidth(), GrTextWidthWWFixed(), GrTextWidthWBFixed(), GrCharWidth(), GrFontMetrics(), GrCharMetrics()
From time to time it may become important to know something about the size of a letter to be drawn. The graphics system has several routines for retrieving this information.
GrTextWidth()
returns the width, in points, of a string.
GrTextWidthWWFixed()
does the same thing, but returns a more accurate figure, including a fractional part; note that in assembly, this routine is called
GrTextWidthWBFixed()
.
GrCharWidth()
returns the width of a single character. Note that the width of a text string will normally be different than the sum of the widths of the component characters.
GrTextWidth()
takes track kerning and pairwise kerning into account.
GrFontMetrics()
returns information pertaining to a font. The meanings of these metrics are listed below: