/* * font.c * * map dvi fonts to X fonts */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include #include #include #include "DviP.h" #include "XFontName.h" static char * savestr(const char *s) { size_t len; char * n; if (!s) return NULL; len = strlen(s) + 1; n = XtMalloc (len); if (n) memcpy(n, s, len); return n; } static DviFontList * LookupFontByPosition(DviWidget dw, int position) { DviFontList *f; for (f = dw->dvi.fonts; f; f = f->next) { if (f->dvi_number == position) break; } return f; } static DviFontSizeList * LookupFontSizeBySize(DviWidget dw, DviFontList *f, int size) { DviFontSizeList *best = NULL; if (f->scalable) { char fontNameString[2048]; XFontName fontName; unsigned int fontNameAttributes; for (best = f->sizes; best; best = best->next) { if (best->size == size) return best; } best = (DviFontSizeList *) XtMalloc(sizeof *best); best->next = f->sizes; best->size = size; XParseFontName(f->x_name, &fontName, &fontNameAttributes); fontNameAttributes &= ~(FontNamePixelSize | FontNameAverageWidth); fontNameAttributes |= FontNameResolutionX; fontNameAttributes |= FontNameResolutionY; fontNameAttributes |= FontNamePointSize; fontName.ResolutionX = dw->dvi.screen_resolution; fontName.ResolutionY = dw->dvi.screen_resolution; fontName.PointSize = size * 10 / dw->dvi.size_scale; XFormatFontName(&fontName, fontNameAttributes, fontNameString); best->x_name = savestr(fontNameString); #ifdef USE_XFT /* * Force a match of a core font for adobe-fontspecific * encodings; we don't have a scalable font in * the right encoding */ best->core = False; if (!strcmp(fontName.CharSetRegistry, "adobe") && !strcmp(fontName.CharSetEncoding, "fontspecific")) { best->core = True; } #endif best->doesnt_exist = 0; best->font = NULL; f->sizes = best; } else { int bestdist = 65536; for (DviFontSizeList * fs = f->sizes; fs; fs = fs->next) { int dist = size - fs->size; if (dist < 0) dist = -dist * 16; if (dist < bestdist) { best = fs; bestdist = dist; } } } return best; } static const char * SkipFontNameElement(const char *n) { while (*n != '-') { if (!*++n) return NULL; } return n + 1; } #define SizePosition 8 #define EncodingPosition 13 #ifndef USE_XFT static int ConvertFontNameToSize(const char *n) { int i, size; for (i = 0; i < SizePosition; i++) { n = SkipFontNameElement(n); if (!n) return -1; } size = atoi(n); return size / 10; } #endif static const char * ConvertFontNameToEncoding(const char *n) { for (int i = 0; i < EncodingPosition; i++) { n = SkipFontNameElement(n); if (!n) return NULL; } return n; } static void DisposeFontSizes(DviWidget dw, DviFontSizeList *fs) { DviFontSizeList *next; for (; fs; fs = next) { next = fs->next; if (fs->x_name) XtFree(fs->x_name); if (fs->font) { #ifdef USE_XFT XftFontClose(XtDisplay(dw), fs->font); #else XUnloadFont(XtDisplay(dw), fs->font->fid); XFree((char *) fs->font); #endif } XtFree((char *) fs); } } void ResetFonts(DviWidget dw) { for (DviFontList *f = dw->dvi.fonts; f; f = f->next) { if (f->initialized) { DisposeFontSizes(dw, f->sizes); f->sizes = NULL; f->initialized = FALSE; f->scalable = FALSE; } } /* * force requery of fonts */ dw->dvi.font = NULL; dw->dvi.font_number = -1; dw->dvi.cache.font = NULL; dw->dvi.cache.font_number = -1; } static DviFontSizeList * InstallFontSizes(DviWidget dw, const char *x_name, Boolean *scalablep) { #ifndef USE_XFT char fontNameString[2048]; char **fonts; int count; XFontName fontName; unsigned int fontNameAttributes; #endif DviFontSizeList *sizes = NULL; #ifdef USE_XFT *scalablep = TRUE; #else *scalablep = FALSE; if (!XParseFontName(x_name, &fontName, &fontNameAttributes)) return NULL; fontNameAttributes &= ~(FontNamePixelSize | FontNamePointSize); fontNameAttributes |= FontNameResolutionX; fontNameAttributes |= FontNameResolutionY; fontName.ResolutionX = dw->dvi.screen_resolution; fontName.ResolutionY = dw->dvi.screen_resolution; XFormatFontName(&fontName, fontNameAttributes, fontNameString); fonts = XListFonts(XtDisplay(dw), fontNameString, 10000000, &count); for (int i = 0; i < count; i++) { int size = ConvertFontNameToSize(fonts[i]); if (size == 0) { DisposeFontSizes(dw, sizes); *scalablep = TRUE; sizes = NULL; break; } if (size != -1) { DviFontSizeList *new = (DviFontSizeList *) XtMalloc(sizeof *new); new->next = sizes; new->size = size; new->x_name = savestr(fonts[i]); new->doesnt_exist = 0; new->font = NULL; sizes = new; } } XFreeFontNames(fonts); #endif return sizes; } static DviFontList * InstallFont(DviWidget dw, int position, const char *dvi_name, const char *x_name) { DviFontList *f = LookupFontByPosition(dw, position); if (f) { /* * ignore gratuitous font loading */ if (!strcmp(f->dvi_name, dvi_name) && !strcmp(f->x_name, x_name)) return f; DisposeFontSizes(dw, f->sizes); if (f->dvi_name) XtFree(f->dvi_name); if (f->x_name) XtFree(f->x_name); } else { f = (DviFontList *) XtMalloc(sizeof(*f)); f->next = dw->dvi.fonts; dw->dvi.fonts = f; } f->initialized = FALSE; f->dvi_name = savestr(dvi_name); f->x_name = savestr(x_name); f->dvi_number = position; f->sizes = NULL; f->scalable = FALSE; if (f->x_name) { const char *encoding = ConvertFontNameToEncoding(f->x_name); f->char_map = DviFindMap(encoding); } else f->char_map = NULL; /* * force requery of fonts */ dw->dvi.font = NULL; dw->dvi.font_number = -1; dw->dvi.cache.font = NULL; dw->dvi.cache.font_number = -1; return f; } static const char * MapDviNameToXName(DviWidget dw, const char *dvi_name) { DviFontMap *fm; for (fm = dw->dvi.font_map; fm; fm = fm->next) if (!strcmp(fm->dvi_name, dvi_name)) return fm->x_name; ++dvi_name; for (fm = dw->dvi.font_map; fm; fm = fm->next) if (!strcmp(fm->dvi_name, "R")) return fm->x_name; if (dw->dvi.font_map->x_name) return dw->dvi.font_map->x_name; return "-*-*-*-*-*-*-*-*-*-*-*-*-iso8859-1"; } void ParseFontMap(DviWidget dw) { char *m; DviFontMap *fm; if (dw->dvi.font_map) DestroyFontMap(dw->dvi.font_map); fm = NULL; m = dw->dvi.font_map_string; while (*m) { char dvi_name[1024]; char x_name[2048]; char *s = m; while (*m && !isspace(*m)) ++m; strncpy(dvi_name, s, m - s); dvi_name[m - s] = '\0'; while (isspace(*m)) ++m; s = m; while (*m && *m != '\n') ++m; strncpy(x_name, s, m - s); x_name[m - s] = '\0'; DviFontMap *new = (DviFontMap *) XtMalloc(sizeof *new); new->x_name = savestr(x_name); new->dvi_name = savestr(dvi_name); new->next = fm; fm = new; ++m; } dw->dvi.font_map = fm; } void DestroyFontMap(DviFontMap *font_map) { DviFontMap *next; for (; font_map; font_map = next) { next = font_map->next; if (font_map->x_name) XtFree(font_map->x_name); if (font_map->dvi_name) XtFree(font_map->dvi_name); XtFree((char *) font_map); } } /*ARGSUSED*/ void SetFontPosition(DviWidget dw, int position, const char *dvi_name, const char *extra) { const char *x_name; x_name = MapDviNameToXName(dw, dvi_name); (void) InstallFont(dw, position, dvi_name, x_name); } #ifdef USE_XFT XftFont * #else XFontStruct * #endif QueryFont(DviWidget dw, int position, int size) { DviFontList *f; DviFontSizeList *fs; f = LookupFontByPosition(dw, position); if (!f) return dw->dvi.default_font; if (!f->initialized) { f->sizes = InstallFontSizes(dw, f->x_name, &f->scalable); f->initialized = TRUE; } fs = LookupFontSizeBySize(dw, f, size); if (!fs) return dw->dvi.default_font; if (!fs->font) { if (fs->x_name) { #ifdef USE_XFT XftPattern *pat; XftPattern *match; XftResult result; pat = XftXlfdParse(fs->x_name, False, False); XftPatternAddBool(pat, XFT_CORE, fs->core); match = XftFontMatch(XtDisplay(dw), XScreenNumberOfScreen(dw->core.screen), pat, &result); XftPatternDestroy(pat); if (match) { fs->font = XftFontOpenPattern(XtDisplay(dw), match); if (!fs->font) XftPatternDestroy(match); } else fs->font = 0; #else fs->font = XLoadQueryFont(XtDisplay(dw), fs->x_name); #endif } if (!fs->font) fs->font = dw->dvi.default_font; } return fs->font; } DviCharNameMap * QueryFontMap(DviWidget dw, int position) { DviFontList *f = LookupFontByPosition(dw, position); if (f) return f->char_map; else return NULL; } unsigned char * DviCharIsLigature(DviCharNameMap *map, const char *name) { for (int i = 0; i < DVI_MAX_LIGATURES; i++) { if (!map->ligatures[i][0]) break; if (!strcmp(name, map->ligatures[i][0])) return (unsigned char *) map->ligatures[i][1]; } return NULL; }