diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/font.c | 2571 | ||||
| -rw-r--r-- | src/font.h | 479 | ||||
| -rw-r--r-- | src/ftfont.c | 731 | ||||
| -rw-r--r-- | src/ftxfont.c | 346 | ||||
| -rw-r--r-- | src/xfont.c | 868 | ||||
| -rw-r--r-- | src/xftfont.c | 552 |
6 files changed, 5547 insertions, 0 deletions
diff --git a/src/font.c b/src/font.c new file mode 100644 index 00000000000..eaf2ac0a84e --- /dev/null +++ b/src/font.c | |||
| @@ -0,0 +1,2571 @@ | |||
| 1 | /* font.c -- "Font" primitives. | ||
| 2 | Copyright (C) 2006 Free Software Foundation, Inc. | ||
| 3 | Copyright (C) 2006 | ||
| 4 | National Institute of Advanced Industrial Science and Technology (AIST) | ||
| 5 | Registration Number H13PRO009 | ||
| 6 | |||
| 7 | This file is part of GNU Emacs. | ||
| 8 | |||
| 9 | GNU Emacs is free software; you can redistribute it and/or modify | ||
| 10 | it under the terms of the GNU General Public License as published by | ||
| 11 | the Free Software Foundation; either version 2, or (at your option) | ||
| 12 | any later version. | ||
| 13 | |||
| 14 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 17 | GNU General Public License for more details. | ||
| 18 | |||
| 19 | You should have received a copy of the GNU General Public License | ||
| 20 | along with GNU Emacs; see the file COPYING. If not, write to | ||
| 21 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
| 22 | Boston, MA 02110-1301, USA. */ | ||
| 23 | |||
| 24 | #include <config.h> | ||
| 25 | #include <stdio.h> | ||
| 26 | #include <stdlib.h> | ||
| 27 | #include <ctype.h> | ||
| 28 | |||
| 29 | #include "lisp.h" | ||
| 30 | #include "buffer.h" | ||
| 31 | #include "frame.h" | ||
| 32 | #include "dispextern.h" | ||
| 33 | #include "charset.h" | ||
| 34 | #include "character.h" | ||
| 35 | #include "composite.h" | ||
| 36 | #include "fontset.h" | ||
| 37 | #include "font.h" | ||
| 38 | |||
| 39 | #define FONT_DEBUG | ||
| 40 | |||
| 41 | #ifdef FONT_DEBUG | ||
| 42 | #undef xassert | ||
| 43 | #define xassert(X) do {if (!(X)) abort ();} while (0) | ||
| 44 | #else | ||
| 45 | #define xassert(X) (void) 0 | ||
| 46 | #endif | ||
| 47 | |||
| 48 | int enable_font_backend; | ||
| 49 | |||
| 50 | Lisp_Object Qfontp; | ||
| 51 | |||
| 52 | /* Like CHECK_FONT_SPEC but also validate properties of the font-spec, | ||
| 53 | and set X to the validated result. */ | ||
| 54 | |||
| 55 | #define CHECK_VALIDATE_FONT_SPEC(x) \ | ||
| 56 | do { \ | ||
| 57 | if (! FONT_SPEC_P (x)) x = wrong_type_argument (Qfont, x); \ | ||
| 58 | x = font_prop_validate (x); \ | ||
| 59 | } while (0) | ||
| 60 | |||
| 61 | /* Number of pt per inch (from the TeXbook). */ | ||
| 62 | #define PT_PER_INCH 72.27 | ||
| 63 | |||
| 64 | /* Return a pixel size corresponding to POINT size (1/10 pt unit) on | ||
| 65 | resolution RESY. */ | ||
| 66 | #define POINT_TO_PIXEL(POINT, RESY) ((POINT) * (RESY) / PT_PER_INCH / 10 + 0.5) | ||
| 67 | |||
| 68 | #define PIXEL_TO_POINT(PIXEL, RESY) ((PIXEL) * PT_PER_INCH * 10 / (RESY) + 0.5) | ||
| 69 | |||
| 70 | /* Special string of zero length. It is used to specify a NULL name | ||
| 71 | in a font properties (e.g. adstyle). We don't use the symbol of | ||
| 72 | NULL name because it's confusing (Lisp printer prints nothing for | ||
| 73 | it). */ | ||
| 74 | Lisp_Object null_string; | ||
| 75 | |||
| 76 | /* Special vector of zero length. This is repeatedly used by (struct | ||
| 77 | font_driver *)->list when a specified font is not found. */ | ||
| 78 | Lisp_Object null_vector; | ||
| 79 | |||
| 80 | /* Vector of 3 elements. Each element is an alist for one of font | ||
| 81 | style properties (weight, slant, width). The alist contains a | ||
| 82 | mapping between symbolic property values (e.g. `medium' for weight) | ||
| 83 | and numeric property values (e.g. 100). So, it looks like this: | ||
| 84 | [((thin . 0) ... (heavy . 210)) | ||
| 85 | ((ro . 0) ... (ot . 210)) | ||
| 86 | ((ultracondensed . 50) ... (wide . 200))] */ | ||
| 87 | static Lisp_Object font_style_table; | ||
| 88 | |||
| 89 | /* Alist of font family vs the corresponding aliases. | ||
| 90 | Each element has this form: | ||
| 91 | (FAMILY ALIAS1 ALIAS2 ...) */ | ||
| 92 | |||
| 93 | static Lisp_Object font_family_alist; | ||
| 94 | |||
| 95 | /* Symbols representing keys of normal font properties. */ | ||
| 96 | extern Lisp_Object QCtype, QCfamily, QCweight, QCslant, QCwidth, QCsize, QCname; | ||
| 97 | Lisp_Object QCfoundry, QCadstyle, QCregistry, QCextra; | ||
| 98 | /* Symbols representing keys of font extra info. */ | ||
| 99 | Lisp_Object QCotf, QClanguage, QCscript; | ||
| 100 | |||
| 101 | /* List of all font drivers. All font-backends (XXXfont.c) call | ||
| 102 | add_font_driver in syms_of_XXXfont to register the font-driver | ||
| 103 | here. */ | ||
| 104 | static struct font_driver_list *font_driver_list; | ||
| 105 | |||
| 106 | static Lisp_Object prop_name_to_numeric P_ ((enum font_property_index, | ||
| 107 | Lisp_Object)); | ||
| 108 | static Lisp_Object prop_numeric_to_name P_ ((enum font_property_index, int)); | ||
| 109 | static Lisp_Object font_open_entity P_ ((FRAME_PTR, Lisp_Object, int)); | ||
| 110 | |||
| 111 | /* Number of registered font drivers. */ | ||
| 112 | static int num_font_drivers; | ||
| 113 | |||
| 114 | /* Return a numeric value corresponding to PROP's NAME (symbol). If | ||
| 115 | NAME is not registered in font_style_table, return Qnil. PROP must | ||
| 116 | be one of FONT_{WEIGHT|SLANT|SWIDTH}_INDEX. */ | ||
| 117 | |||
| 118 | static Lisp_Object | ||
| 119 | prop_name_to_numeric (prop, name) | ||
| 120 | enum font_property_index prop; | ||
| 121 | Lisp_Object name; | ||
| 122 | { | ||
| 123 | int table_index = prop - FONT_WEIGHT_INDEX; | ||
| 124 | Lisp_Object val; | ||
| 125 | |||
| 126 | val = assq_no_quit (name, AREF (font_style_table, table_index)); | ||
| 127 | return (NILP (val) ? Qnil : XCDR (val)); | ||
| 128 | } | ||
| 129 | |||
| 130 | |||
| 131 | /* Return a name (symbol) corresponding to PROP's NUMERIC value. If | ||
| 132 | no name is registered for NUMERIC in font_style_table, return a | ||
| 133 | symbol of integer name (e.g. `123'). PROP must be one of | ||
| 134 | FONT_{WEIGHT|SLANT|SWIDTH}_INDEX. */ | ||
| 135 | |||
| 136 | static Lisp_Object | ||
| 137 | prop_numeric_to_name (prop, numeric) | ||
| 138 | enum font_property_index prop; | ||
| 139 | int numeric; | ||
| 140 | { | ||
| 141 | int table_index = prop - FONT_WEIGHT_INDEX; | ||
| 142 | Lisp_Object table = AREF (font_style_table, table_index); | ||
| 143 | char buf[10]; | ||
| 144 | |||
| 145 | while (! NILP (table)) | ||
| 146 | { | ||
| 147 | if (XINT (XCDR (XCAR (table))) >= numeric) | ||
| 148 | { | ||
| 149 | if (XINT (XCDR (XCAR (table))) == numeric) | ||
| 150 | return XCAR (XCAR (table)); | ||
| 151 | else | ||
| 152 | break; | ||
| 153 | } | ||
| 154 | table = XCDR (table); | ||
| 155 | } | ||
| 156 | sprintf (buf, "%d", numeric); | ||
| 157 | return intern (buf); | ||
| 158 | } | ||
| 159 | |||
| 160 | |||
| 161 | /* Return a symbol whose name is STR (length LEN). If STR contains | ||
| 162 | uppercase letters, downcase them in advance. */ | ||
| 163 | |||
| 164 | Lisp_Object | ||
| 165 | intern_downcase (str, len) | ||
| 166 | char *str; | ||
| 167 | int len; | ||
| 168 | { | ||
| 169 | char *buf; | ||
| 170 | int i; | ||
| 171 | |||
| 172 | for (i = 0; i < len; i++) | ||
| 173 | if (isupper (str[i])) | ||
| 174 | break; | ||
| 175 | if (i == len) | ||
| 176 | return Fintern (make_unibyte_string (str, len), Qnil); | ||
| 177 | buf = alloca (len); | ||
| 178 | if (! buf) | ||
| 179 | return Fintern (null_string, Qnil); | ||
| 180 | bcopy (str, buf, len); | ||
| 181 | for (; i < len; i++) | ||
| 182 | if (isascii (buf[i])) | ||
| 183 | buf[i] = tolower (buf[i]); | ||
| 184 | return Fintern (make_unibyte_string (buf, len), Qnil); | ||
| 185 | } | ||
| 186 | |||
| 187 | extern Lisp_Object Vface_alternative_font_family_alist; | ||
| 188 | |||
| 189 | static void | ||
| 190 | build_font_family_alist () | ||
| 191 | { | ||
| 192 | Lisp_Object alist = Vface_alternative_font_family_alist; | ||
| 193 | |||
| 194 | for (; CONSP (alist); alist = XCDR (alist)) | ||
| 195 | { | ||
| 196 | Lisp_Object tail, elt; | ||
| 197 | |||
| 198 | for (tail = XCAR (alist), elt = Qnil ; CONSP (tail); tail = XCDR (tail)) | ||
| 199 | elt = nconc2 (elt, Fcons (Fintern (XCAR (tail), Qnil), Qnil)); | ||
| 200 | font_family_alist = Fcons (elt, font_family_alist); | ||
| 201 | } | ||
| 202 | } | ||
| 203 | |||
| 204 | |||
| 205 | /* Font property validater. */ | ||
| 206 | |||
| 207 | static Lisp_Object | ||
| 208 | font_prop_validate_type (prop, val) | ||
| 209 | enum font_property_index prop; | ||
| 210 | Lisp_Object val; | ||
| 211 | { | ||
| 212 | return (SYMBOLP (val) ? val : Qerror); | ||
| 213 | } | ||
| 214 | |||
| 215 | static Lisp_Object | ||
| 216 | font_prop_validate_symbol (prop, val) | ||
| 217 | enum font_property_index prop; | ||
| 218 | Lisp_Object val; | ||
| 219 | { | ||
| 220 | if (STRINGP (val)) | ||
| 221 | val = (SCHARS (val) == 0 ? null_string | ||
| 222 | : intern_downcase ((char *) SDATA (val), SBYTES (val))); | ||
| 223 | else if (SYMBOLP (val)) | ||
| 224 | { | ||
| 225 | if (SCHARS (SYMBOL_NAME (val)) == 0) | ||
| 226 | val = null_string; | ||
| 227 | } | ||
| 228 | else | ||
| 229 | val = Qerror; | ||
| 230 | return val; | ||
| 231 | } | ||
| 232 | |||
| 233 | static Lisp_Object | ||
| 234 | font_prop_validate_style (prop, val) | ||
| 235 | enum font_property_index prop; | ||
| 236 | Lisp_Object val; | ||
| 237 | { | ||
| 238 | if (! INTEGERP (val)) | ||
| 239 | { | ||
| 240 | if (STRINGP (val)) | ||
| 241 | val = intern_downcase ((char *) SDATA (val), SBYTES (val)); | ||
| 242 | if (! SYMBOLP (val)) | ||
| 243 | val = Qerror; | ||
| 244 | else | ||
| 245 | { | ||
| 246 | val = prop_name_to_numeric (prop, val); | ||
| 247 | if (NILP (val)) | ||
| 248 | val = Qerror; | ||
| 249 | } | ||
| 250 | } | ||
| 251 | return val; | ||
| 252 | } | ||
| 253 | |||
| 254 | static Lisp_Object | ||
| 255 | font_prop_validate_size (prop, val) | ||
| 256 | enum font_property_index prop; | ||
| 257 | Lisp_Object val; | ||
| 258 | { | ||
| 259 | return (NATNUMP (val) || (FLOATP (val) && XFLOAT_DATA (val) >= 0) | ||
| 260 | ? val : Qerror); | ||
| 261 | } | ||
| 262 | |||
| 263 | static Lisp_Object | ||
| 264 | font_prop_validate_extra (prop, val) | ||
| 265 | enum font_property_index prop; | ||
| 266 | Lisp_Object val; | ||
| 267 | { | ||
| 268 | Lisp_Object tail; | ||
| 269 | |||
| 270 | for (tail = val; CONSP (tail); tail = XCDR (tail)) | ||
| 271 | { | ||
| 272 | Lisp_Object key = Fcar (XCAR (tail)), this_val = Fcdr (XCAR (tail)); | ||
| 273 | |||
| 274 | if (NILP (this_val)) | ||
| 275 | return Qnil; | ||
| 276 | if (EQ (key, QClanguage)) | ||
| 277 | if (! SYMBOLP (this_val)) | ||
| 278 | { | ||
| 279 | for (; CONSP (this_val); this_val = XCDR (this_val)) | ||
| 280 | if (! SYMBOLP (XCAR (this_val))) | ||
| 281 | return Qerror; | ||
| 282 | if (! NILP (this_val)) | ||
| 283 | return Qerror; | ||
| 284 | } | ||
| 285 | if (EQ (key, QCotf)) | ||
| 286 | if (! STRINGP (this_val)) | ||
| 287 | return Qerror; | ||
| 288 | } | ||
| 289 | return (NILP (tail) ? val : Qerror); | ||
| 290 | } | ||
| 291 | |||
| 292 | |||
| 293 | struct | ||
| 294 | { | ||
| 295 | Lisp_Object *key; | ||
| 296 | Lisp_Object (*validater) P_ ((enum font_property_index prop, | ||
| 297 | Lisp_Object val)); | ||
| 298 | } font_property_table[FONT_SPEC_MAX] = | ||
| 299 | { { &QCtype, font_prop_validate_type }, | ||
| 300 | { &QCfoundry, font_prop_validate_symbol }, | ||
| 301 | { &QCfamily, font_prop_validate_symbol }, | ||
| 302 | { &QCadstyle, font_prop_validate_symbol }, | ||
| 303 | { &QCregistry, font_prop_validate_symbol }, | ||
| 304 | { &QCweight, font_prop_validate_style }, | ||
| 305 | { &QCslant, font_prop_validate_style }, | ||
| 306 | { &QCwidth, font_prop_validate_style }, | ||
| 307 | { &QCsize, font_prop_validate_size }, | ||
| 308 | { &QCextra, font_prop_validate_extra } | ||
| 309 | }; | ||
| 310 | |||
| 311 | static enum font_property_index | ||
| 312 | check_font_prop_name (key) | ||
| 313 | Lisp_Object key; | ||
| 314 | { | ||
| 315 | enum font_property_index i; | ||
| 316 | |||
| 317 | for (i = FONT_TYPE_INDEX; i < FONT_SPEC_MAX; i++) | ||
| 318 | if (EQ (key, *font_property_table[i].key)) | ||
| 319 | break; | ||
| 320 | return i; | ||
| 321 | } | ||
| 322 | |||
| 323 | static Lisp_Object | ||
| 324 | font_prop_validate (spec) | ||
| 325 | Lisp_Object spec; | ||
| 326 | { | ||
| 327 | enum font_property_index i; | ||
| 328 | Lisp_Object val; | ||
| 329 | |||
| 330 | for (i = FONT_TYPE_INDEX; i <= FONT_EXTRA_INDEX; i++) | ||
| 331 | { | ||
| 332 | if (! NILP (AREF (spec, i))) | ||
| 333 | { | ||
| 334 | val = (font_property_table[i].validater) (i, AREF (spec, i)); | ||
| 335 | if (EQ (val, Qerror)) | ||
| 336 | Fsignal (Qerror, list3 (build_string ("invalid font property"), | ||
| 337 | *font_property_table[i].key, | ||
| 338 | AREF (spec, i))); | ||
| 339 | ASET (spec, i, val); | ||
| 340 | } | ||
| 341 | } | ||
| 342 | return spec; | ||
| 343 | } | ||
| 344 | |||
| 345 | |||
| 346 | /* Font name parser and unparser */ | ||
| 347 | |||
| 348 | /* An enumerator for each field of an XLFD font name. */ | ||
| 349 | |||
| 350 | enum xlfd_field_index | ||
| 351 | { | ||
| 352 | XLFD_FOUNDRY_INDEX, | ||
| 353 | XLFD_FAMILY_INDEX, | ||
| 354 | XLFD_WEIGHT_INDEX, | ||
| 355 | XLFD_SLANT_INDEX, | ||
| 356 | XLFD_SWIDTH_INDEX, | ||
| 357 | XLFD_ADSTYLE_INDEX, | ||
| 358 | XLFD_PIXEL_SIZE_INDEX, | ||
| 359 | XLFD_POINT_SIZE_INDEX, | ||
| 360 | XLFD_RESX_INDEX, | ||
| 361 | XLFD_RESY_INDEX, | ||
| 362 | XLFD_SPACING_INDEX, | ||
| 363 | XLFD_AVGWIDTH_INDEX, | ||
| 364 | XLFD_REGISTRY_INDEX, | ||
| 365 | XLFD_ENCODING_INDEX, | ||
| 366 | XLFD_LAST_INDEX | ||
| 367 | }; | ||
| 368 | |||
| 369 | /* Return a symbol interned by string at STR and bytes LEN. | ||
| 370 | If LEN == 0, return a null string. | ||
| 371 | If the string is "*", return Qnil. | ||
| 372 | It is assured that LEN < 256. */ | ||
| 373 | |||
| 374 | static Lisp_Object | ||
| 375 | intern_font_field (f, xlfd) | ||
| 376 | char *f[XLFD_LAST_INDEX + 1]; | ||
| 377 | int xlfd; | ||
| 378 | { | ||
| 379 | char *str = f[xlfd] + 1; | ||
| 380 | int len; | ||
| 381 | |||
| 382 | if (xlfd != XLFD_RESY_INDEX) | ||
| 383 | len = f[xlfd + 1] - f[xlfd] - 1; | ||
| 384 | else | ||
| 385 | len = f[XLFD_REGISTRY_INDEX] - f[xlfd] - 1; | ||
| 386 | |||
| 387 | if (len == 0) | ||
| 388 | return null_string; | ||
| 389 | if (*str == '*' && len == 1) | ||
| 390 | return Qnil; | ||
| 391 | return intern_downcase (str, len); | ||
| 392 | } | ||
| 393 | |||
| 394 | /* Parse P pointing the pixel/point size field of the form | ||
| 395 | `[A B C D]' which specifies a transformation matrix: | ||
| 396 | |||
| 397 | A B 0 | ||
| 398 | C D 0 | ||
| 399 | 0 0 1 | ||
| 400 | |||
| 401 | by which all glyphs of the font are transformed. The spec says | ||
| 402 | that scalar value N for the pixel/point size is equivalent to: | ||
| 403 | A = N * resx/resy, B = C = 0, D = N. | ||
| 404 | |||
| 405 | Return the scalar value N if the form is valid. Otherwise return | ||
| 406 | -1. */ | ||
| 407 | |||
| 408 | static int | ||
| 409 | parse_matrix (p) | ||
| 410 | char *p; | ||
| 411 | { | ||
| 412 | double matrix[4]; | ||
| 413 | char *end; | ||
| 414 | int i; | ||
| 415 | |||
| 416 | for (i = 0, p++; i < 4 && *p && *p != ']'; i++) | ||
| 417 | { | ||
| 418 | if (*p == '~') | ||
| 419 | matrix[i] = - strtod (p + 1, &end); | ||
| 420 | else | ||
| 421 | matrix[i] = strtod (p, &end); | ||
| 422 | p = end; | ||
| 423 | } | ||
| 424 | return (i == 4 ? (int) matrix[3] : -1); | ||
| 425 | } | ||
| 426 | |||
| 427 | /* Parse NAME (null terminated) as XLFD format, and store information | ||
| 428 | in FONT (font-spec or font-entity). If NAME is successfully | ||
| 429 | parsed, return 2 (non-scalable font), 1 (scalable vector font), or | ||
| 430 | 0 (auto-scaled font). Otherwise return -1. | ||
| 431 | |||
| 432 | If FONT is a font-entity, store RESY-SPACING-AVWIDTH information as | ||
| 433 | a symbol in FONT_EXTRA_INDEX. | ||
| 434 | |||
| 435 | If MERGE is nonzero, set a property of FONT only when it's nil. */ | ||
| 436 | |||
| 437 | int | ||
| 438 | font_parse_xlfd (name, font, merge) | ||
| 439 | char *name; | ||
| 440 | Lisp_Object font; | ||
| 441 | int merge; | ||
| 442 | { | ||
| 443 | int len = strlen (name); | ||
| 444 | int i, j; | ||
| 445 | int pixel_size, resy, avwidth; | ||
| 446 | double point_size; | ||
| 447 | char *f[XLFD_LAST_INDEX + 1]; | ||
| 448 | Lisp_Object val; | ||
| 449 | int first_wildcard_field = -1, last_wildcard_field = XLFD_LAST_INDEX; | ||
| 450 | |||
| 451 | if (len > 255) | ||
| 452 | /* Maximum XLFD name length is 255. */ | ||
| 453 | return -1; | ||
| 454 | for (i = 0; *name; name++) | ||
| 455 | if (*name == '-' | ||
| 456 | && i < XLFD_LAST_INDEX) | ||
| 457 | { | ||
| 458 | f[i] = name; | ||
| 459 | if (name[1] == '*' && (! name[2] || name[2] == '-')) | ||
| 460 | { | ||
| 461 | if (first_wildcard_field < 0) | ||
| 462 | first_wildcard_field = i; | ||
| 463 | last_wildcard_field = i; | ||
| 464 | } | ||
| 465 | i++; | ||
| 466 | } | ||
| 467 | |||
| 468 | f[XLFD_LAST_INDEX] = name; | ||
| 469 | if (i < XLFD_LAST_INDEX) | ||
| 470 | { | ||
| 471 | /* Not a fully specified XLFD. */ | ||
| 472 | if (first_wildcard_field < 0 ) | ||
| 473 | /* No wild card. */ | ||
| 474 | return -1; | ||
| 475 | i--; | ||
| 476 | if (last_wildcard_field < i) | ||
| 477 | { | ||
| 478 | /* Shift fields after the last wildcard field. */ | ||
| 479 | for (j = XLFD_LAST_INDEX - 1; j > last_wildcard_field; j--, i--) | ||
| 480 | f[j] = f[i]; | ||
| 481 | /* Make all fields between the first and last wildcard fieled | ||
| 482 | also wildcard fields. */ | ||
| 483 | for (j--; j > first_wildcard_field; j--) | ||
| 484 | f[j] = "-*"; | ||
| 485 | } | ||
| 486 | } | ||
| 487 | f[XLFD_ENCODING_INDEX] = f[XLFD_LAST_INDEX]; | ||
| 488 | |||
| 489 | if (! merge || NILP (AREF (font, FONT_FOUNDRY_INDEX))) | ||
| 490 | ASET (font, FONT_FOUNDRY_INDEX, intern_font_field (f, XLFD_FOUNDRY_INDEX)); | ||
| 491 | if (! merge || NILP (AREF (font, FONT_FAMILY_INDEX))) | ||
| 492 | ASET (font, FONT_FAMILY_INDEX, intern_font_field (f, XLFD_FAMILY_INDEX)); | ||
| 493 | if (! merge || NILP (AREF (font, FONT_ADSTYLE_INDEX))) | ||
| 494 | ASET (font, FONT_ADSTYLE_INDEX, intern_font_field (f, XLFD_ADSTYLE_INDEX)); | ||
| 495 | if (! merge || NILP (AREF (font, FONT_REGISTRY_INDEX))) | ||
| 496 | ASET (font, FONT_REGISTRY_INDEX, intern_font_field (f, XLFD_REGISTRY_INDEX)); | ||
| 497 | |||
| 498 | for (i = FONT_WEIGHT_INDEX, j = XLFD_WEIGHT_INDEX; | ||
| 499 | j <= XLFD_SWIDTH_INDEX; i++, j++) | ||
| 500 | if (! merge || NILP (AREF (font, i))) | ||
| 501 | { | ||
| 502 | if (isdigit(f[j][1])) | ||
| 503 | val = make_number (atoi (f[j] + 1)); | ||
| 504 | else | ||
| 505 | { | ||
| 506 | Lisp_Object sym = intern_font_field (f, j); | ||
| 507 | |||
| 508 | val = prop_name_to_numeric (i, sym); | ||
| 509 | if (NILP (val)) | ||
| 510 | val = sym; | ||
| 511 | } | ||
| 512 | ASET (font, i, val); | ||
| 513 | } | ||
| 514 | |||
| 515 | if (f[XLFD_PIXEL_SIZE_INDEX][1] == '*') | ||
| 516 | pixel_size = -1; /* indicates "unspecified" */ | ||
| 517 | else if (f[XLFD_PIXEL_SIZE_INDEX][1] == '[') | ||
| 518 | pixel_size = parse_matrix (f[XLFD_PIXEL_SIZE_INDEX] + 1); | ||
| 519 | else if (isdigit (f[XLFD_PIXEL_SIZE_INDEX][1])) | ||
| 520 | pixel_size = strtod (f[XLFD_PIXEL_SIZE_INDEX] + 1, NULL); | ||
| 521 | else | ||
| 522 | pixel_size = -1; | ||
| 523 | |||
| 524 | if (pixel_size < 0 && FONT_ENTITY_P (font)) | ||
| 525 | return -1; | ||
| 526 | |||
| 527 | if (f[XLFD_POINT_SIZE_INDEX][1] == '*') | ||
| 528 | point_size = -1; /* indicates "unspecified" */ | ||
| 529 | else if (f[XLFD_POINT_SIZE_INDEX][1] == '[') | ||
| 530 | point_size = parse_matrix (f[XLFD_POINT_SIZE_INDEX] + 1); | ||
| 531 | else if (isdigit (f[XLFD_POINT_SIZE_INDEX][1])) | ||
| 532 | point_size = strtod (f[XLFD_POINT_SIZE_INDEX] + 1, NULL); | ||
| 533 | else | ||
| 534 | point_size = -1; | ||
| 535 | |||
| 536 | if (f[XLFD_RESY_INDEX][1] == '*') | ||
| 537 | resy = -1; /* indicates "unspecified" */ | ||
| 538 | else | ||
| 539 | resy = strtod (f[XLFD_RESY_INDEX] + 1, NULL); | ||
| 540 | |||
| 541 | if (f[XLFD_AVGWIDTH_INDEX][1] == '*') | ||
| 542 | avwidth = -1; /* indicates "unspecified" */ | ||
| 543 | else if (f[XLFD_AVGWIDTH_INDEX][1] == '~') | ||
| 544 | avwidth = - strtod (f[XLFD_AVGWIDTH_INDEX] + 2, NULL); | ||
| 545 | else | ||
| 546 | avwidth = strtod (f[XLFD_AVGWIDTH_INDEX] + 1, NULL); | ||
| 547 | |||
| 548 | if (! merge || NILP (AREF (font, FONT_SIZE_INDEX))) | ||
| 549 | { | ||
| 550 | if (pixel_size >= 0) | ||
| 551 | ASET (font, FONT_SIZE_INDEX, make_number (pixel_size)); | ||
| 552 | else | ||
| 553 | { | ||
| 554 | if (point_size >= 0) | ||
| 555 | { | ||
| 556 | if (resy > 0) | ||
| 557 | { | ||
| 558 | pixel_size = POINT_TO_PIXEL (point_size, resy); | ||
| 559 | ASET (font, FONT_SIZE_INDEX, make_number (pixel_size)); | ||
| 560 | } | ||
| 561 | else | ||
| 562 | { | ||
| 563 | ASET (font, FONT_SIZE_INDEX, make_float (point_size / 10)); | ||
| 564 | } | ||
| 565 | } | ||
| 566 | else | ||
| 567 | ASET (font, FONT_SIZE_INDEX, Qnil); | ||
| 568 | } | ||
| 569 | } | ||
| 570 | |||
| 571 | if (FONT_ENTITY_P (font) | ||
| 572 | && EQ (AREF (font, FONT_TYPE_INDEX), Qx)) | ||
| 573 | ASET (font, FONT_EXTRA_INDEX, intern_font_field (f, XLFD_RESY_INDEX)); | ||
| 574 | |||
| 575 | return (avwidth > 0 ? 2 : resy == 0); | ||
| 576 | } | ||
| 577 | |||
| 578 | /* Store XLFD name of FONT (font-spec or font-entity) in NAME (NBYTES | ||
| 579 | length), and return the name length. If FONT_SIZE_INDEX of FONT is | ||
| 580 | 0, use PIXEL_SIZE instead. */ | ||
| 581 | |||
| 582 | int | ||
| 583 | font_unparse_xlfd (font, pixel_size, name, nbytes) | ||
| 584 | Lisp_Object font; | ||
| 585 | char *name; | ||
| 586 | int nbytes; | ||
| 587 | { | ||
| 588 | char *f[XLFD_REGISTRY_INDEX + 1], *pixel_point; | ||
| 589 | char work[256]; | ||
| 590 | Lisp_Object val; | ||
| 591 | int i, j, len = 0; | ||
| 592 | |||
| 593 | xassert (FONTP (font)); | ||
| 594 | |||
| 595 | for (i = FONT_FOUNDRY_INDEX, j = XLFD_FOUNDRY_INDEX; i <= FONT_REGISTRY_INDEX; | ||
| 596 | i++, j++) | ||
| 597 | { | ||
| 598 | if (i == FONT_ADSTYLE_INDEX) | ||
| 599 | j = XLFD_ADSTYLE_INDEX; | ||
| 600 | else if (i == FONT_REGISTRY_INDEX) | ||
| 601 | j = XLFD_REGISTRY_INDEX; | ||
| 602 | val = AREF (font, i); | ||
| 603 | if (NILP (val)) | ||
| 604 | f[j] = "*", len += 2; | ||
| 605 | else | ||
| 606 | { | ||
| 607 | if (SYMBOLP (val)) | ||
| 608 | val = SYMBOL_NAME (val); | ||
| 609 | f[j] = (char *) SDATA (val), len += SBYTES (val) + 1; | ||
| 610 | } | ||
| 611 | } | ||
| 612 | |||
| 613 | for (i = FONT_WEIGHT_INDEX, j = XLFD_WEIGHT_INDEX; i <= FONT_WIDTH_INDEX; | ||
| 614 | i++, j++) | ||
| 615 | { | ||
| 616 | val = AREF (font, i); | ||
| 617 | if (NILP (val)) | ||
| 618 | f[j] = "*", len += 2; | ||
| 619 | else | ||
| 620 | { | ||
| 621 | if (INTEGERP (val)) | ||
| 622 | val = prop_numeric_to_name (i, XINT (val)); | ||
| 623 | if (SYMBOLP (val)) | ||
| 624 | val = SYMBOL_NAME (val); | ||
| 625 | xassert (STRINGP (val)); | ||
| 626 | f[j] = (char *) SDATA (val), len += SBYTES (val) + 1; | ||
| 627 | } | ||
| 628 | } | ||
| 629 | |||
| 630 | val = AREF (font, FONT_SIZE_INDEX); | ||
| 631 | xassert (NUMBERP (val) || NILP (val)); | ||
| 632 | if (INTEGERP (val)) | ||
| 633 | { | ||
| 634 | i = XINT (val); | ||
| 635 | if (i > 0) | ||
| 636 | len += sprintf (work, "%d", i) + 1; | ||
| 637 | else /* i == 0 */ | ||
| 638 | len += sprintf (work, "%d-*", pixel_size) + 1; | ||
| 639 | pixel_point = work; | ||
| 640 | } | ||
| 641 | else if (FLOATP (val)) | ||
| 642 | { | ||
| 643 | i = XFLOAT_DATA (val) * 10; | ||
| 644 | len += sprintf (work, "*-%d", i) + 1; | ||
| 645 | pixel_point = work; | ||
| 646 | } | ||
| 647 | else | ||
| 648 | pixel_point = "*-*", len += 4; | ||
| 649 | |||
| 650 | if (FONT_ENTITY_P (font) | ||
| 651 | && EQ (AREF (font, FONT_TYPE_INDEX), Qx)) | ||
| 652 | { | ||
| 653 | /* Setup names for RESY-SPACING-AVWIDTH. */ | ||
| 654 | val = AREF (font, FONT_EXTRA_INDEX); | ||
| 655 | if (SYMBOLP (val) && ! NILP (val)) | ||
| 656 | { | ||
| 657 | val = SYMBOL_NAME (val); | ||
| 658 | f[XLFD_RESY_INDEX] = (char *) SDATA (val), len += SBYTES (val) + 1; | ||
| 659 | } | ||
| 660 | else | ||
| 661 | f[XLFD_RESY_INDEX] = "*-*-*", len += 6; | ||
| 662 | } | ||
| 663 | else | ||
| 664 | f[XLFD_RESY_INDEX] = "*-*-*", len += 6; | ||
| 665 | |||
| 666 | len += 3; /* for "-*" of resx, and terminating '\0'. */ | ||
| 667 | if (len >= nbytes) | ||
| 668 | return -1; | ||
| 669 | return sprintf (name, "-%s-%s-%s-%s-%s-%s-%s-*-%s-%s", | ||
| 670 | f[XLFD_FOUNDRY_INDEX], f[XLFD_FAMILY_INDEX], | ||
| 671 | f[XLFD_WEIGHT_INDEX], f[XLFD_SLANT_INDEX], | ||
| 672 | f[XLFD_SWIDTH_INDEX], | ||
| 673 | f[XLFD_ADSTYLE_INDEX], pixel_point, | ||
| 674 | f[XLFD_RESY_INDEX], f[XLFD_REGISTRY_INDEX]); | ||
| 675 | } | ||
| 676 | |||
| 677 | void | ||
| 678 | font_merge_old_spec (name, family, registry, spec) | ||
| 679 | Lisp_Object name, family, registry, spec; | ||
| 680 | { | ||
| 681 | if (STRINGP (name)) | ||
| 682 | { | ||
| 683 | if (font_parse_xlfd ((char *) SDATA (name), spec, 1) < 0) | ||
| 684 | { | ||
| 685 | Lisp_Object extra = Fcons (Fcons (QCname, name), Qnil); | ||
| 686 | |||
| 687 | ASET (spec, FONT_EXTRA_INDEX, extra); | ||
| 688 | } | ||
| 689 | } | ||
| 690 | else | ||
| 691 | { | ||
| 692 | if (! NILP (family)) | ||
| 693 | { | ||
| 694 | int len; | ||
| 695 | char *p0, *p1; | ||
| 696 | |||
| 697 | xassert (STRINGP (family)); | ||
| 698 | len = SBYTES (family); | ||
| 699 | p0 = (char *) SDATA (family); | ||
| 700 | p1 = index (p0, '-'); | ||
| 701 | if (p1) | ||
| 702 | { | ||
| 703 | if (NILP (AREF (spec, FONT_FOUNDRY_INDEX))) | ||
| 704 | ASET (spec, FONT_FOUNDRY_INDEX, | ||
| 705 | intern_downcase (p0, p1 - p0)); | ||
| 706 | if (NILP (AREF (spec, FONT_FAMILY_INDEX))) | ||
| 707 | ASET (spec, FONT_FAMILY_INDEX, | ||
| 708 | intern_downcase (p1 + 1, len - (p1 + 1 - p0))); | ||
| 709 | } | ||
| 710 | else if (NILP (AREF (spec, FONT_FAMILY_INDEX))) | ||
| 711 | ASET (spec, FONT_FAMILY_INDEX, intern_downcase (p0, len)); | ||
| 712 | } | ||
| 713 | if (! NILP (registry) | ||
| 714 | && NILP (AREF (spec, FONT_REGISTRY_INDEX))) | ||
| 715 | ASET (spec, FONT_REGISTRY_INDEX, | ||
| 716 | intern_downcase ((char *) SDATA (registry), SBYTES (registry))); | ||
| 717 | } | ||
| 718 | } | ||
| 719 | |||
| 720 | |||
| 721 | /* OTF handler */ | ||
| 722 | |||
| 723 | #ifdef HAVE_LIBOTF | ||
| 724 | #include <otf.h> | ||
| 725 | |||
| 726 | struct otf_list | ||
| 727 | { | ||
| 728 | Lisp_Object entity; | ||
| 729 | OTF *otf; | ||
| 730 | struct otf_list *next; | ||
| 731 | }; | ||
| 732 | |||
| 733 | static struct otf_list *otf_list; | ||
| 734 | |||
| 735 | static Lisp_Object | ||
| 736 | otf_tag_symbol (tag) | ||
| 737 | OTF_Tag tag; | ||
| 738 | { | ||
| 739 | char name[5]; | ||
| 740 | |||
| 741 | OTF_tag_name (tag, name); | ||
| 742 | return Fintern (make_unibyte_string (name, 4), Qnil); | ||
| 743 | } | ||
| 744 | |||
| 745 | static OTF * | ||
| 746 | otf_open (entity, file) | ||
| 747 | Lisp_Object entity; | ||
| 748 | char *file; | ||
| 749 | { | ||
| 750 | struct otf_list *list = otf_list; | ||
| 751 | |||
| 752 | while (list && ! EQ (list->entity, entity)) | ||
| 753 | list = list->next; | ||
| 754 | if (! list) | ||
| 755 | { | ||
| 756 | list = malloc (sizeof (struct otf_list)); | ||
| 757 | list->entity = entity; | ||
| 758 | list->otf = file ? OTF_open (file) : NULL; | ||
| 759 | list->next = otf_list; | ||
| 760 | otf_list = list; | ||
| 761 | } | ||
| 762 | return list->otf; | ||
| 763 | } | ||
| 764 | |||
| 765 | |||
| 766 | /* Return a list describing which scripts/languages FONT supports by | ||
| 767 | which GSUB/GPOS features of OpenType tables. See the comment of | ||
| 768 | (sturct font_driver).otf_capability. */ | ||
| 769 | |||
| 770 | Lisp_Object | ||
| 771 | font_otf_capability (font) | ||
| 772 | struct font *font; | ||
| 773 | { | ||
| 774 | OTF *otf; | ||
| 775 | Lisp_Object capability = Fcons (Qnil, Qnil); | ||
| 776 | int i; | ||
| 777 | |||
| 778 | otf = otf_open (font->entity, font->file_name); | ||
| 779 | if (! otf) | ||
| 780 | return Qnil; | ||
| 781 | for (i = 0; i < 2; i++) | ||
| 782 | { | ||
| 783 | OTF_GSUB_GPOS *gsub_gpos; | ||
| 784 | Lisp_Object script_list = Qnil; | ||
| 785 | int j; | ||
| 786 | |||
| 787 | if (OTF_get_features (otf, i == 0) < 0) | ||
| 788 | continue; | ||
| 789 | gsub_gpos = i == 0 ? otf->gsub : otf->gpos; | ||
| 790 | for (j = gsub_gpos->ScriptList.ScriptCount - 1; j >= 0; j--) | ||
| 791 | { | ||
| 792 | OTF_Script *script = gsub_gpos->ScriptList.Script + j; | ||
| 793 | Lisp_Object langsys_list = Qnil; | ||
| 794 | Lisp_Object script_tag = otf_tag_symbol (script->ScriptTag); | ||
| 795 | int k; | ||
| 796 | |||
| 797 | for (k = script->LangSysCount; k >= 0; k--) | ||
| 798 | { | ||
| 799 | OTF_LangSys *langsys; | ||
| 800 | Lisp_Object feature_list = Qnil; | ||
| 801 | Lisp_Object langsys_tag; | ||
| 802 | int l; | ||
| 803 | |||
| 804 | if (j == script->LangSysCount) | ||
| 805 | { | ||
| 806 | langsys = &script->DefaultLangSys; | ||
| 807 | langsys_tag = Qnil; | ||
| 808 | } | ||
| 809 | else | ||
| 810 | { | ||
| 811 | langsys = script->LangSys + k; | ||
| 812 | langsys_tag | ||
| 813 | = otf_tag_symbol (script->LangSysRecord[k].LangSysTag); | ||
| 814 | } | ||
| 815 | for (l = langsys->FeatureCount -1; l >= 0; l--) | ||
| 816 | { | ||
| 817 | OTF_Feature *feature | ||
| 818 | = gsub_gpos->FeatureList.Feature + langsys->FeatureIndex[l]; | ||
| 819 | Lisp_Object feature_tag | ||
| 820 | = otf_tag_symbol (feature->FeatureTag); | ||
| 821 | |||
| 822 | feature_list = Fcons (feature_tag, feature_list); | ||
| 823 | } | ||
| 824 | langsys_list = Fcons (Fcons (langsys_tag, feature_list), | ||
| 825 | langsys_list); | ||
| 826 | } | ||
| 827 | script_list = Fcons (Fcons (script_tag, langsys_list), | ||
| 828 | script_list); | ||
| 829 | } | ||
| 830 | |||
| 831 | if (i == 0) | ||
| 832 | XSETCAR (capability, script_list); | ||
| 833 | else | ||
| 834 | XSETCDR (capability, script_list); | ||
| 835 | } | ||
| 836 | |||
| 837 | return capability; | ||
| 838 | } | ||
| 839 | |||
| 840 | static int | ||
| 841 | parse_gsub_gpos_spec (spec, script, langsys, features) | ||
| 842 | Lisp_Object spec; | ||
| 843 | char **script, **langsys, **features; | ||
| 844 | { | ||
| 845 | Lisp_Object val; | ||
| 846 | int len; | ||
| 847 | char *p; | ||
| 848 | int asterisk; | ||
| 849 | |||
| 850 | val = XCAR (spec); | ||
| 851 | *script = (char *) SDATA (SYMBOL_NAME (val)); | ||
| 852 | spec = XCDR (spec); | ||
| 853 | val = XCAR (spec); | ||
| 854 | *langsys = NILP (val) ? NULL : (char *) SDATA (SYMBOL_NAME (val)); | ||
| 855 | spec = XCDR (spec); | ||
| 856 | len = XINT (Flength (spec)); | ||
| 857 | *features = p = malloc (6 * len); | ||
| 858 | if (! p) | ||
| 859 | return -1; | ||
| 860 | |||
| 861 | for (asterisk = 0; CONSP (spec); spec = XCDR (spec)) | ||
| 862 | { | ||
| 863 | val = XCAR (spec); | ||
| 864 | if (SREF (SYMBOL_NAME (val), 0) == '*') | ||
| 865 | { | ||
| 866 | asterisk = 1; | ||
| 867 | p += sprintf (p, ",*"); | ||
| 868 | } | ||
| 869 | else if (! asterisk) | ||
| 870 | p += sprintf (p, ",%s", SDATA (SYMBOL_NAME (val))); | ||
| 871 | else | ||
| 872 | p += sprintf (p, ",~%s", SDATA (SYMBOL_NAME (val))); | ||
| 873 | } | ||
| 874 | return 0; | ||
| 875 | } | ||
| 876 | |||
| 877 | #define DEVICE_DELTA(table, size) \ | ||
| 878 | (((size) >= (table).StartSize && (size) <= (table).EndSize) \ | ||
| 879 | ? (table).DeltaValue[(size) >= (table).StartSize] \ | ||
| 880 | : 0) | ||
| 881 | |||
| 882 | void | ||
| 883 | adjust_anchor (struct font *font, OTF_Anchor *anchor, | ||
| 884 | unsigned code, int size, int *x, int *y) | ||
| 885 | { | ||
| 886 | if (anchor->AnchorFormat == 2) | ||
| 887 | { | ||
| 888 | int x0, y0; | ||
| 889 | |||
| 890 | if (font->driver->anchor_point (font, code, anchor->f.f1.AnchorPoint, | ||
| 891 | &x0, &y0) >= 0) | ||
| 892 | *x = x0, *y = y0; | ||
| 893 | } | ||
| 894 | else if (anchor->AnchorFormat == 3) | ||
| 895 | { | ||
| 896 | if (anchor->f.f2.XDeviceTable.offset) | ||
| 897 | *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, size); | ||
| 898 | if (anchor->f.f2.YDeviceTable.offset) | ||
| 899 | *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, size); | ||
| 900 | } | ||
| 901 | } | ||
| 902 | |||
| 903 | |||
| 904 | /* Drive FONT's OTF GSUB features according to GSUB_SPEC. See the | ||
| 905 | comment of (sturct font_driver).otf_gsub. */ | ||
| 906 | |||
| 907 | int | ||
| 908 | font_otf_gsub (font, gsub_spec, gstring_in, from, to, gstring_out, idx) | ||
| 909 | struct font *font; | ||
| 910 | Lisp_Object gsub_spec; | ||
| 911 | Lisp_Object gstring_in; | ||
| 912 | int from, to; | ||
| 913 | Lisp_Object gstring_out; | ||
| 914 | int idx; | ||
| 915 | { | ||
| 916 | int len; | ||
| 917 | int i; | ||
| 918 | OTF *otf; | ||
| 919 | OTF_GlyphString otf_gstring; | ||
| 920 | OTF_Glyph *g; | ||
| 921 | char *script, *langsys, *features; | ||
| 922 | |||
| 923 | otf = otf_open (font->entity, font->file_name); | ||
| 924 | if (! otf) | ||
| 925 | return 0; | ||
| 926 | if (OTF_get_table (otf, "head") < 0) | ||
| 927 | return 0; | ||
| 928 | if (OTF_check_table (otf, "GSUB") < 0) | ||
| 929 | return 0; | ||
| 930 | if (parse_gsub_gpos_spec (gsub_spec, &script, &langsys, &features) < 0) | ||
| 931 | return 0; | ||
| 932 | len = to - from; | ||
| 933 | otf_gstring.size = otf_gstring.used = len; | ||
| 934 | otf_gstring.glyphs = (OTF_Glyph *) malloc (sizeof (OTF_Glyph) * len); | ||
| 935 | memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len); | ||
| 936 | for (i = 0; i < len; i++) | ||
| 937 | { | ||
| 938 | Lisp_Object g = LGSTRING_GLYPH (gstring_in, from + i); | ||
| 939 | |||
| 940 | otf_gstring.glyphs[i].c = XINT (LGLYPH_CHAR (g)); | ||
| 941 | otf_gstring.glyphs[i].glyph_id = XINT (LGLYPH_CODE (g)); | ||
| 942 | } | ||
| 943 | |||
| 944 | OTF_drive_gdef (otf, &otf_gstring); | ||
| 945 | if (OTF_drive_gsub (otf, &otf_gstring, script, langsys, features) < 0) | ||
| 946 | { | ||
| 947 | free (otf_gstring.glyphs); | ||
| 948 | return 0; | ||
| 949 | } | ||
| 950 | if (ASIZE (gstring_out) < idx + otf_gstring.used) | ||
| 951 | { | ||
| 952 | free (otf_gstring.glyphs); | ||
| 953 | return -1; | ||
| 954 | } | ||
| 955 | |||
| 956 | for (i = 0, g = otf_gstring.glyphs; i < otf_gstring.used;) | ||
| 957 | { | ||
| 958 | int i0 = g->f.index.from, i1 = g->f.index.to; | ||
| 959 | Lisp_Object glyph = LGSTRING_GLYPH (gstring_in, from + i0); | ||
| 960 | Lisp_Object min_idx = AREF (glyph, 0); | ||
| 961 | Lisp_Object max_idx = AREF (glyph, 1); | ||
| 962 | |||
| 963 | if (i0 < i1) | ||
| 964 | { | ||
| 965 | int min_idx_i = XINT (min_idx), max_idx_i = XINT (max_idx); | ||
| 966 | |||
| 967 | for (i0++; i0 <= i1; i0++) | ||
| 968 | { | ||
| 969 | glyph = LGSTRING_GLYPH (gstring_in, from + i0); | ||
| 970 | if (min_idx_i > XINT (AREF (glyph, 0))) | ||
| 971 | min_idx_i = XINT (AREF (glyph, 0)); | ||
| 972 | if (max_idx_i < XINT (AREF (glyph, 1))) | ||
| 973 | max_idx_i = XINT (AREF (glyph, 1)); | ||
| 974 | } | ||
| 975 | min_idx = make_number (min_idx_i); | ||
| 976 | max_idx = make_number (max_idx_i); | ||
| 977 | i0 = g->f.index.from; | ||
| 978 | } | ||
| 979 | for (; i < otf_gstring.used && g->f.index.from == i0; i++, g++) | ||
| 980 | { | ||
| 981 | glyph = LGSTRING_GLYPH (gstring_out, idx + i); | ||
| 982 | ASET (glyph, 0, min_idx); | ||
| 983 | ASET (glyph, 1, max_idx); | ||
| 984 | LGLYPH_SET_CHAR (glyph, make_number (g->c)); | ||
| 985 | LGLYPH_SET_CODE (glyph, make_number (g->glyph_id)); | ||
| 986 | } | ||
| 987 | } | ||
| 988 | |||
| 989 | free (otf_gstring.glyphs); | ||
| 990 | return i; | ||
| 991 | } | ||
| 992 | |||
| 993 | /* Drive FONT's OTF GPOS features according to GPOS_SPEC. See the | ||
| 994 | comment of (sturct font_driver).otf_gpos. */ | ||
| 995 | |||
| 996 | int | ||
| 997 | font_otf_gpos (font, gpos_spec, gstring, from, to) | ||
| 998 | struct font *font; | ||
| 999 | Lisp_Object gpos_spec; | ||
| 1000 | Lisp_Object gstring; | ||
| 1001 | int from, to; | ||
| 1002 | { | ||
| 1003 | int len; | ||
| 1004 | int i; | ||
| 1005 | OTF *otf; | ||
| 1006 | OTF_GlyphString otf_gstring; | ||
| 1007 | OTF_Glyph *g; | ||
| 1008 | char *script, *langsys, *features; | ||
| 1009 | Lisp_Object glyph; | ||
| 1010 | int u, size; | ||
| 1011 | Lisp_Object base, mark; | ||
| 1012 | |||
| 1013 | otf = otf_open (font->entity, font->file_name); | ||
| 1014 | if (! otf) | ||
| 1015 | return 0; | ||
| 1016 | if (OTF_get_table (otf, "head") < 0) | ||
| 1017 | return 0; | ||
| 1018 | if (OTF_check_table (otf, "GPOS") < 0) | ||
| 1019 | return 0; | ||
| 1020 | if (parse_gsub_gpos_spec (gpos_spec, &script, &langsys, &features) < 0) | ||
| 1021 | return 0; | ||
| 1022 | len = to - from; | ||
| 1023 | otf_gstring.size = otf_gstring.used = len; | ||
| 1024 | otf_gstring.glyphs = (OTF_Glyph *) malloc (sizeof (OTF_Glyph) * len); | ||
| 1025 | memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len); | ||
| 1026 | for (i = 0; i < len; i++) | ||
| 1027 | { | ||
| 1028 | glyph = LGSTRING_GLYPH (gstring, from + i); | ||
| 1029 | otf_gstring.glyphs[i].glyph_id = XINT (LGLYPH_CODE (glyph)); | ||
| 1030 | } | ||
| 1031 | |||
| 1032 | OTF_drive_gdef (otf, &otf_gstring); | ||
| 1033 | |||
| 1034 | if (OTF_drive_gpos (otf, &otf_gstring, script, langsys, features) < 0) | ||
| 1035 | { | ||
| 1036 | free (otf_gstring.glyphs); | ||
| 1037 | return 0; | ||
| 1038 | } | ||
| 1039 | |||
| 1040 | u = otf->head->unitsPerEm; | ||
| 1041 | size = font->pixel_size; | ||
| 1042 | base = mark = Qnil; | ||
| 1043 | for (i = 0, g = otf_gstring.glyphs; i < otf_gstring.used; i++, g++) | ||
| 1044 | { | ||
| 1045 | Lisp_Object prev; | ||
| 1046 | int xoff = 0, yoff = 0, width_adjust = 0; | ||
| 1047 | |||
| 1048 | if (! g->glyph_id) | ||
| 1049 | continue; | ||
| 1050 | |||
| 1051 | glyph = LGSTRING_GLYPH (gstring, from + i); | ||
| 1052 | switch (g->positioning_type) | ||
| 1053 | { | ||
| 1054 | case 0: | ||
| 1055 | break; | ||
| 1056 | case 1: case 2: | ||
| 1057 | { | ||
| 1058 | int format = g->f.f1.format; | ||
| 1059 | |||
| 1060 | if (format & OTF_XPlacement) | ||
| 1061 | xoff = g->f.f1.value->XPlacement * size / u; | ||
| 1062 | if (format & OTF_XPlaDevice) | ||
| 1063 | xoff += DEVICE_DELTA (g->f.f1.value->XPlaDevice, size); | ||
| 1064 | if (format & OTF_YPlacement) | ||
| 1065 | yoff = - (g->f.f1.value->YPlacement * size / u); | ||
| 1066 | if (format & OTF_YPlaDevice) | ||
| 1067 | yoff -= DEVICE_DELTA (g->f.f1.value->YPlaDevice, size); | ||
| 1068 | if (format & OTF_XAdvance) | ||
| 1069 | width_adjust += g->f.f1.value->XAdvance * size / u; | ||
| 1070 | if (format & OTF_XAdvDevice) | ||
| 1071 | width_adjust += DEVICE_DELTA (g->f.f1.value->XAdvDevice, size); | ||
| 1072 | } | ||
| 1073 | break; | ||
| 1074 | case 3: | ||
| 1075 | /* Not yet supported. */ | ||
| 1076 | break; | ||
| 1077 | case 4: case 5: | ||
| 1078 | if (NILP (base)) | ||
| 1079 | break; | ||
| 1080 | prev = base; | ||
| 1081 | goto label_adjust_anchor; | ||
| 1082 | default: /* i.e. case 6 */ | ||
| 1083 | if (NILP (mark)) | ||
| 1084 | break; | ||
| 1085 | prev = mark; | ||
| 1086 | |||
| 1087 | label_adjust_anchor: | ||
| 1088 | { | ||
| 1089 | int base_x, base_y, mark_x, mark_y, width; | ||
| 1090 | unsigned code; | ||
| 1091 | |||
| 1092 | base_x = g->f.f4.base_anchor->XCoordinate * size / u; | ||
| 1093 | base_y = g->f.f4.base_anchor->YCoordinate * size / u; | ||
| 1094 | mark_x = g->f.f4.mark_anchor->XCoordinate * size / u; | ||
| 1095 | mark_y = g->f.f4.mark_anchor->YCoordinate * size / u; | ||
| 1096 | |||
| 1097 | code = XINT (LGLYPH_CODE (prev)); | ||
| 1098 | if (g->f.f4.base_anchor->AnchorFormat != 1) | ||
| 1099 | adjust_anchor (font, g->f.f4.base_anchor, | ||
| 1100 | code, size, &base_x, &base_y); | ||
| 1101 | if (g->f.f4.mark_anchor->AnchorFormat != 1) | ||
| 1102 | adjust_anchor (font, g->f.f4.mark_anchor, | ||
| 1103 | code, size, &mark_x, &mark_y); | ||
| 1104 | |||
| 1105 | if (NILP (LGLYPH_WIDTH (prev))) | ||
| 1106 | { | ||
| 1107 | width = font->driver->text_extents (font, &code, 1, NULL); | ||
| 1108 | LGLYPH_SET_WIDTH (prev, make_number (width)); | ||
| 1109 | } | ||
| 1110 | xoff = XINT (LGLYPH_XOFF (prev)) + (base_x - width) - mark_x; | ||
| 1111 | yoff = XINT (LGLYPH_YOFF (prev)) + mark_y - base_y; | ||
| 1112 | } | ||
| 1113 | } | ||
| 1114 | if (g->GlyphClass == OTF_GlyphClass0) | ||
| 1115 | base = mark = glyph; | ||
| 1116 | else if (g->GlyphClass == OTF_GlyphClassMark) | ||
| 1117 | mark = glyph; | ||
| 1118 | else | ||
| 1119 | base = glyph; | ||
| 1120 | |||
| 1121 | LGLYPH_SET_XOFF (glyph, make_number (xoff)); | ||
| 1122 | LGLYPH_SET_YOFF (glyph, make_number (yoff)); | ||
| 1123 | LGLYPH_SET_WADJUST (glyph, make_number (width_adjust)); | ||
| 1124 | } | ||
| 1125 | |||
| 1126 | free (otf_gstring.glyphs); | ||
| 1127 | return 0; | ||
| 1128 | } | ||
| 1129 | |||
| 1130 | #endif /* HAVE_LIBOTF */ | ||
| 1131 | |||
| 1132 | |||
| 1133 | /* glyph-string handler */ | ||
| 1134 | |||
| 1135 | /* GSTRING is a vector of this form: | ||
| 1136 | [ [FONT-OBJECT LBEARING RBEARING WITH ASCENT DESCENT] GLYPH ... ] | ||
| 1137 | and GLYPH is a vector of this form: | ||
| 1138 | [ FROM-IDX TO-IDX C CODE X-OFF Y-OFF WIDTH WADJUST ] | ||
| 1139 | where | ||
| 1140 | FROM-IDX and TO-IDX are used internally and should not be touched. | ||
| 1141 | C is a character of the glyph. | ||
| 1142 | CODE is a glyph-code of C in FONT-OBJECT. | ||
| 1143 | X-OFF and Y-OFF are offests to the base position for the glyph. | ||
| 1144 | WIDTH is a normal width of the glyph. | ||
| 1145 | WADJUST is an adjustment to the normal width of the glyph. */ | ||
| 1146 | |||
| 1147 | struct font * | ||
| 1148 | font_prepare_composition (cmp) | ||
| 1149 | struct composition *cmp; | ||
| 1150 | { | ||
| 1151 | Lisp_Object gstring | ||
| 1152 | = AREF (XHASH_TABLE (composition_hash_table)->key_and_value, | ||
| 1153 | cmp->hash_index * 2); | ||
| 1154 | struct font *font = XSAVE_VALUE (LGSTRING_FONT (gstring))->pointer; | ||
| 1155 | int len = LGSTRING_LENGTH (gstring); | ||
| 1156 | int i; | ||
| 1157 | |||
| 1158 | cmp->font = font; | ||
| 1159 | cmp->lbearing = cmp->rbearing = cmp->pixel_width = 0; | ||
| 1160 | cmp->ascent = font->ascent; | ||
| 1161 | cmp->descent = font->descent; | ||
| 1162 | |||
| 1163 | for (i = 0; i < len; i++) | ||
| 1164 | { | ||
| 1165 | Lisp_Object g = LGSTRING_GLYPH (gstring, i); | ||
| 1166 | unsigned code = XINT (LGLYPH_CODE (g)); | ||
| 1167 | struct font_metrics metrics; | ||
| 1168 | |||
| 1169 | font->driver->text_extents (font, &code, 1, &metrics); | ||
| 1170 | LGLYPH_SET_WIDTH (g, make_number (metrics.width)); | ||
| 1171 | metrics.lbearing += XINT (LGLYPH_XOFF (g)); | ||
| 1172 | metrics.rbearing += XINT (LGLYPH_XOFF (g)); | ||
| 1173 | metrics.ascent += XINT (LGLYPH_YOFF (g)); | ||
| 1174 | metrics.descent += XINT (LGLYPH_YOFF (g)); | ||
| 1175 | |||
| 1176 | if (cmp->lbearing > cmp->pixel_width + metrics.lbearing) | ||
| 1177 | cmp->lbearing = cmp->pixel_width + metrics.lbearing; | ||
| 1178 | if (cmp->rbearing < cmp->pixel_width + metrics.rbearing) | ||
| 1179 | cmp->rbearing = cmp->pixel_width + metrics.rbearing; | ||
| 1180 | if (cmp->ascent < metrics.ascent) | ||
| 1181 | cmp->ascent = metrics.ascent; | ||
| 1182 | if (cmp->descent < metrics.descent) | ||
| 1183 | cmp->descent = metrics.descent; | ||
| 1184 | cmp->pixel_width += metrics.width + XINT (LGLYPH_WADJUST (g)); | ||
| 1185 | } | ||
| 1186 | LGSTRING_SET_LBEARING (gstring, make_number (cmp->lbearing)); | ||
| 1187 | LGSTRING_SET_RBEARING (gstring, make_number (cmp->rbearing)); | ||
| 1188 | LGSTRING_SET_WIDTH (gstring, make_number (cmp->pixel_width)); | ||
| 1189 | LGSTRING_SET_ASCENT (gstring, make_number (cmp->ascent)); | ||
| 1190 | LGSTRING_SET_DESCENT (gstring, make_number (cmp->descent)); | ||
| 1191 | |||
| 1192 | return font; | ||
| 1193 | } | ||
| 1194 | |||
| 1195 | int | ||
| 1196 | font_gstring_produce (old, from, to, new, idx, code, n) | ||
| 1197 | Lisp_Object old; | ||
| 1198 | int from, to; | ||
| 1199 | Lisp_Object new; | ||
| 1200 | int idx; | ||
| 1201 | unsigned *code; | ||
| 1202 | int n; | ||
| 1203 | { | ||
| 1204 | Lisp_Object min_idx, max_idx; | ||
| 1205 | int i; | ||
| 1206 | |||
| 1207 | if (idx + n > ASIZE (new)) | ||
| 1208 | return -1; | ||
| 1209 | if (from == to) | ||
| 1210 | { | ||
| 1211 | if (from == 0) | ||
| 1212 | { | ||
| 1213 | min_idx = make_number (0); | ||
| 1214 | max_idx = make_number (1); | ||
| 1215 | } | ||
| 1216 | else | ||
| 1217 | { | ||
| 1218 | min_idx = AREF (AREF (old, from - 1), 0); | ||
| 1219 | max_idx = AREF (AREF (old, from - 1), 1); | ||
| 1220 | } | ||
| 1221 | } | ||
| 1222 | else if (from + 1 == to) | ||
| 1223 | { | ||
| 1224 | min_idx = AREF (AREF (old, from), 0); | ||
| 1225 | max_idx = AREF (AREF (old, from), 1); | ||
| 1226 | } | ||
| 1227 | else | ||
| 1228 | { | ||
| 1229 | int min_idx_i = XINT (AREF (AREF (old, from), 0)); | ||
| 1230 | int max_idx_i = XINT (AREF (AREF (old, from), 1)); | ||
| 1231 | |||
| 1232 | for (i = from + 1; i < to; i++) | ||
| 1233 | { | ||
| 1234 | if (min_idx_i > XINT (AREF (AREF (old, i), 0))) | ||
| 1235 | min_idx_i = XINT (AREF (AREF (old, i), 0)); | ||
| 1236 | if (max_idx_i < XINT (AREF (AREF (old, i), 1))) | ||
| 1237 | max_idx_i = XINT (AREF (AREF (old, i), 1)); | ||
| 1238 | } | ||
| 1239 | min_idx = make_number (min_idx_i); | ||
| 1240 | max_idx = make_number (max_idx_i); | ||
| 1241 | } | ||
| 1242 | |||
| 1243 | for (i = 0; i < n; i++) | ||
| 1244 | { | ||
| 1245 | ASET (AREF (new, idx + i), 0, min_idx); | ||
| 1246 | ASET (AREF (new, idx + i), 1, max_idx); | ||
| 1247 | ASET (AREF (new, idx + i), 2, make_number (code[i])); | ||
| 1248 | } | ||
| 1249 | |||
| 1250 | return 0; | ||
| 1251 | } | ||
| 1252 | |||
| 1253 | /* Font sorting */ | ||
| 1254 | |||
| 1255 | static unsigned font_score P_ ((Lisp_Object, Lisp_Object)); | ||
| 1256 | static int font_compare P_ ((const void *, const void *)); | ||
| 1257 | static Lisp_Object font_sort_entites P_ ((Lisp_Object, Lisp_Object, | ||
| 1258 | Lisp_Object, Lisp_Object)); | ||
| 1259 | |||
| 1260 | /* We sort fonts by scoring each of them against a specified | ||
| 1261 | font-spec. The score value is 32 bit (`unsigned'), and the smaller | ||
| 1262 | the value is, the closer the font is to the font-spec. | ||
| 1263 | |||
| 1264 | Each 1-bit in the highest 4 bits of the score is used for atomic | ||
| 1265 | properties FOUNDRY, FAMILY, ADSTYLE, and REGISTRY. | ||
| 1266 | |||
| 1267 | Each 7-bit in the lowest 28 bits are used for numeric properties | ||
| 1268 | WEIGHT, SLANT, WIDTH, and SIZE. */ | ||
| 1269 | |||
| 1270 | /* How many bits to shift to store the difference value of each font | ||
| 1271 | property in a score. */ | ||
| 1272 | static int sort_shift_bits[FONT_SIZE_INDEX + 1]; | ||
| 1273 | |||
| 1274 | /* Score font-entity ENTITY against font-spec SPEC. The return value | ||
| 1275 | indicates how different ENTITY is compared with SPEC. */ | ||
| 1276 | |||
| 1277 | static unsigned | ||
| 1278 | font_score (entity, spec) | ||
| 1279 | Lisp_Object entity, spec; | ||
| 1280 | { | ||
| 1281 | unsigned score = 0; | ||
| 1282 | int i; | ||
| 1283 | /* Score atomic fields. Maximum difference is 1. */ | ||
| 1284 | for (i = FONT_FOUNDRY_INDEX; i <= FONT_REGISTRY_INDEX; i++) | ||
| 1285 | { | ||
| 1286 | Lisp_Object val = AREF (spec, i); | ||
| 1287 | |||
| 1288 | if (! NILP (val) | ||
| 1289 | && ! EQ (val, AREF (entity, i))) | ||
| 1290 | score |= 1 << sort_shift_bits[i]; | ||
| 1291 | } | ||
| 1292 | |||
| 1293 | /* Score numeric fields. Maximum difference is 127. */ | ||
| 1294 | for (i = FONT_WEIGHT_INDEX; i <= FONT_SIZE_INDEX; i++) | ||
| 1295 | { | ||
| 1296 | Lisp_Object spec_val = AREF (spec, i); | ||
| 1297 | Lisp_Object entity_val = AREF (entity, i); | ||
| 1298 | |||
| 1299 | if (! NILP (spec_val) && ! EQ (spec_val, entity_val)) | ||
| 1300 | { | ||
| 1301 | if (! INTEGERP (entity_val)) | ||
| 1302 | score |= 127 << sort_shift_bits[i]; | ||
| 1303 | else if (i < FONT_SIZE_INDEX | ||
| 1304 | || XINT (entity_val) != 0) | ||
| 1305 | { | ||
| 1306 | int diff = XINT (entity_val) - XINT (spec_val); | ||
| 1307 | |||
| 1308 | if (diff < 0) | ||
| 1309 | diff = - diff; | ||
| 1310 | score |= min (diff, 127) << sort_shift_bits[i]; | ||
| 1311 | } | ||
| 1312 | } | ||
| 1313 | } | ||
| 1314 | |||
| 1315 | return score; | ||
| 1316 | } | ||
| 1317 | |||
| 1318 | |||
| 1319 | /* The comparison function for qsort. */ | ||
| 1320 | |||
| 1321 | static int | ||
| 1322 | font_compare (d1, d2) | ||
| 1323 | const void *d1, *d2; | ||
| 1324 | { | ||
| 1325 | return (*(unsigned *) d1 < *(unsigned *) d2 | ||
| 1326 | ? -1 : *(unsigned *) d1 > *(unsigned *) d2); | ||
| 1327 | } | ||
| 1328 | |||
| 1329 | |||
| 1330 | /* The structure for elements being sorted by qsort. */ | ||
| 1331 | struct font_sort_data | ||
| 1332 | { | ||
| 1333 | unsigned score; | ||
| 1334 | Lisp_Object entity; | ||
| 1335 | }; | ||
| 1336 | |||
| 1337 | |||
| 1338 | /* Sort font-entities in vector VEC by closeness to font-spec PREFER. | ||
| 1339 | If PREFER specifies a point-size, calculate the corresponding | ||
| 1340 | pixel-size from the Y-resolution of FRAME before sorting. If SPEC | ||
| 1341 | is not nil, it is a font-spec to get the font-entities in VEC. */ | ||
| 1342 | |||
| 1343 | static Lisp_Object | ||
| 1344 | font_sort_entites (vec, prefer, frame, spec) | ||
| 1345 | Lisp_Object vec, prefer, frame, spec; | ||
| 1346 | { | ||
| 1347 | Lisp_Object size; | ||
| 1348 | int len, i; | ||
| 1349 | struct font_sort_data *data; | ||
| 1350 | int prefer_is_copy = 0; | ||
| 1351 | USE_SAFE_ALLOCA; | ||
| 1352 | |||
| 1353 | len = ASIZE (vec); | ||
| 1354 | if (len <= 1) | ||
| 1355 | return vec; | ||
| 1356 | |||
| 1357 | size = AREF (spec, FONT_SIZE_INDEX); | ||
| 1358 | if (FLOATP (size)) | ||
| 1359 | { | ||
| 1360 | double point_size = XFLOAT_DATA (size) * 10; | ||
| 1361 | int pixel_size = POINT_TO_PIXEL (point_size, XFRAME (frame)->resy); | ||
| 1362 | |||
| 1363 | prefer = Fcopy_sequence (prefer); | ||
| 1364 | ASET (prefer, FONT_SIZE_INDEX, make_number (pixel_size)); | ||
| 1365 | prefer_is_copy = 1; | ||
| 1366 | } | ||
| 1367 | |||
| 1368 | if (! NILP (spec)) | ||
| 1369 | { | ||
| 1370 | /* As it is assured that all fonts in VEC match with SPEC, we | ||
| 1371 | should ignore properties specified in SPEC. So, set the | ||
| 1372 | corresponding properties in PREFER nil. */ | ||
| 1373 | for (i = FONT_WEIGHT_INDEX; i <= FONT_SIZE_INDEX; i++) | ||
| 1374 | if (! NILP (AREF (spec, i)) && ! NILP (AREF (prefer, i))) | ||
| 1375 | break; | ||
| 1376 | if (i <= FONT_SIZE_INDEX) | ||
| 1377 | { | ||
| 1378 | if (! prefer_is_copy) | ||
| 1379 | prefer = Fcopy_sequence (prefer); | ||
| 1380 | for (; i <= FONT_SIZE_INDEX; i++) | ||
| 1381 | if (! NILP (AREF (spec, i)) && ! NILP (AREF (prefer, i))) | ||
| 1382 | ASET (prefer, i, Qnil); | ||
| 1383 | } | ||
| 1384 | } | ||
| 1385 | |||
| 1386 | /* Scoring and sorting. */ | ||
| 1387 | SAFE_ALLOCA (data, struct font_sort_data *, (sizeof *data) * len); | ||
| 1388 | for (i = 0; i < len; i++) | ||
| 1389 | { | ||
| 1390 | data[i].entity = AREF (vec, i); | ||
| 1391 | data[i].score = font_score (data[i].entity, prefer); | ||
| 1392 | } | ||
| 1393 | qsort (data, len, sizeof *data, font_compare); | ||
| 1394 | for (i = 0; i < len; i++) | ||
| 1395 | ASET (vec, i, data[i].entity); | ||
| 1396 | SAFE_FREE (); | ||
| 1397 | |||
| 1398 | return vec; | ||
| 1399 | } | ||
| 1400 | |||
| 1401 | |||
| 1402 | /* API of Font Service Layer. */ | ||
| 1403 | |||
| 1404 | void | ||
| 1405 | font_update_sort_order (order) | ||
| 1406 | int *order; | ||
| 1407 | { | ||
| 1408 | int i, shift_bits = 21; | ||
| 1409 | |||
| 1410 | for (i = 0; i < 4; i++, shift_bits -= 7) | ||
| 1411 | { | ||
| 1412 | int xlfd_idx = order[i]; | ||
| 1413 | |||
| 1414 | if (xlfd_idx == XLFD_WEIGHT_INDEX) | ||
| 1415 | sort_shift_bits[FONT_WEIGHT_INDEX] = shift_bits; | ||
| 1416 | else if (xlfd_idx == XLFD_SLANT_INDEX) | ||
| 1417 | sort_shift_bits[FONT_SLANT_INDEX] = shift_bits; | ||
| 1418 | else if (xlfd_idx == XLFD_SWIDTH_INDEX) | ||
| 1419 | sort_shift_bits[FONT_WIDTH_INDEX] = shift_bits; | ||
| 1420 | else | ||
| 1421 | sort_shift_bits[FONT_SIZE_INDEX] = shift_bits; | ||
| 1422 | } | ||
| 1423 | } | ||
| 1424 | |||
| 1425 | Lisp_Object | ||
| 1426 | font_symbolic_weight (font) | ||
| 1427 | Lisp_Object font; | ||
| 1428 | { | ||
| 1429 | Lisp_Object weight = AREF (font, FONT_WEIGHT_INDEX); | ||
| 1430 | |||
| 1431 | if (INTEGERP (weight)) | ||
| 1432 | weight = prop_numeric_to_name (FONT_WEIGHT_INDEX, XINT (weight)); | ||
| 1433 | return weight; | ||
| 1434 | } | ||
| 1435 | |||
| 1436 | Lisp_Object | ||
| 1437 | font_symbolic_slant (font) | ||
| 1438 | Lisp_Object font; | ||
| 1439 | { | ||
| 1440 | Lisp_Object slant = AREF (font, FONT_SLANT_INDEX); | ||
| 1441 | |||
| 1442 | if (INTEGERP (slant)) | ||
| 1443 | slant = prop_numeric_to_name (FONT_SLANT_INDEX, XINT (slant)); | ||
| 1444 | return slant; | ||
| 1445 | } | ||
| 1446 | |||
| 1447 | Lisp_Object | ||
| 1448 | font_symbolic_width (font) | ||
| 1449 | Lisp_Object font; | ||
| 1450 | { | ||
| 1451 | Lisp_Object width = AREF (font, FONT_WIDTH_INDEX); | ||
| 1452 | |||
| 1453 | if (INTEGERP (width)) | ||
| 1454 | width = prop_numeric_to_name (FONT_WIDTH_INDEX, XINT (width)); | ||
| 1455 | return width; | ||
| 1456 | } | ||
| 1457 | |||
| 1458 | Lisp_Object | ||
| 1459 | font_find_object (font) | ||
| 1460 | struct font *font; | ||
| 1461 | { | ||
| 1462 | Lisp_Object tail, elt; | ||
| 1463 | |||
| 1464 | for (tail = AREF (font->entity, FONT_OBJLIST_INDEX); CONSP (tail); | ||
| 1465 | tail = XCDR (tail)) | ||
| 1466 | { | ||
| 1467 | elt = XCAR (tail); | ||
| 1468 | if (font == XSAVE_VALUE (elt)->pointer | ||
| 1469 | && XSAVE_VALUE (elt)->integer > 0) | ||
| 1470 | return elt; | ||
| 1471 | } | ||
| 1472 | abort (); | ||
| 1473 | return Qnil; | ||
| 1474 | } | ||
| 1475 | |||
| 1476 | static Lisp_Object scratch_font_spec, scratch_font_prefer; | ||
| 1477 | |||
| 1478 | /* Return a vector of font-entities matching with SPEC on frame F. */ | ||
| 1479 | |||
| 1480 | static Lisp_Object | ||
| 1481 | font_list_entities (frame, spec) | ||
| 1482 | Lisp_Object frame, spec; | ||
| 1483 | { | ||
| 1484 | FRAME_PTR f = XFRAME (frame); | ||
| 1485 | struct font_driver_list *driver_list = f->font_driver_list; | ||
| 1486 | Lisp_Object ftype, family, alternate_familes; | ||
| 1487 | Lisp_Object *vec = alloca (sizeof (Lisp_Object) * num_font_drivers); | ||
| 1488 | int i; | ||
| 1489 | |||
| 1490 | if (! vec) | ||
| 1491 | return null_vector; | ||
| 1492 | |||
| 1493 | family = AREF (spec, FONT_FAMILY_INDEX); | ||
| 1494 | if (NILP (family)) | ||
| 1495 | alternate_familes = Qnil; | ||
| 1496 | else | ||
| 1497 | { | ||
| 1498 | if (NILP (font_family_alist) | ||
| 1499 | && !NILP (Vface_alternative_font_family_alist)) | ||
| 1500 | build_font_family_alist (); | ||
| 1501 | alternate_familes = assq_no_quit (family, font_family_alist); | ||
| 1502 | if (! NILP (alternate_familes)) | ||
| 1503 | alternate_familes = XCDR (alternate_familes); | ||
| 1504 | } | ||
| 1505 | xassert (ASIZE (spec) == FONT_SPEC_MAX); | ||
| 1506 | ftype = AREF (spec, FONT_TYPE_INDEX); | ||
| 1507 | |||
| 1508 | for (i = 0; driver_list; driver_list = driver_list->next) | ||
| 1509 | if (NILP (ftype) || EQ (driver_list->driver->type, ftype)) | ||
| 1510 | { | ||
| 1511 | Lisp_Object cache = driver_list->driver->get_cache (frame); | ||
| 1512 | Lisp_Object tail = alternate_familes; | ||
| 1513 | Lisp_Object val; | ||
| 1514 | |||
| 1515 | xassert (CONSP (cache)); | ||
| 1516 | ASET (spec, FONT_TYPE_INDEX, driver_list->driver->type); | ||
| 1517 | ASET (spec, FONT_FAMILY_INDEX, family); | ||
| 1518 | |||
| 1519 | while (1) | ||
| 1520 | { | ||
| 1521 | val = assoc_no_quit (spec, XCDR (cache)); | ||
| 1522 | if (CONSP (val)) | ||
| 1523 | val = XCDR (val); | ||
| 1524 | else | ||
| 1525 | { | ||
| 1526 | val = driver_list->driver->list (frame, spec); | ||
| 1527 | if (VECTORP (val)) | ||
| 1528 | XSETCDR (cache, Fcons (Fcons (Fcopy_sequence (spec), val), | ||
| 1529 | XCDR (cache))); | ||
| 1530 | } | ||
| 1531 | if (VECTORP (val) && ASIZE (val) > 0) | ||
| 1532 | { | ||
| 1533 | vec[i++] = val; | ||
| 1534 | break; | ||
| 1535 | } | ||
| 1536 | if (NILP (tail)) | ||
| 1537 | break; | ||
| 1538 | ASET (spec, FONT_FAMILY_INDEX, XCAR (tail)); | ||
| 1539 | tail = XCDR (tail); | ||
| 1540 | } | ||
| 1541 | } | ||
| 1542 | ASET (spec, FONT_TYPE_INDEX, ftype); | ||
| 1543 | ASET (spec, FONT_FAMILY_INDEX, family); | ||
| 1544 | return (i > 0 ? Fvconcat (i, vec) : null_vector); | ||
| 1545 | } | ||
| 1546 | |||
| 1547 | static int num_fonts; | ||
| 1548 | |||
| 1549 | static Lisp_Object | ||
| 1550 | font_open_entity (f, entity, pixel_size) | ||
| 1551 | FRAME_PTR f; | ||
| 1552 | Lisp_Object entity; | ||
| 1553 | int pixel_size; | ||
| 1554 | { | ||
| 1555 | struct font_driver_list *driver_list; | ||
| 1556 | Lisp_Object objlist, size, val; | ||
| 1557 | struct font *font; | ||
| 1558 | |||
| 1559 | size = AREF (entity, FONT_SIZE_INDEX); | ||
| 1560 | xassert (NATNUMP (size)); | ||
| 1561 | if (XINT (size) != 0) | ||
| 1562 | pixel_size = XINT (size); | ||
| 1563 | |||
| 1564 | for (objlist = AREF (entity, FONT_OBJLIST_INDEX); CONSP (objlist); | ||
| 1565 | objlist = XCDR (objlist)) | ||
| 1566 | { | ||
| 1567 | font = XSAVE_VALUE (XCAR (objlist))->pointer; | ||
| 1568 | if (font->pixel_size == pixel_size) | ||
| 1569 | { | ||
| 1570 | XSAVE_VALUE (XCAR (objlist))->integer++; | ||
| 1571 | return XCAR (objlist); | ||
| 1572 | } | ||
| 1573 | } | ||
| 1574 | |||
| 1575 | xassert (FONT_ENTITY_P (entity)); | ||
| 1576 | val = AREF (entity, FONT_TYPE_INDEX); | ||
| 1577 | for (driver_list = f->font_driver_list; | ||
| 1578 | driver_list && ! EQ (driver_list->driver->type, val); | ||
| 1579 | driver_list = driver_list->next); | ||
| 1580 | if (! driver_list) | ||
| 1581 | return Qnil; | ||
| 1582 | |||
| 1583 | font = driver_list->driver->open (f, entity, pixel_size); | ||
| 1584 | if (! font) | ||
| 1585 | return Qnil; | ||
| 1586 | val = make_save_value (font, 1); | ||
| 1587 | ASET (entity, FONT_OBJLIST_INDEX, | ||
| 1588 | Fcons (val, AREF (entity, FONT_OBJLIST_INDEX))); | ||
| 1589 | num_fonts++; | ||
| 1590 | return val; | ||
| 1591 | } | ||
| 1592 | |||
| 1593 | void | ||
| 1594 | font_close_object (f, font_object) | ||
| 1595 | FRAME_PTR f; | ||
| 1596 | Lisp_Object font_object; | ||
| 1597 | { | ||
| 1598 | struct font *font; | ||
| 1599 | Lisp_Object objlist = AREF (font->entity, FONT_OBJLIST_INDEX); | ||
| 1600 | Lisp_Object tail, prev = Qnil; | ||
| 1601 | |||
| 1602 | for (prev = Qnil, tail = objlist; CONSP (tail); | ||
| 1603 | prev = tail, tail = XCDR (tail)) | ||
| 1604 | if (EQ (font_object, XCAR (tail))) | ||
| 1605 | { | ||
| 1606 | struct Lisp_Save_Value *p = XSAVE_VALUE (font_object); | ||
| 1607 | |||
| 1608 | xassert (p->integer > 0); | ||
| 1609 | p->integer--; | ||
| 1610 | if (p->integer == 0) | ||
| 1611 | { | ||
| 1612 | if (font->driver->close) | ||
| 1613 | font->driver->close (f, p->pointer); | ||
| 1614 | p->pointer = NULL; | ||
| 1615 | if (NILP (prev)) | ||
| 1616 | ASET (font->entity, FONT_OBJLIST_INDEX, XCDR (objlist)); | ||
| 1617 | else | ||
| 1618 | XSETCDR (prev, XCDR (objlist)); | ||
| 1619 | } | ||
| 1620 | break; | ||
| 1621 | } | ||
| 1622 | } | ||
| 1623 | |||
| 1624 | int | ||
| 1625 | font_has_char (f, font_entity, c) | ||
| 1626 | FRAME_PTR f; | ||
| 1627 | Lisp_Object font_entity; | ||
| 1628 | int c; | ||
| 1629 | { | ||
| 1630 | Lisp_Object type = AREF (font_entity, FONT_TYPE_INDEX); | ||
| 1631 | struct font_driver_list *driver_list; | ||
| 1632 | |||
| 1633 | for (driver_list = f->font_driver_list; | ||
| 1634 | driver_list && ! EQ (driver_list->driver->type, type); | ||
| 1635 | driver_list = driver_list->next); | ||
| 1636 | if (! driver_list) | ||
| 1637 | return -1; | ||
| 1638 | return driver_list->driver->has_char (font_entity, c); | ||
| 1639 | } | ||
| 1640 | |||
| 1641 | unsigned | ||
| 1642 | font_encode_char (font_object, c) | ||
| 1643 | Lisp_Object font_object; | ||
| 1644 | int c; | ||
| 1645 | { | ||
| 1646 | struct font *font = XSAVE_VALUE (font_object)->pointer; | ||
| 1647 | |||
| 1648 | return font->driver->encode_char (font, c); | ||
| 1649 | } | ||
| 1650 | |||
| 1651 | char * | ||
| 1652 | font_get_name (font_object) | ||
| 1653 | Lisp_Object font_object; | ||
| 1654 | { | ||
| 1655 | struct font *font = XSAVE_VALUE (font_object)->pointer; | ||
| 1656 | |||
| 1657 | return (font->font.full_name ? font->font.full_name | ||
| 1658 | : font->file_name ? font->file_name | ||
| 1659 | : ""); | ||
| 1660 | } | ||
| 1661 | |||
| 1662 | Lisp_Object | ||
| 1663 | font_get_frame (font) | ||
| 1664 | Lisp_Object font; | ||
| 1665 | { | ||
| 1666 | if (FONT_OBJECT_P (font)) | ||
| 1667 | font = ((struct font *) XSAVE_VALUE (font)->pointer)->entity; | ||
| 1668 | xassert (FONT_ENTITY_P (font)); | ||
| 1669 | return AREF (font, FONT_FRAME_INDEX); | ||
| 1670 | } | ||
| 1671 | |||
| 1672 | extern Lisp_Object Qunspecified, Qignore_defface; | ||
| 1673 | |||
| 1674 | Lisp_Object | ||
| 1675 | font_find_for_lface (f, lface, spec) | ||
| 1676 | FRAME_PTR f; | ||
| 1677 | Lisp_Object *lface; | ||
| 1678 | Lisp_Object spec; | ||
| 1679 | { | ||
| 1680 | Lisp_Object attrs[LFACE_SLANT_INDEX + 1]; | ||
| 1681 | Lisp_Object frame, val, entities; | ||
| 1682 | int i; | ||
| 1683 | unsigned char try_unspecified[FONT_SPEC_MAX]; | ||
| 1684 | |||
| 1685 | for (i = 0; i <= LFACE_SLANT_INDEX; i++) | ||
| 1686 | { | ||
| 1687 | val = lface[i]; | ||
| 1688 | if (EQ (val, Qunspecified) || EQ (val, Qignore_defface)) | ||
| 1689 | val = Qnil; | ||
| 1690 | attrs[i] = val; | ||
| 1691 | } | ||
| 1692 | if (NILP (spec)) | ||
| 1693 | for (i = 0; i < FONT_SPEC_MAX; i++) | ||
| 1694 | ASET (scratch_font_spec, i, Qnil); | ||
| 1695 | else | ||
| 1696 | for (i = 0; i < FONT_SPEC_MAX; i++) | ||
| 1697 | ASET (scratch_font_spec, i, AREF (spec, i)); | ||
| 1698 | |||
| 1699 | /* If SPEC doesn't specify a specific property, it can be tried with | ||
| 1700 | nil even if FACE specifies it. */ | ||
| 1701 | for (i = FONT_FOUNDRY_INDEX; i <= FONT_SIZE_INDEX; i++) | ||
| 1702 | try_unspecified[i] = NILP (AREF (scratch_font_spec, i)); | ||
| 1703 | |||
| 1704 | if (STRINGP (attrs[LFACE_FONT_INDEX])) | ||
| 1705 | font_merge_old_spec (attrs[LFACE_FONT_INDEX], Qnil, Qnil, | ||
| 1706 | scratch_font_spec); | ||
| 1707 | if (NILP (AREF (scratch_font_spec, FONT_FAMILY_INDEX)) | ||
| 1708 | && ! NILP (attrs[LFACE_FAMILY_INDEX])) | ||
| 1709 | font_merge_old_spec (Qnil, attrs[LFACE_FAMILY_INDEX], Qnil, | ||
| 1710 | scratch_font_spec); | ||
| 1711 | if (NILP (AREF (scratch_font_spec, FONT_REGISTRY_INDEX))) | ||
| 1712 | { | ||
| 1713 | ASET (scratch_font_spec, FONT_REGISTRY_INDEX, intern ("iso8859-1")); | ||
| 1714 | try_unspecified[FONT_REGISTRY_INDEX] = 0; | ||
| 1715 | } | ||
| 1716 | |||
| 1717 | for (i = FONT_FAMILY_INDEX; i <= FONT_SIZE_INDEX; i++) | ||
| 1718 | if (try_unspecified[i] | ||
| 1719 | && NILP (AREF (scratch_font_spec, i))) | ||
| 1720 | try_unspecified[i] = 0; | ||
| 1721 | |||
| 1722 | XSETFRAME (frame, f); | ||
| 1723 | entities = font_list_entities (frame, scratch_font_spec); | ||
| 1724 | while (ASIZE (entities) == 0) | ||
| 1725 | { | ||
| 1726 | if (try_unspecified[FONT_WEIGHT_INDEX] | ||
| 1727 | || try_unspecified[FONT_SLANT_INDEX] | ||
| 1728 | || try_unspecified[FONT_WIDTH_INDEX] | ||
| 1729 | || try_unspecified[FONT_SIZE_INDEX]) | ||
| 1730 | { | ||
| 1731 | for (i = FONT_WEIGHT_INDEX; i <= FONT_SIZE_INDEX; i++) | ||
| 1732 | { | ||
| 1733 | try_unspecified[i] = 0; | ||
| 1734 | ASET (scratch_font_spec, i, Qnil); | ||
| 1735 | } | ||
| 1736 | entities = font_list_entities (frame, scratch_font_spec); | ||
| 1737 | } | ||
| 1738 | else if (try_unspecified[FONT_FOUNDRY_INDEX]) | ||
| 1739 | { | ||
| 1740 | try_unspecified[FONT_FOUNDRY_INDEX] = 0; | ||
| 1741 | ASET (scratch_font_spec, FONT_FOUNDRY_INDEX, Qnil); | ||
| 1742 | entities = font_list_entities (frame, scratch_font_spec); | ||
| 1743 | } | ||
| 1744 | else if (try_unspecified[FONT_FAMILY_INDEX]) | ||
| 1745 | { | ||
| 1746 | try_unspecified[FONT_FAMILY_INDEX] = 0; | ||
| 1747 | ASET (scratch_font_spec, FONT_FAMILY_INDEX, Qnil); | ||
| 1748 | entities = font_list_entities (frame, scratch_font_spec); | ||
| 1749 | } | ||
| 1750 | else | ||
| 1751 | return Qnil; | ||
| 1752 | } | ||
| 1753 | |||
| 1754 | if (ASIZE (entities) > 1) | ||
| 1755 | { | ||
| 1756 | Lisp_Object prefer = scratch_font_prefer; | ||
| 1757 | |||
| 1758 | for (i = 0; i < FONT_WEIGHT_INDEX; i++) | ||
| 1759 | ASET (prefer, i, Qnil); | ||
| 1760 | if (! NILP (attrs[LFACE_WEIGHT_INDEX])) | ||
| 1761 | ASET (prefer, FONT_WEIGHT_INDEX, | ||
| 1762 | font_prop_validate_style (FONT_WEIGHT_INDEX, | ||
| 1763 | attrs[LFACE_WEIGHT_INDEX])); | ||
| 1764 | if (! NILP (attrs[LFACE_SLANT_INDEX])) | ||
| 1765 | ASET (prefer, FONT_SLANT_INDEX, | ||
| 1766 | font_prop_validate_style (FONT_SLANT_INDEX, | ||
| 1767 | attrs[LFACE_SLANT_INDEX])); | ||
| 1768 | if (! NILP (attrs[LFACE_SWIDTH_INDEX])) | ||
| 1769 | ASET (prefer, FONT_WIDTH_INDEX, | ||
| 1770 | font_prop_validate_style (FONT_WIDTH_INDEX, | ||
| 1771 | attrs[LFACE_SWIDTH_INDEX])); | ||
| 1772 | if (! NILP (attrs[LFACE_HEIGHT_INDEX])) | ||
| 1773 | { | ||
| 1774 | int size; | ||
| 1775 | |||
| 1776 | val = attrs[LFACE_HEIGHT_INDEX]; | ||
| 1777 | size = POINT_TO_PIXEL (XINT (val), f->resy); | ||
| 1778 | ASET (prefer, FONT_SIZE_INDEX, make_number (size)); | ||
| 1779 | } | ||
| 1780 | font_sort_entites (entities, prefer, frame, spec); | ||
| 1781 | } | ||
| 1782 | |||
| 1783 | return AREF (entities, 0); | ||
| 1784 | } | ||
| 1785 | |||
| 1786 | Lisp_Object | ||
| 1787 | font_open_for_lface (f, lface, entity) | ||
| 1788 | FRAME_PTR f; | ||
| 1789 | Lisp_Object *lface; | ||
| 1790 | Lisp_Object entity; | ||
| 1791 | { | ||
| 1792 | int pt = XINT (lface[LFACE_HEIGHT_INDEX]); | ||
| 1793 | int size = POINT_TO_PIXEL (pt, f->resy); | ||
| 1794 | |||
| 1795 | return font_open_entity (f, entity, size); | ||
| 1796 | } | ||
| 1797 | |||
| 1798 | void | ||
| 1799 | font_load_for_face (f, face) | ||
| 1800 | FRAME_PTR f; | ||
| 1801 | struct face *face; | ||
| 1802 | { | ||
| 1803 | Lisp_Object entity; | ||
| 1804 | |||
| 1805 | face->font_info_id = -1; | ||
| 1806 | face->font_info = NULL; | ||
| 1807 | face->font = NULL; | ||
| 1808 | face->font_name = NULL; | ||
| 1809 | |||
| 1810 | entity = font_find_for_lface (f, face->lface, Qnil); | ||
| 1811 | if (! NILP (entity)) | ||
| 1812 | { | ||
| 1813 | Lisp_Object font_object = font_open_for_lface (f, face->lface, entity); | ||
| 1814 | |||
| 1815 | if (! NILP (font_object)) | ||
| 1816 | { | ||
| 1817 | struct font *font = XSAVE_VALUE (font_object)->pointer; | ||
| 1818 | |||
| 1819 | face->font = font->font.font; | ||
| 1820 | face->font_info = (struct font_info *) font; | ||
| 1821 | face->font_info_id = 0; | ||
| 1822 | face->font_name = font->font.full_name; | ||
| 1823 | } | ||
| 1824 | } | ||
| 1825 | if (! face->font) | ||
| 1826 | add_to_log ("Unable to load font for a face%s", null_string, Qnil); | ||
| 1827 | } | ||
| 1828 | |||
| 1829 | void | ||
| 1830 | font_prepare_for_face (f, face) | ||
| 1831 | FRAME_PTR f; | ||
| 1832 | struct face *face; | ||
| 1833 | { | ||
| 1834 | struct font *font = (struct font *) face->font_info; | ||
| 1835 | |||
| 1836 | if (font->driver->prepare_face) | ||
| 1837 | font->driver->prepare_face (f, face); | ||
| 1838 | } | ||
| 1839 | |||
| 1840 | void | ||
| 1841 | font_done_for_face (f, face) | ||
| 1842 | FRAME_PTR f; | ||
| 1843 | struct face *face; | ||
| 1844 | { | ||
| 1845 | struct font *font = (struct font *) face->font_info; | ||
| 1846 | |||
| 1847 | if (font->driver->done_face) | ||
| 1848 | font->driver->done_face (f, face); | ||
| 1849 | face->extra = NULL; | ||
| 1850 | } | ||
| 1851 | |||
| 1852 | Lisp_Object | ||
| 1853 | font_open_by_name (f, name) | ||
| 1854 | FRAME_PTR f; | ||
| 1855 | char *name; | ||
| 1856 | { | ||
| 1857 | Lisp_Object spec = Ffont_spec (0, NULL); | ||
| 1858 | Lisp_Object entities = Qnil; | ||
| 1859 | Lisp_Object frame; | ||
| 1860 | int pixel_size; | ||
| 1861 | |||
| 1862 | XSETFRAME (frame, f); | ||
| 1863 | |||
| 1864 | ASET (spec, FONT_EXTRA_INDEX, | ||
| 1865 | Fcons (Fcons (QCname, make_unibyte_string (name, strlen (name))), | ||
| 1866 | Qnil)); | ||
| 1867 | entities = font_list_entities (frame, spec); | ||
| 1868 | if (ASIZE (entities) == 0) | ||
| 1869 | return Qnil; | ||
| 1870 | pixel_size = XINT (AREF (AREF (entities, 0), FONT_SIZE_INDEX)); | ||
| 1871 | if (pixel_size == 0) | ||
| 1872 | pixel_size = 12; | ||
| 1873 | return font_open_entity (f, AREF (entities, 0), pixel_size); | ||
| 1874 | } | ||
| 1875 | |||
| 1876 | |||
| 1877 | /* Register font-driver DRIVER. This function is used in two ways. | ||
| 1878 | |||
| 1879 | The first is with frame F non-NULL. In this case, DRIVER is | ||
| 1880 | registered to be used for drawing characters on F. All frame | ||
| 1881 | creaters (e.g. Fx_create_frame) must call this function at least | ||
| 1882 | once with an available font-driver. | ||
| 1883 | |||
| 1884 | The second is with frame F NULL. In this case, DRIVER is globally | ||
| 1885 | registered in the variable `font_driver_list'. All font-driver | ||
| 1886 | implementations must call this function in its syms_of_XXXX | ||
| 1887 | (e.g. syms_of_xfont). */ | ||
| 1888 | |||
| 1889 | void | ||
| 1890 | register_font_driver (driver, f) | ||
| 1891 | struct font_driver *driver; | ||
| 1892 | FRAME_PTR f; | ||
| 1893 | { | ||
| 1894 | struct font_driver_list *root = f ? f->font_driver_list : font_driver_list; | ||
| 1895 | struct font_driver_list *prev, *list; | ||
| 1896 | |||
| 1897 | if (f && ! driver->draw) | ||
| 1898 | error ("Unsable font driver for a frame: %s", | ||
| 1899 | SDATA (SYMBOL_NAME (driver->type))); | ||
| 1900 | |||
| 1901 | for (prev = NULL, list = root; list; prev = list, list = list->next) | ||
| 1902 | if (list->driver->type == driver->type) | ||
| 1903 | error ("Duplicated font driver: %s", SDATA (SYMBOL_NAME (driver->type))); | ||
| 1904 | |||
| 1905 | list = malloc (sizeof (struct font_driver_list)); | ||
| 1906 | list->driver = driver; | ||
| 1907 | list->next = NULL; | ||
| 1908 | if (prev) | ||
| 1909 | prev->next = list; | ||
| 1910 | else if (f) | ||
| 1911 | f->font_driver_list = list; | ||
| 1912 | else | ||
| 1913 | font_driver_list = list; | ||
| 1914 | num_font_drivers++; | ||
| 1915 | } | ||
| 1916 | |||
| 1917 | /* Free font-driver list on frame F. It doesn't free font-drivers | ||
| 1918 | themselves. */ | ||
| 1919 | |||
| 1920 | void | ||
| 1921 | free_font_driver_list (f) | ||
| 1922 | FRAME_PTR f; | ||
| 1923 | { | ||
| 1924 | while (f->font_driver_list) | ||
| 1925 | { | ||
| 1926 | struct font_driver_list *next = f->font_driver_list->next; | ||
| 1927 | |||
| 1928 | free (f->font_driver_list); | ||
| 1929 | f->font_driver_list = next; | ||
| 1930 | } | ||
| 1931 | } | ||
| 1932 | |||
| 1933 | |||
| 1934 | /* Lisp API */ | ||
| 1935 | |||
| 1936 | DEFUN ("fontp", Ffontp, Sfontp, 1, 1, 0, | ||
| 1937 | doc: /* Return t if object is a font-spec or font-entity. */) | ||
| 1938 | (object) | ||
| 1939 | Lisp_Object object; | ||
| 1940 | { | ||
| 1941 | return (FONTP (object) ? Qt : Qnil); | ||
| 1942 | } | ||
| 1943 | |||
| 1944 | DEFUN ("font-spec", Ffont_spec, Sfont_spec, 0, MANY, 0, | ||
| 1945 | doc: /* Return a newly created font-spec with specified arguments as properties. | ||
| 1946 | usage: (font-spec &rest properties) */) | ||
| 1947 | (nargs, args) | ||
| 1948 | int nargs; | ||
| 1949 | Lisp_Object *args; | ||
| 1950 | { | ||
| 1951 | Lisp_Object spec = Fmake_vector (make_number (FONT_SPEC_MAX), Qnil); | ||
| 1952 | Lisp_Object extra = Qnil; | ||
| 1953 | int i; | ||
| 1954 | |||
| 1955 | for (i = 0; i < nargs; i += 2) | ||
| 1956 | { | ||
| 1957 | enum font_property_index prop; | ||
| 1958 | Lisp_Object key = args[i], val = args[i + 1]; | ||
| 1959 | |||
| 1960 | prop = check_font_prop_name (key); | ||
| 1961 | if (prop < FONT_EXTRA_INDEX) | ||
| 1962 | ASET (spec, prop, (font_property_table[prop].validater) (prop, val)); | ||
| 1963 | else | ||
| 1964 | extra = Fcons (Fcons (key, val), extra); | ||
| 1965 | } | ||
| 1966 | ASET (spec, FONT_EXTRA_INDEX, extra); | ||
| 1967 | return spec; | ||
| 1968 | } | ||
| 1969 | |||
| 1970 | |||
| 1971 | DEFUN ("font-get", Ffont_get, Sfont_get, 2, 2, 0, | ||
| 1972 | doc: /* Return the value of FONT's PROP property. | ||
| 1973 | FONT may be a font-spec or font-entity. | ||
| 1974 | If FONT is font-entity and PROP is :extra, always nil is returned. */) | ||
| 1975 | (font, prop) | ||
| 1976 | Lisp_Object font, prop; | ||
| 1977 | { | ||
| 1978 | enum font_property_index idx; | ||
| 1979 | |||
| 1980 | CHECK_FONT (font); | ||
| 1981 | idx = check_font_prop_name (prop); | ||
| 1982 | if (idx < FONT_EXTRA_INDEX) | ||
| 1983 | return AREF (font, idx); | ||
| 1984 | if (FONT_ENTITY_P (font)) | ||
| 1985 | return Qnil; | ||
| 1986 | return Fcdr (Fassoc (AREF (font, FONT_EXTRA_INDEX), prop)); | ||
| 1987 | } | ||
| 1988 | |||
| 1989 | |||
| 1990 | DEFUN ("font-put", Ffont_put, Sfont_put, 3, 3, 0, | ||
| 1991 | doc: /* Set one property of FONT-SPEC: give property PROP value VALUE. */) | ||
| 1992 | (font_spec, prop, val) | ||
| 1993 | Lisp_Object font_spec, prop, val; | ||
| 1994 | { | ||
| 1995 | enum font_property_index idx; | ||
| 1996 | Lisp_Object extra, slot; | ||
| 1997 | |||
| 1998 | CHECK_FONT_SPEC (font_spec); | ||
| 1999 | idx = check_font_prop_name (prop); | ||
| 2000 | if (idx < FONT_EXTRA_INDEX) | ||
| 2001 | return ASET (font_spec, idx, val); | ||
| 2002 | extra = AREF (font_spec, FONT_EXTRA_INDEX); | ||
| 2003 | slot = Fassoc (extra, prop); | ||
| 2004 | if (NILP (slot)) | ||
| 2005 | extra = Fcons (Fcons (prop, val), extra); | ||
| 2006 | else | ||
| 2007 | Fsetcdr (slot, val); | ||
| 2008 | return val; | ||
| 2009 | } | ||
| 2010 | |||
| 2011 | DEFUN ("list-fonts", Flist_fonts, Slist_fonts, 1, 4, 0, | ||
| 2012 | doc: /* List available fonts matching FONT-SPEC on the current frame. | ||
| 2013 | Optional 2nd argument FRAME specifies the target frame. | ||
| 2014 | Optional 3rd argument NUM, if non-nil, limits the number of returned fonts. | ||
| 2015 | Optional 4th argument PREFER, if non-nil, is a font-spec to sort fonts | ||
| 2016 | by closeness to PREFER. */) | ||
| 2017 | (font_spec, frame, num, prefer) | ||
| 2018 | Lisp_Object font_spec, frame, num, prefer; | ||
| 2019 | { | ||
| 2020 | Lisp_Object vec, list, tail; | ||
| 2021 | int n = 0, i, len; | ||
| 2022 | |||
| 2023 | if (NILP (frame)) | ||
| 2024 | frame = selected_frame; | ||
| 2025 | CHECK_LIVE_FRAME (frame); | ||
| 2026 | CHECK_VALIDATE_FONT_SPEC (font_spec); | ||
| 2027 | if (! NILP (num)) | ||
| 2028 | { | ||
| 2029 | CHECK_NUMBER (num); | ||
| 2030 | n = XINT (num); | ||
| 2031 | if (n <= 0) | ||
| 2032 | return Qnil; | ||
| 2033 | } | ||
| 2034 | if (! NILP (prefer)) | ||
| 2035 | CHECK_FONT (prefer); | ||
| 2036 | |||
| 2037 | vec = font_list_entities (frame, font_spec); | ||
| 2038 | len = ASIZE (vec); | ||
| 2039 | if (len == 0) | ||
| 2040 | return Qnil; | ||
| 2041 | if (len == 1) | ||
| 2042 | return Fcons (AREF (vec, 0), Qnil); | ||
| 2043 | |||
| 2044 | if (! NILP (prefer)) | ||
| 2045 | vec = font_sort_entites (vec, prefer, frame, font_spec); | ||
| 2046 | |||
| 2047 | list = tail = Fcons (AREF (vec, 0), Qnil); | ||
| 2048 | if (n == 0 || n > len) | ||
| 2049 | n = len; | ||
| 2050 | for (i = 1; i < n; i++) | ||
| 2051 | { | ||
| 2052 | Lisp_Object val = Fcons (AREF (vec, i), Qnil); | ||
| 2053 | |||
| 2054 | XSETCDR (tail, val); | ||
| 2055 | tail = val; | ||
| 2056 | } | ||
| 2057 | return list; | ||
| 2058 | } | ||
| 2059 | |||
| 2060 | DEFUN ("list-families", Flist_families, Slist_families, 0, 1, 0, | ||
| 2061 | doc: /* List available font families on the current frame. | ||
| 2062 | Optional 2nd argument FRAME specifies the target frame. */) | ||
| 2063 | (frame) | ||
| 2064 | Lisp_Object frame; | ||
| 2065 | { | ||
| 2066 | FRAME_PTR f; | ||
| 2067 | struct font_driver_list *driver_list; | ||
| 2068 | Lisp_Object list; | ||
| 2069 | |||
| 2070 | if (NILP (frame)) | ||
| 2071 | frame = selected_frame; | ||
| 2072 | CHECK_LIVE_FRAME (frame); | ||
| 2073 | f = XFRAME (frame); | ||
| 2074 | list = Qnil; | ||
| 2075 | for (driver_list = f->font_driver_list; driver_list; | ||
| 2076 | driver_list = driver_list->next) | ||
| 2077 | if (driver_list->driver->list_family) | ||
| 2078 | { | ||
| 2079 | Lisp_Object val = driver_list->driver->list_family (frame); | ||
| 2080 | |||
| 2081 | if (NILP (list)) | ||
| 2082 | list = val; | ||
| 2083 | else | ||
| 2084 | { | ||
| 2085 | Lisp_Object tail = list; | ||
| 2086 | |||
| 2087 | for (; CONSP (val); val = XCDR (val)) | ||
| 2088 | if (NILP (Fmemq (XCAR (val), tail))) | ||
| 2089 | list = Fcons (XCAR (val), list); | ||
| 2090 | } | ||
| 2091 | } | ||
| 2092 | return list; | ||
| 2093 | } | ||
| 2094 | |||
| 2095 | DEFUN ("find-font", Ffind_font, Sfind_font, 1, 2, 0, | ||
| 2096 | doc: /* Return a font-entity matching with FONT-SPEC on the current frame. | ||
| 2097 | Optional 2nd argument FRAME, if non-nil, specifies the target frame. */) | ||
| 2098 | (font_spec, frame) | ||
| 2099 | Lisp_Object font_spec, frame; | ||
| 2100 | { | ||
| 2101 | Lisp_Object val = Flist_fonts (font_spec, frame, make_number (1), Qnil); | ||
| 2102 | |||
| 2103 | if (CONSP (val)) | ||
| 2104 | val = XCAR (val); | ||
| 2105 | return val; | ||
| 2106 | } | ||
| 2107 | |||
| 2108 | DEFUN ("font-xlfd-name", Ffont_xlfd_name, Sfont_xlfd_name, 1, 1, 0, | ||
| 2109 | doc: /* Return XLFD name of FONT. | ||
| 2110 | FONT is a font-spec, font-entity, or font-object. | ||
| 2111 | If the name is too long for XLFD (maximum 255 chars), return nil. */) | ||
| 2112 | (font) | ||
| 2113 | Lisp_Object font; | ||
| 2114 | { | ||
| 2115 | char name[256]; | ||
| 2116 | int pixel_size = 0; | ||
| 2117 | |||
| 2118 | if (FONT_SPEC_P (font)) | ||
| 2119 | CHECK_VALIDATE_FONT_SPEC (font); | ||
| 2120 | else if (FONT_ENTITY_P (font)) | ||
| 2121 | CHECK_FONT (font); | ||
| 2122 | else | ||
| 2123 | { | ||
| 2124 | struct font *fontp; | ||
| 2125 | |||
| 2126 | CHECK_FONT_GET_OBJECT (font, fontp); | ||
| 2127 | font = fontp->entity; | ||
| 2128 | pixel_size = fontp->pixel_size; | ||
| 2129 | } | ||
| 2130 | |||
| 2131 | if (font_unparse_xlfd (font, pixel_size, name, 256) < 0) | ||
| 2132 | return Qnil; | ||
| 2133 | return build_string (name); | ||
| 2134 | } | ||
| 2135 | |||
| 2136 | DEFUN ("clear-font-cache", Fclear_font_cache, Sclear_font_cache, 0, 0, 0, | ||
| 2137 | doc: /* Clear font cache. */) | ||
| 2138 | () | ||
| 2139 | { | ||
| 2140 | Lisp_Object list, frame; | ||
| 2141 | |||
| 2142 | FOR_EACH_FRAME (list, frame) | ||
| 2143 | { | ||
| 2144 | FRAME_PTR f = XFRAME (frame); | ||
| 2145 | struct font_driver_list *driver_list = f->font_driver_list; | ||
| 2146 | |||
| 2147 | for (; driver_list; driver_list = driver_list->next) | ||
| 2148 | { | ||
| 2149 | Lisp_Object cache = driver_list->driver->get_cache (frame); | ||
| 2150 | Lisp_Object tail, elt; | ||
| 2151 | |||
| 2152 | for (tail = XCDR (cache); CONSP (tail); tail = XCDR (tail)) | ||
| 2153 | { | ||
| 2154 | elt = XCAR (tail); | ||
| 2155 | if (CONSP (elt) && FONT_SPEC_P (XCAR (elt))) | ||
| 2156 | { | ||
| 2157 | Lisp_Object vec = XCDR (elt); | ||
| 2158 | int i; | ||
| 2159 | |||
| 2160 | for (i = 0; i < ASIZE (vec); i++) | ||
| 2161 | { | ||
| 2162 | Lisp_Object entity = AREF (vec, i); | ||
| 2163 | Lisp_Object objlist = AREF (entity, FONT_OBJLIST_INDEX); | ||
| 2164 | |||
| 2165 | for (; CONSP (objlist); objlist = XCDR (objlist)) | ||
| 2166 | { | ||
| 2167 | Lisp_Object val = XCAR (objlist); | ||
| 2168 | struct Lisp_Save_Value *p = XSAVE_VALUE (val); | ||
| 2169 | struct font *font = p->pointer; | ||
| 2170 | |||
| 2171 | xassert (font | ||
| 2172 | && driver_list->driver == font->driver); | ||
| 2173 | driver_list->driver->close (f, font); | ||
| 2174 | p->pointer = NULL; | ||
| 2175 | p->integer = 0; | ||
| 2176 | } | ||
| 2177 | if (driver_list->driver->free_entity) | ||
| 2178 | driver_list->driver->free_entity (entity); | ||
| 2179 | } | ||
| 2180 | } | ||
| 2181 | } | ||
| 2182 | XSETCDR (cache, Qnil); | ||
| 2183 | } | ||
| 2184 | } | ||
| 2185 | |||
| 2186 | return Qnil; | ||
| 2187 | } | ||
| 2188 | |||
| 2189 | DEFUN ("internal-set-font-style-table", Finternal_set_font_style_table, | ||
| 2190 | Sinternal_set_font_style_table, 2, 2, 0, | ||
| 2191 | doc: /* Set font style table for PROP to TABLE. | ||
| 2192 | PROP must be `:weight', `:slant', or `:width'. | ||
| 2193 | TABLE must be an alist of symbols vs the corresponding numeric values | ||
| 2194 | sorted by numeric values. */) | ||
| 2195 | (prop, table) | ||
| 2196 | Lisp_Object prop, table; | ||
| 2197 | { | ||
| 2198 | int table_index; | ||
| 2199 | int numeric; | ||
| 2200 | Lisp_Object tail, val; | ||
| 2201 | |||
| 2202 | CHECK_SYMBOL (prop); | ||
| 2203 | table_index = (EQ (prop, QCweight) ? 0 | ||
| 2204 | : EQ (prop, QCslant) ? 1 | ||
| 2205 | : EQ (prop, QCwidth) ? 2 | ||
| 2206 | : 3); | ||
| 2207 | if (table_index >= ASIZE (font_style_table)) | ||
| 2208 | error ("Invalid font style property: %s", SDATA (SYMBOL_NAME (prop))); | ||
| 2209 | table = Fcopy_sequence (table); | ||
| 2210 | numeric = -1; | ||
| 2211 | for (tail = table; ! NILP (tail); tail = Fcdr (tail)) | ||
| 2212 | { | ||
| 2213 | prop = Fcar (Fcar (tail)); | ||
| 2214 | val = Fcdr (Fcar (tail)); | ||
| 2215 | CHECK_SYMBOL (prop); | ||
| 2216 | CHECK_NATNUM (val); | ||
| 2217 | if (numeric > XINT (val)) | ||
| 2218 | error ("Numeric values not sorted for %s", SDATA (SYMBOL_NAME (prop))); | ||
| 2219 | numeric = XINT (val); | ||
| 2220 | XSETCAR (tail, Fcons (prop, val)); | ||
| 2221 | } | ||
| 2222 | ASET (font_style_table, table_index, table); | ||
| 2223 | return Qnil; | ||
| 2224 | } | ||
| 2225 | |||
| 2226 | DEFUN ("font-make-gstring", Ffont_make_gstring, Sfont_make_gstring, 2, 2, 0, | ||
| 2227 | doc: /* Return a newly created glyph-string for FONT-OBJECT with NUM glyphs. | ||
| 2228 | FONT-OBJECT may be nil if it is not yet known. */) | ||
| 2229 | (font_object, num) | ||
| 2230 | Lisp_Object font_object, num; | ||
| 2231 | { | ||
| 2232 | Lisp_Object gstring, g; | ||
| 2233 | int len; | ||
| 2234 | int i; | ||
| 2235 | |||
| 2236 | if (! NILP (font_object)) | ||
| 2237 | CHECK_FONT_OBJECT (font_object); | ||
| 2238 | CHECK_NATNUM (num); | ||
| 2239 | |||
| 2240 | len = XINT (num) + 1; | ||
| 2241 | gstring = Fmake_vector (make_number (len), Qnil); | ||
| 2242 | g = Fmake_vector (make_number (6), Qnil); | ||
| 2243 | ASET (g, 0, font_object); | ||
| 2244 | ASET (gstring, 0, g); | ||
| 2245 | for (i = 1; i < len; i++) | ||
| 2246 | ASET (gstring, i, Fmake_vector (make_number (8), make_number (0))); | ||
| 2247 | return gstring; | ||
| 2248 | } | ||
| 2249 | |||
| 2250 | DEFUN ("font-fill-gstring", Ffont_fill_gstring, Sfont_fill_gstring, 4, 5, 0, | ||
| 2251 | doc: /* Fillin glyph-string GSTRING by characters for FONT-OBJECT. | ||
| 2252 | START and END specifies the region to extract characters. | ||
| 2253 | If optional 3rd argument OBJECT is non-nil, it is a buffer or a string from | ||
| 2254 | where to extract characters. | ||
| 2255 | FONT-OBJECT may be nil if GSTRING already already contains one. */) | ||
| 2256 | (gstring, font_object, start, end, object) | ||
| 2257 | Lisp_Object gstring, font_object, start, end, object; | ||
| 2258 | { | ||
| 2259 | int len, i, c; | ||
| 2260 | unsigned code; | ||
| 2261 | struct font *font; | ||
| 2262 | |||
| 2263 | CHECK_VECTOR (gstring); | ||
| 2264 | if (NILP (font_object)) | ||
| 2265 | font_object = Faref (Faref (gstring, make_number (0)), make_number (0)); | ||
| 2266 | CHECK_FONT_GET_OBJECT (font_object, font); | ||
| 2267 | |||
| 2268 | if (STRINGP (object)) | ||
| 2269 | { | ||
| 2270 | const unsigned char *p; | ||
| 2271 | |||
| 2272 | CHECK_NATNUM (start); | ||
| 2273 | CHECK_NATNUM (end); | ||
| 2274 | if (XINT (start) > XINT (end) | ||
| 2275 | || XINT (end) > ASIZE (object) | ||
| 2276 | || XINT (end) - XINT (start) >= XINT (Flength (gstring))) | ||
| 2277 | args_out_of_range (start, end); | ||
| 2278 | |||
| 2279 | len = XINT (end) - XINT (start); | ||
| 2280 | p = SDATA (object) + string_char_to_byte (object, XINT (start)); | ||
| 2281 | for (i = 0; i < len; i++) | ||
| 2282 | { | ||
| 2283 | Lisp_Object g = LGSTRING_GLYPH (gstring, i); | ||
| 2284 | |||
| 2285 | c = STRING_CHAR_ADVANCE (p); | ||
| 2286 | code = font->driver->encode_char (font, c); | ||
| 2287 | if (code > MOST_POSITIVE_FIXNUM) | ||
| 2288 | error ("Glyph code 0x%X is too large", code); | ||
| 2289 | ASET (g, 0, make_number (i)); | ||
| 2290 | ASET (g, 1, make_number (i + 1)); | ||
| 2291 | LGLYPH_SET_CHAR (g, make_number (c)); | ||
| 2292 | LGLYPH_SET_CODE (g, make_number (code)); | ||
| 2293 | } | ||
| 2294 | } | ||
| 2295 | else | ||
| 2296 | { | ||
| 2297 | int pos, pos_byte; | ||
| 2298 | |||
| 2299 | if (! NILP (object)) | ||
| 2300 | Fset_buffer (object); | ||
| 2301 | validate_region (&start, &end); | ||
| 2302 | if (XINT (end) - XINT (start) > len) | ||
| 2303 | args_out_of_range (start, end); | ||
| 2304 | len = XINT (end) - XINT (start); | ||
| 2305 | pos = XINT (start); | ||
| 2306 | pos_byte = CHAR_TO_BYTE (pos); | ||
| 2307 | for (i = 0; i < len; i++) | ||
| 2308 | { | ||
| 2309 | Lisp_Object g = LGSTRING_GLYPH (gstring, i); | ||
| 2310 | |||
| 2311 | FETCH_CHAR_ADVANCE (c, pos, pos_byte); | ||
| 2312 | code = font->driver->encode_char (font, c); | ||
| 2313 | if (code > MOST_POSITIVE_FIXNUM) | ||
| 2314 | error ("Glyph code 0x%X is too large", code); | ||
| 2315 | ASET (g, 0, make_number (i)); | ||
| 2316 | ASET (g, 1, make_number (i + 1)); | ||
| 2317 | LGLYPH_SET_CHAR (g, make_number (c)); | ||
| 2318 | LGLYPH_SET_CODE (g, make_number (code)); | ||
| 2319 | } | ||
| 2320 | } | ||
| 2321 | return Qnil; | ||
| 2322 | } | ||
| 2323 | |||
| 2324 | |||
| 2325 | #ifdef FONT_DEBUG | ||
| 2326 | |||
| 2327 | DEFUN ("open-font", Fopen_font, Sopen_font, 1, 3, 0, | ||
| 2328 | doc: /* Open FONT-ENTITY. */) | ||
| 2329 | (font_entity, size, frame) | ||
| 2330 | Lisp_Object font_entity; | ||
| 2331 | Lisp_Object size; | ||
| 2332 | Lisp_Object frame; | ||
| 2333 | { | ||
| 2334 | int isize; | ||
| 2335 | |||
| 2336 | CHECK_FONT_ENTITY (font_entity); | ||
| 2337 | if (NILP (size)) | ||
| 2338 | size = AREF (font_entity, FONT_SIZE_INDEX); | ||
| 2339 | CHECK_NUMBER (size); | ||
| 2340 | if (NILP (frame)) | ||
| 2341 | frame = selected_frame; | ||
| 2342 | CHECK_LIVE_FRAME (frame); | ||
| 2343 | |||
| 2344 | isize = XINT (size); | ||
| 2345 | if (isize < 0) | ||
| 2346 | isize = POINT_TO_PIXEL (- isize, XFRAME (frame)->resy); | ||
| 2347 | |||
| 2348 | return font_open_entity (XFRAME (frame), font_entity, isize); | ||
| 2349 | } | ||
| 2350 | |||
| 2351 | DEFUN ("close-font", Fclose_font, Sclose_font, 1, 2, 0, | ||
| 2352 | doc: /* Close FONT-OBJECT. */) | ||
| 2353 | (font_object, frame) | ||
| 2354 | Lisp_Object font_object, frame; | ||
| 2355 | { | ||
| 2356 | CHECK_FONT_OBJECT (font_object); | ||
| 2357 | if (NILP (frame)) | ||
| 2358 | frame = selected_frame; | ||
| 2359 | CHECK_LIVE_FRAME (frame); | ||
| 2360 | font_close_object (XFRAME (frame), font_object); | ||
| 2361 | return Qnil; | ||
| 2362 | } | ||
| 2363 | |||
| 2364 | DEFUN ("query-font", Fquery_font, Squery_font, 1, 1, 0, | ||
| 2365 | doc: /* Return information about FONT-OBJECT. */) | ||
| 2366 | (font_object) | ||
| 2367 | Lisp_Object font_object; | ||
| 2368 | { | ||
| 2369 | struct font *font; | ||
| 2370 | Lisp_Object val; | ||
| 2371 | |||
| 2372 | CHECK_FONT_GET_OBJECT (font_object, font); | ||
| 2373 | |||
| 2374 | val = Fmake_vector (make_number (9), Qnil); | ||
| 2375 | ASET (val, 0, Ffont_xlfd_name (font_object)); | ||
| 2376 | if (font->file_name) | ||
| 2377 | ASET (val, 1, make_unibyte_string (font->file_name, | ||
| 2378 | strlen (font->file_name))); | ||
| 2379 | ASET (val, 2, make_number (font->pixel_size)); | ||
| 2380 | ASET (val, 3, make_number (font->font.size)); | ||
| 2381 | ASET (val, 4, make_number (font->ascent)); | ||
| 2382 | ASET (val, 5, make_number (font->descent)); | ||
| 2383 | ASET (val, 6, make_number (font->font.space_width)); | ||
| 2384 | ASET (val, 7, make_number (font->font.average_width)); | ||
| 2385 | if (font->driver->otf_capability) | ||
| 2386 | ASET (val, 8, font->driver->otf_capability (font)); | ||
| 2387 | return val; | ||
| 2388 | } | ||
| 2389 | |||
| 2390 | DEFUN ("get-font-glyphs", Fget_font_glyphs, Sget_font_glyphs, 2, 2, 0, | ||
| 2391 | doc: /* Return a vector of glyphs of FONT-OBJECT for drawing STRING. | ||
| 2392 | Each element is a vector [GLYPH-CODE LBEARING RBEARING WIDTH ASCENT DESCENT]. */) | ||
| 2393 | (font_object, string) | ||
| 2394 | Lisp_Object font_object, string; | ||
| 2395 | { | ||
| 2396 | struct font *font; | ||
| 2397 | int i, len; | ||
| 2398 | Lisp_Object vec; | ||
| 2399 | |||
| 2400 | CHECK_FONT_GET_OBJECT (font_object, font); | ||
| 2401 | CHECK_STRING (string); | ||
| 2402 | len = SCHARS (string); | ||
| 2403 | vec = Fmake_vector (make_number (len), Qnil); | ||
| 2404 | for (i = 0; i < len; i++) | ||
| 2405 | { | ||
| 2406 | Lisp_Object ch = Faref (string, make_number (i)); | ||
| 2407 | Lisp_Object val; | ||
| 2408 | int c = XINT (ch); | ||
| 2409 | unsigned code; | ||
| 2410 | struct font_metrics metrics; | ||
| 2411 | |||
| 2412 | code = font->driver->encode_char (font, c); | ||
| 2413 | if (code == FONT_INVALID_CODE) | ||
| 2414 | continue; | ||
| 2415 | val = Fmake_vector (make_number (6), Qnil); | ||
| 2416 | if (code <= MOST_POSITIVE_FIXNUM) | ||
| 2417 | ASET (val, 0, make_number (code)); | ||
| 2418 | else | ||
| 2419 | ASET (val, 0, Fcons (make_number (code >> 16), | ||
| 2420 | make_number (code & 0xFFFF))); | ||
| 2421 | font->driver->text_extents (font, &code, 1, &metrics); | ||
| 2422 | ASET (val, 1, make_number (metrics.lbearing)); | ||
| 2423 | ASET (val, 2, make_number (metrics.rbearing)); | ||
| 2424 | ASET (val, 3, make_number (metrics.width)); | ||
| 2425 | ASET (val, 4, make_number (metrics.ascent)); | ||
| 2426 | ASET (val, 5, make_number (metrics.descent)); | ||
| 2427 | ASET (vec, i, val); | ||
| 2428 | } | ||
| 2429 | return vec; | ||
| 2430 | } | ||
| 2431 | |||
| 2432 | #if 0 | ||
| 2433 | DEFUN ("draw-string", Fdraw_string, Sdraw_string, 2, 2, 0, | ||
| 2434 | doc: /* Draw STRING by FONT-OBJECT on the top left corner of the current frame. | ||
| 2435 | The value is a number of glyphs drawn. | ||
| 2436 | Type C-l to recover what previously shown. */) | ||
| 2437 | (font_object, string) | ||
| 2438 | Lisp_Object font_object, string; | ||
| 2439 | { | ||
| 2440 | Lisp_Object frame = selected_frame; | ||
| 2441 | FRAME_PTR f = XFRAME (frame); | ||
| 2442 | struct font *font; | ||
| 2443 | struct face *face; | ||
| 2444 | int i, len, width; | ||
| 2445 | unsigned *code; | ||
| 2446 | |||
| 2447 | CHECK_FONT_GET_OBJECT (font_object, font); | ||
| 2448 | CHECK_STRING (string); | ||
| 2449 | len = SCHARS (string); | ||
| 2450 | code = alloca (sizeof (unsigned) * len); | ||
| 2451 | for (i = 0; i < len; i++) | ||
| 2452 | { | ||
| 2453 | Lisp_Object ch = Faref (string, make_number (i)); | ||
| 2454 | Lisp_Object val; | ||
| 2455 | int c = XINT (ch); | ||
| 2456 | |||
| 2457 | code[i] = font->driver->encode_char (font, c); | ||
| 2458 | if (code[i] == FONT_INVALID_CODE) | ||
| 2459 | break; | ||
| 2460 | } | ||
| 2461 | face = FACE_FROM_ID (f, DEFAULT_FACE_ID); | ||
| 2462 | face->fontp = font; | ||
| 2463 | if (font->driver->prepare_face) | ||
| 2464 | font->driver->prepare_face (f, face); | ||
| 2465 | width = font->driver->text_extents (font, code, i, NULL); | ||
| 2466 | len = font->driver->draw_text (f, face, 0, font->ascent, code, i, width); | ||
| 2467 | if (font->driver->done_face) | ||
| 2468 | font->driver->done_face (f, face); | ||
| 2469 | face->fontp = NULL; | ||
| 2470 | return make_number (len); | ||
| 2471 | } | ||
| 2472 | #endif | ||
| 2473 | |||
| 2474 | #endif /* FONT_DEBUG */ | ||
| 2475 | |||
| 2476 | |||
| 2477 | extern void syms_of_ftfont P_ (()); | ||
| 2478 | extern void syms_of_xfont P_ (()); | ||
| 2479 | extern void syms_of_xftfont P_ (()); | ||
| 2480 | extern void syms_of_ftxfont P_ (()); | ||
| 2481 | extern void syms_of_bdffont P_ (()); | ||
| 2482 | extern void syms_of_w32font P_ (()); | ||
| 2483 | extern void syms_of_atmfont P_ (()); | ||
| 2484 | |||
| 2485 | void | ||
| 2486 | syms_of_font () | ||
| 2487 | { | ||
| 2488 | sort_shift_bits[FONT_SLANT_INDEX] = 0; | ||
| 2489 | sort_shift_bits[FONT_WEIGHT_INDEX] = 7; | ||
| 2490 | sort_shift_bits[FONT_SIZE_INDEX] = 14; | ||
| 2491 | sort_shift_bits[FONT_WIDTH_INDEX] = 21; | ||
| 2492 | sort_shift_bits[FONT_ADSTYLE_INDEX] = 28; | ||
| 2493 | sort_shift_bits[FONT_FOUNDRY_INDEX] = 29; | ||
| 2494 | sort_shift_bits[FONT_FAMILY_INDEX] = 30; | ||
| 2495 | sort_shift_bits[FONT_REGISTRY_INDEX] = 31; | ||
| 2496 | /* Note that sort_shift_bits[FONT_SLANT_TYPE] is never used. */ | ||
| 2497 | |||
| 2498 | staticpro (&font_style_table); | ||
| 2499 | font_style_table = Fmake_vector (make_number (3), Qnil); | ||
| 2500 | |||
| 2501 | staticpro (&font_family_alist); | ||
| 2502 | font_family_alist = Qnil; | ||
| 2503 | |||
| 2504 | DEFSYM (Qfontp, "fontp"); | ||
| 2505 | |||
| 2506 | DEFSYM (QCotf, ":otf"); | ||
| 2507 | DEFSYM (QClanguage, ":language"); | ||
| 2508 | DEFSYM (QCscript, ":script"); | ||
| 2509 | |||
| 2510 | DEFSYM (QCfoundry, ":foundry"); | ||
| 2511 | DEFSYM (QCadstyle, ":adstyle"); | ||
| 2512 | DEFSYM (QCregistry, ":registry"); | ||
| 2513 | DEFSYM (QCextra, ":extra"); | ||
| 2514 | |||
| 2515 | staticpro (&null_string); | ||
| 2516 | null_string = build_string (""); | ||
| 2517 | staticpro (&null_vector); | ||
| 2518 | null_vector = Fmake_vector (make_number (0), Qnil); | ||
| 2519 | |||
| 2520 | staticpro (&scratch_font_spec); | ||
| 2521 | scratch_font_spec = Ffont_spec (0, NULL); | ||
| 2522 | staticpro (&scratch_font_prefer); | ||
| 2523 | scratch_font_prefer = Ffont_spec (0, NULL); | ||
| 2524 | |||
| 2525 | defsubr (&Sfontp); | ||
| 2526 | defsubr (&Sfont_spec); | ||
| 2527 | defsubr (&Sfont_get); | ||
| 2528 | defsubr (&Sfont_put); | ||
| 2529 | defsubr (&Slist_fonts); | ||
| 2530 | defsubr (&Slist_families); | ||
| 2531 | defsubr (&Sfind_font); | ||
| 2532 | defsubr (&Sfont_xlfd_name); | ||
| 2533 | defsubr (&Sclear_font_cache); | ||
| 2534 | defsubr (&Sinternal_set_font_style_table); | ||
| 2535 | defsubr (&Sfont_make_gstring); | ||
| 2536 | defsubr (&Sfont_fill_gstring); | ||
| 2537 | |||
| 2538 | #ifdef FONT_DEBUG | ||
| 2539 | defsubr (&Sopen_font); | ||
| 2540 | defsubr (&Sclose_font); | ||
| 2541 | defsubr (&Squery_font); | ||
| 2542 | defsubr (&Sget_font_glyphs); | ||
| 2543 | #if 0 | ||
| 2544 | defsubr (&Sdraw_string); | ||
| 2545 | #endif | ||
| 2546 | #endif /* FONT_DEBUG */ | ||
| 2547 | |||
| 2548 | #ifdef HAVE_FREETYPE | ||
| 2549 | syms_of_ftfont (); | ||
| 2550 | #ifdef HAVE_X_WINDOWS | ||
| 2551 | syms_of_xfont (); | ||
| 2552 | syms_of_ftxfont (); | ||
| 2553 | #ifdef HAVE_XFT | ||
| 2554 | syms_of_xftfont (); | ||
| 2555 | #endif /* HAVE_XFT */ | ||
| 2556 | #endif /* HAVE_X_WINDOWS */ | ||
| 2557 | #else /* not HAVE_FREETYPE */ | ||
| 2558 | #ifdef HAVE_X_WINDOWS | ||
| 2559 | syms_of_xfont (); | ||
| 2560 | #endif /* HAVE_X_WINDOWS */ | ||
| 2561 | #endif /* not HAVE_FREETYPE */ | ||
| 2562 | #ifdef HAVE_BDFFONT | ||
| 2563 | syms_of_bdffont (); | ||
| 2564 | #endif /* HAVE_BDFFONT */ | ||
| 2565 | #ifdef WINDOWSNT | ||
| 2566 | syms_of_w32font (); | ||
| 2567 | #endif /* WINDOWSNT */ | ||
| 2568 | #ifdef MAC_OS | ||
| 2569 | syms_of_atmfont (); | ||
| 2570 | #endif /* MAC_OS */ | ||
| 2571 | } | ||
diff --git a/src/font.h b/src/font.h new file mode 100644 index 00000000000..3af90f5ddc8 --- /dev/null +++ b/src/font.h | |||
| @@ -0,0 +1,479 @@ | |||
| 1 | /* font.h -- Interface definition for font handling. | ||
| 2 | Copyright (C) 2006 Free Software Foundation, Inc. | ||
| 3 | Copyright (C) 2006 | ||
| 4 | National Institute of Advanced Industrial Science and Technology (AIST) | ||
| 5 | Registration Number H13PRO009 | ||
| 6 | |||
| 7 | This file is part of GNU Emacs. | ||
| 8 | |||
| 9 | GNU Emacs is free software; you can redistribute it and/or modify | ||
| 10 | it under the terms of the GNU General Public License as published by | ||
| 11 | the Free Software Foundation; either version 2, or (at your option) | ||
| 12 | any later version. | ||
| 13 | |||
| 14 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 17 | GNU General Public License for more details. | ||
| 18 | |||
| 19 | You should have received a copy of the GNU General Public License | ||
| 20 | along with GNU Emacs; see the file COPYING. If not, write to | ||
| 21 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
| 22 | Boston, MA 02110-1301, USA. */ | ||
| 23 | |||
| 24 | #ifndef EMACS_FONT_H | ||
| 25 | #define EMACS_FONT_H | ||
| 26 | |||
| 27 | #include "ccl.h" | ||
| 28 | |||
| 29 | /* We have three types of Lisp objects related to font. | ||
| 30 | |||
| 31 | FONT-SPEC | ||
| 32 | |||
| 33 | Vector (length FONT_SPEC_MAX) of font properties. Some | ||
| 34 | properties can be left unspecified (i.e. nil). Emacs asks | ||
| 35 | font-drivers to find a font by FONT-SPEC. A fontset entry | ||
| 36 | specifies requisite properties whereas a face specifies just | ||
| 37 | preferable properties. This object is fully modifiable by | ||
| 38 | Lisp. | ||
| 39 | |||
| 40 | FONT-ENTITY | ||
| 41 | |||
| 42 | Vector (length FONT_ENTITY_MAX) of fully specified font | ||
| 43 | properties that a font-driver returns upon a request of | ||
| 44 | FONT-SPEC. | ||
| 45 | |||
| 46 | Note: Only the method `list' of a font-driver can create this | ||
| 47 | object, and should never be modified by Lisp. In that sense, | ||
| 48 | it may be cleaner to implement it as a Lisp object of a new | ||
| 49 | type (e.g. struct Lisp_Font). | ||
| 50 | |||
| 51 | FONT-OBJECT | ||
| 52 | |||
| 53 | Lisp object of type Lisp_Misc_Save_Value encapsulating a | ||
| 54 | pointer to "struct font". This corresponds to an opened font. | ||
| 55 | |||
| 56 | Note: The note for FONT-ENTITY also applies to this. | ||
| 57 | */ | ||
| 58 | |||
| 59 | |||
| 60 | struct font_driver; | ||
| 61 | struct font; | ||
| 62 | |||
| 63 | /* An enumerator for each font property. This is used as an index to | ||
| 64 | the vector of FONT-SPEC and FONT-ENTITY. | ||
| 65 | |||
| 66 | Note: The order is important and should not be changed. */ | ||
| 67 | |||
| 68 | enum font_property_index | ||
| 69 | { | ||
| 70 | /* FONT-TYPE is a symbol indicating a font backend; currently `x', | ||
| 71 | `xft', `ftx', `freetype' are available. For windows, we need | ||
| 72 | `bdf' and `windows'. For Mac OS X, we need `atm'. */ | ||
| 73 | FONT_TYPE_INDEX, | ||
| 74 | |||
| 75 | /* FONT-FOUNDRY is a foundry name (symbol). */ | ||
| 76 | FONT_FOUNDRY_INDEX, | ||
| 77 | |||
| 78 | /* FONT-FAMILY is a family name (symbol). */ | ||
| 79 | FONT_FAMILY_INDEX, | ||
| 80 | |||
| 81 | /* FONT-ADSTYLE is an additional style name (symbol). */ | ||
| 82 | FONT_ADSTYLE_INDEX, | ||
| 83 | |||
| 84 | /* FONT-REGISTRY is a combination of a charset-registry and | ||
| 85 | charset0encoding name (symbol). */ | ||
| 86 | FONT_REGISTRY_INDEX, | ||
| 87 | |||
| 88 | /* FONT-WEIGHT is a numeric value of weight (e.g. medium, bold) of | ||
| 89 | the font. The value is what defined by FC_WEIGHT_* in | ||
| 90 | fontconfig. */ | ||
| 91 | FONT_WEIGHT_INDEX, | ||
| 92 | |||
| 93 | /* FONT-SLANT is a numeric value of slant (e.g. r, i, o) of the | ||
| 94 | font. The value is what defined by FC_SLANT_* in | ||
| 95 | fontconfig plus 100. */ | ||
| 96 | FONT_SLANT_INDEX, | ||
| 97 | |||
| 98 | /* FONT-WIDTH is a numeric value of setwidth (e.g. normal, | ||
| 99 | condensed) of the font. The value is what defined by | ||
| 100 | FC_WIDTH_* in fontconfig. */ | ||
| 101 | FONT_WIDTH_INDEX, | ||
| 102 | |||
| 103 | /* FONT-SIZE is a size of the font. If integer, it is a pixel | ||
| 104 | size. For a font-spec, the value can be float specifying a | ||
| 105 | point size. For a font-entity, the value can be zero meaning | ||
| 106 | that the font is scalable. */ | ||
| 107 | FONT_SIZE_INDEX, | ||
| 108 | |||
| 109 | /* In a font-spec, the value is an alist of extra information of a | ||
| 110 | font such as name, OpenType features, and language coverage. | ||
| 111 | In a font-entity, the value is an extra infomation for | ||
| 112 | identifying a font (font-driver dependent). */ | ||
| 113 | FONT_EXTRA_INDEX, /* alist alist */ | ||
| 114 | |||
| 115 | /* This value is the length of font-spec vector. */ | ||
| 116 | FONT_SPEC_MAX, | ||
| 117 | |||
| 118 | /* The followings are used only for a font-entity. */ | ||
| 119 | |||
| 120 | /* Frame on which the font is found. The value is nil if the font | ||
| 121 | can be opend on any frame. */ | ||
| 122 | FONT_FRAME_INDEX = FONT_SPEC_MAX, | ||
| 123 | |||
| 124 | /* List of font-objects opened from the font-entity. */ | ||
| 125 | FONT_OBJLIST_INDEX, | ||
| 126 | |||
| 127 | /* This value is the length of font-entity vector. */ | ||
| 128 | FONT_ENTITY_MAX | ||
| 129 | }; | ||
| 130 | |||
| 131 | extern Lisp_Object QCotf, QClanguage, QCscript; | ||
| 132 | |||
| 133 | extern Lisp_Object null_string; | ||
| 134 | extern Lisp_Object null_vector; | ||
| 135 | |||
| 136 | /* Structure for an opened font. We can safely cast this structure to | ||
| 137 | "struft font_info". */ | ||
| 138 | |||
| 139 | struct font | ||
| 140 | { | ||
| 141 | struct font_info font; | ||
| 142 | |||
| 143 | /* From which font-entity the font is opened. */ | ||
| 144 | Lisp_Object entity; | ||
| 145 | |||
| 146 | /* By which pixel size the font is opened. */ | ||
| 147 | int pixel_size; | ||
| 148 | |||
| 149 | /* Font-driver for the font. */ | ||
| 150 | struct font_driver *driver; | ||
| 151 | |||
| 152 | /* File name of the font, or NULL if the font is not associated with | ||
| 153 | a file. */ | ||
| 154 | char *file_name; | ||
| 155 | |||
| 156 | /* Charset to encode a character code into a glyph code of the | ||
| 157 | font. */ | ||
| 158 | int encoding_charset; | ||
| 159 | |||
| 160 | /* Charset to check if a character code is supported by the font. | ||
| 161 | -1 means that the contents of the font must be looked up to | ||
| 162 | determine it. | ||
| 163 | */ | ||
| 164 | int repertory_charet; | ||
| 165 | |||
| 166 | /* Minimum glyph width (in pixels). */ | ||
| 167 | int min_width; | ||
| 168 | |||
| 169 | /* Ascent and descent of the font (in pixels). */ | ||
| 170 | int ascent, descent; | ||
| 171 | |||
| 172 | /* There will be more to this structure, but they are private to a | ||
| 173 | font-driver. */ | ||
| 174 | }; | ||
| 175 | |||
| 176 | struct font_metrics | ||
| 177 | { | ||
| 178 | short lbearing, rbearing, width, ascent, descent; | ||
| 179 | }; | ||
| 180 | |||
| 181 | struct font_bitmap | ||
| 182 | { | ||
| 183 | int rows; | ||
| 184 | int width; | ||
| 185 | int pitch; | ||
| 186 | unsigned char *buffer; | ||
| 187 | int left; | ||
| 188 | int top; | ||
| 189 | int advance; | ||
| 190 | void *extra; | ||
| 191 | }; | ||
| 192 | |||
| 193 | /* Predicates to check various font-related objects. */ | ||
| 194 | |||
| 195 | #define FONTP(x) \ | ||
| 196 | (VECTORP (x) && (ASIZE (x) == FONT_SPEC_MAX || ASIZE (x) == FONT_ENTITY_MAX)) | ||
| 197 | #define FONT_SPEC_P(x) \ | ||
| 198 | (VECTORP (x) && ASIZE (x) == FONT_SPEC_MAX) | ||
| 199 | #define FONT_ENTITY_P(x) \ | ||
| 200 | (VECTORP (x) && ASIZE (x) == FONT_ENTITY_MAX) | ||
| 201 | #define FONT_OBJECT_P(x) \ | ||
| 202 | (XTYPE (x) == Lisp_Misc && XMISCTYPE (x) == Lisp_Misc_Save_Value) | ||
| 203 | |||
| 204 | |||
| 205 | /* Check macros for various font-related objects. */ | ||
| 206 | |||
| 207 | #define CHECK_FONT(x) \ | ||
| 208 | do { if (! FONTP (x)) x = wrong_type_argument (Qfont, x); } while (0) | ||
| 209 | #define CHECK_FONT_SPEC(x) \ | ||
| 210 | do { if (! FONT_SPEC_P (x)) x = wrong_type_argument (Qfont, x); } while (0) | ||
| 211 | #define CHECK_FONT_ENTITY(x) \ | ||
| 212 | do { if (! FONT_ENTITY_P (x)) x = wrong_type_argument (Qfont, x); } while (0) | ||
| 213 | #define CHECK_FONT_OBJECT(x) \ | ||
| 214 | do { if (! FONT_OBJECT_P (x)) x = wrong_type_argument (Qfont, x); } while (0) | ||
| 215 | |||
| 216 | #define CHECK_FONT_GET_OBJECT(x, font) \ | ||
| 217 | do { \ | ||
| 218 | if (! FONT_OBJECT_P (x)) x = wrong_type_argument (Qfont, x); \ | ||
| 219 | if (! XSAVE_VALUE (x)->pointer) error ("Font already closed"); \ | ||
| 220 | font = XSAVE_VALUE (x)->pointer; \ | ||
| 221 | } while (0) | ||
| 222 | |||
| 223 | struct face; | ||
| 224 | struct composition; | ||
| 225 | |||
| 226 | /* Macros for lispy glyph-string. */ | ||
| 227 | #define LGSTRING_FONT(lgs) AREF (AREF ((lgs), 0), 0) | ||
| 228 | #define LGSTRING_LBEARING(lgs) AREF (AREF ((lgs), 0), 1) | ||
| 229 | #define LGSTRING_RBEARING(lgs) AREF (AREF ((lgs), 0), 2) | ||
| 230 | #define LGSTRING_WIDTH(lgs) AREF (AREF ((lgs), 0), 3) | ||
| 231 | #define LGSTRING_ASCENT(lgs) AREF (AREF ((lgs), 0), 4) | ||
| 232 | #define LGSTRING_DESCENT(lgs) AREF (AREF ((lgs), 0), 5) | ||
| 233 | #define LGSTRING_SET_FONT(lgs, val) ASET (AREF ((lgs), 0), 0, (val)) | ||
| 234 | #define LGSTRING_SET_LBEARING(lgs, val) ASET (AREF ((lgs), 0), 1, (val)) | ||
| 235 | #define LGSTRING_SET_RBEARING(lgs, val) ASET (AREF ((lgs), 0), 2, (val)) | ||
| 236 | #define LGSTRING_SET_WIDTH(lgs, val) ASET (AREF ((lgs), 0), 3, (val)) | ||
| 237 | #define LGSTRING_SET_ASCENT(lgs, val) ASET (AREF ((lgs), 0), 4, (val)) | ||
| 238 | #define LGSTRING_SET_DESCENT(lgs, val) ASET (AREF ((lgs), 0), 5, (val)) | ||
| 239 | |||
| 240 | #define LGSTRING_LENGTH(lgs) (ASIZE ((lgs)) - 1) | ||
| 241 | #define LGSTRING_GLYPH(lgs, idx) AREF ((lgs), (idx) + 1) | ||
| 242 | |||
| 243 | #define LGLYPH_CHAR(g) AREF ((g), 2) | ||
| 244 | #define LGLYPH_CODE(g) AREF ((g), 3) | ||
| 245 | #define LGLYPH_XOFF(g) AREF ((g), 4) | ||
| 246 | #define LGLYPH_YOFF(g) AREF ((g), 5) | ||
| 247 | #define LGLYPH_WIDTH(g) AREF ((g), 6) | ||
| 248 | #define LGLYPH_WADJUST(g) AREF ((g), 7) | ||
| 249 | #define LGLYPH_SET_CHAR(g, val) ASET ((g), 2, (val)) | ||
| 250 | #define LGLYPH_SET_CODE(g, val) ASET ((g), 3, (val)) | ||
| 251 | #define LGLYPH_SET_XOFF(g, val) ASET ((g), 4, (val)) | ||
| 252 | #define LGLYPH_SET_YOFF(g, val) ASET ((g), 5, (val)) | ||
| 253 | #define LGLYPH_SET_WIDTH(g, val) ASET ((g), 6, (val)) | ||
| 254 | #define LGLYPH_SET_WADJUST(g, val) ASET ((g), 7, (val)) | ||
| 255 | |||
| 256 | #define FONT_INVALID_CODE 0xFFFFFFFF | ||
| 257 | |||
| 258 | struct font_driver | ||
| 259 | { | ||
| 260 | /* Symbol indicating the type of the font-driver. */ | ||
| 261 | Lisp_Object type; | ||
| 262 | |||
| 263 | /* Return a cache of font-entities on FRAME. The cache must be a | ||
| 264 | cons whose cdr part is the actual cache area. */ | ||
| 265 | Lisp_Object (*get_cache) P_ ((Lisp_Object frame)); | ||
| 266 | |||
| 267 | /* Parse font name NAME, store the font properties in SPEC, and | ||
| 268 | return 0. If the font-driver can't parse NAME, return -1. */ | ||
| 269 | int (*parse_name) P_ ((FRAME_PTR f, char *name, Lisp_Object spec)); | ||
| 270 | |||
| 271 | /* List fonts matching with FONT_SPEC on FRAME. The value is a | ||
| 272 | vector of font-entities. This is the sole API that allocates | ||
| 273 | font-entities. */ | ||
| 274 | Lisp_Object (*list) P_ ((Lisp_Object frame, Lisp_Object font_spec)); | ||
| 275 | |||
| 276 | /* List available families. The value is a list of family names | ||
| 277 | (symbols). The method can be NULL if the driver doesn't support | ||
| 278 | this facility. */ | ||
| 279 | Lisp_Object (*list_family) P_ ((Lisp_Object frame)); | ||
| 280 | |||
| 281 | /* Free FONT_EXTRA_INDEX field of FONT_ENTITY. This method can be | ||
| 282 | NULL if FONT_EXTRA_INDEX of FONT_ENTITY is a normal Lisp object | ||
| 283 | (i.e. not Lisp_Save_Value). */ | ||
| 284 | void (*free_entity) P_ ((Lisp_Object font_entity)); | ||
| 285 | |||
| 286 | /* Open a font specified by FONT_ENTITY on frame F. If the font is | ||
| 287 | scalable, open it with PIXEL_SIZE. */ | ||
| 288 | struct font *(*open) P_ ((FRAME_PTR f, Lisp_Object font_entity, | ||
| 289 | int pixel_size)); | ||
| 290 | |||
| 291 | /* Close FONT on frame F. */ | ||
| 292 | void (*close) P_ ((FRAME_PTR f, struct font *font)); | ||
| 293 | |||
| 294 | /* Prepare FACE for displaying characters by FONT on frame F. If | ||
| 295 | successful, return 0. Otherwise, return -1. This method can be | ||
| 296 | NULL if there's nothing to do. */ | ||
| 297 | int (*prepare_face) P_ ((FRAME_PTR f, struct face *face)); | ||
| 298 | |||
| 299 | /* Done FACE for displaying characters by FACE->font on frame F. | ||
| 300 | This method can be NULL if there's nothing to do. */ | ||
| 301 | void (*done_face) P_ ((FRAME_PTR f, struct face *face)); | ||
| 302 | |||
| 303 | /* If FONT_ENTITY has a glyph for character C, return 1. If not, | ||
| 304 | return 0. If a font must be opened to check it, return -1. This | ||
| 305 | method can be NULL if the driver always requires a font to be | ||
| 306 | opened for this check. In that case, we must open a font and use | ||
| 307 | `encode_char' method. */ | ||
| 308 | int (*has_char) P_ ((Lisp_Object entity, int c)); | ||
| 309 | |||
| 310 | /* Return a glyph code of FONT for characer C. If FONT doesn't have | ||
| 311 | such a glyph, return FONT_INVALID_CODE. */ | ||
| 312 | unsigned (*encode_char) P_ ((struct font *font, int c)); | ||
| 313 | |||
| 314 | /* Perform the size computation of glyphs of FONT and fillin members | ||
| 315 | of METRICS. The glyphs are specified by their glyph codes in | ||
| 316 | CODE (length NGLYPHS). */ | ||
| 317 | int (*text_extents) P_ ((struct font *font, | ||
| 318 | unsigned *code, int nglyphs, | ||
| 319 | struct font_metrics *metrics)); | ||
| 320 | |||
| 321 | /* Draw glyphs between FROM and TO of S->char2b at (X Y) pixel | ||
| 322 | position of frame F with S->FACE and S->GC. If WITH_BACKGROUND | ||
| 323 | is nonzero, fill the background in advance. It is assured that | ||
| 324 | WITH_BACKGROUND is zero when (FROM > 0 || TO < S->nchars). */ | ||
| 325 | int (*draw) P_ ((struct glyph_string *s, int from, int to, | ||
| 326 | int x, int y, int with_background)); | ||
| 327 | |||
| 328 | /* Store bitmap data for glyph-code CODE of FONT in BITMAP. This | ||
| 329 | method can be NULL if the driver doesn't support this facility. | ||
| 330 | It is intended that this method is callled from the other | ||
| 331 | font-driver for actual drawing. */ | ||
| 332 | int (*get_bitmap) P_ ((struct font *font, unsigned code, | ||
| 333 | struct font_bitmap *bitmap, | ||
| 334 | int bits_per_pixel)); | ||
| 335 | |||
| 336 | /* Free bitmap data in BITMAP. This method can be NULL if no data | ||
| 337 | have to be freed. */ | ||
| 338 | void (*free_bitmap) P_ ((struct font *font, struct font_bitmap *bitmap)); | ||
| 339 | |||
| 340 | /* Return an outline data for glyph-code CODE of FONT. The format | ||
| 341 | of the outline data depends on the font-driver. This method can | ||
| 342 | be NULL if the driver doesn't support this facility. */ | ||
| 343 | void *(*get_outline) P_ ((struct font *font, unsigned code)); | ||
| 344 | |||
| 345 | /* Free OUTLINE (that is obtained by the above method). */ | ||
| 346 | void (*free_outline) P_ ((struct font *font, void *outline)); | ||
| 347 | |||
| 348 | /* Get coordinates of the INDEXth anchor point of the glyph whose | ||
| 349 | code is CODE. Store the coordinates in *X and *Y. Return 0 if | ||
| 350 | the operations was successfull. Otherwise return -1. This | ||
| 351 | method can be NULL if the driver doesn't support this | ||
| 352 | facility. */ | ||
| 353 | int (*anchor_point) P_ ((struct font *font, unsigned code, int index, | ||
| 354 | int *x, int *y)); | ||
| 355 | |||
| 356 | /* Return a list describing which scripts/languages FONT | ||
| 357 | supports by which GSUB/GPOS features of OpenType tables. */ | ||
| 358 | Lisp_Object (*otf_capability) P_ ((struct font *font)); | ||
| 359 | |||
| 360 | /* Drive FONT's OTF GSUB features according to GSUB_SPEC. | ||
| 361 | |||
| 362 | GSUB_SPEC is in this format (all elements are symbols): | ||
| 363 | (SCRIPT LANGSYS GSUB-FEATURE ...) | ||
| 364 | If one of GSUB-FEATURE is nil, apply all gsub features except for | ||
| 365 | already applied and listed later. For instance, if the font has | ||
| 366 | GSUB features nukt, haln, rphf, blwf, and half, | ||
| 367 | (deva nil nukt haln nil rphf) | ||
| 368 | applies nukt and haln in this order, then applies blwf and half | ||
| 369 | in the order apearing in the font. The features are of the | ||
| 370 | default langsys of `deva' script. | ||
| 371 | |||
| 372 | This method applies the specified features to the codes in the | ||
| 373 | elements of GSTRING-IN (between FROMth and TOth). The output | ||
| 374 | codes are stored in GSTRING-OUT at the IDXth element and the | ||
| 375 | following elements. | ||
| 376 | |||
| 377 | Return the number of output codes. If none of the features are | ||
| 378 | applicable to the input data, return 0. If GSTRING-OUT is too | ||
| 379 | short, return -1. */ | ||
| 380 | int (*otf_gsub) P_ ((struct font *font, Lisp_Object gsub_spec, | ||
| 381 | Lisp_Object gstring_in, int from, int to, | ||
| 382 | Lisp_Object gstring_out, int idx)); | ||
| 383 | |||
| 384 | /* Drive FONT's OTF GPOS features according to GPOS_SPEC. | ||
| 385 | |||
| 386 | GPOS_SPEC is in this format (all elements are symbols): | ||
| 387 | (SCRIPT LANGSYS GPOS-FEATURE ...) | ||
| 388 | The meaning is the same as GSUB_SPEC above. | ||
| 389 | |||
| 390 | This method applies the specified features to the codes in the | ||
| 391 | elements of GSTRING (between FROMth and TOth). The resulting | ||
| 392 | positioning information (x-offset and y-offset) is stored in the | ||
| 393 | slots of the elements. | ||
| 394 | |||
| 395 | Return 1 if at least one glyph has nonzero x-offset or y-offset. | ||
| 396 | Otherwise return 0. */ | ||
| 397 | int (*otf_gpos) P_ ((struct font *font, Lisp_Object gpos_spec, | ||
| 398 | Lisp_Object gstring, int from, int to)); | ||
| 399 | }; | ||
| 400 | |||
| 401 | |||
| 402 | struct font_driver_list | ||
| 403 | { | ||
| 404 | struct font_driver *driver; | ||
| 405 | struct font_driver_list *next; | ||
| 406 | }; | ||
| 407 | |||
| 408 | extern int enable_font_backend; | ||
| 409 | |||
| 410 | EXFUN (Ffont_spec, MANY); | ||
| 411 | |||
| 412 | extern Lisp_Object font_symbolic_weight P_ ((Lisp_Object font)); | ||
| 413 | extern Lisp_Object font_symbolic_slant P_ ((Lisp_Object font)); | ||
| 414 | extern Lisp_Object font_symbolic_width P_ ((Lisp_Object font)); | ||
| 415 | |||
| 416 | extern Lisp_Object font_find_object P_ ((struct font *font)); | ||
| 417 | extern char *font_get_name P_ ((Lisp_Object)); | ||
| 418 | extern Lisp_Object font_get_frame P_ ((Lisp_Object font)); | ||
| 419 | extern int font_has_char P_ ((FRAME_PTR, Lisp_Object, int)); | ||
| 420 | extern unsigned font_encode_char P_ ((Lisp_Object, int)); | ||
| 421 | |||
| 422 | extern int font_set_lface_from_name P_ ((FRAME_PTR f, | ||
| 423 | Lisp_Object lface, | ||
| 424 | Lisp_Object fontname, | ||
| 425 | int force_p, int may_fail_p)); | ||
| 426 | extern Lisp_Object font_find_for_lface P_ ((FRAME_PTR f, Lisp_Object *lface, | ||
| 427 | Lisp_Object spec)); | ||
| 428 | extern Lisp_Object font_open_for_lface P_ ((FRAME_PTR f, Lisp_Object *lface, | ||
| 429 | Lisp_Object entity)); | ||
| 430 | extern void font_load_for_face P_ ((FRAME_PTR f, struct face *face)); | ||
| 431 | extern void font_prepare_for_face P_ ((FRAME_PTR f, struct face *face)); | ||
| 432 | extern Lisp_Object font_open_by_name P_ ((FRAME_PTR f, char *name)); | ||
| 433 | |||
| 434 | extern Lisp_Object intern_downcase P_ ((char *str, int len)); | ||
| 435 | extern void font_update_sort_order P_ ((int *order)); | ||
| 436 | |||
| 437 | extern void font_parse_old_font_spec P_ ((Lisp_Object, Lisp_Object, | ||
| 438 | Lisp_Object, Lisp_Object)); | ||
| 439 | |||
| 440 | |||
| 441 | extern int font_parse_xlfd P_ ((char *name, Lisp_Object font, int merge)); | ||
| 442 | extern int font_unparse_xlfd P_ ((Lisp_Object font, int pixel_size, | ||
| 443 | char *name, int bytes)); | ||
| 444 | extern void register_font_driver P_ ((struct font_driver *driver, FRAME_PTR f)); | ||
| 445 | extern void free_font_driver_list P_ ((FRAME_PTR f)); | ||
| 446 | |||
| 447 | extern struct font *font_prepare_composition P_ ((struct composition *cmp)); | ||
| 448 | |||
| 449 | |||
| 450 | #ifdef HAVE_LIBOTF | ||
| 451 | /* This can be used as `otf_capability' method of a font-driver. */ | ||
| 452 | extern Lisp_Object font_otf_capability P_ ((struct font *font)); | ||
| 453 | /* This can be used as `otf_gsub' method of a font-driver. */ | ||
| 454 | extern int font_otf_gsub P_ ((struct font *font, Lisp_Object gsub_spec, | ||
| 455 | Lisp_Object gstring_in, int from, int to, | ||
| 456 | Lisp_Object gstring_out, int idx)); | ||
| 457 | /* This can be used as `otf_gpos' method of a font-driver. */ | ||
| 458 | extern int font_otf_gpos P_ ((struct font *font, Lisp_Object gpos_spec, | ||
| 459 | Lisp_Object gstring, int from, int to)); | ||
| 460 | #endif /* HAVE_LIBOTF */ | ||
| 461 | |||
| 462 | #ifdef HAVE_FREETYPE | ||
| 463 | extern struct font_driver ftfont_driver; | ||
| 464 | #endif /* HAVE_FREETYPE */ | ||
| 465 | #ifdef HAVE_X_WINDOWS | ||
| 466 | extern struct font_driver xfont_driver; | ||
| 467 | extern struct font_driver ftxfont_driver; | ||
| 468 | #ifdef HAVE_XFT | ||
| 469 | extern struct font_driver xftfont_driver; | ||
| 470 | #endif /* HAVE_XFT */ | ||
| 471 | #endif /* HAVE_X_WINDOWS */ | ||
| 472 | #ifdef WINDOWSNT | ||
| 473 | extern struct font_driver w32font_driver; | ||
| 474 | #endif /* WINDOWSNT */ | ||
| 475 | #ifdef MAC_OS | ||
| 476 | extern struct font_driver atmfont_driver; | ||
| 477 | #endif /* MAC_OS */ | ||
| 478 | |||
| 479 | #endif /* not EMACS_FONT_H */ | ||
diff --git a/src/ftfont.c b/src/ftfont.c new file mode 100644 index 00000000000..fff8dd72a49 --- /dev/null +++ b/src/ftfont.c | |||
| @@ -0,0 +1,731 @@ | |||
| 1 | /* ftfont.c -- FreeType font driver. | ||
| 2 | Copyright (C) 2006 Free Software Foundation, Inc. | ||
| 3 | Copyright (C) 2006 | ||
| 4 | National Institute of Advanced Industrial Science and Technology (AIST) | ||
| 5 | Registration Number H13PRO009 | ||
| 6 | |||
| 7 | This file is part of GNU Emacs. | ||
| 8 | |||
| 9 | GNU Emacs is free software; you can redistribute it and/or modify | ||
| 10 | it under the terms of the GNU General Public License as published by | ||
| 11 | the Free Software Foundation; either version 2, or (at your option) | ||
| 12 | any later version. | ||
| 13 | |||
| 14 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 17 | GNU General Public License for more details. | ||
| 18 | |||
| 19 | You should have received a copy of the GNU General Public License | ||
| 20 | along with GNU Emacs; see the file COPYING. If not, write to | ||
| 21 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
| 22 | Boston, MA 02110-1301, USA. */ | ||
| 23 | |||
| 24 | #include <config.h> | ||
| 25 | #include <stdio.h> | ||
| 26 | |||
| 27 | #include <ft2build.h> | ||
| 28 | #include FT_FREETYPE_H | ||
| 29 | #include FT_SIZES_H | ||
| 30 | #include <fontconfig/fontconfig.h> | ||
| 31 | #include <fontconfig/fcfreetype.h> | ||
| 32 | |||
| 33 | #include "lisp.h" | ||
| 34 | #include "dispextern.h" | ||
| 35 | #include "frame.h" | ||
| 36 | #include "blockinput.h" | ||
| 37 | #include "character.h" | ||
| 38 | #include "charset.h" | ||
| 39 | #include "coding.h" | ||
| 40 | #include "fontset.h" | ||
| 41 | #include "font.h" | ||
| 42 | |||
| 43 | Lisp_Object Qfreetype; | ||
| 44 | |||
| 45 | static int fc_initialized; | ||
| 46 | static FT_Library ft_library; | ||
| 47 | |||
| 48 | static Lisp_Object freetype_font_cache; | ||
| 49 | |||
| 50 | static Lisp_Object Qiso8859_1, Qiso10646_1, Qunicode_bmp; | ||
| 51 | |||
| 52 | static FcCharSet *cs_iso8859_1; | ||
| 53 | |||
| 54 | /* The actual structure for FreeType font that can be casted to struct | ||
| 55 | font. */ | ||
| 56 | |||
| 57 | struct ftfont_info | ||
| 58 | { | ||
| 59 | struct font font; | ||
| 60 | FT_Size ft_size; | ||
| 61 | }; | ||
| 62 | |||
| 63 | static int | ||
| 64 | ftfont_build_basic_charsets () | ||
| 65 | { | ||
| 66 | FcChar32 c; | ||
| 67 | |||
| 68 | cs_iso8859_1 = FcCharSetCreate (); | ||
| 69 | if (! cs_iso8859_1) | ||
| 70 | return -1; | ||
| 71 | for (c = ' '; c < 127; c++) | ||
| 72 | if (! FcCharSetAddChar (cs_iso8859_1, c)) | ||
| 73 | return -1; | ||
| 74 | for (c = 192; c < 256; c++) | ||
| 75 | if (! FcCharSetAddChar (cs_iso8859_1, c)) | ||
| 76 | return -1; | ||
| 77 | return 0; | ||
| 78 | } | ||
| 79 | |||
| 80 | static Lisp_Object ftfont_get_cache P_ ((Lisp_Object)); | ||
| 81 | static int ftfont_parse_name P_ ((FRAME_PTR, char *, Lisp_Object)); | ||
| 82 | static Lisp_Object ftfont_list P_ ((Lisp_Object, Lisp_Object)); | ||
| 83 | static Lisp_Object ftfont_list_family P_ ((Lisp_Object)); | ||
| 84 | static void ftfont_free_entity P_ ((Lisp_Object)); | ||
| 85 | static struct font *ftfont_open P_ ((FRAME_PTR, Lisp_Object, int)); | ||
| 86 | static void ftfont_close P_ ((FRAME_PTR, struct font *)); | ||
| 87 | static int ftfont_has_char P_ ((Lisp_Object, int)); | ||
| 88 | static unsigned ftfont_encode_char P_ ((struct font *, int)); | ||
| 89 | static int ftfont_text_extents P_ ((struct font *, unsigned *, int, | ||
| 90 | struct font_metrics *)); | ||
| 91 | static int ftfont_get_bitmap P_ ((struct font *, unsigned, | ||
| 92 | struct font_bitmap *, int)); | ||
| 93 | static int ftfont_anchor_point P_ ((struct font *, unsigned, int, | ||
| 94 | int *, int *)); | ||
| 95 | |||
| 96 | struct font_driver ftfont_driver = | ||
| 97 | { | ||
| 98 | (Lisp_Object) NULL, /* Qfreetype */ | ||
| 99 | ftfont_get_cache, | ||
| 100 | ftfont_parse_name, | ||
| 101 | ftfont_list, | ||
| 102 | ftfont_list_family, | ||
| 103 | ftfont_free_entity, | ||
| 104 | ftfont_open, | ||
| 105 | ftfont_close, | ||
| 106 | /* We can't draw a text without device dependent functions. */ | ||
| 107 | NULL, | ||
| 108 | NULL, | ||
| 109 | ftfont_has_char, | ||
| 110 | ftfont_encode_char, | ||
| 111 | ftfont_text_extents, | ||
| 112 | /* We can't draw a text without device dependent functions. */ | ||
| 113 | NULL, | ||
| 114 | ftfont_get_bitmap, | ||
| 115 | NULL, | ||
| 116 | NULL, | ||
| 117 | NULL, | ||
| 118 | ftfont_anchor_point, | ||
| 119 | #ifdef HAVE_LIBOTF | ||
| 120 | font_otf_capability, | ||
| 121 | font_otf_gsub, | ||
| 122 | font_otf_gpos | ||
| 123 | #else | ||
| 124 | NULL, | ||
| 125 | NULL, | ||
| 126 | NULL | ||
| 127 | #endif /* HAVE_LIBOTF */ | ||
| 128 | }; | ||
| 129 | |||
| 130 | #define SYMBOL_FcChar8(SYM) (FcChar8 *) SDATA (SYMBOL_NAME (SYM)) | ||
| 131 | |||
| 132 | extern Lisp_Object QCname; | ||
| 133 | |||
| 134 | static Lisp_Object | ||
| 135 | ftfont_get_cache (frame) | ||
| 136 | Lisp_Object frame; | ||
| 137 | { | ||
| 138 | if (NILP (freetype_font_cache)) | ||
| 139 | freetype_font_cache = Fcons (Qt, Qnil); | ||
| 140 | return freetype_font_cache; | ||
| 141 | } | ||
| 142 | |||
| 143 | static int | ||
| 144 | ftfont_parse_name (f, name, spec) | ||
| 145 | FRAME_PTR f; | ||
| 146 | char *name; | ||
| 147 | Lisp_Object spec; | ||
| 148 | { | ||
| 149 | FcPattern *p; | ||
| 150 | FcChar8 *str; | ||
| 151 | int numeric; | ||
| 152 | double dbl; | ||
| 153 | |||
| 154 | if (name[0] == '-' || strchr (name, '*')) | ||
| 155 | /* It seems that NAME is XLFD. */ | ||
| 156 | return -1; | ||
| 157 | p = FcNameParse ((FcChar8 *) name); | ||
| 158 | if (! p) | ||
| 159 | return -1; | ||
| 160 | if (FcPatternGetString (p, FC_FOUNDRY, 0, &str) == FcResultMatch) | ||
| 161 | ASET (spec, FONT_FOUNDRY_INDEX, | ||
| 162 | intern_downcase ((char *) str, strlen ((char *) str))); | ||
| 163 | if (FcPatternGetString (p, FC_FAMILY, 0, &str) == FcResultMatch) | ||
| 164 | ASET (spec, FONT_FAMILY_INDEX, | ||
| 165 | intern_downcase ((char *) str, strlen ((char *) str))); | ||
| 166 | if (FcPatternGetInteger (p, FC_WEIGHT, 0, &numeric) == FcResultMatch) | ||
| 167 | ASET (spec, FONT_WEIGHT_INDEX, make_number (numeric)); | ||
| 168 | if (FcPatternGetInteger (p, FC_SLANT, 0, &numeric) == FcResultMatch) | ||
| 169 | ASET (spec, FONT_SLANT_INDEX, make_number (numeric + 100)); | ||
| 170 | if (FcPatternGetInteger (p, FC_WIDTH, 0, &numeric) == FcResultMatch) | ||
| 171 | ASET (spec, FONT_WIDTH_INDEX, make_number (numeric)); | ||
| 172 | if (FcPatternGetDouble (p, FC_PIXEL_SIZE, 0, &dbl) == FcResultMatch) | ||
| 173 | ASET (spec, FONT_SIZE_INDEX, make_number (dbl)); | ||
| 174 | else if (FcPatternGetDouble (p, FC_SIZE, 0, &dbl) == FcResultMatch) | ||
| 175 | ASET (spec, FONT_SIZE_INDEX, make_float (dbl)); | ||
| 176 | return 0; | ||
| 177 | } | ||
| 178 | |||
| 179 | static Lisp_Object | ||
| 180 | ftfont_list (frame, spec) | ||
| 181 | Lisp_Object frame, spec; | ||
| 182 | { | ||
| 183 | Lisp_Object val, tmp, extra, font_name; | ||
| 184 | int i; | ||
| 185 | FcPattern *pattern = NULL; | ||
| 186 | FcCharSet *charset = NULL; | ||
| 187 | FcLangSet *langset = NULL; | ||
| 188 | FcFontSet *fontset = NULL; | ||
| 189 | FcObjectSet *objset = NULL; | ||
| 190 | Lisp_Object registry = Qnil; | ||
| 191 | |||
| 192 | val = null_vector; | ||
| 193 | |||
| 194 | if (! fc_initialized) | ||
| 195 | { | ||
| 196 | FcInit (); | ||
| 197 | fc_initialized = 1; | ||
| 198 | } | ||
| 199 | |||
| 200 | if (! NILP (AREF (spec, FONT_ADSTYLE_INDEX))) | ||
| 201 | return val; | ||
| 202 | if (! NILP (AREF (spec, FONT_REGISTRY_INDEX))) | ||
| 203 | { | ||
| 204 | registry = AREF (spec, FONT_REGISTRY_INDEX); | ||
| 205 | if (EQ (registry, Qiso8859_1)) | ||
| 206 | { | ||
| 207 | if (! cs_iso8859_1 | ||
| 208 | && ftfont_build_basic_charsets () < 0) | ||
| 209 | goto err; | ||
| 210 | charset = cs_iso8859_1; | ||
| 211 | registry = Qnil; | ||
| 212 | } | ||
| 213 | } | ||
| 214 | |||
| 215 | extra = AREF (spec, FONT_EXTRA_INDEX); | ||
| 216 | font_name = Qnil; | ||
| 217 | if (CONSP (extra)) | ||
| 218 | { | ||
| 219 | tmp = Fassq (QCotf, extra); | ||
| 220 | if (! NILP (tmp)) | ||
| 221 | return val; | ||
| 222 | tmp = Fassq (QClanguage, extra); | ||
| 223 | if (CONSP (tmp)) | ||
| 224 | { | ||
| 225 | langset = FcLangSetCreate (); | ||
| 226 | if (! langset) | ||
| 227 | goto err; | ||
| 228 | tmp = XCDR (tmp); | ||
| 229 | if (SYMBOLP (tmp)) | ||
| 230 | { | ||
| 231 | if (! FcLangSetAdd (langset, SYMBOL_FcChar8 (tmp))) | ||
| 232 | goto err; | ||
| 233 | } | ||
| 234 | else | ||
| 235 | while (CONSP (tmp)) | ||
| 236 | { | ||
| 237 | if (SYMBOLP (XCAR (tmp)) | ||
| 238 | && ! FcLangSetAdd (langset, SYMBOL_FcChar8 (XCAR (tmp)))) | ||
| 239 | goto err; | ||
| 240 | tmp = XCDR (tmp); | ||
| 241 | } | ||
| 242 | } | ||
| 243 | tmp = Fassq (QCname, extra); | ||
| 244 | if (CONSP (tmp)) | ||
| 245 | font_name = XCDR (tmp); | ||
| 246 | tmp = Fassq (QCscript, extra); | ||
| 247 | if (CONSP (tmp) && ! charset) | ||
| 248 | { | ||
| 249 | Lisp_Object script = XCDR (tmp); | ||
| 250 | Lisp_Object chars = assq_no_quit (script, | ||
| 251 | Vscript_representative_chars); | ||
| 252 | |||
| 253 | if (CONSP (chars)) | ||
| 254 | { | ||
| 255 | charset = FcCharSetCreate (); | ||
| 256 | if (! charset) | ||
| 257 | goto err; | ||
| 258 | for (chars = XCDR (chars); CONSP (chars); chars = XCDR (chars)) | ||
| 259 | if (CHARACTERP (XCAR (chars)) | ||
| 260 | && ! FcCharSetAddChar (charset, XUINT (XCAR (chars)))) | ||
| 261 | goto err; | ||
| 262 | } | ||
| 263 | } | ||
| 264 | } | ||
| 265 | |||
| 266 | if (! NILP (registry) && ! charset) | ||
| 267 | goto finish; | ||
| 268 | |||
| 269 | if (STRINGP (font_name)) | ||
| 270 | { | ||
| 271 | if (! isalpha (SDATA (font_name)[0])) | ||
| 272 | goto finish; | ||
| 273 | pattern = FcNameParse (SDATA (font_name)); | ||
| 274 | if (! pattern) | ||
| 275 | goto err; | ||
| 276 | } | ||
| 277 | else | ||
| 278 | { | ||
| 279 | pattern = FcPatternCreate (); | ||
| 280 | if (! pattern) | ||
| 281 | goto err; | ||
| 282 | |||
| 283 | tmp = AREF (spec, FONT_FOUNDRY_INDEX); | ||
| 284 | if (SYMBOLP (tmp) && ! NILP (tmp) | ||
| 285 | && ! FcPatternAddString (pattern, FC_FOUNDRY, SYMBOL_FcChar8 (tmp))) | ||
| 286 | goto err; | ||
| 287 | tmp = AREF (spec, FONT_FAMILY_INDEX); | ||
| 288 | if (SYMBOLP (tmp) && ! NILP (tmp) | ||
| 289 | && ! FcPatternAddString (pattern, FC_FAMILY, SYMBOL_FcChar8 (tmp))) | ||
| 290 | goto err; | ||
| 291 | tmp = AREF (spec, FONT_WEIGHT_INDEX); | ||
| 292 | if (INTEGERP (tmp) | ||
| 293 | && ! FcPatternAddInteger (pattern, FC_WEIGHT, XINT (tmp))) | ||
| 294 | goto err; | ||
| 295 | tmp = AREF (spec, FONT_SLANT_INDEX); | ||
| 296 | if (INTEGERP (tmp) | ||
| 297 | && XINT (tmp) >= 100 | ||
| 298 | && ! FcPatternAddInteger (pattern, FC_SLANT, XINT (tmp) - 100)) | ||
| 299 | goto err; | ||
| 300 | tmp = AREF (spec, FONT_WIDTH_INDEX); | ||
| 301 | if (INTEGERP (tmp) | ||
| 302 | && ! FcPatternAddInteger (pattern, FC_WIDTH, XINT (tmp))) | ||
| 303 | goto err; | ||
| 304 | if (! FcPatternAddBool (pattern, FC_SCALABLE, FcTrue)) | ||
| 305 | goto err; | ||
| 306 | } | ||
| 307 | |||
| 308 | if (charset | ||
| 309 | && ! FcPatternAddCharSet (pattern, FC_CHARSET, charset)) | ||
| 310 | goto err; | ||
| 311 | if (langset | ||
| 312 | && ! FcPatternAddLangSet (pattern, FC_LANG, langset)) | ||
| 313 | goto err; | ||
| 314 | objset = FcObjectSetBuild (FC_FOUNDRY, FC_FAMILY, FC_WEIGHT, FC_SLANT, | ||
| 315 | FC_WIDTH, FC_PIXEL_SIZE, FC_SPACING, | ||
| 316 | FC_CHARSET, FC_FILE, NULL); | ||
| 317 | if (! objset) | ||
| 318 | goto err; | ||
| 319 | |||
| 320 | BLOCK_INPUT; | ||
| 321 | fontset = FcFontList (NULL, pattern, objset); | ||
| 322 | UNBLOCK_INPUT; | ||
| 323 | if (! fontset) | ||
| 324 | goto err; | ||
| 325 | val = Qnil; | ||
| 326 | for (i = 0; i < fontset->nfont; i++) | ||
| 327 | { | ||
| 328 | FcPattern *p = fontset->fonts[i]; | ||
| 329 | FcChar8 *str, *file; | ||
| 330 | |||
| 331 | if (FcPatternGetString (p, FC_FILE, 0, &file) == FcResultMatch | ||
| 332 | && FcPatternGetCharSet (p, FC_CHARSET, 0, &charset) == FcResultMatch) | ||
| 333 | { | ||
| 334 | Lisp_Object entity = Fmake_vector (make_number (FONT_ENTITY_MAX), | ||
| 335 | null_string); | ||
| 336 | int numeric; | ||
| 337 | double dbl; | ||
| 338 | FcPattern *p0; | ||
| 339 | |||
| 340 | ASET (entity, FONT_TYPE_INDEX, Qfreetype); | ||
| 341 | ASET (entity, FONT_REGISTRY_INDEX, Qiso10646_1); | ||
| 342 | ASET (entity, FONT_FRAME_INDEX, frame); | ||
| 343 | ASET (entity, FONT_OBJLIST_INDEX, Qnil); | ||
| 344 | |||
| 345 | if (FcPatternGetString (p, FC_FOUNDRY, 0, &str) == FcResultMatch) | ||
| 346 | ASET (entity, FONT_FOUNDRY_INDEX, | ||
| 347 | intern_downcase ((char *) str, strlen ((char *) str))); | ||
| 348 | if (FcPatternGetString (p, FC_FAMILY, 0, &str) == FcResultMatch) | ||
| 349 | ASET (entity, FONT_FAMILY_INDEX, | ||
| 350 | intern_downcase ((char *) str, strlen ((char *) str))); | ||
| 351 | if (FcPatternGetInteger (p, FC_WEIGHT, 0, &numeric) == FcResultMatch) | ||
| 352 | ASET (entity, FONT_WEIGHT_INDEX, make_number (numeric)); | ||
| 353 | if (FcPatternGetInteger (p, FC_SLANT, 0, &numeric) == FcResultMatch) | ||
| 354 | ASET (entity, FONT_SLANT_INDEX, make_number (numeric + 100)); | ||
| 355 | if (FcPatternGetInteger (p, FC_WIDTH, 0, &numeric) == FcResultMatch) | ||
| 356 | ASET (entity, FONT_WIDTH_INDEX, make_number (numeric)); | ||
| 357 | if (FcPatternGetDouble (p, FC_PIXEL_SIZE, 0, &dbl) == FcResultMatch) | ||
| 358 | ASET (entity, FONT_SIZE_INDEX, make_number (dbl)); | ||
| 359 | else | ||
| 360 | ASET (entity, FONT_SIZE_INDEX, make_number (0)); | ||
| 361 | |||
| 362 | if (FcPatternGetInteger (p, FC_SPACING, 0, &numeric) != FcResultMatch) | ||
| 363 | numeric = FC_MONO; | ||
| 364 | p0 = FcPatternCreate (); | ||
| 365 | if (! p0 | ||
| 366 | || FcPatternAddString (p0, FC_FILE, file) == FcFalse | ||
| 367 | || FcPatternAddCharSet (p0, FC_CHARSET, charset) == FcFalse | ||
| 368 | || FcPatternAddInteger (p0, FC_SPACING, numeric) == FcFalse) | ||
| 369 | break; | ||
| 370 | ASET (entity, FONT_EXTRA_INDEX, make_save_value (p0, 0)); | ||
| 371 | |||
| 372 | val = Fcons (entity, val); | ||
| 373 | } | ||
| 374 | } | ||
| 375 | val = Fvconcat (1, &val); | ||
| 376 | goto finish; | ||
| 377 | |||
| 378 | err: | ||
| 379 | /* We come here because of unexpected error in fontconfig API call | ||
| 380 | (usually insufficiency memory). */ | ||
| 381 | val = Qnil; | ||
| 382 | |||
| 383 | finish: | ||
| 384 | if (charset && charset != cs_iso8859_1) FcCharSetDestroy (charset); | ||
| 385 | if (objset) FcObjectSetDestroy (objset); | ||
| 386 | if (fontset) FcFontSetDestroy (fontset); | ||
| 387 | if (langset) FcLangSetDestroy (langset); | ||
| 388 | if (pattern) FcPatternDestroy (pattern); | ||
| 389 | |||
| 390 | return val; | ||
| 391 | } | ||
| 392 | |||
| 393 | static Lisp_Object | ||
| 394 | ftfont_list_family (frame) | ||
| 395 | Lisp_Object frame; | ||
| 396 | { | ||
| 397 | Lisp_Object list; | ||
| 398 | FcPattern *pattern = NULL; | ||
| 399 | FcFontSet *fontset = NULL; | ||
| 400 | FcObjectSet *objset = NULL; | ||
| 401 | int i; | ||
| 402 | |||
| 403 | if (! fc_initialized) | ||
| 404 | { | ||
| 405 | FcInit (); | ||
| 406 | fc_initialized = 1; | ||
| 407 | } | ||
| 408 | |||
| 409 | pattern = FcPatternCreate (); | ||
| 410 | if (! pattern) | ||
| 411 | goto finish; | ||
| 412 | objset = FcObjectSetBuild (FC_FAMILY); | ||
| 413 | if (! objset) | ||
| 414 | goto finish; | ||
| 415 | fontset = FcFontList (NULL, pattern, objset); | ||
| 416 | if (! fontset) | ||
| 417 | goto finish; | ||
| 418 | |||
| 419 | list = Qnil; | ||
| 420 | for (i = 0; i < fontset->nfont; i++) | ||
| 421 | { | ||
| 422 | FcPattern *pat = fontset->fonts[i]; | ||
| 423 | FcChar8 *str; | ||
| 424 | |||
| 425 | if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch) | ||
| 426 | list = Fcons (intern_downcase ((char *) str, strlen ((char *) str)), | ||
| 427 | list); | ||
| 428 | } | ||
| 429 | |||
| 430 | finish: | ||
| 431 | if (objset) FcObjectSetDestroy (objset); | ||
| 432 | if (fontset) FcFontSetDestroy (fontset); | ||
| 433 | if (pattern) FcPatternDestroy (pattern); | ||
| 434 | |||
| 435 | return list; | ||
| 436 | } | ||
| 437 | |||
| 438 | |||
| 439 | static void | ||
| 440 | ftfont_free_entity (entity) | ||
| 441 | Lisp_Object entity; | ||
| 442 | { | ||
| 443 | Lisp_Object val = AREF (entity, FONT_EXTRA_INDEX); | ||
| 444 | FcPattern *pattern = XSAVE_VALUE (val)->pointer; | ||
| 445 | |||
| 446 | FcPatternDestroy (pattern); | ||
| 447 | } | ||
| 448 | |||
| 449 | static struct font * | ||
| 450 | ftfont_open (f, entity, pixel_size) | ||
| 451 | FRAME_PTR f; | ||
| 452 | Lisp_Object entity; | ||
| 453 | int pixel_size; | ||
| 454 | { | ||
| 455 | struct ftfont_info *ftfont_info; | ||
| 456 | struct font *font; | ||
| 457 | FT_Face ft_face; | ||
| 458 | FT_Size ft_size; | ||
| 459 | FT_UInt size; | ||
| 460 | Lisp_Object val; | ||
| 461 | FcPattern *pattern; | ||
| 462 | FcChar8 *file; | ||
| 463 | int spacing; | ||
| 464 | |||
| 465 | val = AREF (entity, FONT_EXTRA_INDEX); | ||
| 466 | if (XTYPE (val) != Lisp_Misc | ||
| 467 | || XMISCTYPE (val) != Lisp_Misc_Save_Value) | ||
| 468 | return NULL; | ||
| 469 | pattern = XSAVE_VALUE (val)->pointer; | ||
| 470 | if (XSAVE_VALUE (val)->integer == 0) | ||
| 471 | { | ||
| 472 | /* We have not yet created FT_Face for this font. */ | ||
| 473 | if (! ft_library | ||
| 474 | && FT_Init_FreeType (&ft_library) != 0) | ||
| 475 | return NULL; | ||
| 476 | if (FcPatternGetString (pattern, FC_FILE, 0, &file) != FcResultMatch) | ||
| 477 | return NULL; | ||
| 478 | if (FT_New_Face (ft_library, (char *) file, 0, &ft_face) != 0) | ||
| 479 | return NULL; | ||
| 480 | FcPatternAddFTFace (pattern, FC_FT_FACE, ft_face); | ||
| 481 | ft_size = ft_face->size; | ||
| 482 | } | ||
| 483 | else | ||
| 484 | { | ||
| 485 | if (FcPatternGetFTFace (pattern, FC_FT_FACE, 0, &ft_face) | ||
| 486 | != FcResultMatch) | ||
| 487 | return NULL; | ||
| 488 | if (FT_New_Size (ft_face, &ft_size) != 0) | ||
| 489 | return NULL; | ||
| 490 | if (FT_Activate_Size (ft_size) != 0) | ||
| 491 | { | ||
| 492 | FT_Done_Size (ft_size); | ||
| 493 | return NULL; | ||
| 494 | } | ||
| 495 | } | ||
| 496 | |||
| 497 | size = XINT (AREF (entity, FONT_SIZE_INDEX)); | ||
| 498 | if (size == 0) | ||
| 499 | size = pixel_size; | ||
| 500 | if (FT_Set_Pixel_Sizes (ft_face, size, size) != 0) | ||
| 501 | { | ||
| 502 | if (XSAVE_VALUE (val)->integer == 0) | ||
| 503 | FT_Done_Face (ft_face); | ||
| 504 | return NULL; | ||
| 505 | } | ||
| 506 | |||
| 507 | ftfont_info = malloc (sizeof (struct ftfont_info)); | ||
| 508 | if (! ftfont_info) | ||
| 509 | return NULL; | ||
| 510 | ftfont_info->ft_size = ft_size; | ||
| 511 | |||
| 512 | font = (struct font *) ftfont_info; | ||
| 513 | font->entity = entity; | ||
| 514 | font->pixel_size = size; | ||
| 515 | font->driver = &ftfont_driver; | ||
| 516 | font->font.name = font->font.full_name = NULL; | ||
| 517 | font->file_name = (char *) file; | ||
| 518 | font->font.size = ft_face->size->metrics.max_advance >> 6; | ||
| 519 | font->ascent = ft_face->size->metrics.ascender >> 6; | ||
| 520 | font->descent = - ft_face->size->metrics.descender >> 6; | ||
| 521 | font->font.height = ft_face->size->metrics.height >> 6; | ||
| 522 | if (FcPatternGetInteger (pattern, FC_SPACING, 0, &spacing) != FcResultMatch | ||
| 523 | || spacing != FC_PROPORTIONAL) | ||
| 524 | font->font.average_width = font->font.space_width = font->font.size; | ||
| 525 | else | ||
| 526 | { | ||
| 527 | int i; | ||
| 528 | |||
| 529 | for (i = 32; i < 127; i++) | ||
| 530 | { | ||
| 531 | if (FT_Load_Char (ft_face, i, FT_LOAD_DEFAULT) != 0) | ||
| 532 | break; | ||
| 533 | if (i == 32) | ||
| 534 | font->font.space_width = ft_face->glyph->metrics.horiAdvance >> 6; | ||
| 535 | font->font.average_width += ft_face->glyph->metrics.horiAdvance >> 6; | ||
| 536 | } | ||
| 537 | if (i == 127) | ||
| 538 | { | ||
| 539 | /* The font contains all ASCII printable characters. */ | ||
| 540 | font->font.average_width /= 95; | ||
| 541 | } | ||
| 542 | else | ||
| 543 | { | ||
| 544 | if (i == 32) | ||
| 545 | font->font.space_width = font->font.size; | ||
| 546 | font->font.average_width = font->font.size; | ||
| 547 | } | ||
| 548 | } | ||
| 549 | |||
| 550 | font->font.baseline_offset = 0; | ||
| 551 | font->font.relative_compose = 0; | ||
| 552 | font->font.default_ascent = 0; | ||
| 553 | font->font.vertical_centering = 0; | ||
| 554 | |||
| 555 | (XSAVE_VALUE (val)->integer)++; | ||
| 556 | |||
| 557 | return font; | ||
| 558 | } | ||
| 559 | |||
| 560 | static void | ||
| 561 | ftfont_close (f, font) | ||
| 562 | FRAME_PTR f; | ||
| 563 | struct font *font; | ||
| 564 | { | ||
| 565 | struct ftfont_info *ftfont_info = (struct ftfont_info *) font; | ||
| 566 | Lisp_Object entity = font->entity; | ||
| 567 | Lisp_Object val = AREF (entity, FONT_EXTRA_INDEX); | ||
| 568 | |||
| 569 | (XSAVE_VALUE (val)->integer)--; | ||
| 570 | if (XSAVE_VALUE (val)->integer == 0) | ||
| 571 | FT_Done_Face (ftfont_info->ft_size->face); | ||
| 572 | else | ||
| 573 | FT_Done_Size (ftfont_info->ft_size); | ||
| 574 | |||
| 575 | free (font); | ||
| 576 | } | ||
| 577 | |||
| 578 | static int | ||
| 579 | ftfont_has_char (entity, c) | ||
| 580 | Lisp_Object entity; | ||
| 581 | int c; | ||
| 582 | { | ||
| 583 | Lisp_Object val; | ||
| 584 | FcPattern *pattern; | ||
| 585 | FcCharSet *charset; | ||
| 586 | |||
| 587 | val = AREF (entity, FONT_EXTRA_INDEX); | ||
| 588 | pattern = XSAVE_VALUE (val)->pointer; | ||
| 589 | FcPatternGetCharSet (pattern, FC_CHARSET, 0, &charset); | ||
| 590 | |||
| 591 | return (FcCharSetHasChar (charset, (FcChar32) c) == FcTrue); | ||
| 592 | } | ||
| 593 | |||
| 594 | static unsigned | ||
| 595 | ftfont_encode_char (font, c) | ||
| 596 | struct font *font; | ||
| 597 | int c; | ||
| 598 | { | ||
| 599 | struct ftfont_info *ftfont_info = (struct ftfont_info *) font; | ||
| 600 | FT_Face ft_face = ftfont_info->ft_size->face; | ||
| 601 | FT_ULong charcode = c; | ||
| 602 | FT_UInt code = FT_Get_Char_Index (ft_face, charcode); | ||
| 603 | |||
| 604 | return (code > 0 ? code : 0xFFFFFFFF); | ||
| 605 | } | ||
| 606 | |||
| 607 | static int | ||
| 608 | ftfont_text_extents (font, code, nglyphs, metrics) | ||
| 609 | struct font *font; | ||
| 610 | unsigned *code; | ||
| 611 | int nglyphs; | ||
| 612 | struct font_metrics *metrics; | ||
| 613 | { | ||
| 614 | struct ftfont_info *ftfont_info = (struct ftfont_info *) font; | ||
| 615 | FT_Face ft_face = ftfont_info->ft_size->face; | ||
| 616 | int width = 0; | ||
| 617 | int i; | ||
| 618 | |||
| 619 | if (ftfont_info->ft_size != ft_face->size) | ||
| 620 | FT_Activate_Size (ftfont_info->ft_size); | ||
| 621 | if (metrics) | ||
| 622 | bzero (metrics, sizeof (struct font_metrics)); | ||
| 623 | for (i = 0; i < nglyphs; i++) | ||
| 624 | { | ||
| 625 | if (FT_Load_Glyph (ft_face, code[i], FT_LOAD_DEFAULT) == 0) | ||
| 626 | { | ||
| 627 | FT_Glyph_Metrics *m = &ft_face->glyph->metrics; | ||
| 628 | |||
| 629 | if (metrics) | ||
| 630 | { | ||
| 631 | if (metrics->lbearing > width + (m->horiBearingX >> 6)) | ||
| 632 | metrics->lbearing = width + (m->horiBearingX >> 6); | ||
| 633 | if (metrics->rbearing | ||
| 634 | < width + ((m->horiBearingX + m->width) >> 6)) | ||
| 635 | metrics->rbearing | ||
| 636 | = width + ((m->horiBearingX + m->width) >> 6); | ||
| 637 | if (metrics->ascent < (m->horiBearingY >> 6)) | ||
| 638 | metrics->ascent = m->horiBearingY >> 6; | ||
| 639 | if (metrics->descent > ((m->horiBearingY + m->height) >> 6)) | ||
| 640 | metrics->descent = (m->horiBearingY + m->height) >> 6; | ||
| 641 | } | ||
| 642 | width += m->horiAdvance >> 6; | ||
| 643 | } | ||
| 644 | else | ||
| 645 | { | ||
| 646 | width += font->font.space_width; | ||
| 647 | } | ||
| 648 | } | ||
| 649 | if (metrics) | ||
| 650 | metrics->width = width; | ||
| 651 | |||
| 652 | return width; | ||
| 653 | } | ||
| 654 | |||
| 655 | static int | ||
| 656 | ftfont_get_bitmap (font, code, bitmap, bits_per_pixel) | ||
| 657 | struct font *font; | ||
| 658 | unsigned code; | ||
| 659 | struct font_bitmap *bitmap; | ||
| 660 | int bits_per_pixel; | ||
| 661 | { | ||
| 662 | struct ftfont_info *ftfont_info = (struct ftfont_info *) font; | ||
| 663 | FT_Face ft_face = ftfont_info->ft_size->face; | ||
| 664 | FT_Int32 load_flags = FT_LOAD_RENDER; | ||
| 665 | |||
| 666 | if (ftfont_info->ft_size != ft_face->size) | ||
| 667 | FT_Activate_Size (ftfont_info->ft_size); | ||
| 668 | if (bits_per_pixel == 1) | ||
| 669 | { | ||
| 670 | #ifdef FT_LOAD_TARGET_MONO | ||
| 671 | load_flags |= FT_LOAD_TARGET_MONO; | ||
| 672 | #else | ||
| 673 | load_flags |= FT_LOAD_MONOCHROME; | ||
| 674 | #endif | ||
| 675 | } | ||
| 676 | else if (bits_per_pixel != 8) | ||
| 677 | /* We don't support such a rendering. */ | ||
| 678 | return -1; | ||
| 679 | |||
| 680 | if (FT_Load_Glyph (ft_face, code, load_flags) != 0) | ||
| 681 | return -1; | ||
| 682 | bitmap->rows = ft_face->glyph->bitmap.rows; | ||
| 683 | bitmap->width = ft_face->glyph->bitmap.width; | ||
| 684 | bitmap->pitch = ft_face->glyph->bitmap.pitch; | ||
| 685 | bitmap->buffer = ft_face->glyph->bitmap.buffer; | ||
| 686 | bitmap->left = ft_face->glyph->bitmap_left; | ||
| 687 | bitmap->top = ft_face->glyph->bitmap_top; | ||
| 688 | bitmap->advance = ft_face->glyph->metrics.horiAdvance >> 6; | ||
| 689 | bitmap->extra = NULL; | ||
| 690 | |||
| 691 | return 0; | ||
| 692 | } | ||
| 693 | |||
| 694 | static int | ||
| 695 | ftfont_anchor_point (font, code, index, x, y) | ||
| 696 | struct font *font; | ||
| 697 | unsigned code; | ||
| 698 | int index; | ||
| 699 | int *x, *y; | ||
| 700 | { | ||
| 701 | struct ftfont_info *ftfont_info = (struct ftfont_info *) font; | ||
| 702 | FT_Face ft_face = ftfont_info->ft_size->face; | ||
| 703 | |||
| 704 | if (ftfont_info->ft_size != ft_face->size) | ||
| 705 | FT_Activate_Size (ftfont_info->ft_size); | ||
| 706 | if (FT_Load_Glyph (ft_face, code, FT_LOAD_DEFAULT) != 0) | ||
| 707 | return -1; | ||
| 708 | if (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE) | ||
| 709 | return -1; | ||
| 710 | if (index >= ft_face->glyph->outline.n_points) | ||
| 711 | return -1; | ||
| 712 | *x = ft_face->glyph->outline.points[index].x; | ||
| 713 | *y = ft_face->glyph->outline.points[index].y; | ||
| 714 | return 0; | ||
| 715 | } | ||
| 716 | |||
| 717 | |||
| 718 | void | ||
| 719 | syms_of_ftfont () | ||
| 720 | { | ||
| 721 | staticpro (&freetype_font_cache); | ||
| 722 | freetype_font_cache = Qnil; | ||
| 723 | |||
| 724 | DEFSYM (Qfreetype, "freetype"); | ||
| 725 | DEFSYM (Qiso8859_1, "iso8859-1"); | ||
| 726 | DEFSYM (Qiso10646_1, "iso10646-1"); | ||
| 727 | DEFSYM (Qunicode_bmp, "unicode-bmp"); | ||
| 728 | |||
| 729 | ftfont_driver.type = Qfreetype; | ||
| 730 | register_font_driver (&ftfont_driver, NULL); | ||
| 731 | } | ||
diff --git a/src/ftxfont.c b/src/ftxfont.c new file mode 100644 index 00000000000..af6a96f7060 --- /dev/null +++ b/src/ftxfont.c | |||
| @@ -0,0 +1,346 @@ | |||
| 1 | /* ftxfont.c -- FreeType font driver on X (without using XFT). | ||
| 2 | Copyright (C) 2006 Free Software Foundation, Inc. | ||
| 3 | Copyright (C) 2006 | ||
| 4 | National Institute of Advanced Industrial Science and Technology (AIST) | ||
| 5 | Registration Number H13PRO009 | ||
| 6 | |||
| 7 | This file is part of GNU Emacs. | ||
| 8 | |||
| 9 | GNU Emacs is free software; you can redistribute it and/or modify | ||
| 10 | it under the terms of the GNU General Public License as published by | ||
| 11 | the Free Software Foundation; either version 2, or (at your option) | ||
| 12 | any later version. | ||
| 13 | |||
| 14 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 17 | GNU General Public License for more details. | ||
| 18 | |||
| 19 | You should have received a copy of the GNU General Public License | ||
| 20 | along with GNU Emacs; see the file COPYING. If not, write to | ||
| 21 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
| 22 | Boston, MA 02110-1301, USA. */ | ||
| 23 | |||
| 24 | #include <config.h> | ||
| 25 | #include <stdio.h> | ||
| 26 | #include <X11/Xlib.h> | ||
| 27 | |||
| 28 | #include "lisp.h" | ||
| 29 | #include "dispextern.h" | ||
| 30 | #include "xterm.h" | ||
| 31 | #include "frame.h" | ||
| 32 | #include "blockinput.h" | ||
| 33 | #include "character.h" | ||
| 34 | #include "charset.h" | ||
| 35 | #include "fontset.h" | ||
| 36 | #include "font.h" | ||
| 37 | |||
| 38 | /* FTX font driver. */ | ||
| 39 | |||
| 40 | static Lisp_Object Qftx; | ||
| 41 | |||
| 42 | /* Prototypes for helper function. */ | ||
| 43 | static int ftxfont_draw_bitmap P_ ((FRAME_PTR, GC *, struct font *, unsigned, | ||
| 44 | int, int, XPoint *, int, int *n)); | ||
| 45 | static void ftxfont_draw_backgrond P_ ((FRAME_PTR, struct font *, GC, | ||
| 46 | int, int, int)); | ||
| 47 | |||
| 48 | static int | ||
| 49 | ftxfont_draw_bitmap (f, gc, font, code, x, y, p, size, n) | ||
| 50 | FRAME_PTR f; | ||
| 51 | GC *gc; | ||
| 52 | struct font *font; | ||
| 53 | unsigned code; | ||
| 54 | int x, y; | ||
| 55 | XPoint *p; | ||
| 56 | int size, *n; | ||
| 57 | { | ||
| 58 | struct font_bitmap bitmap; | ||
| 59 | unsigned char *b; | ||
| 60 | int i, j; | ||
| 61 | |||
| 62 | if (ftfont_driver.get_bitmap (font, code, &bitmap, 1) < 0) | ||
| 63 | return 0; | ||
| 64 | for (i = 0, b = bitmap.buffer; i < bitmap.rows; | ||
| 65 | i++, b += bitmap.pitch) | ||
| 66 | { | ||
| 67 | if (size > 0x100) | ||
| 68 | { | ||
| 69 | for (j = 0; j < bitmap.width; j++) | ||
| 70 | if (b[j / 8] & (1 << (7 - (j % 8)))) | ||
| 71 | { | ||
| 72 | p[n[0]].x = x + bitmap.left + j; | ||
| 73 | p[n[0]].y = y - bitmap.top + i; | ||
| 74 | if (++n[0] == 0x400) | ||
| 75 | { | ||
| 76 | XDrawPoints (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), | ||
| 77 | gc[0], p, size, CoordModeOrigin); | ||
| 78 | n[0] = 0; | ||
| 79 | } | ||
| 80 | } | ||
| 81 | } | ||
| 82 | else | ||
| 83 | { | ||
| 84 | for (j = 0; j < bitmap.width; j++) | ||
| 85 | { | ||
| 86 | int idx = (b[j] >> 5) - 1; | ||
| 87 | |||
| 88 | if (idx >= 0) | ||
| 89 | { | ||
| 90 | XPoint *pp = p + size * idx; | ||
| 91 | |||
| 92 | pp[n[idx]].x = x + bitmap.left + j; | ||
| 93 | pp[n[idx]].y = y - bitmap.top + i; | ||
| 94 | if (++(n[idx]) == 0x100) | ||
| 95 | { | ||
| 96 | XDrawPoints (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), | ||
| 97 | gc[idx], pp, size, CoordModeOrigin); | ||
| 98 | n[idx] = 0; | ||
| 99 | } | ||
| 100 | } | ||
| 101 | } | ||
| 102 | } | ||
| 103 | } | ||
| 104 | |||
| 105 | if (ftfont_driver.free_bitmap) | ||
| 106 | ftfont_driver.free_bitmap (font, &bitmap); | ||
| 107 | |||
| 108 | return bitmap.advance; | ||
| 109 | } | ||
| 110 | |||
| 111 | static void | ||
| 112 | ftxfont_draw_backgrond (f, font, gc, x, y, width) | ||
| 113 | FRAME_PTR f; | ||
| 114 | struct font *font; | ||
| 115 | GC gc; | ||
| 116 | int x, y, width; | ||
| 117 | { | ||
| 118 | XGCValues xgcv; | ||
| 119 | |||
| 120 | XGetGCValues (FRAME_X_DISPLAY (f), gc, | ||
| 121 | GCForeground | GCBackground, &xgcv); | ||
| 122 | XSetForeground (FRAME_X_DISPLAY (f), gc, xgcv.background); | ||
| 123 | XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc, | ||
| 124 | x, y - font->ascent, width, font->font.height); | ||
| 125 | XSetForeground (FRAME_X_DISPLAY (f), gc, xgcv.foreground); | ||
| 126 | } | ||
| 127 | |||
| 128 | /* Prototypes for font-driver methods. */ | ||
| 129 | static Lisp_Object ftxfont_list P_ ((Lisp_Object, Lisp_Object)); | ||
| 130 | static struct font *ftxfont_open P_ ((FRAME_PTR, Lisp_Object, int)); | ||
| 131 | static void ftxfont_close P_ ((FRAME_PTR, struct font *)); | ||
| 132 | static int ftxfont_prepare_face (FRAME_PTR, struct face *); | ||
| 133 | static void ftxfont_done_face (FRAME_PTR, struct face *); | ||
| 134 | |||
| 135 | static int ftxfont_draw P_ ((struct glyph_string *, int, int, int, int, int)); | ||
| 136 | |||
| 137 | struct font_driver ftxfont_driver; | ||
| 138 | |||
| 139 | static Lisp_Object | ||
| 140 | ftxfont_list (frame, spec) | ||
| 141 | Lisp_Object frame; | ||
| 142 | Lisp_Object spec; | ||
| 143 | { | ||
| 144 | Lisp_Object val = ftfont_driver.list (frame, spec); | ||
| 145 | |||
| 146 | if (! NILP (val)) | ||
| 147 | { | ||
| 148 | int i; | ||
| 149 | |||
| 150 | for (i = 0; i < ASIZE (val); i++) | ||
| 151 | ASET (AREF (val, i), FONT_TYPE_INDEX, Qftx); | ||
| 152 | } | ||
| 153 | return val; | ||
| 154 | } | ||
| 155 | |||
| 156 | static struct font * | ||
| 157 | ftxfont_open (f, entity, pixel_size) | ||
| 158 | FRAME_PTR f; | ||
| 159 | Lisp_Object entity; | ||
| 160 | int pixel_size; | ||
| 161 | { | ||
| 162 | Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f); | ||
| 163 | struct font *font; | ||
| 164 | XFontStruct *xfont = malloc (sizeof (XFontStruct)); | ||
| 165 | |||
| 166 | if (! xfont) | ||
| 167 | return NULL; | ||
| 168 | font = ftfont_driver.open (f, entity, pixel_size); | ||
| 169 | if (! font) | ||
| 170 | { | ||
| 171 | free (xfont); | ||
| 172 | return NULL; | ||
| 173 | } | ||
| 174 | |||
| 175 | xfont->fid = FRAME_FONT (f)->fid; | ||
| 176 | xfont->ascent = font->ascent; | ||
| 177 | xfont->descent = font->descent; | ||
| 178 | xfont->max_bounds.width = font->font.size; | ||
| 179 | xfont->min_bounds.width = font->min_width; | ||
| 180 | font->font.font = xfont; | ||
| 181 | font->driver = &ftxfont_driver; | ||
| 182 | |||
| 183 | dpyinfo->n_fonts++; | ||
| 184 | |||
| 185 | /* Set global flag fonts_changed_p to non-zero if the font loaded | ||
| 186 | has a character with a smaller width than any other character | ||
| 187 | before, or if the font loaded has a smaller height than any other | ||
| 188 | font loaded before. If this happens, it will make a glyph matrix | ||
| 189 | reallocation necessary. */ | ||
| 190 | if (dpyinfo->n_fonts == 1) | ||
| 191 | { | ||
| 192 | dpyinfo->smallest_font_height = font->font.height; | ||
| 193 | dpyinfo->smallest_char_width = font->min_width; | ||
| 194 | fonts_changed_p = 1; | ||
| 195 | } | ||
| 196 | else | ||
| 197 | { | ||
| 198 | if (dpyinfo->smallest_font_height > font->font.height) | ||
| 199 | dpyinfo->smallest_font_height = font->font.height, fonts_changed_p |= 1; | ||
| 200 | if (dpyinfo->smallest_char_width > font->min_width) | ||
| 201 | dpyinfo->smallest_char_width = font->min_width, fonts_changed_p |= 1; | ||
| 202 | } | ||
| 203 | |||
| 204 | return font; | ||
| 205 | } | ||
| 206 | |||
| 207 | static void | ||
| 208 | ftxfont_close (f, font) | ||
| 209 | FRAME_PTR f; | ||
| 210 | struct font *font; | ||
| 211 | { | ||
| 212 | ftfont_driver.close (f, font); | ||
| 213 | FRAME_X_DISPLAY_INFO (f)->n_fonts--; | ||
| 214 | } | ||
| 215 | |||
| 216 | static int | ||
| 217 | ftxfont_prepare_face (f, face) | ||
| 218 | FRAME_PTR f; | ||
| 219 | struct face *face; | ||
| 220 | { | ||
| 221 | GC gc[6]; | ||
| 222 | XColor colors[3]; | ||
| 223 | XGCValues xgcv; | ||
| 224 | unsigned long mask = GCForeground | GCBackground | GCGraphicsExposures; | ||
| 225 | int i; | ||
| 226 | |||
| 227 | face->extra = NULL; | ||
| 228 | |||
| 229 | /* Here, we create 6 more GCs to simulate anti-aliasing. */ | ||
| 230 | BLOCK_INPUT; | ||
| 231 | XGetGCValues (FRAME_X_DISPLAY (f), face->gc, mask, &xgcv); | ||
| 232 | colors[0].pixel = face->foreground; | ||
| 233 | colors[1].pixel = face->background; | ||
| 234 | XQueryColors (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), colors, 2); | ||
| 235 | for (i = 1; i < 7; i++) | ||
| 236 | { | ||
| 237 | colors[2].red = (colors[0].red * i + colors[1].red * (7 - i)) / 7; | ||
| 238 | colors[2].green = (colors[0].green * i + colors[1].green * (7 - i)) / 7; | ||
| 239 | colors[2].blue = (colors[0].blue * i + colors[1].blue * (7 - i)) / 7; | ||
| 240 | if (! x_alloc_nearest_color (f, FRAME_X_COLORMAP (f), &colors[2])) | ||
| 241 | break; | ||
| 242 | xgcv.foreground = colors[2].pixel; | ||
| 243 | gc[i - 1] = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), | ||
| 244 | mask, &xgcv); | ||
| 245 | } | ||
| 246 | UNBLOCK_INPUT; | ||
| 247 | |||
| 248 | if (i < 7) | ||
| 249 | return -1; | ||
| 250 | face->extra = malloc (sizeof (GC) * 7); | ||
| 251 | if (! face->extra) | ||
| 252 | return -1; | ||
| 253 | for (i = 0; i < 6; i++) | ||
| 254 | ((GC *) face->extra)[i] = gc[i]; | ||
| 255 | ((GC *) face->extra)[i] = face->gc; | ||
| 256 | return 0; | ||
| 257 | } | ||
| 258 | |||
| 259 | static void | ||
| 260 | ftxfont_done_face (f, face) | ||
| 261 | FRAME_PTR f; | ||
| 262 | struct face *face; | ||
| 263 | { | ||
| 264 | if (face->extra) | ||
| 265 | { | ||
| 266 | int i; | ||
| 267 | |||
| 268 | BLOCK_INPUT; | ||
| 269 | for (i = 0; i < 7; i++) | ||
| 270 | XFreeGC (FRAME_X_DISPLAY (f), ((GC *) face->extra)[i]); | ||
| 271 | UNBLOCK_INPUT; | ||
| 272 | free (face->extra); | ||
| 273 | face->extra = NULL; | ||
| 274 | } | ||
| 275 | } | ||
| 276 | |||
| 277 | static int | ||
| 278 | ftxfont_draw (s, from, to, x, y, with_background) | ||
| 279 | struct glyph_string *s; | ||
| 280 | int from, to, x, y, with_background; | ||
| 281 | { | ||
| 282 | FRAME_PTR f = s->f; | ||
| 283 | struct face *face = s->face; | ||
| 284 | struct font *font = (struct font *) face->font; | ||
| 285 | XPoint p[0x700]; | ||
| 286 | int n[7]; | ||
| 287 | unsigned *code; | ||
| 288 | int len = to - from; | ||
| 289 | int i; | ||
| 290 | |||
| 291 | n[0] = n[1] = n[2] = n[3] = n[4] = n[5] = n[6] = 0; | ||
| 292 | |||
| 293 | BLOCK_INPUT; | ||
| 294 | |||
| 295 | if (with_background) | ||
| 296 | ftxfont_draw_backgrond (f, font, s->gc, x, y, s->width); | ||
| 297 | code = alloca (sizeof (unsigned) * len); | ||
| 298 | for (i = 0; i < len; i++) | ||
| 299 | code[i] = ((XCHAR2B_BYTE1 (s->char2b + from + i) << 8) | ||
| 300 | | XCHAR2B_BYTE2 (s->char2b + from + i)); | ||
| 301 | |||
| 302 | if (! face->extra) | ||
| 303 | { | ||
| 304 | for (i = 0; i < len; i++) | ||
| 305 | x += ftxfont_draw_bitmap (f, &face->gc, font, code[i], x, y, | ||
| 306 | p, 0x700, n); | ||
| 307 | if (n[0] > 0) | ||
| 308 | XDrawPoints (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), | ||
| 309 | face->gc, p, n[0], CoordModeOrigin); | ||
| 310 | } | ||
| 311 | else | ||
| 312 | { | ||
| 313 | GC *gc = face->extra; | ||
| 314 | |||
| 315 | for (i = 0; i < len; i++) | ||
| 316 | x += ftxfont_draw_bitmap (f, &face->gc, font, code[i], x, y, | ||
| 317 | p, 0x100, n); | ||
| 318 | for (i = 0; i < 7; i++) | ||
| 319 | if (n[i] > 0) | ||
| 320 | XDrawPoints (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), | ||
| 321 | gc[i], p + 0x100 * i, n[i], CoordModeOrigin); | ||
| 322 | } | ||
| 323 | |||
| 324 | UNBLOCK_INPUT; | ||
| 325 | |||
| 326 | return len; | ||
| 327 | } | ||
| 328 | |||
| 329 | |||
| 330 | |||
| 331 | void | ||
| 332 | syms_of_ftxfont () | ||
| 333 | { | ||
| 334 | DEFSYM (Qftx, "ftx"); | ||
| 335 | |||
| 336 | ftxfont_driver = ftfont_driver; | ||
| 337 | ftxfont_driver.type = Qftx; | ||
| 338 | ftxfont_driver.list = ftxfont_list; | ||
| 339 | ftxfont_driver.open = ftxfont_open; | ||
| 340 | ftxfont_driver.close = ftxfont_close; | ||
| 341 | ftxfont_driver.prepare_face = ftxfont_prepare_face; | ||
| 342 | ftxfont_driver.done_face = ftxfont_done_face; | ||
| 343 | ftxfont_driver.draw = ftxfont_draw; | ||
| 344 | |||
| 345 | register_font_driver (&ftxfont_driver, NULL); | ||
| 346 | } | ||
diff --git a/src/xfont.c b/src/xfont.c new file mode 100644 index 00000000000..0d5d2f70b7d --- /dev/null +++ b/src/xfont.c | |||
| @@ -0,0 +1,868 @@ | |||
| 1 | /* xfont.c -- X core font driver. | ||
| 2 | Copyright (C) 2006 Free Software Foundation, Inc. | ||
| 3 | Copyright (C) 2006 | ||
| 4 | National Institute of Advanced Industrial Science and Technology (AIST) | ||
| 5 | Registration Number H13PRO009 | ||
| 6 | |||
| 7 | This file is part of GNU Emacs. | ||
| 8 | |||
| 9 | GNU Emacs is free software; you can redistribute it and/or modify | ||
| 10 | it under the terms of the GNU General Public License as published by | ||
| 11 | the Free Software Foundation; either version 2, or (at your option) | ||
| 12 | any later version. | ||
| 13 | |||
| 14 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 17 | GNU General Public License for more details. | ||
| 18 | |||
| 19 | You should have received a copy of the GNU General Public License | ||
| 20 | along with GNU Emacs; see the file COPYING. If not, write to | ||
| 21 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
| 22 | Boston, MA 02110-1301, USA. */ | ||
| 23 | |||
| 24 | #include <config.h> | ||
| 25 | #include <stdio.h> | ||
| 26 | #include <X11/Xlib.h> | ||
| 27 | |||
| 28 | #include "lisp.h" | ||
| 29 | #include "dispextern.h" | ||
| 30 | #include "xterm.h" | ||
| 31 | #include "frame.h" | ||
| 32 | #include "blockinput.h" | ||
| 33 | #include "character.h" | ||
| 34 | #include "charset.h" | ||
| 35 | #include "fontset.h" | ||
| 36 | #include "font.h" | ||
| 37 | |||
| 38 | |||
| 39 | /* X core font driver. */ | ||
| 40 | |||
| 41 | Lisp_Object Qx; | ||
| 42 | |||
| 43 | /* Alist of font registry symbol and the corresponding charsets | ||
| 44 | information. The information is retrieved from | ||
| 45 | Vfont_encoding_alist on demand. | ||
| 46 | |||
| 47 | Eash element has the form: | ||
| 48 | (REGISTRY . (ENCODING-CHARSET-ID . REPERTORY-CHARSET-ID)) | ||
| 49 | or | ||
| 50 | (REGISTRY . nil) | ||
| 51 | |||
| 52 | In the former form, ENCODING-CHARSET-ID is an ID of a charset that | ||
| 53 | encodes a character code to a glyph code of a font, and | ||
| 54 | REPERTORY-CHARSET-ID is an ID of a charset that tells if a | ||
| 55 | character is supported by a font. | ||
| 56 | |||
| 57 | The latter form means that the information for REGISTRY couldn't be | ||
| 58 | retrieved. */ | ||
| 59 | static Lisp_Object x_font_charset_alist; | ||
| 60 | |||
| 61 | /* Prototypes of support functions. */ | ||
| 62 | extern void x_clear_errors P_ ((Display *)); | ||
| 63 | |||
| 64 | static char *xfont_query_font P_ ((Display *, char *, Lisp_Object)); | ||
| 65 | static XCharStruct *xfont_get_pcm P_ ((XFontStruct *, XChar2b *)); | ||
| 66 | static int xfont_registry_charsets P_ ((Lisp_Object, struct charset **, | ||
| 67 | struct charset **)); | ||
| 68 | |||
| 69 | static char * | ||
| 70 | xfont_query_font (display, name, spec) | ||
| 71 | Display *display; | ||
| 72 | char *name; | ||
| 73 | Lisp_Object spec; | ||
| 74 | { | ||
| 75 | XFontStruct *font; | ||
| 76 | |||
| 77 | BLOCK_INPUT; | ||
| 78 | x_catch_errors (display); | ||
| 79 | font = XLoadQueryFont (display, name); | ||
| 80 | name = NULL; | ||
| 81 | if (x_had_errors_p (display)) | ||
| 82 | { | ||
| 83 | /* This error is perhaps due to insufficient memory on X | ||
| 84 | server. Let's just ignore it. */ | ||
| 85 | x_clear_errors (display); | ||
| 86 | } | ||
| 87 | else if (font) | ||
| 88 | { | ||
| 89 | unsigned long value; | ||
| 90 | |||
| 91 | if (XGetFontProperty (font, XA_FONT, &value)) | ||
| 92 | { | ||
| 93 | char *n = (char *) XGetAtomName (display, (Atom) value); | ||
| 94 | |||
| 95 | if (font_parse_xlfd (n, spec, 0) >= 0) | ||
| 96 | name = n; | ||
| 97 | else | ||
| 98 | XFree (n); | ||
| 99 | } | ||
| 100 | XFreeFont (display, font); | ||
| 101 | } | ||
| 102 | x_uncatch_errors (); | ||
| 103 | UNBLOCK_INPUT; | ||
| 104 | |||
| 105 | return name; | ||
| 106 | } | ||
| 107 | |||
| 108 | |||
| 109 | /* Get metrics of character CHAR2B in XFONT. Value is null if CHAR2B | ||
| 110 | is not contained in the font. */ | ||
| 111 | |||
| 112 | static XCharStruct * | ||
| 113 | xfont_get_pcm (xfont, char2b) | ||
| 114 | XFontStruct *xfont; | ||
| 115 | XChar2b *char2b; | ||
| 116 | { | ||
| 117 | /* The result metric information. */ | ||
| 118 | XCharStruct *pcm = NULL; | ||
| 119 | |||
| 120 | xassert (xfont && char2b); | ||
| 121 | |||
| 122 | if (xfont->per_char != NULL) | ||
| 123 | { | ||
| 124 | if (xfont->min_byte1 == 0 && xfont->max_byte1 == 0) | ||
| 125 | { | ||
| 126 | /* min_char_or_byte2 specifies the linear character index | ||
| 127 | corresponding to the first element of the per_char array, | ||
| 128 | max_char_or_byte2 is the index of the last character. A | ||
| 129 | character with non-zero CHAR2B->byte1 is not in the font. | ||
| 130 | A character with byte2 less than min_char_or_byte2 or | ||
| 131 | greater max_char_or_byte2 is not in the font. */ | ||
| 132 | if (char2b->byte1 == 0 | ||
| 133 | && char2b->byte2 >= xfont->min_char_or_byte2 | ||
| 134 | && char2b->byte2 <= xfont->max_char_or_byte2) | ||
| 135 | pcm = xfont->per_char + char2b->byte2 - xfont->min_char_or_byte2; | ||
| 136 | } | ||
| 137 | else | ||
| 138 | { | ||
| 139 | /* If either min_byte1 or max_byte1 are nonzero, both | ||
| 140 | min_char_or_byte2 and max_char_or_byte2 are less than | ||
| 141 | 256, and the 2-byte character index values corresponding | ||
| 142 | to the per_char array element N (counting from 0) are: | ||
| 143 | |||
| 144 | byte1 = N/D + min_byte1 | ||
| 145 | byte2 = N\D + min_char_or_byte2 | ||
| 146 | |||
| 147 | where: | ||
| 148 | |||
| 149 | D = max_char_or_byte2 - min_char_or_byte2 + 1 | ||
| 150 | / = integer division | ||
| 151 | \ = integer modulus */ | ||
| 152 | if (char2b->byte1 >= xfont->min_byte1 | ||
| 153 | && char2b->byte1 <= xfont->max_byte1 | ||
| 154 | && char2b->byte2 >= xfont->min_char_or_byte2 | ||
| 155 | && char2b->byte2 <= xfont->max_char_or_byte2) | ||
| 156 | pcm = (xfont->per_char | ||
| 157 | + ((xfont->max_char_or_byte2 - xfont->min_char_or_byte2 + 1) | ||
| 158 | * (char2b->byte1 - xfont->min_byte1)) | ||
| 159 | + (char2b->byte2 - xfont->min_char_or_byte2)); | ||
| 160 | } | ||
| 161 | } | ||
| 162 | else | ||
| 163 | { | ||
| 164 | /* If the per_char pointer is null, all glyphs between the first | ||
| 165 | and last character indexes inclusive have the same | ||
| 166 | information, as given by both min_bounds and max_bounds. */ | ||
| 167 | if (char2b->byte2 >= xfont->min_char_or_byte2 | ||
| 168 | && char2b->byte2 <= xfont->max_char_or_byte2) | ||
| 169 | pcm = &xfont->max_bounds; | ||
| 170 | } | ||
| 171 | |||
| 172 | return ((pcm == NULL | ||
| 173 | || (pcm->width == 0 && (pcm->rbearing - pcm->lbearing) == 0)) | ||
| 174 | ? NULL : pcm); | ||
| 175 | } | ||
| 176 | |||
| 177 | extern Lisp_Object find_font_encoding P_ ((Lisp_Object)); | ||
| 178 | |||
| 179 | /* Return encoding charset and repertory charset for REGISTRY in | ||
| 180 | ENCODING and REPERTORY correspondingly. If correct information for | ||
| 181 | REGISTRY is available, return 0. Otherwise return -1. */ | ||
| 182 | |||
| 183 | static int | ||
| 184 | xfont_registry_charsets (registry, encoding, repertory) | ||
| 185 | Lisp_Object registry; | ||
| 186 | struct charset **encoding, **repertory; | ||
| 187 | { | ||
| 188 | Lisp_Object val; | ||
| 189 | int encoding_id, repertory_id; | ||
| 190 | |||
| 191 | val = assq_no_quit (registry, x_font_charset_alist); | ||
| 192 | if (! NILP (val)) | ||
| 193 | { | ||
| 194 | val = XCDR (val); | ||
| 195 | if (NILP (val)) | ||
| 196 | return -1; | ||
| 197 | encoding_id = XINT (XCAR (val)); | ||
| 198 | repertory_id = XINT (XCDR (val)); | ||
| 199 | } | ||
| 200 | else | ||
| 201 | { | ||
| 202 | val = find_font_encoding (SYMBOL_NAME (registry)); | ||
| 203 | if (SYMBOLP (val) && CHARSETP (val)) | ||
| 204 | { | ||
| 205 | encoding_id = repertory_id = XINT (CHARSET_SYMBOL_ID (val)); | ||
| 206 | } | ||
| 207 | else if (CONSP (val)) | ||
| 208 | { | ||
| 209 | if (! CHARSETP (XCAR (val))) | ||
| 210 | goto invalid_entry; | ||
| 211 | encoding_id = XINT (CHARSET_SYMBOL_ID (XCAR (val))); | ||
| 212 | if (NILP (XCDR (val))) | ||
| 213 | repertory_id = -1; | ||
| 214 | else | ||
| 215 | { | ||
| 216 | if (! CHARSETP (XCDR (val))) | ||
| 217 | goto invalid_entry; | ||
| 218 | repertory_id = XINT (CHARSET_SYMBOL_ID (XCDR (val))); | ||
| 219 | } | ||
| 220 | } | ||
| 221 | else | ||
| 222 | goto invalid_entry; | ||
| 223 | val = Fcons (make_number (encoding_id), make_number (repertory_id)); | ||
| 224 | x_font_charset_alist | ||
| 225 | = nconc2 (x_font_charset_alist, Fcons (Fcons (registry, val), Qnil)); | ||
| 226 | } | ||
| 227 | |||
| 228 | if (encoding) | ||
| 229 | *encoding = CHARSET_FROM_ID (encoding_id); | ||
| 230 | if (repertory) | ||
| 231 | *repertory = repertory_id >= 0 ? CHARSET_FROM_ID (repertory_id) : NULL; | ||
| 232 | return 0; | ||
| 233 | |||
| 234 | invalid_entry: | ||
| 235 | x_font_charset_alist | ||
| 236 | = nconc2 (x_font_charset_alist, Fcons (Fcons (registry, Qnil), Qnil)); | ||
| 237 | return -1; | ||
| 238 | } | ||
| 239 | |||
| 240 | static Lisp_Object xfont_get_cache P_ ((Lisp_Object)); | ||
| 241 | static int xfont_parse_name P_ ((FRAME_PTR, char *, Lisp_Object)); | ||
| 242 | static Lisp_Object xfont_list P_ ((Lisp_Object, Lisp_Object)); | ||
| 243 | static Lisp_Object xfont_list_family P_ ((Lisp_Object)); | ||
| 244 | static struct font *xfont_open P_ ((FRAME_PTR, Lisp_Object, int)); | ||
| 245 | static void xfont_close P_ ((FRAME_PTR, struct font *)); | ||
| 246 | static int xfont_prepare_face P_ ((FRAME_PTR, struct face *)); | ||
| 247 | #if 0 | ||
| 248 | static void xfont_done_face P_ ((FRAME_PTR, struct face *)); | ||
| 249 | #endif | ||
| 250 | static int xfont_has_char P_ ((Lisp_Object, int)); | ||
| 251 | static unsigned xfont_encode_char P_ ((struct font *, int)); | ||
| 252 | static int xfont_text_extents P_ ((struct font *, unsigned *, int, | ||
| 253 | struct font_metrics *)); | ||
| 254 | static int xfont_draw P_ ((struct glyph_string *, int, int, int, int, int)); | ||
| 255 | |||
| 256 | struct font_driver xfont_driver = | ||
| 257 | { | ||
| 258 | (Lisp_Object) NULL, /* Qx */ | ||
| 259 | xfont_get_cache, | ||
| 260 | xfont_parse_name, | ||
| 261 | xfont_list, | ||
| 262 | xfont_list_family, | ||
| 263 | NULL, | ||
| 264 | xfont_open, | ||
| 265 | xfont_close, | ||
| 266 | xfont_prepare_face, | ||
| 267 | NULL /*xfont_done_face*/, | ||
| 268 | xfont_has_char, | ||
| 269 | xfont_encode_char, | ||
| 270 | xfont_text_extents, | ||
| 271 | xfont_draw, | ||
| 272 | }; | ||
| 273 | |||
| 274 | extern Lisp_Object QCname; | ||
| 275 | |||
| 276 | static Lisp_Object | ||
| 277 | xfont_get_cache (frame) | ||
| 278 | Lisp_Object frame; | ||
| 279 | { | ||
| 280 | Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (XFRAME (frame)); | ||
| 281 | |||
| 282 | return (dpyinfo->name_list_element); | ||
| 283 | } | ||
| 284 | |||
| 285 | static int | ||
| 286 | xfont_parse_name (f, name, spec) | ||
| 287 | FRAME_PTR f; | ||
| 288 | char *name; | ||
| 289 | Lisp_Object spec; | ||
| 290 | { | ||
| 291 | if (font_parse_xlfd (name, spec, 0) >= 0) | ||
| 292 | return 0; | ||
| 293 | name = xfont_query_font (FRAME_X_DISPLAY (f), name, spec); | ||
| 294 | if (name) | ||
| 295 | { | ||
| 296 | XFree (name); | ||
| 297 | return 0; | ||
| 298 | } | ||
| 299 | return -1; | ||
| 300 | } | ||
| 301 | |||
| 302 | extern Lisp_Object Vface_alternative_font_registry_alist; | ||
| 303 | |||
| 304 | static Lisp_Object | ||
| 305 | xfont_list (frame, spec) | ||
| 306 | Lisp_Object frame, spec; | ||
| 307 | { | ||
| 308 | FRAME_PTR f = XFRAME (frame); | ||
| 309 | Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f); | ||
| 310 | Lisp_Object *vec, val, extra, font_name, entity; | ||
| 311 | char name[256], **names; | ||
| 312 | int i, idx, limit, num_fonts; | ||
| 313 | int error_occurred = 0; | ||
| 314 | USE_SAFE_ALLOCA; | ||
| 315 | |||
| 316 | extra = AREF (spec, FONT_EXTRA_INDEX); | ||
| 317 | font_name = Qnil; | ||
| 318 | if (CONSP (extra)) | ||
| 319 | { | ||
| 320 | val = Fassq (QCotf, extra); | ||
| 321 | if (! NILP (val)) | ||
| 322 | return null_vector; | ||
| 323 | val = Fassq (QCname, extra); | ||
| 324 | if (CONSP (val)) | ||
| 325 | font_name = XCDR (val); | ||
| 326 | } | ||
| 327 | |||
| 328 | if (! STRINGP (font_name) | ||
| 329 | && font_unparse_xlfd (spec, 0, name, 256) < 0) | ||
| 330 | return null_vector; | ||
| 331 | |||
| 332 | BLOCK_INPUT; | ||
| 333 | x_catch_errors (dpyinfo->display); | ||
| 334 | |||
| 335 | if (STRINGP (font_name)) | ||
| 336 | { | ||
| 337 | XFontStruct *font = XLoadQueryFont (dpyinfo->display, | ||
| 338 | (char *) SDATA (font_name)); | ||
| 339 | unsigned long value; | ||
| 340 | |||
| 341 | num_fonts = 0; | ||
| 342 | if (x_had_errors_p (dpyinfo->display)) | ||
| 343 | { | ||
| 344 | /* This error is perhaps due to insufficient memory on X | ||
| 345 | server. Let's just ignore it. */ | ||
| 346 | font = NULL; | ||
| 347 | error_occurred = 1; | ||
| 348 | x_clear_errors (dpyinfo->display); | ||
| 349 | } | ||
| 350 | if (font) | ||
| 351 | { | ||
| 352 | if (XGetFontProperty (font, XA_FONT, &value)) | ||
| 353 | { | ||
| 354 | char *n = (char *) XGetAtomName (dpyinfo->display, (Atom) value); | ||
| 355 | int len = strlen (n); | ||
| 356 | char *tmp; | ||
| 357 | |||
| 358 | /* If DXPC (a Differential X Protocol Compressor) | ||
| 359 | Ver.3.7 is running, XGetAtomName will return null | ||
| 360 | string. We must avoid such a name. */ | ||
| 361 | if (len > 0) | ||
| 362 | { | ||
| 363 | num_fonts = 1; | ||
| 364 | names = (char **) alloca (sizeof (char *)); | ||
| 365 | /* Some systems only allow alloca assigned to a | ||
| 366 | simple var. */ | ||
| 367 | tmp = (char *) alloca (len + 1); names[0] = tmp; | ||
| 368 | bcopy (n, names[0], len + 1); | ||
| 369 | } | ||
| 370 | XFree (n); | ||
| 371 | } | ||
| 372 | XFreeFont (dpyinfo->display, font); | ||
| 373 | } | ||
| 374 | } | ||
| 375 | else | ||
| 376 | { | ||
| 377 | Lisp_Object registry = AREF (spec, FONT_REGISTRY_INDEX); | ||
| 378 | Lisp_Object alter = Qnil; | ||
| 379 | char *r = NULL; | ||
| 380 | |||
| 381 | if (! NILP (registry)) | ||
| 382 | alter = Fassoc_string (SYMBOL_NAME (registry), | ||
| 383 | Vface_alternative_font_registry_alist); | ||
| 384 | while (1) | ||
| 385 | { | ||
| 386 | for (limit = 512, num_fonts = 0; ; limit *= 2) | ||
| 387 | { | ||
| 388 | names = XListFonts (dpyinfo->display, name, limit, &num_fonts); | ||
| 389 | if (x_had_errors_p (dpyinfo->display)) | ||
| 390 | { | ||
| 391 | /* This error is perhaps due to insufficient memory | ||
| 392 | on X server. Let's just ignore it. */ | ||
| 393 | x_clear_errors (dpyinfo->display); | ||
| 394 | error_occurred = 1; | ||
| 395 | num_fonts = 0; | ||
| 396 | break; | ||
| 397 | } | ||
| 398 | if (num_fonts < limit) | ||
| 399 | break; | ||
| 400 | XFreeFontNames (names); | ||
| 401 | } | ||
| 402 | if (num_fonts > 0 | ||
| 403 | || NILP (alter)) | ||
| 404 | break; | ||
| 405 | |||
| 406 | /* Setup for trying alternatives. */ | ||
| 407 | if (! r | ||
| 408 | && ! (r = strstr (name, (char *) SDATA (SYMBOL_NAME (registry))))) | ||
| 409 | abort (); | ||
| 410 | while (1) | ||
| 411 | { | ||
| 412 | registry = Qnil; | ||
| 413 | alter = XCDR (alter); | ||
| 414 | if (NILP (alter)) | ||
| 415 | break; | ||
| 416 | registry = XCAR (alter); | ||
| 417 | if ((r - name) + SBYTES (registry) < 255) | ||
| 418 | break; | ||
| 419 | } | ||
| 420 | if (NILP (registry)) | ||
| 421 | break; | ||
| 422 | bcopy (SDATA (registry), r, SBYTES (registry)); | ||
| 423 | } | ||
| 424 | } | ||
| 425 | |||
| 426 | x_uncatch_errors (); | ||
| 427 | UNBLOCK_INPUT; | ||
| 428 | |||
| 429 | if (error_occurred) | ||
| 430 | return Qnil; | ||
| 431 | if (num_fonts == 0) | ||
| 432 | return null_vector; | ||
| 433 | |||
| 434 | entity = Fmake_vector (make_number (FONT_ENTITY_MAX), Qnil); | ||
| 435 | ASET (entity, FONT_TYPE_INDEX, Qx); | ||
| 436 | ASET (entity, FONT_FRAME_INDEX, frame); | ||
| 437 | |||
| 438 | SAFE_ALLOCA_LISP (vec, num_fonts); | ||
| 439 | for (i = idx = 0; i < num_fonts; i++) | ||
| 440 | { | ||
| 441 | if (font_parse_xlfd (names[i], entity, 0) > 0) | ||
| 442 | vec[idx++] = Fcopy_sequence (entity); | ||
| 443 | } | ||
| 444 | if (! STRINGP (font_name)) | ||
| 445 | { | ||
| 446 | BLOCK_INPUT; | ||
| 447 | XFreeFontNames (names); | ||
| 448 | UNBLOCK_INPUT; | ||
| 449 | } | ||
| 450 | val = Fvector (idx, vec); | ||
| 451 | SAFE_FREE (); | ||
| 452 | |||
| 453 | return val; | ||
| 454 | } | ||
| 455 | |||
| 456 | static int | ||
| 457 | memq_no_quit (elt, list) | ||
| 458 | Lisp_Object elt, list; | ||
| 459 | { | ||
| 460 | while (CONSP (list) && ! EQ (XCAR (list), elt)) | ||
| 461 | list = XCDR (list); | ||
| 462 | return (CONSP (list)); | ||
| 463 | } | ||
| 464 | |||
| 465 | static Lisp_Object | ||
| 466 | xfont_list_family (frame) | ||
| 467 | { | ||
| 468 | FRAME_PTR f = XFRAME (frame); | ||
| 469 | Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f); | ||
| 470 | char **names; | ||
| 471 | int num_fonts, i; | ||
| 472 | Lisp_Object list; | ||
| 473 | char *last_family; | ||
| 474 | int last_len; | ||
| 475 | |||
| 476 | BLOCK_INPUT; | ||
| 477 | x_catch_errors (dpyinfo->display); | ||
| 478 | names = XListFonts (dpyinfo->display, "-*-*-*-*-*-*-*-*-*-*-*-*-*-*", | ||
| 479 | 0x8000, &num_fonts); | ||
| 480 | if (x_had_errors_p (dpyinfo->display)) | ||
| 481 | { | ||
| 482 | /* This error is perhaps due to insufficient memory on X server. | ||
| 483 | Let's just ignore it. */ | ||
| 484 | x_clear_errors (dpyinfo->display); | ||
| 485 | num_fonts = 0; | ||
| 486 | } | ||
| 487 | |||
| 488 | list = Qnil; | ||
| 489 | for (i = 0, last_len = 0; i < num_fonts; i++) | ||
| 490 | { | ||
| 491 | char *p0 = names[i], *p1; | ||
| 492 | Lisp_Object family; | ||
| 493 | |||
| 494 | p0++; /* skip the leading '-' */ | ||
| 495 | while (*p0 && *p0 != '-') p0++; /* skip foundry */ | ||
| 496 | if (! *p0) | ||
| 497 | continue; | ||
| 498 | p1 = ++p0; | ||
| 499 | while (*p1 && *p1 != '-') p1++; /* find the end of family */ | ||
| 500 | if (! *p1 || p1 == p0) | ||
| 501 | continue; | ||
| 502 | if (last_len == p1 - p0 | ||
| 503 | && bcmp (last_family, p0, last_len) == 0) | ||
| 504 | continue; | ||
| 505 | last_len = p1 - p0; | ||
| 506 | last_family = p0; | ||
| 507 | family = intern_downcase (p0, last_len); | ||
| 508 | if (! memq_no_quit (family, list)) | ||
| 509 | list = Fcons (family, list); | ||
| 510 | } | ||
| 511 | |||
| 512 | XFreeFontNames (names); | ||
| 513 | x_uncatch_errors (); | ||
| 514 | UNBLOCK_INPUT; | ||
| 515 | |||
| 516 | return list; | ||
| 517 | } | ||
| 518 | |||
| 519 | static struct font * | ||
| 520 | xfont_open (f, entity, pixel_size) | ||
| 521 | FRAME_PTR f; | ||
| 522 | Lisp_Object entity; | ||
| 523 | int pixel_size; | ||
| 524 | { | ||
| 525 | Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f); | ||
| 526 | Display *display = dpyinfo->display; | ||
| 527 | char name[256]; | ||
| 528 | int len; | ||
| 529 | unsigned long value; | ||
| 530 | Lisp_Object registry; | ||
| 531 | struct charset *encoding, *repertory; | ||
| 532 | struct font *font; | ||
| 533 | XFontStruct *xfont; | ||
| 534 | |||
| 535 | /* At first, check if we know how to encode characters for this | ||
| 536 | font. */ | ||
| 537 | registry = AREF (entity, FONT_REGISTRY_INDEX); | ||
| 538 | if (xfont_registry_charsets (registry, &encoding, &repertory) < 0) | ||
| 539 | return NULL; | ||
| 540 | |||
| 541 | if (XINT (AREF (entity, FONT_SIZE_INDEX)) != 0) | ||
| 542 | pixel_size = XINT (AREF (entity, FONT_SIZE_INDEX)); | ||
| 543 | len = font_unparse_xlfd (entity, pixel_size, name, 256); | ||
| 544 | if (len <= 0) | ||
| 545 | return NULL; | ||
| 546 | |||
| 547 | BLOCK_INPUT; | ||
| 548 | x_catch_errors (display); | ||
| 549 | xfont = XLoadQueryFont (display, name); | ||
| 550 | if (x_had_errors_p (display)) | ||
| 551 | { | ||
| 552 | /* This error is perhaps due to insufficient memory on X server. | ||
| 553 | Let's just ignore it. */ | ||
| 554 | x_clear_errors (display); | ||
| 555 | xfont = NULL; | ||
| 556 | } | ||
| 557 | x_uncatch_errors (); | ||
| 558 | UNBLOCK_INPUT; | ||
| 559 | |||
| 560 | if (! xfont) | ||
| 561 | return NULL; | ||
| 562 | font = malloc (sizeof (struct font)); | ||
| 563 | font->font.font = xfont; | ||
| 564 | font->entity = entity; | ||
| 565 | font->pixel_size = pixel_size; | ||
| 566 | font->driver = &xfont_driver; | ||
| 567 | font->font.name = malloc (len + 1); | ||
| 568 | if (! font->font.name) | ||
| 569 | { | ||
| 570 | XFreeFont (display, xfont); | ||
| 571 | free (font); | ||
| 572 | return NULL; | ||
| 573 | } | ||
| 574 | bcopy (name, font->font.name, len + 1); | ||
| 575 | font->font.charset = encoding->id; | ||
| 576 | font->encoding_charset = encoding->id; | ||
| 577 | font->repertory_charet = repertory ? repertory->id : -1; | ||
| 578 | font->ascent = xfont->ascent; | ||
| 579 | font->descent = xfont->descent; | ||
| 580 | |||
| 581 | if (xfont->min_bounds.width == xfont->max_bounds.width) | ||
| 582 | { | ||
| 583 | /* Fixed width font. */ | ||
| 584 | font->font.average_width = font->font.space_width | ||
| 585 | = xfont->min_bounds.width; | ||
| 586 | } | ||
| 587 | else | ||
| 588 | { | ||
| 589 | XChar2b char2b; | ||
| 590 | XCharStruct *pcm; | ||
| 591 | |||
| 592 | char2b.byte1 = 0x00, char2b.byte2 = 0x20; | ||
| 593 | pcm = xfont_get_pcm (xfont, &char2b); | ||
| 594 | if (pcm) | ||
| 595 | font->font.space_width = pcm->width; | ||
| 596 | else | ||
| 597 | font->font.space_width = xfont->max_bounds.width; | ||
| 598 | |||
| 599 | font->font.average_width | ||
| 600 | = (XGetFontProperty (xfont, dpyinfo->Xatom_AVERAGE_WIDTH, &value) | ||
| 601 | ? (long) value / 10 : 0); | ||
| 602 | if (font->font.average_width < 0) | ||
| 603 | font->font.average_width = - font->font.average_width; | ||
| 604 | if (font->font.average_width == 0) | ||
| 605 | { | ||
| 606 | if (pcm) | ||
| 607 | { | ||
| 608 | int width = pcm->width; | ||
| 609 | for (char2b.byte2 = 33; char2b.byte2 <= 126; char2b.byte2++) | ||
| 610 | if ((pcm = xfont_get_pcm (xfont, &char2b)) != NULL) | ||
| 611 | width += pcm->width; | ||
| 612 | font->font.average_width = width / 95; | ||
| 613 | } | ||
| 614 | else | ||
| 615 | font->font.average_width = xfont->max_bounds.width; | ||
| 616 | } | ||
| 617 | } | ||
| 618 | font->min_width = xfont->min_bounds.width; | ||
| 619 | if (font->min_width <= 0) | ||
| 620 | font->min_width = font->font.space_width; | ||
| 621 | |||
| 622 | BLOCK_INPUT; | ||
| 623 | /* Try to get the full name of FONT. Put it in FULL_NAME. */ | ||
| 624 | if (XGetFontProperty (xfont, XA_FONT, &value)) | ||
| 625 | { | ||
| 626 | char *full_name = NULL, *p0, *p; | ||
| 627 | int dashes = 0; | ||
| 628 | |||
| 629 | p0 = p = (char *) XGetAtomName (FRAME_X_DISPLAY (f), (Atom) value);; | ||
| 630 | /* Count the number of dashes in the "full name". | ||
| 631 | If it is too few, this isn't really the font's full name, | ||
| 632 | so don't use it. | ||
| 633 | In X11R4, the fonts did not come with their canonical names | ||
| 634 | stored in them. */ | ||
| 635 | while (*p) | ||
| 636 | { | ||
| 637 | if (*p == '-') | ||
| 638 | dashes++; | ||
| 639 | p++; | ||
| 640 | } | ||
| 641 | |||
| 642 | if (dashes >= 13) | ||
| 643 | { | ||
| 644 | full_name = (char *) malloc (p - p0 + 1); | ||
| 645 | if (full_name) | ||
| 646 | bcopy (p0, full_name, p - p0 + 1); | ||
| 647 | } | ||
| 648 | XFree (p0); | ||
| 649 | |||
| 650 | if (full_name) | ||
| 651 | font->font.full_name = full_name; | ||
| 652 | else | ||
| 653 | font->font.full_name = font->font.name; | ||
| 654 | } | ||
| 655 | font->file_name = NULL; | ||
| 656 | |||
| 657 | font->font.size = xfont->max_bounds.width; | ||
| 658 | font->font.height = xfont->ascent + xfont->descent; | ||
| 659 | font->font.baseline_offset | ||
| 660 | = (XGetFontProperty (xfont, dpyinfo->Xatom_MULE_BASELINE_OFFSET, &value) | ||
| 661 | ? (long) value : 0); | ||
| 662 | font->font.relative_compose | ||
| 663 | = (XGetFontProperty (xfont, dpyinfo->Xatom_MULE_RELATIVE_COMPOSE, &value) | ||
| 664 | ? (long) value : 0); | ||
| 665 | font->font.default_ascent | ||
| 666 | = (XGetFontProperty (xfont, dpyinfo->Xatom_MULE_DEFAULT_ASCENT, &value) | ||
| 667 | ? (long) value : 0); | ||
| 668 | font->font.vertical_centering | ||
| 669 | = (STRINGP (Vvertical_centering_font_regexp) | ||
| 670 | && (fast_c_string_match_ignore_case | ||
| 671 | (Vvertical_centering_font_regexp, font->font.full_name) >= 0)); | ||
| 672 | |||
| 673 | UNBLOCK_INPUT; | ||
| 674 | |||
| 675 | dpyinfo->n_fonts++; | ||
| 676 | |||
| 677 | /* Set global flag fonts_changed_p to non-zero if the font loaded | ||
| 678 | has a character with a smaller width than any other character | ||
| 679 | before, or if the font loaded has a smaller height than any other | ||
| 680 | font loaded before. If this happens, it will make a glyph matrix | ||
| 681 | reallocation necessary. */ | ||
| 682 | if (dpyinfo->n_fonts == 1) | ||
| 683 | { | ||
| 684 | dpyinfo->smallest_font_height = font->font.height; | ||
| 685 | dpyinfo->smallest_char_width = font->min_width; | ||
| 686 | fonts_changed_p = 1; | ||
| 687 | } | ||
| 688 | else | ||
| 689 | { | ||
| 690 | if (dpyinfo->smallest_font_height > font->font.height) | ||
| 691 | dpyinfo->smallest_font_height = font->font.height, fonts_changed_p |= 1; | ||
| 692 | if (dpyinfo->smallest_char_width > font->min_width) | ||
| 693 | dpyinfo->smallest_char_width = font->min_width, fonts_changed_p |= 1; | ||
| 694 | } | ||
| 695 | |||
| 696 | return font; | ||
| 697 | } | ||
| 698 | |||
| 699 | static void | ||
| 700 | xfont_close (f, font) | ||
| 701 | FRAME_PTR f; | ||
| 702 | struct font *font; | ||
| 703 | { | ||
| 704 | BLOCK_INPUT; | ||
| 705 | XFreeFont (FRAME_X_DISPLAY (f), font->font.font); | ||
| 706 | UNBLOCK_INPUT; | ||
| 707 | |||
| 708 | if (font->font.name != font->font.full_name) | ||
| 709 | free (font->font.full_name); | ||
| 710 | free (font->font.name); | ||
| 711 | free (font); | ||
| 712 | FRAME_X_DISPLAY_INFO (f)->n_fonts--; | ||
| 713 | } | ||
| 714 | |||
| 715 | static int | ||
| 716 | xfont_prepare_face (f, face) | ||
| 717 | FRAME_PTR f; | ||
| 718 | struct face *face; | ||
| 719 | { | ||
| 720 | BLOCK_INPUT; | ||
| 721 | XSetFont (FRAME_X_DISPLAY (f), face->gc, face->font->fid); | ||
| 722 | UNBLOCK_INPUT; | ||
| 723 | |||
| 724 | return 0; | ||
| 725 | } | ||
| 726 | |||
| 727 | #if 0 | ||
| 728 | static void | ||
| 729 | xfont_done_face (f, face) | ||
| 730 | FRAME_PTR f; | ||
| 731 | struct face *face; | ||
| 732 | { | ||
| 733 | if (face->extra) | ||
| 734 | { | ||
| 735 | BLOCK_INPUT; | ||
| 736 | XFreeGC (FRAME_X_DISPLAY (f), (GC) face->extra); | ||
| 737 | UNBLOCK_INPUT; | ||
| 738 | face->extra = NULL; | ||
| 739 | } | ||
| 740 | } | ||
| 741 | #endif /* 0 */ | ||
| 742 | |||
| 743 | static int | ||
| 744 | xfont_has_char (entity, c) | ||
| 745 | Lisp_Object entity; | ||
| 746 | int c; | ||
| 747 | { | ||
| 748 | Lisp_Object registry = AREF (entity, FONT_REGISTRY_INDEX); | ||
| 749 | struct charset *repertory; | ||
| 750 | |||
| 751 | if (xfont_registry_charsets (registry, NULL, &repertory) < 0) | ||
| 752 | return -1; | ||
| 753 | if (! repertory) | ||
| 754 | return -1; | ||
| 755 | return (ENCODE_CHAR (repertory, c) != CHARSET_INVALID_CODE (repertory)); | ||
| 756 | } | ||
| 757 | |||
| 758 | static unsigned | ||
| 759 | xfont_encode_char (font, c) | ||
| 760 | struct font *font; | ||
| 761 | int c; | ||
| 762 | { | ||
| 763 | struct charset *charset; | ||
| 764 | unsigned code; | ||
| 765 | XChar2b char2b; | ||
| 766 | |||
| 767 | charset = CHARSET_FROM_ID (font->encoding_charset); | ||
| 768 | code = ENCODE_CHAR (charset, c); | ||
| 769 | if (code == CHARSET_INVALID_CODE (charset)) | ||
| 770 | return 0xFFFFFFFF; | ||
| 771 | if (font->repertory_charet >= 0) | ||
| 772 | { | ||
| 773 | charset = CHARSET_FROM_ID (font->repertory_charet); | ||
| 774 | return (ENCODE_CHAR (charset, c) != CHARSET_INVALID_CODE (charset) | ||
| 775 | ? code : 0xFFFFFFFF); | ||
| 776 | } | ||
| 777 | char2b.byte1 = code >> 16; | ||
| 778 | char2b.byte2 = code & 0xFFFF; | ||
| 779 | return (xfont_get_pcm (font->font.font, &char2b) ? code : 0xFFFFFFFF); | ||
| 780 | } | ||
| 781 | |||
| 782 | static int | ||
| 783 | xfont_text_extents (font, code, nglyphs, metrics) | ||
| 784 | struct font *font; | ||
| 785 | unsigned *code; | ||
| 786 | int nglyphs; | ||
| 787 | struct font_metrics *metrics; | ||
| 788 | { | ||
| 789 | int width = 0; | ||
| 790 | int i, x; | ||
| 791 | |||
| 792 | if (metrics) | ||
| 793 | bzero (metrics, sizeof (struct font_metrics)); | ||
| 794 | for (i = 0, x = 0; i < nglyphs; i++) | ||
| 795 | { | ||
| 796 | XChar2b char2b; | ||
| 797 | static XCharStruct *pcm; | ||
| 798 | |||
| 799 | if (code[i] >= 0x10000) | ||
| 800 | continue; | ||
| 801 | char2b.byte1 = code[i] >> 8, char2b.byte2 = code[i] & 0xFF; | ||
| 802 | pcm = xfont_get_pcm (font->font.font, &char2b); | ||
| 803 | if (! pcm) | ||
| 804 | continue; | ||
| 805 | if (metrics->lbearing > width + pcm->lbearing) | ||
| 806 | metrics->lbearing = width + pcm->lbearing; | ||
| 807 | if (metrics->rbearing < width + pcm->rbearing) | ||
| 808 | metrics->rbearing = width + pcm->rbearing; | ||
| 809 | if (metrics->ascent < pcm->ascent) | ||
| 810 | metrics->ascent = pcm->ascent; | ||
| 811 | if (metrics->descent < pcm->descent) | ||
| 812 | metrics->descent = pcm->descent; | ||
| 813 | width += pcm->width; | ||
| 814 | } | ||
| 815 | if (metrics) | ||
| 816 | metrics->width = width; | ||
| 817 | return width; | ||
| 818 | } | ||
| 819 | |||
| 820 | static int | ||
| 821 | xfont_draw (s, from, to, x, y, with_background) | ||
| 822 | struct glyph_string *s; | ||
| 823 | int from, to, x, y, with_background; | ||
| 824 | { | ||
| 825 | XFontStruct *xfont = s->face->font; | ||
| 826 | int len = to - from; | ||
| 827 | |||
| 828 | if (xfont->min_byte1 == 0 && xfont->max_byte1 == 0) | ||
| 829 | { | ||
| 830 | char *str; | ||
| 831 | int i; | ||
| 832 | USE_SAFE_ALLOCA; | ||
| 833 | |||
| 834 | SAFE_ALLOCA (str, char *, len); | ||
| 835 | for (i = 0; i < len ; i++) | ||
| 836 | str[i] = XCHAR2B_BYTE2 (s->char2b + from + i); | ||
| 837 | if (with_background > 0) | ||
| 838 | XDrawImageString (FRAME_X_DISPLAY (s->f), FRAME_X_WINDOW (s->f), | ||
| 839 | s->gc, x, y, str, len); | ||
| 840 | else | ||
| 841 | XDrawString (FRAME_X_DISPLAY (s->f), FRAME_X_WINDOW (s->f), | ||
| 842 | s->gc, x, y, str, len); | ||
| 843 | SAFE_FREE (); | ||
| 844 | return s->nchars; | ||
| 845 | } | ||
| 846 | |||
| 847 | if (with_background > 0) | ||
| 848 | XDrawImageString16 (FRAME_X_DISPLAY (s->f), FRAME_X_WINDOW (s->f), | ||
| 849 | s->gc, x, y, s->char2b + from, len); | ||
| 850 | else | ||
| 851 | XDrawString16 (FRAME_X_DISPLAY (s->f), FRAME_X_WINDOW (s->f), | ||
| 852 | s->gc, x, y, s->char2b + from, len); | ||
| 853 | |||
| 854 | return len; | ||
| 855 | } | ||
| 856 | |||
| 857 | |||
| 858 | |||
| 859 | void | ||
| 860 | syms_of_xfont () | ||
| 861 | { | ||
| 862 | staticpro (&x_font_charset_alist); | ||
| 863 | x_font_charset_alist = Qnil; | ||
| 864 | |||
| 865 | DEFSYM (Qx, "x"); | ||
| 866 | xfont_driver.type = Qx; | ||
| 867 | register_font_driver (&xfont_driver, NULL); | ||
| 868 | } | ||
diff --git a/src/xftfont.c b/src/xftfont.c new file mode 100644 index 00000000000..dd2b95ccd14 --- /dev/null +++ b/src/xftfont.c | |||
| @@ -0,0 +1,552 @@ | |||
| 1 | /* xftfont.c -- XFT font driver. | ||
| 2 | Copyright (C) 2006 Free Software Foundation, Inc. | ||
| 3 | Copyright (C) 2006 | ||
| 4 | National Institute of Advanced Industrial Science and Technology (AIST) | ||
| 5 | Registration Number H13PRO009 | ||
| 6 | |||
| 7 | This file is part of GNU Emacs. | ||
| 8 | |||
| 9 | GNU Emacs is free software; you can redistribute it and/or modify | ||
| 10 | it under the terms of the GNU General Public License as published by | ||
| 11 | the Free Software Foundation; either version 2, or (at your option) | ||
| 12 | any later version. | ||
| 13 | |||
| 14 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 17 | GNU General Public License for more details. | ||
| 18 | |||
| 19 | You should have received a copy of the GNU General Public License | ||
| 20 | along with GNU Emacs; see the file COPYING. If not, write to | ||
| 21 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
| 22 | Boston, MA 02110-1301, USA. */ | ||
| 23 | |||
| 24 | #include <config.h> | ||
| 25 | #include <stdio.h> | ||
| 26 | #include <X11/Xlib.h> | ||
| 27 | #include <X11/Xft/Xft.h> | ||
| 28 | |||
| 29 | #include "lisp.h" | ||
| 30 | #include "dispextern.h" | ||
| 31 | #include "xterm.h" | ||
| 32 | #include "frame.h" | ||
| 33 | #include "blockinput.h" | ||
| 34 | #include "character.h" | ||
| 35 | #include "charset.h" | ||
| 36 | #include "fontset.h" | ||
| 37 | #include "font.h" | ||
| 38 | |||
| 39 | /* Xft font driver. */ | ||
| 40 | |||
| 41 | static Lisp_Object Qxft; | ||
| 42 | |||
| 43 | /* The actual structure for Xft font that can be casted to struct | ||
| 44 | font. */ | ||
| 45 | |||
| 46 | struct xftfont_info | ||
| 47 | { | ||
| 48 | struct font font; | ||
| 49 | Display *display; | ||
| 50 | int screen; | ||
| 51 | XftFont *xftfont; | ||
| 52 | FT_Face ft_face; | ||
| 53 | }; | ||
| 54 | |||
| 55 | /* Structure pointed by (struct face *)->extra */ | ||
| 56 | struct xftface_info | ||
| 57 | { | ||
| 58 | XftColor xft_fg; | ||
| 59 | XftColor xft_bg; | ||
| 60 | XftDraw *xft_draw; | ||
| 61 | }; | ||
| 62 | |||
| 63 | static void xftfont_get_colors P_ ((FRAME_PTR, struct face *, GC gc, | ||
| 64 | struct xftface_info *, | ||
| 65 | XftColor *fg, XftColor *bg)); | ||
| 66 | static Font xftfont_default_fid P_ ((FRAME_PTR)); | ||
| 67 | |||
| 68 | |||
| 69 | /* Setup colors pointed by FG and BG for GC. If XFTFACE_INFO is not | ||
| 70 | NULL, reuse the colors in it if possible. BG may be NULL. */ | ||
| 71 | static void | ||
| 72 | xftfont_get_colors (f, face, gc, xftface_info, fg, bg) | ||
| 73 | FRAME_PTR f; | ||
| 74 | struct face *face; | ||
| 75 | GC gc; | ||
| 76 | struct xftface_info *xftface_info; | ||
| 77 | XftColor *fg, *bg; | ||
| 78 | { | ||
| 79 | if (xftface_info && face->gc == gc) | ||
| 80 | { | ||
| 81 | *fg = xftface_info->xft_fg; | ||
| 82 | if (bg) | ||
| 83 | *bg = xftface_info->xft_bg; | ||
| 84 | } | ||
| 85 | else | ||
| 86 | { | ||
| 87 | XGCValues xgcv; | ||
| 88 | int fg_done = 0, bg_done = 0; | ||
| 89 | |||
| 90 | BLOCK_INPUT; | ||
| 91 | XGetGCValues (FRAME_X_DISPLAY (f), gc, | ||
| 92 | GCForeground | GCBackground, &xgcv); | ||
| 93 | if (xftface_info) | ||
| 94 | { | ||
| 95 | if (xgcv.foreground == face->foreground) | ||
| 96 | *fg = xftface_info->xft_fg, fg_done = 1; | ||
| 97 | else if (xgcv.foreground == face->background) | ||
| 98 | *fg = xftface_info->xft_bg, fg_done = 1; | ||
| 99 | if (! bg) | ||
| 100 | bg_done = 1; | ||
| 101 | else if (xgcv.background == face->background) | ||
| 102 | *bg = xftface_info->xft_bg, bg_done = 1; | ||
| 103 | else if (xgcv.background == face->foreground) | ||
| 104 | *bg = xftface_info->xft_fg, bg_done = 1; | ||
| 105 | } | ||
| 106 | |||
| 107 | if (fg_done + bg_done < 2) | ||
| 108 | { | ||
| 109 | XColor colors[2]; | ||
| 110 | |||
| 111 | colors[0].pixel = fg->pixel = xgcv.foreground; | ||
| 112 | if (bg) | ||
| 113 | colors[1].pixel = bg->pixel = xgcv.background; | ||
| 114 | XQueryColors (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), colors, | ||
| 115 | bg ? 2 : 1); | ||
| 116 | fg->color.alpha = 0xFFFF; | ||
| 117 | fg->color.red = colors[0].red; | ||
| 118 | fg->color.green = colors[0].green; | ||
| 119 | fg->color.blue = colors[0].blue; | ||
| 120 | if (bg) | ||
| 121 | { | ||
| 122 | bg->color.alpha = 0xFFFF; | ||
| 123 | bg->color.red = colors[1].red; | ||
| 124 | bg->color.green = colors[1].green; | ||
| 125 | bg->color.blue = colors[1].blue; | ||
| 126 | } | ||
| 127 | } | ||
| 128 | UNBLOCK_INPUT; | ||
| 129 | } | ||
| 130 | } | ||
| 131 | |||
| 132 | /* Return the default Font ID on frame F. */ | ||
| 133 | |||
| 134 | static Font | ||
| 135 | xftfont_default_fid (f) | ||
| 136 | FRAME_PTR f; | ||
| 137 | { | ||
| 138 | static int fid_known; | ||
| 139 | static Font fid; | ||
| 140 | |||
| 141 | if (! fid_known) | ||
| 142 | { | ||
| 143 | fid = XLoadFont (FRAME_X_DISPLAY (f), "fixed"); | ||
| 144 | if (! fid) | ||
| 145 | { | ||
| 146 | fid = XLoadFont (FRAME_X_DISPLAY (f), "*"); | ||
| 147 | if (! fid) | ||
| 148 | abort (); | ||
| 149 | } | ||
| 150 | } | ||
| 151 | return fid; | ||
| 152 | } | ||
| 153 | |||
| 154 | |||
| 155 | static Lisp_Object xftfont_list P_ ((Lisp_Object, Lisp_Object)); | ||
| 156 | static struct font *xftfont_open P_ ((FRAME_PTR, Lisp_Object, int)); | ||
| 157 | static void xftfont_close P_ ((FRAME_PTR, struct font *)); | ||
| 158 | static int xftfont_prepare_face P_ ((FRAME_PTR, struct face *)); | ||
| 159 | static void xftfont_done_face P_ ((FRAME_PTR, struct face *)); | ||
| 160 | static unsigned xftfont_encode_char P_ ((struct font *, int)); | ||
| 161 | static int xftfont_text_extents P_ ((struct font *, unsigned *, int, | ||
| 162 | struct font_metrics *)); | ||
| 163 | static int xftfont_draw P_ ((struct glyph_string *, int, int, int, int, int)); | ||
| 164 | |||
| 165 | static int xftfont_anchor_point P_ ((struct font *, unsigned, int, | ||
| 166 | int *, int *)); | ||
| 167 | |||
| 168 | struct font_driver xftfont_driver; | ||
| 169 | |||
| 170 | static Lisp_Object | ||
| 171 | xftfont_list (frame, spec) | ||
| 172 | Lisp_Object frame; | ||
| 173 | Lisp_Object spec; | ||
| 174 | { | ||
| 175 | Lisp_Object val = ftfont_driver.list (frame, spec); | ||
| 176 | |||
| 177 | if (! NILP (val)) | ||
| 178 | { | ||
| 179 | int i; | ||
| 180 | |||
| 181 | for (i = 0; i < ASIZE (val); i++) | ||
| 182 | ASET (AREF (val, i), FONT_TYPE_INDEX, Qxft); | ||
| 183 | } | ||
| 184 | return val; | ||
| 185 | } | ||
| 186 | |||
| 187 | static FcChar8 ascii_printable[95]; | ||
| 188 | |||
| 189 | static struct font * | ||
| 190 | xftfont_open (f, entity, pixel_size) | ||
| 191 | FRAME_PTR f; | ||
| 192 | Lisp_Object entity; | ||
| 193 | int pixel_size; | ||
| 194 | { | ||
| 195 | Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f); | ||
| 196 | Display *display = FRAME_X_DISPLAY (f); | ||
| 197 | Lisp_Object val; | ||
| 198 | FcPattern *pattern, *pat; | ||
| 199 | FcChar8 *file; | ||
| 200 | XFontStruct *xfont; | ||
| 201 | struct xftfont_info *xftfont_info; | ||
| 202 | struct font *font; | ||
| 203 | double size = 0; | ||
| 204 | XftFont *xftfont; | ||
| 205 | int spacing; | ||
| 206 | |||
| 207 | val = AREF (entity, FONT_EXTRA_INDEX); | ||
| 208 | if (XTYPE (val) != Lisp_Misc | ||
| 209 | || XMISCTYPE (val) != Lisp_Misc_Save_Value) | ||
| 210 | return NULL; | ||
| 211 | pattern = XSAVE_VALUE (val)->pointer; | ||
| 212 | if (FcPatternGetString (pattern, FC_FILE, 0, &file) != FcResultMatch) | ||
| 213 | return NULL; | ||
| 214 | |||
| 215 | size = XINT (AREF (entity, FONT_SIZE_INDEX)); | ||
| 216 | if (size == 0) | ||
| 217 | size = pixel_size; | ||
| 218 | pat = FcPatternCreate (); | ||
| 219 | FcPatternAddString (pat, FC_FILE, file); | ||
| 220 | FcPatternAddDouble (pat, FC_PIXEL_SIZE, pixel_size); | ||
| 221 | FcPatternAddBool (pat, FC_ANTIALIAS, FcTrue); | ||
| 222 | xftfont = XftFontOpenPattern (display, pat); | ||
| 223 | /* We should not destroy PAT here because it is kept in XFTFONT and | ||
| 224 | destroyed automatically when XFTFONT is closed. */ | ||
| 225 | if (! xftfont) | ||
| 226 | return NULL; | ||
| 227 | |||
| 228 | xftfont_info = malloc (sizeof (struct xftfont_info)); | ||
| 229 | if (! xftfont_info) | ||
| 230 | { | ||
| 231 | XftFontClose (display, xftfont); | ||
| 232 | return NULL; | ||
| 233 | } | ||
| 234 | xfont = malloc (sizeof (XFontStruct)); | ||
| 235 | if (! xftfont_info) | ||
| 236 | { | ||
| 237 | XftFontClose (display, xftfont); | ||
| 238 | free (xftfont_info); | ||
| 239 | return NULL; | ||
| 240 | } | ||
| 241 | xftfont_info->display = display; | ||
| 242 | xftfont_info->screen = FRAME_X_SCREEN_NUMBER (f); | ||
| 243 | xftfont_info->xftfont = xftfont; | ||
| 244 | xftfont_info->ft_face = XftLockFace (xftfont); | ||
| 245 | |||
| 246 | font = (struct font *) xftfont_info; | ||
| 247 | font->entity = entity; | ||
| 248 | font->pixel_size = size; | ||
| 249 | font->driver = &xftfont_driver; | ||
| 250 | font->font.name = font->font.full_name = NULL; | ||
| 251 | font->file_name = (char *) file; | ||
| 252 | font->font.size = xftfont->max_advance_width; | ||
| 253 | font->ascent = xftfont->ascent; | ||
| 254 | font->descent = xftfont->descent; | ||
| 255 | font->font.height = xftfont->ascent + xftfont->descent; | ||
| 256 | |||
| 257 | if (FcPatternGetInteger (xftfont->pattern, FC_SPACING, 0, &spacing) | ||
| 258 | != FcResultMatch) | ||
| 259 | spacing = FC_PROPORTIONAL; | ||
| 260 | if (spacing != FC_PROPORTIONAL) | ||
| 261 | font->font.average_width = font->font.space_width | ||
| 262 | = xftfont->max_advance_width; | ||
| 263 | else | ||
| 264 | { | ||
| 265 | XGlyphInfo extents; | ||
| 266 | |||
| 267 | if (! ascii_printable[0]) | ||
| 268 | { | ||
| 269 | int i; | ||
| 270 | for (i = 0; i < 95; i++) | ||
| 271 | ascii_printable[i] = ' ' + i; | ||
| 272 | } | ||
| 273 | XftTextExtents8 (display, xftfont, ascii_printable, 1, &extents); | ||
| 274 | font->font.space_width = extents.xOff; | ||
| 275 | if (font->font.space_width <= 0) | ||
| 276 | /* dirty workaround */ | ||
| 277 | font->font.space_width = pixel_size; | ||
| 278 | XftTextExtents8 (display, xftfont, ascii_printable + 1, 94, &extents); | ||
| 279 | font->font.average_width = (font->font.space_width + extents.xOff) / 95; | ||
| 280 | } | ||
| 281 | |||
| 282 | /* Unfortunately Xft doesn't provide a way to get minimum char | ||
| 283 | width. So, we use space_width instead. */ | ||
| 284 | font->min_width = font->font.space_width; | ||
| 285 | |||
| 286 | font->font.baseline_offset = 0; | ||
| 287 | font->font.relative_compose = 0; | ||
| 288 | font->font.default_ascent = 0; | ||
| 289 | font->font.vertical_centering = 0; | ||
| 290 | |||
| 291 | /* Setup pseudo XFontStruct */ | ||
| 292 | xfont->fid = xftfont_default_fid (f); | ||
| 293 | xfont->ascent = xftfont->ascent; | ||
| 294 | xfont->descent = xftfont->descent; | ||
| 295 | xfont->max_bounds.descent = xftfont->descent; | ||
| 296 | xfont->max_bounds.width = xftfont->max_advance_width; | ||
| 297 | xfont->min_bounds.width = font->font.space_width; | ||
| 298 | font->font.font = xfont; | ||
| 299 | |||
| 300 | dpyinfo->n_fonts++; | ||
| 301 | |||
| 302 | /* Set global flag fonts_changed_p to non-zero if the font loaded | ||
| 303 | has a character with a smaller width than any other character | ||
| 304 | before, or if the font loaded has a smaller height than any other | ||
| 305 | font loaded before. If this happens, it will make a glyph matrix | ||
| 306 | reallocation necessary. */ | ||
| 307 | if (dpyinfo->n_fonts == 1) | ||
| 308 | { | ||
| 309 | dpyinfo->smallest_font_height = font->font.height; | ||
| 310 | dpyinfo->smallest_char_width = font->min_width; | ||
| 311 | fonts_changed_p = 1; | ||
| 312 | } | ||
| 313 | else | ||
| 314 | { | ||
| 315 | if (dpyinfo->smallest_font_height > font->font.height) | ||
| 316 | dpyinfo->smallest_font_height = font->font.height, | ||
| 317 | fonts_changed_p |= 1; | ||
| 318 | if (dpyinfo->smallest_char_width > font->min_width) | ||
| 319 | dpyinfo->smallest_char_width = font->min_width, | ||
| 320 | fonts_changed_p |= 1; | ||
| 321 | } | ||
| 322 | |||
| 323 | return font; | ||
| 324 | } | ||
| 325 | |||
| 326 | static void | ||
| 327 | xftfont_close (f, font) | ||
| 328 | FRAME_PTR f; | ||
| 329 | struct font *font; | ||
| 330 | { | ||
| 331 | struct xftfont_info *xftfont_info = (struct xftfont_info *) font; | ||
| 332 | |||
| 333 | XftUnlockFace (xftfont_info->xftfont); | ||
| 334 | XftFontClose (xftfont_info->display, xftfont_info->xftfont); | ||
| 335 | free (font); | ||
| 336 | FRAME_X_DISPLAY_INFO (f)->n_fonts--; | ||
| 337 | } | ||
| 338 | |||
| 339 | struct xftdraw_list | ||
| 340 | { | ||
| 341 | XftDraw *xftdraw; | ||
| 342 | struct xftdraw_list *next; | ||
| 343 | }; | ||
| 344 | |||
| 345 | static struct xftdraw_list *xftdraw_list; | ||
| 346 | |||
| 347 | static void | ||
| 348 | register_xftdraw (xftdraw) | ||
| 349 | XftDraw *xftdraw; | ||
| 350 | { | ||
| 351 | struct xftdraw_list *list = malloc (sizeof (struct xftdraw_list)); | ||
| 352 | |||
| 353 | list->xftdraw = xftdraw; | ||
| 354 | list->next = xftdraw_list; | ||
| 355 | xftdraw_list = list; | ||
| 356 | } | ||
| 357 | |||
| 358 | static void | ||
| 359 | check_xftdraw (xftdraw) | ||
| 360 | XftDraw *xftdraw; | ||
| 361 | { | ||
| 362 | struct xftdraw_list *list, *prev; | ||
| 363 | |||
| 364 | for (list = xftdraw_list, prev = NULL; list; prev = list, list = list->next) | ||
| 365 | { | ||
| 366 | if (list->xftdraw == xftdraw) | ||
| 367 | { | ||
| 368 | if (! prev) | ||
| 369 | { | ||
| 370 | list = xftdraw_list->next; | ||
| 371 | free (xftdraw_list); | ||
| 372 | xftdraw_list = list; | ||
| 373 | } | ||
| 374 | else | ||
| 375 | { | ||
| 376 | prev->next = list->next; | ||
| 377 | free (list); | ||
| 378 | list = prev; | ||
| 379 | } | ||
| 380 | return; | ||
| 381 | } | ||
| 382 | } | ||
| 383 | abort (); | ||
| 384 | } | ||
| 385 | |||
| 386 | static int | ||
| 387 | xftfont_prepare_face (f, face) | ||
| 388 | FRAME_PTR f; | ||
| 389 | struct face *face; | ||
| 390 | { | ||
| 391 | struct xftface_info *xftface_info = malloc (sizeof (struct xftface_info)); | ||
| 392 | |||
| 393 | if (! xftface_info) | ||
| 394 | return -1; | ||
| 395 | |||
| 396 | BLOCK_INPUT; | ||
| 397 | xftface_info->xft_draw = XftDrawCreate (FRAME_X_DISPLAY (f), | ||
| 398 | FRAME_X_WINDOW (f), | ||
| 399 | FRAME_X_VISUAL (f), | ||
| 400 | FRAME_X_COLORMAP (f)); | ||
| 401 | register_xftdraw (xftface_info->xft_draw); | ||
| 402 | |||
| 403 | xftfont_get_colors (f, face, face->gc, NULL, | ||
| 404 | &xftface_info->xft_fg, &xftface_info->xft_bg); | ||
| 405 | UNBLOCK_INPUT; | ||
| 406 | |||
| 407 | face->extra = xftface_info; | ||
| 408 | return 0; | ||
| 409 | } | ||
| 410 | |||
| 411 | static void | ||
| 412 | xftfont_done_face (f, face) | ||
| 413 | FRAME_PTR f; | ||
| 414 | struct face *face; | ||
| 415 | { | ||
| 416 | struct xftface_info *xftface_info = (struct xftface_info *) face->extra; | ||
| 417 | |||
| 418 | if (xftface_info) | ||
| 419 | { | ||
| 420 | BLOCK_INPUT; | ||
| 421 | check_xftdraw (xftface_info->xft_draw); | ||
| 422 | XftDrawDestroy (xftface_info->xft_draw); | ||
| 423 | UNBLOCK_INPUT; | ||
| 424 | free (xftface_info); | ||
| 425 | face->extra = NULL; | ||
| 426 | } | ||
| 427 | } | ||
| 428 | |||
| 429 | static unsigned | ||
| 430 | xftfont_encode_char (font, c) | ||
| 431 | struct font *font; | ||
| 432 | int c; | ||
| 433 | { | ||
| 434 | struct xftfont_info *xftfont_info = (struct xftfont_info *) font; | ||
| 435 | unsigned code = XftCharIndex (xftfont_info->display, xftfont_info->xftfont, | ||
| 436 | (FcChar32) c); | ||
| 437 | |||
| 438 | return (code ? code : 0xFFFFFFFF); | ||
| 439 | } | ||
| 440 | |||
| 441 | static int | ||
| 442 | xftfont_text_extents (font, code, nglyphs, metrics) | ||
| 443 | struct font *font; | ||
| 444 | unsigned *code; | ||
| 445 | int nglyphs; | ||
| 446 | struct font_metrics *metrics; | ||
| 447 | { | ||
| 448 | struct xftfont_info *xftfont_info = (struct xftfont_info *) font; | ||
| 449 | XGlyphInfo extents; | ||
| 450 | |||
| 451 | BLOCK_INPUT; | ||
| 452 | XftGlyphExtents (xftfont_info->display, xftfont_info->xftfont, code, nglyphs, | ||
| 453 | &extents); | ||
| 454 | UNBLOCK_INPUT; | ||
| 455 | if (metrics) | ||
| 456 | { | ||
| 457 | metrics->lbearing = - extents.x; | ||
| 458 | metrics->rbearing = - extents.x + extents.width; | ||
| 459 | metrics->width = extents.xOff; | ||
| 460 | metrics->ascent = extents.y; | ||
| 461 | metrics->descent = extents.y - extents.height; | ||
| 462 | } | ||
| 463 | return extents.xOff; | ||
| 464 | } | ||
| 465 | |||
| 466 | static int | ||
| 467 | xftfont_draw (s, from, to, x, y, with_background) | ||
| 468 | struct glyph_string *s; | ||
| 469 | int from, to, x, y, with_background; | ||
| 470 | { | ||
| 471 | FRAME_PTR f = s->f; | ||
| 472 | struct face *face = s->face; | ||
| 473 | struct xftfont_info *xftfont_info = (struct xftfont_info *) face->font_info; | ||
| 474 | struct xftface_info *xftface_info = (struct xftface_info *) face->extra; | ||
| 475 | FT_UInt *code; | ||
| 476 | XftColor fg, bg; | ||
| 477 | XRectangle r; | ||
| 478 | int len = to - from; | ||
| 479 | int i; | ||
| 480 | |||
| 481 | xftfont_get_colors (f, face, s->gc, xftface_info, | ||
| 482 | &fg, s->width ? &bg : NULL); | ||
| 483 | BLOCK_INPUT; | ||
| 484 | if (s->clip_width) | ||
| 485 | { | ||
| 486 | r.x = s->clip_x, r.width = s->clip_width; | ||
| 487 | r.y = s->clip_y, r.height = s->clip_height; | ||
| 488 | XftDrawSetClipRectangles (xftface_info->xft_draw, 0, 0, &r, 1); | ||
| 489 | } | ||
| 490 | if (with_background) | ||
| 491 | { | ||
| 492 | struct font *font = (struct font *) face->font_info; | ||
| 493 | |||
| 494 | XftDrawRect (xftface_info->xft_draw, &bg, | ||
| 495 | x, y - face->font->ascent, s->width, font->font.height); | ||
| 496 | } | ||
| 497 | code = alloca (sizeof (FT_UInt) * len); | ||
| 498 | for (i = 0; i < len; i++) | ||
| 499 | code[i] = ((XCHAR2B_BYTE1 (s->char2b + from + i) << 8) | ||
| 500 | | XCHAR2B_BYTE2 (s->char2b + from + i)); | ||
| 501 | |||
| 502 | XftDrawGlyphs (xftface_info->xft_draw, &fg, xftfont_info->xftfont, | ||
| 503 | x, y, code, len); | ||
| 504 | if (s->clip_width) | ||
| 505 | XftDrawSetClip (xftface_info->xft_draw, NULL); | ||
| 506 | UNBLOCK_INPUT; | ||
| 507 | |||
| 508 | return len; | ||
| 509 | } | ||
| 510 | |||
| 511 | static int | ||
| 512 | xftfont_anchor_point (font, code, index, x, y) | ||
| 513 | struct font *font; | ||
| 514 | unsigned code; | ||
| 515 | int index; | ||
| 516 | int *x, *y; | ||
| 517 | { | ||
| 518 | struct xftfont_info *xftfont_info = (struct xftfont_info *) font; | ||
| 519 | FT_Face ft_face = xftfont_info->ft_face; | ||
| 520 | |||
| 521 | if (FT_Load_Glyph (ft_face, code, FT_LOAD_DEFAULT) != 0) | ||
| 522 | return -1; | ||
| 523 | if (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE) | ||
| 524 | return -1; | ||
| 525 | if (index >= ft_face->glyph->outline.n_points) | ||
| 526 | return -1; | ||
| 527 | *x = ft_face->glyph->outline.points[index].x; | ||
| 528 | *y = ft_face->glyph->outline.points[index].y; | ||
| 529 | return 0; | ||
| 530 | } | ||
| 531 | |||
| 532 | |||
| 533 | void | ||
| 534 | syms_of_xftfont () | ||
| 535 | { | ||
| 536 | DEFSYM (Qxft, "xft"); | ||
| 537 | |||
| 538 | xftfont_driver = ftfont_driver; | ||
| 539 | xftfont_driver.type = Qxft; | ||
| 540 | xftfont_driver.get_cache = xfont_driver.get_cache; | ||
| 541 | xftfont_driver.list = xftfont_list; | ||
| 542 | xftfont_driver.open = xftfont_open; | ||
| 543 | xftfont_driver.close = xftfont_close; | ||
| 544 | xftfont_driver.prepare_face = xftfont_prepare_face; | ||
| 545 | xftfont_driver.done_face = xftfont_done_face; | ||
| 546 | xftfont_driver.encode_char = xftfont_encode_char; | ||
| 547 | xftfont_driver.text_extents = xftfont_text_extents; | ||
| 548 | xftfont_driver.draw = xftfont_draw; | ||
| 549 | xftfont_driver.anchor_point = xftfont_anchor_point; | ||
| 550 | |||
| 551 | register_font_driver (&xftfont_driver, NULL); | ||
| 552 | } | ||