font.c 124 KB
Newer Older
Kenichi Handa's avatar
Kenichi Handa committed
1
/* font.c -- "Font" primitives.
Glenn Morris's avatar
Glenn Morris committed
2 3
   Copyright (C) 2006, 2007, 2008 Free Software Foundation, Inc.
   Copyright (C) 2006, 2007, 2008
Kenichi Handa's avatar
Kenichi Handa committed
4 5 6 7 8
     National Institute of Advanced Industrial Science and Technology (AIST)
     Registration Number H13PRO009

This file is part of GNU Emacs.

9
GNU Emacs is free software: you can redistribute it and/or modify
Kenichi Handa's avatar
Kenichi Handa committed
10
it under the terms of the GNU General Public License as published by
11 12
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Kenichi Handa's avatar
Kenichi Handa committed
13 14 15 16 17 18 19

GNU Emacs is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
20
along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
Kenichi Handa's avatar
Kenichi Handa committed
21 22 23 24

#include <config.h>
#include <stdio.h>
#include <stdlib.h>
Kenichi Handa's avatar
Kenichi Handa committed
25
#include <strings.h>
Kenichi Handa's avatar
Kenichi Handa committed
26
#include <ctype.h>
27 28 29
#ifdef HAVE_M17N_FLT
#include <m17n-flt.h>
#endif
Kenichi Handa's avatar
Kenichi Handa committed
30 31 32 33

#include "lisp.h"
#include "buffer.h"
#include "frame.h"
Kenichi Handa's avatar
Kenichi Handa committed
34
#include "window.h"
Kenichi Handa's avatar
Kenichi Handa committed
35 36 37 38 39 40 41
#include "dispextern.h"
#include "charset.h"
#include "character.h"
#include "composite.h"
#include "fontset.h"
#include "font.h"

Kenichi Handa's avatar
Kenichi Handa committed
42 43 44 45 46 47 48 49 50 51 52 53
#ifdef HAVE_X_WINDOWS
#include "xterm.h"
#endif /* HAVE_X_WINDOWS */

#ifdef HAVE_NTGUI
#include "w32term.h"
#endif /* HAVE_NTGUI */

#ifdef MAC_OS
#include "macterm.h"
#endif /* MAC_OS */

Kenichi Handa's avatar
Kenichi Handa committed
54
Lisp_Object Qfont_spec, Qfont_entity, Qfont_object;
Kenichi Handa's avatar
Kenichi Handa committed
55

Kenichi Handa's avatar
Kenichi Handa committed
56 57
Lisp_Object Qopentype;

Kenichi Handa's avatar
Kenichi Handa committed
58
/* Important character set strings.  */
Kenichi Handa's avatar
Kenichi Handa committed
59
Lisp_Object Qiso8859_1, Qiso10646_1, Qunicode_bmp, Qunicode_sip;
60

Kenichi Handa's avatar
Kenichi Handa committed
61 62
/* Special vector of zero length.  This is repeatedly used by (struct
   font_driver *)->list when a specified font is not found. */
Kenichi Handa's avatar
Kenichi Handa committed
63
static Lisp_Object null_vector;
Kenichi Handa's avatar
Kenichi Handa committed
64

65 66 67
static Lisp_Object Vfont_weight_table, Vfont_slant_table, Vfont_width_table;

/* Vector of Vfont_weight_table, Vfont_slant_table, and Vfont_width_table. */
Kenichi Handa's avatar
Kenichi Handa committed
68 69
static Lisp_Object font_style_table;

70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
/* Structure used for tables mapping weight, slant, and width numeric
   values and their names.  */

struct table_entry
{
  int numeric;
  /* The first one is a valid name as a face attribute.
     The second one (if any) is a typical name in XLFD field.  */
  char *names[5];
  Lisp_Object *symbols;
};

/* Table of weight numeric values and their names.  This table must be
   sorted by numeric values in ascending order.  */

static struct table_entry weight_table[] =
{
  { 0, { "thin" }},
  { 20, { "ultra-light", "ultralight" }},
  { 40, { "extra-light", "extralight" }},
  { 50, { "light" }},
  { 75, { "semi-light", "semilight", "demilight", "book" }},
  { 100, { "normal", "medium", "regular" }},
  { 180, { "semi-bold", "semibold", "demibold", "demi" }},
  { 200, { "bold" }},
  { 205, { "extra-bold", "extrabold" }},
  { 210, { "ultra-bold", "ultrabold", "black" }}
};

/* Table of slant numeric values and their names.  This table must be
   sorted by numeric values in ascending order.  */

static struct table_entry slant_table[] =
{
  { 0, { "reverse-oblique", "ro" }},
  { 10, { "reverse-italic", "ri" }},
  { 100, { "normal", "r" }},
  { 200, { "italic" ,"i", "ot" }},
  { 210, { "oblique", "o" }}
};

/* Table of width numeric values and their names.  This table must be
   sorted by numeric values in ascending order.  */

static struct table_entry width_table[] =
{
  { 50, { "ultra-condensed", "ultracondensed" }},
  { 63, { "extra-condensed", "extracondensed" }},
  { 75, { "condensed", "compressed", "narrow" }},
  { 87, { "semi-condensed", "semicondensed", "demicondensed" }},
  { 100, { "normal", "medium", "regular" }},
  { 113, { "semi-expanded", "semiexpanded", "demiexpanded" }},
  { 125, { "expanded" }},
  { 150, { "extra-expanded", "extraexpanded" }},
  { 200, { "ultra-expanded", "ultraexpanded", "wide" }}
};

Kenichi Handa's avatar
Kenichi Handa committed
127
extern Lisp_Object Qnormal;
Kenichi Handa's avatar
Kenichi Handa committed
128 129 130

/* Symbols representing keys of normal font properties.  */
extern Lisp_Object QCtype, QCfamily, QCweight, QCslant, QCwidth, QCsize, QCname;
Kenichi Handa's avatar
Kenichi Handa committed
131
Lisp_Object QCfoundry, QCadstyle, QCregistry;
Kenichi Handa's avatar
Kenichi Handa committed
132
/* Symbols representing keys of font extra info.  */
Kenichi Handa's avatar
Kenichi Handa committed
133 134
Lisp_Object QCspacing, QCdpi, QCscalable, QCotf, QClang, QCscript, QCavgwidth;
Lisp_Object QCantialias, QCfont_entity, QCfc_unknown_spec;
135 136
/* Symbols representing values of font spacing property.  */
Lisp_Object Qc, Qm, Qp, Qd;
Kenichi Handa's avatar
Kenichi Handa committed
137

138 139
Lisp_Object Vfont_encoding_alist;

