home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Programmer's Library 1.3 / Microsoft-Programers-Library-v1.3.iso / sampcode / os2sdk / os2sdk11 / tk5 / vectfont / vectfont.doc < prev    next >
Encoding:
Text File  |  1989-02-20  |  46.4 KB  |  1,387 lines

  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            Caption:                                              
  1351.             contain fonts. The font face names are shown in quotation
  1352.             marks.
  1353.             
  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.