OS/2 NativeFontInfo support
[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 wxFillLogFont(
262 LOGFONT* pFattrs // OS2 GPI FATTRS
263 , PFACENAMEDESC pFaceName
264 , HPS hPS
265 , long* pflId
266 , wxString& sFaceName
267 , wxFont* pFont
268 )
269 {
270 LONG lNumFonts = 0L; // For system font count
271 ERRORID vError; // For logging API errors
272 LONG lTemp;
273 bool bInternalPS = FALSE; // if we have to create one
274 PFONTMETRICS pFM = NULL;
275
276 //
277 // Initial house cleaning to free data buffers and ensure we have a
278 // functional PS to work with
279 //
280 if (!hPS)
281 {
282 hPS = ::WinGetPS(HWND_DESKTOP);
283 bInternalPS = TRUE;
284 }
285
286 //
287 // Determine the number of fonts.
288 //
289 lNumFonts = ::GpiQueryFonts( hPS
290 ,QF_PUBLIC
291 ,NULL
292 ,&lTemp
293 ,(LONG) sizeof(FONTMETRICS)
294 ,NULL
295 );
296
297 //
298 // Allocate space for the font metrics.
299 //
300 pFM = new FONTMETRICS[lNumFonts + 1];
301
302 //
303 // Retrieve the font metrics.
304 //
305 lTemp = lNumFonts;
306 lTemp = ::GpiQueryFonts( hPS
307 ,QF_PUBLIC
308 ,NULL
309 ,&lTemp
310 ,(LONG) sizeof(FONTMETRICS)
311 ,pFM
312 );
313 pFont->SetFM( pFM
314 ,(int)lNumFonts
315 );
316
317 wxString sVals;
318
319 for (int i = 0; i < lNumFonts; i++)
320 {
321 sVals << "Face: " << pFM[i].szFacename
322 << "Family: " << pFM[i].szFamilyname
323 << " PointSize: " << pFM[i].lEmHeight
324 << " Height: " << pFM[i].lXHeight
325 ;
326 sVals = "";
327 }
328
329 //
330 // Initialize FATTR and FACENAMEDESC
331 //
332 pFattrs->usRecordLength = sizeof(FATTRS);
333 pFattrs->fsFontUse = FATTR_FONTUSE_OUTLINE | // only outline fonts allowed
334 FATTR_FONTUSE_TRANSFORMABLE; // may be transformed
335 pFattrs->fsType = 0;
336 pFattrs->lMaxBaselineExt = pFattrs->lAveCharWidth = 0;
337 pFattrs->idRegistry = 0;
338 pFattrs->lMatch = 0;
339
340 pFaceName->usSize = sizeof(FACENAMEDESC);
341 pFaceName->usWidthClass = FWIDTH_NORMAL;
342 pFaceName->usReserved = 0;
343 pFaceName->flOptions = 0;
344
345 //
346 // This does the actual selection of fonts
347 //
348 wxOS2SelectMatchingFontByName( pFattrs
349 ,pFaceName
350 ,pFM
351 ,(int)lNumFonts
352 ,pFont
353 );
354 //
355 // We should now have the correct FATTRS set with the selected
356 // font, so now we need to generate an ID
357 //
358 long lNumLids = ::GpiQueryNumberSetIds(hPS);
359 long lGpiError;
360
361 if(lNumLids )
362 {
363 long alTypes[255];
364 STR8 azNames[255];
365 long alIds[255];
366
367 if(!::GpiQuerySetIds( hPS
368 ,lNumLids
369 ,alTypes
370 ,azNames
371 ,alIds
372 ))
373 {
374 if (bInternalPS)
375 ::WinReleasePS(hPS);
376 return;
377 }
378
379 for(unsigned long LCNum = 0; LCNum < lNumLids; LCNum++)
380 if(alIds[LCNum] == *pflId)
381 ++*pflId;
382 if(*pflId > 254) // wow, no id available!
383 {
384 if (bInternalPS)
385 ::WinReleasePS(hPS);
386 return;
387 }
388 }
389
390 //
391 // Release and delete the current font
392 //
393 ::GpiSetCharSet(hPS, LCID_DEFAULT);/* release the font before deleting */
394 ::GpiDeleteSetId(hPS, 1L); /* delete the logical font */
395
396 //
397 // Now build a facestring
398 //
399 char zFacename[128];
400
401 strcpy(zFacename, pFattrs->szFacename);
402
403 if(::GpiQueryFaceString( hPS
404 ,zFacename
405 ,pFaceName
406 ,FACESIZE
407 ,pFattrs->szFacename
408 ) == GPI_ERROR)
409 {
410 vError = ::WinGetLastError(vHabmain);
411 }
412 sFaceName = zFacename;
413
414 //
415 // That's it, we now have everything we need to actually create the font
416 //
417 } // end of wxFillLogFont
418
419 void wxOS2SelectMatchingFontByName(
420 PFATTRS pFattrs
421 , PFACENAMEDESC pFaceName
422 , PFONTMETRICS pFM
423 , int nNumFonts
424 , const wxFont* pFont
425 )
426 {
427 int i;
428 int nDiff0;
429 int nPointSize;
430 int nDiff;
431 int nIs;
432 int nIndex;
433 int nMinDiff;
434 int nMinDiff0;
435 int nApirc;
436 int anDiff[16];
437 int anMinDiff[16];
438 STR8 zFn;
439 char zFontFaceName[FACESIZE];
440 wxString sFaceName;
441 USHORT usWeightClass;
442 int fsSelection = 0;
443
444 nMinDiff0 = 0xf000;
445 for(i = 0;i < 16; i++)
446 anMinDiff[i] = nMinDiff0;
447
448 switch (pFont->GetFamily())
449 {
450 case wxSCRIPT:
451 sFaceName = wxT("Script");
452 break;
453
454 case wxDECORATIVE:
455 case wxROMAN:
456 sFaceName = wxT("Times New Roman");
457 break;
458
459 case wxTELETYPE:
460 case wxMODERN:
461 sFaceName = wxT("Courier") ;
462 break;
463
464 case wxSWISS:
465 sFaceName = wxT("WarpSans") ;
466 break;
467
468 case wxDEFAULT:
469 default:
470 sFaceName = wxT("Helv") ;
471 }
472
473 switch (pFont->GetWeight())
474 {
475 default:
476 wxFAIL_MSG(_T("unknown font weight"));
477 // fall through
478 usWeightClass = FWEIGHT_DONT_CARE;
479 break;
480
481 case wxNORMAL:
482 usWeightClass = FWEIGHT_NORMAL;
483 break;
484
485 case wxLIGHT:
486 usWeightClass = FWEIGHT_LIGHT;
487 break;
488
489 case wxBOLD:
490 usWeightClass = FWEIGHT_BOLD;
491 break;
492
493 case wxFONTWEIGHT_MAX:
494 usWeightClass = FWEIGHT_ULTRA_BOLD;
495 break;
496 }
497 pFaceName->usWeightClass = usWeightClass;
498
499 switch (pFont->GetStyle())
500 {
501 case wxITALIC:
502 case wxSLANT:
503 fsSelection = FM_SEL_ITALIC;
504 pFaceName->flOptions = FTYPE_ITALIC;
505 break;
506
507 default:
508 wxFAIL_MSG(wxT("unknown font slant"));
509 // fall through
510
511 case wxNORMAL:
512 fsSelection = 0;
513 break;
514 }
515
516 wxStrncpy(zFontFaceName, sFaceName.c_str(), WXSIZEOF(zFontFaceName));
517 nPointSize = pFont->GetPointSize();
518
519 //
520 // Matching logic to find the right FM struct
521 //
522 nIndex = 0;
523 for(i = 0, nIs = 0; i < nNumFonts; i++)
524 {
525 int nEmHeight = 0;
526 int nXHeight = 0;
527
528 anDiff[0] = wxGpiStrcmp(pFM[i].szFamilyname, zFontFaceName);
529 anDiff[1] = abs(pFM[i].lEmHeight - nPointSize);
530 anDiff[2] = abs(pFM[i].usWeightClass - usWeightClass);
531 anDiff[3] = abs((pFM[i].fsSelection & 0x2f) - fsSelection);
532 if(anDiff[0] == 0)
533 {
534 nEmHeight = (int)pFM[i].lEmHeight;
535 nXHeight =(int)pFM[i].lXHeight;
536 if( (nIs & 0x01) == 0)
537 {
538 nIs = 1;
539 nIndex = i;
540 anMinDiff[1] = anDiff[1];
541 anMinDiff[2] = anDiff[2];
542 anMinDiff[3] = anDiff[3];
543 }
544 else if(anDiff[3] < anMinDiff[3])
545 {
546 nIndex = i;
547 anMinDiff[3] = anDiff[3];
548 }
549 else if(anDiff[2] < anMinDiff[2])
550 {
551 nIndex = i;
552 anMinDiff[2] = anDiff[2];
553 }
554 else if(anDiff[1] < anMinDiff[1])
555 {
556 nIndex = i;
557 anMinDiff[1] = anDiff[1];
558 }
559 anMinDiff[0] = 0;
560 }
561 else if(anDiff[0] < anMinDiff[0])
562 {
563 nIs = 2;
564 nIndex = i;
565 anMinDiff[3] = anDiff[3];
566 anMinDiff[2] = anDiff[2];
567 anMinDiff[1] = anDiff[1];
568 anMinDiff[0] = anDiff[0];
569 }
570 else if(anDiff[0] == anMinDiff[0])
571 {
572 if(anDiff[3] < anMinDiff[3])
573 {
574 nIndex = i;
575 anMinDiff[3] = anDiff[3];
576 nIs = 2;
577 }
578 else if(anDiff[2] < anMinDiff[2])
579 {
580 nIndex = i;
581 anMinDiff[2] = anDiff[2];
582 nIs = 2;
583 }
584 else if(anDiff[1] < anMinDiff[1])
585 {
586 nIndex = i;
587 anMinDiff[1] = anDiff[1];
588 nIs = 2;
589 }
590 }
591 }
592
593 //
594 // Fill in the FATTRS with the best match from FONTMETRICS
595 //
596 pFattrs->usRecordLength = sizeof(FATTRS); // sets size of structure
597 pFattrs->fsSelection = pFM[nIndex].fsSelection; // uses default selection
598 pFattrs->lMatch = pFM[nIndex].lMatch; // force match
599 pFattrs->idRegistry = pFM[nIndex].idRegistry; // uses default registry
600 pFattrs->usCodePage = pFM[nIndex].usCodePage; // code-page
601 if(pFM[nIndex].lMatch)
602 {
603 pFattrs->lMaxBaselineExt = pFM[nIndex].lMaxBaselineExt; // requested font height
604 pFattrs->lAveCharWidth = pFM[nIndex].lAveCharWidth ; // requested font width
605 }
606 else
607 {
608 pFattrs->lMaxBaselineExt = 0;
609 pFattrs->lAveCharWidth = 0;
610 }
611 pFattrs->fsType = 0;// pfm->fsType; /* uses default type */
612 pFattrs->fsFontUse = 0;
613
614 wxStrcpy(pFattrs->szFacename, pFM[nIndex].szFacename);
615 // Debug
616 strcpy(zFontFaceName, pFM[nIndex].szFacename);
617 strcpy(zFontFaceName, pFattrs->szFacename);
618
619 if(usWeightClass >= FWEIGHT_BOLD)
620 pFattrs->fsSelection |= FATTR_SEL_BOLD;
621 if(pFont->GetUnderlined())
622 pFattrs->fsSelection |= FATTR_SEL_UNDERSCORE;
623 if(fsSelection & FM_SEL_ITALIC)
624 pFattrs->fsSelection |= FATTR_SEL_ITALIC;
625 } // end of wxOS2SelectMatchingFontByName
626
627 wxFont wxCreateFontFromLogFont(
628 const LOGFONT* pLogFont
629 , const PFONTMETRICS pFM
630 , PFACENAMEDESC pFaceName
631 )
632 {
633 //
634 // Extract family from facename
635 //
636 int nFontFamily;
637
638 if (strcmp(pLogFont->szFacename, "Times New Roman") == 0)
639 nFontFamily = wxROMAN;
640 else if (strcmp(pLogFont->szFacename, "WarpSans") == 0)
641 nFontFamily = wxSWISS;
642 else if (strcmp(pLogFont->szFacename, "Script") == 0)
643 nFontFamily = wxSCRIPT;
644 else if (strcmp(pLogFont->szFacename, "Courier New") == 0)
645 nFontFamily = wxMODERN;
646 else
647 nFontFamily = wxSWISS;
648
649 //
650 // Weight and Style
651 //
652 int nFontWeight = wxNORMAL;
653
654 switch (pFaceName->usWeightClass)
655 {
656 case FWEIGHT_LIGHT:
657 nFontWeight = wxLIGHT;
658 break;
659
660 default:
661 case FWEIGHT_NORMAL:
662 nFontWeight = wxNORMAL;
663 break;
664
665 case FWEIGHT_BOLD:
666 nFontWeight = wxBOLD;
667 break;
668 }
669
670 int nFontStyle;
671
672 if(pLogFont->fsSelection & FATTR_SEL_ITALIC)
673 nFontStyle = wxITALIC;
674 else
675 nFontStyle = wxNORMAL;
676
677 bool bFontUnderline = (pLogFont->fsSelection & FATTR_SEL_UNDERSCORE);
678 wxString sFontFace = pLogFont->szFacename;
679 int nFontPoints = pFM->lEmHeight;
680 wxFontEncoding vFontEncoding;
681
682 switch (pLogFont->usCodePage)
683 {
684 default:
685 wxFAIL_MSG(wxT("unsupported charset"));
686 // fall through
687
688 case 850:
689 vFontEncoding = wxFONTENCODING_CP1252;
690 break;
691
692 case 1250:
693 vFontEncoding = wxFONTENCODING_CP1250;
694 break;
695
696 case 921:
697 vFontEncoding = wxFONTENCODING_CP1257;
698 break;
699
700 case 866:
701 vFontEncoding = wxFONTENCODING_CP1251;
702 break;
703
704 case 864:
705 vFontEncoding = wxFONTENCODING_CP1256;
706 break;
707
708 case 869:
709 vFontEncoding = wxFONTENCODING_CP1253;
710 break;
711
712 case 862:
713 vFontEncoding = wxFONTENCODING_CP1255;
714 break;
715
716 case 857:
717 vFontEncoding = wxFONTENCODING_CP1254;
718 break;
719
720 case 874:
721 vFontEncoding = wxFONTENCODING_CP437;
722 break;
723
724 case 437:
725 vFontEncoding = wxFONTENCODING_CP437;
726 break;
727 }
728
729 return wxFont( nFontPoints
730 ,nFontFamily
731 ,nFontStyle
732 ,nFontWeight
733 ,bFontUnderline
734 ,sFontFace
735 ,vFontEncoding
736 );
737 } // end of wxCreateFontFromLogFont
738
739 int wxGpiStrcmp(
740 char* s0
741 , char* s1
742 )
743 { int l0;
744 int l1;
745 int l;
746 int d;
747 int d1;
748 int i;
749 int rc;
750
751 rc = 0;
752 if(s0 == NULL)
753 {
754 if(s1 == NULL)
755 return 0;
756 else
757 return 32;
758 }
759 else if(s1 == NULL)
760 return 32;
761
762 l0 = strlen(s0);
763 l1 = strlen(s1);
764 l = l0;
765 if(l0 != l1)
766 {
767 rc++;
768 if(l1 < l0)
769 l = l1;
770 }
771 for(i=0;i<l;i++)
772 {
773 d = s0[i]-s1[i];
774 if(!d)
775 continue;
776 d1 = toupper(s0[i]) - toupper(s1[i]);
777 if(!d1)
778 continue;
779 rc += abs(d);
780 }
781 return rc;
782 }
783