140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
/* Alist of font registry symbol and the corresponding charsets
   information.  The information is retrieved from
   Vfont_encoding_alist on demand.

   Eash element has the form:
	(REGISTRY . (ENCODING-CHARSET-ID . REPERTORY-CHARSET-ID))
   or
	(REGISTRY . nil)

   In the former form, ENCODING-CHARSET-ID is an ID of a charset that
   encodes a character code to a glyph code of a font, and
   REPERTORY-CHARSET-ID is an ID of a charset that tells if a
   character is supported by a font.

   The latter form means that the information for REGISTRY couldn't be
   retrieved.  */
static Lisp_Object font_charset_alist;

158 159
/* List of all font drivers.  Each font-backend (XXXfont.c) calls
   register_font_driver in syms_of_XXXfont to register its font-driver
Kenichi Handa's avatar
Kenichi Handa committed
160 161 162
   here.  */
static struct font_driver_list *font_driver_list;

Kenichi Handa's avatar
Kenichi Handa committed
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204


/* Creaters of font-related Lisp object.  */

Lisp_Object
font_make_spec ()
{
  Lisp_Object font_spec;
  struct font_spec *spec
    = ((struct font_spec *)
       allocate_pseudovector (VECSIZE (struct font_spec),
			      FONT_SPEC_MAX, PVEC_FONT));
  XSETFONT (font_spec, spec);
  return font_spec;
}

Lisp_Object
font_make_entity ()
{
  Lisp_Object font_entity;
  struct font_entity *entity
    = ((struct font_entity *)
       allocate_pseudovector (VECSIZE (struct font_entity),
			      FONT_ENTITY_MAX, PVEC_FONT));
  XSETFONT (font_entity, entity);
  return font_entity;
}

Lisp_Object
font_make_object (size)
     int size;
{
  Lisp_Object font_object;
  struct font *font
    = (struct font *) allocate_pseudovector (size, FONT_OBJECT_MAX, PVEC_FONT);
  XSETFONT (font_object, font);

  return font_object;
}



205
static int font_pixel_size P_ ((FRAME_PTR f, Lisp_Object));
Kenichi Handa's avatar
Kenichi Handa committed
206
static Lisp_Object font_open_entity P_ ((FRAME_PTR, Lisp_Object, int));
Kenichi Handa's avatar
Kenichi Handa committed
207 208
static Lisp_Object font_matching_entity P_ ((FRAME_PTR, Lisp_Object *,
					     Lisp_Object));
Kenichi Handa's avatar
Kenichi Handa committed
209 210 211 212

/* Number of registered font drivers.  */
static int num_font_drivers;

Kenichi Handa's avatar
Kenichi Handa committed
213 214 215 216 217 218 219 220 221 222 223 224

/* Return a Lispy value of a font property value at STR and LEN bytes.
   If STR is "*", it returns nil.
   If all characters in STR are digits, it returns an integer.
   Otherwise, it returns a symbol interned from STR.  */

Lisp_Object
font_intern_prop (str, len)
     char *str;
     int len;
{
  int i;
225
  Lisp_Object tem;
Kenichi Handa's avatar
Kenichi Handa committed
226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248
  Lisp_Object obarray;

  if (len == 1 && *str == '*')
    return Qnil;
  if (len >=1 && isdigit (*str))
    {
      for (i = 1; i < len; i++)
	if (! isdigit (str[i]))
	  break;
      if (i == len)
	return make_number (atoi (str));
    }

  /* The following code is copied from the function intern (in lread.c).  */
  obarray = Vobarray;
  if (!VECTORP (obarray) || XVECTOR (obarray)->size == 0)
    obarray = check_obarray (obarray);
  tem = oblookup (obarray, str, len, len);
  if (SYMBOLP (tem))
    return tem;
  return Fintern (make_unibyte_string (str, len), obarray);
}

249
/* Return a pixel size of font-spec SPEC on frame F.  */
250

251 252 253 254 255
static int
font_pixel_size (f, spec)
     FRAME_PTR f;
     Lisp_Object spec;
{
256
#ifdef HAVE_WINDOW_SYSTEM
257 258
  Lisp_Object size = AREF (spec, FONT_SIZE_INDEX);
  double point_size;
Kenichi Handa's avatar
Kenichi Handa committed
259
  int dpi, pixel_size;
260
  Lisp_Object val;
261

262 263 264
  if (INTEGERP (size))
    return XINT (size);
  if (NILP (size))
265
    return 0;
266
  font_assert (FLOATP (size));
267
  point_size = XFLOAT_DATA (size);
Kenichi Handa's avatar
Kenichi Handa committed
268 269 270
  val = AREF (spec, FONT_DPI_INDEX);
  if (INTEGERP (val))
    dpi = XINT (XCDR (val));
271 272 273 274
  else
    dpi = f->resy;
  pixel_size = POINT_TO_PIXEL (point_size, dpi);
  return pixel_size;
275 276 277
#else
  return 1;
#endif
278 279
}

Kenichi Handa's avatar
Kenichi Handa committed
280

Kenichi Handa's avatar
Kenichi Handa committed
281 282 283 284 285 286
/* Return a value of PROP's VAL (symbol or integer) to be stored in a
   font vector.  If VAL is not valid (i.e. not registered in
   font_style_table), return -1 if NOERROR is zero, and return a
   proper index if NOERROR is nonzero.  In that case, register VAL in
   font_style_table if VAL is a symbol, and return a closest index if
   VAL is an integer.  */
Kenichi Handa's avatar
Kenichi Handa committed
287

Kenichi Handa's avatar
Kenichi Handa committed
288 289
int
font_style_to_value (prop, val, noerror)
Kenichi Handa's avatar
Kenichi Handa committed
290
     enum font_property_index prop;
Kenichi Handa's avatar
Kenichi Handa committed
291 292
     Lisp_Object val;
     int noerror;
