Added the minmax.h header (VC6).
[wine] / graphics / x11drv / codepage.c
1 /*
2  * X11 codepage handling
3  *
4  * Copyright 2000 Hidenori Takeshima <hidenori@a2.ctktv.ne.jp>
5  */
6
7 #include "config.h"
8
9 #include "ts_xlib.h"
10
11 #include <math.h>
12
13 #include "windef.h"
14 #include "winnls.h"
15 #include "heap.h"
16 #include "x11font.h"
17 #include "debugtools.h"
18
19 DEFAULT_DEBUG_CHANNEL(text);
20
21 /***********************************************************************
22  *           IsLegalDBCSChar for cp932/936/949/950/euc
23  */
24 static inline
25 int IsLegalDBCSChar_cp932( BYTE lead, BYTE trail )
26 {
27     return ( ( ( lead >= (BYTE)0x81 && lead <= (BYTE)0x9f ) ||
28                ( lead >= (BYTE)0xe0 && lead <= (BYTE)0xfc ) ) &&
29              ( ( trail >= (BYTE)0x40 && trail <= (BYTE)0x7e ) ||
30                ( trail >= (BYTE)0x80 && trail <= (BYTE)0xfc ) ) );
31 }
32
33 static inline
34 int IsLegalDBCSChar_cp936( BYTE lead, BYTE trail )
35 {
36     return ( ( lead >= (BYTE)0x81 && lead <= (BYTE)0xfe ) &&
37              ( trail >= (BYTE)0x40 && trail <= (BYTE)0xfe ) );
38 }
39
40 static inline
41 int IsLegalDBCSChar_cp949( BYTE lead, BYTE trail )
42 {
43     return ( ( lead >= (BYTE)0x81 && lead <= (BYTE)0xfe ) &&
44              ( trail >= (BYTE)0x41 && trail <= (BYTE)0xfe ) );
45 }
46
47 static inline
48 int IsLegalDBCSChar_cp950( BYTE lead, BYTE trail )
49 {
50     return (   ( lead >= (BYTE)0x81 && lead <= (BYTE)0xfe ) &&
51              ( ( trail >= (BYTE)0x40 && trail <= (BYTE)0x7e ) ||
52                ( trail >= (BYTE)0xa1 && trail <= (BYTE)0xfe ) ) );
53 }
54
55 static inline
56 int IsLegalDBCSChar_euc( BYTE lead, BYTE trail )
57 {
58     return ( ( lead >= (BYTE)0xa1 && lead <= (BYTE)0xfe ) &&
59              ( trail >= (BYTE)0xa1 && trail <= (BYTE)0xfe ) );
60 }
61
62
63 /***********************************************************************
64  *           DBCSCharToXChar2b for cp932/euc
65  */
66
67 static inline
68 void DBCSCharToXChar2b_cp932( XChar2b* pch, BYTE lead, BYTE trail )
69 {
70     unsigned int  high, low;
71
72     high = (unsigned int)lead;
73     low = (unsigned int)trail;
74
75     if ( high <= 0x9f )
76         high = (high<<1) - 0xe0;
77     else
78         high = (high<<1) - 0x160;
79     if ( low < 0x9f )
80     {
81         high --;
82         if ( low < 0x7f )
83             low -= 0x1f;
84         else
85             low -= 0x20;
86     }
87     else
88     {
89         low -= 0x7e;
90     }
91
92     pch->byte1 = (unsigned char)high;
93     pch->byte2 = (unsigned char)low;
94 }
95
96 static inline
97 void DBCSCharToXChar2b_euc( XChar2b* pch, BYTE lead, BYTE trail )
98 {
99     pch->byte1 = lead & (BYTE)0x7f;
100     pch->byte2 = trail & (BYTE)0x7f;
101 }
102
103
104
105
106 static WORD X11DRV_enum_subfont_charset_normal( UINT index )
107 {
108     return DEFAULT_CHARSET;
109 }
110
111 static WORD X11DRV_enum_subfont_charset_cp932( UINT index )
112 {
113     switch ( index )
114     {
115     case 0: return X11FONT_JISX0201_CHARSET;
116     case 1: return X11FONT_JISX0212_CHARSET;
117     }
118
119     return DEFAULT_CHARSET;
120 }
121
122 static WORD X11DRV_enum_subfont_charset_cp936( UINT index )
123 {
124     switch ( index )
125     {
126     case 0: return ANSI_CHARSET;
127     }
128
129     return DEFAULT_CHARSET;
130 }
131
132 static WORD X11DRV_enum_subfont_charset_cp949( UINT index )
133 {
134     switch ( index )
135     {
136     case 0: return ANSI_CHARSET;
137     }
138
139     return DEFAULT_CHARSET;
140 }
141
142 static WORD X11DRV_enum_subfont_charset_cp950( UINT index )
143 {
144     FIXME( "please implement X11DRV_enum_subfont_charset_cp950!\n" );
145     return DEFAULT_CHARSET;
146 }
147
148
149 static XChar2b* X11DRV_unicode_to_char2b_sbcs( fontObject* pfo,
150                                                LPCWSTR lpwstr, UINT count )
151 {
152     XChar2b *str2b;
153     UINT i;
154     BYTE *str;
155     UINT codepage = pfo->fi->codepage;
156     char ch = pfo->fs->default_char;
157
158     if (!(str2b = HeapAlloc( GetProcessHeap(), 0, count * sizeof(XChar2b) )))
159         return NULL;
160     if (!(str = HeapAlloc( GetProcessHeap(), 0, count )))
161     {
162         HeapFree( GetProcessHeap(), 0, str2b );
163         return NULL;
164     }
165
166     WideCharToMultiByte( codepage, 0, lpwstr, count, str, count, &ch, NULL );
167
168     for (i = 0; i < count; i++)
169     {
170         str2b[i].byte1 = 0;
171         str2b[i].byte2 = str[i];
172     }
173     HeapFree( GetProcessHeap(), 0, str );
174
175     return str2b;
176 }
177
178 static XChar2b* X11DRV_unicode_to_char2b_unicode( fontObject* pfo,
179                                                   LPCWSTR lpwstr, UINT count )
180 {
181     XChar2b *str2b;
182     UINT i;
183
184     if (!(str2b = HeapAlloc( GetProcessHeap(), 0, count * sizeof(XChar2b) )))
185         return NULL;
186
187     for (i = 0; i < count; i++)
188     {
189         str2b[i].byte1 = lpwstr[i] >> 8;
190         str2b[i].byte2 = lpwstr[i] & 0xff;
191     }
192
193     return str2b;
194 }
195
196 /* FIXME: handle jisx0212.1990... */
197 static XChar2b* X11DRV_unicode_to_char2b_cp932( fontObject* pfo,
198                                                 LPCWSTR lpwstr, UINT count )
199 {
200     XChar2b *str2b;
201     XChar2b *str2b_dst;
202     BYTE *str;
203     BYTE *str_src;
204     UINT i;
205     char ch = pfo->fs->default_char;
206
207     if (!(str2b = HeapAlloc( GetProcessHeap(), 0, count * sizeof(XChar2b) )))
208         return NULL;
209     if (!(str = HeapAlloc( GetProcessHeap(), 0, count*2 )))
210     {
211         HeapFree( GetProcessHeap(), 0, str2b );
212         return NULL;
213     }
214
215     /* handle jisx0212.1990... */
216     WideCharToMultiByte( 932, 0, lpwstr, count, str, count*2, &ch, NULL );
217
218     str_src = str;
219     str2b_dst = str2b;
220     for (i = 0; i < count; i++, str_src++, str2b_dst++)
221     {
222         if ( IsLegalDBCSChar_cp932( *str_src, *(str_src+1) ) )
223         {
224             DBCSCharToXChar2b_cp932( str2b_dst, *str_src, *(str_src+1) );
225             str_src++;
226         }
227         else
228         {
229             str2b_dst->byte1 = 0;
230             str2b_dst->byte2 = *str_src;
231         }
232     }
233
234     HeapFree( GetProcessHeap(), 0, str );
235
236     return str2b;
237 }
238
239
240 static XChar2b* X11DRV_unicode_to_char2b_cp936( fontObject* pfo,
241                                                 LPCWSTR lpwstr, UINT count )
242 {
243     XChar2b *str2b;
244     XChar2b *str2b_dst;
245     BYTE *str;
246     BYTE *str_src;
247     UINT i;
248     char ch = pfo->fs->default_char;
249
250     if (!(str2b = HeapAlloc( GetProcessHeap(), 0, count * sizeof(XChar2b) )))
251         return NULL;
252     if (!(str = HeapAlloc( GetProcessHeap(), 0, count*2 )))
253     {
254         HeapFree( GetProcessHeap(), 0, str2b );
255         return NULL;
256     }
257     WideCharToMultiByte( 936, 0, lpwstr, count, str, count*2, &ch, NULL );
258
259     str_src = str;
260     str2b_dst = str2b;
261     for (i = 0; i < count; i++, str_src++, str2b_dst++)
262     {
263         if ( IsLegalDBCSChar_cp936( *str_src, *(str_src+1) ) )
264         {
265             if ( IsLegalDBCSChar_euc( *str_src, *(str_src+1) ) )
266             {
267                 DBCSCharToXChar2b_euc( str2b_dst, *str_src, *(str_src+1) );
268             }
269             else
270             {
271                 /* FIXME */
272                 str2b_dst->byte1 = 0;
273                 str2b_dst->byte2 = 0;
274             }
275             str_src++;
276         }
277         else
278         {
279             str2b_dst->byte1 = 0;
280             str2b_dst->byte2 = *str_src;
281         }
282     }
283
284     HeapFree( GetProcessHeap(), 0, str );
285
286     return str2b;
287 }
288
289 static XChar2b* X11DRV_unicode_to_char2b_cp949( fontObject* pfo,
290                                                 LPCWSTR lpwstr, UINT count )
291 {
292     XChar2b *str2b;
293     XChar2b *str2b_dst;
294     BYTE *str;
295     BYTE *str_src;
296     UINT i;
297     char ch = pfo->fs->default_char;
298
299     if (!(str2b = HeapAlloc( GetProcessHeap(), 0, count * sizeof(XChar2b) )))
300         return NULL;
301     if (!(str = HeapAlloc( GetProcessHeap(), 0, count*2 )))
302     {
303         HeapFree( GetProcessHeap(), 0, str2b );
304         return NULL;
305     }
306     WideCharToMultiByte( 949, 0, lpwstr, count, str, count*2, &ch, NULL );
307
308     str_src = str;
309     str2b_dst = str2b;
310     for (i = 0; i < count; i++, str_src++, str2b_dst++)
311     {
312         if ( IsLegalDBCSChar_cp949( *str_src, *(str_src+1) ) )
313         {
314             if ( IsLegalDBCSChar_euc( *str_src, *(str_src+1) ) )
315             {
316                 DBCSCharToXChar2b_euc( str2b_dst, *str_src, *(str_src+1) );
317             }
318             else
319             {
320                 /* FIXME */
321                 str2b_dst->byte1 = 0;
322                 str2b_dst->byte2 = 0;
323             }
324             str_src++;
325         }
326         else
327         {
328             str2b_dst->byte1 = 0;
329             str2b_dst->byte2 = *str_src;
330         }
331     }
332
333     HeapFree( GetProcessHeap(), 0, str );
334
335     return str2b;
336 }
337
338
339 static XChar2b* X11DRV_unicode_to_char2b_cp950( fontObject* pfo,
340                                                 LPCWSTR lpwstr, UINT count )
341 {
342     FIXME( "please implement X11DRV_unicode_to_char2b_cp950!\n" );
343     return NULL;
344 }
345
346
347 static void X11DRV_DrawString_normal( fontObject* pfo, Display* pdisp,
348                                       Drawable d, GC gc, int x, int y,
349                                       XChar2b* pstr, int count )
350 {
351     TSXDrawString16( pdisp, d, gc, x, y, pstr, count );
352 }
353
354 static int X11DRV_TextWidth_normal( fontObject* pfo, XChar2b* pstr, int count )
355 {
356     return TSXTextWidth16( pfo->fs, pstr, count );
357 }
358
359 static void X11DRV_DrawText_normal( fontObject* pfo, Display* pdisp, Drawable d,
360                                     GC gc, int x, int y, XTextItem16* pitems,
361                                     int count )
362 {
363     TSXDrawText16( pdisp, d, gc, x, y, pitems, count );
364 }
365
366 static void X11DRV_TextExtents_normal( fontObject* pfo, XChar2b* pstr, int count,
367                                        int* pdir, int* pascent, int* pdescent,
368                                        int* pwidth )
369 {
370     XCharStruct info;
371
372     TSXTextExtents16( pfo->fs, pstr, count, pdir, pascent, pdescent, &info );
373     *pwidth = info.width;
374 }
375
376 static void X11DRV_GetTextMetricsA_normal( fontObject* pfo, LPTEXTMETRICA pTM )
377 {
378     LPIFONTINFO16 pdf = &pfo->fi->df;
379
380     if( ! pfo->lpX11Trans ) {
381       pTM->tmAscent = pfo->fs->ascent;
382       pTM->tmDescent = pfo->fs->descent;
383     } else {
384       pTM->tmAscent = pfo->lpX11Trans->ascent;
385       pTM->tmDescent = pfo->lpX11Trans->descent;
386     }
387
388     pTM->tmAscent *= pfo->rescale;
389     pTM->tmDescent *= pfo->rescale;
390
391     pTM->tmHeight = pTM->tmAscent + pTM->tmDescent;
392
393     pTM->tmAveCharWidth = pfo->foAvgCharWidth * pfo->rescale;
394     pTM->tmMaxCharWidth = pfo->foMaxCharWidth * pfo->rescale;
395
396     pTM->tmInternalLeading = pfo->foInternalLeading * pfo->rescale;
397     pTM->tmExternalLeading = pdf->dfExternalLeading * pfo->rescale;
398
399     pTM->tmStruckOut = (pfo->fo_flags & FO_SYNTH_STRIKEOUT )
400                         ? 1 : pdf->dfStrikeOut;
401     pTM->tmUnderlined = (pfo->fo_flags & FO_SYNTH_UNDERLINE )
402                         ? 1 : pdf->dfUnderline;
403
404     pTM->tmOverhang = 0;
405     if( pfo->fo_flags & FO_SYNTH_ITALIC ) 
406     {
407         pTM->tmOverhang += pTM->tmHeight/3;
408         pTM->tmItalic = 1;
409     } else 
410         pTM->tmItalic = pdf->dfItalic;
411
412     pTM->tmWeight = pdf->dfWeight;
413     if( pfo->fo_flags & FO_SYNTH_BOLD ) 
414     {
415         pTM->tmOverhang++; 
416         pTM->tmWeight += 100;
417     } 
418
419     pTM->tmFirstChar = pdf->dfFirstChar;
420     pTM->tmLastChar = pdf->dfLastChar;
421     pTM->tmDefaultChar = pdf->dfDefaultChar;
422     pTM->tmBreakChar = pdf->dfBreakChar;
423
424     pTM->tmCharSet = pdf->dfCharSet;
425     pTM->tmPitchAndFamily = pdf->dfPitchAndFamily;
426
427     pTM->tmDigitizedAspectX = pdf->dfHorizRes;
428     pTM->tmDigitizedAspectY = pdf->dfVertRes;
429 }
430
431
432
433 static
434 void X11DRV_DrawString_dbcs( fontObject* pfo, Display* pdisp,
435                              Drawable d, GC gc, int x, int y,
436                              XChar2b* pstr, int count )
437 {
438     XTextItem16 item;
439
440     item.chars = pstr;
441     item.delta = 0;
442     item.nchars = count;
443     item.font = None;
444     X11DRV_cptable[pfo->fi->cptable].pDrawText(
445                 pfo, pdisp, d, gc, x, y, &item, 1 );
446 }
447
448 static
449 int X11DRV_TextWidth_dbcs_2fonts( fontObject* pfo, XChar2b* pstr, int count )
450 {
451     int i;
452     int width;
453     int curfont;
454     fontObject* pfos[X11FONT_REFOBJS_MAX+1];
455
456     pfos[0] = XFONT_GetFontObject( pfo->prefobjs[0] );
457     pfos[1] = pfo;
458     if ( pfos[0] == NULL ) pfos[0] = pfo;
459
460     width = 0;
461     for ( i = 0; i < count; i++ )
462     {
463         curfont = ( pstr->byte1 != 0 ) ? 1 : 0;
464         width += TSXTextWidth16( pfos[curfont]->fs, pstr, 1 );
465         pstr ++;
466     }
467
468     return width;
469 }
470
471 static
472 void X11DRV_DrawText_dbcs_2fonts( fontObject* pfo, Display* pdisp, Drawable d,
473                                   GC gc, int x, int y, XTextItem16* pitems,
474                                   int count )
475 {
476     int i, nitems, prevfont = -1, curfont;
477     XChar2b* pstr;
478     XTextItem16* ptibuf;
479     XTextItem16* pti;
480     fontObject* pfos[X11FONT_REFOBJS_MAX+1];
481
482     pfos[0] = XFONT_GetFontObject( pfo->prefobjs[0] );
483     pfos[1] = pfo;
484     if ( pfos[0] == NULL ) pfos[0] = pfo;
485
486     nitems = 0;
487     for ( i = 0; i < count; i++ )
488         nitems += pitems->nchars;
489     ptibuf = HeapAlloc( GetProcessHeap(), 0, sizeof(XTextItem16) * nitems );
490     if ( ptibuf == NULL )
491         return; /* out of memory */
492
493     pti = ptibuf;
494     while ( count-- > 0 )
495     {
496         pti->chars = pstr = pitems->chars;
497         pti->delta = pitems->delta;
498         pti->font = None;
499         for ( i = 0; i < pitems->nchars; i++, pstr++ )
500         {
501             curfont = ( pstr->byte1 != 0 ) ? 1 : 0;
502             if ( curfont != prevfont )
503             {
504                 if ( pstr != pti->chars )
505                 {
506                     pti->nchars = pstr - pti->chars;
507                     pti ++;
508                     pti->chars = pstr;
509                     pti->delta = 0;
510                 }
511                 pti->font = pfos[curfont]->fs->fid;
512                 prevfont = curfont;
513             }
514         }
515         pti->nchars = pstr - pti->chars;
516         pitems ++; pti ++;
517     }
518     TSXDrawText16( pdisp, d, gc, x, y, ptibuf, pti - ptibuf );
519     HeapFree( GetProcessHeap(), 0, ptibuf );
520 }
521
522 static
523 void X11DRV_TextExtents_dbcs_2fonts( fontObject* pfo, XChar2b* pstr, int count,
524                                      int* pdir, int* pascent, int* pdescent,
525                                      int* pwidth )
526 {
527     XCharStruct info;
528     int ascent, descent, width;
529     int i;
530     int curfont;
531     fontObject* pfos[X11FONT_REFOBJS_MAX+1];
532
533     pfos[0] = XFONT_GetFontObject( pfo->prefobjs[0] );
534     pfos[1] = pfo;
535     if ( pfos[0] == NULL ) pfos[0] = pfo;
536
537     width = 0;
538     *pascent = 0;
539     *pdescent = 0;
540     for ( i = 0; i < count; i++ )
541     {
542         curfont = ( pstr->byte1 != 0 ) ? 1 : 0;
543         TSXTextExtents16( pfos[curfont]->fs, pstr, 1, pdir,
544                           &ascent, &descent, &info );
545         if ( *pascent < ascent ) *pascent = ascent;
546         if ( *pdescent < descent ) *pdescent = descent;
547         width += info.width;
548
549         pstr ++;
550     }
551
552     *pwidth = width;
553 }
554
555 static void X11DRV_GetTextMetricsA_cp932( fontObject* pfo, LPTEXTMETRICA pTM )
556 {
557     fontObject* pfo_ansi = XFONT_GetFontObject( pfo->prefobjs[0] );
558     LPIFONTINFO16 pdf = &pfo->fi->df;
559     LPIFONTINFO16 pdf_ansi;
560
561     pdf_ansi = ( pfo_ansi != NULL ) ? (&pfo_ansi->fi->df) : pdf;
562
563     if( ! pfo->lpX11Trans ) {
564       pTM->tmAscent = pfo->fs->ascent;
565       pTM->tmDescent = pfo->fs->descent;
566     } else {
567       pTM->tmAscent = pfo->lpX11Trans->ascent;
568       pTM->tmDescent = pfo->lpX11Trans->descent;
569     }
570
571     pTM->tmAscent *= pfo->rescale;
572     pTM->tmDescent *= pfo->rescale;
573
574     pTM->tmHeight = pTM->tmAscent + pTM->tmDescent;
575
576     if ( pfo_ansi != NULL )
577     {
578         pTM->tmAveCharWidth = floor((pfo_ansi->foAvgCharWidth * 2.0 + pfo->foAvgCharWidth) / 3.0 * pfo->rescale + 0.5);
579         pTM->tmMaxCharWidth = max(pfo_ansi->foMaxCharWidth, pfo->foMaxCharWidth) * pfo->rescale;
580     }
581     else
582     {
583         pTM->tmAveCharWidth = floor((pfo->foAvgCharWidth * pfo->rescale + 1.0) / 2.0);
584         pTM->tmMaxCharWidth = pfo->foMaxCharWidth * pfo->rescale;
585     }
586
587     pTM->tmInternalLeading = pfo->foInternalLeading * pfo->rescale;
588     pTM->tmExternalLeading = pdf->dfExternalLeading * pfo->rescale;
589
590     pTM->tmStruckOut = (pfo->fo_flags & FO_SYNTH_STRIKEOUT )
591                         ? 1 : pdf->dfStrikeOut;
592     pTM->tmUnderlined = (pfo->fo_flags & FO_SYNTH_UNDERLINE )
593                         ? 1 : pdf->dfUnderline;
594
595     pTM->tmOverhang = 0;
596     if( pfo->fo_flags & FO_SYNTH_ITALIC ) 
597     {
598         pTM->tmOverhang += pTM->tmHeight/3;
599         pTM->tmItalic = 1;
600     } else 
601         pTM->tmItalic = pdf->dfItalic;
602
603     pTM->tmWeight = pdf->dfWeight;
604     if( pfo->fo_flags & FO_SYNTH_BOLD ) 
605     {
606         pTM->tmOverhang++; 
607         pTM->tmWeight += 100;
608     } 
609
610     pTM->tmFirstChar = pdf_ansi->dfFirstChar;
611     pTM->tmLastChar = pdf_ansi->dfLastChar;
612     pTM->tmDefaultChar = pdf_ansi->dfDefaultChar;
613     pTM->tmBreakChar = pdf_ansi->dfBreakChar;
614
615     pTM->tmCharSet = pdf->dfCharSet;
616     pTM->tmPitchAndFamily = pdf->dfPitchAndFamily;
617
618     pTM->tmDigitizedAspectX = pdf->dfHorizRes;
619     pTM->tmDigitizedAspectY = pdf->dfVertRes;
620 }
621
622
623
624
625
626 const X11DRV_CP X11DRV_cptable[X11DRV_CPTABLE_COUNT] =
627 {
628     { /* SBCS */
629         X11DRV_enum_subfont_charset_normal,
630         X11DRV_unicode_to_char2b_sbcs,
631         X11DRV_DrawString_normal,
632         X11DRV_TextWidth_normal,
633         X11DRV_DrawText_normal,
634         X11DRV_TextExtents_normal,
635         X11DRV_GetTextMetricsA_normal,
636     },
637     { /* UNICODE */
638         X11DRV_enum_subfont_charset_normal,
639         X11DRV_unicode_to_char2b_unicode,
640         X11DRV_DrawString_normal,
641         X11DRV_TextWidth_normal,
642         X11DRV_DrawText_normal,
643         X11DRV_TextExtents_normal,
644         X11DRV_GetTextMetricsA_normal,
645     },
646     { /* CP932 */
647         X11DRV_enum_subfont_charset_cp932,
648         X11DRV_unicode_to_char2b_cp932,
649         X11DRV_DrawString_dbcs,
650         X11DRV_TextWidth_dbcs_2fonts,
651         X11DRV_DrawText_dbcs_2fonts,
652         X11DRV_TextExtents_dbcs_2fonts,
653         X11DRV_GetTextMetricsA_cp932,
654     },
655     { /* CP936 */
656         X11DRV_enum_subfont_charset_cp936,
657         X11DRV_unicode_to_char2b_cp936,
658         X11DRV_DrawString_dbcs,
659         X11DRV_TextWidth_dbcs_2fonts,
660         X11DRV_DrawText_dbcs_2fonts,
661         X11DRV_TextExtents_dbcs_2fonts,
662         X11DRV_GetTextMetricsA_normal, /* FIXME */
663     },
664     { /* CP949 */
665         X11DRV_enum_subfont_charset_cp949,
666         X11DRV_unicode_to_char2b_cp949,
667         X11DRV_DrawString_dbcs,
668         X11DRV_TextWidth_dbcs_2fonts,
669         X11DRV_DrawText_dbcs_2fonts,
670         X11DRV_TextExtents_dbcs_2fonts,
671         X11DRV_GetTextMetricsA_normal, /* FIXME */
672     },
673     { /* CP950 */
674         X11DRV_enum_subfont_charset_cp950,
675         X11DRV_unicode_to_char2b_cp950,
676         X11DRV_DrawString_normal, /* FIXME */
677         X11DRV_TextWidth_normal, /* FIXME */
678         X11DRV_DrawText_normal, /* FIXME */
679         X11DRV_TextExtents_normal, /* FIXME */
680         X11DRV_GetTextMetricsA_normal, /* FIXME */
681     },
682 };