Annotation of pmsdk/samples/vectfont/vectfont.doc, revision 1.1.1.1

1.1       root        1: 
                      2: 
                      3: 
                      4: 
                      5: 
                      6: 
                      7:             The Presentation Manager Vector Fonts
                      8:             by Charles Petzold
                      9:             
                     10:             
                     11:             
                     12:             Let's begin with a question: What graphics programming
                     13:             language stores fonts as a lines and curves (rather than
                     14:             bitmaps), and thus allows fonts to be arbitrarily stretched,
                     15:             rotated, outlined, filled with different patterns, or even
                     16:             used as clipping areas?
                     17:             
                     18:             One answer is obviously PostScript, Adobe Systems' page
                     19:             composition language implemented on many high-end laser
                     20:             printers (beginning with the Apple LaserWriter) and Allied
                     21:             Corporation's Linotronic phototypesetters. Over the past few
                     22:             years, PostScript has become the language of choice for
                     23:             computer manipulation of fonts and text.
                     24:             
                     25:             But an equally valid answer is GPI -- the Graphics
                     26:             Programming Interface component of the OS/2 Presentation
                     27:             Manager. As we'll see, GPI has facilities to do virtually
                     28:             everything with fonts that you can do with PostScript.
                     29:             
                     30:             
                     31:             The Trouble With Text
                     32:             
                     33:             The display of text is always the most problematic part of a
                     34:             graphics programming system. Unlike lines and polygons
                     35:             (which are merely mathematical constructs), text is rooted
                     36:             in a long tradition of aesthetic typography. In any computer
                     37:             graphics system, the goal must always be to display text
                     38:             that is as pleasing and as easy to read as a well-printed
                     39:             book.
                     40:             
                     41:             Yet, most computer output devices (such as video displays
                     42:             and printers) are digital media. The subtly shaped and
                     43:             rounded characters that comprise traditional fonts must be
                     44:             broken down into discrete pixels for storage and then
                     45:             reassembled on the output device. This often causes
                     46:             distortions in the appearance of the text.
                     47:             
                     48:             But one major advantage of using a computer for this job is
                     49:             versatility:  We can use a wide variety of fonts in various
                     50:             sizes and characteristics, and modify these fonts for
                     51:             display.  The extent to which we can modify fonts is
                     52:             dependent on the way in which the fonts are stored in
                     53:             memory.
                     54:             
                     55:             
                     56:             Images and Vectors
                     57:             
                     58:             A font is generally stored in computer (or printer) memory
                     59:             in one of two very different ways:
                     60:             
                     61: 
                     62: 
                     63: 
                     64: 
                     65: 
                     66: 
                     67: 
                     68: 
                     69: 
                     70: 
                     71: 
                     72: 
                     73:             First, a font can be stored as an "image" or "bitmap." Each
                     74:             character of the font is simply a rectanglar array of bits.
                     75:             The 0 bits generally correspond to the background around the
                     76:             character and the 1 bits correspond to the character itself.
                     77:             
                     78:             Secondly, a font can be stored in a "vector" or "outline"
                     79:             format. Each character is defined as a series of lines and
                     80:             curves that enclose areas. The character is displayed by
                     81:             drawing the outline on the output device and filling the
                     82:             enclosed areas.
                     83:             
                     84:             Image and vector fonts have distinct advantages and
                     85:             disadvantages. Image font are always created for specific
                     86:             font sizes and specific device resolutions. The size of a
                     87:             particular image font cannot easily be changed. (For
                     88:             example, enlarging an image font by doubling the rows and
                     89:             columns of pixels often emphasizes the jaggedness of the
                     90:             characters.) Also, image fonts cannot be rotated except
                     91:             possibly by 90 degree increments.
                     92:             
                     93:             Vector fonts are much more malleable. Because they are
                     94:             defined as a series of lines and curves, vector fonts can be
                     95:             stretched or compressed to any size and can be rotated to
                     96:             any angle. Vector fonts are not tied to a particular output
                     97:             device resolution.
                     98:             
                     99:             In general, however, image fonts are more legible that
                    100:             vector fonts. Various techniques are used to design image
                    101:             fonts so they fool the eye into thinking the characters are
                    102:             smoother than they actually are. Vector fonts --
                    103:             particularly when displayed on low resolution devices and
                    104:             scaled to small font sizes -- can be adjusted only by
                    105:             mathematical algorithms, which currently are less capable
                    106:             than human font designers. Another advantage of image fonts
                    107:             is performance:  Vector fonts usually require much more
                    108:             processing time to draw each character.
                    109:             
                    110:             Most conventional laser printers store fonts as images,
                    111:             either within the printer or in font cartridges. The printer
                    112:             is restricted to specific font sizes and the characters
                    113:             cannot be arbitrarily rotated. Much more versatile are the
                    114:             fonts stored in PostScript-based printers. These fonts are
                    115:             stored as vectors. PostScript fonts can be stretched or
                    116:             compressed to any size, they can be arbitrarily rotated,
                    117:             filled with various patterns, and used for clipping.
                    118:             
                    119:             
                    120:             The GPI Fonts
                    121:             
                    122:             The Graphics Programming Interface (GPI) of the OS/2
                    123:             Presentation Manager can, of course, take advantage of fonts
                    124:             that are stored in and supported by output devices such as
                    125:             laser printers.
                    126:             
                    127: 
                    128: 
                    129: 
                    130: 
                    131: 
                    132: 
                    133: 
                    134: 
                    135: 
                    136: 
                    137: 
                    138: 
                    139:             But GPI also includes its own support of both image and
                    140:             vector fonts. The image fonts are expected, of course,
                    141:             because they are particularly suited for low resolution
                    142:             video displays and dot matrix printers. Image fonts are an
                    143:             important part of most graphics programming systems (such as
                    144:             Microsoft Windows GDI).
                    145:             
                    146:             The addition of vector fonts in GPI is a real treat. GPI can
                    147:             use these vector fonts with any output device. Thus, various
                    148:             font techniques that previously have been restricted to
                    149:             PostScript printers are now possible with other laser
                    150:             printers and even the video display.
                    151:             
                    152:             This article shows you how to work with vector fonts in GPI
                    153:             and demonstrates many PostScript-like techniques. Quite
                    154:             simply, the font support in GPI is nearly as strong as that
                    155:             in PostScript. However, GPI has a serious deficiency that
                    156:             I'll discuss at the end of this article.
                    157:             
                    158:             OS/2 1.1 is shipped with three resource-only dyanamic link
                    159:             libraries with a .FON extension. These are font files, and
                    160:             the contents are shown in Figure 1.
                    161:             
                    162:             In addition, the video display device driver (DISPLAY.DLL)
                    163:             and printer device drivers may also contain fonts designed
                    164:             specifically for the device. For example, the default
                    165:             "System Proportional" font is stored in DISPLAY.DLL.
                    166:             
                    167:             Important: If you want to use any of the fonts in the .FON
                    168:             files, you must install the fonts from the Presentation
                    169:             Manager Control Panel program. It is only necessary to
                    170:             install one font from each of the three files, and you only
                    171:             need do this once.
                    172:             
                    173:             Each font has a face name. This is shown in quotation marks
                    174:             in Figure 1.  Each of the image fonts is available in
                    175:             several point sizes and for several output devices: the CGA,
                    176:             EGA, VGA (and 8514/A), and IBM Proprinter. GPI can syntesize
                    177:             variations of these fonts, such as italic or boldfaced
                    178:             versions.
                    179:             
                    180:             Vector fonts, however, need not be designed for a particular
                    181:             output device and point size because they can be arbitrary
                    182:             scaled. You'll note that italic and boldface versions of the
                    183:             vector fonts are also included.
                    184:             
                    185:             The vector fonts in GPI are equivalent to the Courier,
                    186:             Helvetica, and Times fonts included in most PostScript
                    187:             printers. However, because Helvetica and Times are
                    188:             registered trademarks, these names are not used to identify
                    189:             the vector fonts in GPI.
                    190:             
                    191:             A little exploration of the font files will reveal that
                    192:             vector fonts are encoded as a series of GPI drawing orders.
                    193: 
                    194: 
                    195: 
                    196: 
                    197: 
                    198: 
                    199: 
                    200: 
                    201: 
                    202: 
                    203: 
                    204: 
                    205:             When drawing text with these fonts, GPI translates the
                    206:             drawing orders into GPI functions, usually GpiPolyLine to
                    207:             draw straight lines and GpiPolyFilletSharp to draw curves.
                    208:             
                    209:             
                    210:             The VECTFONT Program
                    211:             
                    212:             The VECTFONT program demonstrates the use GPI vector fonts.
                    213:             For purposes of clarity, I've divided the program into
                    214:             several modules.
                    215:             
                    216:             The VECTFONT "Display" menu lists 16 options. The first
                    217:             option (to display nothing) is the default. The other 15
                    218:             options correspond to routines in the VF01.C through VF15.C
                    219:             files (described below).  The VF00.C file contains some
                    220:             "helper" functions used by the routines in VF01.C through
                    221:             VF15.C.
                    222:             
                    223:             VECTFONT creates a micro presentation space during the
                    224:             WM_CREATE message using page units of PU_TWIPS. ("Twips" is
                    225:             fabricated word standing for "20th of a point." A printer's
                    226:             point size is 1/72nd inch, so page units correspond to
                    227:             1/1440 inch.) VECTFONT then modifies the page viewport
                    228:             rectangle so that a page unit corresponds to 1 point, which
                    229:             (as you may know) is the default coordinate system in
                    230:             PostScript.
                    231:             
                    232:             Although VECTFONT displays output to the screen, vector
                    233:             fonts are obviously more suited for laser printers. As you
                    234:             will see, the appearance of the fonts -- even at 24 point
                    235:             sizes -- is not nearly as good as the image fonts.
                    236:             
                    237:             You'll also notice that several of the demonstration
                    238:             routines in VECTFONT requires a few seconds to run. For
                    239:             anything other than a demonstration program, you'd probably
                    240:             want to use a second thread of execution so as to not hold
                    241:             up message processing.
                    242:             
                    243:             
                    244:             Selecting an Outline Font
                    245:             
                    246:             To use an outline font in a Presentation Manager program,
                    247:             you must first create a "logical font" and then select the
                    248:             font into your presentation space.
                    249:             
                    250:             The GpiCreateLogFont function creates a logical font and
                    251:             associates the font with a local ID (a number between 1L and
                    252:             254L that you select). This function requires a pointer to a
                    253:             structure of type FATTRS ("font attributes") that specifies
                    254:             the attributes of the font you want.
                    255:             
                    256:             To create a vector font, most of the fields in this
                    257:             structure can be set to zero. The most important fields are
                    258:             szFacename (which is set to the face name of the font) and
                    259: 
                    260: 
                    261: 
                    262: 
                    263: 
                    264: 
                    265: 
                    266: 
                    267: 
                    268: 
                    269: 
                    270: 
                    271:             fsFontUse, which is set to the constant identifiers
                    272:             FATTR_FONTUSE_OUTLINE and FATTR_FONTUSE_TRANSFORMABLE,
                    273:             combined with the C bitwise OR operator.
                    274:             
                    275:             You may prefer using the CreateVectorFont function in VF00.C
                    276:             for creating a vector font. The VF00.C file contains several
                    277:             other helpful functions that are used by the demonstration
                    278:             routines in VF01.C through VF15.C.
                    279:             
                    280:             The CreateVectorFont function requires only the presentation
                    281:             space handle, the local ID, and the face name:
                    282:             
                    283:             
                    284:             CreateVectorFont(hps, lcid,
                    285:                              szFacename);
                    286:             
                    287:             
                    288:             After you create a logical font (using either
                    289:             GpiCreateLogFont or CreateVectorFont), you can select the
                    290:             font into the presentation space:
                    291:             
                    292:             
                    293:             GpiSetCharSet(hps, lcid);
                    294:             
                    295:             
                    296:             The lcid parameter is the local ID for the font. After the
                    297:             font is selected in the presentation space, you can alter
                    298:             the attributes of the font with various functions described
                    299:             below, obtain information about the font by calling
                    300:             GpiQueryFontMetrics, GpiQueryWidthTable, and
                    301:             GpiQueryTextBox, and you can use the font for text output
                    302:             with one of the text functions such as GpiCharStringAt.
                    303:             
                    304: 
                    305: 
                    306: 
                    307: 
                    308: 
                    309: 
                    310: 
                    311: 
                    312: 
                    313: 
                    314: 
                    315: 
                    316: 
                    317: 
                    318: 
                    319: 
                    320: 
                    321: 
                    322: 
                    323: 
                    324: 
                    325: 
                    326: 
                    327: 
                    328: 
                    329: 
                    330: 
                    331: 
                    332: 
                    333: 
                    334: 
                    335: 
                    336: 
                    337:             When you no longer need the font, you select the default
                    338:             font back into the presentation space:
                    339:             
                    340:             
                    341:             GpiSetCharSet(
                    342:                   hps,
                    343:                   LCID_DEFAULT);
                    344:             
                    345:             
                    346:             and then delete the local ID associated with the font:
                    347:             
                    348:             
                    349:             GpiDeleteSetId(hps, lcid);
                    350:             
                    351:             
                    352:             In VECTFONT, I always use the identifier LCID_MYFONT for the
                    353:             local ID. This is defined in VECTFONT.H as 1L.
                    354:             
                    355:             
                    356:             Scaling to a Point Size
                    357:             
                    358:             When you call GpiSetCharSet to select a vector font into the
                    359:             prsentation space, the initial width and height of the font
                    360:             are based on the GPI "character box," which defines a
                    361:             character width and height in page units. The default
                    362:             character box is based on the size of the default system
                    363:             font. You can change the character box size by calling
                    364:             GpiSetCharBox.
                    365:             
                    366:             Very important: To get a correctly proportioned vector font,
                    367:             it is necessary to change the character box size. Do not use
                    368:             the default Generally you set the height of the character
                    369:             box to the desired height of the font. If you want the a
                    370:             vector font to have a normal width, you set the width of the
                    371:             character box equal to the height. For a skinnier font, set
                    372:             the width of the character box less than the height; for a
                    373:             fatter font, set the width greater than the height.
                    374:             
                    375:             If you're working in page units of PU_PELS, you must also
                    376:             adjust the character box dimensions to account for
                    377:             differences in horizontal and vertical resolution of the
                    378:             output device. For this reason, it's much easier to work
                    379:             with vector fonts if you use one of the metric page units
                    380:             (PU_LOENGLISH, PU_HIENGLISH, PU_LOMETRIC, PU_HIMETRIC, or
                    381:             PU_TWIPS). With these page units, horizontal and vertical
                    382:             page units are the same.
                    383:             
                    384:             For example, suppose you're using page units of PU_TWIPS.
                    385:             This means that one page unit is equal to 1/20 of a point or
                    386:             1/1440 inch.  After selecting a vector font into the
                    387:             presentation space, you want to scale the font to 24 points.
                    388:             You first define a structure of type SIZEF:
                    389:             
                    390:             
                    391: 
                    392: 
                    393: 
                    394: 
                    395: 
                    396: 
                    397: 
                    398: 
                    399: 
                    400: 
                    401: 
                    402: 
                    403:             SIZEF sizfx;
                    404:             
                    405:             
                    406:             The two fields of this structure are named cx and cy and are
                    407:             interpreted as 32-bit FIXED numbers, that is, the high 16-
                    408:             bits are interpreted as an integer, and the low 16-bits are
                    409:             interpreted as a fraction.
                    410:             
                    411:             If you want to scale the vector font to a 24 point height,
                    412:             you can use the MAKEFIXED macro to set to the fields of the
                    413:             structure like this:
                    414:             
                    415:             
                    416:             sizfx.cx = MAKEFIXED(
                    417:                          24 * 20, 0);
                    418:             sizfx.cy = MAKEFIXED(
                    419:                          24 * 20, 0);
                    420:             
                    421:             
                    422:             Multiplying by 20 is necessary to convert the point size you
                    423:             want to twips. Then call GpiSetCharBox:
                    424:             
                    425:             
                    426:             GpiSetCharBox(hps, &sizfx);
                    427:             
                    428:             
                    429:             After setting the character box, any character or text
                    430:             dimensions you obtain from GpiQueryFontMetrics,
                    431:             GpiQueryTextBox, and GpiQueryWidthTable will reflect the new
                    432:             font size.
                    433:             
                    434:             The ScaleVectorFont routine in VF00.C can help in scaling a
                    435:             vector font to a desired point size. The function will work
                    436:             with any page units, even PU_PELS. The second and third
                    437:             parameters to ScaleVectorFont specify a point size in units
                    438:             of 0.1 points. (For example, use 240 for a 24-point size.)
                    439:             If you want a normally proportioned vector font, set the
                    440:             third parameter to ScaleVectorFont equal to the second
                    441:             parameter.
                    442:             
                    443:             The VF01.C file shows how the functions discussed so far can
                    444:             be used to display all the available vector fonts in 24
                    445:             point sizes. You can run the function in VF01.C by selecting
                    446:             the "24 Point Fonts" option from the VECTFONT "Display"
                    447:             menu.
                    448:             
                    449:             
                    450:             Arbitrary Stretching
                    451:             
                    452:             Besides scaling the vector font to a specific point size,
                    453:             you can also scale vector fonts to fit within an arbitrary
                    454:             rectangle. For example, you may want to scale a short text
                    455:             string to fill the client window.
                    456:             
                    457: 
                    458: 
                    459: 
                    460: 
                    461: 
                    462: 
                    463: 
                    464: 
                    465: 
                    466: 
                    467: 
                    468: 
                    469:             The function shown in VF02.C shows how this is done. You can
                    470:             run this function by selecting "Stretched Font" from
                    471:             VECTFONT's menu. The function in VF02.C displays the word
                    472:             "Hello!" in the "Tms Rmn Italic" font stretched to the size
                    473:             of the client window.
                    474:             
                    475:             The ScaleFontToBox function in VF00.C helps out with this
                    476:             job. This function first calls GpiQueryTextBox to obtain the
                    477:             coordinates of a parallelogram that encompasses the text
                    478:             string. The character box is then scaled based on the size
                    479:             of this text box and the rectangle to which the font must be
                    480:             stretched. The QueryStartPointInTextBox function in VF00.C
                    481:             determines the starting point of the text string (that is,
                    482:             the point at the baseline of the left side of the first
                    483:             character) within this rectangle. This point is used in the
                    484:             GpiCharStringAt function to display the text.
                    485:             
                    486:             
                    487:             Mirror Images
                    488:             
                    489:             Besides scaling the font to a particular size, the character
                    490:             box can also flip the characters around the horizontal or
                    491:             vertical axis.
                    492:             
                    493:             If the character box height (the cy field of the SIZEF
                    494:             structure) is negative, then the characters will be flipped
                    495:             around the baseline and displayed upside down. If the
                    496:             character box width (the cx field) is negative, the
                    497:             individual characters are flipped around the vertical axis.
                    498:             Moreover, GpiCharStringAt will draw a character string from
                    499:             right to left. It's as if the whole character string is
                    500:             flipped around the vertical line at the left side of the
                    501:             first character.
                    502:             
                    503:             The function in VF03.C displays the same string four times,
                    504:             using all possible combinations of negative and positive
                    505:             character box dimensions. You can run this function by
                    506:             selecting "Mirrored Font" from the VECTFONT menu.
                    507:             
                    508:             
                    509:             Vector Fonts and Transformations
                    510:             
                    511:             Unlike image fonts, vector fonts can be scaled to any size
                    512:             and sheared and rotated to any angle. The matrix transforms
                    513:             described in my article "OS/2 Graphics Programming
                    514:             Interface: An Introduction to Coordinate Spaces" (Microsoft
                    515:             Systems Journal, Volume 3, Number 4) affect vector fonts in
                    516:             the same way they affect the display of other graphics
                    517:             primitives.
                    518:             
                    519:             In addition, GPI also supports several functions
                    520:             specifically for performing transforms on vector fonts.
                    521:             We've already seen how the GpiSetCharBox function allows
                    522:             font characters to be scaled. The GpiSetCharAngle rotates
                    523: 
                    524: 
                    525: 
                    526: 
                    527: 
                    528: 
                    529: 
                    530: 
                    531: 
                    532: 
                    533: 
                    534: 
                    535:             the font characters and the GpiSetCharShear performs x-
                    536:             shear.
                    537:             
                    538:             
                    539:             Character Angle and Rotation
                    540:             
                    541:             By default, the baseline of the vector font characters is
                    542:             parallel to the x axis in world coordinates. You can change
                    543:             this by calling GpiSetCharAngle. This rotates the vector
                    544:             fonts characters.
                    545:             
                    546:             The character angle is specified using a GRADIENTL
                    547:             structure, which has two fields named x and y of type LONG.
                    548:             Imagine a line connecting the point (0,0) to the point (x,y)
                    549:             in world coordinates. The baseline of each character is
                    550:             parallel to this line. The direction of the text is the same
                    551:             as the direction from (0,0) to (x,y).
                    552:             
                    553: 
                    554: 
                    555: 
                    556: 
                    557: 
                    558: 
                    559: 
                    560: 
                    561: 
                    562: 
                    563: 
                    564: 
                    565: 
                    566: 
                    567: 
                    568: 
                    569: 
                    570: 
                    571: 
                    572: 
                    573: 
                    574: 
                    575: 
                    576: 
                    577: 
                    578: 
                    579: 
                    580: 
                    581: 
                    582: 
                    583: 
                    584: 
                    585: 
                    586: 
                    587: 
                    588: 
                    589: 
                    590: 
                    591: 
                    592: 
                    593: 
                    594: 
                    595: 
                    596: 
                    597: 
                    598: 
                    599: 
                    600: 
                    601:             You can also think of this in trigonometric terms. The
                    602:             baseline of the text is parallel to a line at angle a
                    603:             measured counterclockwise from the x-axis, where:
                    604:             
                    605:             
                    606:             a = arctan (y/x)
                    607:             
                    608:             
                    609:             and y and x are the two fields of the GRADIENTL structure.
                    610:             
                    611:             
                    612:             
                    613:             The absolute magnitudes of y and x are not important. What's
                    614:             important are the relative magnitudes and signs. The signs
                    615:             of x and y determine the direction of the text string as
                    616:             indicated in the following table:
                    617:             
                    618:             
                    619:             x    y    Direction
                    620:             -    -    ---------
                    621:             
                    622:             +    +    To upper right
                    623:             -    +    To upper left
                    624:             -    -    To lower left
                    625:             +    -    To lower right
                    626:             
                    627:             
                    628:             The function in VF04.C uses the GpiSetCharAngle function to
                    629:             display eight text strings at 45 degree increments around
                    630:             the center of the client window. Each string displays the
                    631:             fields of the GRADIENTL structure that is used in the
                    632:             GpiSetCharAngle call.
                    633:             
                    634:             In this example, the text strings begin with a blank
                    635:             character so as not to make a mess of overlapping characters
                    636:             in the center of the client window. The character angle does
                    637:             not affect the interpretation of the starting position of
                    638:             the string specified in the GpiCharStringAt function. If you
                    639:             move your head so that a particular string is seen as
                    640:             running left to right, the starting position still refers to
                    641:             the point at the baseline of the left side of the first
                    642:             character.
                    643:             
                    644:             You can make the characters in a text string follow a curved
                    645:             path by individually calculating the starting position an
                    646:             angle of each character and displaying the characters one at
                    647:             a time. This is what is done in VF05.C to display "Hello,
                    648:             world!" around the perimeter of a circle.
                    649:             
                    650:             The text string is scaled based on the circumference of a
                    651:             circle that is positioned in the center of the window and
                    652:             has a diameter half the width or height (whichever is less)
                    653:             of the window. The GpiQueryWidthTable function is used to
                    654: 
                    655: 
                    656: 
                    657: 
                    658: 
                    659: 
                    660: 
                    661: 
                    662: 
                    663: 
                    664: 
                    665: 
                    666: 
                    667:             obtain the width of individual characters and then space
                    668:             them around the circle.
                    669:             
                    670:             
                    671:             Character Shear
                    672:             
                    673:             It is easy to confuse the character angle and character
                    674:             shear. Lets look at the difference. The character angle
                    675:             refers to the orientation of the baseline. Text displayed
                    676:             with various character angles is rotated but otherwise not
                    677:             distorted in any way.
                    678:             
                    679:             The character shear affects the appearance of the characters
                    680:             themselves apart from any rotation. Character shear by
                    681:             itself "bends" characters to the left or right, but the
                    682:             bottom of each character remains parallel to the x-axis. You
                    683:             can use character shear to create oblique (sometimes
                    684:             mistakenly called italic) versions of a font.
                    685:             
                    686:             To set character shear you call the GpiSetCharShear
                    687:             function. This function requires a pointer to a structure of
                    688:             type POINTL, which has two fields named x and y. Imagine a
                    689:             line drawn from (0,0) to the point (x,y) in world
                    690:             coordinates. The left and right sides of each character are
                    691:             parallel to this line.
                    692:             
                    693:             The function shown in in VF06.C displays seven text strings
                    694:             using different character shears.
                    695:             
                    696:             You can run this function by selecting "Character Shear"
                    697:             from the VECTFONT menu. Each string displays the x and y
                    698:             values used in the POINTL structure to set the character
                    699:             shear.
                    700:             
                    701:             The character shear is governed by the relative magnitudes
                    702:             and signs of the x and y fields of the POINTL structure. If
                    703:             the signs of both fields are the same, the characters tilt
                    704:             to the right; if different, the characters tilt to the left.
                    705:             The character shear does not cause characters to be flipped
                    706:             upside down. For example, character shear using the point
                    707:             (100,100) has the same effect as (-100,-100).
                    708:             
                    709:             The angle of the left and right sides of the characters from
                    710:             the y axis is sometimes called the shear angle. In theory,
                    711:             the shear angle can range to just above -180 degrees
                    712:             (infinite left shear) to just under +180 degrees (infinite
                    713:             right shear) and is equal to:
                    714:             
                    715:             
                    716:             a = arctan (x/y)
                    717:             
                    718:             
                    719:             where x and y are the two fields of the POINTL structure.
                    720:             
                    721: 
                    722: 
                    723: 
                    724: 
                    725: 
                    726: 
                    727: 
                    728: 
                    729: 
                    730: 
                    731: 
                    732: 
                    733:             When you set a non-default character shear, the
                    734:             GpiQueryTextBox function returns an array of points that
                    735:             define a parallelogram rather than a rectangle. However, the
                    736:             top and bottom sides of this text box are the same width as
                    737:             for a non-sheared text string, and the distance between the
                    738:             top and bottom sides also remains the same.
                    739:             
                    740:             You can use character shear to draw an oblique shadow of a
                    741:             text string. The function in VF07.C colors the background of
                    742:             the client window blue, and displays the text string
                    743:             "Shadow" twice.
                    744:             
                    745:             The first call to GpiCharStringAt displays the shadow. This
                    746:             is drawn in dark blue using a positive character shear. The
                    747:             second call to GpiCharStringAt draws the characters upright
                    748:             in red with a slightly smaller character box height. You can
                    749:             run this function by selecting "Font with Shadow" from the
                    750:             VECTFONT menu.
                    751:             
                    752:             
                    753:             A Primer on Paths
                    754:             
                    755:             To explore more capabilities of vector fonts, it's necessary
                    756:             to become familiar with the GPI "path," which is similar to
                    757:             a PostScript path. In GPI, you create a path by calling line
                    758:             drawing functions between calls to the GpiBeginPath and
                    759:             GpiEndPath functions:
                    760:             
                    761:             
                    762:             GpiBeginPath(hps, idPath);
                    763:                  <... call line
                    764:                       drawing
                    765:                       functions ... >
                    766:             GpiEndPath (hps) ;
                    767:             
                    768:             
                    769:             This is called a "path bracket." In OS/2 1.1, idPath must be
                    770:             set equal to 1L. The functions that are valid within a path
                    771:             bracket are listed in the documentation of the Presentation
                    772:             Manager functions.
                    773:             
                    774:             The functions you call within the path bracket do not draw
                    775:             anything. Instead, the lines that make up the path are
                    776:             retained by the system. Often the lines you draw in a path
                    777:             will enclose areas, but they don't have to.
                    778:             
                    779:             After the GpiEndPath call, you can do one of three things
                    780:             with the path you've created:
                    781:             
                    782:                  *    Call GpiStrokePath to draw the lines that comprise
                    783:                       the path. These lines are drawn using the
                    784:                       geometric line width, joins, and ends (discussed
                    785:                       shortly).
                    786:             
                    787: 
                    788: 
                    789: 
                    790: 
                    791: 
                    792: 
                    793: 
                    794: 
                    795: 
                    796: 
                    797: 
                    798: 
                    799:                  *    Call GpiFillPath to fill enclosed areas defined by
                    800:                       the path. Any open areas are automatically
                    801:                       closed. The area is filled with the current
                    802:                       pattern.
                    803:             
                    804:                  *    Call GpiSetClipPath to make the enclosed areas of
                    805:                       the path a clipping area. Any open areas are
                    806:                       automatically closed. Subsequent GPI calls will
                    807:                       only display output within the enclosed area
                    808:                       defined by the path.
                    809:             
                    810:             Each of these three functions cause the path to be deleted.
                    811:             Prior to calling any of these three functions you can call
                    812:             GpiModifyPath, which I'll describe towards the end of this
                    813:             article.
                    814:             
                    815:             Normally, GpiCharStringAt and the other text output
                    816:             functions are not valid in a path bracket. The exception is
                    817:             when a vector font is selected in the presentation space.
                    818:             When called from within a path bracket, GpiCharStringAt does
                    819:             not draw the text string. Instead, the outlines of the
                    820:             characters become part of the path.
                    821:             
                    822:             This facility opens up a whole collection of PostScript-like
                    823:             stylistic techniques that you can use with vector fonts.
                    824:             
                    825:             
                    826:             Hollow Characters
                    827:             
                    828:             Let's begin by calling GpiCharStringAt in a path bracket and
                    829:             then use GpiStrokePath to draw the lines of the path.
                    830:             GpiStrokePath has the following syntax:
                    831:             
                    832:             
                    833:             GpiStrokePath(
                    834:                  hps, idPath, 0L);
                    835:             
                    836:             
                    837:             In the initial version of the Presentation Manager, the last
                    838:             parameter of the function must be set to 0L. When used to
                    839:             stroke a path created by calling GpiCharStringAt, only the
                    840:             outline is drawn and not the interiors. This creates hollow
                    841:             characters.
                    842:             
                    843:             The function in VF08.C uses this technique to display the
                    844:             outline of the characters in the text string "Hollow." You
                    845:             can run this function by selecting "Hollow Font" from the
                    846:             VECTFONT menu.
                    847:             
                    848:             You may want to display characters in one color with an
                    849:             outline of another color. In this case, you must call
                    850:             GpiCharStringAt twice, first to draw the interior in a
                    851:             specific color, and secondly in a path bracket followed by a
                    852:             GpiStrokeFont call to draw the outline.
                    853: 
                    854: 
                    855: 
                    856: 
                    857: 
                    858: 
                    859: 
                    860: 
                    861: 
                    862: 
                    863: 
                    864: 
                    865:             
                    866:             The function in VF09.C does something like this to draw text
                    867:             with a drop shadow.
                    868:             
                    869:             The shadow is drawn first using a normal GpiCharStringAt
                    870:             call. Another GpiCharStringAt functions draws the text again
                    871:             in the current window background color at a 1/6 inch offset
                    872:             to the first string. This is surrounded by an outline
                    873:             created by a third GpiCharStringAt call in a path bracket
                    874:             followed by GpiStrokeFont.
                    875:             
                    876:             Quite similar to this is the creation of characters that
                    877:             look like solid blocks, as shown in the function in VF10.C.
                    878:             Eighteen character strings are drawn at 1 point offsets
                    879:             using CLR_DARKGREEN. This is capped by the character string
                    880:             drawn again in CLR_GREEN and the border in CLR_DARKGREEN.
                    881:             
                    882:             
                    883: 
                    884: 
                    885: 
                    886: 
                    887: 
                    888: 
                    889: 
                    890: 
                    891: 
                    892: 
                    893: 
                    894: 
                    895: 
                    896: 
                    897: 
                    898: 
                    899: 
                    900: 
                    901: 
                    902: 
                    903: 
                    904: 
                    905: 
                    906: 
                    907: 
                    908: 
                    909: 
                    910: 
                    911: 
                    912: 
                    913: 
                    914: 
                    915: 
                    916: 
                    917: 
                    918: 
                    919: 
                    920: 
                    921: 
                    922: 
                    923: 
                    924: 
                    925: 
                    926: 
                    927: 
                    928: 
                    929: 
                    930: 
                    931:             Geometrically Thick Lines
                    932:             
                    933:             At first, it may seem as if there is no difference between
                    934:             drawing a line normally, like this:
                    935:             
                    936:             
                    937:             GpiMove(hps, &ptlBeg);
                    938:             GpiLine(hps, &ptlEnd);
                    939:             
                    940:             
                    941:             and calling these same two functions within a path bracket
                    942:             and then stroking the path, like this:
                    943:             
                    944:             
                    945:             GpiBeginPath(hps, idPath);
                    946:             GpiMove(hps, &ptlBeg);
                    947:             GpiLine(hps, &ptlEnd);
                    948:             GpiEndPath(hps)
                    949:             GpiStrokePath(hps, idPath, 0);
                    950:             
                    951:             
                    952:             There are, in fact, some very significant differences.
                    953:             
                    954:             First, the line drawn with the normal GpiLine function has
                    955:             what is called a "cosmetic" line width. The default width of
                    956:             the line is based on the resolution of the output device. It
                    957:             is a device dependent width for a "normal" line. The width
                    958:             of the line does not change when you use matrix transforms
                    959:             to set different scaling factors in the coordinate space.
                    960:             Although GPI provides a function called GpiSetLineWidth to
                    961:             change the cosmetic line width, this function is not
                    962:             implemented in OS/2 1.1.
                    963:             
                    964:             But a line drawn by stroking a path has a "geometric" line
                    965:             width. This is a line width (in world coordinates) that you
                    966:             set with the GpiSetLineWidthGeom function. Because this line
                    967:             width is specified in world coordinates, it is affected by
                    968:             any scaling that you set using matrix transforms.
                    969:             
                    970:             Secondly, a line draw with GpiLine can have different line
                    971:             types that you set with the GpiSetLineType function. These
                    972:             line types are various combinations of dots and dashes. The
                    973:             line is drawn with the current line color and the current
                    974:             line mix.
                    975:             
                    976:             But a line drawn by stroking a path does not use the line
                    977:             type. The line is instead treated as an area that follows
                    978:             the path of the line but which has a geometric width. This
                    979:             area is filled with the pattern that you set with
                    980:             GpiSetPattern, colored with the current pattern foreground
                    981:             and background color, and the current pattern foreground and
                    982:             background mix.
                    983:             
                    984: 
                    985: 
                    986: 
                    987: 
                    988: 
                    989: 
                    990: 
                    991: 
                    992: 
                    993: 
                    994: 
                    995: 
                    996: 
                    997:             Third, a line drawn by stroking the path can have various
                    998:             types of line "joins" and "ends." By calling GpiSetLineJoin
                    999:             you can specify that lines meet with a rounded, square, or
                   1000:             miter join. GpiSetLineEnd lets you specify rounded, square,
                   1001:             or flat ends to the lines.
                   1002:             
                   1003:             The function in the VF11.C file demonstrates the use of
                   1004:             geometrically thick lines filled with patterns to give the
                   1005:             letters a kind of "neon" look.
                   1006:             
                   1007:             You can run this function by selecting "Neon Effect" from
                   1008:             the VECTFONT menu. The function strokes the path using
                   1009:             various geometric line widths filled with a PATSYM_HALFTONE
                   1010:             pattern and several colors. The outline of the font is
                   1011:             white, but surrounded with a halo of red.
                   1012:             
                   1013:             A better effect could be achieved on devices capable of more
                   1014:             than 16 colors. In this case, you can use a solid pattern
                   1015:             but color each stroke with a different shade of red.
                   1016:             
                   1017:             
                   1018:             Filling the Path
                   1019:             
                   1020:             When introducing paths earlier in this article, I mentioned
                   1021:             that you can do one of three things with a path: stroke it,
                   1022:             fill it, or use it for clipping. Let's move on to the
                   1023:             second: filling the path.
                   1024:             
                   1025:             To fill a path, you call:
                   1026:             
                   1027:             
                   1028:             GpiFillPath(hps,
                   1029:                  idPath, lOption);
                   1030:             
                   1031:             
                   1032:             This fills the path with the current pattern. Any open areas
                   1033:             of the path are automatically closed before being filled.
                   1034:             The lOption parameter can be either FPATH_ALTERNATE or
                   1035:             FPATH_WINDING to fill the path using alternate or winding
                   1036:             modes. For vector fonts, FPATH_WINDING causes the interiors
                   1037:             of some letters (such as "O") to be filled. You'll probably
                   1038:             want to use FPATH_ALTERNATE instead.
                   1039:             
                   1040:             If the current area filling pattern is PATSYM_SOLID, then
                   1041:             the code:
                   1042:             
                   1043:             
                   1044:             GpiBeginPath(hps, idPath);
                   1045:             GpiCharStringAt(hps, &ptl,
                   1046:                             cch, szText);
                   1047:             GpiEndPath(hps);
                   1048:             GpiFillPath(hps,
                   1049:                         idPath,
                   1050:                         FPATH_ALTERNATE);
                   1051: 
                   1052: 
                   1053: 
                   1054: 
                   1055: 
                   1056: 
                   1057: 
                   1058: 
                   1059: 
                   1060: 
                   1061: 
                   1062: 
                   1063:             
                   1064:             
                   1065:             does roughly the same thing with a vector font as a
                   1066:             GpiCharStringAt by itself. When using GpiFillPath you'll
                   1067:             want to set a pattern other than PATSYM_SOLID. (A bug in
                   1068:             OS/2 1.1 causes the current pattern to be reset to
                   1069:             PATSYM_SOLID during a path bracket in which GpiCharStringAt
                   1070:             is called. You can get around this bug by calling
                   1071:             GpiSetPattern after you end the path.)
                   1072:             
                   1073:             The function in VF12.C uses GpiFillPath to display the text
                   1074:             string "Fade" eight times filled with the eight GPI shading
                   1075:             patterns (PATSYM_DENSE1 through PATSYM_DENSE8) and then
                   1076:             finishes by calling GpiCharStringAt outside of a path
                   1077:             bracket. You can run this function by selecting "Fading
                   1078:             Font" from the VECTFONT menu.
                   1079:             
                   1080:             
                   1081:             Clipping to the Text Characters
                   1082:             
                   1083:             The third option after creating a path is to call
                   1084:             GpiSetClipPath:
                   1085:             
                   1086:             
                   1087:             GpiSetClipPath(hps, idPath,
                   1088:                            lOption);
                   1089:             
                   1090:             The lOption parameter can be either SCP_RESET (which equals
                   1091:             0L, so it's the default) or SCP_AND. The SCP_RESET option
                   1092:             causes the clipping path to be reset so that no clipping
                   1093:             occurs. The SCP_AND option sets the new clipping path to the
                   1094:             intersection of the old clipping path and the path you've
                   1095:             just defined in a path bracket. Any open areas in the path
                   1096:             are automatically closed.
                   1097:             
                   1098:             You can combine the SCP_AND option with either SCP_ALTERNATE
                   1099:             (the default) or SCP_WINDING. As with GpiFillPath, you'll
                   1100:             probably want to use alternate mode when working with paths
                   1101:             created from vector fonts
                   1102:             
                   1103:             The function in VF13.C calls GpiCharStringAt with the text
                   1104:             string "WOW" within a path bracket. This is followed by a
                   1105:             call to GpiSetClipPath. The clipping path is now the
                   1106:             interior of the letters. The function draws a series of
                   1107:             colored lines emanating from the center of the client
                   1108:             window.
                   1109:             
                   1110:             The function in VF14.C uses a similar technique but draws a
                   1111:             series of areas defined by splines.
                   1112:             
                   1113:             
                   1114:             Modifying the Path
                   1115:             
                   1116: 
                   1117: 
                   1118: 
                   1119: 
                   1120: 
                   1121: 
                   1122: 
                   1123: 
                   1124: 
                   1125: 
                   1126: 
                   1127: 
                   1128: 
                   1129:             Between the call to GpiEndPath to end the path and the call
                   1130:             to GpiStrokePath, GpiFillPath, or GpiSetClipPath, you can
                   1131:             call GpiModifyPath. This function uses the current geometric
                   1132:             line width, line join, and line end to convert every line in
                   1133:             the path to a new line that encloses an area around the old
                   1134:             line.
                   1135:             
                   1136:             For example, suppose that the path contained a single
                   1137:             straight line. After GpiModifyPath the path would contain a
                   1138:             closed line in the shape of a hotdog. The width of this
                   1139:             hotdog is the geometric line width. The ends of the hotdog
                   1140:             could be round, square, or flat, depending on the current
                   1141:             line end attribute.
                   1142:             
                   1143: 
                   1144: 
                   1145: 
                   1146: 
                   1147: 
                   1148: 
                   1149: 
                   1150: 
                   1151: 
                   1152: 
                   1153: 
                   1154: 
                   1155: 
                   1156: 
                   1157: 
                   1158: 
                   1159: 
                   1160: 
                   1161: 
                   1162: 
                   1163: 
                   1164: 
                   1165: 
                   1166: 
                   1167: 
                   1168: 
                   1169: 
                   1170: 
                   1171: 
                   1172: 
                   1173: 
                   1174: 
                   1175: 
                   1176: 
                   1177: 
                   1178: 
                   1179: 
                   1180: 
                   1181: 
                   1182: 
                   1183: 
                   1184: 
                   1185: 
                   1186: 
                   1187: 
                   1188: 
                   1189: 
                   1190: 
                   1191: 
                   1192: 
                   1193: 
                   1194: 
                   1195:             Following the creation of a path, these two functions in
                   1196:             succession:
                   1197:             
                   1198:             
                   1199:             GpiModifyPath(hps, ID_PATH,
                   1200:                           MPATH_STROKE);
                   1201:             GpiFillPath(hps, ID_PATH,
                   1202:                         FPATH_WINDING) ;
                   1203:             
                   1204:             
                   1205:             is usually equivalent to:
                   1206:             
                   1207:             
                   1208:             GpiStrokePath(hps, ID_PATH,
                   1209:                           0L);
                   1210:             
                   1211:             
                   1212:             GpiModifyPath and GpiStrokePath are the only two functions
                   1213:             that use the geometric line width, joins, and ends.
                   1214:             
                   1215:             In theory, you can call GpiStrokePath after GpiModifyPath,
                   1216:             like this:
                   1217:             
                   1218:             
                   1219:             GpiModifyPath(hps, ID_PATH,
                   1220:                           MPATH_STROKE);
                   1221:             GpiStrokePath(hps, ID_PATH,
                   1222:                           0L);
                   1223:             
                   1224:             
                   1225:             This should do something, and it should be rather
                   1226:             interesting, but GPI usually reports that it can't create
                   1227:             the path because it's too complex.
                   1228:             
                   1229:             Instead, let's look at GpiModifyPath followed by
                   1230:             GpiSetClipPath. The function in VF15.C is almost the same as
                   1231:             the one in VF13.C except that it sets the geometric line
                   1232:             width to 6 (1/12 inch) and calls GpiModifyPath before
                   1233:             calling GpiSetClipPath.
                   1234:             
                   1235:             Note that the colored lines are clipped not to the interior
                   1236:             of the characters, but to their original outlines. By the
                   1237:             use of GpiModifyPath, the outlines of the characters have
                   1238:             themselves been made into a path that is 1/12 inch wide.
                   1239:             This is the path that is used for clipping.
                   1240:             
                   1241:             
                   1242:             Is It Enough?
                   1243:             
                   1244:             I think it's clear that the facilities provided by GPI for
                   1245:             working with vector fonts equal -- and sometimes exceed --
                   1246:             those in PostScript. The GPI interface is very powerful and
                   1247:             very versatile.
                   1248:             
                   1249: 
                   1250: 
                   1251: 
                   1252: 
                   1253: 
                   1254: 
                   1255: 
                   1256: 
                   1257: 
                   1258: 
                   1259: 
                   1260: 
                   1261:             Is that enough?
                   1262:             
                   1263:             No, it's not. The implementation of vector fonts in GPI has
                   1264:             a structural flaw that still leaves PostScript the king.
                   1265:             
                   1266:             Take a close look at the display of the "Helv" font. You'll
                   1267:             notice that the two legs of the "H" are different in width
                   1268:             by one pixel when they should be the same width. This is
                   1269:             undoubtedly due to a rounding error. It's obviously more
                   1270:             noticeable on a low-resolution video display than it would
                   1271:             be on a 300 dpi laser printer, but even on a laser printer
                   1272:             such errors will affect the legibility of the text.
                   1273:             
                   1274:             Errors such as this do not occur with PostScript fonts.
                   1275:             PostScript fonts are true algorithms that are able to
                   1276:             recognize and correct any anomalies in the rendition of the
                   1277:             characters. In contrast, GPI fonts (which are encoded as a
                   1278:             simple series of polylines and polyfillets) are drawn
                   1279:             blindly without any feedback or correction.
                   1280:             
                   1281:             So, while we can rejoice in what we have in GPI, there is
                   1282:             still the need to hope for improvement.
                   1283:             
                   1284:             
                   1285: 
                   1286: 
                   1287: 
                   1288: 
                   1289: 
                   1290: 
                   1291: 
                   1292: 
                   1293: 
                   1294: 
                   1295: 
                   1296: 
                   1297: 
                   1298: 
                   1299: 
                   1300: 
                   1301: 
                   1302: 
                   1303: 
                   1304: 
                   1305: 
                   1306: 
                   1307: 
                   1308: 
                   1309: 
                   1310: 
                   1311: 
                   1312: 
                   1313: 
                   1314: 
                   1315: 
                   1316: 
                   1317: 
                   1318: 
                   1319: 
                   1320: 
                   1321: 
                   1322: 
                   1323: 
                   1324: 
                   1325: 
                   1326: 
                   1327:             Figure 1
                   1328:             
                   1329:             
                   1330:             Dynamic Link
                   1331:             Library File   Image Fonts             Vector Fonts
                   1332:             ------------   -----------             ------------
                   1333:             
                   1334:             COURIER.FON    "Courier" (8, 10, and   "Courier"
                   1335:                             12 points for CGA,     "Courier Bold"
                   1336:                             EGA, VGA, and          "Courier Italic"
                   1337:                             IBM Proprinter)        "Courier Bold Italic"
                   1338:             
                   1339:             HELV.FON       "Helv" (8, 10, 12, 14,  "Helv"
                   1340:                             18, and 24 points      "Helv Bold"
                   1341:                             for CGA, EGA, VGA,     "Helv Italic"
                   1342:                             and IBM Proprinter)    "Helv Bold Italic"
                   1343:             
                   1344:             TIMES.FON      "Tms Rmn" (8, 10, 12,   "Tms Rmn"
                   1345:                             14, 18, and 24 points  "Tms Rmn Bold"
                   1346:                             for CGA, EGA, VGA,     "Tms Rmn Italic"
                   1347:                             and IBM Proprinter)    "Tms Rmn Bold Italic"
                   1348:             
                   1349:             
                   1350:             Caption:  The OS/2 1.1 dynamic link library files that
                   1351:             Caption:                                              
                   1352:             contain fonts. The font face names are shown in quotation
                   1353:             marks.
                   1354:             
                   1355:             
                   1356: 
                   1357: 
                   1358: 
                   1359: 
                   1360: 
                   1361: 
                   1362: 
                   1363: 
                   1364: 
                   1365: 
                   1366: 
                   1367: 
                   1368: 
                   1369: 
                   1370: 
                   1371: 
                   1372: 
                   1373: 
                   1374: 
                   1375: 
                   1376: 
                   1377: 
                   1378: 
                   1379: 
                   1380: 
                   1381: 
                   1382: 
                   1383: 
                   1384: 
                   1385: 
                   1386: 
                   1387: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.