Kenichi Handa's avatar
Kenichi Handa committed
293
{
Kenichi Handa's avatar
Kenichi Handa committed
294 295
  Lisp_Object table = AREF (font_style_table, prop - FONT_WEIGHT_INDEX);
  int len = ASIZE (table);
296
  int i, j;
Kenichi Handa's avatar
Kenichi Handa committed
297

Kenichi Handa's avatar
Kenichi Handa committed
298
  if (SYMBOLP (val))
Kenichi Handa's avatar
Kenichi Handa committed
299
    {
Kenichi Handa's avatar
Kenichi Handa committed
300 301 302 303 304
      char *s;
      Lisp_Object args[2], elt;

      /* At first try exact match.  */
      for (i = 0; i < len; i++)
305 306 307 308
	for (j = 1; j < ASIZE (AREF (table, i)); j++)
	  if (EQ (val, AREF (AREF (table, i), j)))
	    return ((XINT (AREF (AREF (table, i), 0)) << 8)
		    | (i << 4) | (j - 1));
Kenichi Handa's avatar
Kenichi Handa committed
309
      /* Try also with case-folding match.  */
310
      s = (char *) SDATA (SYMBOL_NAME (val));
Kenichi Handa's avatar
Kenichi Handa committed
311
      for (i = 0; i < len; i++)
312 313 314 315 316 317 318
	for (j = 1; j < ASIZE (AREF (table, i)); j++)
	  {
	    elt = AREF (AREF (table, i), j);
	    if (strcasecmp (s, (char *) SDATA (SYMBOL_NAME (elt))) == 0)
	      return ((XINT (AREF (AREF (table, i), 0)) << 8)
		      | (i << 4) | (j - 1));
	  }
Kenichi Handa's avatar
Kenichi Handa committed
319 320 321 322
      if (! noerror)
	return -1;
      if (len == 255)
	abort ();
323 324
      elt = Fmake_vector (make_number (2), make_number (255));
      ASET (elt, 1, val);
Kenichi Handa's avatar
Kenichi Handa committed
325
      args[0] = table;
326
      args[1] = Fmake_vector (make_number (1), elt);
Kenichi Handa's avatar
Kenichi Handa committed
327
      ASET (font_style_table, prop - FONT_WEIGHT_INDEX, Fvconcat (2, args));
328
      return (255 << 8) | (i << 4);
Kenichi Handa's avatar
Kenichi Handa committed
329
    }
Kenichi Handa's avatar
Kenichi Handa committed
330 331
  else
    {
332
      int i, last_n;
Kenichi Handa's avatar
Kenichi Handa committed
333
      int numeric = XINT (val);
Kenichi Handa's avatar
Kenichi Handa committed
334

335
      for (i = 0, last_n = -1; i < len; i++)
Kenichi Handa's avatar
Kenichi Handa committed
336
	{
337
	  int n = XINT (AREF (AREF (table, i), 0));
Kenichi Handa's avatar
Kenichi Handa committed
338

Kenichi Handa's avatar
Kenichi Handa committed
339
	  if (numeric == n)
340
	    return (n << 8) | (i << 4);
Kenichi Handa's avatar
Kenichi Handa committed
341 342 343 344
	  if (numeric < n)
	    {
	      if (! noerror)
		return -1;
345 346
	      return ((i == 0 || n - numeric < numeric - last_n)
		      ? (n << 8) | (i << 4): (last_n << 8 | ((i - 1) << 4)));
Kenichi Handa's avatar
Kenichi Handa committed
347 348 349 350 351
	    }
	  last_n = n;
	}
      if (! noerror)
	return -1;
352
      return ((last_n << 8) | ((i - 1) << 4));
Kenichi Handa's avatar
Kenichi Handa committed
353 354
    }
}
Kenichi Handa's avatar
Kenichi Handa committed
355 356

Lisp_Object
Kenichi Handa's avatar
Kenichi Handa committed
357 358 359 360
font_style_symbolic (font, prop, for_face)
     Lisp_Object font;
     enum font_property_index prop;
     int for_face;
Kenichi Handa's avatar
Kenichi Handa committed
361
{
Kenichi Handa's avatar
Kenichi Handa committed
362
  Lisp_Object val = AREF (font, prop);
363 364
  Lisp_Object table, elt;
  int i;
Kenichi Handa's avatar
Kenichi Handa committed
365

Kenichi Handa's avatar
Kenichi Handa committed
366 367 368
  if (NILP (val))
    return Qnil;
  table = AREF (font_style_table, prop - FONT_WEIGHT_INDEX);
369 370 371 372 373
  i = XINT (val) & 0xFF;
  font_assert (((i >> 4) & 0xF) < ASIZE (table));
  elt = AREF (table, ((i >> 4) & 0xF));
  font_assert ((i & 0xF) + 1 < ASIZE (elt));
  return (for_face ? AREF (elt, 1) : AREF (elt, (i & 0xF) + 1));
Kenichi Handa's avatar
Kenichi Handa committed
374 375 376 377
}

extern Lisp_Object Vface_alternative_font_family_alist;

378 379
extern Lisp_Object find_font_encoding P_ ((Lisp_Object));

Kenichi Handa's avatar
Kenichi Handa committed
380

381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405
/* Return ENCODING or a cons of ENCODING and REPERTORY of the font
   FONTNAME.  ENCODING is a charset symbol that specifies the encoding
   of the font.  REPERTORY is a charset symbol or nil.  */

Lisp_Object
find_font_encoding (fontname)
     Lisp_Object fontname;
{
  Lisp_Object tail, elt;

  for (tail = Vfont_encoding_alist; CONSP (tail); tail = XCDR (tail))
    {
      elt = XCAR (tail);
      if (CONSP (elt)
	  && STRINGP (XCAR (elt))
	  && fast_string_match_ignore_case (XCAR (elt), fontname) >= 0
	  && (SYMBOLP (XCDR (elt))
	      ? CHARSETP (XCDR (elt))
	      : CONSP (XCDR (elt)) && CHARSETP (XCAR (XCDR (elt)))))
	return (XCDR (elt));
    }
  /* We don't know the encoding of this font.  Let's assume `ascii'.  */
  return Qascii;
}

406 407 408 409 410 411 412 413 414 415 416 417
/* Return encoding charset and repertory charset for REGISTRY in
   ENCODING and REPERTORY correspondingly.  If correct information for
   REGISTRY is available, return 0.  Otherwise return -1.  */

int
font_registry_charsets (registry, encoding, repertory)
     Lisp_Object registry;
     struct charset **encoding, **repertory;
{
  Lisp_Object val;
  int encoding_id, repertory_id;

Kenichi Handa's avatar
Kenichi Handa committed
418
  val = Fassoc_string (registry, font_charset_alist, Qt);
419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446
  if (! NILP (val))
    {
      val = XCDR (val);
      if (NILP (val))
	return -1;
      encoding_id = XINT (XCAR (val));
      repertory_id = XINT (XCDR (val));
    }
  else
    {
      val = find_font_encoding (SYMBOL_NAME (registry));
      if (SYMBOLP (val) && CHARSETP (val))
	{
	  encoding_id = repertory_id = XINT (CHARSET_SYMBOL_ID (val));
	}
      else if (CONSP (val))
	{
	  if (! CHARSETP (XCAR (val)))
	    goto invalid_entry;
	  encoding_id = XINT (CHARSET_SYMBOL_ID (XCAR (val)));
	  if (NILP (XCDR (val)))
	    repertory_id = -1;
	  else
	    {
	      if (! CHARSETP (XCDR (val)))
		goto invalid_entry;
	      repertory_id = XINT (CHARSET_SYMBOL_ID (XCDR (val)));
	    }
447
	}
448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466
      else
	goto invalid_entry;
      val = Fcons (make_number (encoding_id), make_number (repertory_id));
      font_charset_alist
	= nconc2 (font_charset_alist, Fcons (Fcons (registry, val), Qnil));
    }

  if (encoding)
    *encoding = CHARSET_FROM_ID (encoding_id);
  if (repertory)
    *repertory = repertory_id >= 0 ? CHARSET_FROM_ID (repertory_id) : NULL;
  return 0;

