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