[9] | 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>
|
---|