 invalid_entry:
  font_charset_alist
    = nconc2 (font_charset_alist, Fcons (Fcons (registry, Qnil), Qnil));
  return -1;
}

Kenichi Handa's avatar
Kenichi Handa committed
467

468 469 470
/* Font property value validaters.  See the comment of
   font_property_table for the meaning of the arguments.  */

Kenichi Handa's avatar
Kenichi Handa committed
471
static Lisp_Object font_prop_validate P_ ((int, Lisp_Object, Lisp_Object));
472 473 474 475
static Lisp_Object font_prop_validate_symbol P_ ((Lisp_Object, Lisp_Object));
static Lisp_Object font_prop_validate_style P_ ((Lisp_Object, Lisp_Object));
static Lisp_Object font_prop_validate_non_neg P_ ((Lisp_Object, Lisp_Object));
static Lisp_Object font_prop_validate_spacing P_ ((Lisp_Object, Lisp_Object));
Kenichi Handa's avatar
Kenichi Handa committed
476
static int get_font_prop_index P_ ((Lisp_Object));
Kenichi Handa's avatar
Kenichi Handa committed
477 478

static Lisp_Object
479
font_prop_validate_symbol (prop, val)
480
     Lisp_Object prop, val;
Kenichi Handa's avatar
Kenichi Handa committed
481 482
{
  if (STRINGP (val))
Kenichi Handa's avatar
Kenichi Handa committed
483 484
    val = Fintern (val, Qnil);
  if (! SYMBOLP (val))
Kenichi Handa's avatar
Kenichi Handa committed
485
    val = Qerror;
Kenichi Handa's avatar
Kenichi Handa committed
486 487
  else if (EQ (prop, QCregistry))
    val = Fintern (Fdowncase (SYMBOL_NAME (val)), Qnil);
Kenichi Handa's avatar
Kenichi Handa committed
488 489 490
  return val;
}

Kenichi Handa's avatar
Kenichi Handa committed
491

Kenichi Handa's avatar
Kenichi Handa committed
492
static Lisp_Object
Kenichi Handa's avatar
Kenichi Handa committed
493 494
font_prop_validate_style (style, val)
     Lisp_Object style, val;
Kenichi Handa's avatar
Kenichi Handa committed
495
{
Kenichi Handa's avatar
Kenichi Handa committed
496 497 498 499 500
  enum font_property_index prop = (EQ (style, QCweight) ? FONT_WEIGHT_INDEX
				   : EQ (style, QCslant) ? FONT_SLANT_INDEX
				   : FONT_WIDTH_INDEX);
  int n;
  if (INTEGERP (val))
Kenichi Handa's avatar
Kenichi Handa committed
501
    {
Kenichi Handa's avatar
Kenichi Handa committed
502 503 504
      n = XINT (val);
      if ((n & 0xFF)
	  >= ASIZE (AREF (font_style_table, prop - FONT_WEIGHT_INDEX)))
Kenichi Handa's avatar
Kenichi Handa committed
505 506 507
	val = Qerror;
      else
	{
Kenichi Handa's avatar
Kenichi Handa committed
508 509
	  Lisp_Object elt = AREF (AREF (font_style_table, prop - FONT_WEIGHT_INDEX), n & 0xFF);
	  if (XINT (XCDR (elt)) != (n >> 8))
Kenichi Handa's avatar
Kenichi Handa committed
510 511 512
	    val = Qerror;
	}
    }
Kenichi Handa's avatar
Kenichi Handa committed
513 514 515 516 517 518 519 520
  else if (SYMBOLP (val))
    {
      int n = font_style_to_value (prop, val, 0);

      val = n >= 0 ? make_number (n) : Qerror;
    }
  else
    val = Qerror;
Kenichi Handa's avatar
Kenichi Handa committed
521 522 523 524
  return val;
}

static Lisp_Object
525
font_prop_validate_non_neg (prop, val)
526
     Lisp_Object prop, val;
Kenichi Handa's avatar
Kenichi Handa committed
527 528 529 530 531 532
{
  return (NATNUMP (val) || (FLOATP (val) && XFLOAT_DATA (val) >= 0)
	  ? val : Qerror);
}

static Lisp_Object
533
font_prop_validate_spacing (prop, val)
534 535 536 537 538 539 540 541 542 543
     Lisp_Object prop, val;
{
  if (NILP (val) || (NATNUMP (val) && XINT (val) <= FONT_SPACING_CHARCELL))
    return val;
  if (EQ (val, Qc))
    return make_number (FONT_SPACING_CHARCELL);
  if (EQ (val, Qm))
    return make_number (FONT_SPACING_MONO);
  if (EQ (val, Qp))
    return make_number (FONT_SPACING_PROPORTIONAL);
Kenichi Handa's avatar
Kenichi Handa committed
544 545
  if (EQ (val, Qd))
    return make_number (FONT_SPACING_DUAL);
546 547 548
  return Qerror;
}

549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583
static Lisp_Object
font_prop_validate_otf (prop, val)
     Lisp_Object prop, val;
{
  Lisp_Object tail, tmp;
  int i;

  /* VAL = (SCRIPT [ LANGSYS [ GSUB-FEATURES [ GPOS-FEATURES ]]])
     GSUB-FEATURES = (FEATURE ... [ nil FEATURE ... ]) | nil
     GPOS-FEATURES = (FEATURE ... [ nil FEATURE ... ]) | nil  */
  if (! CONSP (val))
    return Qerror;
  if (! SYMBOLP (XCAR (val)))
    return Qerror;
  tail = XCDR (val);
  if (NILP (tail))
    return val;
  if (! CONSP (tail) || ! SYMBOLP (XCAR (val)))
    return Qerror;
  for (i = 0; i < 2; i++)
    {
      tail = XCDR (tail);
      if (NILP (tail))
	return val;
      if (! CONSP (tail))
	return Qerror;
      for (tmp = XCAR (tail); CONSP (tmp); tmp = XCDR (tmp))
	if (! SYMBOLP (XCAR (tmp)))
	  return Qerror;
      if (! NILP (tmp))
	return Qerror;
    }
  return val;
}

584 585
/* Structure of known font property keys and validater of the
   values.  */
