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