diff options
| author | Chong Yidong | 2008-06-10 20:01:06 +0000 |
|---|---|---|
| committer | Chong Yidong | 2008-06-10 20:01:06 +0000 |
| commit | 8c102d5bfee908d9f09506377bed7ab61ef0cda0 (patch) | |
| tree | 8734fc79dd5f21cdd52fabf3ea812c22bd8830cd | |
| parent | 0abdd19768c8a2c058a79aab773fd908a26c0754 (diff) | |
| download | emacs-8c102d5bfee908d9f09506377bed7ab61ef0cda0.tar.gz emacs-8c102d5bfee908d9f09506377bed7ab61ef0cda0.zip | |
(font_parse_fcname): Accept GTK-style font names too.
| -rw-r--r-- | src/font.c | 303 |
1 files changed, 217 insertions, 86 deletions
diff --git a/src/font.c b/src/font.c index 04de0cfdf03..72ef2d3b58d 100644 --- a/src/font.c +++ b/src/font.c | |||
| @@ -1323,122 +1323,253 @@ font_unparse_xlfd (font, pixel_size, name, nbytes) | |||
| 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; | ||
| 1344 | else | ||
| 1345 | { | 1355 | { |
| 1346 | Lisp_Object family; | 1356 | if (*p == '\\' && p[1]) |
| 1347 | double point_size; | 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 | } | ||
| 1348 | 1382 | ||
| 1349 | for (p0 = name + 1; *p0 && (*p0 != '-' && *p0 != ':'); p0++) | 1383 | if (family_end) |
| 1350 | if (*p0 == '\\' && p0[1]) | 1384 | { |
| 1351 | p0++; | 1385 | /* A fontconfig name with size and/or property data. */ |
| 1352 | family = font_intern_prop (name, p0 - name, 1); | 1386 | if (family_end > name) |
| 1353 | if (*p0 == '-') | ||
| 1354 | { | 1387 | { |
| 1355 | if (! isdigit (p0[1])) | 1388 | Lisp_Object family; |
| 1356 | return -1; | 1389 | family = font_intern_prop (name, family_end - name, 1); |
| 1357 | point_size = strtod (p0 + 1, &p1); | 1390 | ASET (font, FONT_FAMILY_INDEX, family); |
| 1358 | if (*p1 && *p1 != ':') | 1391 | } |
| 1359 | return -1; | 1392 | if (size_beg) |
| 1393 | { | ||
| 1394 | double point_size = strtod (size_beg, &size_end); | ||
| 1360 | ASET (font, FONT_SIZE_INDEX, make_float (point_size)); | 1395 | ASET (font, FONT_SIZE_INDEX, make_float (point_size)); |
| 1361 | p0 = p1; | 1396 | if (*size_end == ':' && size_end[1]) |
| 1397 | props_beg = size_end + 1; | ||
| 1362 | } | 1398 | } |
| 1363 | ASET (font, FONT_FAMILY_INDEX, family); | 1399 | if (props_beg) |
| 1364 | } | 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; | ||
| 1365 | 1405 | ||
| 1366 | len -= p0 - name; | 1406 | name = copy = alloca (name + len - props_beg); |
| 1367 | copy = alloca (len + 1); | 1407 | if (! copy) |
| 1368 | if (! copy) | 1408 | return -1; |
| 1369 | return -1; | 1409 | |
| 1370 | name = copy; | 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++); | ||
| 1371 | 1464 | ||
| 1372 | /* Now parse ":KEY=VAL" patterns. Store known keys and values in | 1465 | val = font_intern_prop (p, word_len, 0); |
| 1373 | extra, copy unknown ones to COPY. It is stored in extra slot by | 1466 | if (! NILP (val)) |
| 1374 | the key QCfc_unknown_spec. */ | 1467 | { |
| 1375 | while (*p0) | 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 | } | ||
| 1487 | else | ||
| 1376 | { | 1488 | { |
| 1377 | Lisp_Object key, val; | 1489 | /* Either a fontconfig-style name with no size and property |
| 1378 | int prop; | 1490 | data, or a GTK-style name. */ |
| 1491 | Lisp_Object prop; | ||
| 1492 | int word_len, prop_found = 0; | ||
| 1379 | 1493 | ||
| 1380 | for (p1 = p0 + 1; *p1 && *p1 != '=' && *p1 != ':'; p1++); | 1494 | for (p = name; *p; p = *q ? q + 1 : q) |
| 1381 | if (*p1 != '=') | ||
| 1382 | { | 1495 | { |
| 1383 | /* Must be an enumerated value. */ | 1496 | if (isdigit (*p)) |
| 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); | 1538 | } |
| 1431 | else | 1539 | else if (PROP_MATCH ("Bold", 4)) |
| 1432 | bcopy (keyhead, copy, p1 - keyhead); | 1540 | { |
| 1433 | copy += p1 - keyhead; | 1541 | prop_found = 1; |
| 1542 | prop = font_intern_prop ("bold", 4, 1); | ||
| 1543 | FONT_SET_STYLE (font, FONT_WEIGHT_INDEX, prop); | ||
| 1544 | } | ||
| 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); | ||
| 1434 | } | 1556 | } |
| 1557 | else { | ||
| 1558 | if (prop_found) | ||
| 1559 | return -1; /* Unknown property in GTK-style font name. */ | ||
| 1560 | family_end = q; | ||
| 1561 | } | ||
| 1435 | } | 1562 | } |
| 1436 | p0 = p1; | 1563 | #undef PROP_MATCH |
| 1437 | } | ||
| 1438 | if (name != copy) | ||
| 1439 | font_put_extra (font, QCfc_unknown_spec, | ||
| 1440 | make_unibyte_string (name, copy - name)); | ||
| 1441 | 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 | ||