Kenichi Handa's avatar
Kenichi Handa committed
586 587
struct
{
588
  /* Pointer to the key symbol.  */
Kenichi Handa's avatar
Kenichi Handa committed
589
  Lisp_Object *key;
590 591 592 593
  /* Function to validate PROP's value VAL, or NULL if any value is
     ok.  The value is VAL or its regularized value if VAL is valid,
     and Qerror if not.  */
  Lisp_Object (*validater) P_ ((Lisp_Object prop, Lisp_Object val));
594 595
} font_property_table[] =
  { { &QCtype, font_prop_validate_symbol },
Kenichi Handa's avatar
Kenichi Handa committed
596 597 598 599 600 601 602
    { &QCfoundry, font_prop_validate_symbol },
    { &QCfamily, font_prop_validate_symbol },
    { &QCadstyle, font_prop_validate_symbol },
    { &QCregistry, font_prop_validate_symbol },
    { &QCweight, font_prop_validate_style },
    { &QCslant, font_prop_validate_style },
    { &QCwidth, font_prop_validate_style },
603 604 605
    { &QCsize, font_prop_validate_non_neg },
    { &QCdpi, font_prop_validate_non_neg },
    { &QCspacing, font_prop_validate_spacing },
Kenichi Handa's avatar
Kenichi Handa committed
606 607 608 609 610 611
    { &QCavgwidth, font_prop_validate_non_neg },
    /* The order of the above entries must match with enum
       font_property_index.  */
    { &QClang, font_prop_validate_symbol },
    { &QCscript, font_prop_validate_symbol },
    { &QCotf, font_prop_validate_otf }
Kenichi Handa's avatar
Kenichi Handa committed
612 613
  };

614
/* Size (number of elements) of the above table.  */
615 616 617
#define FONT_PROPERTY_TABLE_SIZE \
  ((sizeof font_property_table) / (sizeof *font_property_table))

618
/* Return an index number of font property KEY or -1 if KEY is not an
Kenichi Handa's avatar
Kenichi Handa committed
619
   already known property.  */
620

621
static int
Kenichi Handa's avatar
Kenichi Handa committed
622
get_font_prop_index (key)
Kenichi Handa's avatar
Kenichi Handa committed
623 624
     Lisp_Object key;
{
Kenichi Handa's avatar
Kenichi Handa committed
625 626 627 628 629
  int i;

  for (i = 0; i < FONT_PROPERTY_TABLE_SIZE; i++)
    if (EQ (key, *font_property_table[i].key))
      return i;
630
  return -1;
Kenichi Handa's avatar
Kenichi Handa committed
631 632
}

Kenichi Handa's avatar
Kenichi Handa committed
633 634 635
/* Validate the font property.  The property key is specified by the
   symbol PROP, or the index IDX (if PROP is nil).  If VAL is invalid,
   signal an error.  The value is VAL or the regularized one.  */
636

Kenichi Handa's avatar
Kenichi Handa committed
637
static Lisp_Object
Kenichi Handa's avatar
Kenichi Handa committed
638 639 640
font_prop_validate (idx, prop, val)
     int idx;
     Lisp_Object prop, val;
Kenichi Handa's avatar
Kenichi Handa committed
641
{
Kenichi Handa's avatar
Kenichi Handa committed
642
  Lisp_Object validated;
Kenichi Handa's avatar
Kenichi Handa committed
643

644 645
  if (NILP (val))
    return val;
Kenichi Handa's avatar
Kenichi Handa committed
646 647 648
  if (NILP (prop))
    prop = *font_property_table[idx].key;
  else
649
    {
Kenichi Handa's avatar
Kenichi Handa committed
650 651 652
      idx = get_font_prop_index (prop);
      if (idx < 0)
	return val;
653
    }
Kenichi Handa's avatar
Kenichi Handa committed
654 655 656 657
  validated = (font_property_table[idx].validater) (prop, val);
  if (EQ (validated, Qerror))
    signal_error ("invalid font property", Fcons (prop, val));
  return validated;
Kenichi Handa's avatar
Kenichi Handa committed
658
}
659

Kenichi Handa's avatar
Kenichi Handa committed
660 661 662

/* Store VAL as a value of extra font property PROP in FONT while
   keeping the sorting order.  Don't check the validity of VAL.  */
663

664
Lisp_Object
665
font_put_extra (font, prop, val)
666 667 668
     Lisp_Object font, prop, val;
{
  Lisp_Object extra = AREF (font, FONT_EXTRA_INDEX);
669
  Lisp_Object slot = (NILP (extra) ? Qnil : assq_no_quit (prop, extra));
670 671 672

  if (NILP (slot))
    {
Kenichi Handa's avatar
Kenichi Handa committed
673 674 675 676 677 678 679 680 681
      Lisp_Object prev = Qnil;

      while (CONSP (extra)
	     && NILP (Fstring_lessp (prop, XCAR (XCAR (extra)))))
	prev = extra, extra = XCDR (extra);
      if (NILP (prev))
	ASET (font, FONT_EXTRA_INDEX, Fcons (Fcons (prop, val), extra));
      else
	XSETCDR (prev, Fcons (Fcons (prop, val), extra));
682
      return val;
683 684
    }
  XSETCDR (slot, val);
685
  return val;
686 687
}

Kenichi Handa's avatar
Kenichi Handa committed
688 689 690

/* Font name parser and unparser */

691 692 693
static int parse_matrix P_ ((char *));
static int font_expand_wildcards P_ ((Lisp_Object *, int));
static int font_parse_name P_ ((char *, Lisp_Object));
Kenichi Handa's avatar
Kenichi Handa committed
694

695
/* An enumerator for each field of an XLFD font name.  */
Kenichi Handa's avatar
Kenichi Handa committed
696 697 698 699 700 701 702 703
enum xlfd_field_index
{
  XLFD_FOUNDRY_INDEX,
  XLFD_FAMILY_INDEX,
  XLFD_WEIGHT_INDEX,
  XLFD_SLANT_INDEX,
  XLFD_SWIDTH_INDEX,
  XLFD_ADSTYLE_INDEX,
704 705
  XLFD_PIXEL_INDEX,
  XLFD_POINT_INDEX,
Kenichi Handa's avatar
Kenichi Handa committed
706 707 708 709 710 711 712 713 714
  XLFD_RESX_INDEX,
  XLFD_RESY_INDEX,
  XLFD_SPACING_INDEX,
  XLFD_AVGWIDTH_INDEX,
  XLFD_REGISTRY_INDEX,
  XLFD_ENCODING_INDEX,
  XLFD_LAST_INDEX
};

715
/* An enumerator for mask bit corresponding to each XLFD field.  */
716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734
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
};


Kenichi Handa's avatar
Kenichi Handa committed
735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767
/* Parse P pointing the pixel/point size field of the form
   `[A B C D]' which specifies a transformation matrix:

	A  B  0
	C  D  0
	0  0  1

   by which all glyphs of the font are transformed.  The spec says
   that scalar value N for the pixel/point size is equivalent to:
   A = N * resx/resy, B = C = 0, D = N.

   Return the scalar value N if the form is valid.  Otherwise return
   -1.  */

static int
parse_matrix (p)
     char *p;
{
  double matrix[4];
  char *end;
  int i;

  for (i = 0, p++; i < 4 && *p && *p != ']'; i++)
    {
      if (*p == '~')
	matrix[i] = - strtod (p + 1, &end);
      else
	matrix[i] = strtod (p, &end);
      p = end;
    }
  return (i == 4 ? (int) matrix[3] : -1);
}

768 769 770 771
/* 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.  */

