fcname.c revision 18bd4a06
1/* 2 * fontconfig/src/fcname.c 3 * 4 * Copyright © 2000 Keith Packard 5 * 6 * Permission to use, copy, modify, distribute, and sell this software and its 7 * documentation for any purpose is hereby granted without fee, provided that 8 * the above copyright notice appear in all copies and that both that 9 * copyright notice and this permission notice appear in supporting 10 * documentation, and that the name of the author(s) not be used in 11 * advertising or publicity pertaining to distribution of the software without 12 * specific, written prior permission. The authors make no 13 * representations about the suitability of this software for any purpose. It 14 * is provided "as is" without express or implied warranty. 15 * 16 * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 18 * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR 19 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 20 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 21 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 22 * PERFORMANCE OF THIS SOFTWARE. 23 */ 24 25#include "fcint.h" 26#include <ctype.h> 27#include <stdlib.h> 28#include <string.h> 29#include <stdio.h> 30 31static const FcObjectType FcObjects[] = { 32#define FC_OBJECT(NAME, Type, Cmp) { FC_##NAME, Type }, 33#include "fcobjs.h" 34#undef FC_OBJECT 35}; 36 37#define NUM_OBJECT_TYPES ((int) (sizeof FcObjects / sizeof FcObjects[0])) 38 39static const FcObjectType * 40FcObjectFindById (FcObject object) 41{ 42 if (1 <= object && object <= NUM_OBJECT_TYPES) 43 return &FcObjects[object - 1]; 44 return FcObjectLookupOtherTypeById (object); 45} 46 47FcBool 48FcNameRegisterObjectTypes (const FcObjectType *types, int ntypes) 49{ 50 /* Deprecated. */ 51 return FcFalse; 52} 53 54FcBool 55FcNameUnregisterObjectTypes (const FcObjectType *types, int ntypes) 56{ 57 /* Deprecated. */ 58 return FcFalse; 59} 60 61const FcObjectType * 62FcNameGetObjectType (const char *object) 63{ 64 int id = FcObjectLookupBuiltinIdByName (object); 65 66 if (!id) 67 return FcObjectLookupOtherTypeByName (object); 68 69 return &FcObjects[id - 1]; 70} 71 72FcBool 73FcObjectValidType (FcObject object, FcType type) 74{ 75 const FcObjectType *t = FcObjectFindById (object); 76 77 if (t) { 78 switch ((int) t->type) { 79 case FcTypeUnknown: 80 return FcTrue; 81 case FcTypeDouble: 82 case FcTypeInteger: 83 if (type == FcTypeDouble || type == FcTypeInteger) 84 return FcTrue; 85 break; 86 case FcTypeLangSet: 87 if (type == FcTypeLangSet || type == FcTypeString) 88 return FcTrue; 89 break; 90 case FcTypeRange: 91 if (type == FcTypeRange || 92 type == FcTypeDouble || 93 type == FcTypeInteger) 94 return FcTrue; 95 break; 96 default: 97 if (type == t->type) 98 return FcTrue; 99 break; 100 } 101 return FcFalse; 102 } 103 return FcTrue; 104} 105 106FcObject 107FcObjectFromName (const char * name) 108{ 109 return FcObjectLookupIdByName (name); 110} 111 112FcObjectSet * 113FcObjectGetSet (void) 114{ 115 int i; 116 FcObjectSet *os = NULL; 117 118 119 os = FcObjectSetCreate (); 120 for (i = 0; i < NUM_OBJECT_TYPES; i++) 121 FcObjectSetAdd (os, FcObjects[i].object); 122 123 return os; 124} 125 126const char * 127FcObjectName (FcObject object) 128{ 129 const FcObjectType *o = FcObjectFindById (object); 130 131 if (o) 132 return o->object; 133 134 return FcObjectLookupOtherNameById (object); 135} 136 137static const FcConstant _FcBaseConstants[] = { 138 { (FcChar8 *) "thin", "weight", FC_WEIGHT_THIN, }, 139 { (FcChar8 *) "extralight", "weight", FC_WEIGHT_EXTRALIGHT, }, 140 { (FcChar8 *) "ultralight", "weight", FC_WEIGHT_EXTRALIGHT, }, 141 { (FcChar8 *) "demilight", "weight", FC_WEIGHT_DEMILIGHT, }, 142 { (FcChar8 *) "semilight", "weight", FC_WEIGHT_DEMILIGHT, }, 143 { (FcChar8 *) "light", "weight", FC_WEIGHT_LIGHT, }, 144 { (FcChar8 *) "book", "weight", FC_WEIGHT_BOOK, }, 145 { (FcChar8 *) "regular", "weight", FC_WEIGHT_REGULAR, }, 146 { (FcChar8 *) "medium", "weight", FC_WEIGHT_MEDIUM, }, 147 { (FcChar8 *) "demibold", "weight", FC_WEIGHT_DEMIBOLD, }, 148 { (FcChar8 *) "semibold", "weight", FC_WEIGHT_DEMIBOLD, }, 149 { (FcChar8 *) "bold", "weight", FC_WEIGHT_BOLD, }, 150 { (FcChar8 *) "extrabold", "weight", FC_WEIGHT_EXTRABOLD, }, 151 { (FcChar8 *) "ultrabold", "weight", FC_WEIGHT_EXTRABOLD, }, 152 { (FcChar8 *) "black", "weight", FC_WEIGHT_BLACK, }, 153 { (FcChar8 *) "heavy", "weight", FC_WEIGHT_HEAVY, }, 154 155 { (FcChar8 *) "roman", "slant", FC_SLANT_ROMAN, }, 156 { (FcChar8 *) "italic", "slant", FC_SLANT_ITALIC, }, 157 { (FcChar8 *) "oblique", "slant", FC_SLANT_OBLIQUE, }, 158 159 { (FcChar8 *) "ultracondensed", "width", FC_WIDTH_ULTRACONDENSED }, 160 { (FcChar8 *) "extracondensed", "width", FC_WIDTH_EXTRACONDENSED }, 161 { (FcChar8 *) "condensed", "width", FC_WIDTH_CONDENSED }, 162 { (FcChar8 *) "semicondensed", "width", FC_WIDTH_SEMICONDENSED }, 163 { (FcChar8 *) "normal", "width", FC_WIDTH_NORMAL }, 164 { (FcChar8 *) "semiexpanded", "width", FC_WIDTH_SEMIEXPANDED }, 165 { (FcChar8 *) "expanded", "width", FC_WIDTH_EXPANDED }, 166 { (FcChar8 *) "extraexpanded", "width", FC_WIDTH_EXTRAEXPANDED }, 167 { (FcChar8 *) "ultraexpanded", "width", FC_WIDTH_ULTRAEXPANDED }, 168 169 { (FcChar8 *) "proportional", "spacing", FC_PROPORTIONAL, }, 170 { (FcChar8 *) "dual", "spacing", FC_DUAL, }, 171 { (FcChar8 *) "mono", "spacing", FC_MONO, }, 172 { (FcChar8 *) "charcell", "spacing", FC_CHARCELL, }, 173 174 { (FcChar8 *) "unknown", "rgba", FC_RGBA_UNKNOWN }, 175 { (FcChar8 *) "rgb", "rgba", FC_RGBA_RGB, }, 176 { (FcChar8 *) "bgr", "rgba", FC_RGBA_BGR, }, 177 { (FcChar8 *) "vrgb", "rgba", FC_RGBA_VRGB }, 178 { (FcChar8 *) "vbgr", "rgba", FC_RGBA_VBGR }, 179 { (FcChar8 *) "none", "rgba", FC_RGBA_NONE }, 180 181 { (FcChar8 *) "hintnone", "hintstyle", FC_HINT_NONE }, 182 { (FcChar8 *) "hintslight", "hintstyle", FC_HINT_SLIGHT }, 183 { (FcChar8 *) "hintmedium", "hintstyle", FC_HINT_MEDIUM }, 184 { (FcChar8 *) "hintfull", "hintstyle", FC_HINT_FULL }, 185 186 { (FcChar8 *) "antialias", "antialias", FcTrue }, 187 { (FcChar8 *) "hinting", "hinting", FcTrue }, 188 { (FcChar8 *) "verticallayout", "verticallayout", FcTrue }, 189 { (FcChar8 *) "autohint", "autohint", FcTrue }, 190 { (FcChar8 *) "globaladvance", "globaladvance", FcTrue }, /* deprecated */ 191 { (FcChar8 *) "outline", "outline", FcTrue }, 192 { (FcChar8 *) "scalable", "scalable", FcTrue }, 193 { (FcChar8 *) "minspace", "minspace", FcTrue }, 194 { (FcChar8 *) "embolden", "embolden", FcTrue }, 195 { (FcChar8 *) "embeddedbitmap", "embeddedbitmap", FcTrue }, 196 { (FcChar8 *) "decorative", "decorative", FcTrue }, 197 { (FcChar8 *) "lcdnone", "lcdfilter", FC_LCD_NONE }, 198 { (FcChar8 *) "lcddefault", "lcdfilter", FC_LCD_DEFAULT }, 199 { (FcChar8 *) "lcdlight", "lcdfilter", FC_LCD_LIGHT }, 200 { (FcChar8 *) "lcdlegacy", "lcdfilter", FC_LCD_LEGACY }, 201}; 202 203#define NUM_FC_CONSTANTS (sizeof _FcBaseConstants/sizeof _FcBaseConstants[0]) 204 205FcBool 206FcNameRegisterConstants (const FcConstant *consts, int nconsts) 207{ 208 /* Deprecated. */ 209 return FcFalse; 210} 211 212FcBool 213FcNameUnregisterConstants (const FcConstant *consts, int nconsts) 214{ 215 /* Deprecated. */ 216 return FcFalse; 217} 218 219const FcConstant * 220FcNameGetConstant (const FcChar8 *string) 221{ 222 unsigned int i; 223 224 for (i = 0; i < NUM_FC_CONSTANTS; i++) 225 if (!FcStrCmpIgnoreCase (string, _FcBaseConstants[i].name)) 226 return &_FcBaseConstants[i]; 227 228 return 0; 229} 230 231FcBool 232FcNameConstant (const FcChar8 *string, int *result) 233{ 234 const FcConstant *c; 235 236 if ((c = FcNameGetConstant(string))) 237 { 238 *result = c->value; 239 return FcTrue; 240 } 241 return FcFalse; 242} 243 244FcBool 245FcNameBool (const FcChar8 *v, FcBool *result) 246{ 247 char c0, c1; 248 249 c0 = *v; 250 c0 = FcToLower (c0); 251 if (c0 == 't' || c0 == 'y' || c0 == '1') 252 { 253 *result = FcTrue; 254 return FcTrue; 255 } 256 if (c0 == 'f' || c0 == 'n' || c0 == '0') 257 { 258 *result = FcFalse; 259 return FcTrue; 260 } 261 if (c0 == 'o') 262 { 263 c1 = v[1]; 264 c1 = FcToLower (c1); 265 if (c1 == 'n') 266 { 267 *result = FcTrue; 268 return FcTrue; 269 } 270 if (c1 == 'f') 271 { 272 *result = FcFalse; 273 return FcTrue; 274 } 275 } 276 return FcFalse; 277} 278 279static FcValue 280FcNameConvert (FcType type, FcChar8 *string) 281{ 282 FcValue v; 283 FcMatrix m; 284 double b, e; 285 char *p; 286 287 v.type = type; 288 switch ((int) v.type) { 289 case FcTypeInteger: 290 if (!FcNameConstant (string, &v.u.i)) 291 v.u.i = atoi ((char *) string); 292 break; 293 case FcTypeString: 294 v.u.s = FcStrdup (string); 295 if (!v.u.s) 296 v.type = FcTypeVoid; 297 break; 298 case FcTypeBool: 299 if (!FcNameBool (string, &v.u.b)) 300 v.u.b = FcFalse; 301 break; 302 case FcTypeDouble: 303 v.u.d = strtod ((char *) string, 0); 304 break; 305 case FcTypeMatrix: 306 FcMatrixInit (&m); 307 sscanf ((char *) string, "%lg %lg %lg %lg", &m.xx, &m.xy, &m.yx, &m.yy); 308 v.u.m = FcMatrixCopy (&m); 309 break; 310 case FcTypeCharSet: 311 v.u.c = FcNameParseCharSet (string); 312 if (!v.u.c) 313 v.type = FcTypeVoid; 314 break; 315 case FcTypeLangSet: 316 v.u.l = FcNameParseLangSet (string); 317 if (!v.u.l) 318 v.type = FcTypeVoid; 319 break; 320 case FcTypeRange: 321 if (sscanf ((char *) string, "[%lg %lg)", &b, &e) != 2) 322 { 323 v.u.d = strtod ((char *) string, &p); 324 if (p != NULL && p[0] != 0) 325 { 326 v.type = FcTypeVoid; 327 break; 328 } 329 v.type = FcTypeDouble; 330 } 331 else 332 v.u.r = FcRangeCreateDouble (b, e); 333 break; 334 default: 335 break; 336 } 337 return v; 338} 339 340static const FcChar8 * 341FcNameFindNext (const FcChar8 *cur, const char *delim, FcChar8 *save, FcChar8 *last) 342{ 343 FcChar8 c; 344 345 while ((c = *cur)) 346 { 347 if (!isspace (c)) 348 break; 349 ++cur; 350 } 351 while ((c = *cur)) 352 { 353 if (c == '\\') 354 { 355 ++cur; 356 if (!(c = *cur)) 357 break; 358 } 359 else if (strchr (delim, c)) 360 break; 361 ++cur; 362 *save++ = c; 363 } 364 *save = 0; 365 *last = *cur; 366 if (*cur) 367 cur++; 368 return cur; 369} 370 371FcPattern * 372FcNameParse (const FcChar8 *name) 373{ 374 FcChar8 *save; 375 FcPattern *pat; 376 double d; 377 FcChar8 *e; 378 FcChar8 delim; 379 FcValue v; 380 const FcObjectType *t; 381 const FcConstant *c; 382 383 /* freed below */ 384 save = malloc (strlen ((char *) name) + 1); 385 if (!save) 386 goto bail0; 387 pat = FcPatternCreate (); 388 if (!pat) 389 goto bail1; 390 391 for (;;) 392 { 393 name = FcNameFindNext (name, "-,:", save, &delim); 394 if (save[0]) 395 { 396 if (!FcPatternAddString (pat, FC_FAMILY, save)) 397 goto bail2; 398 } 399 if (delim != ',') 400 break; 401 } 402 if (delim == '-') 403 { 404 for (;;) 405 { 406 name = FcNameFindNext (name, "-,:", save, &delim); 407 d = strtod ((char *) save, (char **) &e); 408 if (e != save) 409 { 410 if (!FcPatternAddDouble (pat, FC_SIZE, d)) 411 goto bail2; 412 } 413 if (delim != ',') 414 break; 415 } 416 } 417 while (delim == ':') 418 { 419 name = FcNameFindNext (name, "=_:", save, &delim); 420 if (save[0]) 421 { 422 if (delim == '=' || delim == '_') 423 { 424 t = FcNameGetObjectType ((char *) save); 425 for (;;) 426 { 427 name = FcNameFindNext (name, ":,", save, &delim); 428 if (t) 429 { 430 v = FcNameConvert (t->type, save); 431 if (!FcPatternAdd (pat, t->object, v, FcTrue)) 432 { 433 FcValueDestroy (v); 434 goto bail2; 435 } 436 FcValueDestroy (v); 437 } 438 if (delim != ',') 439 break; 440 } 441 } 442 else 443 { 444 if ((c = FcNameGetConstant (save))) 445 { 446 t = FcNameGetObjectType ((char *) c->object); 447 if (t == NULL) 448 goto bail2; 449 switch ((int) t->type) { 450 case FcTypeInteger: 451 case FcTypeDouble: 452 if (!FcPatternAddInteger (pat, c->object, c->value)) 453 goto bail2; 454 break; 455 case FcTypeBool: 456 if (!FcPatternAddBool (pat, c->object, c->value)) 457 goto bail2; 458 break; 459 default: 460 break; 461 } 462 } 463 } 464 } 465 } 466 467 free (save); 468 return pat; 469 470bail2: 471 FcPatternDestroy (pat); 472bail1: 473 free (save); 474bail0: 475 return 0; 476} 477static FcBool 478FcNameUnparseString (FcStrBuf *buf, 479 const FcChar8 *string, 480 const FcChar8 *escape) 481{ 482 FcChar8 c; 483 while ((c = *string++)) 484 { 485 if (escape && strchr ((char *) escape, (char) c)) 486 { 487 if (!FcStrBufChar (buf, escape[0])) 488 return FcFalse; 489 } 490 if (!FcStrBufChar (buf, c)) 491 return FcFalse; 492 } 493 return FcTrue; 494} 495 496FcBool 497FcNameUnparseValue (FcStrBuf *buf, 498 FcValue *v0, 499 FcChar8 *escape) 500{ 501 FcChar8 temp[1024]; 502 FcValue v = FcValueCanonicalize(v0); 503 504 switch (v.type) { 505 case FcTypeUnknown: 506 case FcTypeVoid: 507 return FcTrue; 508 case FcTypeInteger: 509 sprintf ((char *) temp, "%d", v.u.i); 510 return FcNameUnparseString (buf, temp, 0); 511 case FcTypeDouble: 512 sprintf ((char *) temp, "%g", v.u.d); 513 return FcNameUnparseString (buf, temp, 0); 514 case FcTypeString: 515 return FcNameUnparseString (buf, v.u.s, escape); 516 case FcTypeBool: 517 return FcNameUnparseString (buf, v.u.b ? (FcChar8 *) "True" : (FcChar8 *) "False", 0); 518 case FcTypeMatrix: 519 sprintf ((char *) temp, "%g %g %g %g", 520 v.u.m->xx, v.u.m->xy, v.u.m->yx, v.u.m->yy); 521 return FcNameUnparseString (buf, temp, 0); 522 case FcTypeCharSet: 523 return FcNameUnparseCharSet (buf, v.u.c); 524 case FcTypeLangSet: 525 return FcNameUnparseLangSet (buf, v.u.l); 526 case FcTypeFTFace: 527 return FcTrue; 528 case FcTypeRange: 529 sprintf ((char *) temp, "[%g %g)", v.u.r->begin, v.u.r->end); 530 return FcNameUnparseString (buf, temp, 0); 531 } 532 return FcFalse; 533} 534 535FcBool 536FcNameUnparseValueList (FcStrBuf *buf, 537 FcValueListPtr v, 538 FcChar8 *escape) 539{ 540 while (v) 541 { 542 if (!FcNameUnparseValue (buf, &v->value, escape)) 543 return FcFalse; 544 if ((v = FcValueListNext(v)) != NULL) 545 if (!FcNameUnparseString (buf, (FcChar8 *) ",", 0)) 546 return FcFalse; 547 } 548 return FcTrue; 549} 550 551#define FC_ESCAPE_FIXED "\\-:," 552#define FC_ESCAPE_VARIABLE "\\=_:," 553 554FcChar8 * 555FcNameUnparse (FcPattern *pat) 556{ 557 return FcNameUnparseEscaped (pat, FcTrue); 558} 559 560FcChar8 * 561FcNameUnparseEscaped (FcPattern *pat, FcBool escape) 562{ 563 FcStrBuf buf, buf2; 564 FcChar8 buf_static[8192], buf2_static[256]; 565 int i; 566 FcPatternElt *e; 567 568 FcStrBufInit (&buf, buf_static, sizeof (buf_static)); 569 FcStrBufInit (&buf2, buf2_static, sizeof (buf2_static)); 570 e = FcPatternObjectFindElt (pat, FC_FAMILY_OBJECT); 571 if (e) 572 { 573 if (!FcNameUnparseValueList (&buf, FcPatternEltValues(e), escape ? (FcChar8 *) FC_ESCAPE_FIXED : 0)) 574 goto bail0; 575 } 576 e = FcPatternObjectFindElt (pat, FC_SIZE_OBJECT); 577 if (e) 578 { 579 FcChar8 *p; 580 581 if (!FcNameUnparseString (&buf2, (FcChar8 *) "-", 0)) 582 goto bail0; 583 if (!FcNameUnparseValueList (&buf2, FcPatternEltValues(e), escape ? (FcChar8 *) FC_ESCAPE_FIXED : 0)) 584 goto bail0; 585 p = FcStrBufDoneStatic (&buf2); 586 FcStrBufDestroy (&buf2); 587 if (strlen ((const char *)p) > 1) 588 if (!FcStrBufString (&buf, p)) 589 goto bail0; 590 } 591 for (i = 0; i < NUM_OBJECT_TYPES; i++) 592 { 593 FcObject id = i + 1; 594 const FcObjectType *o; 595 o = &FcObjects[i]; 596 if (!strcmp (o->object, FC_FAMILY) || 597 !strcmp (o->object, FC_SIZE)) 598 continue; 599 600 e = FcPatternObjectFindElt (pat, id); 601 if (e) 602 { 603 if (!FcNameUnparseString (&buf, (FcChar8 *) ":", 0)) 604 goto bail0; 605 if (!FcNameUnparseString (&buf, (FcChar8 *) o->object, escape ? (FcChar8 *) FC_ESCAPE_VARIABLE : 0)) 606 goto bail0; 607 if (!FcNameUnparseString (&buf, (FcChar8 *) "=", 0)) 608 goto bail0; 609 if (!FcNameUnparseValueList (&buf, FcPatternEltValues(e), escape ? 610 (FcChar8 *) FC_ESCAPE_VARIABLE : 0)) 611 goto bail0; 612 } 613 } 614 return FcStrBufDone (&buf); 615bail0: 616 FcStrBufDestroy (&buf); 617 return 0; 618} 619#define __fcname__ 620#include "fcaliastail.h" 621#undef __fcname__ 622