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