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