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