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 19static char * 20savestr(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 34static DviFontList * 35LookupFontByPosition(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 46static DviFontSizeList * 47LookupFontSizeBySize(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 106static const char * 107SkipFontNameElement(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 120static int 121ConvertFontNameToSize(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 135static const char * 136ConvertFontNameToEncoding(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 146static void 147DisposeFontSizes(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 167void 168ResetFonts(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 187static DviFontSizeList * 188InstallFontSizes(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 238static DviFontList * 239InstallFont(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 285static const char * 286MapDviNameToXName(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 302void 303ParseFontMap(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 339void 340DestroyFontMap(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 355SetFontPosition(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 365XftFont * 366#else 367XFontStruct * 368#endif 369QueryFont(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 414DviCharNameMap * 415QueryFontMap(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 425unsigned char * 426DviCharIsLigature(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