fcname.c revision 7872e0a1
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 245FcNameConstantWithObjectCheck (const FcChar8 *string, const char *object, int *result) 246{ 247 const FcConstant *c; 248 249 if ((c = FcNameGetConstant(string))) 250 { 251 if (strcmp (c->object, object) != 0) 252 { 253 fprintf (stderr, "Fontconfig error: Unexpected constant name `%s' used for object `%s': should be `%s'\n", string, object, c->object); 254 return FcFalse; 255 } 256 *result = c->value; 257 return FcTrue; 258 } 259 return FcFalse; 260} 261 262FcBool 263FcNameBool (const FcChar8 *v, FcBool *result) 264{ 265 char c0, c1; 266 267 c0 = *v; 268 c0 = FcToLower (c0); 269 if (c0 == 't' || c0 == 'y' || c0 == '1') 270 { 271 *result = FcTrue; 272 return FcTrue; 273 } 274 if (c0 == 'f' || c0 == 'n' || c0 == '0') 275 { 276 *result = FcFalse; 277 return FcTrue; 278 } 279 if (c0 == 'd' || c0 == 'x' || c0 == '2') 280 { 281 *result = FcDontCare; 282 return FcTrue; 283 } 284 if (c0 == 'o') 285 { 286 c1 = v[1]; 287 c1 = FcToLower (c1); 288 if (c1 == 'n') 289 { 290 *result = FcTrue; 291 return FcTrue; 292 } 293 if (c1 == 'f') 294 { 295 *result = FcFalse; 296 return FcTrue; 297 } 298 if (c1 == 'r') 299 { 300 *result = FcDontCare; 301 return FcTrue; 302 } 303 } 304 return FcFalse; 305} 306 307static FcValue 308FcNameConvert (FcType type, const char *object, FcChar8 *string) 309{ 310 FcValue v; 311 FcMatrix m; 312 double b, e; 313 char *p; 314 315 v.type = type; 316 switch ((int) v.type) { 317 case FcTypeInteger: 318 if (!FcNameConstantWithObjectCheck (string, object, &v.u.i)) 319 v.u.i = atoi ((char *) string); 320 break; 321 case FcTypeString: 322 v.u.s = FcStrdup (string); 323 if (!v.u.s) 324 v.type = FcTypeVoid; 325 break; 326 case FcTypeBool: 327 if (!FcNameBool (string, &v.u.b)) 328 v.u.b = FcFalse; 329 break; 330 case FcTypeDouble: 331 v.u.d = strtod ((char *) string, 0); 332 break; 333 case FcTypeMatrix: 334 FcMatrixInit (&m); 335 sscanf ((char *) string, "%lg %lg %lg %lg", &m.xx, &m.xy, &m.yx, &m.yy); 336 v.u.m = FcMatrixCopy (&m); 337 break; 338 case FcTypeCharSet: 339 v.u.c = FcNameParseCharSet (string); 340 if (!v.u.c) 341 v.type = FcTypeVoid; 342 break; 343 case FcTypeLangSet: 344 v.u.l = FcNameParseLangSet (string); 345 if (!v.u.l) 346 v.type = FcTypeVoid; 347 break; 348 case FcTypeRange: 349 if (sscanf ((char *) string, "[%lg %lg]", &b, &e) != 2) 350 { 351 char *sc, *ec; 352 size_t len = strlen ((const char *) string); 353 int si, ei; 354 355 sc = malloc (len + 1); 356 ec = malloc (len + 1); 357 if (sc && ec && sscanf ((char *) string, "[%s %[^]]]", sc, ec) == 2) 358 { 359 if (FcNameConstantWithObjectCheck ((const FcChar8 *) sc, object, &si) && 360 FcNameConstantWithObjectCheck ((const FcChar8 *) ec, object, &ei)) 361 v.u.r = FcRangeCreateDouble (si, ei); 362 else 363 goto bail1; 364 } 365 else 366 { 367 bail1: 368 v.type = FcTypeDouble; 369 if (FcNameConstantWithObjectCheck (string, object, &si)) 370 { 371 v.u.d = (double) si; 372 } else { 373 v.u.d = strtod ((char *) string, &p); 374 if (p != NULL && p[0] != 0) 375 v.type = FcTypeVoid; 376 } 377 } 378 if (sc) 379 free (sc); 380 if (ec) 381 free (ec); 382 } 383 else 384 v.u.r = FcRangeCreateDouble (b, e); 385 break; 386 default: 387 break; 388 } 389 return v; 390} 391 392static const FcChar8 * 393FcNameFindNext (const FcChar8 *cur, const char *delim, FcChar8 *save, FcChar8 *last) 394{ 395 FcChar8 c; 396 397 while ((c = *cur)) 398 { 399 if (!isspace (c)) 400 break; 401 ++cur; 402 } 403 while ((c = *cur)) 404 { 405 if (c == '\\') 406 { 407 ++cur; 408 if (!(c = *cur)) 409 break; 410 } 411 else if (strchr (delim, c)) 412 break; 413 ++cur; 414 *save++ = c; 415 } 416 *save = 0; 417 *last = *cur; 418 if (*cur) 419 cur++; 420 return cur; 421} 422 423FcPattern * 424FcNameParse (const FcChar8 *name) 425{ 426 FcChar8 *save; 427 FcPattern *pat; 428 double d; 429 FcChar8 *e; 430 FcChar8 delim; 431 FcValue v; 432 const FcObjectType *t; 433 const FcConstant *c; 434 435 /* freed below */ 436 save = malloc (strlen ((char *) name) + 1); 437 if (!save) 438 goto bail0; 439 pat = FcPatternCreate (); 440 if (!pat) 441 goto bail1; 442 443 for (;;) 444 { 445 name = FcNameFindNext (name, "-,:", save, &delim); 446 if (save[0]) 447 { 448 if (!FcPatternObjectAddString (pat, FC_FAMILY_OBJECT, save)) 449 goto bail2; 450 } 451 if (delim != ',') 452 break; 453 } 454 if (delim == '-') 455 { 456 for (;;) 457 { 458 name = FcNameFindNext (name, "-,:", save, &delim); 459 d = strtod ((char *) save, (char **) &e); 460 if (e != save) 461 { 462 if (!FcPatternObjectAddDouble (pat, FC_SIZE_OBJECT, d)) 463 goto bail2; 464 } 465 if (delim != ',') 466 break; 467 } 468 } 469 while (delim == ':') 470 { 471 name = FcNameFindNext (name, "=_:", save, &delim); 472 if (save[0]) 473 { 474 if (delim == '=' || delim == '_') 475 { 476 t = FcNameGetObjectType ((char *) save); 477 for (;;) 478 { 479 name = FcNameFindNext (name, ":,", save, &delim); 480 if (t) 481 { 482 v = FcNameConvert (t->type, t->object, save); 483 if (!FcPatternAdd (pat, t->object, v, FcTrue)) 484 { 485 FcValueDestroy (v); 486 goto bail2; 487 } 488 FcValueDestroy (v); 489 } 490 if (delim != ',') 491 break; 492 } 493 } 494 else 495 { 496 if ((c = FcNameGetConstant (save))) 497 { 498 t = FcNameGetObjectType ((char *) c->object); 499 if (t == NULL) 500 goto bail2; 501 switch ((int) t->type) { 502 case FcTypeInteger: 503 case FcTypeDouble: 504 if (!FcPatternAddInteger (pat, c->object, c->value)) 505 goto bail2; 506 break; 507 case FcTypeBool: 508 if (!FcPatternAddBool (pat, c->object, c->value)) 509 goto bail2; 510 break; 511 case FcTypeRange: 512 if (!FcPatternAddInteger (pat, c->object, c->value)) 513 goto bail2; 514 break; 515 default: 516 break; 517 } 518 } 519 } 520 } 521 } 522 523 free (save); 524 return pat; 525 526bail2: 527 FcPatternDestroy (pat); 528bail1: 529 free (save); 530bail0: 531 return 0; 532} 533static FcBool 534FcNameUnparseString (FcStrBuf *buf, 535 const FcChar8 *string, 536 const FcChar8 *escape) 537{ 538 FcChar8 c; 539 while ((c = *string++)) 540 { 541 if (escape && strchr ((char *) escape, (char) c)) 542 { 543 if (!FcStrBufChar (buf, escape[0])) 544 return FcFalse; 545 } 546 if (!FcStrBufChar (buf, c)) 547 return FcFalse; 548 } 549 return FcTrue; 550} 551 552FcBool 553FcNameUnparseValue (FcStrBuf *buf, 554 FcValue *v0, 555 FcChar8 *escape) 556{ 557 FcChar8 temp[1024]; 558 FcValue v = FcValueCanonicalize(v0); 559 560 switch (v.type) { 561 case FcTypeUnknown: 562 case FcTypeVoid: 563 return FcTrue; 564 case FcTypeInteger: 565 sprintf ((char *) temp, "%d", v.u.i); 566 return FcNameUnparseString (buf, temp, 0); 567 case FcTypeDouble: 568 sprintf ((char *) temp, "%g", v.u.d); 569 return FcNameUnparseString (buf, temp, 0); 570 case FcTypeString: 571 return FcNameUnparseString (buf, v.u.s, escape); 572 case FcTypeBool: 573 return FcNameUnparseString (buf, 574 v.u.b == FcTrue ? (FcChar8 *) "True" : 575 v.u.b == FcFalse ? (FcChar8 *) "False" : 576 (FcChar8 *) "DontCare", 0); 577 case FcTypeMatrix: 578 sprintf ((char *) temp, "%g %g %g %g", 579 v.u.m->xx, v.u.m->xy, v.u.m->yx, v.u.m->yy); 580 return FcNameUnparseString (buf, temp, 0); 581 case FcTypeCharSet: 582 return FcNameUnparseCharSet (buf, v.u.c); 583 case FcTypeLangSet: 584 return FcNameUnparseLangSet (buf, v.u.l); 585 case FcTypeFTFace: 586 return FcTrue; 587 case FcTypeRange: 588 sprintf ((char *) temp, "[%g %g]", v.u.r->begin, v.u.r->end); 589 return FcNameUnparseString (buf, temp, 0); 590 } 591 return FcFalse; 592} 593 594FcBool 595FcNameUnparseValueList (FcStrBuf *buf, 596 FcValueListPtr v, 597 FcChar8 *escape) 598{ 599 while (v) 600 { 601 if (!FcNameUnparseValue (buf, &v->value, escape)) 602 return FcFalse; 603 if ((v = FcValueListNext(v)) != NULL) 604 if (!FcNameUnparseString (buf, (FcChar8 *) ",", 0)) 605 return FcFalse; 606 } 607 return FcTrue; 608} 609 610#define FC_ESCAPE_FIXED "\\-:," 611#define FC_ESCAPE_VARIABLE "\\=_:," 612 613FcChar8 * 614FcNameUnparse (FcPattern *pat) 615{ 616 return FcNameUnparseEscaped (pat, FcTrue); 617} 618 619FcChar8 * 620FcNameUnparseEscaped (FcPattern *pat, FcBool escape) 621{ 622 FcStrBuf buf, buf2; 623 FcChar8 buf_static[8192], buf2_static[256]; 624 int i; 625 FcPatternElt *e; 626 627 FcStrBufInit (&buf, buf_static, sizeof (buf_static)); 628 FcStrBufInit (&buf2, buf2_static, sizeof (buf2_static)); 629 e = FcPatternObjectFindElt (pat, FC_FAMILY_OBJECT); 630 if (e) 631 { 632 if (!FcNameUnparseValueList (&buf, FcPatternEltValues(e), escape ? (FcChar8 *) FC_ESCAPE_FIXED : 0)) 633 goto bail0; 634 } 635 e = FcPatternObjectFindElt (pat, FC_SIZE_OBJECT); 636 if (e) 637 { 638 FcChar8 *p; 639 640 if (!FcNameUnparseString (&buf2, (FcChar8 *) "-", 0)) 641 goto bail0; 642 if (!FcNameUnparseValueList (&buf2, FcPatternEltValues(e), escape ? (FcChar8 *) FC_ESCAPE_FIXED : 0)) 643 goto bail0; 644 p = FcStrBufDoneStatic (&buf2); 645 FcStrBufDestroy (&buf2); 646 if (strlen ((const char *)p) > 1) 647 if (!FcStrBufString (&buf, p)) 648 goto bail0; 649 } 650 for (i = 0; i < NUM_OBJECT_TYPES; i++) 651 { 652 FcObject id = i + 1; 653 const FcObjectType *o; 654 o = &FcObjects[i]; 655 if (!strcmp (o->object, FC_FAMILY) || 656 !strcmp (o->object, FC_SIZE)) 657 continue; 658 659 e = FcPatternObjectFindElt (pat, id); 660 if (e) 661 { 662 if (!FcNameUnparseString (&buf, (FcChar8 *) ":", 0)) 663 goto bail0; 664 if (!FcNameUnparseString (&buf, (FcChar8 *) o->object, escape ? (FcChar8 *) FC_ESCAPE_VARIABLE : 0)) 665 goto bail0; 666 if (!FcNameUnparseString (&buf, (FcChar8 *) "=", 0)) 667 goto bail0; 668 if (!FcNameUnparseValueList (&buf, FcPatternEltValues(e), escape ? 669 (FcChar8 *) FC_ESCAPE_VARIABLE : 0)) 670 goto bail0; 671 } 672 } 673 return FcStrBufDone (&buf); 674bail0: 675 FcStrBufDestroy (&buf); 676 return 0; 677} 678#define __fcname__ 679#include "fcaliastail.h" 680#undef __fcname__ 681