comparison src/font.c @ 95790:a486132d892c

(font_parse_fcname): Accept GTK-style font names too.
author Chong Yidong <cyd@stupidchicken.com>
date Tue, 10 Jun 2008 20:01:06 +0000
parents b490fda95b13
children 27e773c9952b
comparison
equal deleted inserted replaced
95789:2d4b2068b7ec 95790:a486132d892c
1321 f[XLFD_PIXEL_INDEX], f[XLFD_RESX_INDEX], 1321 f[XLFD_PIXEL_INDEX], f[XLFD_RESX_INDEX],
1322 f[XLFD_SPACING_INDEX], f[XLFD_AVGWIDTH_INDEX], 1322 f[XLFD_SPACING_INDEX], f[XLFD_AVGWIDTH_INDEX],
1323 f[XLFD_REGISTRY_INDEX]); 1323 f[XLFD_REGISTRY_INDEX]);
1324 } 1324 }
1325 1325
1326 /* Parse NAME (null terminated) as Fonconfig's name format and store 1326 /* Parse NAME (null terminated) and store information in FONT
1327 information in FONT (font-spec or font-entity). If NAME is 1327 (font-spec or font-entity). NAME is supplied in either the
1328 successfully parsed, return 0. Otherwise return -1. */ 1328 Fontconfig or GTK font name format. If NAME is successfully
1329 parsed, return 0. Otherwise return -1.
1330
1331 The fontconfig format is
1332
1333 FAMILY[-SIZE][:PROP1[=VAL1][:PROP2[=VAL2]...]]
1334
1335 The GTK format is
1336
1337 FAMILY [PROPS...] [SIZE]
1338
1339 This function tries to guess which format it is. */
1329 1340
1330 int 1341 int
1331 font_parse_fcname (name, font) 1342 font_parse_fcname (name, font)
1332 char *name; 1343 char *name;
1333 Lisp_Object font; 1344 Lisp_Object font;
1334 { 1345 {
1335 char *p0, *p1; 1346 char *p, *q;
1347 char *size_beg = NULL, *size_end = NULL;
1348 char *props_beg = NULL, *family_end = NULL;
1336 int len = strlen (name); 1349 int len = strlen (name);
1337 char *copy;
1338 1350
1339 if (len == 0) 1351 if (len == 0)
1340 return -1; 1352 return -1;
1341 /* It is assured that (name[0] && name[0] != '-'). */ 1353
1342 if (name[0] == ':') 1354 for (p = name; *p; p++)
1343 p0 = name; 1355 {
1356 if (*p == '\\' && p[1])
1357 p++;
1358 else if (*p == ':')
1359 {
1360 family_end = p;
1361 props_beg = p + 1;
1362 break;
1363 }
1364 else if (*p == '-')
1365 {
1366 int size_found = 1;
1367 for (q = p + 1; *q && *q != ':'; q++)
1368 if (! isdigit(*q))
1369 {
1370 size_found = 0;
1371 break;
1372 }
1373 if (size_found)
1374 {
1375 family_end = p;
1376 size_beg = p + 1;
1377 size_end = q;
1378 break;
1379 }
1380 }
1381 }
1382
1383 if (family_end)
1384 {
1385 /* A fontconfig name with size and/or property data. */
1386 if (family_end > name)
1387 {
1388 Lisp_Object family;
1389 family = font_intern_prop (name, family_end - name, 1);
1390 ASET (font, FONT_FAMILY_INDEX, family);
1391 }
1392 if (size_beg)
1393 {
1394 double point_size = strtod (size_beg, &size_end);
1395 ASET (font, FONT_SIZE_INDEX, make_float (point_size));
1396 if (*size_end == ':' && size_end[1])
1397 props_beg = size_end + 1;
1398 }
1399 if (props_beg)
1400 {
1401 /* Now parse ":KEY=VAL" patterns. Store known keys and values in
1402 extra, copy unknown ones to COPY. It is stored in extra slot by
1403 the key QCfc_unknown_spec. */
1404 char *copy;
1405
1406 name = copy = alloca (name + len - props_beg);
1407 if (! copy)
1408 return -1;
1409
1410 p = props_beg;
1411 while (*p)
1412 {
1413 Lisp_Object val;
1414 int word_len, prop;
1415
1416 #define PROP_MATCH(STR,N) ((word_len == N) && memcmp (p, STR, N) == 0)
1417
1418 for (q = p + 1; *q && *q != '=' && *q != ':'; q++);
1419 word_len = q - p;
1420 if (*q != '=')
1421 {
1422 /* Must be an enumerated value. */
1423 val = font_intern_prop (p, q - p, 1);
1424 if (PROP_MATCH ("light", 5)
1425 || PROP_MATCH ("medium", 6)
1426 || PROP_MATCH ("demibold", 8)
1427 || PROP_MATCH ("bold", 4)
1428 || PROP_MATCH ("black", 5))
1429 FONT_SET_STYLE (font, FONT_WEIGHT_INDEX, val);
1430 else if (PROP_MATCH ("roman", 5)
1431 || PROP_MATCH ("italic", 6)
1432 || PROP_MATCH ("oblique", 7))
1433 FONT_SET_STYLE (font, FONT_SLANT_INDEX, val);
1434 else if (PROP_MATCH ("charcell", 8))
1435 ASET (font, FONT_SPACING_INDEX,
1436 make_number (FONT_SPACING_CHARCELL));
1437 else if (PROP_MATCH ("mono", 4))
1438 ASET (font, FONT_SPACING_INDEX,
1439 make_number (FONT_SPACING_MONO));
1440 else if (PROP_MATCH ("proportional", 12))
1441 ASET (font, FONT_SPACING_INDEX,
1442 make_number (FONT_SPACING_PROPORTIONAL));
1443 else
1444 {
1445 /* Unknown key */
1446 bcopy (p, copy, word_len);
1447 copy += word_len;
1448 }
1449 }
1450 else /* KEY=VAL pairs */
1451 {
1452 Lisp_Object key;
1453 char *keyhead = p;
1454
1455 if (PROP_MATCH ("pixelsize=", 10))
1456 prop = FONT_SIZE_INDEX;
1457 else
1458 {
1459 key = font_intern_prop (p, q - p, 1);
1460 prop = get_font_prop_index (key);
1461 }
1462 p = q + 1;
1463 for (q = p; *q && *q != ':'; q++);
1464
1465 val = font_intern_prop (p, word_len, 0);
1466 if (! NILP (val))
1467 {
1468 if (prop >= FONT_FOUNDRY_INDEX
1469 && prop < FONT_EXTRA_INDEX)
1470 ASET (font, prop,
1471 font_prop_validate (prop, Qnil, val));
1472 else if (prop >= 0)
1473 Ffont_put (font, key, val);
1474 else
1475 bcopy (keyhead, copy, q - keyhead);
1476 copy += q - keyhead;
1477 }
1478 }
1479 p = *q ? q + 1 : q;
1480 #undef PROP_MATCH
1481 }
1482 if (name != copy)
1483 font_put_extra (font, QCfc_unknown_spec,
1484 make_unibyte_string (name, copy - name));
1485 }
1486 }
1344 else 1487 else
1345 { 1488 {
1346 Lisp_Object family; 1489 /* Either a fontconfig-style name with no size and property
1347 double point_size; 1490 data, or a GTK-style name. */
1348 1491 Lisp_Object prop;
1349 for (p0 = name + 1; *p0 && (*p0 != '-' && *p0 != ':'); p0++) 1492 int word_len, prop_found = 0;
1350 if (*p0 == '\\' && p0[1]) 1493
1351 p0++; 1494 for (p = name; *p; p = *q ? q + 1 : q)
1352 family = font_intern_prop (name, p0 - name, 1); 1495 {
1353 if (*p0 == '-') 1496 if (isdigit (*p))
1354 {
1355 if (! isdigit (p0[1]))
1356 return -1;
1357 point_size = strtod (p0 + 1, &p1);
1358 if (*p1 && *p1 != ':')
1359 return -1;
1360 ASET (font, FONT_SIZE_INDEX, make_float (point_size));
1361 p0 = p1;
1362 }
1363 ASET (font, FONT_FAMILY_INDEX, family);
1364 }
1365
1366 len -= p0 - name;
1367 copy = alloca (len + 1);
1368 if (! copy)
1369 return -1;
1370 name = copy;
1371
1372 /* Now parse ":KEY=VAL" patterns. Store known keys and values in
1373 extra, copy unknown ones to COPY. It is stored in extra slot by
1374 the key QCfc_unknown_spec. */
1375 while (*p0)
1376 {
1377 Lisp_Object key, val;
1378 int prop;
1379
1380 for (p1 = p0 + 1; *p1 && *p1 != '=' && *p1 != ':'; p1++);
1381 if (*p1 != '=')
1382 {
1383 /* Must be an enumerated value. */
1384 val = font_intern_prop (p0 + 1, p1 - p0 - 1, 1);
1385 if (memcmp (p0 + 1, "light", 5) == 0
1386 || memcmp (p0 + 1, "medium", 6) == 0
1387 || memcmp (p0 + 1, "demibold", 8) == 0
1388 || memcmp (p0 + 1, "bold", 4) == 0
1389 || memcmp (p0 + 1, "black", 5) == 0)
1390 FONT_SET_STYLE (font, FONT_WEIGHT_INDEX, val);
1391 else if (memcmp (p0 + 1, "roman", 5) == 0
1392 || memcmp (p0 + 1, "italic", 6) == 0
1393 || memcmp (p0 + 1, "oblique", 7) == 0)
1394 FONT_SET_STYLE (font, FONT_SLANT_INDEX, val);
1395 else if (memcmp (p0 + 1, "charcell", 8) == 0
1396 || memcmp (p0 + 1, "mono", 4) == 0
1397 || memcmp (p0 + 1, "proportional", 12) == 0)
1398 { 1497 {
1399 int spacing = (p0[1] == 'c' ? FONT_SPACING_CHARCELL 1498 char *r;
1400 : p0[1] == 'm' ? FONT_SPACING_MONO 1499 int size_found = 1;
1401 : FONT_SPACING_PROPORTIONAL); 1500 for (q = p + 1; *q && *q != ' '; q++)
1402 ASET (font, FONT_SPACING_INDEX, make_number (spacing)); 1501 if (! isdigit (*q))
1502 {
1503 size_found = 0;
1504 break;
1505 }
1506 if (size_found)
1507 {
1508 double point_size = strtod (p, &q);
1509 ASET (font, FONT_SIZE_INDEX, make_float (point_size));
1510 continue;
1511 }
1403 } 1512 }
1404 else 1513
1514 for (q = p + 1; *q && *q != ' '; q++)
1515 if (*q == '\\' && q[1])
1516 q++;
1517 word_len = q - p;
1518
1519 #define PROP_MATCH(STR,N) ((word_len == N) && memcmp (p, STR, N) == 0)
1520
1521 if (PROP_MATCH ("Ultra-Light", 11))
1405 { 1522 {
1406 /* unknown key */ 1523 prop_found = 1;
1407 bcopy (p0, copy, p1 - p0); 1524 prop = font_intern_prop ("ultra-light", 11, 1);
1408 copy += p1 - p0; 1525 FONT_SET_STYLE (font, FONT_WEIGHT_INDEX, prop);
1409 } 1526 }
1410 } 1527 else if (PROP_MATCH ("Light", 5))
1411 else
1412 {
1413 char *keyhead = p0;
1414
1415 if (memcmp (p0 + 1, "pixelsize=", 10) == 0)
1416 prop = FONT_SIZE_INDEX;
1417 else
1418 { 1528 {
1419 key = font_intern_prop (p0, p1 - p0, 1); 1529 prop_found = 1;
1420 prop = get_font_prop_index (key); 1530 prop = font_intern_prop ("light", 5, 1);
1531 FONT_SET_STYLE (font, FONT_WEIGHT_INDEX, prop);
1421 } 1532 }
1422 p0 = p1 + 1; 1533 else if (PROP_MATCH ("Semi-Bold", 9))
1423 for (p1 = p0; *p1 && *p1 != ':'; p1++);
1424 val = font_intern_prop (p0, p1 - p0, 0);
1425 if (! NILP (val))
1426 { 1534 {
1427 if (prop >= FONT_FOUNDRY_INDEX && prop < FONT_EXTRA_INDEX) 1535 prop_found = 1;
1428 ASET (font, prop, font_prop_validate (prop, Qnil, val)); 1536 prop = font_intern_prop ("semi-bold", 9, 1);
1429 else if (prop >= 0) 1537 FONT_SET_STYLE (font, FONT_WEIGHT_INDEX, prop);
1430 Ffont_put (font, key, val);
1431 else
1432 bcopy (keyhead, copy, p1 - keyhead);
1433 copy += p1 - keyhead;
1434 } 1538 }
1435 } 1539 else if (PROP_MATCH ("Bold", 4))
1436 p0 = p1; 1540 {
1437 } 1541 prop_found = 1;
1438 if (name != copy) 1542 prop = font_intern_prop ("bold", 4, 1);
1439 font_put_extra (font, QCfc_unknown_spec, 1543 FONT_SET_STYLE (font, FONT_WEIGHT_INDEX, prop);
1440 make_unibyte_string (name, copy - name)); 1544 }
1441 1545 else if (PROP_MATCH ("Italic", 6))
1546 {
1547 prop_found = 1;
1548 prop = font_intern_prop ("italic", 4, 1);
1549 FONT_SET_STYLE (font, FONT_SLANT_INDEX, prop);
1550 }
1551 else if (PROP_MATCH ("Oblique", 7))
1552 {
1553 prop_found = 1;
1554 prop = font_intern_prop ("oblique", 7, 1);
1555 FONT_SET_STYLE (font, FONT_SLANT_INDEX, prop);
1556 }
1557 else {
1558 if (prop_found)
1559 return -1; /* Unknown property in GTK-style font name. */
1560 family_end = q;
1561 }
1562 }
1563 #undef PROP_MATCH
1564
1565 if (family_end)
1566 {
1567 Lisp_Object family;
1568 family = font_intern_prop (name, family_end - name, 1);
1569 ASET (font, FONT_FAMILY_INDEX, family);
1570 }
1571 }
1572
1442 return 0; 1573 return 0;
1443 } 1574 }
1444 1575
1445 /* Store fontconfig's font name of FONT (font-spec or font-entity) in 1576 /* Store fontconfig's font name of FONT (font-spec or font-entity) in
1446 NAME (NBYTES length), and return the name length. If 1577 NAME (NBYTES length), and return the name length. If