Mercurial > hg > xemacs-beta
changeset 3659:98af8a976fc3
[xemacs-hg @ 2006-11-05 22:31:31 by aidan]
Support specifying fonts for particular character sets in Mule; support
translation to ISO 10646-1 for Mule character sets without an otherwise
matching font; move to a vector of X11-charset-X11-registry instead of a
regex for the charset-registry property.
author | aidan |
---|---|
date | Sun, 05 Nov 2006 22:31:46 +0000 |
parents | 0db1aaedbbef |
children | def257d9e948 |
files | lisp/ChangeLog lisp/faces.el lisp/mule/arabic.el lisp/mule/chinese.el lisp/mule/english.el lisp/mule/ethiopic.el lisp/mule/european.el lisp/mule/indian.el lisp/mule/japanese.el lisp/mule/lao.el lisp/mule/misc-lang.el lisp/mule/mule-charset.el lisp/mule/thai-xtis.el lisp/mule/tibetan.el lisp/mule/vietnamese.el lisp/unicode.el lisp/x-faces.el lisp/x-font-menu.el src/ChangeLog src/charset.h src/console-impl.h src/faces.c src/faces.h src/font-mgr.h src/general-slots.h src/intl.c src/lisp.h src/mule-charset.c src/objects-gtk.c src/objects-msw.c src/objects-tty.c src/objects-x.c src/objects-xlike-inc.c src/objects.c src/objects.h src/redisplay-x.c src/redisplay.c src/specifier.c src/specifier.h src/unicode.c |
diffstat | 40 files changed, 2485 insertions(+), 1476 deletions(-) [+] |
line wrap: on
line diff
--- a/lisp/ChangeLog Sat Nov 04 22:51:03 2006 +0000 +++ b/lisp/ChangeLog Sun Nov 05 22:31:46 2006 +0000 @@ -1,3 +1,61 @@ +2006-11-05 Aidan Kehoe <kehoea@parhasard.net> + + * mule/arabic.el (arabic-digit): + * mule/arabic.el (arabic-1-column): + * mule/arabic.el (arabic-2-column): + * mule/chinese.el (make-chinese-cns11643-charset): + * mule/chinese.el (chinese-sisheng): + * mule/english.el (ascii-right-to-left): + * mule/ethiopic.el (ethiopic): + * mule/european.el (latin-iso8859-14): + * mule/european.el (latin-iso8859-16): + * mule/indian.el (indian-is13194): + * mule/indian.el (indian-1-column): + * mule/indian.el (indian-2-column): + * mule/japanese.el (japanese-jisx0213-1): + * mule/japanese.el (japanese-jisx0213-2): + * mule/lao.el (lao): + * mule/misc-lang.el (ipa): + * mule/mule-charset.el: + * mule/thai-xtis.el (thai-xtis): + * mule/tibetan.el (tibetan-1-column): + * mule/tibetan.el (tibetan): + * mule/vietnamese.el (vietnamese-viscii-lower): + * mule/vietnamese.el (vietnamese-viscii-upper): + Stop using the `registry' charset property; use `registries' + instead. The difference is that registries is an ordered vector of + X11 registries and encodings rather than a regexp; this means we + can leave the matching to the X11 server, avoiding transferring + huge amounts of data (perhaps across the network!) in order to do + a regexp search on it. + * mule/mule-charset.el (charset-registries): New. + charset-registries returns the registries of a charset; + * mule/mule-charset.el (set-charset-registry): Moved here from C. + +2006-11-05 Aidan Kehoe <kehoea@parhasard.net> + + * faces.el (face-property-matching-instance): + Simplify. + * faces.el (face-font-instance): + Document CHARSET. + * faces.el (set-face-font): + Give more details on common values for font instantiators, + LOCALEs. + * unicode.el: + Remove a few comments that were only relevant to GNU Emacs. + * unicode.el (decode-char): + * unicode.el (encode-char): + Document CODE, CHAR using uppercase, since they're + parameters. Update commentary on GNU's mule-unicode charsets and + how we've solved the same problem. + * x-faces.el (x-init-face-from-resources): + Retain some of the fallbacks in the generated default face, since + it doesn't make sense to try Andale Mono's ISO-10646-1 encoding + for Amharic or Thai. + * x-font-menu.el (charset-registries): + * x-font-menu.el (x-reset-device-font-menus-core): + Use charset-registries instead of charset-registry. + 2006-11-02 Adrian Aichner <adrian@xemacs.org> * font-lock.el: Sync font-lock-add-keywords and
--- a/lisp/faces.el Sat Nov 04 22:51:03 2006 +0000 +++ b/lisp/faces.el Sun Nov 05 22:31:46 2006 +0000 @@ -250,19 +250,9 @@ (setq face (get-face face)) (let ((value (get face property))) - (if (specifierp value) - (setq value (if (or (charsetp matchspec) - (and (symbolp matchspec) - (find-charset matchspec))) - (or - (specifier-matching-instance - value (cons matchspec nil) domain default - no-fallback) - (specifier-matching-instance - value (cons matchspec t) domain default - no-fallback)) - (specifier-matching-instance value matchspec domain - default no-fallback)))) + (when (specifierp value) + (setq value (specifier-matching-instance value matchspec domain + default no-fallback))) value)) (defun set-face-property (face property value &optional locale tag-set @@ -473,25 +463,40 @@ and an instance object describing how the font appears in that particular window and buffer will be returned. +CHARSET is a Mule charset (meaning return the font used for that charset) or +nil (meaning return the font used for ASCII.) + See `face-property-instance' for more information." - (if charset - (face-property-matching-instance face 'font charset domain) - (face-property-instance face 'font domain))) + (if (null charset) + (face-property-instance face 'font domain) + (let (matchspec) + ;; get-charset signals an error if its argument doesn't have an + ;; associated charset. + (setq charset (get-charset charset) + matchspec (cons charset nil)) + (or (null (setcdr matchspec 'initial)) + (face-property-matching-instance + face 'font matchspec domain) + (null (setcdr matchspec 'final)) + (face-property-matching-instance + face 'font matchspec domain))))) (defun set-face-font (face font &optional locale tag-set how-to-add) "Change the font of FACE to FONT in LOCALE. FACE may be either a face object or a symbol representing a face. -FONT should be an instantiator (see `make-font-specifier'), a list of - instantiators, an alist of specifications (each mapping a - locale to an instantiator list), or a font specifier object. +FONT should be an instantiator (see `make-font-specifier'; a common + instantiator is a platform-dependent string naming the font), a list + of instantiators, an alist of specifications (each mapping a locale + to an instantiator list), or a font specifier object. -If FONT is an alist, LOCALE must be omitted. If FONT is a - specifier object, LOCALE can be a locale, a locale type, `all', - or nil; see `copy-specifier' for its semantics. Otherwise LOCALE - specifies the locale under which the specified instantiator(s) - will be added, and defaults to `global'. +If FONT is an alist, LOCALE must be omitted. If FONT is a specifier + object, LOCALE can be a locale, a locale type, `all', or nil; see + `copy-specifier' for its semantics. Common LOCALEs are buffer + objects, window objects, device objects and `global'. Otherwise + LOCALE specifies the locale under which the specified + instantiator(s) will be added, and defaults to `global'. See `set-face-property' for more information." (interactive (face-interactive "font"))
--- a/lisp/mule/arabic.el Sat Nov 04 22:51:03 2006 +0000 +++ b/lisp/mule/arabic.el Sun Nov 05 22:31:46 2006 +0000 @@ -47,9 +47,8 @@ ;; Others are of direction right-to-left and of width 1-column or ;; 2-column. (make-charset 'arabic-digit "Arabic digit" - '(dimension - 1 - registry "MuleArabic-0" + '(dimension 1 + registries ["MuleArabic-0"] chars 94 columns 1 direction l2r @@ -62,7 +61,7 @@ (make-charset 'arabic-1-column "Arabic 1-column" '(dimension 1 - registry "MuleArabic-1" + registries ["MuleArabic-1"] chars 94 columns 1 direction r2l @@ -75,7 +74,7 @@ (make-charset 'arabic-2-column "Arabic 2-column" '(dimension 1 - registry "MuleArabic-2" + registries ["MuleArabic-2"] chars 94 columns 2 direction r2l
--- a/lisp/mule/chinese.el Sat Nov 04 22:51:03 2006 +0000 +++ b/lisp/mule/chinese.el Sun Nov 05 22:31:46 2006 +0000 @@ -146,8 +146,8 @@ (name plane final) (make-charset name (concat "CNS 11643 Plane " plane " (Chinese traditional)") - `(registry - ,(concat "CNS11643[.-]\\(.*[.-]\\)?" plane "$") + `(registries + ,(vector (concat "cns11643.1992-" plane )) dimension 2 chars 94 final ,final @@ -171,7 +171,7 @@ (make-charset ;; not in FSF 21.1 'chinese-isoir165 "ISO-IR-165 (CCITT Extended GB; Chinese simplified)" - `(registry "isoir165" + `(registries ["isoir165-0"] dimension 2 chars 94 final ?E @@ -185,7 +185,7 @@ '(dimension 1 ;; XEmacs addition: second half of registry spec - registry "sisheng_cwnn\\|OMRON_UDC_ZH" + registries ["omron_udc_zh-0" "sisheng_cwnn-0"] chars 94 columns 1 direction l2r
--- a/lisp/mule/english.el Sat Nov 04 22:51:03 2006 +0000 +++ b/lisp/mule/english.el Sun Nov 05 22:31:46 2006 +0000 @@ -36,7 +36,7 @@ "ASCII (left half of ISO 8859-1) with right-to-left direction" '(dimension 1 - registry "ISO8859-1" + registries ["ISO8859-1"] chars 94 columns 1 direction r2l
--- a/lisp/mule/ethiopic.el Sat Nov 04 22:51:03 2006 +0000 +++ b/lisp/mule/ethiopic.el Sun Nov 05 22:31:46 2006 +0000 @@ -32,7 +32,7 @@ (make-charset 'ethiopic "Ethiopic characters" '(dimension 2 - registry "Ethiopic-Unicode" + registries ["Ethiopic-Unicode"] chars 94 columns 2 direction l2r @@ -83,4 +83,7 @@ (sample-text . "$(3$Q#U!.(B") (documentation . t))) +;; In a more ideal world, we could set the default face fallback from here +;; to use one of the misc-fixed sizes that handles Ethiopic. + ;;; ethiopic.el ends here
--- a/lisp/mule/european.el Sat Nov 04 22:51:03 2006 +0000 +++ b/lisp/mule/european.el Sun Nov 05 22:31:46 2006 +0000 @@ -121,7 +121,7 @@ "Right-Hand Part of Latin Alphabet 8 (ISO/IEC 8859-14)" '(dimension 1 - registry "ISO8859-14" + registries ["ISO8859-14"] chars 96 columns 1 direction l2r @@ -135,7 +135,7 @@ "Right-Hand Part of Latin Alphabet 10 (ISO/IEC 8859-16)" '(dimension 1 - registry "ISO8859-16" + registries ["ISO8859-16"] chars 96 columns 1 direction l2r
--- a/lisp/mule/indian.el Sat Nov 04 22:51:03 2006 +0000 +++ b/lisp/mule/indian.el Sun Nov 05 22:31:46 2006 +0000 @@ -99,7 +99,7 @@ "Generic Indian charset for data exchange with IS 13194" '(dimension 1 - registry "IS13194-Devanagari" + registries ["IS13194-Devanagari"] chars 94 columns 2 direction l2r @@ -114,7 +114,7 @@ "Indian charset for 2-column width glyphs" '(dimension 2 - registry "MuleIndian-1" + registries ["MuleIndian-1"] chars 94 columns 1 direction l2r @@ -129,7 +129,7 @@ "Indian charset for 2-column width glyphs" '(dimension 2 - registry "MuleIndian-2" + registries ["MuleIndian-2"] chars 94 columns 2 direction l2r
--- a/lisp/mule/japanese.el Sat Nov 04 22:51:03 2006 +0000 +++ b/lisp/mule/japanese.el Sun Nov 05 22:31:46 2006 +0000 @@ -33,80 +33,10 @@ ;;; Code: -; (make-charset 'katakana-jisx0201 -; "Katakana Part of JISX0201.1976" -; '(dimension -; 1 -; registry "JISX0201" -; chars 94 -; columns 1 -; direction l2r -; final ?I -; graphic 1 -; short-name "JISX0201 Katakana" -; long-name "Japanese Katakana (JISX0201.1976)" -; )) - -; (make-charset 'latin-jisx0201 -; "Roman Part of JISX0201.1976" -; '(dimension -; 1 -; registry "JISX0201" -; chars 94 -; columns 1 -; direction l2r -; final ?J -; graphic 0 -; short-name "JISX0201 Roman" -; long-name "Japanese Roman (JISX0201.1976)" -; )) - -; (make-charset 'japanese-jisx0208-1978 -; "JISX0208.1978 Japanese Kanji (so called \"old JIS\"): ISO-IR-42" -; '(dimension -; 2 -; registry "JISX0208.1990" -; registry "JISX0208.1978" -; chars 94 -; columns 2 -; direction l2r -; final ?@ -; graphic 0 -; short-name "JISX0208.1978" -; long-name "JISX0208.1978 (Japanese): ISO-IR-42" -; )) - -; (make-charset 'japanese-jisx0208 -; "JISX0208.1983/1990 Japanese Kanji: ISO-IR-87" -; '(dimension -; 2 -; chars 94 -; columns 2 -; direction l2r -; final ?B -; graphic 0 -; short-name "JISX0208" -; long-name "JISX0208.1983/1990 (Japanese): ISO-IR-87" -; )) - -; (make-charset 'japanese-jisx0212 -; "JISX0212 Japanese supplement: ISO-IR-159" -; '(dimension -; 2 -; registry "JISX0212" -; chars 94 -; columns 2 -; direction l2r -; final ?D -; graphic 0 -; short-name "JISX0212" -; long-name "JISX0212 (Japanese): ISO-IR-159" -; )) - (make-charset 'japanese-jisx0213-1 "JISX0213 Plane 1 (Japanese)" '(dimension 2 - registry "JISX0213.2000-1" + registries ["JISX0213.2000-1"] chars 94 columns 2 direction l2r @@ -120,7 +50,7 @@ (make-charset 'japanese-jisx0213-2 "JISX0213 Plane 2 (Japanese)" '(dimension 2 - registry "JISX0213.2000-2" + registries ["JISX0213.2000-2"] chars 94 columns 2 direction l2r
--- a/lisp/mule/lao.el Sat Nov 04 22:51:03 2006 +0000 +++ b/lisp/mule/lao.el Sun Nov 05 22:31:46 2006 +0000 @@ -33,7 +33,7 @@ (make-charset 'lao "Lao characters (ISO10646 0E80..0EDF)" '(dimension 1 - registry "MuleLao-1" + registries ["MuleLao-1"] chars 94 columns 1 direction l2r
--- a/lisp/mule/misc-lang.el Sat Nov 04 22:51:03 2006 +0000 +++ b/lisp/mule/misc-lang.el Sun Nov 05 22:31:46 2006 +0000 @@ -34,7 +34,7 @@ (make-charset 'ipa "IPA (International Phonetic Association)" '(dimension 1 - registry "MuleIPA" + registries ["MuleIPA"] chars 96 columns 1 direction l2r
--- a/lisp/mule/mule-charset.el Sat Nov 04 22:51:03 2006 +0000 +++ b/lisp/mule/mule-charset.el Sun Nov 05 22:31:46 2006 +0000 @@ -106,12 +106,31 @@ 0 1)) -;; Not in Emacs/Mule +;; Not in GNU Emacs/Mule (defun charset-registry (charset) "Return the registry of CHARSET. This is a regular expression matching the registry field of fonts that can display the characters in CHARSET." - (charset-property charset 'registry)) + (lwarn 'xintl 'warning + "charset-registry is obsolete--use charset-registries instead. ") + (when (charset-property charset 'registries) + (elt (charset-property charset 'registries) 0))) + +(defun charset-registries (charset) + "Return the registries of CHARSET." + (charset-property charset 'registries)) + +(defun set-charset-registry (charset registry) + "Obsolete; use set-charset-registries instead. " + (check-argument-type 'stringp registry) + (check-argument-type 'charsetp (find-charset charset)) + (unless (equal registry (regexp-quote registry)) + (lwarn 'xintl 'warning + "Regexps no longer allowed for charset-registry. Treating %s%s" + registry " as a string.")) + (set-charset-registries + charset + (apply 'vector registry (append (charset-registries charset) nil)))) (defun charset-ccl-program (charset) "Return the CCL program of CHARSET.
--- a/lisp/mule/thai-xtis.el Sat Nov 04 22:51:03 2006 +0000 +++ b/lisp/mule/thai-xtis.el Sun Nov 05 22:31:46 2006 +0000 @@ -35,12 +35,12 @@ ;;; Code: (make-charset 'thai-xtis "Precomposed Thai (XTIS by Virach)." - '(registry "xtis-0" - dimension 2 - columns 1 - chars 94 - final ?? - graphic 0)) + '(registries ["xtis-0"] + dimension 2 + columns 1 + chars 94 + final ?? + graphic 0)) (define-category ?x "Precomposed Thai character.") (modify-category-entry 'thai-xtis ?x)
--- a/lisp/mule/tibetan.el Sat Nov 04 22:51:03 2006 +0000 +++ b/lisp/mule/tibetan.el Sun Nov 05 22:31:46 2006 +0000 @@ -87,7 +87,7 @@ (make-charset 'tibetan-1-column "Tibetan 1 column glyph" '(dimension 2 - registry "MuleTibetan-1" + registries ["MuleTibetan-1"] chars 94 columns 1 direction l2r @@ -101,7 +101,7 @@ (make-charset 'tibetan "Tibetan characters" '(dimension 2 - registry "MuleTibetan-2" + registries ["MuleTibetan-2"] chars 94 columns 2 direction l2r
--- a/lisp/mule/vietnamese.el Sat Nov 04 22:51:03 2006 +0000 +++ b/lisp/mule/vietnamese.el Sun Nov 05 22:31:46 2006 +0000 @@ -37,7 +37,7 @@ (make-charset 'vietnamese-viscii-lower "VISCII1.1 lower-case" '(dimension 1 - registry "VISCII1.1" + registries ["VISCII1.1"] chars 96 columns 1 direction l2r @@ -50,7 +50,7 @@ (make-charset 'vietnamese-viscii-upper "VISCII1.1 upper-case" '(dimension 1 - registry "VISCII1.1" + registries ["VISCII1.1"] chars 96 columns 1 direction l2r
--- a/lisp/unicode.el Sat Nov 04 22:51:03 2006 +0000 +++ b/lisp/unicode.el Sun Nov 05 22:31:46 2006 +0000 @@ -29,53 +29,18 @@ ;;; Code: -; ;; Subsets of Unicode. +;; GNU Emacs has the charsets: -; #### what is this bogosity ... "chars 96, final ?2" !!?! -; (make-charset 'mule-unicode-2500-33ff -; "Unicode characters of the range U+2500..U+33FF." -; '(dimension -; 2 -; registry "ISO10646-1" -; chars 96 -; columns 1 -; direction l2r -; final ?2 -; graphic 0 -; short-name "Unicode subset 2" -; long-name "Unicode subset (U+2500..U+33FF)" -; )) - +;; mule-unicode-2500-33ff +;; mule-unicode-e000-ffff +;; mule-unicode-0100-24ff -; (make-charset 'mule-unicode-e000-ffff -; "Unicode characters of the range U+E000..U+FFFF." -; '(dimension -; 2 -; registry "ISO10646-1" -; chars 96 -; columns 1 -; direction l2r -; final ?3 -; graphic 0 -; short-name "Unicode subset 3" -; long-name "Unicode subset (U+E000+FFFF)" -; )) - - -; (make-charset 'mule-unicode-0100-24ff -; "Unicode characters of the range U+0100..U+24FF." -; '(dimension -; 2 -; registry "ISO10646-1" -; chars 96 -; columns 1 -; direction l2r -; final ?1 -; graphic 0 -; short-name "Unicode subset" -; long-name "Unicode subset (U+0100..U+24FF)" -; )) - +;; built-in. This is hack--and an incomplete hack at that--against the +;; spirit and the letter of standard ISO 2022 character sets. Instead of +;; this, we have the jit-ucs-charset-N Mule character sets, created in +;; unicode.c on encountering a Unicode code point that we don't recognise, +;; and saved in ISO 2022 coding systems using the UTF-8 escape described in +;; ISO-IR 196. ;; accessed in loadup.el, mule-cmds.el; see discussion in unicode.c (defvar load-unicode-tables-at-dump-time (eq system-type 'windows-nt) @@ -305,51 +270,19 @@ need-bom t)) (defun decode-char (quote-ucs code &optional restriction) - "FSF compatibility--return Mule character with Unicode codepoint `code'. + "FSF compatibility--return Mule character with Unicode codepoint CODE. The second argument must be 'ucs, the third argument is ignored. " (assert (eq quote-ucs 'ucs) t "Sorry, decode-char doesn't yet support anything but the UCS. ") (unicode-to-char code)) (defun encode-char (char quote-ucs &optional restriction) - "FSF compatibility--return the Unicode code point of `char'. + "FSF compatibility--return the Unicode code point of CHAR. The second argument must be 'ucs, the third argument is ignored. " (assert (eq quote-ucs 'ucs) t "Sorry, encode-char doesn't yet support anything but the UCS. ") (char-to-unicode char)) -(when (featurep 'mule) - ;; This CCL program is used for displaying the fallback UCS character set, - ;; and can be repurposed to lao and the IPA, all going well. - ;; - ;; define-ccl-program is available after mule-ccl is loaded, much later - ;; than this file in the build process. The below is the result of - ;; - ;; (macroexpand - ;; '(define-ccl-program ccl-encode-to-ucs-2 - ;; `(1 - ;; ((r1 = (r1 << 8)) - ;; (r1 = (r1 | r2)) - ;; (mule-to-unicode r0 r1) - ;; (r1 = (r0 >> 8)) - ;; (r2 = (r0 & 255)))) - ;; "CCL program to transform Mule characters to UCS-2.")) - ;; - ;; and it should occasionally be confirmed that the correspondence still - ;; holds. - - (let ((prog [1 10 131127 8 98872 65823 147513 8 82009 255 22])) - (defconst ccl-encode-to-ucs-2 prog - "CCL program to transform Mule characters to UCS-2.") - (put (quote ccl-encode-to-ucs-2) (quote ccl-program-idx) - (register-ccl-program (quote ccl-encode-to-ucs-2) prog)) nil)) - -;; Won't do this just yet, though. -;; (set-charset-registry 'lao "iso10646-1") -;; (set-charset-ccl-program 'lao 'ccl-encode-to-ucs-2) -;; (set-charset-registry 'ipa "iso10646-1") -;; (set-charset-ccl-program 'ipa 'ccl-encode-to-ucs-2) - ;; #### UTF-7 is not yet implemented, and it's tricky to do. There's ;; an implementation in appendix A.1 of the Unicode Standard, Version ;; 2.0, but I don't know its licensing characteristics. @@ -358,8 +291,7 @@ ; 'utf-7 'unicode ; "UTF-7" ; '(mnemonic "UTF7" -; documentation -; "UTF-7 Unicode encoding -- 7-bit-ASCII modal Internet-mail-compatible +; documentation; "UTF-7 Unicode encoding -- 7-bit-ASCII modal Internet-mail-compatible ; encoding especially designed for headers, with the following ; properties:
--- a/lisp/x-faces.el Sat Nov 04 22:51:03 2006 +0000 +++ b/lisp/x-faces.el Sun Nov 05 22:31:46 2006 +0000 @@ -782,7 +782,28 @@ ;; globally. This means we should override global ;; defaults for all X device classes. (remove-specifier (face-font face) locale x-tag-set nil)) - (set-face-font face fn locale 'x append)) + (set-face-font face fn locale 'x append) + ; + ; (debug-print "the face is %s, locale %s, specifier %s" + ; face locale (face-font face)) + ; + ;; And retain some of the fallbacks in the generated default face, + ;; since we don't want to try andale-mono's ISO-10646-1 encoding for + ;; Amharic or Thai. This is fragile; it depends on the code in + ;; faces.c. + (dolist (assocked '((x encode-as-utf-8 initial) + (x two-dimensional initial) + (x one-dimensional final) + (x two-dimensional final))) + (when (and (specifierp (face-font face)) + (consp (specifier-fallback (face-font face))) + (setq assocked + (assoc assocked + (specifier-fallback + (face-font face))))) + (set-face-font face (cdr assocked) locale + (nreverse (car assocked)) append)))) + ;; Kludge-o-rooni. Set the foreground and background resources for ;; X devices only -- otherwise things tend to get all messed up ;; if you start up an X frame and then later create a TTY frame.
--- a/lisp/x-font-menu.el Sat Nov 04 22:51:03 2006 +0000 +++ b/lisp/x-font-menu.el Sun Nov 05 22:31:46 2006 +0000 @@ -43,7 +43,7 @@ x-font-regexp-spacing)) (globally-declare-fboundp - '(charset-registry)) + '(charset-registries)) (defvar x-font-menu-registry-encoding nil "Registry and encoding to use with font menu fonts.") @@ -157,9 +157,7 @@ ;; #### - this should implement a `menus-only' option, which would ;; recalculate the menus from the cache w/o having to do font-list again. (unless x-font-regexp-ascii - (setq x-font-regexp-ascii (if (featurep 'mule) - (charset-registry 'ascii) - "iso8859-1"))) + (setq x-font-regexp-ascii (elt (charset-registries 'ascii) 0))) (setq x-font-menu-registry-encoding (if (featurep 'mule) "*-*" "iso8859-1")) (let ((case-fold-search t)
--- a/src/ChangeLog Sat Nov 04 22:51:03 2006 +0000 +++ b/src/ChangeLog Sun Nov 05 22:31:46 2006 +0000 @@ -1,3 +1,136 @@ +2006-11-05 Aidan Kehoe <kehoea@parhasard.net> + + * charset.h: + Prefer the charset-registries property to the charset-registry + property; accept the latter for compatibility, warning when its + regexp functionality is used. + + * charset.h (XCHARSET_CCL_PROGRAM): + * charset.h (XCHARSET_NAME): + Make dummy versions of these available in non-Mule. + + * console-impl.h: + * console-impl.h (struct console_methods): + Rename the last parameter to a couple of methods; reformat their + declarations. + + * faces.c: + * faces.c (face_property_matching_instance): + * faces.c (ensure_face_cachel_contains_charset): + * faces.c (merge_face_cachel_data): + * faces.c (reset_face_cachel): + * faces.c (mark_face_cachels_as_not_updated): + * faces.c (syms_of_faces): + * faces.c (vars_of_faces): + * faces.c (complex_vars_of_faces): + Provide a DEBUG_FACES macro; use it to make debugging output + available in debug builds. + Implement multi-stage font lookup, assigning the stages names, not + numbers. + Re-implement the cachel->font_specified cache using the + infrastructure for Lisp bit vectors. + + * faces.h: + * faces.h (struct face_cachel): + * faces.h (FACE_CACHEL_FONT_UPDATED): + * faces.h (FACE_FONT): + Re-implement the cachel->font_specified cache using the + infrastructure for Lisp bit vectors. + + * font-mgr.h: + Move some XFT debug macros here from objects-x.c. + + * general-slots.h: + Provide a few new symbols for the multi-stage font resolution + process. + + * intl.c (init_intl): + Correct a comment. + + * lisp.h: + Provide a macro to declare an inline lisp bit vector where the + size is fixed. + Make Qregistries available all over, not Qregistry. + + * mule-charset.c: + * mule-charset.c (mark_charset): + * mule-charset.c (print_charset): + * mule-charset.c (make_charset): + * mule-charset.c (Fmake_charset): + * mule-charset.c (Fcharset_property): + * mule-charset.c (Fset_charset_ccl_program): + * mule-charset.c (syms_of_mule_charset): + * mule-charset.c (complex_vars_of_mule_charset): + * mule-charset.c (CHINESE_CNS_PLANE): + Prefer the charset-registries property to the charset-registry + property; accept the latter for compatibility, warning when its + regexp functionality is used. + + * objects-gtk.c: + * objects-gtk.c (gtk_font_spec_matches_charset): + * objects-gtk.c (gtk_find_charset_font): + * objects-msw.c (mswindows_find_charset_font): + * objects-tty.c (tty_find_charset_font): + Redeclare various functions to work with the multi-stage lookup + process. Include objects-xlike-inc. + + * objects-x.c: + Provide a DEBUG_OBJECTS macro; use it to make debugging output + available in debug builds. + + * objects-x.c (x_initialize_font_instance): + * objects-x.c (x_print_font_instance): + * objects-x.c (xlistfonts_checking_charset): + * objects-x.c (vars_of_objects_x): + Don't regex match on the output of XListFonts; instead, use the + fixed strings of the charset-registries to comparatively limit the + IPC that will happen. Include objects-xlike-inc.c + + * objects-xlike-inc.c: + * objects-xlike-inc.c (count_hyphens): + New. How many ASCII minus characters in a string? + + * objects-xlike-inc.c (xlistfonts_checking_charset): + * objects-xlike-inc.c (mule_to_fc_charset): + * objects-xlike-inc.c (xft_find_charset_font): + * objects-x.c (x_find_charset_font): + Move some methods here to share them with GTK. + + * objects.c (print_font_instance): + * objects.c (font_spec_matches_charset): + * objects.c (font_validate_matchspec): + * objects.c (font_instantiate): + Redeclare some methods to take enums rather than numeric stages. + + * objects.h (EXFUN): + Make Fregexp_quote available to mule-charset.c + + * redisplay-x.c: + * redisplay-x.c (separate_textual_runs): + Make this slightly faster, cleaner. Make it accept a face cachel + pointer argument, and check it as to whether a given charset + should be translated to UCS-2 before redisplay. + + * specifier.c: + * specifier.c (charset_matches_specifier_tag_set_p): + * specifier.c (define_specifier_tag): + * specifier.c (Fdefine_specifier_tag): + * specifier.c (setup_device_initial_specifier_tags): + * specifier.c (setup_charset_initial_specifier_tags): + * specifier.c (specifier_instance_from_inst_list): + * specifier.c (syms_of_specifier): + * specifier.c (vars_of_specifier): + * specifier.h: + Extend specifiers to allow limiting their applicability by using + charset predicates. Document this. + Run indent-region on the file, at Stephen's suggestion. + + * unicode.c (unicode_to_ichar): + * unicode.c (syms_of_unicode): + * unicode.c (vars_of_unicode): + Use unicode-registries, a dumped vector, as the charset-registries + of the on-the-fly JIT charsets. + 2006-11-01 Adrian Aichner <adrian@xemacs.org> * sysdep.c (wcslen): Check for NULL pointer.
--- a/src/charset.h Sat Nov 04 22:51:03 2006 +0000 +++ b/src/charset.h Sun Nov 05 22:31:46 2006 +0000 @@ -58,6 +58,8 @@ (byte1) = (ch); \ (byte2) = 0; \ } while (0) +#define XCHARSET_CCL_PROGRAM(cs) Qnil +#define XCHARSET_NAME(cs) Qascii #else /* MULE */ @@ -186,7 +188,7 @@ int id; Lisp_Object name; Lisp_Object doc_string; - Lisp_Object registry; + Lisp_Object registries; Lisp_Object short_name; Lisp_Object long_name; @@ -271,7 +273,7 @@ #define CHARSET_DIRECTION(cs) ((cs)->direction) #define CHARSET_FINAL(cs) ((cs)->final) #define CHARSET_DOC_STRING(cs) ((cs)->doc_string) -#define CHARSET_REGISTRY(cs) ((cs)->registry) +#define CHARSET_REGISTRIES(cs) ((cs)->registries) #define CHARSET_CCL_PROGRAM(cs) ((cs)->ccl_program) #define CHARSET_DIMENSION(cs) ((cs)->dimension) #define CHARSET_CHARS(cs) ((cs)->chars) @@ -280,7 +282,6 @@ #define CHARSET_FROM_UNICODE_TABLE(cs) ((cs)->from_unicode_table) #define CHARSET_FROM_UNICODE_LEVELS(cs) ((cs)->from_unicode_levels) - #define CHARSET_PRIVATE_P(cs) leading_byte_private_p (CHARSET_LEADING_BYTE (cs)) #define XCHARSET_ID(cs) CHARSET_ID (XCHARSET (cs)) @@ -295,11 +296,12 @@ #define XCHARSET_DIRECTION(cs) CHARSET_DIRECTION (XCHARSET (cs)) #define XCHARSET_FINAL(cs) CHARSET_FINAL (XCHARSET (cs)) #define XCHARSET_DOC_STRING(cs) CHARSET_DOC_STRING (XCHARSET (cs)) -#define XCHARSET_REGISTRY(cs) CHARSET_REGISTRY (XCHARSET (cs)) +#define XCHARSET_REGISTRIES(cs) CHARSET_REGISTRIES (XCHARSET (cs)) #define XCHARSET_LEADING_BYTE(cs) CHARSET_LEADING_BYTE (XCHARSET (cs)) #define XCHARSET_CCL_PROGRAM(cs) CHARSET_CCL_PROGRAM (XCHARSET (cs)) #define XCHARSET_DIMENSION(cs) CHARSET_DIMENSION (XCHARSET (cs)) #define XCHARSET_CHARS(cs) CHARSET_CHARS (XCHARSET (cs)) + #define XCHARSET_PRIVATE_P(cs) CHARSET_PRIVATE_P (XCHARSET (cs)) #define XCHARSET_REVERSE_DIRECTION_CHARSET(cs) \ CHARSET_REVERSE_DIRECTION_CHARSET (XCHARSET (cs))
--- a/src/console-impl.h Sat Nov 04 22:51:03 2006 +0000 +++ b/src/console-impl.h Sun Nov 05 22:31:46 2006 +0000 @@ -26,6 +26,7 @@ #define INCLUDED_console_impl_h_ #include "console.h" +#include "specifier.h" extern const struct sized_memory_description cted_description; extern const struct sized_memory_description console_methods_description; @@ -212,17 +213,13 @@ Lisp_Object (*font_list_method) (Lisp_Object pattern, Lisp_Object device, Lisp_Object maxnumber); - Lisp_Object (*find_charset_font_method) (Lisp_Object device, - Lisp_Object font, - Lisp_Object charset, - int stage); - int (*font_spec_matches_charset_method) (struct device *d, - Lisp_Object charset, - const Ibyte *nonreloc, - Lisp_Object reloc, - Bytecount offset, - Bytecount length, - int stage); + Lisp_Object (*find_charset_font_method) + (Lisp_Object device, Lisp_Object font, Lisp_Object charset, + enum font_specifier_matchspec_stages stage); + int (*font_spec_matches_charset_method) + (struct device *d, Lisp_Object charset, const Ibyte *nonreloc, + Lisp_Object reloc, Bytecount offset, Bytecount length, + enum font_specifier_matchspec_stages stage); /* image methods */ void (*mark_image_instance_method) (Lisp_Image_Instance *);
--- a/src/faces.c Sat Nov 04 22:51:03 2006 +0000 +++ b/src/faces.c Sun Nov 05 22:31:46 2006 +0000 @@ -72,6 +72,31 @@ Lisp_Object Vbuilt_in_face_specifiers; +#ifdef DEBUG_XEMACS +Fixnum debug_x_faces; +#endif + +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901) + +#ifdef DEBUG_XEMACS +# define DEBUG_FACES(FORMAT, ...) \ + do { if (debug_x_faces) stderr_out(FORMAT, __VA_ARGS__); } while (0) +#else /* DEBUG_XEMACS */ +# define DEBUG_FACES(format, ...) +#endif /* DEBUG_XEMACS */ + +#elif defined(__GNUC__) + +#ifdef DEBUG_XEMACS +# define DEBUG_FACES(format, args...) \ + do { if (debug_x_faces) stderr_out(format, args ); } while (0) +#else /* DEBUG_XEMACS */ +# define DEBUG_FACES(format, args...) +#endif /* DEBUG_XEMACS */ + +#else /* defined(__STDC_VERSION__) [...] */ +# define DEBUG_FACES (void) +#endif static Lisp_Object mark_face (Lisp_Object obj) @@ -554,37 +579,31 @@ face_property_matching_instance (Lisp_Object face, Lisp_Object property, Lisp_Object charset, Lisp_Object domain, Error_Behavior errb, int no_fallback, - Lisp_Object depth) + Lisp_Object depth, + enum font_specifier_matchspec_stages stage) { Lisp_Object retval; Lisp_Object matchspec = Qunbound; struct gcpro gcpro1; if (!NILP (charset)) - matchspec = noseeum_cons (charset, Qnil); + matchspec = noseeum_cons (charset, + stage == initial ? Qinitial : Qfinal); + GCPRO1 (matchspec); retval = specifier_instance_no_quit (Fget (face, property, Qnil), matchspec, domain, errb, no_fallback, depth); - if (UNBOUNDP (retval)) - { - if (CONSP (matchspec)) - Fsetcdr (matchspec, Qt); - retval = specifier_instance_no_quit (Fget (face, property, Qnil), - matchspec, domain, errb, - no_fallback, depth); - } UNGCPRO; if (CONSP (matchspec)) free_cons (matchspec); - if (UNBOUNDP (retval) && !no_fallback) + if (UNBOUNDP (retval) && !no_fallback && final == stage) { if (EQ (property, Qfont)) { if (NILP (memq_no_quit (charset, XFACE (face)->charsets_warned_about))) { -#ifdef MULE if (!UNBOUNDP (charset)) warn_when_safe (Qfont, Qnotice, @@ -593,12 +612,6 @@ (XSYMBOL (XCHARSET_NAME (charset)))), XSTRING_DATA (symbol_name (XSYMBOL (XFACE (face)->name)))); - else -#endif - warn_when_safe (Qfont, Qnotice, - "Unable to instantiate font for face %s", - XSTRING_DATA (symbol_name - (XSYMBOL (XFACE (face)->name)))); XFACE (face)->charsets_warned_about = Fcons (charset, XFACE (face)->charsets_warned_about); } @@ -1071,11 +1084,11 @@ { Lisp_Object new_val; Lisp_Object face = cachel->face; - int bound = 1; + int bound = 1, final_stage = 0; int offs = XCHARSET_LEADING_BYTE (charset) - MIN_LEADING_BYTE; - if (!UNBOUNDP (cachel->font[offs]) - && cachel->font_updated[offs]) + if (!UNBOUNDP (cachel->font[offs]) && + bit_vector_bit(FACE_CACHEL_FONT_UPDATED (cachel), offs)) return cachel->font[offs]; if (UNBOUNDP (face)) @@ -1085,7 +1098,8 @@ struct window *w = XWINDOW (domain); new_val = Qunbound; - cachel->font_specified[offs] = 0; + set_bit_vector_bit(FACE_CACHEL_FONT_SPECIFIED(cachel), offs, 0); + for (i = 0; i < cachel->nfaces; i++) { struct face_cachel *oth; @@ -1095,15 +1109,18 @@ /* Tout le monde aime la recursion */ ensure_face_cachel_contains_charset (oth, domain, charset); - if (oth->font_specified[offs]) + if (bit_vector_bit(FACE_CACHEL_FONT_SPECIFIED(oth), offs)) { new_val = oth->font[offs]; - cachel->font_specified[offs] = 1; + set_bit_vector_bit(FACE_CACHEL_FONT_SPECIFIED(cachel), offs, 1); + set_bit_vector_bit + (FACE_CACHEL_FONT_FINAL_STAGE(cachel), offs, + bit_vector_bit(FACE_CACHEL_FONT_FINAL_STAGE(oth), offs)); break; } } - if (!cachel->font_specified[offs]) + if (!bit_vector_bit(FACE_CACHEL_FONT_SPECIFIED(cachel), offs)) /* need to do the default face. */ { struct face_cachel *oth = @@ -1113,31 +1130,108 @@ new_val = oth->font[offs]; } - if (!UNBOUNDP (cachel->font[offs]) && !EQ (cachel->font[offs], new_val)) + if (!UNBOUNDP (cachel->font[offs]) && + !EQ (cachel->font[offs], new_val)) cachel->dirty = 1; - cachel->font_updated[offs] = 1; + set_bit_vector_bit(FACE_CACHEL_FONT_UPDATED(cachel), offs, 1); cachel->font[offs] = new_val; + DEBUG_FACES("just recursed on the unbound face, returning " + "something %s\n", UNBOUNDP(new_val) ? "not bound" + : "bound"); return new_val; } - new_val = face_property_matching_instance (face, Qfont, charset, domain, - /* #### look into error flag */ - ERROR_ME_DEBUG_WARN, 1, Qzero); - if (UNBOUNDP (new_val)) - { - bound = 0; - new_val = face_property_matching_instance (face, Qfont, - charset, domain, - /* #### look into error - flag */ - ERROR_ME_DEBUG_WARN, 0, - Qzero); - } + do { + + /* Lookup the face, specifying the initial stage and that fallbacks + shouldn't happen. */ + new_val = face_property_matching_instance (face, Qfont, charset, domain, + /* ERROR_ME_DEBUG_WARN is + fine here. */ + ERROR_ME_DEBUG_WARN, 1, Qzero, + initial); + DEBUG_FACES("just called f_p_m_i on face %s, charset %s, initial, " + "result was something %s\n", + XSTRING_DATA(XSYMBOL_NAME(XFACE(cachel->face)->name)), + XSTRING_DATA(XSYMBOL_NAME(XCHARSET_NAME(charset))), + UNBOUNDP(new_val) ? "not bound" : "bound"); + + if (!UNBOUNDP (new_val)) break; + + bound = 0; + /* Lookup the face again, this time allowing the fallback. If this + succeeds, it'll give a font intended for the script in question, + which is preferable to translating to ISO10646-1 and using the + fixed-with fallback. */ + new_val = face_property_matching_instance (face, Qfont, + charset, domain, + ERROR_ME_DEBUG_WARN, 0, + Qzero, + initial); + + DEBUG_FACES("just called f_p_m_i on face %s, charset %s, initial, " + "allow fallback, result was something %s\n", + XSTRING_DATA(XSYMBOL_NAME(XFACE(cachel->face)->name)), + XSTRING_DATA(XSYMBOL_NAME(XCHARSET_NAME(charset))), + UNBOUNDP(new_val) ? "not bound" : "bound"); + + if (!UNBOUNDP(new_val)) + { + break; + } + + bound = 1; + /* Try the face itself with the final-stage specifiers. */ + new_val = face_property_matching_instance (face, Qfont, + charset, domain, + ERROR_ME_DEBUG_WARN, 1, + Qzero, + final); + + DEBUG_FACES("just called f_p_m_i on face %s, charset %s, final, " + "result was something %s\n", + XSTRING_DATA(XSYMBOL_NAME(XFACE(cachel->face)->name)), + XSTRING_DATA(XSYMBOL_NAME(XCHARSET_NAME(charset))), + UNBOUNDP(new_val) ? "not bound" : "bound"); + /* Tell X11 redisplay that it should translate to iso10646-1. */ + if (!UNBOUNDP(new_val)) + { + final_stage = 1; + break; + } + + bound = 0; + + /* Lookup the face again, this time both allowing the fallback and + allowing its final stage to be used. */ + new_val = face_property_matching_instance (face, Qfont, + charset, domain, + ERROR_ME_DEBUG_WARN, 0, + Qzero, + final); + + DEBUG_FACES("just called f_p_m_i on face %s, charset %s, initial, " + "allow fallback, result was something %s\n", + XSTRING_DATA(XSYMBOL_NAME(XFACE(cachel->face)->name)), + XSTRING_DATA(XSYMBOL_NAME(XCHARSET_NAME(charset))), + UNBOUNDP(new_val) ? "not bound" : "bound"); + if (!UNBOUNDP(new_val)) + { + /* Tell X11 redisplay that it should translate to iso10646-1. */ + final_stage = 1; + break; + } + } while (0); + if (!UNBOUNDP (cachel->font[offs]) && !EQ (new_val, cachel->font[offs])) cachel->dirty = 1; - cachel->font_updated[offs] = 1; + + set_bit_vector_bit(FACE_CACHEL_FONT_UPDATED(cachel), offs, 1); + set_bit_vector_bit(FACE_CACHEL_FONT_FINAL_STAGE(cachel), offs, + final_stage); + set_bit_vector_bit(FACE_CACHEL_FONT_SPECIFIED(cachel), offs, + (bound || EQ (face, Vdefault_face))); cachel->font[offs] = new_val; - cachel->font_specified[offs] = (bound || EQ (face, Vdefault_face)); return new_val; } @@ -1372,6 +1466,8 @@ merge_face_cachel_data (struct window *w, face_index findex, struct face_cachel *cachel) { + int offs; + #define FINDEX_FIELD(field) \ Dynarr_atp (w->face_cachels, findex)->field @@ -1395,18 +1491,24 @@ FROB (dim); FROB (reverse); FROB (blinking); - /* And do ASCII, of course. */ - { - int offs = LEADING_BYTE_ASCII - MIN_LEADING_BYTE; - if (!cachel->font_specified[offs] && FINDEX_FIELD (font_specified[offs])) - { - cachel->font[offs] = FINDEX_FIELD (font[offs]); - cachel->font_specified[offs] = 1; - cachel->dirty = 1; - } - } - + for (offs = 0; offs < NUM_LEADING_BYTES; ++offs) + { + if (!(bit_vector_bit(FACE_CACHEL_FONT_SPECIFIED(cachel), offs)) + && bit_vector_bit(FACE_CACHEL_FONT_SPECIFIED + (Dynarr_atp(w->face_cachels, findex)), offs)) + { + cachel->font[offs] = FINDEX_FIELD (font[offs]); + set_bit_vector_bit(FACE_CACHEL_FONT_SPECIFIED(cachel), offs, 1); + /* Also propagate whether we're translating to Unicode for the + given face. */ + set_bit_vector_bit(FACE_CACHEL_FONT_FINAL_STAGE(cachel), offs, + bit_vector_bit(FACE_CACHEL_FONT_FINAL_STAGE + (Dynarr_atp(w->face_cachels, + findex)), offs)); + cachel->dirty = 1; + } + } #undef FROB #undef FINDEX_FIELD @@ -1433,6 +1535,8 @@ } cachel->display_table = Qunbound; cachel->background_pixmap = Qunbound; + FACE_CACHEL_FONT_SPECIFIED (cachel)->size = sizeof(cachel->font_specified); + FACE_CACHEL_FONT_UPDATED (cachel)->size = sizeof(cachel->font_updated); } /* Retrieve the index to a cachel for window W that corresponds to @@ -1505,11 +1609,10 @@ for (elt = 0; elt < Dynarr_length (w->face_cachels); elt++) { struct face_cachel *cachel = Dynarr_atp (w->face_cachels, elt); - int i; cachel->updated = 0; - for (i = 0; i < NUM_LEADING_BYTES; i++) - cachel->font_updated[i] = 0; + memset(FACE_CACHEL_FONT_UPDATED(cachel)->bits, 0, + BIT_VECTOR_LONG_STORAGE (NUM_LEADING_BYTES)); } } @@ -1896,6 +1999,81 @@ return new_name; } +#ifdef MULE + +Lisp_Object Qone_dimensional, Qtwo_dimensional; + +DEFUN ("specifier-tag-one-dimensional-p", + Fspecifier_tag_one_dimensional_p, + 2, 2, 0, /* +Return non-nil if (charset-dimension CHARSET) is 1. + +Used by the X11 platform font code; see `define-specifier-tag'. You +shouldn't ever need to call this yourself. +*/ + (charset, UNUSED(stage))) +{ + CHECK_CHARSET(charset); + return (1 == XCHARSET_DIMENSION(charset)) ? Qt : Qnil; +} + +DEFUN ("specifier-tag-two-dimensional-p", + Fspecifier_tag_two_dimensional_p, + 2, 2, 0, /* +Return non-nil if (charset-dimension CHARSET) is 2. + +Used by the X11 platform font code; see `define-specifier-tag'. You +shouldn't ever need to call this yourself. +*/ + (charset, UNUSED(stage))) +{ + CHECK_CHARSET(charset); + return (2 == XCHARSET_DIMENSION(charset)) ? Qt : Qnil; +} + +DEFUN ("specifier-tag-final-stage-p", + Fspecifier_tag_final_stage_p, + 2, 2, 0, /* +Return non-nil if STAGE is 'final. + +Used by the X11 platform font code for giving fallbacks; see +`define-specifier-tag'. You shouldn't ever need to call this. +*/ + (UNUSED(charset), stage)) +{ + return EQ(stage, Qfinal) ? Qt : Qnil; +} + +DEFUN ("specifier-tag-initial-stage-p", + Fspecifier_tag_initial_stage_p, + 2, 2, 0, /* +Return non-nil if STAGE is 'initial. + +Used by the X11 platform font code for giving fallbacks; see +`define-specifier-tag'. You shouldn't ever need to call this. +*/ + (UNUSED(charset), stage)) +{ + return EQ(stage, Qinitial) ? Qt : Qnil; +} + +DEFUN ("specifier-tag-encode-as-utf-8-p", + Fspecifier_tag_encode_as_utf_8_p, + 2, 2, 0, /* +Return t if and only if (charset-property CHARSET 'encode-as-utf-8)). + +Used by the X11 platform font code; see `define-specifier-tag'. You +shouldn't ever need to call this. +*/ + (charset, UNUSED(stage))) +{ + /* Used to check that the stage was initial too. */ + CHECK_CHARSET(charset); + return XCHARSET_ENCODE_AS_UTF_8(charset) ? Qt : Qnil; +} + +#endif /* MULE */ + void syms_of_faces (void) @@ -1917,6 +2095,17 @@ DEFSUBR (Fmake_face); DEFSUBR (Fcopy_face); +#ifdef MULE + DEFSYMBOL (Qone_dimensional); + DEFSYMBOL (Qtwo_dimensional); + /* I would much prefer these were in Lisp. */ + DEFSUBR (Fspecifier_tag_one_dimensional_p); + DEFSUBR (Fspecifier_tag_two_dimensional_p); + DEFSUBR (Fspecifier_tag_initial_stage_p); + DEFSUBR (Fspecifier_tag_final_stage_p); + DEFSUBR (Fspecifier_tag_encode_as_utf_8_p); +#endif /* MULE */ + DEFSYMBOL (Qfacep); DEFSYMBOL (Qforeground); DEFSYMBOL (Qbackground); @@ -1980,6 +2169,13 @@ staticpro (&Vpointer_face); Vpointer_face = Qnil; +#ifdef DEBUG_XEMACS + DEFVAR_INT ("debug-x-faces", &debug_x_faces /* +If non-zero, display debug information about X faces +*/ ); + debug_x_faces = 0; +#endif + { Lisp_Object syms[20]; int n = 0; @@ -2046,6 +2242,14 @@ #if defined (HAVE_X_WINDOWS) || defined (HAVE_GTK) +#ifdef HAVE_GTK + Lisp_Object device_symbol = Qgtk; +#else + Lisp_Object device_symbol = Qx; +#endif + +#ifdef MULE + const Ascbyte *fonts[] = { #ifdef USE_XFT @@ -2053,165 +2257,128 @@ /* Note that fontconfig can search for several font families in one call. We should use this facility. */ - "monospace-12", /* Western #### add encoding info? */ + "Monospace-12", /* do we need to worry about non-Latin characters for monospace? No, at least in Debian's implementation of Xft. We should recommend that "gothic" and "mincho" aliases be created? */ - "Sazanami Mincho-12", /* Japanese #### add encoding info? */ + "Sazanami Mincho-12", + /* Japanese #### add encoding info? */ /* Arphic for Chinese? */ /* Korean */ #else - - /************** ISO-8859 fonts *************/ - - "-*-courier-medium-r-*-*-*-120-*-*-*-*-iso8859-*", - /* under USE_XFT, we always succeed, so let's not waste the effort */ - "-*-fixed-medium-r-*-*-*-120-*-*-*-*-iso8859-*", - "-*-courier-*-r-*-*-*-120-*-*-*-*-iso8859-*", - "-*-fixed-*-r-*-*-*-120-*-*-*-*-iso8859-*", - /* Next try for any "medium" charcell or monospaced iso8859 font. */ - "-*-*-medium-r-*-*-*-120-*-*-m-*-iso8859-*", - "-*-*-medium-r-*-*-*-120-*-*-c-*-iso8859-*", - /* Next try for any charcell or monospaced iso8859 font. */ - "-*-*-*-r-*-*-*-120-*-*-m-*-iso8859-*", - "-*-*-*-r-*-*-*-120-*-*-c-*-iso8859-*", - - /* Repeat, any size */ - "-*-courier-medium-r-*-*-*-*-*-*-*-*-iso8859-*", - "-*-fixed-medium-r-*-*-*-*-*-*-*-*-iso8859-*", - "-*-courier-*-r-*-*-*-*-*-*-*-*-iso8859-*", - "-*-fixed-*-r-*-*-*-*-*-*-*-*-iso8859-*", - /* Next try for any "medium" charcell or monospaced iso8859 font. */ - "-*-*-medium-r-*-*-*-*-*-*-m-*-iso8859-*", - "-*-*-medium-r-*-*-*-*-*-*-c-*-iso8859-*", - /* Next try for any charcell or monospaced iso8859 font. */ - "-*-*-*-r-*-*-*-*-*-*-m-*-iso8859-*", - "-*-*-*-r-*-*-*-*-*-*-c-*-iso8859-*", - - /* Non-proportional fonts -- last resort. */ - "-*-*-*-r-*-*-*-120-*-*-*-*-iso8859-*", - "-*-*-*-r-*-*-*-*-*-*-*-*-iso8859-*", - "-*-*-*-*-*-*-*-*-*-*-*-*-iso8859-*", - - /************* Japanese fonts ************/ - - /* Following 3 fonts proposed by Teruhiko.Kurosaka@Japan.eng.sun */ - "-sun-gothic-medium-r-normal--14-120-75-75-c-60-jisx0201.1976-0", - "-sun-gothic-medium-r-normal--14-120-75-75-c-120-jisx0208.1983-0", - "-wadalab-gothic-medium-r-normal--14-120-75-75-c-120-jisx0212.1990-0", - - /* Other Japanese fonts */ - "-*-fixed-medium-r-*--*-jisx0201.1976-*", - "-*-fixed-medium-r-*--*-jisx0208.1983-*", - "-*-fixed-medium-r-*--*-jisx0212*-*", - "-*-*-*-r-*--*-jisx0201.1976-*", - "-*-*-*-r-*--*-jisx0208.1983-*", - "-*-*-*-r-*--*-jisx0212*-*", - - /************* Chinese fonts ************/ - - "-*-*-medium-r-*--*-gb2312.1980-*", - "-*-fixed-medium-r-*--*-cns11643*-*", - - "-*-fixed-medium-r-*--*-big5*-*," - "-*-fixed-medium-r-*--*-sisheng_cwnn-0", - - /************* Korean fonts *************/ - - "-*-mincho-medium-r-*--*-ksc5601.1987-*", - - /************* Thai fonts **************/ - - "-*-fixed-medium-r-*--*-tis620.2529-1", - - /************* Other fonts (nonstandard) *************/ - - "-*-fixed-medium-r-*--*-viscii1.1-1", - "-*-fixed-medium-r-*--*-mulearabic-*", - "-*-fixed-medium-r-*--*-muleipa-*", - "-*-fixed-medium-r-*--*-ethio-*", - - /************* Unicode fonts **************/ - - /* #### We don't yet support Unicode fonts, but doing so would not be - hard because all the machinery has already been added for Windows - support. We need to do this: - - (1) Add "stage 2" support in find_charset_font()/etc.; this finds - an appropriate Unicode font after all the charset-specific fonts - have been checked. This should look at the per-char font info and - check whether we have support for some of the chars in the - charset. (#### Bogus, but that's the way it currently works) - - sjt sez: With Xft/fontconfig that information is available as a - language support property. The character set (actually a bit - vector) is also available. So what we need to do is to map charset - -> language (Mule redesign Phase 1) and eventually use language - information in the buffer, then map to charsets (Phase 2) at font - instantiation time. - - (2) Record in the font instance a flag indicating when we're - dealing with a Unicode font. - - (3) Notice this flag in separate_textual_runs() and translate the - text into Unicode if so. - */ - - "-*-courier-medium-r-*-*-*-120-*-*-*-*-iso10646-1", - "-*-fixed-medium-r-*-*-*-120-*-*-*-*-iso10646-1", - "-*-courier-*-r-*-*-*-120-*-*-*-*-iso10646-1", - "-*-fixed-*-r-*-*-*-120-*-*-*-*-iso10646-1", - /* Next try for any "medium" charcell or monospaced iso8859 font. */ - "-*-*-medium-r-*-*-*-120-*-*-m-*-iso10646-1", - "-*-*-medium-r-*-*-*-120-*-*-c-*-iso10646-1", - /* Next try for any charcell or monospaced iso8859 font. */ - "-*-*-*-r-*-*-*-120-*-*-m-*-iso10646-1", - "-*-*-*-r-*-*-*-120-*-*-c-*-iso10646-1", - - /* Repeat, any size */ - "-*-courier-medium-r-*-*-*-*-*-*-*-*-iso10646-1", - "-*-fixed-medium-r-*-*-*-*-*-*-*-*-iso10646-1", - "-*-courier-*-r-*-*-*-*-*-*-*-*-iso10646-1", - "-*-fixed-*-r-*-*-*-*-*-*-*-*-iso10646-1", - /* Next try for any "medium" charcell or monospaced iso8859 font. */ - "-*-*-medium-r-*-*-*-*-*-*-m-*-iso10646-1", - "-*-*-medium-r-*-*-*-*-*-*-c-*-iso10646-1", - /* Next try for any charcell or monospaced iso8859 font. */ - "-*-*-*-r-*-*-*-*-*-*-m-*-iso10646-1", - "-*-*-*-r-*-*-*-*-*-*-c-*-iso10646-1", - - /* Non-proportional fonts -- last resort. */ - "-*-*-*-r-*-*-*-120-*-*-*-*-iso10646-1", - "-*-*-*-r-*-*-*-*-*-*-*-*-iso10646-1", - "-*-*-*-*-*-*-*-*-*-*-*-*-iso10646-1", - - /*********** Last resort ***********/ - - /* Boy, we sure are losing now. Try the above, but in any encoding. */ - "-*-*-medium-r-*-*-*-120-*-*-m-*-*-*", - "-*-*-medium-r-*-*-*-120-*-*-c-*-*-*", - "-*-*-*-r-*-*-*-120-*-*-m-*-*-*", - "-*-*-*-r-*-*-*-120-*-*-c-*-*-*", - /* Hello? Please? */ - "-*-*-*-r-*-*-*-120-*-*-*-*-*-*", - "-*-*-*-*-*-*-*-120-*-*-*-*-*-*", - "-*-*-*-*-*-*-*-*-*-*-*-*-*-*", - "*" + /* The default Japanese fonts installed with XFree86 4.0 use this + point size, and the -misc-fixed fonts (which look really bad with + Han characters) don't. We need to prefer the former. */ + "-*-*-medium-r-*-*-*-150-*-*-c-*-*-*", + /* And the Chinese ones, maddeningly, use this one. (But on 4.0, while + XListFonts returns them, XLoadQueryFont on the fully-specified XLFD + corresponding to one of them fails!) */ + "-*-*-medium-r-*-*-*-160-*-*-c-*-*-*", + "-*-*-medium-r-*-*-*-170-*-*-c-*-*-*", #endif }; const Ascbyte **fontptr; -#ifdef HAVE_X_WINDOWS - for (fontptr = fonts + countof(fonts) - 1; fontptr >= fonts; fontptr--) - inst_list = Fcons (Fcons (list1 (Qx), build_string (*fontptr)), - inst_list); -#endif /* HAVE_X_WINDOWS */ + /* Define some specifier tags for classes of character sets. Combining + these allows for distinct fallback fonts for distinct dimensions of + character sets and stages. */ + + define_specifier_tag(Qtwo_dimensional, Qnil, + intern ("specifier-tag-two-dimensional-p")); + + define_specifier_tag(Qone_dimensional, Qnil, + intern ("specifier-tag-one-dimensional-p")); + + define_specifier_tag(Qinitial, Qnil, + intern ("specifier-tag-initial-stage-p")); + + define_specifier_tag(Qfinal, Qnil, + intern ("specifier-tag-final-stage-p")); + + define_specifier_tag (Qencode_as_utf_8, Qnil, + intern("specifier-tag-encode-as-utf-8-p")); + +#endif /* MULE */ + + inst_list = + Fcons + (Fcons + (list1 (device_symbol), + build_string ("*")), + inst_list); + +#ifdef MULE + + /* For Han characters and Ethiopic, we want the misc-fixed font used to + be distinct from that for alphabetic scripts, because the font + specified below is distractingly ugly when used for Han characters + (this is slightly less so) and because its coverage isn't up to + handling them (well, chiefly, it's not up to handling Ethiopic--we do + have charset-specific fallbacks for the East Asian charsets.) */ + inst_list = + Fcons + (Fcons + (list3(device_symbol, Qtwo_dimensional, Qfinal), + build_string + ("-misc-fixed-medium-r-normal--15-140-75-75-c-90-iso10646-1")), + inst_list); + + /* Use Markus Kuhn's version of misc-fixed as the font for the font for + when a given charset's registries can't be found and redisplay for + that charset falls back to iso10646-1. */ -#ifdef HAVE_GTK + inst_list = + Fcons + (Fcons + (list3(device_symbol, Qone_dimensional, Qfinal), + build_string + ("-misc-fixed-medium-r-semicondensed--13-120-75-75-c-60-iso10646-1")), + inst_list); + for (fontptr = fonts + countof(fonts) - 1; fontptr >= fonts; fontptr--) - inst_list = Fcons (Fcons (list1 (Qgtk), build_string (*fontptr)), + inst_list = Fcons (Fcons (list3 (device_symbol, + Qtwo_dimensional, Qinitial), + build_string (*fontptr)), inst_list); -#endif /* HAVE_GTK */ + + /* We need to set the font for the JIT-ucs-charsets separately from the + final stage, since otherwise it picks up the two-dimensional + specification (see specifier-tag-two-dimensional-initial-stage-p + above). They also use Markus Kuhn's ISO 10646-1 fixed fonts for + redisplay. */ + + inst_list = + Fcons + (Fcons + (list3(device_symbol, Qencode_as_utf_8, Qinitial), + build_string + ("-misc-fixed-medium-r-semicondensed--13-120-75-75-c-60-iso10646-1")), + inst_list); + +#endif /* MULE */ + + /* Needed to make sure that charsets with non-specified fonts don't + use bold and oblique first if medium and regular are available. */ + inst_list = + Fcons + (Fcons + (list1 (device_symbol), + build_string ("-*-*-medium-r-*-*-*-120-*-*-c-*-*-*")), + inst_list); + + /* With a Cygwin XFree86 install, this returns the best (clearest, + most readable) font I can find when scaling of bitmap fonts is + turned on, as it is by default. (WHO IN THE NAME OF CHRIST THOUGHT + THAT WAS A GOOD IDEA?!?!) The other fonts that used to be specified + here gave horrendous results. */ + + inst_list = + Fcons + (Fcons + (list1 (device_symbol), + build_string ("-*-lucidatypewriter-medium-r-*-*-*-120-*-*-*-*-*-*")), + inst_list); + #endif /* HAVE_X_WINDOWS || HAVE_GTK */ #ifdef HAVE_TTY
--- a/src/faces.h Sat Nov 04 22:51:03 2006 +0000 +++ b/src/faces.h Sun Nov 05 22:31:46 2006 +0000 @@ -25,6 +25,7 @@ #define INCLUDED_faces_h_ #include "charset.h" /* for NUM_LEADING_BYTES */ +#include "specifier.h" /* a Lisp_Face is the C object corresponding to a face. There is one of these per face. It basically contains all of the specifiers for @@ -181,8 +182,8 @@ /* Used when merging to tell if the above field represents an actual value of this face or a fallback value. */ - /* #### Of course we should use a bit array or something. */ - unsigned char font_specified[NUM_LEADING_BYTES]; + DECLARE_INLINE_LISP_BIT_VECTOR(NUM_LEADING_BYTES) font_specified; + unsigned int foreground_specified :1; unsigned int background_specified :1; unsigned int display_table_specified :1; @@ -223,8 +224,13 @@ storing a "blank font" if the instantiation fails. */ unsigned int dirty :1; unsigned int updated :1; - /* #### Of course we should use a bit array or something. */ - unsigned char font_updated[NUM_LEADING_BYTES]; + + DECLARE_INLINE_LISP_BIT_VECTOR(NUM_LEADING_BYTES) font_updated; + + /* Whether the font for the charset in question was determined in the + "final stage"; that is, the last stage Lisp code could specify it, + after the initial stage and before the fallback. */ + DECLARE_INLINE_LISP_BIT_VECTOR(NUM_LEADING_BYTES) font_final_stage; }; #ifdef NEW_GC @@ -303,6 +309,13 @@ #define FACE_CACHEL_FONT(cachel, charset) \ (cachel->font[XCHARSET_LEADING_BYTE (charset) - MIN_LEADING_BYTE]) +#define FACE_CACHEL_FONT_UPDATED(x) \ + ((struct Lisp_Bit_Vector *)(&((x)->font_updated))) +#define FACE_CACHEL_FONT_SPECIFIED(x) \ + ((struct Lisp_Bit_Vector *)(&((x)->font_specified))) +#define FACE_CACHEL_FONT_FINAL_STAGE(x) \ + ((struct Lisp_Bit_Vector *)(&((x)->font_final_stage))) + #define WINDOW_FACE_CACHEL(window, index) \ Dynarr_atp ((window)->face_cachels, index) @@ -352,13 +365,15 @@ FACE_PROPERTY_INSTANCE_1 (face, property, domain, ERROR_ME_DEBUG_WARN, \ no_fallback, depth) -Lisp_Object face_property_matching_instance (Lisp_Object face, - Lisp_Object property, - Lisp_Object charset, - Lisp_Object domain, - Error_Behavior errb, - int no_fallback, - Lisp_Object depth); +Lisp_Object face_property_matching_instance + (Lisp_Object face, + Lisp_Object property, + Lisp_Object charset, + Lisp_Object domain, + Error_Behavior errb, + int no_fallback, + Lisp_Object depth, + enum font_specifier_matchspec_stages stages); #define FACE_PROPERTY_SPEC_LIST(face, property, locale) \ Fspecifier_spec_list (FACE_PROPERTY_SPECIFIER (face, property), \ @@ -373,7 +388,8 @@ FACE_PROPERTY_INSTANCE (face, Qbackground, domain, 0, Qzero) #define FACE_FONT(face, domain, charset) \ face_property_matching_instance (face, Qfont, charset, domain, \ - ERROR_ME_DEBUG_WARN, 0, Qzero) + ERROR_ME_DEBUG_WARN, 0, Qzero, \ + initial) #define FACE_DISPLAY_TABLE(face, domain) \ FACE_PROPERTY_INSTANCE (face, Qdisplay_table, domain, 0, Qzero) #define FACE_BACKGROUND_PIXMAP(face, domain) \
--- a/src/font-mgr.h Sat Nov 04 22:51:03 2006 +0000 +++ b/src/font-mgr.h Sun Nov 05 22:31:46 2006 +0000 @@ -68,4 +68,73 @@ #define CONCHECK_FCPATTERN(x) CONCHECK_RECORD (x, fc_pattern) #define XFCPATTERN_PTR(x) (XFCPATTERN(x)->fcpatPtr) +#ifdef USE_XFT +/* + The format of a fontname (as returned by fontconfig) is not well-documented, + But the character repertoire is represented in an ASCII-compatible way. See + fccharset.c (FcCharSetUnparse). So we can use UTF-8 for long names. + + Currently we have a hack where different versions of the unparsed name are + used in different contexts fairly arbitrarily. I don't think this is close + to coherency; even without the charset and lang properties fontconfig names + are too unwieldy to use. We need to rethink the approach here. I think + probably Lisp_Font_Instance.name should contain the font name as specified + to Lisp (almost surely much shorter than shortname, even, and most likely + wildcarded), while Lisp_Font_Instance.truename should contain the longname. + For now, I'm going to #ifdef the return values defaulting to short. -- sjt +*/ + +/* DEBUGGING STUFF */ + +/* print message to stderr: one internal-format string argument */ +#define DEBUG_XFT0(level,s) \ + if (debug_xft > level) stderr_out (s) + +/* print message to stderr: one formatted argument */ +#define DEBUG_XFT1(level,format,x1) \ + if (debug_xft > level) stderr_out (format, x1) + +/* print message to stderr: two formatted arguments */ +#define DEBUG_XFT2(level,format,x1,x2) \ + if (debug_xft > level) stderr_out (format, x1, x2) + +/* print message to stderr: three formatted arguments */ +#define DEBUG_XFT3(level,format,x1,x2,x3) \ + if (debug_xft > level) stderr_out (format, x1, x2, x3) + +/* print message to stderr: four formatted arguments */ +#define DEBUG_XFT4(level,format,x1,x2,x3,x4) \ + if (debug_xft > level) stderr_out (format, x1, x2, x3, x4) + +/* print an Xft pattern to stderr + LEVEL is the debug level (to compare to debug_xft) + FORMAT is a newline-terminated printf format with one %s for the pattern + and must be internal format (eg, pure ASCII) + PATTERN is an FcPattern *. */ +#define PRINT_XFT_PATTERN(level,format,pattern) \ + do { \ + DECLARE_EISTRING (eistrpxft_name); \ + FcChar8 *name = FcNameUnparse (pattern); \ + \ + eicpy_ext(eistrpxft_name, name, Qfc_font_name_encoding); \ + DEBUG_XFT1 (level, format, eidata(eistrpxft_name)); \ + free (name); \ + } while (0) + +/* print a progress message + LEVEL is the debug level (to compare to debug_xft) + FONT is the Xft font name in UTF-8 (the native encoding of Xft) + LANG is the language being checked for support (must be ASCII). */ +#define CHECKING_LANG(level,font,lang) \ + do { \ + DECLARE_EISTRING (eistrcl_name); \ + eicpy_ext(eistrcl_name, font, Qfc_font_name_encoding); \ + DEBUG_XFT2 (level, "checking if %s handles %s\n", \ + eidata(eistrcl_name), lang); \ + } while (0) + +#else /* USE_XFT */ + +#endif /* USE_XFT */ + #endif /* INCLUDED_font_mgr_h_ */
--- a/src/general-slots.h Sat Nov 04 22:51:03 2006 +0000 +++ b/src/general-slots.h Sun Nov 05 22:31:46 2006 +0000 @@ -130,6 +130,7 @@ SYMBOL (Qfile); SYMBOL_MODULE_API (Qfile_name); SYMBOL_KEYWORD (Q_filter); +SYMBOL (Qfinal); SYMBOL (Qfixnum); SYMBOL (Qfloat); SYMBOL (Qfont); @@ -157,6 +158,7 @@ SYMBOL (Qicon); SYMBOL (Qid); SYMBOL (Qignore); +SYMBOL (Qinitial); SYMBOL (Qimage); SYMBOL_KEYWORD (Q_image); SYMBOL_KEYWORD (Q_included); @@ -286,6 +288,7 @@ SYMBOL (Qundecided); SYMBOL (Qundefined); SYMBOL (Qunimplemented); +SYMBOL (Qunicode_registries); SYMBOL (Quser_default); SYMBOL_KEYWORD (Q_value); SYMBOL (Qvalue_assoc);
--- a/src/intl.c Sat Nov 04 22:51:03 2006 +0000 +++ b/src/intl.c Sun Nov 05 22:31:46 2006 +0000 @@ -167,7 +167,7 @@ void init_intl (void) { - /* This function can GC */ + /* This function cannot GC, because it explicitly prevents it. */ if (initialized) { int count = begin_gc_forbidden ();
--- a/src/lisp.h Sat Nov 04 22:51:03 2006 +0000 +++ b/src/lisp.h Sun Nov 05 22:31:46 2006 +0000 @@ -2623,6 +2623,13 @@ #define BIT_VECTOR_LONG_STORAGE(len) \ (((len) + LONGBITS_POWER_OF_2 - 1) >> LONGBITS_LOG2) +/* For when we want to include a bit vector in another structure, and we + know it's of a fixed size. */ +#define DECLARE_INLINE_LISP_BIT_VECTOR(numbits) struct { \ + struct LCRECORD_HEADER lheader; \ + Elemcount size; \ + unsigned long bits[BIT_VECTOR_LONG_STORAGE(numbits)]; \ +} /*------------------------------ symbol --------------------------------*/ @@ -5601,7 +5608,7 @@ extern Lisp_Object Qprogn, Qquit, Qquote, Qrange_error; extern Lisp_Object Qread_char, Qread_from_minibuffer; extern Lisp_Object Qreally_early_error_handler, Qregion_beginning; -extern Lisp_Object Qregion_end, Qregistry, Qreverse_direction_charset; +extern Lisp_Object Qregion_end, Qregistries, Qreverse_direction_charset; extern Lisp_Object Qrun_hooks, Qsans_modifiers, Qsave_buffers_kill_emacs; extern Lisp_Object Qself_insert_command, Qself_insert_defer_undo, Qsequencep; extern Lisp_Object Qset, Qsetting_constant, Qshort_name, Qsingularity_error;
--- a/src/mule-charset.c Sat Nov 04 22:51:03 2006 +0000 +++ b/src/mule-charset.c Sun Nov 05 22:31:46 2006 +0000 @@ -35,6 +35,7 @@ #include "lstream.h" #include "mule-ccl.h" #include "objects.h" +#include "specifier.h" /* The various pre-defined charsets. */ @@ -79,7 +80,7 @@ Lisp_Object Qcharsetp; /* Qdoc_string, Qdimension, Qchars defined in general.c */ -Lisp_Object Qregistry, Qfinal, Qgraphic; +Lisp_Object Qregistries, Qfinal, Qgraphic, Qregistry; Lisp_Object Qdirection; Lisp_Object Qreverse_direction_charset; Lisp_Object Qshort_name, Qlong_name; @@ -128,7 +129,7 @@ mark_object (cs->short_name); mark_object (cs->long_name); mark_object (cs->doc_string); - mark_object (cs->registry); + mark_object (cs->registries); mark_object (cs->ccl_program); return cs->name; } @@ -158,7 +159,7 @@ CHARSET_COLUMNS (cs), CHARSET_GRAPHIC (cs), CHARSET_FINAL (cs)); - print_internal (CHARSET_REGISTRY (cs), printcharfun, 0); + print_internal (CHARSET_REGISTRIES (cs), printcharfun, 0); write_fmt_string (printcharfun, " 0x%x>", cs->header.uid); } @@ -167,7 +168,7 @@ { XD_INT, offsetof (Lisp_Charset, from_unicode_levels) }, { XD_LISP_OBJECT, offsetof (Lisp_Charset, name) }, { XD_LISP_OBJECT, offsetof (Lisp_Charset, doc_string) }, - { XD_LISP_OBJECT, offsetof (Lisp_Charset, registry) }, + { XD_LISP_OBJECT, offsetof (Lisp_Charset, registries) }, { XD_LISP_OBJECT, offsetof (Lisp_Charset, short_name) }, { XD_LISP_OBJECT, offsetof (Lisp_Charset, long_name) }, { XD_LISP_OBJECT, offsetof (Lisp_Charset, reverse_direction_charset) }, @@ -239,7 +240,8 @@ CHARSET_GRAPHIC (cs) = graphic; CHARSET_FINAL (cs) = final; CHARSET_DOC_STRING (cs) = doc; - CHARSET_REGISTRY (cs) = reg; + CHECK_VECTOR(reg); + CHARSET_REGISTRIES (cs) = reg; CHARSET_ENCODE_AS_UTF_8 (cs) = encode_as_utf_8 ? 1 : 0; CHARSET_CCL_PROGRAM (cs) = Qnil; CHARSET_REVERSE_DIRECTION_CHARSET (cs) = Qnil; @@ -271,6 +273,8 @@ } recalculate_unicode_precedence (); + setup_charset_initial_specifier_tags (obj); + return obj; } @@ -419,8 +423,8 @@ `short-name' Short version of the charset name (ex: Latin-1) `long-name' Long version of the charset name (ex: ISO8859-1 (Latin-1)) -`registry' A regular expression matching the font registry field for - this character set. +`registries' A vector of possible XLFD REGISTRY-ENCODING combinations for + this character set. Note that this is not a regular expression. `dimension' Number of octets used to index a character in this charset. Either 1 or 2. Defaults to 1. `columns' Number of columns used to display a character in this charset. @@ -468,7 +472,7 @@ Ibyte final = 0; int direction = CHARSET_LEFT_TO_RIGHT; int type; - Lisp_Object registry = Qnil; + Lisp_Object registries = Qnil; Lisp_Object charset = Qnil; Lisp_Object ccl_program = Qnil; Lisp_Object short_name = Qnil, long_name = Qnil; @@ -538,10 +542,27 @@ invalid_constant ("Invalid value for `graphic'", value); } + else if (EQ (keyword, Qregistries)) + { + CHECK_VECTOR (value); + registries = value; + } + else if (EQ (keyword, Qregistry)) { + Lisp_Object quoted_registry; + CHECK_STRING (value); - registry = value; + quoted_registry = Fregexp_quote(value); + if (strcmp(XSTRING_DATA(quoted_registry), + XSTRING_DATA(value))) + { + warn_when_safe + (Qregistry, Qwarning, + "Regexps no longer allowed for charset-registry. " + "Treating %s as string", XSTRING_DATA(value)); + } + registries = vector1(value); } else if (EQ (keyword, Qdirection)) @@ -613,8 +634,8 @@ } if (NILP (doc_string)) doc_string = build_string (""); - if (NILP (registry)) - registry = build_string (""); + if (NILP (registries)) + registries = make_vector(0, Qnil); if (NILP (short_name)) short_name = XSYMBOL (name)->name; if (NILP (long_name)) @@ -624,7 +645,7 @@ charset = make_charset (id, name, dimension + 2, type, columns, graphic, final, direction, short_name, long_name, - doc_string, registry, !NILP (existing_charset), + doc_string, registries, !NILP (existing_charset), encode_as_utf_8); XCHARSET (charset)->temporary = temporary; @@ -657,7 +678,7 @@ int id, dimension, columns, graphic, encode_as_utf_8; Ibyte final; int direction, type; - Lisp_Object registry, doc_string, short_name, long_name; + Lisp_Object registries, doc_string, short_name, long_name; Lisp_Charset *cs; charset = Fget_charset (charset); @@ -684,12 +705,12 @@ doc_string = CHARSET_DOC_STRING (cs); short_name = CHARSET_SHORT_NAME (cs); long_name = CHARSET_LONG_NAME (cs); - registry = CHARSET_REGISTRY (cs); + registries = CHARSET_REGISTRIES (cs); encode_as_utf_8 = CHARSET_ENCODE_AS_UTF_8 (cs); new_charset = make_charset (id, new_name, dimension + 2, type, columns, graphic, final, direction, short_name, long_name, - doc_string, registry, 0, encode_as_utf_8); + doc_string, registries, 0, encode_as_utf_8); CHARSET_REVERSE_DIRECTION_CHARSET (cs) = new_charset; XCHARSET_REVERSE_DIRECTION_CHARSET (new_charset) = charset; @@ -820,7 +841,7 @@ if (EQ (prop, Qgraphic)) return make_int (CHARSET_GRAPHIC (cs)); if (EQ (prop, Qfinal)) return make_char (CHARSET_FINAL (cs)); if (EQ (prop, Qchars)) return make_int (CHARSET_CHARS (cs)); - if (EQ (prop, Qregistry)) return CHARSET_REGISTRY (cs); + if (EQ (prop, Qregistries)) return CHARSET_REGISTRIES (cs); if (EQ (prop, Qencode_as_utf_8)) return CHARSET_ENCODE_AS_UTF_8 (cs) ? Qt : Qnil; if (EQ (prop, Qccl_program)) return CHARSET_CCL_PROGRAM (cs); @@ -862,15 +883,39 @@ return Qnil; } -/* Japanese folks may want to (set-charset-registry 'ascii "jisx0201") */ -DEFUN ("set-charset-registry", Fset_charset_registry, 2, 2, 0, /* -Set the `registry' property of CHARSET to REGISTRY. +DEFUN ("set-charset-registries", Fset_charset_registries, 2, 2, 0, /* +Set the `registries' property of CHARSET to REGISTRIES. + +REGISTRIES is an ordered vector of strings that describe the X11 +CHARSET_REGISTRY and the CHARSET_ENCODINGs appropriate for this charset. +Separate each registry from the corresponding encoding with a dash. The +strings are not regular expressions, in contrast to the old behavior of +the `charset-registry' property. + +One reason to call this function might be if you're in Japan and you'd +prefer the backslash to display as a Yen sign; the corresponding syntax +would be: + +(set-charset-registries 'ascii ["jisx0201.1976-0"]) + */ - (charset, registry)) + (charset, registries)) { + int i; charset = Fget_charset (charset); - CHECK_STRING (registry); - XCHARSET_REGISTRY (charset) = registry; + CHECK_VECTOR (registries); + + for (i = 0; i < XVECTOR_LENGTH(registries); ++i) + { + CHECK_STRING (XVECTOR_DATA(registries)[i]); + if (NULL == qxestrchr(XSTRING_DATA(XVECTOR_DATA(registries)[i]), '-')) + { + invalid_argument("Not an X11 REGISTRY-ENCODING combination", + XVECTOR_DATA(registries)[i]); + } + } + + XCHARSET_REGISTRIES (charset) = registries; invalidate_charset_font_caches (charset); face_property_was_changed (Vdefault_face, Qfont, Qglobal); return Qnil; @@ -967,16 +1012,17 @@ DEFSUBR (Fcharset_property); DEFSUBR (Fcharset_id); DEFSUBR (Fset_charset_ccl_program); - DEFSUBR (Fset_charset_registry); + DEFSUBR (Fset_charset_registries); #ifdef MEMORY_USAGE_STATS DEFSUBR (Fcharset_memory_usage); #endif DEFSYMBOL (Qcharsetp); - DEFSYMBOL (Qregistry); + DEFSYMBOL (Qregistries); DEFSYMBOL (Qfinal); DEFSYMBOL (Qgraphic); + DEFSYMBOL (Qregistry); DEFSYMBOL (Qdirection); DEFSYMBOL (Qreverse_direction_charset); DEFSYMBOL (Qshort_name); @@ -1056,7 +1102,7 @@ build_string ("ASCII"), build_msg_string ("ASCII"), build_msg_string ("ASCII (ISO646 IRV)"), - build_string ("\\(iso8859-[0-9]*\\|-ascii\\)"), 0, 0); + vector1(build_string("iso8859-1")), 0, 0); staticpro (&Vcharset_control_1); Vcharset_control_1 = make_charset (LEADING_BYTE_CONTROL_1, Qcontrol_1, 2, @@ -1065,7 +1111,7 @@ build_string ("C1"), build_msg_string ("Control characters"), build_msg_string ("Control characters 128-191"), - build_string (""), 0, 0); + vector1(build_string("iso8859-1")), 0, 0); staticpro (&Vcharset_latin_iso8859_1); Vcharset_latin_iso8859_1 = make_charset (LEADING_BYTE_LATIN_ISO8859_1, Qlatin_iso8859_1, 2, @@ -1074,7 +1120,7 @@ build_string ("Latin-1"), build_msg_string ("ISO8859-1 (Latin-1)"), build_msg_string ("ISO8859-1 (Latin-1)"), - build_string ("iso8859-1"), 0, 0); + vector1(build_string("iso8859-1")), 0, 0); staticpro (&Vcharset_latin_iso8859_2); Vcharset_latin_iso8859_2 = make_charset (LEADING_BYTE_LATIN_ISO8859_2, Qlatin_iso8859_2, 2, @@ -1083,7 +1129,7 @@ build_string ("Latin-2"), build_msg_string ("ISO8859-2 (Latin-2)"), build_msg_string ("ISO8859-2 (Latin-2)"), - build_string ("iso8859-2"), 0, 0); + vector1(build_string("iso8859-2")), 0, 0); staticpro (&Vcharset_latin_iso8859_3); Vcharset_latin_iso8859_3 = make_charset (LEADING_BYTE_LATIN_ISO8859_3, Qlatin_iso8859_3, 2, @@ -1092,7 +1138,7 @@ build_string ("Latin-3"), build_msg_string ("ISO8859-3 (Latin-3)"), build_msg_string ("ISO8859-3 (Latin-3)"), - build_string ("iso8859-3"), 0, 0); + vector1(build_string("iso8859-3")), 0, 0); staticpro (&Vcharset_latin_iso8859_4); Vcharset_latin_iso8859_4 = make_charset (LEADING_BYTE_LATIN_ISO8859_4, Qlatin_iso8859_4, 2, @@ -1101,7 +1147,7 @@ build_string ("Latin-4"), build_msg_string ("ISO8859-4 (Latin-4)"), build_msg_string ("ISO8859-4 (Latin-4)"), - build_string ("iso8859-4"), 0, 0); + vector1(build_string("iso8859-2")), 0, 0); staticpro (&Vcharset_thai_tis620); Vcharset_thai_tis620 = make_charset (LEADING_BYTE_THAI_TIS620, Qthai_tis620, 2, @@ -1110,7 +1156,7 @@ build_string ("TIS620"), build_msg_string ("TIS620 (Thai)"), build_msg_string ("TIS620.2529 (Thai)"), - build_string ("tis620"), 0, 0); + vector1(build_string("tis620.2529-1")), 0, 0); staticpro (&Vcharset_greek_iso8859_7); Vcharset_greek_iso8859_7 = make_charset (LEADING_BYTE_GREEK_ISO8859_7, Qgreek_iso8859_7, 2, @@ -1119,7 +1165,7 @@ build_string ("ISO8859-7"), build_msg_string ("ISO8859-7 (Greek)"), build_msg_string ("ISO8859-7 (Greek)"), - build_string ("iso8859-7"), 0, 0); + vector1(build_string("iso8859-7")), 0, 0); staticpro (&Vcharset_arabic_iso8859_6); Vcharset_arabic_iso8859_6 = make_charset (LEADING_BYTE_ARABIC_ISO8859_6, Qarabic_iso8859_6, 2, @@ -1128,7 +1174,7 @@ build_string ("ISO8859-6"), build_msg_string ("ISO8859-6 (Arabic)"), build_msg_string ("ISO8859-6 (Arabic)"), - build_string ("iso8859-6"), 0, 0); + vector1(build_string ("iso8859-6")), 0, 0); staticpro (&Vcharset_hebrew_iso8859_8); Vcharset_hebrew_iso8859_8 = make_charset (LEADING_BYTE_HEBREW_ISO8859_8, Qhebrew_iso8859_8, 2, @@ -1137,7 +1183,7 @@ build_string ("ISO8859-8"), build_msg_string ("ISO8859-8 (Hebrew)"), build_msg_string ("ISO8859-8 (Hebrew)"), - build_string ("iso8859-8"), 0, 0); + vector1(build_string ("iso8859-8")), 0, 0); staticpro (&Vcharset_katakana_jisx0201); Vcharset_katakana_jisx0201 = make_charset (LEADING_BYTE_KATAKANA_JISX0201, Qkatakana_jisx0201, 2, @@ -1146,7 +1192,7 @@ build_string ("JISX0201 Kana"), build_msg_string ("JISX0201.1976 (Japanese Kana)"), build_msg_string ("JISX0201.1976 Japanese Kana"), - build_string ("jisx0201.1976"), 0, 0); + vector1(build_string ("jisx0201.1976-0")), 0, 0); staticpro (&Vcharset_latin_jisx0201); Vcharset_latin_jisx0201 = make_charset (LEADING_BYTE_LATIN_JISX0201, Qlatin_jisx0201, 2, @@ -1155,7 +1201,7 @@ build_string ("JISX0201 Roman"), build_msg_string ("JISX0201.1976 (Japanese Roman)"), build_msg_string ("JISX0201.1976 Japanese Roman"), - build_string ("jisx0201.1976"), 0, 0); + vector1(build_string ("jisx0201.1976-0")), 0, 0); staticpro (&Vcharset_cyrillic_iso8859_5); Vcharset_cyrillic_iso8859_5 = make_charset (LEADING_BYTE_CYRILLIC_ISO8859_5, Qcyrillic_iso8859_5, 2, @@ -1164,7 +1210,7 @@ build_string ("ISO8859-5"), build_msg_string ("ISO8859-5 (Cyrillic)"), build_msg_string ("ISO8859-5 (Cyrillic)"), - build_string ("iso8859-5"), 0, 0); + vector1(build_string ("iso8859-5")), 0, 0); staticpro (&Vcharset_latin_iso8859_9); Vcharset_latin_iso8859_9 = make_charset (LEADING_BYTE_LATIN_ISO8859_9, Qlatin_iso8859_9, 2, @@ -1173,7 +1219,7 @@ build_string ("Latin-5"), build_msg_string ("ISO8859-9 (Latin-5)"), build_msg_string ("ISO8859-9 (Latin-5)"), - build_string ("iso8859-9"), 0, 0); + vector1(build_string ("iso8859-9")), 0, 0); staticpro (&Vcharset_latin_iso8859_15); Vcharset_latin_iso8859_15 = make_charset (LEADING_BYTE_LATIN_ISO8859_15, Qlatin_iso8859_15, 2, @@ -1182,7 +1228,7 @@ build_string ("Latin-9"), build_msg_string ("ISO8859-15 (Latin-9)"), build_msg_string ("ISO8859-15 (Latin-9)"), - build_string ("iso8859-15"), 0, 0); + vector1(build_string ("iso8859-15")), 0, 0); staticpro (&Vcharset_japanese_jisx0208_1978); Vcharset_japanese_jisx0208_1978 = make_charset (LEADING_BYTE_JAPANESE_JISX0208_1978, Qjapanese_jisx0208_1978, 3, @@ -1192,7 +1238,8 @@ build_msg_string ("JISX0208.1978 (Japanese)"), build_msg_string ("JISX0208.1978 Japanese Kanji (so called \"old JIS\")"), - build_string ("\\(jisx0208\\|jisc6226\\)\\.1978"), 0, 0); + vector2(build_string("jisx0208.1978-0"), + build_string("jisc6226.1978-0")), 0, 0); staticpro (&Vcharset_chinese_gb2312); Vcharset_chinese_gb2312 = make_charset (LEADING_BYTE_CHINESE_GB2312, Qchinese_gb2312, 3, @@ -1201,7 +1248,8 @@ build_string ("GB2312"), build_msg_string ("GB2312)"), build_msg_string ("GB2312 Chinese simplified"), - build_string ("gb2312"), 0, 0); + vector2(build_string("gb2312.1980-0"), + build_string("gb2312.80&gb8565.88-0")), 0, 0); staticpro (&Vcharset_japanese_jisx0208); Vcharset_japanese_jisx0208 = make_charset (LEADING_BYTE_JAPANESE_JISX0208, Qjapanese_jisx0208, 3, @@ -1210,7 +1258,8 @@ build_string ("JISX0208"), build_msg_string ("JISX0208.1983/1990 (Japanese)"), build_msg_string ("JISX0208.1983/1990 Japanese Kanji"), - build_string ("jisx0208.19\\(83\\|90\\)"), 0, 0); + vector2(build_string("jisx0208.1983-0"), + build_string("jisx0208.1990-0")), 0, 0); staticpro (&Vcharset_korean_ksc5601); Vcharset_korean_ksc5601 = make_charset (LEADING_BYTE_KOREAN_KSC5601, Qkorean_ksc5601, 3, @@ -1219,7 +1268,7 @@ build_string ("KSC5601"), build_msg_string ("KSC5601 (Korean"), build_msg_string ("KSC5601 Korean Hangul and Hanja"), - build_string ("ksc5601"), 0, 0); + vector1(build_string("ksc5601.1987-0")), 0, 0); staticpro (&Vcharset_japanese_jisx0212); Vcharset_japanese_jisx0212 = make_charset (LEADING_BYTE_JAPANESE_JISX0212, Qjapanese_jisx0212, 3, @@ -1228,9 +1277,9 @@ build_string ("JISX0212"), build_msg_string ("JISX0212 (Japanese)"), build_msg_string ("JISX0212 Japanese Supplement"), - build_string ("jisx0212"), 0, 0); + vector1(build_string("jisx0212.1990-0")), 0, 0); -#define CHINESE_CNS_PLANE_RE(n) "cns11643[.-]\\(.*[.-]\\)?" n "$" +#define CHINESE_CNS_PLANE(n) "cns11643.1992-" n staticpro (&Vcharset_chinese_cns11643_1); Vcharset_chinese_cns11643_1 = make_charset (LEADING_BYTE_CHINESE_CNS11643_1, Qchinese_cns11643_1, 3, @@ -1240,7 +1289,7 @@ build_msg_string ("CNS11643-1 (Chinese traditional)"), build_msg_string ("CNS 11643 Plane 1 Chinese traditional"), - build_string (CHINESE_CNS_PLANE_RE("1")), 0, 0); + vector1(build_string (CHINESE_CNS_PLANE("1"))), 0, 0); staticpro (&Vcharset_chinese_cns11643_2); Vcharset_chinese_cns11643_2 = make_charset (LEADING_BYTE_CHINESE_CNS11643_2, Qchinese_cns11643_2, 3, @@ -1250,7 +1299,7 @@ build_msg_string ("CNS11643-2 (Chinese traditional)"), build_msg_string ("CNS 11643 Plane 2 Chinese traditional"), - build_string (CHINESE_CNS_PLANE_RE("2")), 0, 0); + vector1(build_string (CHINESE_CNS_PLANE("2"))), 0, 0); staticpro (&Vcharset_chinese_big5_1); Vcharset_chinese_big5_1 = make_charset (LEADING_BYTE_CHINESE_BIG5_1, Qchinese_big5_1, 3, @@ -1260,7 +1309,7 @@ build_msg_string ("Big5 (Level-1)"), build_msg_string ("Big5 Level-1 Chinese traditional"), - build_string ("big5"), 0, 0); + vector1(build_string ("big5.eten-0")), 0, 0); staticpro (&Vcharset_chinese_big5_2); Vcharset_chinese_big5_2 = make_charset (LEADING_BYTE_CHINESE_BIG5_2, Qchinese_big5_2, 3, @@ -1270,7 +1319,7 @@ build_msg_string ("Big5 (Level-2)"), build_msg_string ("Big5 Level-2 Chinese traditional"), - build_string ("big5"), 0, 0); + vector1(build_string ("big5.eten-0")), 0, 0); #ifdef ENABLE_COMPOSITE_CHARS @@ -1285,7 +1334,7 @@ build_string ("Composite"), build_msg_string ("Composite characters"), build_msg_string ("Composite characters"), - build_string (""), 0, 0); + vector1(build_string ("")), 0, 0); #else /* We create a hack so that we have a way of storing ESC 0 and ESC 1 sequences as "characters", so that they will be output correctly. */ @@ -1297,6 +1346,6 @@ build_string ("Composite hack"), build_msg_string ("Composite characters hack"), build_msg_string ("Composite characters hack"), - build_string (""), 0, 0); + vector1(build_string ("")), 0, 0); #endif /* ENABLE_COMPOSITE_CHARS */ }
--- a/src/objects-gtk.c Sat Nov 04 22:51:03 2006 +0000 +++ b/src/objects-gtk.c Sun Nov 05 22:31:46 2006 +0000 @@ -40,6 +40,14 @@ /* sigh */ #include <gdk/gdkx.h> +/* XListFonts doesn't allocate memory unconditionally based on this. (For + XFree86 in 2005, at least. */ +#define MAX_FONT_COUNT INT_MAX + +#ifdef DEBUG_XEMACS +Fixnum debug_x_objects; +#endif /* DEBUG_XEMACS */ + /************************************************************************/ /* color instances */ @@ -379,66 +387,9 @@ return (__gtk_font_list_internal (patternext)); } -#ifdef MULE - -static int -gtk_font_spec_matches_charset (struct device *UNUSED (d), Lisp_Object charset, - const Ibyte *nonreloc, Lisp_Object reloc, - Bytecount offset, Bytecount length, - int stage) -{ - if (stage) - return 0; - - if (UNBOUNDP (charset)) - return 1; - /* Hack! Short font names don't have the registry in them, - so we just assume the user knows what they're doing in the - case of ASCII. For other charsets, you gotta give the - long form; sorry buster. - */ - if (EQ (charset, Vcharset_ascii)) - { - const Ibyte *the_nonreloc = nonreloc; - int i; - Bytecount the_length = length; - - if (!the_nonreloc) - the_nonreloc = XSTRING_DATA (reloc); - fixup_internal_substring (nonreloc, reloc, offset, &the_length); - the_nonreloc += offset; - if (!memchr (the_nonreloc, '*', the_length)) - { - for (i = 0;; i++) - { - const Ibyte *new_nonreloc = (const Ibyte *) - memchr (the_nonreloc, '-', the_length); - if (!new_nonreloc) - break; - new_nonreloc++; - the_length -= new_nonreloc - the_nonreloc; - the_nonreloc = new_nonreloc; - } - - /* If it has less than 5 dashes, it's a short font. - Of course, long fonts always have 14 dashes or so, but short - fonts never have more than 1 or 2 dashes, so this is some - sort of reasonable heuristic. */ - if (i < 5) - return 1; - } - } - - return (fast_string_match (XCHARSET_REGISTRY (charset), - nonreloc, reloc, offset, length, 1, - ERROR_ME, 0) >= 0); -} - -/* find a font spec that matches font spec FONT and also matches - (the registry of) CHARSET. */ -static Lisp_Object gtk_find_charset_font (Lisp_Object device, Lisp_Object font, Lisp_Object charset, int stage); - -#endif /* MULE */ +/* Include the charset support, shared, for the moment, with X11. */ +#define THIS_IS_GTK +#include "objects-xlike-inc.c" /************************************************************************/ @@ -479,63 +430,14 @@ void vars_of_objects_gtk (void) { +#ifdef DEBUG_XEMACS + DEFVAR_INT ("debug-x-objects", &debug_x_objects /* +If non-zero, display debug information about X objects +*/ ); + debug_x_objects = 0; +#endif } -/* #### BILL!!! Try to make this go away eventually */ -/* X Specific stuff */ -#include <X11/Xatom.h> - -#define MAX_FONT_COUNT INT_MAX - -#ifdef MULE -/* find a font spec that matches font spec FONT and also matches - (the registry of) CHARSET. */ -static Lisp_Object -gtk_find_charset_font (Lisp_Object device, Lisp_Object font, - Lisp_Object charset, int stage) -{ - char **names; - int count = 0; - Lisp_Object result = Qnil; - const char *patternext; - int i; - - if (stage) - return Qnil; - - TO_EXTERNAL_FORMAT (LISP_STRING, font, C_STRING_ALLOCA, patternext, Qbinary); - - names = XListFonts (GDK_DISPLAY (), - patternext, MAX_FONT_COUNT, &count); - /* #### This code seems awfully bogus -- mrb */ - for (i = 0; i < count; i ++) - { - const Ibyte *intname; - Bytecount intlen; - - TO_INTERNAL_FORMAT (C_STRING, names[i], ALLOCA, (intname, intlen), - Qctext); - if (gtk_font_spec_matches_charset (XDEVICE (device), charset, - intname, Qnil, 0, -1, 0)) - { - result = make_string (intname, intlen); - break; - } - } - - if (names) - XFreeFontNames (names); - - /* Check for a short font name. */ - if (NILP (result) - && gtk_font_spec_matches_charset (XDEVICE (device), charset, 0, - font, 0, -1, 0)) - return font; - - return result; -} -#endif /* MULE */ - static int valid_font_name_p (Display *dpy, char *name) {
--- a/src/objects-msw.c Sat Nov 04 22:51:03 2006 +0000 +++ b/src/objects-msw.c Sun Nov 05 22:31:46 2006 +0000 @@ -2182,7 +2182,8 @@ static Lisp_Object mswindows_find_charset_font (Lisp_Object device, Lisp_Object font, - Lisp_Object charset, int stage) + Lisp_Object charset, + enum font_specifier_matchspec_stages stage) { Lisp_Object fontlist, fonttail;
--- a/src/objects-tty.c Sat Nov 04 22:51:03 2006 +0000 +++ b/src/objects-tty.c Sun Nov 05 22:31:46 2006 +0000 @@ -367,7 +367,8 @@ (the registry of) CHARSET. */ static Lisp_Object tty_find_charset_font (Lisp_Object device, Lisp_Object font, - Lisp_Object charset, int stage) + Lisp_Object charset, + enum font_specifier_matchspec_stages stage) { Ibyte *fontname = XSTRING_DATA (font);
--- a/src/objects-x.c Sat Nov 04 22:51:03 2006 +0000 +++ b/src/objects-x.c Sun Nov 05 22:31:46 2006 +0000 @@ -37,6 +37,7 @@ #include "console-x-impl.h" #include "objects-x-impl.h" +#include "elhash.h" #ifdef USE_XFT #include "font-mgr.h" @@ -44,6 +45,10 @@ int x_handle_non_fully_specified_fonts; +#ifdef DEBUG_XEMACS +Fixnum debug_x_objects; +#endif /* DEBUG_XEMACS */ + /************************************************************************/ /* color instances */ @@ -205,74 +210,6 @@ /* font instances */ /************************************************************************/ -#ifdef USE_XFT -/* #### all these #defines should probably move to font-mgr.h */ - -/* - The format of a fontname (as returned by fontconfig) is not well-documented, - But the character repertoire is represented in an ASCII-compatible way. See - fccharset.c (FcCharSetUnparse). So we can use UTF-8 for long names. - - Currently we have a hack where different versions of the unparsed name are - used in different contexts fairly arbitrarily. I don't think this is close - to coherency; even without the charset and lang properties fontconfig names - are too unwieldy to use. We need to rethink the approach here. I think - probably Lisp_Font_Instance.name should contain the font name as specified - to Lisp (almost surely much shorter than shortname, even, and most likely - wildcarded), while Lisp_Font_Instance.truename should contain the longname. - For now, I'm going to #ifdef the return values defaulting to short. -- sjt -*/ - -/* DEBUGGING STUFF */ - -/* print message to stderr: one internal-format string argument */ -#define DEBUG_XFT0(level,s) \ - if (debug_xft > level) stderr_out (s) - -/* print message to stderr: one formatted argument */ -#define DEBUG_XFT1(level,format,x1) \ - if (debug_xft > level) stderr_out (format, x1) - -/* print message to stderr: two formatted arguments */ -#define DEBUG_XFT2(level,format,x1,x2) \ - if (debug_xft > level) stderr_out (format, x1, x2) - -/* print message to stderr: three formatted arguments */ -#define DEBUG_XFT3(level,format,x1,x2,x3) \ - if (debug_xft > level) stderr_out (format, x1, x2, x3) - -/* print message to stderr: four formatted arguments */ -#define DEBUG_XFT4(level,format,x1,x2,x3,x4) \ - if (debug_xft > level) stderr_out (format, x1, x2, x3, x4) - -/* print an Xft pattern to stderr - LEVEL is the debug level (to compare to debug_xft) - FORMAT is a newline-terminated printf format with one %s for the pattern - and must be internal format (eg, pure ASCII) - PATTERN is an FcPattern *. */ -#define PRINT_XFT_PATTERN(level,format,pattern) \ - do { \ - DECLARE_EISTRING (eistrpxft_name); \ - Extbyte *name = (Extbyte *) FcNameUnparse (pattern); \ - \ - eicpy_ext(eistrpxft_name, name, Qfc_font_name_encoding); \ - DEBUG_XFT1 (level, format, eidata(eistrpxft_name)); \ - free (name); \ - } while (0) - -/* print a progress message - LEVEL is the debug level (to compare to debug_xft) - FONT is the Xft font name in UTF-8 (the native encoding of Xft) - LANG is the language being checked for support (must be ASCII). */ -#define CHECKING_LANG(level,font,lang) \ - do { \ - DECLARE_EISTRING (eistrcl_name); \ - eicpy_ext(eistrcl_name, (Extbyte *) font, Qfc_font_name_encoding); \ - DEBUG_XFT2 (level, "checking if %s handles %s\n", \ - eidata(eistrcl_name), lang); \ - } while (0) - -#endif /* USE_XFT */ static int x_initialize_font_instance (Lisp_Font_Instance *f, Lisp_Object UNUSED (name), @@ -299,6 +236,12 @@ rf = xft_open_font_by_name (dpy, extname); #endif LISP_STRING_TO_EXTERNAL (f->name, extname, Qx_font_name_encoding); + /* With XFree86 4.0's fonts, XListFonts returns an entry for + -isas-fangsong ti-medium-r-normal--16-160-72-72-c-160-gb2312.1980-0 but + an XLoadQueryFont on the corresponding XLFD returns NULL. + + XListFonts is not trustworthy (of course, this is news to exactly + no-one used to reading XEmacs source.) */ fs = XLoadQueryFont (dpy, extname); if (!fs && !rf) @@ -461,9 +404,13 @@ Lisp_Object printcharfun, int UNUSED (escapeflag)) { + /* We should print information here about initial vs. final stages; we + can't rely on the device charset stage cache for that, + unfortunately. */ if (FONT_INSTANCE_X_FONT (f)) - write_fmt_string (printcharfun, " font id: 0x%lx", - (unsigned long) FONT_INSTANCE_X_FONT (f)->fid); + write_fmt_string (printcharfun, " font id: 0x%lx,", + (unsigned long) FONT_INSTANCE_X_FONT (f)->fid); + #ifdef USE_XFT /* #### What should we do here? For now, print the address. */ if (FONT_INSTANCE_X_XFTFONT (f)) @@ -944,534 +891,9 @@ return result; } -#ifdef MULE - -static int -x_font_spec_matches_charset (struct device * USED_IF_XFT (d), - Lisp_Object charset, - const Ibyte *nonreloc, Lisp_Object reloc, - Bytecount offset, Bytecount length, - int stage) -{ - if (stage) -#ifdef USE_XFT - { - Display *dpy = DEVICE_X_DISPLAY (d); - Extbyte *extname; - XftFont *rf; - const Ibyte *the_nonreloc; - - if (!NILP(reloc)) - { - the_nonreloc = XSTRING_DATA (reloc); - LISP_STRING_TO_EXTERNAL (reloc, extname, Qx_font_name_encoding); - rf = xft_open_font_by_name (dpy, extname); - return 0; /* #### maybe this will compile and run ;) */ - } - } -#else - return 0; -#endif - - if (UNBOUNDP (charset)) - return 1; - /* Hack! Short font names don't have the registry in them, - so we just assume the user knows what they're doing in the - case of ASCII. For other charsets, you gotta give the - long form; sorry buster. - #### FMH: this screws fontconfig/Xft? - STRATEGY: use fontconfig's ability to hack languages and character - sets (lang and charset properties). - #### Maybe we can use the fontconfig model to eliminate the difference - between faces and fonts? No - it looks like that would be an abuse - (fontconfig doesn't know about colors, although Xft does). - */ - if (EQ (charset, Vcharset_ascii)) - { - const Ibyte *the_nonreloc = nonreloc; - int i; - Bytecount the_length = length; - - if (!the_nonreloc) - the_nonreloc = XSTRING_DATA (reloc); - fixup_internal_substring (nonreloc, reloc, offset, &the_length); - the_nonreloc += offset; - if (!memchr (the_nonreloc, '*', the_length)) - { - for (i = 0;; i++) - { - const Ibyte *new_nonreloc = (const Ibyte *) - memchr (the_nonreloc, '-', the_length); - if (!new_nonreloc) - break; - new_nonreloc++; - the_length -= new_nonreloc - the_nonreloc; - the_nonreloc = new_nonreloc; - } - - /* If it has less than 5 dashes, it's a short font. - Of course, long fonts always have 14 dashes or so, but short - fonts never have more than 1 or 2 dashes, so this is some - sort of reasonable heuristic. */ - if (i < 5) - return 1; - } - } - - return (fast_string_match (XCHARSET_REGISTRY (charset), - nonreloc, reloc, offset, length, 1, - ERROR_ME, 0) >= 0); -} - -#ifdef USE_XFT -/* #### debug functions: find a better place for us */ -const char *FcResultToString (FcResult r); -const char * -FcResultToString (FcResult r) -{ - static char buffer[256]; - switch (r) - { - case FcResultMatch: - return "FcResultMatch"; - case FcResultNoMatch: - return "FcResultNoMatch"; - case FcResultTypeMismatch: - return "FcResultTypeMismatch"; - case FcResultNoId: - return "FcResultNoId"; - default: - snprintf (buffer, 255, "FcResultUndocumentedValue (%d)", r); - return buffer; - } -} - -const char *FcTypeOfValueToString (FcValue v); -const char * -FcTypeOfValueToString (FcValue v) -{ - static char buffer[256]; - switch (v.type) - { - case FcTypeMatrix: - return "FcTypeMatrix"; - case FcTypeString: - return "FcTypeString"; - case FcTypeVoid: - return "FcTypeVoid"; - case FcTypeDouble: - return "FcTypeDouble"; - case FcTypeInteger: - return "FcTypeInteger"; - case FcTypeBool: - return "FcTypeBool"; - case FcTypeCharSet: - return "FcTypeCharSet"; - case FcTypeLangSet: - return "FcTypeLangSet"; - /* #### There is no union member of this type, but there are void* and - FcPattern* members, as of fontconfig.h FC_VERSION 10002 */ - case FcTypeFTFace: - return "FcTypeFTFace"; - default: - snprintf (buffer, 255, "FcTypeUndocumentedType (%d)", v.type); - return buffer; - } -} - -static FcCharSet * -mule_to_fc_charset (Lisp_Object cs) -{ - int ucode, i, j; - FcCharSet *fccs; - - CHECK_CHARSET (cs); - fccs = FcCharSetCreate (); - /* #### do we also need to deal with 94 vs. 96 charsets? - ie, how are SP and DEL treated in ASCII? non-graphic should return -1 */ - if (1 == XCHARSET_DIMENSION (cs)) - /* Unicode tables are indexed by offsets from ASCII SP, not by ASCII */ - for (i = 0; i < 96; i++) - { - ucode = ((int *) XCHARSET_TO_UNICODE_TABLE (cs))[i]; - if (ucode >= 0) - /* #### should check for allocation failure */ - FcCharSetAddChar (fccs, (FcChar32) ucode); - } - else if (2 == XCHARSET_DIMENSION (cs)) - /* Unicode tables are indexed by offsets from ASCII SP, not by ASCII */ - for (i = 0; i < 96; i++) - for (j = 0; j < 96; j++) - { - ucode = ((int **) XCHARSET_TO_UNICODE_TABLE (cs))[i][j]; - if (ucode >= 0) - /* #### should check for allocation failure */ - FcCharSetAddChar (fccs, (FcChar32) ucode); - } - else - { - FcCharSetDestroy (fccs); - fccs = NULL; - } - return fccs; -} - -struct charset_reporter { - Lisp_Object *charset; - /* This is a debug facility, require ASCII. */ - Extbyte *language; /* ASCII, please */ - /* Technically this is FcChar8, but fsckin' GCC 4 bitches. */ - Extbyte *rfc3066; /* ASCII, please */ -}; - -static struct charset_reporter charset_table[] = - { - /* #### It's my branch, my favorite charsets get checked first! - That's a joke, Son. - Ie, I don't know what I'm doing, so my charsets first is as good as - any other arbitrary order. If you have a better idea, speak up! */ - { &Vcharset_ascii, "English", "en" }, - { &Vcharset_japanese_jisx0208, "Japanese", "ja" }, - { &Vcharset_japanese_jisx0212, "Japanese", "ja" }, - { &Vcharset_katakana_jisx0201, "Japanese", "ja" }, - { &Vcharset_latin_jisx0201, "Japanese", "ja" }, - { &Vcharset_japanese_jisx0208_1978, "Japanese", "ja" }, - { &Vcharset_greek_iso8859_7, "Greek", "el" }, - /* #### all the Chinese need checking - Damn the blood-sucking ISO anyway. */ - { &Vcharset_chinese_gb2312, "simplified Chinese", "zh-CN" }, - { &Vcharset_korean_ksc5601, "Korean", "ko" }, - { &Vcharset_chinese_cns11643_1, "traditional Chinese", "zh-TW" }, - { &Vcharset_chinese_cns11643_2, "traditional Chinese", "zh-TW" }, - { &Vcharset_latin_iso8859_1, NULL, NULL }, - { &Vcharset_latin_iso8859_2, NULL, NULL }, - { &Vcharset_latin_iso8859_3, NULL, NULL }, - { &Vcharset_latin_iso8859_4, NULL, NULL }, - { &Vcharset_latin_iso8859_9, NULL, NULL }, - { &Vcharset_latin_iso8859_15, NULL, NULL }, - { &Vcharset_thai_tis620, NULL, NULL }, - { &Vcharset_arabic_iso8859_6, NULL, NULL }, - { &Vcharset_hebrew_iso8859_8, "Hebrew", "he" }, - { &Vcharset_cyrillic_iso8859_5, NULL, NULL }, - /* #### these probably are not quite right */ - { &Vcharset_chinese_big5_1, "traditional Chinese", "zh-TW" }, - { &Vcharset_chinese_big5_2, "traditional Chinese", "zh-TW" }, - { NULL, NULL, NULL } - }; - -/* Choose appropriate font name for debug messages. - Use only in the top half of next function (enforced with #undef). */ -#define DECLARE_DEBUG_FONTNAME(__xemacs_name) \ - Eistring *__xemacs_name; \ - do \ - { \ - __xemacs_name = debug_xft > 2 ? eistr_fullname \ - : debug_xft > 1 ? eistr_longname \ - : eistr_shortname; \ - } while (0) - -#endif /* USE_XFT */ - -/* find a font spec that matches font spec FONT and also matches - (the registry of) CHARSET. */ -static Lisp_Object -x_find_charset_font (Lisp_Object device, Lisp_Object font, Lisp_Object charset, - int stage) -{ - Extbyte **names; - int count = 0; - const Extbyte *patternext; - Lisp_Object result = Qnil; - int i; - - /* #### with Xft need to handle second stage here -- sjt - Hm. Or maybe not. That would be cool. :-) */ - if (stage) - return Qnil; - -#ifdef USE_XFT - /* Fontconfig converts all FreeType names to UTF-8 before passing them - back to callers---see fcfreetype.c (FcFreeTypeQuery). - I don't believe this is documented. */ - - DEBUG_XFT1 (1, "confirming charset for font instance %s\n", - XSTRING_DATA(font)); - - /* #### this looks like a fair amount of work, but the basic design - has never been rethought, and it should be - - what really should happen here is that we use FcFontSort (FcFontList?) - to get a list of matching fonts, then pick the first (best) one that - gives language or repertoire coverage. - */ - - FcInit (); /* No-op if already initialized. - In fontconfig 2.3.2, this cannot return - failure, but that looks like a bug. We - check for it with FcGetCurrentConfig(), - which *can* fail. */ - if (!FcConfigGetCurrent()) /* #### We should expose FcInit* interfaces - to LISP and decide when to reinitialize - intelligently. */ - stderr_out ("Failed fontconfig initialization\n"); - else - { - FcPattern *fontxft; /* long-lived, freed at end of this block */ - FcResult fcresult; - FcConfig *fcc; - FcChar8 *lang = (FcChar8 *) "en"; /* #### fix this bogus hack! */ - FcCharSet *fccs = NULL; - DECLARE_EISTRING (eistr_shortname); /* user-friendly nickname */ - DECLARE_EISTRING (eistr_longname); /* omit FC_LANG and FC_CHARSET */ - DECLARE_EISTRING (eistr_fullname); /* everything */ - - LISP_STRING_TO_EXTERNAL (font, patternext, Qfc_font_name_encoding); - fcc = FcConfigGetCurrent (); - - /* parse the name, do the substitutions, and match the font */ - - { - FcPattern *p = FcNameParse ((FcChar8 *) patternext); - PRINT_XFT_PATTERN (3, "FcNameParse'ed name is %s\n", p); - /* #### Next two return FcBool, but what does the return mean? */ - /* The order is correct according the fontconfig docs. */ - FcConfigSubstitute (fcc, p, FcMatchPattern); - PRINT_XFT_PATTERN (2, "FcConfigSubstitute'ed name is %s\n", p); - FcDefaultSubstitute (p); - PRINT_XFT_PATTERN (3, "FcDefaultSubstitute'ed name is %s\n", p); - /* #### check fcresult of following match? */ - fontxft = FcFontMatch (fcc, p, &fcresult); - /* this prints the long fontconfig name */ - PRINT_XFT_PATTERN (1, "FcFontMatch'ed name is %s\n", fontxft); - FcPatternDestroy (p); - } - - /* heuristic to give reasonable-length names for debug reports - - I considered #ifdef SUPPORT_FULL_FONTCONFIG_NAME etc but that's - pointless. We're just going to remove this code once the font/ - face refactoring is done, but until then it could be very useful. - */ - { - FcPattern *p = FcFontRenderPrepare (fcc, fontxft, fontxft); - FcChar8 *name; - - /* full name, including language coverage and repertoire */ - name = FcNameUnparse (p); - eicpy_ext (eistr_fullname, (Extbyte *) name, Qfc_font_name_encoding); - free (name); - - /* long name, omitting coverage and repertoire, plus a number - of rarely useful properties */ - FcPatternDel (p, FC_CHARSET); - FcPatternDel (p, FC_LANG); - FcPatternDel (p, FC_WIDTH); - FcPatternDel (p, FC_SPACING); - FcPatternDel (p, FC_HINTING); - FcPatternDel (p, FC_VERTICAL_LAYOUT); - FcPatternDel (p, FC_AUTOHINT); - FcPatternDel (p, FC_GLOBAL_ADVANCE); - FcPatternDel (p, FC_INDEX); - FcPatternDel (p, FC_SCALE); - FcPatternDel (p, FC_FONTVERSION); - name = FcNameUnparse (p); - eicpy_ext (eistr_longname, (Extbyte *) name, Qfc_font_name_encoding); - free (name); - - /* nickname, just family and size, but - "family" names usually have style, slant, and weight */ - FcPatternDel (p, FC_FOUNDRY); - FcPatternDel (p, FC_STYLE); - FcPatternDel (p, FC_SLANT); - FcPatternDel (p, FC_WEIGHT); - FcPatternDel (p, FC_PIXEL_SIZE); - FcPatternDel (p, FC_OUTLINE); - FcPatternDel (p, FC_SCALABLE); - FcPatternDel (p, FC_DPI); - name = FcNameUnparse (p); - eicpy_ext (eistr_shortname, (Extbyte *) name, Qfc_font_name_encoding); - free (name); - - FcPatternDestroy (p); - } - - /* The language approach may better in the long run, but we can't use - it based on Mule charsets; fontconfig doesn't provide a way to test - for unions of languages, etc. That will require support from the - text module. - - Optimization: cache the generated FcCharSet in the Mule charset. - Don't forget to destroy it if the Mule charset gets deallocated. */ - - { - /* This block possibly should be a function, but it generates - multiple values. I find the "pass an address to return the - value in" idiom opaque, so prefer a block. */ - struct charset_reporter *cr; - for (cr = charset_table; - cr->charset && !EQ (*(cr->charset), charset); - cr++) - ; - - if (cr->rfc3066) - { - DECLARE_DEBUG_FONTNAME (name); - CHECKING_LANG (0, eidata(name), cr->language); - lang = (FcChar8 *) cr->rfc3066; - } - else if (cr->charset) - { - /* what the hey, build 'em on the fly */ - /* #### in the case of error this could return NULL! */ - fccs = mule_to_fc_charset (charset); - lang = (FcChar8 *) XSTRING_DATA (XSYMBOL - (XCHARSET_NAME (charset))-> name); - } - else - { - /* OK, we fell off the end of the table */ - warn_when_safe_lispobj (intern ("xft"), intern ("alert"), - list2 (build_string ("unchecked charset"), - charset)); - /* default to "en" - #### THIS IS WRONG, WRONG, WRONG!! - It is why we never fall through to XLFD-checking. */ - } - - ASSERT_ASCTEXT_ASCII((Extbyte *) lang); - } - - if (fccs) - { - /* check for character set coverage */ - int i = 0; - FcCharSet *v; - FcResult r = FcPatternGetCharSet (fontxft, FC_CHARSET, i, &v); - - if (r == FcResultTypeMismatch) - { - DEBUG_XFT0 (0, "Unexpected type return in charset value\n"); - result = Qnil; - } - else if (r == FcResultMatch && FcCharSetIsSubset (fccs, v)) - { - /* The full pattern with the bitmap coverage is massively - unwieldy, but the shorter names are's just *wrong*. We - should have the full thing internally as truename, and - filter stuff the client doesn't want to see on output. - Should we just store it into the truename right here? */ - DECLARE_DEBUG_FONTNAME (name); - DEBUG_XFT2 (0, "Xft font %s supports %s\n", - eidata(name), lang); -#ifdef RETURN_LONG_FONTCONFIG_NAMES - result = eimake_string(eistr_fullname); -#else - result = eimake_string(eistr_longname); -#endif - } - else - { - DECLARE_DEBUG_FONTNAME (name); - DEBUG_XFT2 (0, "Xft font %s doesn't support %s\n", - eidata(name), lang); - result = Qnil; - } - - /* clean up */ - FcCharSetDestroy (fccs); - } - else - { - /* check for language coverage */ - int i = 0; - FcValue v; - /* the main event */ - FcResult r = FcPatternGet (fontxft, FC_LANG, i, &v); - - if (r == FcResultMatch) - { - if (v.type != FcTypeLangSet) /* excessive paranoia */ - { - ASSERT_ASCTEXT_ASCII(FcTypeOfValueToString(v)); - /* Urk! Fall back and punt to core font. */ - DEBUG_XFT1 (0, "Unexpected type of lang value (%s)\n", - FcTypeOfValueToString (v)); - result = Qnil; - } - else if (FcLangSetHasLang (v.u.l, lang) != FcLangDifferentLang) - { - DECLARE_DEBUG_FONTNAME (name); - DEBUG_XFT2 (0, "Xft font %s supports %s\n", - eidata(name), lang); -#ifdef RETURN_LONG_FONTCONFIG_NAMES - result = eimake_string(eistr_fullname); -#else - result = eimake_string(eistr_longname); -#endif - } - else - { - DECLARE_DEBUG_FONTNAME (name); - DEBUG_XFT2 (0, "Xft font %s doesn't support %s\n", - eidata(name), lang); - result = Qnil; - } - } - else - { - ASSERT_ASCTEXT_ASCII(FcResultToString(r)); - DEBUG_XFT1 (0, "Getting lang: unexpected result=%s\n", - FcResultToString (r)); - result = Qnil; - } - } - - /* clean up and maybe return */ - FcPatternDestroy (fontxft); - if (!UNBOUNDP (result)) - return result; - } - - DEBUG_XFT1 (0, "shit happens, try X11 charset match for %s\n", - XSTRING_DATA(font)); -#undef DECLARE_DEBUG_FONTNAME -#endif /* USE_XFT */ - - LISP_STRING_TO_EXTERNAL (font, patternext, Qx_font_name_encoding); - names = XListFonts (DEVICE_X_DISPLAY (XDEVICE (device)), - patternext, MAX_FONT_COUNT, &count); - /* #### This code seems awfully bogus -- mrb */ - /* #### fontconfig does it better -- sjt */ - for (i = 0; i < count; i ++) - { - const Ibyte *intname; - Bytecount intlen; - - TO_INTERNAL_FORMAT (C_STRING, names[i], - ALLOCA, (intname, intlen), - Qx_font_name_encoding); - if (x_font_spec_matches_charset (XDEVICE (device), charset, - intname, Qnil, 0, -1, 0)) - { - result = build_ext_string ((const Extbyte *) intname, - Qx_font_name_encoding); - break; - } - } - - if (names) - XFreeFontNames (names); - - /* Check for a short font name. */ - if (NILP (result) - && x_font_spec_matches_charset (XDEVICE (device), charset, 0, - font, 0, -1, 0)) - return font; - - return result; -} - -#endif /* MULE */ +/* Include the charset support, shared, for the moment, with GTK. */ +#define THIS_IS_X +#include "objects-xlike-inc.c" /************************************************************************/ @@ -1512,6 +934,13 @@ void vars_of_objects_x (void) { +#ifdef DEBUG_XEMACS + DEFVAR_INT ("debug-x-objects", &debug_x_objects /* +If non-zero, display debug information about X objects +*/ ); + debug_x_objects = 0; +#endif + DEFVAR_BOOL ("x-handle-non-fully-specified-fonts", &x_handle_non_fully_specified_fonts /* If this is true then fonts which do not have all characters specified
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/objects-xlike-inc.c Sun Nov 05 22:31:46 2006 +0000 @@ -0,0 +1,776 @@ +/* Shared object code between X and GTK -- include file. + Copyright (C) 1991-5, 1997 Free Software Foundation, Inc. + Copyright (C) 1995 Sun Microsystems, Inc. + Copyright (C) 1996, 2001, 2002, 2003 Ben Wing. + +This file is part of XEmacs. + +XEmacs is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +XEmacs is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with XEmacs; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Synched up with: Not in FSF. */ + +/* Pango is ready for prime-time now, as far as I understand it. The GTK + people should be using that. Oh well. (Aidan Kehoe, Sat Nov 4 12:41:12 + CET 2006) */ + +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901) + +#ifdef DEBUG_XEMACS +# define DEBUG_OBJECTS(FORMAT, ...) \ + do { if (debug_x_objects) stderr_out(FORMAT, __VA_ARGS__); } while (0) +#else /* DEBUG_XEMACS */ +# define DEBUG_OBJECTS(format, ...) +#endif /* DEBUG_XEMACS */ + +#elif defined(__GNUC__) + +#ifdef DEBUG_XEMACS +# define DEBUG_OBJECTS(format, args...) \ + do { if (debug_x_objects) stderr_out(format, args ); } while (0) +#else /* DEBUG_XEMACS */ +# define DEBUG_OBJECTS(format, args...) +#endif /* DEBUG_XEMACS */ + +#else /* defined(__STDC_VERSION__) [...] */ +# define DEBUG_OBJECTS (void) +#endif + +#ifdef MULE + +/* For some code it's reasonable to have only one copy and conditionalize + at run-time. For other code it isn't. */ + +static int +count_hyphens(const Ibyte *str, Bytecount length, Ibyte **last_hyphen) +{ + int hyphen_count = 0; + const Ibyte *hyphening = str; + const Ibyte *new_hyphening; + + for (hyphen_count = 0; + NULL != (new_hyphening = memchr((const void *)hyphening, '-', length)); + hyphen_count++) + { + ++new_hyphening; + length -= new_hyphening - hyphening; + hyphening = new_hyphening; + } + + if (NULL != last_hyphen) + { + *last_hyphen = (Ibyte *)hyphening; + } + + return hyphen_count; +} + +static int +#ifdef THIS_IS_GTK +gtk_font_spec_matches_charset (struct device * USED_IF_XFT (d), + Lisp_Object charset, + const Ibyte *nonreloc, Lisp_Object reloc, + Bytecount offset, Bytecount length, + enum font_specifier_matchspec_stages stage) +#else +x_font_spec_matches_charset (struct device * USED_IF_XFT (d), + Lisp_Object charset, + const Ibyte *nonreloc, Lisp_Object reloc, + Bytecount offset, Bytecount length, + enum font_specifier_matchspec_stages stage) +#endif +{ + Lisp_Object registries = Qnil; + long i, registries_len; + const Ibyte *the_nonreloc; + Bytecount the_length; + + the_nonreloc = nonreloc; + the_length = length; + + if (!the_nonreloc) + the_nonreloc = XSTRING_DATA (reloc); + fixup_internal_substring (nonreloc, reloc, offset, &the_length); + the_nonreloc += offset; + +#ifdef USE_XFT + if (stage) + { + Display *dpy = DEVICE_X_DISPLAY (d); + Extbyte *extname; + XftFont *rf; + const Ibyte *the_nonreloc; + + if (!NILP(reloc)) + { + the_nonreloc = XSTRING_DATA (reloc); + LISP_STRING_TO_EXTERNAL (reloc, extname, Qx_font_name_encoding); + rf = xft_open_font_by_name (dpy, extname); + return 0; /* #### maybe this will compile and run ;) */ + /* Jesus, Stephen, what the fuck? */ + } + } +#endif + + /* Hmm, this smells bad. */ + if (UNBOUNDP (charset)) + return 1; + + /* Hack! Short font names don't have the registry in them, + so we just assume the user knows what they're doing in the + case of ASCII. For other charsets, you gotta give the + long form; sorry buster. + #### FMH: this screws fontconfig/Xft? + STRATEGY: use fontconfig's ability to hack languages and character + sets (lang and charset properties). + #### Maybe we can use the fontconfig model to eliminate the difference + between faces and fonts? No - it looks like that would be an abuse + (fontconfig doesn't know about colors, although Xft does). + */ + if (EQ (charset, Vcharset_ascii) && + (!memchr (the_nonreloc, '*', the_length)) + && (5 > (count_hyphens(the_nonreloc, the_length, NULL)))) + { + return 1; + } + + if (final == stage) + { + registries = Qunicode_registries; + } + else if (initial == stage) + { + registries = XCHARSET_REGISTRIES (charset); + if (NILP(registries)) + { + return 0; + } + } + else assert(0); + + CHECK_VECTOR (registries); + registries_len = XVECTOR_LENGTH(registries); + + for (i = 0; i < registries_len; ++i) + { + if (!(STRINGP(XVECTOR_DATA(registries)[i])) + || (XSTRING_LENGTH(XVECTOR_DATA(registries)[i]) > the_length)) + { + continue; + } + + /* Check if the font spec ends in the registry specified. X11 says + this comparison is case insensitive: XLFD, section 3.11: + + "Alphabetic case distinctions are allowed but are for human + readability concerns only. Conforming X servers will perform + matching on font name query or open requests independent of case." */ + if (0 == qxestrcasecmp(XSTRING_DATA(XVECTOR_DATA(registries)[i]), + the_nonreloc + (the_length - + XSTRING_LENGTH + (XVECTOR_DATA(registries)[i])))) + { + return 1; + } + } + return 0; +} + +static Lisp_Object +xlistfonts_checking_charset (Lisp_Object device, const Extbyte *xlfd, + Lisp_Object charset, + enum font_specifier_matchspec_stages stage) +{ + Extbyte **names; + Lisp_Object result = Qnil; + int count = 0, i; + DECLARE_EISTRING(ei_single_result); + + names = XListFonts ( +#ifdef THIS_IS_GTK + GDK_DISPLAY (), +#else + DEVICE_X_DISPLAY (XDEVICE (device)), +#endif + xlfd, MAX_FONT_COUNT, &count); + + for (i = 0; i < count; ++i) + { + eireset(ei_single_result); + eicpy_ext(ei_single_result, names[i], Qx_font_name_encoding); + + if (DEVMETH_OR_GIVEN(XDEVICE (device), font_spec_matches_charset, + (XDEVICE (device), charset, + eidata(ei_single_result), Qnil, 0, + -1, stage), 0)) + { + result = eimake_string(ei_single_result); + DEBUG_OBJECTS ("in xlistfonts_checking_charset, returning %s\n", + eidata(ei_single_result)); + break; + } + } + + if (names) + { + XFreeFontNames (names); + } + + return result; +} + +#ifdef USE_XFT +/* #### debug functions: find a better place for us */ +const char *FcResultToString (FcResult r); +const char * +FcResultToString (FcResult r) +{ + static char buffer[256]; + switch (r) + { + case FcResultMatch: + return "FcResultMatch"; + case FcResultNoMatch: + return "FcResultNoMatch"; + case FcResultTypeMismatch: + return "FcResultTypeMismatch"; + case FcResultNoId: + return "FcResultNoId"; + default: + snprintf (buffer, 255, "FcResultUndocumentedValue (%d)", r); + return buffer; + } +} + +const char *FcTypeOfValueToString (FcValue v); +const char * +FcTypeOfValueToString (FcValue v) +{ + static char buffer[256]; + switch (v.type) + { + case FcTypeMatrix: + return "FcTypeMatrix"; + case FcTypeString: + return "FcTypeString"; + case FcTypeVoid: + return "FcTypeVoid"; + case FcTypeDouble: + return "FcTypeDouble"; + case FcTypeInteger: + return "FcTypeInteger"; + case FcTypeBool: + return "FcTypeBool"; + case FcTypeCharSet: + return "FcTypeCharSet"; + case FcTypeLangSet: + return "FcTypeLangSet"; + /* #### There is no union member of this type, but there are void* and + FcPattern* members, as of fontconfig.h FC_VERSION 10002 */ + case FcTypeFTFace: + return "FcTypeFTFace"; + default: + snprintf (buffer, 255, "FcTypeUndocumentedType (%d)", v.type); + return buffer; + } +} + +static FcCharSet * +mule_to_fc_charset (Lisp_Object cs) +{ + int ucode, i, j; + FcCharSet *fccs; + + CHECK_CHARSET (cs); + fccs = FcCharSetCreate (); + /* #### do we also need to deal with 94 vs. 96 charsets? + ie, how are SP and DEL treated in ASCII? non-graphic should return -1 */ + if (1 == XCHARSET_DIMENSION (cs)) + /* Unicode tables are indexed by offsets from ASCII SP, not by ASCII */ + for (i = 0; i < 96; i++) + { + ucode = ((int *) XCHARSET_TO_UNICODE_TABLE (cs))[i]; + if (ucode >= 0) + /* #### should check for allocation failure */ + FcCharSetAddChar (fccs, (FcChar32) ucode); + } + else if (2 == XCHARSET_DIMENSION (cs)) + /* Unicode tables are indexed by offsets from ASCII SP, not by ASCII */ + for (i = 0; i < 96; i++) + for (j = 0; j < 96; j++) + { + ucode = ((int **) XCHARSET_TO_UNICODE_TABLE (cs))[i][j]; + if (ucode >= 0) + /* #### should check for allocation failure */ + FcCharSetAddChar (fccs, (FcChar32) ucode); + } + else + { + FcCharSetDestroy (fccs); + fccs = NULL; + } + return fccs; +} + +struct charset_reporter { + Lisp_Object *charset; + /* This is a debug facility, require ASCII. */ + Extbyte *language; /* ASCII, please */ + /* Technically this is FcChar8, but fsckin' GCC 4 bitches. */ + Extbyte *rfc3066; /* ASCII, please */ +}; + +static struct charset_reporter charset_table[] = + { + /* #### It's my branch, my favorite charsets get checked first! + That's a joke, Son. + Ie, I don't know what I'm doing, so my charsets first is as good as + any other arbitrary order. If you have a better idea, speak up! */ + { &Vcharset_ascii, "English", "en" }, + { &Vcharset_japanese_jisx0208, "Japanese", "ja" }, + { &Vcharset_japanese_jisx0212, "Japanese", "ja" }, + { &Vcharset_katakana_jisx0201, "Japanese", "ja" }, + { &Vcharset_latin_jisx0201, "Japanese", "ja" }, + { &Vcharset_japanese_jisx0208_1978, "Japanese", "ja" }, + { &Vcharset_greek_iso8859_7, "Greek", "el" }, + /* #### all the Chinese need checking + Damn the blood-sucking ISO anyway. */ + { &Vcharset_chinese_gb2312, "simplified Chinese", "zh-CN" }, + { &Vcharset_korean_ksc5601, "Korean", "ko" }, + { &Vcharset_chinese_cns11643_1, "traditional Chinese", "zh-TW" }, + { &Vcharset_chinese_cns11643_2, "traditional Chinese", "zh-TW" }, + { &Vcharset_latin_iso8859_1, NULL, NULL }, + { &Vcharset_latin_iso8859_2, NULL, NULL }, + { &Vcharset_latin_iso8859_3, NULL, NULL }, + { &Vcharset_latin_iso8859_4, NULL, NULL }, + { &Vcharset_latin_iso8859_9, NULL, NULL }, + { &Vcharset_latin_iso8859_15, NULL, NULL }, + { &Vcharset_thai_tis620, NULL, NULL }, + { &Vcharset_arabic_iso8859_6, NULL, NULL }, + { &Vcharset_hebrew_iso8859_8, "Hebrew", "he" }, + { &Vcharset_cyrillic_iso8859_5, NULL, NULL }, + /* #### these probably are not quite right */ + { &Vcharset_chinese_big5_1, "traditional Chinese", "zh-TW" }, + { &Vcharset_chinese_big5_2, "traditional Chinese", "zh-TW" }, + { NULL, NULL, NULL } + }; + +/* Choose appropriate font name for debug messages. + Use only in the top half of next function (enforced with #undef). */ +#define DECLARE_DEBUG_FONTNAME(__xemacs_name) \ + Eistring *__xemacs_name; \ + do \ + { \ + __xemacs_name = debug_xft > 2 ? eistr_fullname \ + : debug_xft > 1 ? eistr_longname \ + : eistr_shortname; \ + } while (0) + +static Lisp_Object +xft_find_charset_font (Lisp_Object font, Lisp_Object charset, + enum font_specifier_matchspec_stages stage) +{ + const Extbyte *patternext; + Lisp_Object result = Qnil; + + /* #### with Xft need to handle second stage here -- sjt + Hm. Or maybe not. That would be cool. :-) */ + if (stage) + return Qnil; + + /* Fontconfig converts all FreeType names to UTF-8 before passing them + back to callers---see fcfreetype.c (FcFreeTypeQuery). + I don't believe this is documented. */ + + DEBUG_XFT1 (1, "confirming charset for font instance %s\n", + XSTRING_DATA(font)); + + /* #### this looks like a fair amount of work, but the basic design + has never been rethought, and it should be + + what really should happen here is that we use FcFontSort (FcFontList?) + to get a list of matching fonts, then pick the first (best) one that + gives language or repertoire coverage. + */ + + FcInit (); /* No-op if already initialized. + In fontconfig 2.3.2, this cannot return + failure, but that looks like a bug. We + check for it with FcGetCurrentConfig(), + which *can* fail. */ + if (!FcConfigGetCurrent()) /* #### We should expose FcInit* interfaces + to LISP and decide when to reinitialize + intelligently. */ + stderr_out ("Failed fontconfig initialization\n"); + else + { + FcPattern *fontxft; /* long-lived, freed at end of this block */ + FcResult fcresult; + FcConfig *fcc; + FcChar8 *lang = (FcChar8 *) "en"; /* #### fix this bogus hack! */ + FcCharSet *fccs = NULL; + DECLARE_EISTRING (eistr_shortname); /* user-friendly nickname */ + DECLARE_EISTRING (eistr_longname); /* omit FC_LANG and FC_CHARSET */ + DECLARE_EISTRING (eistr_fullname); /* everything */ + + LISP_STRING_TO_EXTERNAL (font, patternext, Qfc_font_name_encoding); + fcc = FcConfigGetCurrent (); + + /* parse the name, do the substitutions, and match the font */ + + { + FcPattern *p = FcNameParse ((FcChar8 *) patternext); + PRINT_XFT_PATTERN (3, "FcNameParse'ed name is %s\n", p); + /* #### Next two return FcBool, but what does the return mean? */ + /* The order is correct according the fontconfig docs. */ + FcConfigSubstitute (fcc, p, FcMatchPattern); + PRINT_XFT_PATTERN (2, "FcConfigSubstitute'ed name is %s\n", p); + FcDefaultSubstitute (p); + PRINT_XFT_PATTERN (3, "FcDefaultSubstitute'ed name is %s\n", p); + /* #### check fcresult of following match? */ + fontxft = FcFontMatch (fcc, p, &fcresult); + /* this prints the long fontconfig name */ + PRINT_XFT_PATTERN (1, "FcFontMatch'ed name is %s\n", fontxft); + FcPatternDestroy (p); + } + + /* heuristic to give reasonable-length names for debug reports + + I considered #ifdef SUPPORT_FULL_FONTCONFIG_NAME etc but that's + pointless. We're just going to remove this code once the font/ + face refactoring is done, but until then it could be very useful. + */ + { + FcPattern *p = FcFontRenderPrepare (fcc, fontxft, fontxft); + FcChar8 *name; + + /* full name, including language coverage and repertoire */ + name = FcNameUnparse (p); + eicpy_ext (eistr_fullname, (Extbyte *) name, Qfc_font_name_encoding); + free (name); + + /* long name, omitting coverage and repertoire, plus a number + of rarely useful properties */ + FcPatternDel (p, FC_CHARSET); + FcPatternDel (p, FC_LANG); + FcPatternDel (p, FC_WIDTH); + FcPatternDel (p, FC_SPACING); + FcPatternDel (p, FC_HINTING); + FcPatternDel (p, FC_VERTICAL_LAYOUT); + FcPatternDel (p, FC_AUTOHINT); + FcPatternDel (p, FC_GLOBAL_ADVANCE); + FcPatternDel (p, FC_INDEX); + FcPatternDel (p, FC_SCALE); + FcPatternDel (p, FC_FONTVERSION); + name = FcNameUnparse (p); + eicpy_ext (eistr_longname, (Extbyte *) name, Qfc_font_name_encoding); + free (name); + + /* nickname, just family and size, but + "family" names usually have style, slant, and weight */ + FcPatternDel (p, FC_FOUNDRY); + FcPatternDel (p, FC_STYLE); + FcPatternDel (p, FC_SLANT); + FcPatternDel (p, FC_WEIGHT); + FcPatternDel (p, FC_PIXEL_SIZE); + FcPatternDel (p, FC_OUTLINE); + FcPatternDel (p, FC_SCALABLE); + FcPatternDel (p, FC_DPI); + name = FcNameUnparse (p); + eicpy_ext (eistr_shortname, (Extbyte *) name, Qfc_font_name_encoding); + free (name); + + FcPatternDestroy (p); + } + + /* The language approach may better in the long run, but we can't use + it based on Mule charsets; fontconfig doesn't provide a way to test + for unions of languages, etc. That will require support from the + text module. + + Optimization: cache the generated FcCharSet in the Mule charset. + Don't forget to destroy it if the Mule charset gets deallocated. */ + + { + /* This block possibly should be a function, but it generates + multiple values. I find the "pass an address to return the + value in" idiom opaque, so prefer a block. */ + struct charset_reporter *cr; + for (cr = charset_table; + cr->charset && !EQ (*(cr->charset), charset); + cr++) + ; + + if (cr->rfc3066) + { + DECLARE_DEBUG_FONTNAME (name); + CHECKING_LANG (0, eidata(name), cr->language); + lang = (FcChar8 *) cr->rfc3066; + } + else if (cr->charset) + { + /* what the hey, build 'em on the fly */ + /* #### in the case of error this could return NULL! */ + fccs = mule_to_fc_charset (charset); + lang = (FcChar8 *) XSTRING_DATA (XSYMBOL + (XCHARSET_NAME (charset))-> name); + } + else + { + /* OK, we fell off the end of the table */ + warn_when_safe_lispobj (intern ("xft"), intern ("alert"), + list2 (build_string ("unchecked charset"), + charset)); + /* default to "en" + #### THIS IS WRONG, WRONG, WRONG!! + It is why we never fall through to XLFD-checking. */ + } + + ASSERT_ASCTEXT_ASCII((Extbyte *) lang); + + if (fccs) + { + /* check for character set coverage */ + int i = 0; + FcCharSet *v; + FcResult r = FcPatternGetCharSet (fontxft, FC_CHARSET, i, &v); + + if (r == FcResultTypeMismatch) + { + DEBUG_XFT0 (0, "Unexpected type return in charset value\n"); + result = Qnil; + } + else if (r == FcResultMatch && FcCharSetIsSubset (fccs, v)) + { + /* The full pattern with the bitmap coverage is massively + unwieldy, but the shorter names are just *wrong*. We + should have the full thing internally as truename, and + filter stuff the client doesn't want to see on output. + Should we just store it into the truename right here? */ + DECLARE_DEBUG_FONTNAME (name); + DEBUG_XFT2 (0, "Xft font %s supports %s\n", + eidata(name), lang); +#ifdef RETURN_LONG_FONTCONFIG_NAMES + result = eimake_string(eistr_fullname); +#else + result = eimake_string(eistr_longname); +#endif + } + else + { + DECLARE_DEBUG_FONTNAME (name); + DEBUG_XFT2 (0, "Xft font %s doesn't support %s\n", + eidata(name), lang); + result = Qnil; + } + + /* clean up */ + FcCharSetDestroy (fccs); + } + else + { + /* check for language coverage */ + int i = 0; + FcValue v; + /* the main event */ + FcResult r = FcPatternGet (fontxft, FC_LANG, i, &v); + + if (r == FcResultMatch) + { + if (v.type != FcTypeLangSet) /* excessive paranoia */ + { + ASSERT_ASCTEXT_ASCII(FcTypeOfValueToString(v)); + /* Urk! Fall back and punt to core font. */ + DEBUG_XFT1 (0, "Unexpected type of lang value (%s)\n", + FcTypeOfValueToString (v)); + result = Qnil; + } + else if (FcLangSetHasLang (v.u.l, lang) != FcLangDifferentLang) + { + DECLARE_DEBUG_FONTNAME (name); + DEBUG_XFT2 (0, "Xft font %s supports %s\n", + eidata(name), lang); +#ifdef RETURN_LONG_FONTCONFIG_NAMES + result = eimake_string(eistr_fullname); +#else + result = eimake_string(eistr_longname); +#endif + } + else + { + DECLARE_DEBUG_FONTNAME (name); + DEBUG_XFT2 (0, "Xft font %s doesn't support %s\n", + eidata(name), lang); + result = Qnil; + } + } + else + { + ASSERT_ASCTEXT_ASCII(FcResultToString(r)); + DEBUG_XFT1 (0, "Getting lang: unexpected result=%s\n", + FcResultToString (r)); + result = Qnil; + } + } + + /* clean up and maybe return */ + FcPatternDestroy (fontxft); + if (!UNBOUNDP (result)) + return result; + } + } + return Qnil; +} +#undef DECLARE_DEBUG_FONTNAME + +#endif /* USE_XFT */ + +/* find a font spec that matches font spec FONT and also matches + (the registry of) CHARSET. */ +static Lisp_Object +#ifdef THIS_IS_GTK +gtk_find_charset_font (Lisp_Object device, Lisp_Object font, + Lisp_Object charset, + enum font_specifier_matchspec_stages stage) +#else +x_find_charset_font (Lisp_Object device, Lisp_Object font, Lisp_Object charset, + enum font_specifier_matchspec_stages stage) +#endif +{ + Lisp_Object result = Qnil, registries = Qnil; + int j, hyphen_count, registries_len = 0; + Ibyte *hyphening, *new_hyphening; + Bytecount xlfd_length; + + DECLARE_EISTRING(ei_xlfd_without_registry); + DECLARE_EISTRING(ei_xlfd); + +#ifdef USE_XFT + result = xft_find_charset_font(font, charset, stage); + if (!NILP(result)) + { + return result; + } +#endif + + switch (stage) + { + case initial: + { + if (!(NILP(XCHARSET_REGISTRIES(charset))) + && VECTORP(XCHARSET_REGISTRIES(charset))) + { + registries_len = XVECTOR_LENGTH(XCHARSET_REGISTRIES(charset)); + registries = XCHARSET_REGISTRIES(charset); + } + break; + } + case final: + { + registries_len = 1; + registries = Qunicode_registries; + break; + } + default: + { + assert(0); + break; + } + } + + eicpy_lstr(ei_xlfd, font); + hyphening = eidata(ei_xlfd); + xlfd_length = eilen(ei_xlfd); + + /* Count the hyphens in the string, moving new_hyphening to just after the + last one. */ + hyphen_count = count_hyphens(hyphening, xlfd_length, &new_hyphening); + + if (0 == registries_len || (5 > hyphen_count && + !(1 == xlfd_length && '*' == *hyphening))) + { + /* No proper XLFD specified, or we can't modify the pattern to change + the registry and encoding to match what we want, or we have no + information on the registry needed. */ + eito_external(ei_xlfd, Qx_font_name_encoding); + DEBUG_OBJECTS ("about to xlistfonts_checking_charset, XLFD %s\n", + eidata(ei_xlfd)); + result = xlistfonts_checking_charset (device, eiextdata(ei_xlfd), + charset, stage); + /* No need to loop through the available registries; return + immediately. */ + return result; + } + else if (1 == xlfd_length && '*' == *hyphening) + { + /* It's a single asterisk. We can add the registry directly to the + end. */ + eicpy_ch(ei_xlfd_without_registry, '*'); + } + else + { + /* It's a fully-specified XLFD. Work out where the registry and + encoding are, and initialise ei_xlfd_without_registry to the string + without them. */ + + /* count_hyphens has set new_hyphening to just after the last + hyphen. Move back to just after the hyphen before it. */ + + for (new_hyphening -= 2; new_hyphening > hyphening + && '-' != *new_hyphening; --new_hyphening) + ; + ++new_hyphening; + + eicpy_ei(ei_xlfd_without_registry, ei_xlfd); + + /* Manipulate ei_xlfd_without_registry, using the information about + ei_xlfd, to which it's identical. */ + eidel(ei_xlfd_without_registry, new_hyphening - hyphening, -1, + eilen(ei_xlfd) - (new_hyphening - hyphening), -1); + + } + + /* Now, loop through the registries and encodings defined for this + charset, doing an XListFonts each time with the pattern modified to + specify the regisry and encoding. This avoids huge amounts of IPC and + duplicated searching; now we use the searching the X server was doing + anyway, where before the X server did its search, transferred huge + amounts of data, and then we proceeded to do a regexp search on that + data. */ + for (j = 0; j < registries_len && NILP(result); ++j) + { + eireset(ei_xlfd); + eicpy_ei(ei_xlfd, ei_xlfd_without_registry); + + eicat_lstr(ei_xlfd, XVECTOR_DATA(registries)[j]); + + eito_external(ei_xlfd, Qx_font_name_encoding); + + DEBUG_OBJECTS ("about to xlistfonts_checking_charset, XLFD %s\n", + eidata(ei_xlfd)); + result = xlistfonts_checking_charset (device, eiextdata(ei_xlfd), + charset, stage); + } + + /* This function used to return the font spec, in the case where a font + didn't exist on the X server but it did match the charset. We're not + doing that any more, because none of the other platform code does, and + the old behaviour was badly-judged in other respects, so I don't trust + the original author to have had a good reason for it. */ + + return result; +} + +#endif /* MULE */
--- a/src/objects.c Sat Nov 04 22:51:03 2006 +0000 +++ b/src/objects.c Sun Nov 05 22:31:46 2006 +0000 @@ -323,8 +323,11 @@ write_fmt_string_lisp (printcharfun, "#<font-instance %S", 1, f->name); write_fmt_string_lisp (printcharfun, " on %s", 1, f->device); if (!NILP (f->device)) - MAYBE_DEVMETH (XDEVICE (f->device), print_font_instance, - (f, printcharfun, escapeflag)); + { + MAYBE_DEVMETH (XDEVICE (f->device), print_font_instance, + (f, printcharfun, escapeflag)); + + } write_fmt_string (printcharfun, " 0x%x>", f->header.uid); } @@ -776,7 +779,7 @@ font_spec_matches_charset (struct device *d, Lisp_Object charset, const Ibyte *nonreloc, Lisp_Object reloc, Bytecount offset, Bytecount length, - int stage) + enum font_specifier_matchspec_stages stage) { return DEVMETH_OR_GIVEN (d, font_spec_matches_charset, (d, charset, nonreloc, reloc, offset, length, @@ -789,6 +792,21 @@ { CHECK_CONS (matchspec); Fget_charset (XCAR (matchspec)); + + do + { + if (EQ(XCDR(matchspec), Qinitial)) + { + break; + } + if (EQ(XCDR(matchspec), Qfinal)) + { + break; + } + + invalid_argument("Invalid font matchspec stage", + XCDR(matchspec)); + } while (0); } void @@ -836,12 +854,23 @@ Lisp_Object instance; Lisp_Object charset = Qnil; #ifdef MULE - int stage = 0; + enum font_specifier_matchspec_stages stage = initial; if (!UNBOUNDP (matchspec)) { charset = Fget_charset (XCAR (matchspec)); - stage = NILP (XCDR (matchspec)) ? 0 : 1; + +#define FROB(new_stage) if (EQ(Q##new_stage, XCDR(matchspec))) \ + { \ + stage = new_stage; \ + } + + FROB(initial) + else FROB(final) + else assert(0); + +#undef FROB + } #endif @@ -864,6 +893,7 @@ if (STRINGP (instantiator)) { #ifdef MULE + /* #### rename these caches. */ Lisp_Object cache = stage ? d->charset_font_cache_stage_2 : d->charset_font_cache_stage_1; #else @@ -921,10 +951,22 @@ } else if (VECTORP (instantiator)) { + Lisp_Object match_inst = Qunbound; assert (XVECTOR_LENGTH (instantiator) == 1); - return (face_property_matching_instance - (Fget_face (XVECTOR_DATA (instantiator)[0]), Qfont, - charset, domain, ERROR_ME, 0, depth)); + + match_inst = face_property_matching_instance + (Fget_face (XVECTOR_DATA (instantiator)[0]), Qfont, + charset, domain, ERROR_ME, 0, depth, initial); + + if (UNBOUNDP(match_inst)) + { + match_inst = face_property_matching_instance + (Fget_face (XVECTOR_DATA (instantiator)[0]), Qfont, + charset, domain, ERROR_ME, 0, depth, final); + } + + return match_inst; + } else if (NILP (instantiator)) return Qunbound;
--- a/src/objects.h Sat Nov 04 22:51:03 2006 +0000 +++ b/src/objects.h Sun Nov 05 22:31:46 2006 +0000 @@ -76,4 +76,8 @@ void set_face_boolean_attached_to (Lisp_Object obj, Lisp_Object face, Lisp_Object property); +/* Defined in search.c, used in mule-charset.c; slightly ugly to declare it + here, but oh well. */ +EXFUN (Fregexp_quote, 1); + #endif /* INCLUDED_objects_h_ */
--- a/src/redisplay-x.c Sat Nov 04 22:51:03 2006 +0000 +++ b/src/redisplay-x.c Sun Nov 05 22:31:46 2006 +0000 @@ -41,9 +41,8 @@ #include "sysdep.h" #include "window.h" -#ifdef MULE #include "mule-ccl.h" -#endif +#include "charset.h" #include "console-x-impl.h" #include "glyphs-x.h" @@ -154,138 +153,148 @@ static int separate_textual_runs (unsigned char *text_storage, struct textual_run *run_storage, - const Ichar *str, Charcount len) + const Ichar *str, Charcount len, + struct face_cachel *cachel) { Lisp_Object prev_charset = Qunbound; /* not Qnil because that is a possible valid charset when MULE is not defined */ - int runs_so_far = 0; - int i; -#ifdef MULE + int runs_so_far = 0, i; + Ibyte charset_leading_byte = LEADING_BYTE_ASCII; + int dimension = 1, graphic = 0, need_ccl_conversion = 0; + Lisp_Object ccl_prog; struct ccl_program char_converter; - int need_ccl_conversion = 0; -#endif + +#ifdef USE_XFT +#define translate_to_ucs_2 1 /* Translate to UTF-16 unconditionally. */ +#define MAYBE_ASSIGN_TRANSLATE_TO_UCS_2(arg) (void)(arg) /* Empty, + may avoid some + warnings. */ +#else /* USE_XFT */ +#ifndef MULE +#define translate_to_ucs_2 0 /* We don't support falling back to + iso10646-1 without MULE */ +#define MAYBE_ASSIGN_TRANSLATE_TO_UCS_2(arg) (void)(arg) +#else /* if MULE */ + int translate_to_ucs_2 = 0; +#define MAYBE_ASSIGN_TRANSLATE_TO_UCS_2(arg) translate_to_ucs_2 = (arg) +#endif /* MULE */ +#endif /* !USE_XFT */ for (i = 0; i < len; i++) { Ichar ch = str[i]; Lisp_Object charset; - int byte1, byte2; /* #### why aren't these UExtbytes? */ - int dimension; - int graphic; - + int byte1, byte2; /* Not UExbytes because BREAKUP_ICHAR takes + the addresses of its arguments and + dereferences those addresses as integer + pointers. */ BREAKUP_ICHAR (ch, charset, byte1, byte2); - dimension = XCHARSET_DIMENSION (charset); - graphic = XCHARSET_GRAPHIC (charset); if (!EQ (charset, prev_charset)) { run_storage[runs_so_far].ptr = text_storage; run_storage[runs_so_far].charset = charset; -#ifdef USE_XFT - run_storage[runs_so_far].dimension = 2; -#else - run_storage[runs_so_far].dimension = dimension; -#endif if (runs_so_far) { run_storage[runs_so_far - 1].len = text_storage - run_storage[runs_so_far - 1].ptr; - if (run_storage[runs_so_far - 1].dimension == 2) - run_storage[runs_so_far - 1].len >>= 1; + /* Checks the value for dimension from the previous run. */ + if (2 == dimension) run_storage[runs_so_far - 1].len >>= 1; } - runs_so_far++; - prev_charset = charset; + + charset_leading_byte = XCHARSET_LEADING_BYTE(charset); + + MAYBE_ASSIGN_TRANSLATE_TO_UCS_2 + (bit_vector_bit(FACE_CACHEL_FONT_FINAL_STAGE + (cachel), + charset_leading_byte - MIN_LEADING_BYTE)); + + if (translate_to_ucs_2) + { + dimension = 2; + run_storage[runs_so_far].dimension = 2; + } + else + { + dimension = XCHARSET_DIMENSION (charset); + run_storage[runs_so_far].dimension = dimension; #ifdef MULE - { - Lisp_Object ccl_prog = XCHARSET_CCL_PROGRAM (charset); - if ((!NILP (ccl_prog)) + ccl_prog = XCHARSET_CCL_PROGRAM (charset); + if ((!NILP (ccl_prog)) && (setup_ccl_program (&char_converter, ccl_prog) >= 0)) - need_ccl_conversion = 1; - } -#endif - } + { + need_ccl_conversion = 1; + } + else + { + /* The graphic property is only relevant if we're neither + doing the CCL conversion nor doing the UTF-16 + conversion; it's irrelevant otherwise. */ + graphic = XCHARSET_GRAPHIC (charset); + need_ccl_conversion = 0; + } +#endif /* MULE */ + } + prev_charset = charset; -#ifndef USE_XFT - if (graphic == 0) + runs_so_far++; + } + + if (translate_to_ucs_2) { - byte1 &= 0x7F; - byte2 &= 0x7F; - } - else if (graphic == 1) - { - byte1 |= 0x80; - byte2 |= 0x80; + UINT_16_BIT ucs2; + int ucs = ichar_to_unicode(ch); + + /* If UCS is less than zero or greater than 0xFFFF, set ucs2 to + REPLACMENT CHARACTER. */ + ucs2 = (ucs & ~0xFFFF) ? 0xFFFD : ucs; + + /* Ignoring the "graphic" handling. */ +#ifdef USE_XFT + byte1 = ((unsigned char *) (&ucs2))[0]; + byte2 = ((unsigned char *) (&ucs2))[1]; +#else + byte1 = ((unsigned char *) (&ucs2))[1]; + byte2 = ((unsigned char *) (&ucs2))[0]; +#endif /* USE_XFT */ } #ifdef MULE - if (need_ccl_conversion) + else if (need_ccl_conversion) { - char_converter.reg[0] = XCHARSET_ID (charset); + char_converter.reg[0] = charset_leading_byte; char_converter.reg[1] = byte1; char_converter.reg[2] = byte2; ccl_driver (&char_converter, 0, 0, 0, 0, CCL_MODE_ENCODING); byte1 = char_converter.reg[1]; byte2 = char_converter.reg[2]; } + else if (graphic == 0) + { + byte1 &= 0x7F; + byte2 &= 0x7F; + } + else + { + byte1 |= 0x80; + byte2 |= 0x80; + } #endif /* MULE */ - *text_storage++ = (unsigned char) byte1; - /* This dimension stuff is broken if you want to use a two-dimensional - X11 font to display a single-dimensional character set, as is - appropriate for the IPA (use one of the -iso10646-1 fonts) or some - of the other non-standard character sets. */ - if (dimension == 2) - *text_storage++ = (unsigned char) byte2; -#else /* USE_XFT */ - /* #### This is bogus as hell. XftChar16, aka FcChar16, is actually - unsigned short, and therefore is not suitable for indexing matrix - fonts such as the JIS fonts supplied with X11. But if this were - consistent, the XftDraw*8 and XftDraw*16 functions are pretty - incoherent, as then we not should allow anything but ISO 8859/1 - (ie, the first 256 code points of Unicode) in XftDraw*8. So it - looks like this depends on the font, not the charset. */ - { - XftChar16 xftchar16 = 0xFFFD; /* unsigned short */ -#ifndef MULE - int unicode = ch; -#else - int unicode = ichar_to_unicode (ch); - if (unicode < 0) - /* abort(); */ /* #### serious error, tables are corrupt - Unfortunately, not a valid assumption; this can happen with - composite characters. Fake it. */ - unicode = 0xFFFD; /* REPLACEMENT CHARACTER, can't represent */ - else if (need_ccl_conversion) - /* #### maybe we should just ignore this and hope the font wins? */ - unicode = 0xFFFD; /* REPLACEMENT CHARACTER, can't represent */ - else if (unicode > 65535) - unicode = 0xFFFD; /* REPLACEMENT CHARACTER, can't represent */ - else -#endif - xftchar16 = (XftChar16) unicode; - /* #### endianness dependency? No, - apparently xft handles endianness for us; - the "big-endian" code works on Intel and PPC */ -#if 1 - /* big-endian or auto-endian */ - byte1 = ((unsigned char *) (&xftchar16))[0]; - byte2 = ((unsigned char *) (&xftchar16))[1]; -#else - /* little-endian */ - byte1 = ((unsigned char *) (&xftchar16))[1]; - byte2 = ((unsigned char *) (&xftchar16))[0]; -#endif - } - *text_storage++ = (unsigned char) byte1; - *text_storage++ = (unsigned char) byte2; -#endif /* USE_XFT */ + + *text_storage++ = (unsigned char)byte1; + + /* dimension can be two in non-Mule if we're translating to + Unicode. */ + if (2 == dimension) *text_storage++ = (unsigned char)byte2; } if (runs_so_far) { run_storage[runs_so_far - 1].len = text_storage - run_storage[runs_so_far - 1].ptr; - if (run_storage[runs_so_far - 1].dimension == 2) + /* Dimension retains the relevant value for the run before it. */ + if (2 == dimension) run_storage[runs_so_far - 1].len >>= 1; } @@ -361,7 +370,8 @@ int nruns; int i; - nruns = separate_textual_runs (text_storage, runs, str, len); + nruns = separate_textual_runs (text_storage, runs, str, len, + cachel); for (i = 0; i < nruns; i++) width_so_far += x_text_width_single_run (f, cachel, runs + i); @@ -1014,7 +1024,7 @@ } nruns = separate_textual_runs (text_storage, runs, Dynarr_atp (buf, 0), - Dynarr_length (buf)); + Dynarr_length (buf), cachel); for (i = 0; i < nruns; i++) {
--- a/src/redisplay.c Sat Nov 04 22:51:03 2006 +0000 +++ b/src/redisplay.c Sun Nov 05 22:31:46 2006 +0000 @@ -760,7 +760,7 @@ static int space_width (struct window *w) { - /* While tabs are traditional composed of spaces, for variable-width + /* While tabs are traditionally composed of spaces, for variable-width fonts the space character tends to give too narrow a value. So we use 'n' instead. Except that we don't. We use the default character width for the default face. If this is actually
--- a/src/specifier.c Sat Nov 04 22:51:03 2006 +0000 +++ b/src/specifier.c Sun Nov 05 22:31:46 2006 +0000 @@ -47,6 +47,7 @@ Lisp_Object Qconsole_type, Qdevice_class; static Lisp_Object Vuser_defined_tags; +static Lisp_Object Vcharset_tag_lists; typedef struct specifier_type_entry specifier_type_entry; struct specifier_type_entry @@ -428,9 +429,9 @@ }; static const struct memory_description specifier_empty_extra_description_1[] = -{ - { XD_END } -}; + { + { XD_END } + }; const struct sized_memory_description specifier_empty_extra_description = { 0, specifier_empty_extra_description_1 @@ -471,7 +472,7 @@ } maybe_invalid_argument ("Invalid specifier type", - type, Qspecifier, errb); + type, Qspecifier, errb); return 0; } @@ -683,7 +684,7 @@ instantiation will actually occur in the window the image instance itself is instantiated in. */ - (domain)) + (domain)) { /* This cannot GC. */ return ((DEVICEP (domain) && DEVICE_LIVE_P (XDEVICE (domain))) || @@ -694,14 +695,14 @@ ? Qt : Qnil; } -DEFUN ("valid-specifier-locale-type-p", Fvalid_specifier_locale_type_p, 1, 1, 0, - /* +DEFUN ("valid-specifier-locale-type-p", Fvalid_specifier_locale_type_p, 1, + 1, 0, /* Given a specifier LOCALE-TYPE, return non-nil if it is valid. Valid locale types are `global', `device', `frame', `window', and `buffer'. \(Note, however, that in functions that accept either a locale or a locale type, `global' is considered an individual locale.) */ - (locale_type)) + (locale_type)) { /* This cannot GC. */ return (EQ (locale_type, Qglobal) || @@ -731,7 +732,7 @@ /* This cannot GC. */ if (NILP (Fvalid_specifier_locale_p (locale))) invalid_argument ("Invalid specifier locale", - locale); + locale); if (DEVICEP (locale)) return Qdevice; if (FRAMEP (locale)) return Qframe; if (WINDOWP (locale)) return Qwindow; @@ -750,7 +751,7 @@ return locale; else invalid_argument ("Invalid specifier locale", - locale); + locale); return Qnil; } @@ -766,7 +767,7 @@ if (EQ (locale_type, Qbuffer)) return LOCALE_BUFFER; invalid_argument ("Invalid specifier locale type", - locale_type); + locale_type); RETURN_NOT_REACHED (LOCALE_GLOBAL); } @@ -803,7 +804,7 @@ { if (NILP (Fvalid_specifier_domain_p (domain))) invalid_argument ("Invalid specifier domain", - domain); + domain); } Lisp_Object @@ -834,10 +835,10 @@ DEFUN ("valid-specifier-tag-set-p", Fvalid_specifier_tag_set_p, 1, 1, 0, /* Return non-nil if TAG-SET is a valid specifier tag set. -A specifier tag set is an entity that is attached to an instantiator -and can be used to restrict the scope of that instantiator to a -particular device class or device type and/or to mark instantiators -added by a particular package so that they can be later removed. +A specifier tag set is an entity that is attached to an instantiator and can +be used to restrict the scope of that instantiator to a particular device +class, device type, or charset. It can also be used to mark instantiators +added by a particular package so that they can be later removed as a group. A specifier tag set consists of a list of zero of more specifier tags, each of which is a symbol that is recognized by XEmacs as a tag. @@ -846,18 +847,25 @@ \(as opposed to a list) because the order of the tags or the number of times a particular tag occurs does not matter. -Each tag has a predicate associated with it, which specifies whether -that tag applies to a particular device. The tags which are device types -and classes match devices of that type or class. User-defined tags can -have any predicate, or none (meaning that all devices match). When -attempting to instantiate a specifier, a particular instantiator is only -considered if the device of the domain being instantiated over matches -all tags in the tag set attached to that instantiator. +Each tag has two predicates associated with it, which specify, respectively, +whether that tag applies to a particular device and whether it applies to a +particular character set. The predefined tags which are device types and +classes match devices of that type or class. User-defined tags can have any +device predicate, or none (meaning that all devices match). When attempting +to instantiate a specifier, a particular instantiator is only considered if +the device of the domain being instantiated over matches all tags in the tag +set attached to that instantiator. + +If a charset is to be considered--which is only the case for face +instantiators--this consideration may be done twice. The first iteration +pays attention to the character set predicates; if no instantiator can be +found in that case, the search is repeated ignoring the character set +predicates. Most of the time, a tag set is not specified, and the instantiator gets a null tag set, which matches all devices. */ - (tag_set)) + (tag_set)) { Lisp_Object rest; @@ -880,7 +888,7 @@ return list1 (tag_set); if (NILP (Fvalid_specifier_tag_set_p (tag_set))) invalid_argument ("Invalid specifier tag-set", - tag_set); + tag_set); return tag_set; } @@ -973,6 +981,63 @@ return 1; } +static int +charset_matches_specifier_tag_set_p (Lisp_Object charset, + Lisp_Object tag_set, + enum font_specifier_matchspec_stages + stage) +{ + Lisp_Object rest; + int res = 0; + + assert(stage != impossible); + + LIST_LOOP (rest, tag_set) + { + Lisp_Object tag = XCAR (rest); + Lisp_Object assoc; + + /* This function will not ever be called with a charset for which the + relevant information hasn't been calculated (the information is + calculated with the creation of every charset). */ + assert (!NILP(XVECTOR_DATA + (Vcharset_tag_lists)[XCHARSET_LEADING_BYTE(charset) + - MIN_LEADING_BYTE])); + + /* Now, find out what the pre-calculated value is. */ + assoc = assq_no_quit(tag, + XVECTOR_DATA(Vcharset_tag_lists) + [XCHARSET_LEADING_BYTE(charset) + - MIN_LEADING_BYTE]); + + if (!(NILP(assoc)) && !(NILP(XCDR(assoc)))) + { + assert(VECTORP(XCDR(assoc))); + + /* In the event that a tag specifies a charset, then the specifier + must match for (this stage and this charset) for all + charset-specifying tags. */ + if (NILP(XVECTOR_DATA(XCDR(assoc))[stage])) + { + /* It doesn't match for this tag, even though the tag + specifies a charset. Return 0. */ + return 0; + } + + /* This tag specifies charset limitations, and this charset and + stage match those charset limitations. + + In the event that a later tag specifies charset limitations + that don't match, the return 0 above prevents us giving a + positive match. */ + res = 1; + } + } + + return res; +} + + DEFUN ("device-matches-specifier-tag-set-p", Fdevice_matches_specifier_tag_set_p, 2, 2, 0, /* Return non-nil if DEVICE matches specifier tag set TAG-SET. @@ -990,56 +1055,71 @@ return device_matches_specifier_tag_set_p (device, tag_set) ? Qt : Qnil; } -DEFUN ("define-specifier-tag", Fdefine_specifier_tag, 1, 2, 0, /* -Define a new specifier tag. -If PREDICATE is specified, it should be a function of one argument -\(a device) that specifies whether the tag matches that particular -device. If PREDICATE is omitted, the tag matches all devices. - -You can redefine an existing user-defined specifier tag. However, -you cannot redefine the built-in specifier tags (the device types -and classes) or the symbols nil, t, `all', or `global'. -*/ - (tag, predicate)) +Lisp_Object +define_specifier_tag(Lisp_Object tag, Lisp_Object device_predicate, + Lisp_Object charset_predicate) { - Lisp_Object assoc, devcons, concons; - int recompute = 0; - - CHECK_SYMBOL (tag); - if (valid_device_class_p (tag) || - valid_console_type_p (tag)) - invalid_change ("Cannot redefine built-in specifier tags", tag); - /* Try to prevent common instantiators and locales from being - redefined, to reduce ambiguity */ - if (NILP (tag) || EQ (tag, Qt) || EQ (tag, Qall) || EQ (tag, Qglobal)) - invalid_change ("Cannot define nil, t, `all', or `global'", tag); - assoc = assq_no_quit (tag, Vuser_defined_tags); + Lisp_Object assoc = assq_no_quit (tag, Vuser_defined_tags), + concons, devcons, charpres = Qnil; + int recompute_devices = 0, recompute_charsets = 0, i, max_args = -1; + if (NILP (assoc)) { - recompute = 1; - Vuser_defined_tags = Fcons (Fcons (tag, predicate), Vuser_defined_tags); + recompute_devices = recompute_charsets = 1; + Vuser_defined_tags = Fcons (list3 (tag, device_predicate, + charset_predicate), + Vuser_defined_tags); DEVICE_LOOP_NO_BREAK (devcons, concons) { struct device *d = XDEVICE (XCAR (devcons)); /* Initially set the value to t in case of error - in predicate */ + in device_predicate */ DEVICE_USER_DEFINED_TAGS (d) = Fcons (Fcons (tag, Qt), DEVICE_USER_DEFINED_TAGS (d)); } + + if (!NILP (charset_predicate)) + { + max_args = XINT(Ffunction_max_args(charset_predicate)); + if (max_args < 1) + { + invalid_argument + ("Charset predicate must be able to take an argument", tag); + } + } } - else if (!NILP (predicate) && !NILP (XCDR (assoc))) + else if (!NILP (device_predicate) && !NILP (XCADR (assoc))) { - recompute = 1; - XCDR (assoc) = predicate; + recompute_devices = 1; + XCDR (assoc) = list2(device_predicate, charset_predicate); } - - /* recompute the tag values for all devices. However, in the special - case where both the old and new predicates are nil, we know that - we don't have to do this. (It's probably common for people to - call (define-specifier-tag) more than once on the same tag, - and the most common case is where PREDICATE is not specified.) */ - - if (recompute) + else if (!NILP (charset_predicate) || !NILP(XCADDR (assoc))) + { + max_args = XINT(Ffunction_max_args(charset_predicate)); + if (max_args < 1) + { + invalid_argument + ("Charset predicate must be able to take an argument", tag); + } + + /* If there exists a charset_predicate for the tag currently (even if + the new charset_predicate is nil), or if we're adding one, we need + to recompute. This contrasts with the device predicates, where we + don't need to recompute if the old and new device predicates are + both nil. */ + + recompute_charsets = 1; + XCDR (assoc) = list2(device_predicate, charset_predicate); + } + + /* Recompute the tag values for all devices and charsets, if necessary. In + the special case where both the old and new device_predicates are nil, + we know that we don't have to do it for the device. (It's probably + common for people to call (define-specifier-tag) more than once on the + same tag, and the most common case is where DEVICE_PREDICATE is not + specified.) */ + + if (recompute_devices) { DEVICE_LOOP_NO_BREAK (devcons, concons) { @@ -1047,14 +1127,157 @@ assoc = assq_no_quit (tag, DEVICE_USER_DEFINED_TAGS (XDEVICE (device))); assert (CONSP (assoc)); - if (NILP (predicate)) + if (NILP (device_predicate)) XCDR (assoc) = Qt; else - XCDR (assoc) = !NILP (call1 (predicate, device)) ? Qt : Qnil; + XCDR (assoc) = !NILP (call1 (device_predicate, device)) ? Qt + : Qnil; } } - return Qnil; + if (recompute_charsets) + { + if (NILP(charset_predicate)) + { + charpres = Qnil; + } + + for (i = 0; i < NUM_LEADING_BYTES; ++i) + { + if (NILP(charset_by_leading_byte(MIN_LEADING_BYTE + i))) + { + continue; + } + + assoc = assq_no_quit (tag, + XVECTOR_DATA(Vcharset_tag_lists)[i]); + + if (!NILP(charset_predicate)) + { + static int line_1147_calls; + ++line_1147_calls; + charpres = make_vector(impossible, Qnil); + + /* If you want to extend the number of stages available, here + in setup_charset_initial_specifier_tags, and in specifier.h + is where you want to go. */ + +#define DEFINE_SPECIFIER_TAG_FROB(stage) do { \ + if (max_args > 1) \ + { \ + XVECTOR_DATA(charpres)[stage] = \ + call2_trapping_problems \ + ("Error during specifier tag charset predicate," \ + " stage " #stage, charset_predicate, \ + charset_by_leading_byte(MIN_LEADING_BYTE + i), \ + Q##stage, 0); \ + } \ + else \ + { \ + XVECTOR_DATA(charpres)[stage] = \ + call1_trapping_problems \ + ("Error during specifier tag charset predicate," \ + " stage " #stage, charset_predicate, \ + charset_by_leading_byte(MIN_LEADING_BYTE + i), \ + 0); \ + } \ + \ + if (UNBOUNDP(XVECTOR_DATA(charpres)[stage])) \ + { \ + XVECTOR_DATA(charpres)[stage] = Qnil; \ + } \ + else if (!NILP(XVECTOR_DATA(charpres)[stage])) \ + { \ + /* Don't want refs to random other objects. */ \ + XVECTOR_DATA(charpres)[stage] = Qt; \ + } \ + } while (0) + + DEFINE_SPECIFIER_TAG_FROB (initial); + DEFINE_SPECIFIER_TAG_FROB (final); + +#undef DEFINE_SPECIFIER_TAG_FROB + + } + + if (!NILP(assoc)) + { + assert(CONSP(assoc)); + XCDR (assoc) = charpres; + } + else + { + XVECTOR_DATA(Vcharset_tag_lists)[i] + = Fcons(Fcons(tag, charpres), + XVECTOR_DATA (Vcharset_tag_lists)[i]); + } + } + } + return Qt; +} + +DEFUN ("define-specifier-tag", Fdefine_specifier_tag, 1, 3, 0, /* +Define a new specifier tag. + +If DEVICE-PREDICATE is specified, it should be a function of one argument +\(a device) that specifies whether the tag matches that particular device. +If DEVICE-PREDICATE is omitted, the tag matches all devices. + +If CHARSET-PREDICATE is supplied, it should be a function taking a single +Lisp character set argument. A tag's charset predicate is primarily used to +determine what font to use for a given \(set of) charset\(s) when that tag +is used in a set-face-font call; a non-nil return value indicates that the +tag matches the charset. + +The font matching process also has a concept of stages; the defined stages +are currently `initial' and `final', and there exist specifier tags with +those names that correspond to those stages. On X11, 'initial is used when +the font matching process is looking for fonts that match the desired +registries of the charset--see the `charset-registries' function. If that +match process fails, then the 'final tag becomes relevant; this means that a +more general lookup is desired, and that a font doesn't necessarily have to +match the desired XLFD for the face, just the charset repertoire for this +charset. It also means that the charset registry and encoding used will be +`iso10646-1', and the characters will be converted to display using that +registry. + +If a tag set matches no character set; the two-stage match process will +ignore the tag on its first pass, but if no match is found, it will respect +it on the second pass, where character set information is ignored. + +You can redefine an existing user-defined specifier tag. However, you +cannot redefine most of the built-in specifier tags \(the device types and +classes, `initial', and `final') or the symbols nil, t, `all', or `global'. +Note that if a device type is not supported in this XEmacs, it will not be +available as a built-in specifier tag; this is probably something we should +change. +*/ + (tag, device_predicate, charset_predicate)) +{ + int max_args; + + CHECK_SYMBOL (tag); + if (valid_device_class_p (tag) || + valid_console_type_p (tag) || + EQ (tag, Qinitial) || EQ (tag, Qfinal)) + invalid_change ("Cannot redefine built-in specifier tags", tag); + /* Try to prevent common instantiators and locales from being + redefined, to reduce ambiguity */ + if (NILP (tag) || EQ (tag, Qt) || EQ (tag, Qall) || EQ (tag, Qglobal)) + invalid_change ("Cannot define nil, t, `all', or `global'", tag); + + if (!NILP (charset_predicate)) + { + max_args = XINT(Ffunction_max_args(charset_predicate)); + if (max_args != 1) + { + /* We only allow the stage argument to be specifed from C. */ + invalid_change ("Charset predicate must take one argument", + tag); + } + } + + return define_specifier_tag(tag, device_predicate, charset_predicate); } /* Called at device-creation time to initialize the user-defined @@ -1065,6 +1288,8 @@ { Lisp_Object rest, rest2; Lisp_Object device = wrap_device (d); + Lisp_Object device_predicate, charset_predicate; + int list_len; DEVICE_USER_DEFINED_TAGS (d) = Fcopy_alist (Vuser_defined_tags); @@ -1075,21 +1300,89 @@ for (rest = Vuser_defined_tags, rest2 = DEVICE_USER_DEFINED_TAGS (d); !NILP (rest); rest = XCDR (rest), rest2 = XCDR (rest2)) { - Lisp_Object predicate = XCDR (XCAR (rest)); - if (NILP (predicate)) - XCDR (XCAR (rest2)) = Qt; + GET_LIST_LENGTH(XCAR(rest), list_len); + + assert(3 == list_len); + + device_predicate = XCADR(XCAR (rest)); + charset_predicate = XCADDR(XCAR (rest)); + + if (NILP (device_predicate)) + { + XCDR (XCAR (rest2)) = list2(Qt, charset_predicate); + } else - XCDR (XCAR (rest2)) = - !NILP (call_critical_lisp_code (d, predicate, device)) ? Qt : Qnil; + { + device_predicate = !NILP (call_critical_lisp_code + (d, device_predicate, device)) + ? Qt : Qnil; + XCDR (XCAR (rest2)) = list2(device_predicate, charset_predicate); + } } } +void +setup_charset_initial_specifier_tags (Lisp_Object charset) +{ + Lisp_Object rest, charset_predicate, tag, new_value; + Lisp_Object charset_tag_list = Qnil; + + LIST_LOOP (rest, Vuser_defined_tags) + { + tag = XCAR(XCAR(rest)); + charset_predicate = XCADDR(XCAR (rest)); + + if (NILP(charset_predicate)) + { + continue; + } + + new_value = make_vector(impossible, Qnil); + +#define SETUP_CHARSET_TAGS_FROB(stage) do { \ + \ + XVECTOR_DATA(new_value)[stage] = call2_trapping_problems \ + ("Error during specifier tag charset predicate," \ + " stage " #stage, \ + charset_predicate, charset, Q##stage, 0); \ + \ + if (UNBOUNDP(XVECTOR_DATA(new_value)[stage])) \ + { \ + XVECTOR_DATA(new_value)[stage] = Qnil; \ + } \ + else if (!NILP(XVECTOR_DATA(new_value)[stage])) \ + { \ + /* Don't want random other objects hanging around. */ \ + XVECTOR_DATA(new_value)[stage] = Qt; \ + } \ + \ + } while (0) + + SETUP_CHARSET_TAGS_FROB (initial); + SETUP_CHARSET_TAGS_FROB (final); + /* More later? */ + +#undef SETUP_CHARSET_TAGS_FROB + + charset_tag_list = Fcons(Fcons(tag, new_value), charset_tag_list); + } + + XVECTOR_DATA + (Vcharset_tag_lists)[XCHARSET_LEADING_BYTE(charset) - MIN_LEADING_BYTE] + = charset_tag_list; +} + +#ifdef DEBUG_XEMACS + +/* Nothing's calling this, I see no reason to keep it in the production + builds. */ + DEFUN ("device-matching-specifier-tag-list", Fdevice_matching_specifier_tag_list, 0, 1, 0, /* -Return a list of all specifier tags matching DEVICE. -DEVICE defaults to the selected device if omitted. -*/ + Return a list of all specifier tags matching DEVICE. + DEVICE defaults to the selected device if omitted. + */ (device)) { struct device *d = decode_device (device); @@ -1100,7 +1393,7 @@ LIST_LOOP (rest, DEVICE_USER_DEFINED_TAGS (d)) { - if (!NILP (XCDR (XCAR (rest)))) + if (!NILP (XCADR (XCAR (rest)))) list = Fcons (XCAR (XCAR (rest)), list); } @@ -1111,6 +1404,8 @@ RETURN_UNGCPRO (list); } +#endif /* DEBUG_XEMACS */ + DEFUN ("specifier-tag-list", Fspecifier_tag_list, 0, 0, 0, /* Return a list of all currently-defined specifier tags. This includes the built-in ones (the device types and classes). @@ -1132,8 +1427,9 @@ RETURN_UNGCPRO (list); } -DEFUN ("specifier-tag-predicate", Fspecifier_tag_predicate, 1, 1, 0, /* -Return the predicate for the given specifier tag. +DEFUN ("specifier-tag-device-predicate", Fspecifier_tag_device_predicate, + 1, 1, 0, /* +Return the device predicate for the given specifier tag. */ (tag)) { @@ -1142,7 +1438,7 @@ if (NILP (Fvalid_specifier_tag_p (tag))) invalid_argument ("Invalid specifier tag", - tag); + tag); /* Make up some predicates for the built-in types */ @@ -1156,11 +1452,27 @@ list3 (Qeq, list2 (Qquote, tag), list2 (Qdevice_class, Qdevice))); - return XCDR (assq_no_quit (tag, Vuser_defined_tags)); + return XCADR (assq_no_quit (tag, Vuser_defined_tags)); +} + +DEFUN ("specifier-tag-charset-predicate", Fspecifier_tag_charset_predicate, + 1, 1, 0, /* + Return the charset predicate for the given specifier tag. + */ + (tag)) +{ + /* The return value of this function must be GCPRO'd. */ + CHECK_SYMBOL (tag); + + if (NILP (Fvalid_specifier_tag_p (tag))) + invalid_argument ("Invalid specifier tag", + tag); + + return XCADDR (assq_no_quit (tag, Vuser_defined_tags)); } /* Return true if A "matches" B. If EXACT_P is 0, A must be a subset of B. - Otherwise, A must be `equal' to B. The sets must be canonicalized. */ + Otherwise, A must be `equal' to B. The sets must be canonicalized. */ static int tag_sets_match_p (Lisp_Object a, Lisp_Object b, int exact_p) { @@ -1268,15 +1580,15 @@ if (!CONSP (inst_pair)) { maybe_sferror ( - "Invalid instantiator pair", inst_pair, - Qspecifier, errb); + "Invalid instantiator pair", inst_pair, + Qspecifier, errb); return Qnil; } if (NILP (Fvalid_specifier_tag_set_p (tag_set = XCAR (inst_pair)))) { maybe_invalid_argument ( - "Invalid specifier tag", tag_set, - Qspecifier, errb); + "Invalid specifier tag", tag_set, + Qspecifier, errb); return Qnil; } @@ -1317,15 +1629,15 @@ if (!CONSP (spec)) { maybe_sferror ( - "Invalid specification list", spec_list, - Qspecifier, errb); + "Invalid specification list", spec_list, + Qspecifier, errb); return Qnil; } if (NILP (Fvalid_specifier_locale_p (locale = XCAR (spec)))) { maybe_invalid_argument ( - "Invalid specifier locale", locale, - Qspecifier, errb); + "Invalid specifier locale", locale, + Qspecifier, errb); return Qnil; } @@ -1414,13 +1726,13 @@ out the frequency with which this is called with the various types and reorder the check accordingly. */ #define SPECIFIER_GET_SPEC_LIST(specifier, type) \ -(type == LOCALE_GLOBAL ? &(XSPECIFIER (specifier)->global_specs) : \ - type == LOCALE_DEVICE ? &(XSPECIFIER (specifier)->device_specs) : \ - type == LOCALE_FRAME ? &(XSPECIFIER (specifier)->frame_specs) : \ - type == LOCALE_WINDOW ? &(XWEAK_LIST_LIST \ - (XSPECIFIER (specifier)->window_specs)) : \ - type == LOCALE_BUFFER ? &(XSPECIFIER (specifier)->buffer_specs) : \ - 0) + (type == LOCALE_GLOBAL ? &(XSPECIFIER (specifier)->global_specs) : \ + type == LOCALE_DEVICE ? &(XSPECIFIER (specifier)->device_specs) : \ + type == LOCALE_FRAME ? &(XSPECIFIER (specifier)->frame_specs) : \ + type == LOCALE_WINDOW ? &(XWEAK_LIST_LIST \ + (XSPECIFIER (specifier)->window_specs)) : \ + type == LOCALE_BUFFER ? &(XSPECIFIER (specifier)->buffer_specs) : \ + 0) static Lisp_Object * specifier_get_inst_list (Lisp_Object specifier, Lisp_Object locale, @@ -1759,8 +2071,8 @@ validating LOCALE and INST-LIST, but the tag-sets in INST-LIST do not need to be canonicalized. */ - /* #### I really need to rethink the after-change - functions to make them easier to use and more efficient. */ +/* #### I really need to rethink the after-change + functions to make them easier to use and more efficient. */ static void specifier_add_spec (Lisp_Object specifier, Lisp_Object locale, @@ -1856,9 +2168,9 @@ /* map MAPFUN over the locales in SPECIFIER that are given in LOCALE. CLOSURE is passed unchanged to MAPFUN. LOCALE can be one of - -- nil (same as `all') - -- a single locale, locale type, or `all' - -- a list of locales, locale types, and/or `all' + -- nil (same as `all') + -- a single locale, locale type, or `all' + -- a list of locales, locale types, and/or `all' MAPFUN is called for each locale and locale type given; for `all', it is called for the locale `global' and for the four possible @@ -1868,7 +2180,7 @@ If MAPFUN ever returns non-zero, the mapping is halted and the value returned is returned from map_specifier(). Otherwise, the mapping proceeds to the end and map_specifier() returns 0. - */ +*/ static int map_specifier (Lisp_Object specifier, Lisp_Object locale, @@ -2148,7 +2460,7 @@ TAG-SET must be equal to an instantiator's tag set for the instantiator to be returned. */ - (specifier, locale, tag_set, exact_p)) + (specifier, locale, tag_set, exact_p)) { struct specifier_spec_list_closure cl; struct gcpro gcpro1, gcpro2; @@ -2347,7 +2659,7 @@ CHECK_SPECIFIER (dest); check_modifiable_specifier (dest); if (XSPECIFIER (dest)->methods != XSPECIFIER (specifier)->methods) - invalid_argument ("Specifiers not of same type", Qunbound); + invalid_argument ("Specifiers not of same type", Qunbound); } cl.dest = dest; @@ -2496,10 +2808,13 @@ { /* This function can GC */ Lisp_Specifier *sp; - Lisp_Object device; - Lisp_Object rest; - int count = specpdl_depth (); + Lisp_Object device, charset = Qnil, rest; + int count = specpdl_depth (), respected_charsets = 0; struct gcpro gcpro1, gcpro2; + enum font_specifier_matchspec_stages stage = initial; +#ifdef DEBUG_XEMACS + int non_ascii; +#endif GCPRO2 (specifier, inst_list); @@ -2507,37 +2822,125 @@ device = DOMAIN_DEVICE (domain); if (no_quit) - /* The instantiate method is allowed to call eval. Since it - is quite common for this function to get called from somewhere in - redisplay we need to make sure that quits are ignored. Otherwise - Fsignal will abort. */ + /* The instantiate method is allowed to call eval. Since it + is quite common for this function to get called from somewhere in + redisplay we need to make sure that quits are ignored. Otherwise + Fsignal will abort. */ specbind (Qinhibit_quit, Qt); +#ifdef MULE + if (CONSP(matchspec) && (CHARSETP(XCAR(matchspec)))) + { + charset = Ffind_charset(XCAR(matchspec)); + +#ifdef DEBUG_XEMACS + /* This is mostly to have somewhere to set debug breakpoints. */ + if (!EQ(charset, Vcharset_ascii)) + { + non_ascii = 1; + } +#endif /* DEBUG_XEMACS */ + + if (!NILP(XCDR(matchspec))) + { + +#define FROB(new_stage) if (EQ(Q##new_stage, XCDR(matchspec))) \ + { \ + stage = new_stage; \ + } + + FROB(initial) + else FROB(final) + else assert(0); +#undef FROB + + } + } +#endif /* MULE */ + + LIST_LOOP(rest, inst_list) + { + Lisp_Object tagged_inst = XCAR (rest); + Lisp_Object tag_set = XCAR (tagged_inst); + Lisp_Object val, the_instantiator; + + if (!device_matches_specifier_tag_set_p (device, tag_set)) + { + continue; + } + + val = XCDR (tagged_inst); + the_instantiator = val; + + if (!NILP(charset) && + !(charset_matches_specifier_tag_set_p (charset, tag_set, stage))) + { + ++respected_charsets; + continue; + } + + if (HAS_SPECMETH_P (sp, instantiate)) + val = call_with_suspended_errors + ((lisp_fn_t) RAW_SPECMETH (sp, instantiate), + Qunbound, Qspecifier, errb, 5, specifier, + matchspec, domain, val, depth); + + if (!UNBOUNDP (val)) + { + unbind_to (count); + UNGCPRO; + if (instantiator) + *instantiator = the_instantiator; + return val; + } + } + + /* We've checked all the tag sets, and checking the charset part of the + specifier never returned 0 (preventing the attempted instantiation), so + there's no need to loop for the second time to avoid checking the + charsets. */ + if (!respected_charsets) + { + unbind_to (count); + UNGCPRO; + return Qunbound; + } + + /* Right, didn't instantiate a specifier last time, perhaps because we + paid attention to the charset-specific aspects of the specifier. Try + again without checking the charset information. + + We can't emulate the approach for devices, defaulting to matching all + character sets for a given specifier, because $random font instantiator + cannot usefully show all character sets, and indeed having it try is a + failure on our part. */ LIST_LOOP (rest, inst_list) { Lisp_Object tagged_inst = XCAR (rest); Lisp_Object tag_set = XCAR (tagged_inst); - - if (device_matches_specifier_tag_set_p (device, tag_set)) + Lisp_Object val, the_instantiator; + + if (!device_matches_specifier_tag_set_p (device, tag_set)) { - Lisp_Object val = XCDR (tagged_inst); - Lisp_Object the_instantiator = val; - - - if (HAS_SPECMETH_P (sp, instantiate)) - val = call_with_suspended_errors - ((lisp_fn_t) RAW_SPECMETH (sp, instantiate), - Qunbound, Qspecifier, errb, 5, specifier, - matchspec, domain, val, depth); - - if (!UNBOUNDP (val)) - { - unbind_to (count); - UNGCPRO; - if (instantiator) - *instantiator = the_instantiator; - return val; - } + continue; + } + + val = XCDR (tagged_inst); + the_instantiator = val; + + if (HAS_SPECMETH_P (sp, instantiate)) + val = call_with_suspended_errors + ((lisp_fn_t) RAW_SPECMETH (sp, instantiate), + Qunbound, Qspecifier, errb, 5, specifier, + matchspec, domain, val, depth); + + if (!UNBOUNDP (val)) + { + unbind_to (count); + UNGCPRO; + if (instantiator) + *instantiator = the_instantiator; + return val; } } @@ -2552,19 +2955,19 @@ return it. Otherwise return Qunbound. */ #define CHECK_INSTANCE_ENTRY(key, matchspec, type) do { \ - Lisp_Object *CIE_inst_list = \ - specifier_get_inst_list (specifier, key, type); \ - if (CIE_inst_list) \ - { \ - Lisp_Object CIE_val = \ - specifier_instance_from_inst_list (specifier, matchspec, \ - domain, *CIE_inst_list, \ - errb, no_quit, depth, \ - instantiator); \ - if (!UNBOUNDP (CIE_val)) \ - return CIE_val; \ - } \ -} while (0) + Lisp_Object *CIE_inst_list = \ + specifier_get_inst_list (specifier, key, type); \ + if (CIE_inst_list) \ + { \ + Lisp_Object CIE_val = \ + specifier_instance_from_inst_list (specifier, matchspec, \ + domain, *CIE_inst_list, \ + errb, no_quit, depth, \ + instantiator); \ + if (!UNBOUNDP (CIE_val)) \ + return CIE_val; \ + } \ + } while (0) /* We accept any window, frame or device domain and do our checking starting from as specific a locale type as we can determine from the @@ -2919,8 +3322,8 @@ 0); } -DEFUN ("specifier-instantiator-from-inst-list", Fspecifier_instantiator_from_inst_list, - 3, 4, 0, /* +DEFUN ("specifier-instantiator-from-inst-list", + Fspecifier_instantiator_from_inst_list, 3, 4, 0, /* Attempt to convert an inst-list into an instance; return instantiator. This is identical to `specifier-instance-from-inst-list' but returns the instantiator used to generate the instance, rather than the instance @@ -2988,17 +3391,17 @@ If you create a built-in specifier, you should do the following: - Make sure the file you create the specifier in has a - specifier_vars_of_foo() function. If not, create it, declare it in - symsinit.h, and make sure it's called in the appropriate place in - emacs.c. + specifier_vars_of_foo() function. If not, create it, declare it in + symsinit.h, and make sure it's called in the appropriate place in + emacs.c. - In specifier_vars_of_foo(), do a DEFVAR_SPECIFIER(), followed by - initializing the specifier using Fmake_specifier(), followed by - set_specifier_fallback(), followed (optionally) by - set_specifier_caching(). + initializing the specifier using Fmake_specifier(), followed by + set_specifier_fallback(), followed (optionally) by + set_specifier_caching(). - If you used set_specifier_caching(), make sure to create the - appropriate value-changed functions. Also make sure to add the - appropriate slots where the values are cached to frameslots.h and - winslots.h. + appropriate value-changed functions. Also make sure to add the + appropriate slots where the values are cached to frameslots.h and + winslots.h. Do a grep for menubar_visible_p for an example. */ @@ -3025,7 +3428,7 @@ sp->caching = alloc_lrecord_type (struct specifier_caching, &lrecord_specifier_caching); #else /* not NEW_GC */ - sp->caching = xnew_and_zero (struct specifier_caching); + sp->caching = xnew_and_zero (struct specifier_caching); #endif /* not NEW_GC */ sp->caching->offset_into_struct_window = struct_window_offset; sp->caching->value_changed_in_window = value_changed_in_window; @@ -3326,10 +3729,10 @@ DEFINE_SPECIFIER_TYPE (display_table); -#define VALID_SINGLE_DISPTABLE_INSTANTIATOR_P(instantiator) \ - (VECTORP (instantiator) \ - || (CHAR_TABLEP (instantiator) \ - && (XCHAR_TABLE_TYPE (instantiator) == CHAR_TABLE_TYPE_CHAR \ +#define VALID_SINGLE_DISPTABLE_INSTANTIATOR_P(instantiator) \ + (VECTORP (instantiator) \ + || (CHAR_TABLEP (instantiator) \ + && (XCHAR_TABLE_TYPE (instantiator) == CHAR_TABLE_TYPE_CHAR \ || XCHAR_TABLE_TYPE (instantiator) == CHAR_TABLE_TYPE_GENERIC)) \ || RANGE_TABLEP (instantiator)) @@ -3354,7 +3757,7 @@ lose: dead_wrong_type_argument (display_table_specifier_methods->predicate_symbol, - instantiator); + instantiator); } } } @@ -3408,7 +3811,8 @@ DEFSUBR (Fdefine_specifier_tag); DEFSUBR (Fdevice_matching_specifier_tag_list); DEFSUBR (Fspecifier_tag_list); - DEFSUBR (Fspecifier_tag_predicate); + DEFSUBR (Fspecifier_tag_device_predicate); + DEFSUBR (Fspecifier_tag_charset_predicate); DEFSUBR (Fcheck_valid_instantiator); DEFSUBR (Fvalid_instantiator_p); @@ -3509,4 +3913,7 @@ Vunlock_ghost_specifiers = Qnil; staticpro (&Vunlock_ghost_specifiers); + + Vcharset_tag_lists = make_vector(NUM_LEADING_BYTES, Qnil); + staticpro (&Vcharset_tag_lists); }
--- a/src/specifier.h Sat Nov 04 22:51:03 2006 +0000 +++ b/src/specifier.h Sun Nov 05 22:31:46 2006 +0000 @@ -535,6 +535,7 @@ void cleanup_specifiers (void); void prune_specifiers (void); void setup_device_initial_specifier_tags (struct device *d); +void setup_charset_initial_specifier_tags (Lisp_Object charset); void kill_specifier_buffer_locals (Lisp_Object buffer); DECLARE_SPECIFIER_TYPE (generic); @@ -567,4 +568,18 @@ #define CHECK_DISPLAYTABLE_SPECIFIER(x) CHECK_SPECIFIER_TYPE (x, display_table) #define CONCHECK_DISPLAYTABLE_SPECIFIER(x) CONCHECK_SPECIFIER_TYPE (x, display_table) +/* The various stages of font instantiation; initial means "find a font for + CHARSET that matches the charset's registries" and final means "find a + font for CHARSET that matches iso10646-1, since we haven't found a font + that matches its registry." */ +enum font_specifier_matchspec_stages { + initial, + final, + impossible, +}; + +Lisp_Object define_specifier_tag(Lisp_Object tag, + Lisp_Object device_predicate, + Lisp_Object charset_predicate); + #endif /* INCLUDED_specifier_h_ */
--- a/src/unicode.c Sat Nov 04 22:51:03 2006 +0000 +++ b/src/unicode.c Sun Nov 05 22:31:46 2006 +0000 @@ -1115,9 +1115,8 @@ Ibyte setname[32]; Lisp_Object charset_descr = build_string ("Mule charset for otherwise unknown Unicode code points."); - Lisp_Object charset_regr = build_string("iso10646-1"); - struct gcpro gcpro1, gcpro2; + struct gcpro gcpro1; if ('\0' == last_jit_charset_final) { @@ -1138,7 +1137,7 @@ Lisp reader. We GCPRO in case it GCs in the future and no-one checks all the C callers. */ - GCPRO2 (charset_descr, charset_regr); + GCPRO1 (charset_descr); Vcurrent_jit_charset = Fmake_charset (intern((const CIbyte *)setname), charset_descr, /* Set encode-as-utf-8 to t, to have this character set written @@ -1148,7 +1147,7 @@ nconc2 (list2(Qencode_as_utf_8, Qt), nconc2 (list6(Qcolumns, make_int(1), Qchars, make_int(96), Qdimension, make_int(2)), - list6(Qregistry, charset_regr, + list6(Qregistries, Qunicode_registries, Qfinal, make_char(last_jit_charset_final++), /* This CCL program is initialised in unicode.el. */ @@ -2539,6 +2538,8 @@ DEFSYMBOL (Qccl_encode_to_ucs_2); DEFSYMBOL (Qlast_allocated_character); DEFSYMBOL (Qignore_first_column); + + DEFSYMBOL (Qunicode_registries); #endif /* MULE */ DEFSUBR (Fchar_to_unicode); @@ -2611,6 +2612,8 @@ dump_add_root_block_ptr (&unicode_precedence_dynarr, &lisp_object_dynarr_description); + + init_blank_unicode_tables (); staticpro (&Vcurrent_jit_charset); @@ -2636,5 +2639,16 @@ from_unicode_level_3_desc_1); dump_add_root_block (&from_unicode_blank_4, sizeof (void *), from_unicode_level_4_desc_1); + + DEFVAR_LISP ("unicode-registries", &Qunicode_registries /* +Vector describing the X11 registries searched when using fallback fonts. + +"Fallback fonts" here includes by default those fonts used by redisplay when +displaying charsets for which the `encode-as-utf-8' property is true, and +those used when no font matching the charset's registries property has been +found (that is, they're probably Mule-specific charsets like Ethiopic or +IPA.) +*/ ); + Qunicode_registries = vector1(build_string("iso10646-1")); #endif /* MULE */ }