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