772
static int
773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789
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;
790
  int range_from, range_to;
791 792 793 794 795 796
  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_LARGENUM_MASK (XLFD_POINT_MASK | XLFD_RESX_MASK | XLFD_RESY_MASK \
797
			    | XLFD_AVGWIDTH_MASK)
798 799 800 801 802 803 804 805
#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;

806 807 808 809
  /* The triplet RANGE_FROM, RANGE_TO, and RANGE_MASK is a
     position-based retriction for FIELD[I].  */
  for (i = 0, range_from = 0, range_to = 14 - n; i < n;
       i++, range_from++, range_to++, range_mask <<= 1)
810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831
    {
      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);

832 833 834
	      if (i + 1 == n)
		from = to = XLFD_ENCODING_INDEX,
		  mask = XLFD_ENCODING_MASK;
835 836 837
	      else if (numeric == 0)
		from = XLFD_PIXEL_INDEX, to = XLFD_AVGWIDTH_INDEX,
		  mask = XLFD_PIXEL_MASK | XLFD_LARGENUM_MASK;
838 839 840
	      else if (numeric <= 48)
		from = to = XLFD_PIXEL_INDEX,
		  mask = XLFD_PIXEL_MASK;
841
	      else
842
		from = XLFD_POINT_INDEX, to = XLFD_AVGWIDTH_INDEX,
843 844
		  mask = XLFD_LARGENUM_MASK;
	    }
Kenichi Handa's avatar
Kenichi Handa committed
845
	  else if (SBYTES (SYMBOL_NAME (val)) == 0)
846 847 848 849 850 851 852 853 854 855 856 857 858 859 860
	    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;
	    }
861 862
	  else if (range_from <= XLFD_WEIGHT_INDEX
		   && range_to >= XLFD_WEIGHT_INDEX
Kenichi Handa's avatar
Kenichi Handa committed
863
		   && FONT_WEIGHT_NAME_NUMERIC (val) >= 0)
864
	    from = to = XLFD_WEIGHT_INDEX, mask = XLFD_WEIGHT_MASK;
865 866
	  else if (range_from <= XLFD_SLANT_INDEX
		   && range_to >= XLFD_SLANT_INDEX
Kenichi Handa's avatar
Kenichi Handa committed
867
		   && FONT_SLANT_NAME_NUMERIC (val) >= 0)
868
	    from = to = XLFD_SLANT_INDEX, mask = XLFD_SLANT_MASK;
869 870
	  else if (range_from <= XLFD_SWIDTH_INDEX
		   && range_to >= XLFD_SWIDTH_INDEX
Kenichi Handa's avatar
Kenichi Handa committed
871
		   && FONT_WIDTH_NAME_NUMERIC (val) >= 0)
872 873 874
	    from = to = XLFD_SWIDTH_INDEX, mask = XLFD_SWIDTH_MASK;
	  else
	    {
875
	      if (EQ (val, Qc) || EQ (val, Qm) || EQ (val, Qp) || EQ (val, Qd))
876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898
		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)
899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932
	    {
	      /* The range is narrowed by value-based restrictions.
		 Reflect it to the other fields.  */

	      /* Following fields should be after FROM.  */
	      range_from = from;
	      /* Preceding fields should be before TO.  */
	      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;
		}
	    }
933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958
	}
    }

  /* 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;
}

959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991

#ifdef ENABLE_CHECKING
/* Match a 14-field XLFD pattern against a full XLFD font name.  */
static int
font_match_xlfd (char *pattern, char *name)
{
  while (*pattern && *name)
    {
      if (*pattern == *name)
	pattern++;
      else if (*pattern == '*')
	if (*name == pattern[1])
	  pattern += 2;
	else
	  ;
      else
	return 0;
      name++;
    }
  return 1;
}

/* Make sure the font object matches the XLFD font name.  */
static int
font_check_xlfd_parse (Lisp_Object font, char *name)
{
  char name_check[256];
  font_unparse_xlfd (font, 0, name_check, 255);
  return font_match_xlfd (name_check, name);
}

#endif

Kenichi Handa's avatar
Kenichi Handa committed
992

993
/* Parse NAME (null terminated) as XLFD and store information in FONT
994 995 996 997 998 999 1000 1001
   (font-spec or font-entity).  Size property of FONT is set as
   follows:
	specified XLFD fields		FONT property
	---------------------		-------------
	PIXEL_SIZE			PIXEL_SIZE (Lisp integer)
	POINT_SIZE and RESY		calculated pixel size (Lisp integer)
	POINT_SIZE			POINT_SIZE/10 (Lisp float)

1002
   If NAME is successfully parsed, return 0.  Otherwise return -1.
1003

1004 1005
   FONT is usually a font-spec, but when this function is called from
   X font backend driver, it is a font-entity.  In that case, NAME is
Kenichi Handa's avatar
Kenichi Handa committed
1006
   a fully specified XLFD.  */
Kenichi Handa's avatar
Kenichi Handa committed
1007 1008

