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