| 1 | <?xml version="1.0" encoding="UTF-8"?>
 | 
|---|
| 2 | <?xml-stylesheet type="text/css"
 | 
|---|
| 3 | href="eclipseos2-xxe.css"
 | 
|---|
| 4 | ?>
 | 
|---|
| 5 | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
 | 
|---|
| 6 | "xhtml1-strict.dtd">
 | 
|---|
| 7 | <html>
 | 
|---|
| 8 |   <head>
 | 
|---|
| 9 |     <link href="eclipseos2.css" rel="stylesheet" type="text/css" />
 | 
|---|
| 10 | 
 | 
|---|
| 11 |     <title>Eclipse for OS/2 Transitional Project Notes</title>
 | 
|---|
| 12 |   </head>
 | 
|---|
| 13 | 
 | 
|---|
| 14 |   <body>
 | 
|---|
| 15 |     <h1>SWT Step 5. Font handling</h1>
 | 
|---|
| 16 | 
 | 
|---|
| 17 |     <h2>Objective</h2>
 | 
|---|
| 18 | 
 | 
|---|
| 19 |     <p>Implement font handling (including implementation of
 | 
|---|
| 20 |     <code>o.e.swt.graphics.Font</code>, <code>FontData</code> and
 | 
|---|
| 21 |     <code>FontMetrics</code> classes). The test example of this step should
 | 
|---|
| 22 |     draw some text strings with various fonts on the SWT top window client
 | 
|---|
| 23 |     area using corresponding methods of <code>o.e.swt.graphics.GC</code>
 | 
|---|
| 24 |     class.</p>
 | 
|---|
| 25 | 
 | 
|---|
| 26 |     <h2>Task notes</h2>
 | 
|---|
| 27 | 
 | 
|---|
| 28 |     <h3>Font matching</h3>
 | 
|---|
| 29 | 
 | 
|---|
| 30 |     <p>The <code>GpiQueryFaceString()</code> function is intended to compose a
 | 
|---|
| 31 |     font facename (that includes textual representation of the font style)
 | 
|---|
| 32 |     given a font family name and flags describing the desired style (bold,
 | 
|---|
| 33 |     italic etc), by searching the installed fonts for the exact match (the
 | 
|---|
| 34 |     font that truely has the requested style, without any emulation). But this
 | 
|---|
| 35 |     function is buggy and sometimes returns NULL even if the desired font
 | 
|---|
| 36 |     actually exists in the system. The example is the <kbd>Lucida Sans
 | 
|---|
| 37 |     Typewriter</kbd> font family shipped with Java. If we have all 4 styles of
 | 
|---|
| 38 |     this family installed (Regular, Bold, Oblique and Bold Oblique) and try to
 | 
|---|
| 39 |     call this function for it with <code>FWEIGHT_DONT_CARE</code>,
 | 
|---|
| 40 |     <code>FWIDTH_DONT_CARE</code> and <code>FTYPE_ITALIC</code> flags set
 | 