int
1009
font_parse_xlfd (name, font)
Kenichi Handa's avatar
Kenichi Handa committed
1010 1011 1012 1013
     char *name;
     Lisp_Object font;
{
  int len = strlen (name);
Kenichi Handa's avatar
Kenichi Handa committed
1014
  int i, j, n;
1015
  char *f[XLFD_LAST_INDEX + 1];
Kenichi Handa's avatar
Kenichi Handa committed
1016
  Lisp_Object val;
1017
  char *p;
Kenichi Handa's avatar
Kenichi Handa committed
1018 1019 1020 1021

  if (len > 255)
    /* Maximum XLFD name length is 255. */
    return -1;
1022 1023 1024 1025 1026 1027
  /* Accept "*-.." as a fully specified XLFD. */
  if (name[0] == '*' && name[1] == '-')
    i = 1, f[XLFD_FOUNDRY_INDEX] = name;
  else
    i = 0;
  for (p = name + i; *p; p++)
Kenichi Handa's avatar
Kenichi Handa committed
1028 1029 1030 1031 1032 1033 1034
    if (*p == '-')
      {
	f[i++] = p + 1;
	if (i == XLFD_LAST_INDEX)
	  break;
      }
  f[i] = name + len;
Kenichi Handa's avatar
Kenichi Handa committed
1035

Kenichi Handa's avatar
Kenichi Handa committed
1036
#define INTERN_FIELD(N) font_intern_prop (f[N], f[(N) + 1] - 1 - f[N])
1037

1038
  if (i == XLFD_LAST_INDEX)
1039
    {
Kenichi Handa's avatar
Kenichi Handa committed
1040
      /* Fully specified XLFD.  */
1041 1042
      int pixel_size;

Kenichi Handa's avatar
Kenichi Handa committed
1043 1044 1045 1046
      ASET (font, FONT_FOUNDRY_INDEX, INTERN_FIELD (XLFD_FOUNDRY_INDEX));
      ASET (font, FONT_FAMILY_INDEX, INTERN_FIELD (XLFD_FAMILY_INDEX));
      for (i = XLFD_WEIGHT_INDEX, j = FONT_WEIGHT_INDEX;
	   i <= XLFD_SWIDTH_INDEX; i++, j++)
1047
	{
Kenichi Handa's avatar
Kenichi Handa committed
1048
	  val = INTERN_FIELD (i);
1049
	  if (! NILP (val))
1050
	    {
Kenichi Handa's avatar
Kenichi Handa committed
1051 1052 1053
	      if ((n = font_style_to_value (j, INTERN_FIELD (i), 0)) < 0)
		return -1;
	      ASET (font, j, make_number (n));
1054 1055
	    }
	}
Kenichi Handa's avatar
Kenichi Handa committed
1056 1057 1058 1059 1060 1061 1062
      ASET (font, FONT_ADSTYLE_INDEX, INTERN_FIELD (XLFD_ADSTYLE_INDEX));
      if (strcmp (f[XLFD_REGISTRY_INDEX], "*-*") == 0)
	ASET (font, FONT_REGISTRY_INDEX, Qnil);
      else
	ASET (font, FONT_REGISTRY_INDEX,
	      font_intern_prop (f[XLFD_REGISTRY_INDEX],
				f[XLFD_LAST_INDEX] - f[XLFD_REGISTRY_INDEX]));
1063 1064
      p = f[XLFD_PIXEL_INDEX];
      if (*p == '[' && (pixel_size = parse_matrix (p)) >= 0)
1065
	ASET (font, FONT_SIZE_INDEX, make_number (pixel_size));
1066 1067
      else
	{
Kenichi Handa's avatar
Kenichi Handa committed
1068 1069
	  val = INTERN_FIELD (XLFD_PIXEL_INDEX);
	  if (INTEGERP (val))
1070 1071 1072 1073 1074
	    ASET (font, FONT_SIZE_INDEX, val);
	  else
	    {
	      double point_size = -1;

1075
	      font_assert (FONT_SPEC_P (font));
1076 1077 1078 1079 1080 1081 1082
	      p = f[XLFD_POINT_INDEX];
	      if (*p == '[')
		point_size = parse_matrix (p);
	      else if (isdigit (*p))
		point_size = atoi (p), point_size /= 10;
	      if (point_size >= 0)
		ASET (font, FONT_SIZE_INDEX, make_float (point_size));
1083 1084
	    }
	}
1085

Kenichi Handa's avatar
Kenichi Handa committed
1086 1087 1088
      ASET (font, FONT_DPI_INDEX, INTERN_FIELD (XLFD_RESY_INDEX));
      val = INTERN_FIELD (XLFD_SPACING_INDEX);
      if (! NILP (val))
1089
	{
Kenichi Handa's avatar
Kenichi Handa committed
1090 1091 1092 1093
	  val = font_prop_validate_spacing (QCspacing, val);
	  if (! INTEGERP (val))
	    return -1;
	  ASET (font, FONT_SPACING_INDEX, val);
1094 1095 1096 1097
	}
      p = f[XLFD_AVGWIDTH_INDEX];
      if (*p == '~')
	p++;
Kenichi Handa's avatar
Kenichi Handa committed
1098 1099
      ASET (font, FONT_AVGWIDTH_INDEX,
	    font_intern_prop (p, f[XLFD_REGISTRY_INDEX] - 1 - p));
1100 1101
    }
  else
Kenichi Handa's avatar
Kenichi Handa committed
1102
    {
1103
      int wild_card_found = 0;
1104
      Lisp_Object prop[XLFD_LAST_INDEX];
1105

Kenichi Handa's avatar
Kenichi Handa committed
1106 1107
      if (FONT_ENTITY_P (font))
	return -1;
1108
      for (j = 0; j < i; j++)
1109
	{
1110
	  if (*f[j] == '*')
1111
	    {
1112 1113 1114 1115 1116 1117
	      if (f[j][1] && f[j][1] != '-')
		return -1;
	      prop[j] = Qnil;
	      wild_card_found = 1;
	    }
	  else if (j + 1 < i)
Kenichi Handa's avatar
Kenichi Handa committed
1118
	    prop[j] = INTERN_FIELD (j);
1119
	  else
Kenichi Handa's avatar
Kenichi Handa committed
1120
	    prop[j] = font_intern_prop (f[j], f[i] - f[j]);
1121 1122
	}
      if (! wild_card_found)
Kenichi Handa's avatar
Kenichi Handa committed
1123
	return -1;
1124
      if (font_expand_wildcards (prop, i) < 0)
1125
	return -1;
1126

Kenichi Handa's avatar
Kenichi Handa committed
1127 1128 1129 1130
      ASET (font, FONT_FOUNDRY_INDEX, prop[XLFD_FOUNDRY_INDEX]);
      ASET (font, FONT_FAMILY_INDEX, prop[XLFD_FAMILY_INDEX]);
      for (i = XLFD_WEIGHT_INDEX, j = FONT_WEIGHT_INDEX;
	   i <= XLFD_SWIDTH_INDEX; i++, j++)
1131
	if (! NILP (prop[i]))
Kenichi Handa's avatar
Kenichi Handa committed
1132 1133 1134 1135 1136 1137
	  {
	    if ((n = font_style_to_value (j, prop[i], 1)) < 0)
	      return -1;
	    ASET (font, j, make_number (n));
	  }
      ASET (font, FONT_ADSTYLE_INDEX, prop[XLFD_ADSTYLE_INDEX]);
1138 1139
      val = prop[XLFD_REGISTRY_INDEX];
      if (NILP (val))
Kenichi Handa's avatar
Kenichi Handa committed
1140
	{
1141 1142
	  val = prop[XLFD_ENCODING_INDEX];
	  if (! NILP (val))
Kenichi Handa's avatar
Kenichi Handa committed
1143
	    val = concat2 (build_string ("*-"), SYMBOL_NAME (val));
1144
	}
1145
      else if (NILP (prop[XLFD_ENCODING_INDEX]))
Kenichi Handa's avatar
Kenichi Handa committed
1146
	val = concat2 (SYMBOL_NAME (val), build_string ("-*"));
1147
      else
Kenichi Handa's avatar
Kenichi Handa committed
1148 1149
	val = concat3 (SYMBOL_NAME (val), build_string ("-"),
		       SYMBOL_NAME (prop[XLFD_ENCODING_INDEX]));
1150
      if (! NILP (val))
Kenichi Handa's avatar
Kenichi Handa committed
1151
	ASET (font, FONT_REGISTRY_INDEX, Fintern (val, Qnil));
1152 1153 1154 1155

      if (INTEGERP (prop[XLFD_PIXEL_INDEX]))
	ASET (font, FONT_SIZE_INDEX, prop[XLFD_PIXEL_INDEX]);
      else if (INTEGERP (prop[XLFD_POINT_INDEX]))
1156
	{
1157
	  double point_size = XINT (prop[XLFD_POINT_INDEX]);
Kenichi Handa's avatar
Kenichi Handa committed
1158

1159 1160
	  ASET (font, FONT_SIZE_INDEX, make_float (point_size / 10));
	}
Kenichi Handa's avatar
Kenichi Handa committed
1161

Kenichi Handa's avatar
Kenichi Handa committed
1162 1163 1164 1165 1166 1167 1168 1169 1170 1171
      if (INTEGERP (prop[XLFD_RESX_INDEX]))
	ASET (font, FONT_DPI_INDEX, prop[XLFD_RESY_INDEX]);
      if (! NILP (prop[XLFD_SPACING_INDEX]))
	{
	  val = font_prop_validate_spacing (QCspacing,
					    prop[XLFD_SPACING_INDEX]);
	  if (! INTEGERP (val))
	    return -1;
	  ASET (font, FONT_SPACING_INDEX, val);
	}
1172
      if (INTEGERP (prop[XLFD_AVGWIDTH_INDEX]))
Kenichi Handa's avatar
Kenichi Handa committed
1173
	ASET (font, FONT_AVGWIDTH_INDEX, prop[XLFD_AVGWIDTH_INDEX]);
Kenichi Handa's avatar
Kenichi Handa committed
1174 1175
    }

1176
  return 0;
Kenichi Handa's avatar
Kenichi Handa committed
1177 1178 1179 1180 1181 1182 1183 1184 1185
}

