|
|
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:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.