Mercurial > emacs
changeset 90451:6ffc9b378367
(enum xlfd_field_index): Rename XLFD_XXX_SIZE_INDEX to
XLFD_XXX_INDEX.
(enum xlfd_field_mask): New enum.
(intern_font_field): Argument changed. Caller changed. If digits
are followed by non-digits, return a symbol.
(font_expand_wildcards): New function.
(font_parse_xlfd): Fix wildcard handling.
(Ffont_spec): If :name is specified, reflect the info in the other
properties.
author | Kenichi Handa <handa@m17n.org> |
---|---|
date | Wed, 14 Jun 2006 00:42:04 +0000 |
parents | 5c96354daf9e |
children | 92ed1b9edd67 |
files | src/font.c |
diffstat | 1 files changed, 376 insertions(+), 104 deletions(-) [+] |
line wrap: on
line diff
--- a/src/font.c Wed Jun 14 00:38:48 2006 +0000 +++ b/src/font.c Wed Jun 14 00:42:04 2006 +0000 @@ -358,8 +358,8 @@ XLFD_SLANT_INDEX, XLFD_SWIDTH_INDEX, XLFD_ADSTYLE_INDEX, - XLFD_PIXEL_SIZE_INDEX, - XLFD_POINT_SIZE_INDEX, + XLFD_PIXEL_INDEX, + XLFD_POINT_INDEX, XLFD_RESX_INDEX, XLFD_RESY_INDEX, XLFD_SPACING_INDEX, @@ -369,28 +369,49 @@ XLFD_LAST_INDEX }; -/* Return a symbol interned by string at STR and bytes LEN. +enum xlfd_field_mask +{ + XLFD_FOUNDRY_MASK = 0x0001, + XLFD_FAMILY_MASK = 0x0002, + XLFD_WEIGHT_MASK = 0x0004, + XLFD_SLANT_MASK = 0x0008, + XLFD_SWIDTH_MASK = 0x0010, + XLFD_ADSTYLE_MASK = 0x0020, + XLFD_PIXEL_MASK = 0x0040, + XLFD_POINT_MASK = 0x0080, + XLFD_RESX_MASK = 0x0100, + XLFD_RESY_MASK = 0x0200, + XLFD_SPACING_MASK = 0x0400, + XLFD_AVGWIDTH_MASK = 0x0800, + XLFD_REGISTRY_MASK = 0x1000, + XLFD_ENCODING_MASK = 0x2000 +}; + + +/* Return a Lispy value for string at STR and bytes LEN. If LEN == 0, return a null string. If the string is "*", return Qnil. It is assured that LEN < 256. */ static Lisp_Object -intern_font_field (f, xlfd) - char *f[XLFD_LAST_INDEX + 1]; - int xlfd; +intern_font_field (str, len) + char *str; + int len; { - char *str = f[xlfd] + 1; - int len; - - if (xlfd != XLFD_RESY_INDEX) - len = f[xlfd + 1] - f[xlfd] - 1; - else - len = f[XLFD_REGISTRY_INDEX] - f[xlfd] - 1; + int i; if (len == 0) return null_string; if (*str == '*' && len == 1) return Qnil; + if (isdigit (*str)) + { + for (i = 1; i < len; i++) + if (! isdigit (str[i])) + break; + if (i == len) + return make_number (atoi (str)); + } return intern_downcase (str, len); } @@ -427,6 +448,184 @@ return (i == 4 ? (int) matrix[3] : -1); } +/* Expand a wildcard field in FIELD (the first N fields are filled) to + multiple fields to fill in all 14 XLFD fields while restring a + field position by its contents. */ + +int +font_expand_wildcards (field, n) + Lisp_Object field[XLFD_LAST_INDEX]; + int n; +{ + /* Copy of FIELD. */ + Lisp_Object tmp[XLFD_LAST_INDEX]; + /* Array of information about where this element can go. Nth + element is for Nth element of FIELD. */ + struct { + /* Minimum possible field. */ + int from; + /* Maxinum possible field. */ + int to; + /* Bit mask of possible field. Nth bit corresponds to Nth field. */ + int mask; + } range[XLFD_LAST_INDEX]; + int i, j; + unsigned range_mask; + +#define XLFD_SYMBOL_MASK (XLFD_FOUNDRY_MASK | XLFD_FAMILY_MASK \ + | XLFD_ADSTYLE_MASK | XLFD_REGISTRY_MASK) +#define XLFD_NULL_MASK (XLFD_FOUNDRY_MASK | XLFD_ADSTYLE_MASK) +#define XLFD_SMALLNUM_MASK (XLFD_PIXEL_MASK | XLFD_ENCODING_MASK) +#define XLFD_LARGENUM_MASK (XLFD_POINT_MASK | XLFD_RESX_MASK | XLFD_RESY_MASK \ + | XLFD_AVGWIDTH_MASK | XLFD_ENCODING_MASK) +#define XLFD_REGENC_MASK (XLFD_REGISTRY_MASK | XLFD_ENCODING_MASK) + + /* Initialize RANGE_MASK for FIELD[0] which can be 0th to (14 - N)th + field. The value is shifted to left one bit by one in the + following loop. */ + for (i = 0, range_mask = 0; i <= 14 - n; i++) + range_mask = (range_mask << 1) | 1; + + for (i = 0; i < n; i++, range_mask <<= 1) + { + /* The triplet RANGE_FROM, RANGE_TO, and RANGE_MASK is a + position-based retriction for FIELD[I]. */ + int range_from = i, range_to = 14 - n + i; + Lisp_Object val = field[i]; + + tmp[i] = val; + if (NILP (val)) + { + /* Wildcard. */ + range[i].from = range_from; + range[i].to = range_to; + range[i].mask = range_mask; + } + else + { + /* The triplet FROM, TO, and MASK is a value-based + retriction for FIELD[I]. */ + int from, to; + unsigned mask; + + if (INTEGERP (val)) + { + int numeric = XINT (val); + + if (numeric <= 48) + from = XLFD_PIXEL_INDEX, to = XLFD_ENCODING_INDEX, + mask = XLFD_SMALLNUM_MASK; + else + from = XLFD_POINT_INDEX, to = XLFD_ENCODING_INDEX, + mask = XLFD_LARGENUM_MASK; + } + else if (EQ (val, null_string)) + from = XLFD_FOUNDRY_INDEX, to = XLFD_ADSTYLE_INDEX, + mask = XLFD_NULL_MASK; + else if (i == 0) + from = to = XLFD_FOUNDRY_INDEX, mask = XLFD_FOUNDRY_MASK; + else if (i + 1 == n) + { + Lisp_Object name = SYMBOL_NAME (val); + + if (SDATA (name)[SBYTES (name) - 1] == '*') + from = XLFD_REGISTRY_INDEX, to = XLFD_ENCODING_INDEX, + mask = XLFD_REGENC_MASK; + else + from = to = XLFD_ENCODING_INDEX, + mask = XLFD_ENCODING_MASK; + } + else if (!NILP (prop_name_to_numeric (FONT_WEIGHT_INDEX, val))) + from = to = XLFD_WEIGHT_INDEX, mask = XLFD_WEIGHT_MASK; + else if (!NILP (prop_name_to_numeric (FONT_SLANT_INDEX, val))) + from = to = XLFD_SLANT_INDEX, mask = XLFD_SLANT_MASK; + else if (!NILP (prop_name_to_numeric (FONT_WIDTH_INDEX, val))) + from = to = XLFD_SWIDTH_INDEX, mask = XLFD_SWIDTH_MASK; + else + { + Lisp_Object name = SYMBOL_NAME (val); + + if (SBYTES (name) == 1 + && (SDATA (name)[0] == 'c' + || SDATA (name)[0] == 'm' + || SDATA (name)[0] == 'p')) + from = to = XLFD_SPACING_INDEX, mask = XLFD_SPACING_MASK; + else + from = XLFD_FOUNDRY_INDEX, to = XLFD_ENCODING_INDEX, + mask = XLFD_SYMBOL_MASK; + } + + /* Merge position-based and value-based restrictions. */ + mask &= range_mask; + while (from < range_from) + mask &= ~(1 << from++); + while (from < 14 && ! (mask & (1 << from))) + from++; + while (to > range_to) + mask &= ~(1 << to--); + while (to >= 0 && ! (mask & (1 << to))) + to--; + if (from > to) + return -1; + range[i].from = from; + range[i].to = to; + range[i].mask = mask; + + if (from > range_from || to < range_to) + /* The range is narrowed by value-based restrictions. + Reflect it to the previous fields. */ + for (j = i - 1, from--, to--; j >= 0; j--, from--, to--) + { + /* Check FROM for non-wildcard field. */ + if (! NILP (tmp[j]) && range[j].from < from) + { + while (range[j].from < from) + range[j].mask &= ~(1 << range[j].from++); + while (from < 14 && ! (range[j].mask & (1 << from))) + from++; + range[j].from = from; + } + else + from = range[j].from; + if (range[j].to > to) + { + while (range[j].to > to) + range[j].mask &= ~(1 << range[j].to--); + while (to >= 0 && ! (range[j].mask & (1 << to))) + to--; + range[j].to = to; + } + else + to = range[j].to; + if (from > to) + return -1; + } + } + } + + /* Decide all fileds from restrictions in RANGE. */ + for (i = j = 0; i < n ; i++) + { + if (j < range[i].from) + { + if (i == 0 || ! NILP (tmp[i - 1])) + /* None of TMP[X] corresponds to Jth field. */ + return -1; + for (; j < range[i].from; j++) + field[j] = Qnil; + } + field[j++] = tmp[i]; + } + if (! NILP (tmp[n - 1]) && j < XLFD_REGISTRY_INDEX) + return -1; + for (; j < XLFD_LAST_INDEX; j++) + field[j] = Qnil; + if (INTEGERP (field[XLFD_ENCODING_INDEX])) + field[XLFD_ENCODING_INDEX] + = Fintern (Fnumber_to_string (field[XLFD_ENCODING_INDEX]), Qnil); + return 0; +} + /* Parse NAME (null terminated) as XLFD format, and store information in FONT (font-spec or font-entity). If NAME is successfully parsed, return 2 (non-scalable font), 1 (scalable vector font), or @@ -445,137 +644,206 @@ { int len = strlen (name); int i, j; - int pixel_size, resy, avwidth; + int pixel_size, resy, avgwidth; double point_size; - char *f[XLFD_LAST_INDEX + 1]; + Lisp_Object f[XLFD_LAST_INDEX]; Lisp_Object val; - int first_wildcard_field = -1, last_wildcard_field = XLFD_LAST_INDEX; + char *p; if (len > 255) /* Maximum XLFD name length is 255. */ return -1; - for (i = 0; *name; name++) - if (*name == '-' - && i < XLFD_LAST_INDEX) - { - f[i] = name; - if (name[1] == '*' && (! name[2] || name[2] == '-')) - { - if (first_wildcard_field < 0) - first_wildcard_field = i; - last_wildcard_field = i; - } - i++; - } - - f[XLFD_LAST_INDEX] = name; - if (i < XLFD_LAST_INDEX) + i = (name[0] == '*' && name[1] == '-'); + for (p = name + 1; *p; p++) { - /* Not a fully specified XLFD. */ - if (first_wildcard_field < 0 ) - /* No wild card. */ - return -1; - i--; - if (last_wildcard_field < i) + if (*p == '-') { - /* Shift fields after the last wildcard field. */ - for (j = XLFD_LAST_INDEX - 1; j > last_wildcard_field; j--, i--) - f[j] = f[i]; - /* Make all fields between the first and last wildcard fieled - also wildcard fields. */ - for (j--; j > first_wildcard_field; j--) - f[j] = "-*"; + i++; + if (i == XLFD_ENCODING_INDEX) + break; } } - f[XLFD_ENCODING_INDEX] = f[XLFD_LAST_INDEX]; + + pixel_size = resy = avgwidth = -1; + point_size = -1; + + if (i == XLFD_ENCODING_INDEX) + { + /* Fully specified XLFD. */ + if (name[0] == '-') + name++; + for (i = 0, p = name; ; p++) + { + if (*p == '-') + { + if (i < XLFD_PIXEL_INDEX) + f[i++] = intern_font_field (name, p - name); + else if (i == XLFD_PIXEL_INDEX) + { + if (isdigit (*name)) + pixel_size = atoi (name); + else if (*name == '[') + pixel_size = parse_matrix (name); + i++; + } + else if (i == XLFD_POINT_INDEX) + { + if (pixel_size < 0) + { + if (isdigit (*name)) + point_size = atoi (name); + else if (*name == '[') + point_size = parse_matrix (name); + } + i++; + } + else if (i == XLFD_RESX_INDEX) + { + /* Skip this field. */ + f[i++] = Qnil; + } + else if (i == XLFD_RESY_INDEX) + { + /* Stuff RESY, SPACING, and AVGWIDTH. */ + if (pixel_size < 0 && isdigit (*name)) + resy = atoi (name); + for (p++; *p != '-'; p++); + if (isdigit (p[1])) + avgwidth = atoi (p + 1); + else if (p[1] == '~' && isdigit (p[2])) + avgwidth = atoi (p + 2); + for (p++; *p != '-'; p++); + if (FONT_ENTITY_P (font)) + f[i] = intern_font_field (name, p - name); + else + f[i] = Qnil; + i = XLFD_REGISTRY_INDEX; + } + else + { + /* Stuff REGISTRY and ENCODING. */ + for (p++; *p; p++); + f[i++] = intern_font_field (name, p - name); + break; + } + name = p + 1; + } + } + xassert (i == XLFD_ENCODING_INDEX); + } + else + { + int wild_card_found = 0; + + if (name[0] == '-') + name++; + for (i = 0, p = name; ; p++) + { + if (*p == '-' || ! *p) + { + if (*name == '*') + { + if (name + 1 != p) + return -1; + f[i++] = Qnil; + wild_card_found = 1; + } + else if (isdigit (*name)) + { + f[i++] = make_number (atoi (name)); + /* Check if all chars in this field is number. */ + name++; + while (isdigit (*name)) name++; + if (name != p) + return -1; + } + else if (p == name) + f[i++] = null_string; + else + { + f[i++] = intern_downcase (name, p - name); + } + if (! *p) + break; + name = p + 1; + } + } + if (! wild_card_found) + return -1; + if (font_expand_wildcards (f, i) < 0) + return -1; + if (! NILP (f[XLFD_PIXEL_INDEX])) + pixel_size = XINT (f[XLFD_PIXEL_INDEX]); + if (! NILP (f[XLFD_POINT_INDEX])) + point_size = XINT (f[XLFD_POINT_INDEX]); + if (! NILP (f[XLFD_RESY_INDEX])) + resy = XINT (f[XLFD_RESY_INDEX]); + if (! NILP (f[XLFD_AVGWIDTH_INDEX])) + avgwidth = XINT (f[XLFD_AVGWIDTH_INDEX]); + if (NILP (f[XLFD_REGISTRY_INDEX])) + { + if (! NILP (f[XLFD_ENCODING_INDEX])) + f[XLFD_REGISTRY_INDEX] + = Fintern (concat2 (build_string ("*-"), + SYMBOL_NAME (f[XLFD_ENCODING_INDEX])), Qnil); + } + else + { + if (! NILP (f[XLFD_ENCODING_INDEX])) + f[XLFD_REGISTRY_INDEX] + = Fintern (concat2 (SYMBOL_NAME (f[XLFD_REGISTRY_INDEX]), + SYMBOL_NAME (f[XLFD_ENCODING_INDEX])), Qnil); + } + } if (! merge || NILP (AREF (font, FONT_FOUNDRY_INDEX))) - ASET (font, FONT_FOUNDRY_INDEX, intern_font_field (f, XLFD_FOUNDRY_INDEX)); + ASET (font, FONT_FOUNDRY_INDEX, f[XLFD_FOUNDRY_INDEX]); if (! merge || NILP (AREF (font, FONT_FAMILY_INDEX))) - ASET (font, FONT_FAMILY_INDEX, intern_font_field (f, XLFD_FAMILY_INDEX)); + ASET (font, FONT_FAMILY_INDEX, f[XLFD_FAMILY_INDEX]); if (! merge || NILP (AREF (font, FONT_ADSTYLE_INDEX))) - ASET (font, FONT_ADSTYLE_INDEX, intern_font_field (f, XLFD_ADSTYLE_INDEX)); + ASET (font, FONT_ADSTYLE_INDEX, f[XLFD_ADSTYLE_INDEX]); if (! merge || NILP (AREF (font, FONT_REGISTRY_INDEX))) - ASET (font, FONT_REGISTRY_INDEX, intern_font_field (f, XLFD_REGISTRY_INDEX)); + ASET (font, FONT_REGISTRY_INDEX, f[XLFD_REGISTRY_INDEX]); for (i = FONT_WEIGHT_INDEX, j = XLFD_WEIGHT_INDEX; j <= XLFD_SWIDTH_INDEX; i++, j++) if (! merge || NILP (AREF (font, i))) { - if (isdigit(f[j][1])) - val = make_number (atoi (f[j] + 1)); - else + if (! INTEGERP (f[j])) { - Lisp_Object sym = intern_font_field (f, j); - - val = prop_name_to_numeric (i, sym); - if (NILP (val)) - val = sym; + val = prop_name_to_numeric (i, f[j]); + if (INTEGERP (val)) + f[j] = val; } - ASET (font, i, val); + ASET (font, i, f[j]); } - if (f[XLFD_PIXEL_SIZE_INDEX][1] == '*') - pixel_size = -1; /* indicates "unspecified" */ - else if (f[XLFD_PIXEL_SIZE_INDEX][1] == '[') - pixel_size = parse_matrix (f[XLFD_PIXEL_SIZE_INDEX] + 1); - else if (isdigit (f[XLFD_PIXEL_SIZE_INDEX][1])) - pixel_size = strtod (f[XLFD_PIXEL_SIZE_INDEX] + 1, NULL); - else - pixel_size = -1; - if (pixel_size < 0 && FONT_ENTITY_P (font)) return -1; - if (f[XLFD_POINT_SIZE_INDEX][1] == '*') - point_size = -1; /* indicates "unspecified" */ - else if (f[XLFD_POINT_SIZE_INDEX][1] == '[') - point_size = parse_matrix (f[XLFD_POINT_SIZE_INDEX] + 1); - else if (isdigit (f[XLFD_POINT_SIZE_INDEX][1])) - point_size = strtod (f[XLFD_POINT_SIZE_INDEX] + 1, NULL); - else - point_size = -1; - - if (f[XLFD_RESY_INDEX][1] == '*') - resy = -1; /* indicates "unspecified" */ - else - resy = strtod (f[XLFD_RESY_INDEX] + 1, NULL); - - if (f[XLFD_AVGWIDTH_INDEX][1] == '*') - avwidth = -1; /* indicates "unspecified" */ - else if (f[XLFD_AVGWIDTH_INDEX][1] == '~') - avwidth = - strtod (f[XLFD_AVGWIDTH_INDEX] + 2, NULL); - else - avwidth = strtod (f[XLFD_AVGWIDTH_INDEX] + 1, NULL); - if (! merge || NILP (AREF (font, FONT_SIZE_INDEX))) { if (pixel_size >= 0) ASET (font, FONT_SIZE_INDEX, make_number (pixel_size)); - else + else if (point_size >= 0) { - if (point_size >= 0) + if (resy > 0) { - if (resy > 0) - { - pixel_size = POINT_TO_PIXEL (point_size, resy); - ASET (font, FONT_SIZE_INDEX, make_number (pixel_size)); - } - else - { - ASET (font, FONT_SIZE_INDEX, make_float (point_size / 10)); - } + pixel_size = POINT_TO_PIXEL (point_size, resy); + ASET (font, FONT_SIZE_INDEX, make_number (pixel_size)); } else - ASET (font, FONT_SIZE_INDEX, Qnil); + { + ASET (font, FONT_SIZE_INDEX, make_float (point_size / 10)); + } } } if (FONT_ENTITY_P (font) && EQ (AREF (font, FONT_TYPE_INDEX), Qx)) - ASET (font, FONT_EXTRA_INDEX, intern_font_field (f, XLFD_RESY_INDEX)); + ASET (font, FONT_EXTRA_INDEX, f[XLFD_RESY_INDEX]); - return (avwidth > 0 ? 2 : resy == 0); + return (avgwidth > 0 ? 2 : resy == 0); } /* Store XLFD name of FONT (font-spec or font-entity) in NAME (NBYTES @@ -1998,7 +2266,11 @@ if (prop < FONT_EXTRA_INDEX) ASET (spec, prop, (font_property_table[prop].validater) (prop, val)); else - extra = Fcons (Fcons (key, val), extra); + { + if (EQ (key, QCname)) + font_parse_xlfd ((char *) SDATA (val), spec, 0); + extra = Fcons (Fcons (key, val), extra); + } } ASET (spec, FONT_EXTRA_INDEX, extra); return spec;