|---|
| 41 |     ((i.e. we request any <kbd>Lucida Sans Typewriter</kbd> font that has the
 | 
|---|
| 42 |     <code>FM_SEL_ITALIC</code> bit set in the
 | 
|---|
| 43 |     <code>FONTMETRICS.fsSelection</code> field, ignoring
 | 
|---|
| 44 |     <code>usWeightClass</code> and <code>usWidthClass)</code> we get nothing
 | 
|---|
| 45 |     although the <kbd>Lucida Sans Typewriter Oblique</kbd> exists and
 | 
|---|
| 46 |     completely matches the given criteria.</p>
 | 
|---|
| 47 | 
 | 
|---|
| 48 |     <p>Due to this bug, the only way to find a font given its family name and
 | 
|---|
| 49 |     style is the full scan of the list of all fonts installed in the system.
 | 
|---|
| 50 |     So we decided to cache the complete font list in some useful way upon the
 | 
|---|
| 51 |     first font request from the SWT user to speed up further font searches.
 | 
|---|
| 52 |     Hopefully, there is a function <code>GpiQueryFontAction()</code> that can
 | 
|---|
| 53 |     tell us whether the font list has been changed since the last call or not,
 | 
|---|
| 54 |     which can be used to check the validity of the cache.</p>
 | 
|---|
| 55 | 
 | 
|---|
| 56 |     <p>The font matching algorithm is close enough to the original algorithm
 | 
|---|
| 57 |     used by OS/2 to ensure that any font matched by our algorithm can be set
 | 
|---|
| 58 |     as the font for standard OS/2 window classes, but has some differences (in
 | 
|---|
| 59 |     particular, when there is no bitmap font of the requested size installed
 | 
|---|
| 60 |     in the system we select one with the closest size from the font family,
 | 
|---|
| 61 |     while OS/2 always selects the default font in that cases). See the
 | 
|---|
| 62 |     <code>Device.matchFont()</code> methods for more detailed info about the
 | 
|---|
| 63 |     matching algorithm.</p>
 | 
|---|
| 64 | 
 | 
|---|
| 65 |     <h3>Font metrics</h3>
 | 
|---|
| 66 | 
 | 
|---|
| 67 |     <p>There are numerous bugs with calculating font metrics in GPI. For
 | 
|---|
| 68 |     example, various text drawing functions start using and returning wrong
 | 
|---|
| 69 |     character box and string extent coordinates when we set the text alignment
 | 
|---|
| 70 |     (<code>GpiSetTextAlignment()</code>) other than default
 | 
|---|
| 71 |     (<code>TA_NORMAL_HORIZ</code>, <code>TA_NORMAL_VERT</code>). So we always
 | 
|---|
| 72 |     have to use this default alignment (instead of <code>TA_TOP</code> for
 | 
|---|
| 73 |     example, which would be more useful in SWT).</p>
 | 
|---|
| 74 | 
 | 
|---|
| 75 |     <p>Also GPI wrongly fills the background of the string for true type fonts
 | 
|---|
| 76 |     -- it makes it one pixel higher than the real font height
 | 
|---|
| 77 |     (<code>lMaxBaselineExt</code>) and leaves unfilled gaps at the beginning
 | 
|---|
| 78 |     and at the end of the string. For this reason we always fill the
 | 
|---|
| 79 |     background ourselves instructing GPI not to fill it when drawing
 | 
|---|
| 80 |     strings.</p>
 | 
|---|
| 81 | 
 | 
|---|
| 82 |     <p>Another problem is that <code>lMaxBaselineExt</code> (as returned by
 | 
|---|
| 83 |     <code>GpiQueryFontMetrics()</code>) is not always the sum of
 | 
|---|
| 84 |     <code>lMaxAscender</code> and <code>lMaxDescender</code>, sometimes this
 | 
|---|
| 85 |     sum is one pixel larger -- the example is the <kbd>Times New Roman</kbd>
 | 
|---|
| 86 |     TTF font drawn at 24 points (40 pixels). As a solution we calculate the
 | 
|---|
| 87 |     font descent value as <code>lMaxBaselineExt - lMaxAscender</code> instead
 | 
|---|
| 88 |     of taking <code>lMaxDescender</code> from returned font metrics.</p>
 | 
|---|
| 89 | 
 | 
|---|
| 90 |     <h3>FATTRS and FONTMETRICS sz* fields</h3>
 | 
|---|
| 91 | 
 | 
|---|
| 92 |     <p>Originally <code>FATTRS</code> and <code>FONTMETRICS</code> structures
 | 
|---|
| 93 |     have fields, <code>szFamilyname</code> and <code>szFacename</code>
 | 
|---|
| 94 |     (<code>FONTMETRICS</code> only) to store the font family and face name as
 | 
|---|
| 95 |     arrays of <code>char</code>s (not as pointers to arrays). In Java we can
 | 
|---|
| 96 |     only define poiners (references) to arrays as field members. As opposed to
 | 
|---|
| 97 |     Windows version of SWT, where they defined similar fields as a sequence of
 | 
|---|
| 98 |     separate N byte fields (where N is the length of the original array), in
 | 
|---|
| 99 |     OS/2 we defined them as references to java byte arrays. It is much easier
 | 
|---|
| 100 |     to work with these arrays but is potentially dangerous because one can
 | 
|---|
| 101 |     accidentally replace these references with references to arrays of
 | 
|---|
| 102 |     different size -- it must not happen because the code assumes that these
 | 
|---|
| 103 |     arrays always have the length of <code>OS.FACENAME</code> (32) bytes. When
 | 
|---|
| 104 |     the structure is instantiated these arrays are allocated automatically and
 | 
|---|
| 105 |     should not be reallocated later.</p>
 | 
|---|
| 106 | 
 | 
|---|
| 107 |     <h3>Locales</h3>
 | 
|---|
| 108 | 
 | 
|---|
| 109 |     <p>There are two ways to support unicode when working in OS/2 PM/GPI.</p>
 | 
|---|
| 110 | 
 | 
|---|
| 111 |     <p>The first way is to convert unicode strings to single-byte strings
 | 
|---|
| 112 |     using <code>Uni*</code> API (availabel since Warp 4 Fixpak 5) before
 | 
|---|
| 113 |     passing them to PM/GPI calls and provide the corresponding single-byte
 | 
|---|
| 114 |     codepage numbers when creating logical fonts and setting the message queue
 | 
|---|
| 115 |     codepage.</p>
 | 
|---|
| 116 | 
 | 
|---|
| 117 |     <p>The second way is to work in true unicode mode -- this means to use the
 | 
|---|
| 118 |     codepage <kbd>IBM-1200</kbd> for font creation and the message queue and
 | 
|---|
| 119 |     pass unicode strings to PM/GPI as is, i.e. as two-byte unicode
 | 
|---|
| 120 |     strings.</p>
 | 
|---|
| 121 | 
 | 
|---|
| 122 |     <p>It's obvious that the second way is more convenient than the first
 | 
|---|
| 123 |     because it allows to draw characters from different languages
 | 
|---|
| 124 |     simultaneously, using the same logical font (of course, provided that the
 | 
|---|
| 125 |     font physically contains glyphs for all used character groups). It is also
 | 
|---|
| 126 |     the only way to display such different characters in the window's
 | 
|---|
| 127 |     titlebar. Unfortunately, the current implementation of this approach is
 | 
|---|
| 128 |     quite buggy in OS/2. The following bugs are known:</p>
 | 
|---|
| 129 | 
 | 
|---|
| 130 |     <ul>
 | 
|---|
| 131 |       <li>For some bitmap fonts (<kbd>WarpSans</kbd> and <kbd>System
 | 
|---|
| 132 |       Proportional</kbd>) GPI reports the wrong character width/extent for
 | 
|---|
| 133 |       unicode characters that are absent in the font. GPI visualizes such
 | 
|---|
| 134 |       missing characters with an empty rectangle character, but the reported
 | 
|---|
| 135 |       width is two times smaller than its actual width. This causes some
 | 
|---|
| 136 |       problems when formatting text and concatenating text strings in
 | 
|---|
| 137 |       SWT.</li>
 | 
|---|
| 138 | 
 | 
|---|
| 139 |       <li>There is a very strange bug appearing when we draw strings using
 | 
|---|
| 140 |       <kbd>Courier New</kbd> and <kbd>Courier New Bold</kbd> TrueType fonts --
 | 
|---|
| 141 |       GPI places an extra space (equal to the average character width) between
 | 
|---|
| 142 |       every character it draws which makes this fonts unusable in unicode
 | 
|---|
| 143 |       mode.</li>
 | 
|---|
| 144 | 
 | 
|---|
| 145 |       <li>For some bitmap fonts (<kbd>WarpSans</kbd>) GPI refuses to draw
 | 
|---|
| 146 |       characters from some unicode groups (for example, japanese characters in
 | 
|---|
| 147 |       range <code>0xFF00 - 0xFFEF</code>) although their glypths are actually
 | 
|---|
| 148 |       present in the font.</li>
 | 
|---|
| 149 |     </ul>
 | 
|---|
| 150 | 
 | 
|---|
| 151 |     <p>When we use the first approach (single-byte strings with convertion)
 | 
|---|
| 152 |     bugs pointed above do not appear. But this approach doesn't allow to draw
 | 
|---|
| 153 |     characters from different languages using the same font (a separate font
 | 
|---|
| 154 |     for every character group is required).</p>
 | 
|---|
| 155 | 
 | 
|---|
| 156 |     <p>In SWT, the only way to deal with locales is to use the
 | 
|---|
| 157 |     <code>FontData.setLocale()</code> method to create fonts from different
 | 
|---|
| 158 |     locales. As we understand this method makes sense only on systems that
 | 
|---|
| 159 |     lack the true unicode support (Win95?) and it corresponds to the first way
 | 
|---|
| 160 |     of working with unicode described above. For systems that support true
 | 
|---|
| 161 |     unicode it is useless and even produces worse results (WinXP).</p>
 | 
|---|
| 162 | 
 | 
|---|
| 163 |     <p>Since OS/2 provides the true unicode support it seems to be more
 | 
|---|
| 164 |     logical to use it in SWT. But at the present time we decided not to do it
 | 
|---|
| 165 |     because of listed bugs. Currently the only alternative way is to use
 | 
|---|
| 166 |     single-byte approach and implement the <code>setLocale()</code> method.
 | 
|---|
| 167 |     But we decided not to go this way also because of its conceptual
 | 
|---|
| 168 |     limitations and because we believe that bugs of true unicode mode will be
 | 
|---|
| 169 |     fixed in the near future by switching to the usage of the <a
 | 
|---|
| 170 |     href="http://www.freetype.org">FreeType</a> library to work with fonts
 | 
|---|
| 171 |     which is free of many-many font-related bugs seen in OS/2. So, currently,
 | 
|---|
| 172 |     only unicode characters that correspond to the system locale are displayed
 | 
|---|
| 173 |     correctly (unicode is converted to single-byte using
 | 
|---|
| 174 |     <code>String.toBytes()</code> method) and there is no way to switch
 | 
|---|
| 175 |     locales (from the font usage point of view) dynamically in runtime.</p>
 | 
|---|
| 176 | 
 | 
|---|
| 177 |     <h2>Step checklist</h2>
 | 
|---|
| 178 | 
 | 
|---|
| 179 |     <table>
 | 
|---|
| 180 |       <col width="40%" />
 | 
|---|
| 181 | 
 | 
|---|
| 182 |       <col />
 | 
|---|
| 183 | 
 | 
|---|
| 184 |       <col width="50%" />
 | 
|---|
| 185 | 
 | 
|---|
| 186 |       <thead>
 | 
|---|
| 187 |         <tr>
 | 
|---|
| 188 |           <th>Operation</th>
 | 
|---|
| 189 | 
 | 
|---|
| 190 |           <th>Status</th>
 | 
|---|
| 191 | 
 | 
|---|
| 192 |           <th>Remarks</th>
 | 
|---|
| 193 |         </tr>
 | 
|---|
| 194 |       </thead>
 | 
|---|
| 195 | 
 | 
|---|
| 196 |       <tr>
 | 
|---|
| 197 |         <td>Add <code>FATTRS</code> and <code>FONTMETRICS</code> classes and
 | 
|---|
| 198 |         their native getters/setters, <code>FATTRS_*</code> constants,
 | 
|---|
| 199 |         <code>FM_TYPE_*</code>, <code>FM_DEFN_*</code>, <code>FM_SEL_*</code>,
 | 
|---|
| 200 |         <code>FM_CAP_*</code> constants</td>
 | 
|---|
| 201 | 
 | 
|---|
| 202 |         <td>Done [eli, dmik]</td>
 | 
|---|
| 203 | 
 | 
|---|
| 204 |         <td></td>
 | 
|---|
| 205 |       </tr>
 | 
|---|
| 206 | 
 | 
|---|
| 207 |       <tr>
 | 
|---|
| 208 |         <td>Implement <code>FontMetrics</code> class</td>
 | 
|---|
| 209 | 
 | 
|---|
| 210 |         <td>Done [eli, dmik]</td>
 | 
|---|
| 211 | 
 | 
|---|
| 212 |         <td></td>
 | 
|---|
| 213 |       </tr>
 | 
|---|
| 214 | 
 | 
|---|
| 215 |       <tr>
 | 
|---|
| 216 |         <td>Implement several missing methods in the <code>GC</code>
 | 
|---|
| 217 |         class</td>
 | 
|---|
| 218 | 
 | 
|---|
| 219 |         <td>Done [dmik]</td>
 | 
|---|
| 220 | 
 | 
|---|
| 221 |         <td>See the updated <a href="swt006.html">SWT006 Step</a> for more
 | 
|---|
| 222 |         info</td>
 | 
|---|
| 223 |       </tr>
 | 
|---|
| 224 | 
 | 
|---|
| 225 |       <tr>
 | 
|---|
| 226 |         <td>Add <code>OS.WinSetPresParam (...byte[])</code>,
 | 
|---|
| 227 |         <code>WinQueryPresParam()</code></td>
 | 
|---|
| 228 | 
 | 
|---|
| 229 |         <td>Done [dmik]</td>
 | 
|---|
| 230 | 
 | 
|---|
| 231 |         <td></td>
 | 
|---|
| 232 |       </tr>
 | 
|---|
| 233 | 
 | 
|---|
| 234 |       <tr>
 | 
|---|
| 235 |         <td>Add <code>OS.GpiQueryFaceString()</code>,
 | 
|---|
| 236 |         <code>FACENAMEDESC</code> and <code>FWEIGHT_*</code>,
 | 
|---|
| 237 |         <code>FWIDTH_*</code>, <code>FTYPE_*</code> constants...
 | 
|---|
| 238 |         remove!!!</td>
 | 
|---|
| 239 | 
 | 
|---|
| 240 |         <td>Done [dmik]</td>
 | 
|---|
| 241 | 
 | 
|---|
| 242 |         <td></td>
 | 
|---|
| 243 |       </tr>
 | 
|---|
| 244 | 
 | 
|---|
| 245 |       <tr>
 | 
|---|
| 246 |         <td>Add <code>OS.GpiQueryFontAction()</code> and <code>QFA_*</code>
 | 
|---|
| 247 |         constants; <code>GpiQueryFonts()</code> and <code>QF_*</code>
 | 
|---|
| 248 |         constants, <code>GpiQueryFontMetrics()</code></td>
 | 
|---|
| 249 | 
 | 
|---|
| 250 |         <td>Done [dmik]</td>
 | 
|---|
| 251 | 
 | 
|---|
| 252 |         <td></td>
 | 
|---|
| 253 |       </tr>
 | 
|---|
| 254 | 
 | 
|---|
| 255 |       <tr>
 | 
|---|
| 256 |         <td>Add <code>OS.GpiCreateLogFont()</code> and <code>FONT_*</code>
 | 
|---|
| 257 |         constants, <code>GpiSetCharSet()</code>,
 | 
|---|
| 258 |         <code>GpiSetCharBox()</code></td>
 | 
|---|
| 259 | 
 | 
|---|
| 260 |         <td>Done [dmik]</td>
 | 
|---|
| 261 | 
 | 
|---|
| 262 |         <td></td>
 | 
|---|
| 263 |       </tr>
 | 
|---|
| 264 | 
 | 
|---|
| 265 |       <tr>
 | 
|---|
| 266 |         <td>Add <code>OS.GpiCharStringAt()</code>,
 | 
|---|
| 267 |         <code>GpiSetTextAlignment()</code>, <code>GpiQueryTextBox()</code>
 | 
|---|
| 268 |         & <code>TXTBOX_*</code> constants</td>
 | 
|---|
| 269 | 
 | 
|---|
| 270 |         <td>Done [dmik]</td>
 | 
|---|
| 271 | 
 | 
|---|
| 272 |         <td></td>
 | 
|---|
| 273 |       </tr>
 | 
|---|
| 274 | 
 | 
|---|
| 275 |       <tr>
 | 
|---|
| 276 |         <td>Add <code>OS.PrfQueryProfileSize()</code>,
 | 
|---|
| 277 |         <code>PrfQueryProfileString()</code> and <code>HINI_*</code>
 | 
|---|
| 278 |         constants</td>
 | 
|---|
| 279 | 
 | 
|---|
| 280 |         <td>Done [dmik]</td>
 | 
|---|
| 281 | 
 | 
|---|
| 282 |         <td>to read the system font value from OS2.INI</td>
 | 
|---|
| 283 |       </tr>
 | 
|---|
| 284 | 
 | 
|---|
| 285 |       <tr>
 | 
|---|
| 286 |         <td>Add <code>OS.WinEnableWindow()</code> and implement
 | 
|---|
| 287 |         <code>Control.setEnabled()</code></td>
 | 
|---|
| 288 | 
 | 
|---|
| 289 |         <td>Done [dmik]</td>
 | 
|---|
| 290 | 
 | 
|---|
| 291 |         <td></td>
 | 
|---|
| 292 |       </tr>
 | 
|---|
| 293 | 
 | 
|---|
| 294 |       <tr>
 | 
|---|
| 295 |         <td>Implement <code>FontData</code> and <code>Font</code> classes</td>
 | 
|---|
| 296 | 
 | 
|---|
| 297 |         <td>Done [dmik]</td>
 | 
|---|
| 298 | 
 | 
|---|
| 299 |         <td></td>
 | 
|---|
| 300 |       </tr>
 | 
|---|
| 301 | 
 | 
|---|
| 302 |       <tr>
 | 
|---|
| 303 |         <td>Imlement string methods in the <code>GC</code> class</td>
 | 
|---|
| 304 | 
 | 
|---|
| 305 |         <td>Done [dmik]</td>
 | 
|---|
| 306 | 
 | 
|---|
| 307 |         <td></td>
 | 
|---|
| 308 |       </tr>
 | 
|---|
| 309 | 
 | 
|---|
| 310 |       <tr>
 | 
|---|
| 311 |         <td>Add testcases <code>SWT005_01</code> and
 | 
|---|
| 312 |         <code>SWT005_02</code></td>
 | 
|---|
| 313 | 
 | 
|---|
| 314 |         <td>Done [dmik]</td>
 | 
|---|
| 315 | 
 | 
|---|
| 316 |         <td></td>
 | 
|---|
| 317 |       </tr>
 | 
|---|
| 318 |     </table>
 | 
|---|
| 319 |   </body>
 | 
|---|
| 320 | </html>
 | 
|---|