wxOS2 with Open Watcom: correct PCH usage, missing headers, warning fixes, source...
[wxWidgets.git] / src / os2 / fontutil.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: msw/fontutil.cpp
3 // Purpose: font-related helper functions for wxMSW
4 // Author: Modified by David Webster for OS/2
5 // Modified by:
6 // Created: 01.03.00
7 // RCS-ID: $Id$
8 // Copyright: (c) 1999 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #ifdef __GNUG__
21 #pragma implementation "fontutil.h"
22 #endif
23
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
26
27 #define DEBUG_PRINTF(NAME) \
28 { \
29 static int raz=0; \
30 printf( #NAME " %i\n",raz); fflush(stdout); \
31 raz++; \
32 }
33
34 #ifndef WX_PRECOMP
35 #include "wx/app.h"
36 #include "wx/string.h"
37 #include "wx/log.h"
38 #include "wx/intl.h"
39 #endif //WX_PRECOMP
40
41 #include "wx/os2/private.h"
42
43 #include "wx/fontutil.h"
44 #include "wx/fontmap.h"
45 #include "wx/encinfo.h"
46
47 #include "wx/tokenzr.h"
48
49 // ============================================================================
50 // implementation
51 // ============================================================================
52
53 // ----------------------------------------------------------------------------
54 // wxNativeEncodingInfo
55 // ----------------------------------------------------------------------------
56
57 // convert to/from the string representation: format is
58 // encodingid;facename[;charset]
59
60 bool wxNativeEncodingInfo::FromString( const wxString& rsStr )
61 {
62 wxStringTokenizer vTokenizer(rsStr, _T(";"));
63 wxString sEncid = vTokenizer.GetNextToken();
64 long lEnc;
65
66 if (!sEncid.ToLong(&lEnc))
67 return FALSE;
68 encoding = (wxFontEncoding)lEnc;
69 facename = vTokenizer.GetNextToken();
70 if (!facename)
71 return FALSE;
72
73 wxString sTmp = vTokenizer.GetNextToken();
74
75 if (!sTmp)
76 {
77 charset = 850;
78 }
79 else
80 {
81 if ( wxSscanf(sTmp, _T("%u"), &charset) != 1 )
82 {
83 // should be a number!
84 return FALSE;
85 }
86 }
87 return true;
88 } // end of wxNativeEncodingInfo::FromString
89
90 wxString wxNativeEncodingInfo::ToString() const
91 {
92 wxString sStr;
93
94 sStr << (long)encoding << _T(';') << facename;
95
96 if (charset != 850)
97 {
98 sStr << _T(';') << charset;
99 }
100 return sStr;
101 } // end of wxNativeEncodingInfo::ToString
102
103 // ----------------------------------------------------------------------------
104 // helper functions
105 // ----------------------------------------------------------------------------
106
107 bool wxGetNativeFontEncoding( wxFontEncoding vEncoding,
108 wxNativeEncodingInfo* pInfo )
109 {
110 wxCHECK_MSG(pInfo, FALSE, _T("bad pointer in wxGetNativeFontEncoding") );
111 if (vEncoding == wxFONTENCODING_DEFAULT)
112 {
113 vEncoding = wxFont::GetDefaultEncoding();
114 }
115 switch (vEncoding)
116 {
117 case wxFONTENCODING_ISO8859_1:
118 case wxFONTENCODING_ISO8859_15:
119 case wxFONTENCODING_CP1250:
120 pInfo->charset = 1250;
121 break;
122
123 case wxFONTENCODING_ISO8859_2:
124 case wxFONTENCODING_CP1252:
125 pInfo->charset = 1252;
126 break;
127
128 case wxFONTENCODING_ISO8859_4:
129 case wxFONTENCODING_ISO8859_10:
130 pInfo->charset = 921; // what is baltic?
131 break;
132
133 case wxFONTENCODING_ISO8859_5:
134 case wxFONTENCODING_CP1251:
135 pInfo->charset = 1251;
136 break;
137
138 case wxFONTENCODING_ISO8859_6:
139 pInfo->charset = 864;
140 break;
141
142 case wxFONTENCODING_ISO8859_7:
143 pInfo->charset = 869;
144 break;
145
146 case wxFONTENCODING_ISO8859_8:
147 pInfo->charset = 862;
148 break;
149
150 case wxFONTENCODING_ISO8859_9:
151 pInfo->charset = 857;
152 break;
153
154 case wxFONTENCODING_ISO8859_11:
155 pInfo->charset = 874; // what is thai
156 break;
157
158 case wxFONTENCODING_CP437:
159 pInfo->charset = 437;
160 break;
161
162 default:
163 wxFAIL_MSG(wxT("unsupported encoding"));
164 // fall through
165
166 case wxFONTENCODING_SYSTEM:
167 pInfo->charset = 850;
168 break;
169 }
170 return true;
171 } // end of wxGetNativeFontEncoding
172
173 wxFontEncoding wxGetFontEncFromCharSet(
174 int nCharSet
175 )
176 {
177 wxFontEncoding eFontEncoding;
178
179 switch (nCharSet)
180 {
181 default:
182 case 1250:
183 eFontEncoding = wxFONTENCODING_CP1250;
184 break;
185
186 case 1252:
187 eFontEncoding = wxFONTENCODING_CP1252;
188 break;
189
190 case 921:
191 eFontEncoding = wxFONTENCODING_ISO8859_4;
192 break;
193
194 case 1251:
195 eFontEncoding = wxFONTENCODING_CP1251;
196 break;
197
198 case 864:
199 eFontEncoding = wxFONTENCODING_ISO8859_6;
200 break;
201
202 case 869:
203 eFontEncoding = wxFONTENCODING_ISO8859_7;
204 break;
205
206 case 862:
207 eFontEncoding = wxFONTENCODING_ISO8859_8;
208 break;
209
210 case 857:
211 eFontEncoding = wxFONTENCODING_ISO8859_9;
212 break;
213
214 case 874:
215 eFontEncoding = wxFONTENCODING_ISO8859_11;
216 break;
217
218 case 437:
219 eFontEncoding = wxFONTENCODING_CP437;
220 break;
221 }
222 return eFontEncoding;
223 } // end of wxGetNativeFontEncoding
224
225 bool wxTestFontEncoding( const wxNativeEncodingInfo& rInfo )
226 {
227 FATTRS vLogFont;
228 HPS hPS;
229
230 hPS = ::WinGetPS(HWND_DESKTOP);
231
232 memset(&vLogFont, '\0', sizeof(FATTRS)); // all default values
233 vLogFont.usRecordLength = sizeof(FATTRS);
234 vLogFont.usCodePage = (USHORT)rInfo.charset;
235 vLogFont.lMaxBaselineExt = 0L; // Outline fonts should use 0
236 vLogFont.lAveCharWidth = 0L; // Outline fonts should use 0
237 vLogFont.fsFontUse = FATTR_FONTUSE_OUTLINE | // only outline fonts allowed
238 FATTR_FONTUSE_TRANSFORMABLE; // may be transformed
239
240 wxStrncpy((wxChar*)vLogFont.szFacename, rInfo.facename.c_str(), WXSIZEOF(vLogFont.szFacename));
241
242 if (!::GpiCreateLogFont( hPS
243 ,NULL
244 ,1L
245 ,&vLogFont
246 ))
247 {
248 ::WinReleasePS(hPS);
249 return FALSE;
250 }
251 ::WinReleasePS(hPS);
252 return true;
253 } // end of wxTestFontEncoding
254
255 // ----------------------------------------------------------------------------
256 // wxFont <-> LOGFONT conversion
257 // ----------------------------------------------------------------------------
258
259 void wxConvertVectorFontSize(
260 FIXED fxPointSize
261 , PFATTRS pFattrs
262 )
263 {
264 HPS hPS;
265 HDC hDC;
266 LONG lXFontResolution;
267 LONG lYFontResolution;
268 SIZEF vSizef;
269
270 hPS = WinGetScreenPS(HWND_DESKTOP); // Screen presentation space
271
272 //
273 // Query device context for the screen and then query
274 // the resolution of the device for the device context.
275 //
276
277 hDC = GpiQueryDevice(hPS);
278 DevQueryCaps( hDC, CAPS_HORIZONTAL_FONT_RES, (LONG)1, &lXFontResolution);
279 DevQueryCaps( hDC, CAPS_VERTICAL_FONT_RES, (LONG)1, &lYFontResolution);
280
281 //
282 // Calculate the size of the character box, based on the
283 // point size selected and the resolution of the device.
284 // The size parameters are of type FIXED, NOT int.
285 // NOTE: 1 point == 1/72 of an inch.
286 //
287
288 vSizef.cx = (FIXED)(((fxPointSize) / 72 ) * lXFontResolution );
289 vSizef.cy = (FIXED)(((fxPointSize) / 72 ) * lYFontResolution );
290
291 pFattrs->lMaxBaselineExt = MAKELONG( HIUSHORT( vSizef.cy ), 0 );
292 pFattrs->lAveCharWidth = MAKELONG( HIUSHORT( vSizef.cx ), 0 );
293 WinReleasePS(hPS);
294
295 } // end of wxConvertVectorPointSize
296
297 void wxFillLogFont( LOGFONT* pFattrs, // OS2 GPI FATTRS
298 PFACENAMEDESC pFaceName,
299 HPS* phPS,
300 bool* pbInternalPS,
301 long* pflId,
302 wxString& sFaceName,
303 wxFont* pFont )
304 {
305 LONG lNumFonts = 0L; // For system font count
306 ERRORID vError; // For logging API errors
307 LONG lTemp = 0L;
308 bool bInternalPS = false; // if we have to create one
309 PFONTMETRICS pFM = NULL;
310
311 //
312 // Initial house cleaning to free data buffers and ensure we have a
313 // functional PS to work with
314 //
315 if (!*phPS)
316 {
317 *phPS = ::WinGetPS(HWND_DESKTOP);
318 bInternalPS = true;
319 }
320
321 //
322 // Determine the number of fonts.
323 //
324 if((lNumFonts = ::GpiQueryFonts( *phPS
325 ,QF_PUBLIC | QF_PRIVATE
326 ,NULL
327 ,&lTemp
328 ,(LONG) sizeof(FONTMETRICS)
329 ,NULL
330 )) < 0L)
331 {
332 ERRORID vError;
333 wxString sError;
334
335 vError = ::WinGetLastError(wxGetInstance());
336 sError = wxPMErrorToStr(vError);
337 return;
338 }
339
340 //
341 // Allocate space for the font metrics.
342 //
343 pFM = new FONTMETRICS[lNumFonts + 1];
344
345 //
346 // Retrieve the font metrics.
347 //
348 lTemp = lNumFonts;
349 lTemp = ::GpiQueryFonts( *phPS
350 ,QF_PUBLIC
351 ,NULL
352 ,&lTemp
353 ,(LONG) sizeof(FONTMETRICS)
354 ,pFM
355 );
356 pFont->SetFM( pFM
357 ,(int)lNumFonts
358 );
359
360 //
361 // Initialize FATTR and FACENAMEDESC
362 //
363 pFattrs->usRecordLength = sizeof(FATTRS);
364 pFattrs->fsFontUse = FATTR_FONTUSE_OUTLINE; // only outline fonts allowed
365 pFattrs->fsType = 0;
366 pFattrs->lMaxBaselineExt = pFattrs->lAveCharWidth = 0;
367 pFattrs->idRegistry = 0;
368 pFattrs->lMatch = 0;
369
370 pFaceName->usSize = sizeof(FACENAMEDESC);
371 pFaceName->usWeightClass = FWEIGHT_DONT_CARE;
372 pFaceName->usWidthClass = FWIDTH_DONT_CARE;
373 pFaceName->usReserved = 0;
374 pFaceName->flOptions = 0;
375
376 //
377 // This does the actual selection of fonts
378 //
379 wxOS2SelectMatchingFontByName( pFattrs
380 ,pFaceName
381 ,pFM
382 ,(int)lNumFonts
383 ,pFont
384 );
385 //
386 // We should now have the correct FATTRS set with the selected
387 // font, so now we need to generate an ID
388 //
389 long lNumLids = ::GpiQueryNumberSetIds(*phPS);
390
391 if(lNumLids )
392 {
393 long alTypes[255];
394 STR8 azNames[255];
395 long alIds[255];
396
397 memset(alIds, 0, sizeof(long) * 255);
398 if(!::GpiQuerySetIds( *phPS
399 ,lNumLids
400 ,alTypes
401 ,azNames
402 ,alIds
403 ))
404 {
405 if (bInternalPS)
406 ::WinReleasePS(*phPS);
407 return;
408 }
409 if (*pflId == 0L)
410 *pflId = 1L;
411 for(unsigned long LCNum = 0; LCNum < (unsigned long)lNumLids; LCNum++)
412 if(alIds[LCNum] == *pflId)
413 ++*pflId;
414 if(*pflId > 254) // wow, no id available!
415 {
416 if (bInternalPS)
417 ::WinReleasePS(*phPS);
418 return;
419 }
420 }
421 else
422 *pflId = 1L;
423 //
424 // Release and delete the current font
425 //
426 ::GpiSetCharSet(*phPS, LCID_DEFAULT);/* release the font before deleting */
427 ::GpiDeleteSetId(*phPS, 1L); /* delete the logical font */
428
429 //
430 // Now build a facestring
431 //
432 char zFacename[128];
433
434 strcpy(zFacename, pFattrs->szFacename);
435
436 if(::GpiQueryFaceString( *phPS
437 ,zFacename
438 ,pFaceName
439 ,FACESIZE
440 ,pFattrs->szFacename
441 ) == GPI_ERROR)
442 {
443 vError = ::WinGetLastError(vHabmain);
444 }
445 sFaceName = (wxChar*)zFacename;
446 *pbInternalPS = bInternalPS;
447
448 //
449 // That's it, we now have everything we need to actually create the font
450 //
451 } // end of wxFillLogFont
452
453 void wxOS2SelectMatchingFontByName(
454 PFATTRS pFattrs
455 , PFACENAMEDESC pFaceName
456 , PFONTMETRICS pFM
457 , int nNumFonts
458 , const wxFont* pFont
459 )
460 {
461 int i;
462 int nPointSize;
463 int nIs;
464 int nMinDiff0;
465 int anDiff[16];
466 int anMinDiff[16];
467 int nIndex = 0;
468 wxChar zFontFaceName[FACESIZE];
469 wxString sFaceName;
470 USHORT usWeightClass;
471 int fsSelection = 0;
472
473 nMinDiff0 = 0xf000;
474 for(i = 0;i < 16; i++)
475 anMinDiff[i] = nMinDiff0;
476
477 switch (pFont->GetFamily())
478 {
479 case wxSCRIPT:
480 sFaceName = wxT("Tms Rmn");
481 break;
482
483 case wxDECORATIVE:
484 sFaceName = wxT("WarpSans");
485 break;
486
487 case wxROMAN:
488 sFaceName = wxT("Tms Rmn");
489 break;
490
491 case wxTELETYPE:
492 sFaceName = wxT("Courier") ;
493 break;
494
495 case wxMODERN:
496 sFaceName = wxT("System VIO") ;
497 break;
498
499 case wxSWISS:
500 sFaceName = wxT("Helv") ;
501 break;
502
503 case wxDEFAULT:
504 default:
505 sFaceName = wxT("System VIO") ;
506 }
507
508 switch (pFont->GetWeight())
509 {
510 default:
511 wxFAIL_MSG(_T("unknown font weight"));
512 // fall through
513 usWeightClass = FWEIGHT_DONT_CARE;
514 break;
515
516 case wxNORMAL:
517 usWeightClass = FWEIGHT_NORMAL;
518 break;
519
520 case wxLIGHT:
521 usWeightClass = FWEIGHT_LIGHT;
522 break;
523
524 case wxBOLD:
525 usWeightClass = FWEIGHT_BOLD;
526 break;
527
528 case wxFONTWEIGHT_MAX:
529 usWeightClass = FWEIGHT_ULTRA_BOLD;
530 break;
531 }
532 pFaceName->usWeightClass = usWeightClass;
533
534 switch (pFont->GetStyle())
535 {
536 case wxITALIC:
537 case wxSLANT:
538 fsSelection = FM_SEL_ITALIC;
539 pFaceName->flOptions = FTYPE_ITALIC;
540 break;
541
542 default:
543 wxFAIL_MSG(wxT("unknown font slant"));
544 // fall through
545
546 case wxNORMAL:
547 fsSelection = 0;
548 break;
549 }
550
551 wxStrncpy(zFontFaceName, sFaceName.c_str(), WXSIZEOF(zFontFaceName));
552 nPointSize = pFont->GetPointSize();
553
554 //
555 // Matching logic to find the right FM struct
556 //
557 nIndex = 0;
558 for(i = 0, nIs = 0; i < nNumFonts; i++)
559 {
560 int nEmHeight = 0;
561 int nXHeight = 0;
562
563 anDiff[0] = wxGpiStrcmp((wxChar*)pFM[i].szFacename, zFontFaceName);
564 anDiff[1] = abs(pFM[i].lEmHeight - nPointSize);
565 anDiff[2] = abs(pFM[i].usWeightClass - usWeightClass);
566 anDiff[3] = abs((pFM[i].fsSelection & 0x2f) - fsSelection);
567 if(anDiff[0] == 0)
568 {
569 nEmHeight = (int)pFM[i].lEmHeight;
570 nXHeight =(int)pFM[i].lXHeight;
571 if( (nIs & 0x01) == 0)
572 {
573 nIs = 1;
574 nIndex = i;
575 anMinDiff[1] = anDiff[1];
576 anMinDiff[2] = anDiff[2];
577 anMinDiff[3] = anDiff[3];
578 }
579 else if(anDiff[3] < anMinDiff[3])
580 {
581 nIndex = i;
582 anMinDiff[3] = anDiff[3];
583 }
584 else if(anDiff[2] < anMinDiff[2])
585 {
586 nIndex = i;
587 anMinDiff[2] = anDiff[2];
588 }
589 else if(anDiff[1] < anMinDiff[1])
590 {
591 nIndex = i;
592 anMinDiff[1] = anDiff[1];
593 }
594 anMinDiff[0] = 0;
595 }
596 else if(anDiff[0] < anMinDiff[0])
597 {
598 nIs = 2;
599 nIndex = i;
600 anMinDiff[3] = anDiff[3];
601 anMinDiff[2] = anDiff[2];
602 anMinDiff[1] = anDiff[1];
603 anMinDiff[0] = anDiff[0];
604 }
605 else if(anDiff[0] == anMinDiff[0])
606 {
607 if(anDiff[3] < anMinDiff[3])
608 {
609 nIndex = i;
610 anMinDiff[3] = anDiff[3];
611 nIs = 2;
612 }
613 else if(anDiff[2] < anMinDiff[2])
614 {
615 nIndex = i;
616 anMinDiff[2] = anDiff[2];
617 nIs = 2;
618 }
619 else if(anDiff[1] < anMinDiff[1])
620 {
621 nIndex = i;
622 anMinDiff[1] = anDiff[1];
623 nIs = 2;
624 }
625 }
626 }
627
628 //
629 // Fill in the FATTRS with the best match from FONTMETRICS
630 //
631 pFattrs->usRecordLength = sizeof(FATTRS); // Sets size of structure
632 pFattrs->lMatch = pFM[nIndex].lMatch; // Force match
633 pFattrs->idRegistry = 0;
634 pFattrs->usCodePage = 0;
635 pFattrs->fsFontUse = 0;
636 pFattrs->fsType = 0;
637 pFattrs->lMaxBaselineExt = 0;
638 pFattrs->lAveCharWidth = 0;
639 wxStrcpy((wxChar*)pFattrs->szFacename, (wxChar*)pFM[nIndex].szFacename);
640 if (pFont->GetWeight() == wxNORMAL)
641 pFattrs->fsSelection = 0;
642 else
643 pFattrs->fsSelection = FATTR_SEL_BOLD;
644
645 if (pFont->GetStyle() == wxITALIC || pFont->GetStyle() == wxSLANT)
646 pFattrs->fsSelection |= FATTR_SEL_ITALIC;
647
648 if (pFont->GetUnderlined())
649 pFattrs->fsSelection |= FATTR_SEL_UNDERSCORE;
650 } // end of wxOS2SelectMatchingFontByName
651
652 wxFont wxCreateFontFromLogFont(
653 const LOGFONT* pLogFont
654 , const PFONTMETRICS pFM
655 , PFACENAMEDESC pFaceName
656 )
657 {
658 wxNativeFontInfo vInfo;
659
660 vInfo.fa = *pLogFont;
661 vInfo.fm = *pFM;
662 vInfo.fn = *pFaceName;
663 return wxFont(vInfo);
664 } // end of wxCreateFontFromLogFont
665
666 int wxGpiStrcmp(
667 wxChar* s0
668 , wxChar* s1
669 )
670 { int l0;
671 int l1;
672 int l;
673 int d;
674 int d1;
675 int i;
676 int rc;
677
678 rc = 0;
679 if(s0 == NULL)
680 {
681 if(s1 == NULL)
682 return 0;
683 else
684 return 32;
685 }
686 else if(s1 == NULL)
687 return 32;
688
689 l0 = wxStrlen(s0);
690 l1 = wxStrlen(s1);
691 l = l0;
692 if(l0 != l1)
693 {
694 rc++;
695 if(l1 < l0)
696 l = l1;
697 }
698 for(i=0;i<l;i++)
699 {
700 d = s0[i]-s1[i];
701 if(!d)
702 continue;
703 d1 = wxToupper(s0[i]) - wxToupper(s1[i]);
704 if(!d1)
705 continue;
706 rc += abs(d);
707 }
708 return rc;
709 }