/* Store XLFD name of FONT (font-spec or font-entity) in NAME (NBYTES
   length), and return the name length.  If FONT_SIZE_INDEX of FONT is
   0, use PIXEL_SIZE instead.  */

int
font_unparse_xlfd (font, pixel_size, name, nbytes)
     Lisp_Object font;
1186
     int pixel_size;
Kenichi Handa's avatar
Kenichi Handa committed
1187 1188 1189
     char *name;
     int nbytes;
{
1190
  char *f[XLFD_REGISTRY_INDEX + 1];
Kenichi Handa's avatar
Kenichi Handa committed
1191 1192 1193
  Lisp_Object val;
  int i, j, len = 0;

1194
  font_assert (FONTP (font));
Kenichi Handa's avatar
Kenichi Handa committed
1195 1196 1197 1198 1199 1200 1201 1202 1203 1204

  for (i = FONT_FOUNDRY_INDEX, j = XLFD_FOUNDRY_INDEX; i <= FONT_REGISTRY_INDEX;
       i++, j++)
    {
      if (i == FONT_ADSTYLE_INDEX)
	j = XLFD_ADSTYLE_INDEX;
      else if (i == FONT_REGISTRY_INDEX)
	j = XLFD_REGISTRY_INDEX;
      val = AREF (font, i);
      if (NILP (val))
1205 1206 1207 1208 1209 1210
	{
	  if (j == XLFD_REGISTRY_INDEX)
	    f[j] = "*-*", len += 4;
	  else
	    f[j] = "*", len += 2;
	}
Kenichi Handa's avatar
Kenichi Handa committed
1211 1212 1213 1214
      else
	{
	  if (SYMBOLP (val))
	    val = SYMBOL_NAME (val);
1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233
	  if (j == XLFD_REGISTRY_INDEX
	      && ! strchr ((char *) SDATA (val), '-'))
	    {
	      /* Change "jisx0208*" and "jisx0208" to "jisx0208*-*".  */
	      if (SDATA (val)[SBYTES (val) - 1] == '*')
		{
		  f[j] = alloca (SBYTES (val) + 3);
		  sprintf (f[j], "%s-*", SDATA (val));
		  len += SBYTES (val) + 3;
		}
	      else
		{
		  f[j] = alloca (SBYTES (val) + 4);
		  sprintf (f[j], "%s*-*", SDATA (val));
		  len += SBYTES (val) + 4;
		}
	    }
	  else
	    f[j] = (char *) SDATA (val), len += SBYTES (val) + 1;
Kenichi Handa's avatar
Kenichi Handa committed
1234 1235 1236 1237 1238 1239
	}
    }

  for (i = FONT_WEIGHT_INDEX, j = XLFD_WEIGHT_INDEX; i <= FONT_WIDTH_INDEX;
       i++, j++)
    {
Kenichi Handa's avatar
Kenichi Handa committed
1240
      val = font_style_symbolic (font, i, 0);
Kenichi Handa's avatar
Kenichi Handa committed
1241 1242 1243 1244
      if (NILP (val))
	f[j] = "*", len += 2;
      else
	{
Kenichi Handa's avatar
Kenichi Handa committed
1245
	  val = SYMBOL_NAME (val);
Kenichi Handa's avatar
Kenichi Handa committed
1246 1247 1248 1249 1250
	  f[j] = (char *) SDATA (val), len += SBYTES (val) + 1;
	}
    }

  val = AREF (font, FONT_SIZE_INDEX);
1251
  font_assert (NUMBERP (val) || NILP (val));
Kenichi Handa's avatar
Kenichi Handa committed
1252 1253
  if (INTEGERP (val))
    {
Kenichi Handa's avatar
Kenichi Handa committed
1254
      i = XINT (val);
1255 1256
      if (i <= 0)
	i = pixel_size;
Kenichi Handa's avatar
Kenichi Handa committed
1257
      if (i > 0)
1258 1259 1260 1261 1262 1263
	{
	  f[XLFD_PIXEL_INDEX] = alloca (22);
	  len += sprintf (f[XLFD_PIXEL_INDEX], "%d-*", i) + 1;
	}
      else
	f[XLFD_PIXEL_INDEX] = "*-*", len += 4;
Kenichi Handa's avatar
Kenichi Handa committed
1264 1265 1266
    }
  else if (FLOATP (val))
    {
Kenichi Handa's avatar
Kenichi Handa committed
1267
      i = XFLOAT_DATA (val) * 10;
1268 1269
      f[XLFD_PIXEL_INDEX] = alloca (12);
      len += sprintf (f[XLFD_PIXEL_INDEX], "*-%d", i) + 1;
Kenichi Handa's avatar
Kenichi Handa committed
1270 1271
    }
  else
1272 1273
    f[XLFD_PIXEL_INDEX] = "*-*", len += 4;

Kenichi Handa's avatar
Kenichi Handa committed
1274
  if (INTEGERP (AREF (font, FONT_DPI_INDEX)))
Kenichi Handa's avatar
Kenichi Handa committed
1275
    {
Kenichi Handa's avatar
Kenichi Handa committed
1276 1277 1278 1279
      i = XINT (AREF (font, FONT_DPI_INDEX));
      f[XLFD_RESX_INDEX] = alloca (22);
      len += sprintf (f[XLFD_RESX_INDEX],
		      "%d-%d", i, i) + 1;
Kenichi Handa's avatar
Kenichi Handa committed
1280