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>
|
---|