source: trunk/doc/swt005.html@ 20

Last change on this file since 20 was 9, checked in by lpino, 18 years ago
  • Initial commit
File size: 12.7 KB
Line 
1<?xml version="1.0" encoding="UTF-8"?>
2<?xml-stylesheet type="text/css"
3href="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 &amp; <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>
Note: See TracBrowser for help on using the repository browser.