]> git.saurik.com Git - wxWidgets.git/blob - src/os2/fontutil.cpp
fix assertion failure when string transform is requested before entry is set
[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 // 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, wxT(";"));
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, wxT("%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 << wxT(';') << facename;
91
92 if (charset != 850)
93 {
94 sStr << wxT(';') << 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, wxT("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 wxStrlcpy((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 // multiply first to avoid getting vSizef.cx,cy = 0 since fxPointSize
285 // is normally < 72 and FontResolution is typically ca. 100
286 vSizef.cx = (FIXED)( (fxPointSize * lXFontResolution) / 72 );
287 vSizef.cy = (FIXED)( (fxPointSize * lYFontResolution) / 72 );
288
289 if (pFattrs)
290 {
291 pFattrs->lMaxBaselineExt = MAKELONG( HIUSHORT( vSizef.cy ), 0 );
292 pFattrs->lAveCharWidth = MAKELONG( HIUSHORT( vSizef.cx ), 0 );
293 }
294 WinReleasePS(hPS);
295
296 } // end of wxConvertVectorPointSize
297
298 void wxFillLogFont( LOGFONT* pFattrs, // OS2 GPI FATTRS
299 PFACENAMEDESC pFaceName,
300 HPS* phPS,
301 bool* pbInternalPS,
302 long* pflId,
303 wxString& sFaceName,
304 wxFont* pFont )
305 {
306 LONG lNumFonts = 0L; // For system font count
307 ERRORID vError; // For logging API errors
308 LONG lTemp = 0L;
309 bool bInternalPS = false; // if we have to create one
310 PFONTMETRICS pFM = NULL;
311
312 //
313 // Initial house cleaning to free data buffers and ensure we have a
314 // functional PS to work with
315 //
316 if (!*phPS)
317 {
318 *phPS = ::WinGetPS(HWND_DESKTOP);
319 bInternalPS = true;
320 }
321
322 //
323 // Determine the number of fonts.
324 //
325 if((lNumFonts = ::GpiQueryFonts( *phPS
326 ,QF_PUBLIC | QF_PRIVATE
327 ,NULL
328 ,&lTemp
329 ,(LONG) sizeof(FONTMETRICS)
330 ,NULL
331 )) < 0L)
332 {
333 ERRORID vError;
334 wxString sError;
335
336 vError = ::WinGetLastError(wxGetInstance());
337 sError = wxPMErrorToStr(vError);
338 return;
339 }
340
341 //
342 // Allocate space for the font metrics.
343 //
344 pFM = new FONTMETRICS[lNumFonts + 1];
345
346 //
347 // Retrieve the font metrics.
348 //
349 lTemp = lNumFonts;
350 lTemp = ::GpiQueryFonts( *phPS
351 ,QF_PUBLIC
352 ,NULL
353 ,&lTemp
354 ,(LONG) sizeof(FONTMETRICS)
355 ,pFM
356 );
357 pFont->SetFM( pFM
358 ,(int)lNumFonts
359 );
360
361 //
362 // Initialize FATTR and FACENAMEDESC
363 //
364 pFattrs->usRecordLength = sizeof(FATTRS);
365 pFattrs->fsFontUse = FATTR_FONTUSE_OUTLINE; // only outline fonts allowed
366 pFattrs->fsType = 0;
367 pFattrs->lMaxBaselineExt = pFattrs->lAveCharWidth = 0;
368 pFattrs->idRegistry = 0;
369 pFattrs->lMatch = 0;
370
371 pFaceName->usSize = sizeof(FACENAMEDESC);
372 pFaceName->usWeightClass = FWEIGHT_DONT_CARE;
373 pFaceName->usWidthClass = FWIDTH_DONT_CARE;
374 pFaceName->usReserved = 0;
375 pFaceName->flOptions = 0;
376
377 //
378 // This does the actual selection of fonts
379 //
380 wxOS2SelectMatchingFontByName( pFattrs
381 ,pFaceName
382 ,pFM
383 ,(int)lNumFonts
384 ,pFont
385 );
386 //
387 // We should now have the correct FATTRS set with the selected
388 // font, so now we need to generate an ID
389 //
390 long lNumLids = ::GpiQueryNumberSetIds(*phPS);
391
392 if(lNumLids )
393 {
394 long alTypes[255];
395 STR8 azNames[255];
396 long alIds[255];
397
398 memset(alIds, 0, sizeof(long) * 255);
399 if(!::GpiQuerySetIds( *phPS
400 ,lNumLids
401 ,alTypes
402 ,azNames
403 ,alIds
404 ))
405 {
406 if (bInternalPS)
407 ::WinReleasePS(*phPS);
408 return;
409 }
410 if (*pflId == 0L)
411 *pflId = 1L;
412 for(unsigned long LCNum = 0; LCNum < (unsigned long)lNumLids; LCNum++)
413 if(alIds[LCNum] == *pflId)
414 ++*pflId;
415 if(*pflId > 254) // wow, no id available!
416 {
417 if (bInternalPS)
418 ::WinReleasePS(*phPS);
419 return;
420 }
421 }
422 else
423 *pflId = 1L;
424 //
425 // Release and delete the current font
426 //
427 ::GpiSetCharSet(*phPS, LCID_DEFAULT);/* release the font before deleting */
428 ::GpiDeleteSetId(*phPS, 1L); /* delete the logical font */
429
430 //
431 // Now build a facestring
432 //
433 char zFacename[128];
434
435 strcpy(zFacename, pFattrs->szFacename);
436
437 if(::GpiQueryFaceString( *phPS
438 ,zFacename
439 ,pFaceName
440 ,FACESIZE
441 ,pFattrs->szFacename
442 ) == GPI_ERROR)
443 {
444 vError = ::WinGetLastError(vHabmain);
445 }
446 sFaceName = (wxChar*)zFacename;
447 *pbInternalPS = bInternalPS;
448
449 //
450 // That's it, we now have everything we need to actually create the font
451 //
452 } // end of wxFillLogFont
453
454 void wxOS2SelectMatchingFontByName(
455 PFATTRS pFattrs
456 , PFACENAMEDESC pFaceName
457 , PFONTMETRICS pFM
458 , int nNumFonts
459 , const wxFont* pFont
460 )
461 {
462 int i;
463 int nPointSize;
464 int nIs;
465 int nMinDiff0;
466 int anDiff[16];
467 int anMinDiff[16];
468 int nIndex = 0;
469 wxChar zFontFaceName[FACESIZE];
470 wxString sFaceName;
471 USHORT usWeightClass;
472 int fsSelection = 0;
473
474 nMinDiff0 = 0xf000;
475 for(i = 0;i < 16; i++)
476 anMinDiff[i] = nMinDiff0;
477
478 switch (pFont->GetFamily())
479 {
480 case wxSCRIPT:
481 sFaceName = wxT("Tms Rmn");
482 break;
483
484 case wxDECORATIVE:
485 sFaceName = wxT("WarpSans");
486 break;
487
488 case wxROMAN:
489 sFaceName = wxT("Tms Rmn");
490 break;
491
492 case wxTELETYPE:
493 sFaceName = wxT("Courier") ;
494 break;
495
496 case wxMODERN:
497 sFaceName = wxT("System VIO") ;
498 break;
499
500 case wxSWISS:
501 sFaceName = wxT("Helv") ;
502 break;
503
504 case wxDEFAULT:
505 default:
506 sFaceName = wxT("System VIO") ;
507 }
508
509 switch (pFont->GetWeight())
510 {
511 default:
512 wxFAIL_MSG(wxT("unknown font weight"));
513 // fall through
514 usWeightClass = FWEIGHT_DONT_CARE;
515 break;
516
517 case wxNORMAL:
518 usWeightClass = FWEIGHT_NORMAL;
519 break;
520
521 case wxLIGHT:
522 usWeightClass = FWEIGHT_LIGHT;
523 break;
524
525 case wxBOLD:
526 usWeightClass = FWEIGHT_BOLD;
527 break;
528
529 case wxFONTWEIGHT_MAX:
530 usWeightClass = FWEIGHT_ULTRA_BOLD;
531 break;
532 }
533 pFaceName->usWeightClass = usWeightClass;
534
535 switch (pFont->GetStyle())
536 {
537 case wxITALIC:
538 case wxSLANT:
539 fsSelection = FM_SEL_ITALIC;
540 pFaceName->flOptions = FTYPE_ITALIC;
541 break;
542
543 default:
544 wxFAIL_MSG(wxT("unknown font slant"));
545 // fall through
546
547 case wxNORMAL:
548 fsSelection = 0;
549 break;
550 }
551
552 wxStrlcpy(zFontFaceName, sFaceName.c_str(), WXSIZEOF(zFontFaceName));
553 nPointSize = pFont->GetPointSize();
554
555 //
556 // Matching logic to find the right FM struct
557 //
558 nIndex = 0;
559 for(i = 0, nIs = 0; i < nNumFonts; i++)
560 {
561 anDiff[0] = wxGpiStrcmp((wxChar*)pFM[i].szFacename, zFontFaceName);
562 anDiff[1] = abs(pFM[i].lEmHeight - nPointSize);
563 anDiff[2] = abs(pFM[i].usWeightClass - usWeightClass);
564 anDiff[3] = abs((pFM[i].fsSelection & 0x2f) - fsSelection);
565 if(anDiff[0] == 0)
566 {
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 }