84626082063fb9f1170945ad81ae03f4b78bcc88
[platform/upstream/groff.git] / src / devices / xditview / font.c
1 /*
2  * font.c
3  *
4  * map dvi fonts to X fonts
5  */
6
7 #include <config.h>
8
9 #include <X11/Xos.h>
10 #include <X11/IntrinsicP.h>
11 #include <X11/StringDefs.h>
12 #include <stdio.h>
13 #include <ctype.h>
14 #include <stdlib.h>
15
16 #include "DviP.h"
17 #include "XFontName.h"
18 #include "font.h"
19
20 /* forward reference */
21 static void DisposeFontSizes(DviWidget, DviFontSizeList *);
22
23 static char *
24 savestr (const char *s)
25 {
26         char    *n;
27
28         if (!s)
29                 return 0;
30         n = XtMalloc (strlen (s) + 1);
31         if (n)
32                 strcpy (n, s);
33         return n;
34 }
35
36 static DviFontList *
37 LookupFontByPosition (DviWidget dw, int position)
38 {
39         DviFontList     *f;
40
41         for (f = dw->dvi.fonts; f; f = f->next)
42                 if (f->dvi_number == position)
43                         break;
44         return f;
45 }
46
47 int
48 MaxFontPosition (DviWidget dw)
49 {
50         DviFontList     *f;
51         int n = -1;
52
53         for (f = dw->dvi.fonts; f; f = f->next)
54                 if (f->dvi_number > n)
55                         n = f->dvi_number;
56         return n;
57 }
58
59 static DviFontSizeList *
60 LookupFontSizeBySize (DviWidget dw, DviFontList *f, int size)
61 {
62         DviFontSizeList *fs, *best = 0, *smallest = 0;
63         int             bestsize = 0;
64         XFontName       fontName;
65         unsigned int    fontNameAttributes;
66         char            fontNameString[2048];
67         int             decipointsize;
68         
69         if (f->scalable) {
70                 decipointsize = (10*size)/dw->dvi.sizescale;
71                 for (best = f->sizes; best; best = best->next)
72                         if (best->size == decipointsize)
73                                 return best;
74                 best = (DviFontSizeList *) XtMalloc(sizeof *best);
75                 best->next = f->sizes;
76                 best->size = decipointsize;
77                 f->sizes = best;
78                 XParseFontName (f->x_name, &fontName, &fontNameAttributes);
79                 fontNameAttributes &= ~(FontNamePixelSize|FontNameAverageWidth);
80                 fontNameAttributes |= FontNameResolutionX;
81                 fontNameAttributes |= FontNameResolutionY;
82                 fontNameAttributes |= FontNamePointSize;
83                 fontName.ResolutionX = dw->dvi.display_resolution;
84                 fontName.ResolutionY = dw->dvi.display_resolution;
85                 fontName.PointSize = decipointsize;
86                 XFormatFontName (&fontName, fontNameAttributes, fontNameString);
87                 best->x_name = savestr (fontNameString);
88                 best->doesnt_exist = 0;
89                 best->font = 0;
90                 return best;
91         }
92         for (fs = f->sizes; fs; fs=fs->next) {
93                 if (dw->dvi.sizescale*fs->size <= 10*size
94                     && fs->size >= bestsize) {
95                         best = fs;
96                         bestsize = fs->size;
97                 }
98                 if (smallest == 0 || fs->size < smallest->size)
99                         smallest = fs;
100         }
101         return best ? best : smallest;
102 }
103
104 static char *
105 SkipFontNameElement (char *n)
106 {
107         while (*n != '-')
108                 if (!*++n)
109                         return 0;
110         return n+1;
111 }
112
113 # define SizePosition           8
114 # define EncodingPosition       13
115
116 static int
117 ConvertFontNameToSize (char *n)
118 {
119         int     i, size;
120
121         for (i = 0; i < SizePosition; i++) {
122                 n = SkipFontNameElement (n);
123                 if (!n)
124                         return -1;
125         }
126         size = atoi (n);
127         return size;
128 }
129
130 static char *
131 ConvertFontNameToEncoding (char *n)
132 {
133         int i;
134         for (i = 0; i < EncodingPosition; i++) {
135                 n = SkipFontNameElement (n);
136                 if (!n)
137                         return 0;
138         }
139         return n;
140 }
141
142 static DviFontSizeList *
143 InstallFontSizes (DviWidget dw, const char *x_name, Boolean *scalablep)
144 {
145         char    fontNameString[2048];
146         char    **fonts;
147         int     i, count;
148         int     size;
149         DviFontSizeList *sizes, *new_size;
150         XFontName       fontName;
151         unsigned int    fontNameAttributes;
152
153         *scalablep = FALSE;
154         if (!XParseFontName ((XFontNameString)x_name, &fontName,
155                              &fontNameAttributes))
156                 return 0;
157         fontNameAttributes &= ~(FontNamePixelSize|FontNamePointSize
158                                 |FontNameAverageWidth);
159         fontNameAttributes |= FontNameResolutionX;
160         fontNameAttributes |= FontNameResolutionY;
161         fontName.ResolutionX = dw->dvi.display_resolution;
162         fontName.ResolutionY = dw->dvi.display_resolution;
163         XFormatFontName (&fontName, fontNameAttributes, fontNameString);
164         fonts = XListFonts (XtDisplay (dw), fontNameString, 10000000, &count);
165         sizes = 0;
166         for (i = 0; i < count; i++) {
167                 size = ConvertFontNameToSize (fonts[i]);
168                 if (size == 0) {
169                         DisposeFontSizes (dw, sizes);
170                         sizes = 0;
171                         *scalablep = TRUE;
172                         break;
173                 }
174                 if (size != -1) {
175                         new_size = (DviFontSizeList *) XtMalloc (sizeof *new_size);
176                         new_size->next = sizes;
177                         new_size->size = size;
178                         new_size->x_name = savestr (fonts[i]);
179                         new_size->doesnt_exist = 0;
180                         new_size->font = 0;
181                         sizes = new_size;
182                 }
183         }
184         XFreeFontNames (fonts);
185         return sizes;
186 }
187
188 static void
189 DisposeFontSizes (DviWidget dw, DviFontSizeList *fs)
190 {
191         DviFontSizeList *next;
192
193         for (; fs; fs=next) {
194                 next = fs->next;
195                 if (fs->x_name)
196                         XtFree (fs->x_name);
197                 if (fs->font && fs->font != dw->dvi.default_font) {
198                         XUnloadFont (XtDisplay (dw), fs->font->fid);
199                         XFree ((char *)fs->font);
200                 }
201                 XtFree ((char *) fs);
202         }
203 }
204
205 static DviFontList *
206 InstallFont (DviWidget dw, int position,
207              const char *dvi_name, const char *x_name)
208 {
209         DviFontList     *f;
210         char            *encoding;
211
212         if ((f = LookupFontByPosition (dw, position)) != NULL) {
213                 /*
214                  * ignore gratuitous font loading
215                  */
216                 if (!strcmp (f->dvi_name, dvi_name) &&
217                     !strcmp (f->x_name, x_name))
218                         return f;
219
220                 DisposeFontSizes (dw, f->sizes);
221                 if (f->dvi_name)
222                         XtFree (f->dvi_name);
223                 if (f->x_name)
224                         XtFree (f->x_name);
225                 f->device_font = 0;
226         } else {
227                 f = (DviFontList *) XtMalloc (sizeof (*f));
228                 f->next = dw->dvi.fonts;
229                 dw->dvi.fonts = f;
230         }
231         f->initialized = FALSE;
232         f->dvi_name = savestr (dvi_name);
233         f->device_font = device_find_font (dw->dvi.device, dvi_name);
234         f->x_name = savestr (x_name);
235         f->dvi_number = position;
236         f->sizes = 0;
237         f->scalable = FALSE;
238         if (f->x_name) {
239                 encoding = ConvertFontNameToEncoding (f->x_name);
240                 f->char_map = DviFindMap (encoding);
241         } else
242                 f->char_map = 0;
243         /* 
244          * force requery of fonts
245          */
246         dw->dvi.font = 0;
247         dw->dvi.font_number = -1;
248         dw->dvi.cache.font = 0;
249         dw->dvi.cache.font_number = -1;
250         dw->dvi.device_font = 0;
251         dw->dvi.device_font_number = -1;
252         return f;
253 }
254
255 void
256 ForgetFonts (DviWidget dw)
257 {
258         DviFontList *f = dw->dvi.fonts;
259         
260         while (f) {
261                 DviFontList *tem = f;
262
263                 if (f->sizes)
264                         DisposeFontSizes (dw, f->sizes);
265                 if (f->dvi_name)
266                         XtFree (f->dvi_name);
267                 if (f->x_name)
268                         XtFree (f->x_name);
269                 f = f->next;
270                 XtFree ((char *) tem);
271         }
272         
273         /* 
274          * force requery of fonts
275          */
276         dw->dvi.font = 0;
277         dw->dvi.font_number = -1;
278         dw->dvi.cache.font = 0;
279         dw->dvi.cache.font_number = -1;
280         dw->dvi.device_font = 0;
281         dw->dvi.device_font_number = -1;
282         dw->dvi.fonts = 0;
283 }
284
285
286 static char *
287 MapDviNameToXName (DviWidget dw, const char *dvi_name)
288 {
289         DviFontMap      *fm;
290         
291         for (fm = dw->dvi.font_map; fm; fm=fm->next)
292                 if (!strcmp (fm->dvi_name, dvi_name))
293                         return fm->x_name;
294         return 0;
295 }
296
297 #if 0
298 static char *
299 MapXNameToDviName (DviWidget dw, const char *x_name)
300 {
301         DviFontMap      *fm;
302         
303         for (fm = dw->dvi.font_map; fm; fm=fm->next)
304                 if (!strcmp (fm->x_name, x_name))
305                         return fm->dvi_name;
306         return 0;
307 }
308 #endif
309
310 void
311 ParseFontMap (DviWidget dw)
312 {
313         char            dvi_name[1024];
314         char            x_name[2048];
315         char            *m, *s;
316         DviFontMap      *fm, *new_map;
317
318         if (dw->dvi.font_map)
319                 DestroyFontMap (dw->dvi.font_map);
320         fm = 0;
321         m = dw->dvi.font_map_string;
322         while (*m) {
323                 s = m;
324                 while (*m && !isspace (*m))
325                         ++m;
326                 strncpy (dvi_name, s, m-s);
327                 dvi_name[m-s] = '\0';
328                 while (isspace (*m))
329                         ++m;
330                 s = m;
331                 while (*m && *m != '\n')
332                         ++m;
333                 strncpy (x_name, s, m-s);
334                 x_name[m-s] = '\0';
335                 new_map = (DviFontMap *) XtMalloc (sizeof *new_map);
336                 new_map->x_name = savestr (x_name);
337                 new_map->dvi_name = savestr (dvi_name);
338                 new_map->next = fm;
339                 fm = new_map;
340                 ++m;
341         }
342         dw->dvi.font_map = fm;
343 }
344
345 void
346 DestroyFontMap (DviFontMap *font_map)
347 {
348         DviFontMap      *next;
349
350         for (; font_map; font_map = next) {
351                 next = font_map->next;
352                 if (font_map->x_name)
353                         XtFree (font_map->x_name);
354                 if (font_map->dvi_name)
355                         XtFree (font_map->dvi_name);
356                 XtFree ((char *) font_map);
357         }
358 }
359
360 /* ARGSUSED */
361
362 void
363 SetFontPosition (DviWidget dw, int position,
364                  const char *dvi_name, const char *extra)
365 {
366         char    *x_name;
367
368         x_name = MapDviNameToXName (dw, dvi_name);
369         if (x_name)
370                 (void) InstallFont (dw, position, dvi_name, x_name);
371
372         extra = extra;          /* unused; suppress compiler warning */
373 }
374
375 XFontStruct *
376 QueryFont (DviWidget dw, int position, int size)
377 {
378         DviFontList     *f;
379         DviFontSizeList *fs;
380
381         f = LookupFontByPosition (dw, position);
382         if (!f)
383                 return dw->dvi.default_font;
384         if (!f->initialized) {
385                 f->sizes = InstallFontSizes (dw, f->x_name, &f->scalable);
386                 f->initialized = TRUE;
387         }
388         fs = LookupFontSizeBySize (dw, f, size);
389         if (!fs)
390                 return dw->dvi.default_font;
391         if (!fs->font) {
392                 if (fs->x_name)
393                         fs->font = XLoadQueryFont (XtDisplay (dw), fs->x_name);
394                 if (!fs->font)
395                         fs->font = dw->dvi.default_font;
396         }
397         return fs->font;
398 }
399
400 DeviceFont *
401 QueryDeviceFont (DviWidget dw, int position)
402 {
403         DviFontList     *f;
404
405         f = LookupFontByPosition (dw, position);
406         if (!f)
407                 return 0;
408         return f->device_font;
409 }
410
411 DviCharNameMap *
412 QueryFontMap (DviWidget dw, int position)
413 {
414         DviFontList     *f;
415
416         f = LookupFontByPosition (dw, position);
417         if (f)
418             return f->char_map;
419         else
420             return 0;
421 }
422
423 #if 0
424 LoadFont (DviWidget dw, int position, int size)
425 {
426         XFontStruct     *font;
427
428         font = QueryFont (dw, position, size);
429         dw->dvi.font_number = position;
430         dw->dvi.font_size = size;
431         dw->dvi.font = font;
432         XSetFont (XtDisplay (dw), dw->dvi.normal_GC, font->fid);
433         return;
434 }
435 #endif
436
437 /*
438 Local Variables:
439 c-indent-level: 8
440 c-continued-statement-offset: 8
441 c-brace-offset: -8
442 c-argdecl-indent: 8
443 c-label-offset: -8
444 c-tab-always-indent: nil
445 End:
446 */