version update
[goodguy/cinelerra.git] / cinelerra-5.1 / libzmpeg3 / xfont.C
1 #include <stdio.h>
2 #include <stdint.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <X11/Xutil.h>
6 #include <X11/Xlib.h>
7 #include "libzmpeg3.h"
8
9 /* use builtin data, or dynamically load font data from X instead */
10 //#define BUILTIN_FONT_DATA
11 /* generate static font data code */
12 //#define WRITE_FONT_DATA
13 #define MAX_SIZE 4
14
15 #ifdef WRITE_FONT_DATA
16 #undef BUILTIN_FONT_DATA
17 #endif
18
19 int zbitfont_t::font_refs = 0;
20
21
22 static inline int
23 font_index(int style, int pen_size, int italics, int size)
24 {
25   if( pen_size > 0 ) --pen_size;
26   return ((size*2 + italics)*2 + pen_size)*7 + style;
27 }
28
29 #if defined(BUILTIN_FONT_DATA)
30 /* using static builtin font data */
31
32 zbitfont_t *zmpeg3_t::
33 bitfont(int style,int pen_size,int italics,int size)
34 {
35   int k = font_index(style,pen_size,italics,size);
36   return zbitfont_t::fonts[k];
37 }
38
39 zbitfont_t *zwin_t::
40 chr_font(zchr_t *bp, int scale)
41 {
42   int size = bp->font_size + scale-1;
43   return bitfont(bp->font_style,bp->pen_size,bp->italics,size);
44 }
45
46 /* stubs */
47 void zbitfont_t::init_fonts() {}
48 void zbitfont_t::destroy_fonts() {}
49
50 #else
51 /* loading font data on the fly */
52
53 static int
54 init_xfont(zbitfont_t *font,char *font_name)
55 {
56   const char *display_name = ":0";
57   Display *display = XOpenDisplay(display_name);
58   if( !display ) return 1;
59   Font font_id = XLoadFont(display,font_name);
60   int ret = 0;
61   XFontStruct *font_struct = XQueryFont(display,font_id);
62   if( !font_struct ) ret = 1;
63   if( !ret ) {
64     int row_first = font_struct->min_char_or_byte2;
65     int row_last  = font_struct->max_char_or_byte2;
66     int row_count  = row_last-row_first + 1;
67     int col_first = font_struct->min_byte1;
68     int col_last  = font_struct->max_byte1;
69     XCharStruct *per_char = font_struct->per_char;
70     XCharStruct *bounds = per_char == NULL ? NULL : &font_struct->max_bounds;
71     int row_sz, sizeof_data;
72     Screen *screen = DefaultScreenOfDisplay(display);
73     int depth = DefaultDepthOfScreen(screen);
74     Visual *visual = DefaultVisualOfScreen(screen);
75     Window w = DefaultRootWindow(display);
76     font->nch = (col_last-col_first+1) * (row_last-row_first+1);
77     font->chrs = new zbitchar_t[font->nch];
78     font->idx = font->idy = font->imy = 0;
79     int inx = 0, iny = 0;
80   
81     XImage *image;
82     Pixmap pixmap;
83     int b1, b2, x, y, n;
84     unsigned int width, height;
85     GC gcb, gcw;
86     XGCValues gcv;
87   
88     gcv.function = GXcopy;
89     gcv.line_width = 1;
90     gcv.line_style = LineSolid;
91     gcv.font = font_id;
92     n = GCFunction|GCForeground|GCLineWidth|GCLineStyle|GCFont;
93     gcv.foreground = BlackPixelOfScreen(DefaultScreenOfDisplay(display));
94     gcb = XCreateGC(display,w,n,&gcv);
95     gcv.foreground = WhitePixelOfScreen(DefaultScreenOfDisplay(display));
96     gcw = XCreateGC(display,w,n,&gcv);
97   
98     for( b1=col_first; b1<=col_last; ++b1 ) {
99       for( b2=row_first; b2<=row_last; ++b2 ) {
100         int i = (b1-col_first)*row_count + b2-row_first;
101         zbitchar_t *cp = &font->chrs[i];
102         XChar2b ch;
103         ch.byte1 = b1;
104         ch.byte2 = b2;
105         cp->ch = (b1<<8) + b2;
106         if( per_char != NULL )
107           bounds = &per_char[i];
108         cp->left = bounds->lbearing;
109         cp->right = bounds->rbearing;
110         cp->ascent = bounds->ascent;
111         cp->decent = bounds->descent;
112         width  = cp->right - cp->left;
113         height = cp->ascent + cp->decent;
114         if( cp->ascent > font->imy ) font->imy = cp->ascent;
115         if( cp->decent > iny ) iny = cp->decent;
116         row_sz = (width+7) / 8;
117         sizeof_data = row_sz * height;
118         if( sizeof_data > 0 ) {
119           char *data = (char*)malloc(sizeof_data);
120           if( width > 0 ) { font->idx += width;  ++inx; }
121           memset(&data[0],0,sizeof_data);
122           x = -cp->left;  y = cp->ascent;
123           pixmap = XCreatePixmap(display,w,width,height,depth);
124           XFillRectangle(display,pixmap,gcb,0,0,width,height);
125           XDrawString16(display,pixmap,gcw,x,y,&ch,1);
126           image = XCreateImage(display,visual,1,XYBitmap,0,
127              data,width,height,8,row_sz);
128           XGetSubImage(display,pixmap,0,0,width,height,1,
129              XYPixmap,image,0,0);
130           cp->bitmap = new uint8_t [sizeof_data];
131           memcpy(&cp->bitmap[0],&data[0],sizeof_data);
132           XFreePixmap(display,pixmap);
133           XDestroyImage(image);
134         }
135         else
136           cp->bitmap = 0;
137       }
138     }
139     XFreeGC(display,gcb);
140     XFreeGC(display,gcw);
141     XFreeFont(display,font_struct);
142     if( inx == 0 ) inx = 1;
143     font->idx = (font->idx + inx-1) / inx;
144     font->idy = font->imy + iny;
145   }
146   XCloseDisplay(display);
147   return ret;
148 }
149
150 static zbitfont_t *
151 get_xfont(int style, int pen_size, int italics, int size)
152 {
153   int serif = 0, prop = 0, casual = 0; // fst_default
154   switch( style ) {
155   case 1: serif = 1;  prop = 0;  casual = 0;  break; // fst_mono_serif
156   case 2: serif = 1;  prop = 1;  casual = 0;  break; // fst_prop_serif
157   case 3: serif = 0;  prop = 0;  casual = 0;  break; // fst_mono_sans
158   case 4: serif = 0;  prop = 1;  casual = 0;  break; // fst_prop_sans
159   case 5: serif = 1;  prop = 1;  casual = 1;  break; // fst_casual
160   }
161
162   const char *family, *slant;
163 #if 1
164   if( casual ) {
165     family = "adobe-utopia";
166     slant = italics ? "i" : "r";
167   }
168   if( serif == 0 ) {
169    family = prop == 0 ?
170      (slant = italics ? "o" : "r", "urw-nimbus mono l") :
171      (slant = italics ? "i" : "r", "urw-nimbus sans l");
172   }
173   else {
174    family = prop == 0 ?
175      (slant = italics ? "i" : "r", "bitstream-courier 10 pitch"):
176      (slant = italics ? "i" : "r", "bitstream-bitstream charter");
177   }
178 #else
179   if( casual ) {
180     family = "bitstream-bitstream vera serif";
181     slant = "r";
182   }
183   if( serif == 0 ) {
184    family = prop == 0 ?
185      (slant = italics ? "o" : "r", "bitstream-bitstream vera sans mono") :
186      (slant = italics ? "o" : "r", "bitstream-bitstream vera sans");
187   }
188   else {
189    family = prop == 0 ?
190      (slant = italics ? "i" : "r", "bitstream-courier 10 pitch"):
191      (slant = italics ? "i" : "r", "bitstream-bitstream charter");
192   }
193 #endif
194   const char *wght = pen_size > 1 ? "bold" : "medium";
195
196   // range expanded to account for scale
197   if( size < 0 ) size = 0;
198   if( size > MAX_SIZE ) size = MAX_SIZE;
199   int ptsz = 180;
200   switch( size ) {
201   case 0: ptsz =  48;  break; // very fsz_small
202   case 1: ptsz = 100;  break; // fsz_small
203   default:  case 2:    break; // fsz_normal
204   case 3: ptsz = 320;  break; // fsz_large
205   case 4: ptsz = 420;  break; // very fsz_large
206   };
207
208   char name[512];
209   sprintf(&name[0],"-%s-%s-%s-*-*-*-0-%d-%d-*-*-iso8859-1",
210     family, wght, slant, ptsz, ptsz);
211   zbitfont_t *font = new zbitfont_t();
212   if( init_xfont(font,&name[0]) ) {
213     delete font;  font = 0;
214   }
215   return font;
216 }
217
218 /* italics=2, pen_size=2, font_size=5, font_style=7 */
219 int zbitfont_t::total_fonts = 140;
220 zbitfont_t *zbitfont_t::fonts[140];
221
222 zbitfont_t *zmpeg3_t::
223 bitfont(int style,int pen_size,int italics,int size)
224 {
225   int k = font_index(style,pen_size,italics,size);
226   bitfont_t *font = bitfont_t::fonts[k];
227   if( !font ) {
228     font = get_xfont(style,pen_size,italics,size);
229     bitfont_t::fonts[k] = font;
230   }
231   return font;
232 }
233
234 zbitfont_t *zwin_t::
235 chr_font(zchr_t *bp, int scale)
236 {
237   int size = bp->font_size + scale-1;
238   return bitfont(bp->font_style,bp->pen_size,bp->italics,size);
239 }
240
241 #if 0
242 void zbitfont_t::
243 init_fonts()
244 {
245   if( !font_refs )
246     for( int i=0; i<total_fonts; ++i ) fonts[i] = 0;
247   ++font_refs;
248 }
249
250 void zbitfont_t::
251 destroy_fonts()
252 {
253   if( font_refs > 0 ) --font_refs;
254   if( font_refs > 0 ) return;
255   for( int i=0; i<total_fonts; ++i )
256     if( fonts[i] ) { delete fonts[i];  fonts[i] = 0; }
257 }
258 #else
259 void zbitfont_t::init_fonts() {}
260 void zbitfont_t::destroy_fonts() {}
261
262 zstatic_init_t::
263 static_init_t()
264 {
265   for( int i=0; i<total_fonts; ++i ) fonts[i] = 0;
266 }
267 zstatic_init_t::
268 ~static_init_t()
269 {
270   for( int i=0; i<total_fonts; ++i )
271     if( fonts[i] ) { delete fonts[i];  fonts[i] = 0; }
272 }
273
274 zstatic_init_t static_init;
275
276 #endif
277 #endif
278
279 #if defined(WRITE_FONT_DATA)
280 /* generate code for builtin font initialization */
281
282 static int
283 write_font(int fno, zbitfont_t *font)
284 {
285   char font_var[512];
286   
287   sprintf(&font_var[0],"font%02d",fno);
288   printf("#include \"libzmpeg3.h\"\n\n");
289   zbitchar_t *cp = font->chrs;
290   for( int i=0; i<font->nch; ++i,++cp ) {
291     int sizeof_data = (cp->right-cp->left+7)/8 * (cp->ascent+cp->decent);
292     if( sizeof_data > 0 ) {
293       printf("static uint8_t %s_pix%04x[] = {\n",font_var,i);
294       uint8_t *bp = cp->bitmap;
295       int j = 0;
296       while( j < sizeof_data ) {
297         if( (j&7) == 0 ) printf("  ");
298         printf("0x%02x,",*bp++);
299         if( (++j&7) == 0 ) printf("\n");
300       }
301       if( (j&7) != 0 ) printf("\n");
302       printf("};\n");
303     }
304   }
305   printf("\n");
306
307   printf("static zbitchar_t %s_chrs[] = {\n",font_var);
308   cp = font->chrs;
309   for( int i=0; i<font->nch; ++i,++cp ) {
310     printf("  { 0x%04x, %2d, %2d, %2d, %2d, ",
311       cp->ch,cp->left,cp->right,cp->ascent,cp->decent);
312     int sizeof_data = (cp->right-cp->left+7)/8 * (cp->ascent+cp->decent);
313     if( sizeof_data > 0 )
314       printf("&%s_pix%04x[0] },\n",font_var,i);
315     else
316       printf("0 },\n");
317   }
318   printf("};\n");
319   printf("\n");
320   
321   printf("static zbitfont_t %s = { &%s_chrs[0], %d, %d, %d, %d, };\n",
322     font_var,font_var,font->nch,font->idx,font->idy,font->imy);
323   printf("\n");
324   return 0;
325 }
326
327 int main(int ac, char **av)
328 {
329   int fno = 0;
330   for( int size=0; size<=MAX_SIZE; ++size ) {
331     for( int italics=0; italics<=1; ++italics ) {
332       for( int pen_size=1; pen_size<=2; ++pen_size ) {
333         for( int font_style=0; font_style<=6; ++font_style ) {
334           zbitfont_t *font = get_xfont(font_style, pen_size, italics, size);
335           write_font(++fno, font);
336           delete font;
337         }
338       }
339     }
340   }
341   fno = 0;
342   printf("zbitfont_t *zbitfont_t::fonts[] = {\n");
343   for( int size=0; size<=MAX_SIZE; ++size ) {
344     for( int italics=0; italics<=1; ++italics ) {
345       for( int pen_size=1; pen_size<=2; ++pen_size ) {
346         for( int font_style=0; font_style<=6; ++font_style ) {
347           if( (fno&7) == 0 ) printf("  ");
348           printf("&font%02d,",++fno);
349           if( (fno&7) == 0 ) printf("\n");
350         }
351       }
352     }
353   }
354   if( (fno&7) != 0 ) printf("\n");
355   printf("};\n");
356   printf("\n");
357   printf("int zbitfont_t::total_fonts = %d;\n",fno);
358   printf("\n");
359   return 0;
360 }
361
362 #endif
363
364 #if 0
365 /* attach to end of output for testing */
366 int main(int ac, char **av)
367 {
368   int sz = 0;
369   for( int i=0; i<zbitfont_t::total_fonts; ++i ) {
370     zbitfont_t *font = zbitfont_t::fonts[i];
371     for( int ch=0; ch<font->nch; ++ch ) {
372       zbitchar_t *cp = &font->chrs[ch];
373       sz += 16 + (cp->ascent+cp->decent)*((cp->right-cp->left+7)/8);
374     }
375     sz += 20;
376   }
377   printf(" %d bytes\n",sz);
378   zbitchar_t *cp = &font84.chrs['y'];
379   uint8_t *bmap = cp->bitmap;
380   int wd = cp->right - cp->left;
381   int ht = cp->ascent + cp->decent;
382   int wsz = (wd+7) / 8;
383   for( int iy=0; iy<ht; ++iy ) {
384     uint8_t *row = &bmap[iy*wsz];
385     for( int ix=0; ix<wd; ++ix ) {
386       int ch = ((row[ix>>3] >> (ix&7)) & 1) ?  'x' : ' ';
387       printf("%c",ch);
388     }
389     printf("\n");
390   }
391   return 0;
392 }
393 #endif