[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Emacs-diffs] /srv/bzr/emacs/trunk r102210: Implement various display me
From: |
Kenichi Handa |
Subject: |
[Emacs-diffs] /srv/bzr/emacs/trunk r102210: Implement various display methods for glyphless characters. |
Date: |
Mon, 01 Nov 2010 16:56:16 +0900 |
User-agent: |
Bazaar (2.0.3) |
------------------------------------------------------------
revno: 102210 [merge]
committer: Kenichi Handa <address@hidden>
branch nick: trunk
timestamp: Mon 2010-11-01 16:56:16 +0900
message:
Implement various display methods for glyphless characters.
modified:
lisp/ChangeLog
lisp/faces.el
lisp/international/characters.el
src/ChangeLog
src/coding.c
src/dispextern.h
src/nsterm.m
src/term.c
src/termhooks.h
src/w32gui.h
src/w32term.c
src/xdisp.c
src/xterm.c
=== modified file 'lisp/ChangeLog'
--- a/lisp/ChangeLog 2010-11-01 07:40:11 +0000
+++ b/lisp/ChangeLog 2010-11-01 07:55:44 +0000
@@ -1,3 +1,17 @@
+2010-11-01 Kenichi Handa <address@hidden>
+
+ * faces.el (glyphless-char): Inherit underline for tty.
+
+2010-10-28 Kenichi Handa <address@hidden>
+
+ Implement various display methods for glyphless characters.
+
+ * international/characters.el (char-acronym-table): New variable.
+ (glyphless-char-control): New variable.
+ (update-glyphless-char-display): New funciton.
+
+ * faces.el (glyphless-char): New face.
+
2010-11-01 Glenn Morris <address@hidden>
* calendar/holidays.el (general-holidays, oriental-holidays)
=== modified file 'lisp/faces.el'
--- a/lisp/faces.el 2010-11-01 06:13:43 +0000
+++ b/lisp/faces.el 2010-11-01 07:53:08 +0000
@@ -2482,6 +2482,14 @@
(defface help-argument-name '((((supports :slant italic)) :inherit italic))
"Face to highlight argument names in *Help* buffers."
:group 'help)
+
+(defface glyphless-char
+ '((((type tty)) :inherit underline)
+ (t :height 0.6))
+ "Face for displaying non-graphic characters (e.g. U+202A (LRE)).
+It is used for characters of no fonts too."
+ :version "24.1"
+ :group 'basic-faces)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Manipulating font names.
=== modified file 'lisp/international/characters.el'
--- a/lisp/international/characters.el 2010-10-15 00:41:53 +0000
+++ b/lisp/international/characters.el 2010-10-29 00:50:13 +0000
@@ -1234,6 +1234,131 @@
(optimize-char-table (standard-category-table))
+;; Display of glyphless characters.
+
+(defvar char-acronym-table
+ (make-char-table 'char-acronym-table nil)
+ "Char table of acronyms for non-graphic characters.")
+
+(let ((c0-acronyms '("NUL" "SOH" "STX" "ETX" "EOT" "ENQ" "ACK" "BEL"
+ "BS" nil nil "VT" "FF" "CR" "SO" "SI"
+ "DLE" "DC1" "DC2" "DC3" "DC4" "NAK" "SYN" "ETB"
+ "CAN" "EM" "SUB" "ESC" "FC" "GS" "RS" "US")))
+ (dotimes (i 32)
+ (aset char-acronym-table i (car c0-acronyms))
+ (setq c0-acronyms (cdr c0-acronyms))))
+
+(let ((c1-acronyms '("XXX" "XXX" "BPH" "NBH" "IND" "NEL" "SSA" "ESA"
+ "HTS" "HTJ" "VTS" "PLD" "PLU" "R1" "SS2" "SS1"
+ "DCS" "PU1" "PU2" "STS" "CCH" "MW" "SPA" "EPA"
+ "SOS" "XXX" "SC1" "CSI" "ST" "OSC" "PM" "APC")))
+ (dotimes (i 32)
+ (aset char-acronym-table (+ #x0080 i) (car c1-acronyms))
+ (setq c1-acronyms (cdr c1-acronyms))))
+
+(aset char-acronym-table #x17B4 "KIVAQ") ; KHMER VOWEL INHERENT AQ
+(aset char-acronym-table #x17B5 "KIVAA") ; KHMER VOWEL INHERENT AA
+(aset char-acronym-table #x200B "ZWSP") ; ZERO WIDTH SPACE
+(aset char-acronym-table #x200C "ZWNJ") ; ZERO WIDTH NON-JOINER
+(aset char-acronym-table #x200D "ZWJ") ; ZERO WIDTH JOINER
+(aset char-acronym-table #x200E "LRM") ; LEFT-TO-RIGHT MARK
+(aset char-acronym-table #x200F "RLM") ; RIGHT-TO-LEFT MARK
+(aset char-acronym-table #x202A "LRE") ; LEFT-TO-RIGHT EMBEDDING
+(aset char-acronym-table #x202B "RLE") ; RIGHT-TO-LEFT EMBEDDING
+(aset char-acronym-table #x202C "PDF") ; POP DIRECTIONAL FORMATTING
+(aset char-acronym-table #x202D "LRO") ; LEFT-TO-RIGHT OVERRIDE
+(aset char-acronym-table #x202E "RLO") ; RIGHT-TO-LEFT OVERRIDE
+(aset char-acronym-table #x2060 "WJ") ; WORD JOINER
+(aset char-acronym-table #x206A "ISS") ; INHIBIT SYMMETRIC SWAPPING
+(aset char-acronym-table #x206B "ASS") ; ACTIVATE SYMMETRIC SWAPPING
+(aset char-acronym-table #x206C "IAFS") ; INHIBIT ARABIC FORM SHAPING
+(aset char-acronym-table #x206D "AAFS") ; ACTIVATE ARABIC FORM SHAPING
+(aset char-acronym-table #x206E "NADS") ; NATIONAL DIGIT SHAPES
+(aset char-acronym-table #x206F "NODS") ; NOMINAL DIGIT SHAPES
+(aset char-acronym-table #xFEFF "ZWNBSP") ; ZERO WIDTH NO-BREAK SPACE
+(aset char-acronym-table #xFFF9 "IAA") ; INTERLINEAR ANNOTATION ANCHOR
+(aset char-acronym-table #xFFFA "IAS") ; INTERLINEAR ANNOTATION SEPARATOR
+(aset char-acronym-table #xFFFB "IAT") ; INTERLINEAR ANNOTATION TERMINATOR
+(aset char-acronym-table #x1D173 "BEGBM") ; MUSICAL SYMBOL BEGIN BEAM
+(aset char-acronym-table #x1D174 "ENDBM") ; MUSICAL SYMBOL END BEAM
+(aset char-acronym-table #x1D175 "BEGTIE") ; MUSICAL SYMBOL BEGIN TIE
+(aset char-acronym-table #x1D176 "END") ; MUSICAL SYMBOL END TIE
+(aset char-acronym-table #x1D177 "BEGSLR") ; MUSICAL SYMBOL BEGIN SLUR
+(aset char-acronym-table #x1D178 "ENDSLR") ; MUSICAL SYMBOL END SLUR
+(aset char-acronym-table #x1D179 "BEGPHR") ; MUSICAL SYMBOL BEGIN PHRASE
+(aset char-acronym-table #x1D17A "ENDPHR") ; MUSICAL SYMBOL END PHRASE
+(aset char-acronym-table #xE0001 "|->TAG") ; LANGUAGE TAG
+(aset char-acronym-table #xE0020 "SP TAG") ; TAG SPACE
+(dotimes (i 94)
+ (aset char-acronym-table (+ #xE0021 i) (format " %c TAG" (+ 33 i))))
+(aset char-acronym-table #xE007F "->|TAG") ; CANCEL TAG
+
+;;; Control of displaying glyphless characters.
+(defvar glyphless-char-control
+ '((format-control . thin-space)
+ (no-font . hexa-code))
+ "List of directives to control displaying of glyphless characters.
+
+Each element has the form (TARGET . METHOD), where TARGET is a
+symbol specifying the target character group to control, and
+METHOD is a symbol specifying the method of displaying them.
+
+TARGET must be one of these symbols:
+ `c0-control': U+0000..U+001F.
+ `c1-control': U+0080..U+009F.
+ `format-control': Characters of Unicode General Category `Cf'.
+ Ex: U+200C (ZWNJ), U+200E (LRM)), but don't include characters
+ that have graphic image such as U+00AD (SHY).
+ `no-font': characters for which no suitable font is found.
+
+METHOD must be one of these symbols:
+ `zero-width': don't display.
+ `thin-space': display a thin space (1-pixel width).
+ `empty-box': display an empty box.
+ `acronym': display an acronum string in a box.
+ `hexa-code': display a hexadecimal character code in a box.
+
+Just setting this variable does not take effect. Call the
+function `update-glyphless-char-display' (which see) after
+setting this variable.")
+
+(defun update-glyphless-char-display ()
+ "Make the setting of `glyphless-char-control' take effect.
+This function updates the char-table `glyphless-char-display'."
+ (dolist (elt glyphless-char-control)
+ (let ((target (car elt))
+ (method (cdr elt)))
+ (cond ((eq target 'c0-control)
+ (set-char-table-range glyphless-char-display '(#x00 . #x1F)
+ method))
+ ((eq target 'c1-control)
+ (set-char-table-range glyphless-char-display '(#x80 . #x9F)
+ method))
+ ((eq target 'format-control)
+ (map-char-table
+ #'(lambda (char category)
+ (if (eq category 'Cf)
+ (let ((this-method method)
+ from to)
+ (if (consp char)
+ (setq from (car char) to (cdr char))
+ (setq from char to char))
+ (while (<= from to)
+ (when (/= from #xAD)
+ (if (eq method 'acronym)
+ (setq this-method
+ (aref char-acronym-table from)))
+ (set-char-table-range glyphless-char-display
+ from this-method))
+ (setq from (1+ from))))))
+ unicode-category-table))
+ ((eq target 'no-font)
+ (set-char-table-extra-slot glyphless-char-display 0 method))
+ (t
+ (error "Invalid target character group: %s" target))))))
+
+(update-glyphless-char-display)
+
;;; Setting word boundary.
(setq word-combining-categories
=== modified file 'src/ChangeLog'
--- a/src/ChangeLog 2010-10-31 22:35:44 +0000
+++ b/src/ChangeLog 2010-11-01 07:53:08 +0000
@@ -1,3 +1,72 @@
+2010-11-01 Kenichi Handa <address@hidden>
+
+ * dispextern.h (lookup_glyphless_char_display): Extern it.
+
+ * termhooks.h (struct terminal): New member charset_list.
+
+ * coding.c (Fset_terminal_coding_system_internal): Set the
+ `charset_list' member of struct terminal.
+
+ * term.c (produce_glyphs): Handle the case it->what ==
+ IT_GLYPHLESS.
+ (append_glyphless_glyph, produce_glyphless_glyph): New functions.
+
+ * xdisp.c (lookup_glyphless_char_display): Make it non-static.
+ (lookup_glyphless_char_display): Set it->what at the end.
+ (last_glyphless_glyph_frame, last_glyphless_glyph_face_id)
+ (last_glyphless_glyph_merged_face_id): Make them non-static.
+
+ * w32term.c (x_draw_glyphless_glyph_string_foreground): Fix
+ the arg with_background for font->driver->draw.
+
+2010-10-29 Kenichi Handa <address@hidden>
+
+ * w32gui.h (STORE_XCHAR2B, XCHAR2B_BYTE1, XCHAR2B_BYTE2): Surround
+ chp by parentheses.
+
+2010-10-28 Kenichi Handa <address@hidden>
+
+ Implement various display methods for glyphless characters.
+
+ * xdisp.c (Qglyphless_char, Vglyphless_char_display)
+ (Qglyphless_char_display, Qhexa_code, Qempty_box, Qthin_space)
+ (Qzero_width): New variables.
+ (THIN_SPACE_WIDTH): New macro.
+ (lookup_glyphless_char_display): New funciton.
+ (last_glyphless_glyph_frame, last_glyphless_glyph_face_id)
+ (last_glyphless_glyph_merged_face_id): New variables.
+ (get_next_display_element): Check glyphless characters.
+ (redisplay_internal): Initialize last_glyphless_glyph_frame and
+ last_glyphless_glyph_face_id.
+ (fill_glyphless_glyph_string): New function.
+ (BUILD_GLYPHLESS_GLYPH_STRING): New macro.
+ (BUILD_GLYPH_STRINGS): Handle the case GLYPHLESS_GLYPH.
+ (append_glyphless_glyph, produce_glyphless_glyph): New functions.
+ (x_produce_glyphs): If a suitable font is not found, produce a
+ glyphless glyph. Handle the case it->what == IT_GLYPHLESS.
+ (syms_of_xdisp): Intern and staticpro Qglyphless_char,
+ Qglyphless_char_display, Qhexa_code, Qempty_box, Qthin_space, and
+ Qzero_width.
+ (Vglyphless_char_display): Declare it as a Lisp variable.
+
+ * dispextern.h (enum glyph_type): Add GLYPHLESS_GLYPH.
+ (struct glyph): Change the size of the member "type" to 3. Add
+ glyphless to the union slice and u.
+ (enum display_element_type): Add IT_GLYPHLESS.
+ (enum glyphless_display_method): New enum.
+ (struct it): New member glyphless_method.
+ (Vglyphless_char_display): Extern it.
+
+ * xterm.c (x_draw_glyphless_glyph_string_foreground): New function.
+ (x_draw_glyph_string): Handle the case GLYPHLESS_GLYPH.
+
+ * w32term.c (x_draw_glyphless_glyph_string_foreground): New
+ function.
+ (x_draw_glyph_string): Handle the case GLYPHLESS_GLYPH.
+
+ * nsterm.m (ns_draw_glyph_string): Handle the case
+ GLYPHLESS_GLYPH (the detail is not yet implemented).
+
2010-10-31 Glenn Morris <address@hidden>
* xterm.c (x_connection_closed) [USE_X_TOOLKIT]: Fix merge, maybe.
=== modified file 'src/coding.c'
--- a/src/coding.c 2010-10-14 14:32:27 +0000
+++ b/src/coding.c 2010-11-01 04:09:26 +0000
@@ -9297,7 +9297,8 @@
doc: /* Internal use only. */)
(Lisp_Object coding_system, Lisp_Object terminal)
{
- struct coding_system *terminal_coding = TERMINAL_TERMINAL_CODING
(get_terminal (terminal, 1));
+ struct terminal *term = get_terminal (terminal, 1);
+ struct coding_system *terminal_coding = TERMINAL_TERMINAL_CODING (term);
CHECK_SYMBOL (coding_system);
setup_coding_system (Fcheck_coding_system (coding_system), terminal_coding);
/* We had better not send unsafe characters to terminal. */
@@ -9306,6 +9307,10 @@
terminal_coding->common_flags &= ~CODING_ANNOTATE_COMPOSITION_MASK;
terminal_coding->src_multibyte = 1;
terminal_coding->dst_multibyte = 0;
+ if (terminal_coding->common_flags & CODING_REQUIRE_ENCODING_MASK)
+ term->charset_list = coding_charset_list (terminal_coding);
+ else
+ term->charset_list = Fcons (Qascii, Qnil);
return Qnil;
}
=== modified file 'src/dispextern.h'
--- a/src/dispextern.h 2010-10-14 14:32:27 +0000
+++ b/src/dispextern.h 2010-11-01 04:09:26 +0000
@@ -279,6 +279,9 @@
/* Glyph describes a static composition. */
COMPOSITE_GLYPH,
+ /* Glyph describes a glyphless character. */
+ GLYPHLESS_GLYPH,
+
/* Glyph describes an image. */
IMAGE_GLYPH,
@@ -333,7 +336,7 @@
/* Which kind of glyph this is---character, image etc. Value
should be an enumerator of type enum glyph_type. */
- unsigned type : 2;
+ unsigned type : 3;
/* 1 means this glyph was produced from multibyte text. Zero
means it was produced from unibyte text, i.e. charsets aren't
@@ -402,6 +405,11 @@
/* Start and end indices of glyphs of a graphme cluster of a
composition (type == COMPOSITE_GLYPH). */
struct { int from, to; } cmp;
+ /* Pixel offsets for upper and lower part of the acronym. */
+ struct {
+ short upper_xoff, upper_yoff;
+ short lower_xoff, lower_yoff;
+ } glyphless;
} slice;
/* A union of sub-structures for different glyph types. */
@@ -433,6 +441,19 @@
}
stretch;
+ /* Sub-stretch for type == GLYPHLESS_GLYPH. */
+ struct
+ {
+ /* Value is an enum of the type glyphless_display_method. */
+ unsigned method : 2;
+ /* 1 iff this glyph is for a character of no font. */
+ unsigned for_no_font : 1;
+ /* Length of acronym or hexadecimal code string (at most 8). */
+ unsigned len : 4;
+ /* Character to display. Actually we need only 22 bits. */
+ unsigned ch : 26;
+ } glyphless;
+
/* Used to compare all bit-fields above in one step. */
unsigned val;
} u;
@@ -1918,6 +1939,9 @@
/* A composition (static and automatic). */
IT_COMPOSITION,
+ /* A glyphless character (e.g. ZWNJ, LRE). */
+ IT_GLYPHLESS,
+
/* An image. */
IT_IMAGE,
@@ -1964,6 +1988,20 @@
WINDOW_WRAP
};
+/* An enumerator for the method of displaying glyphless characters. */
+
+enum glyphless_display_method
+ {
+ /* Display a thin (1-pixel width) space. */
+ GLYPHLESS_DISPLAY_THIN_SPACE,
+ /* Display an empty box of proper width. */
+ GLYPHLESS_DISPLAY_EMPTY_BOX,
+ /* Display an acronym string in a box. */
+ GLYPHLESS_DISPLAY_ACRONYM,
+ /* Display a hexadecimal character code in a box. */
+ GLYPHLESS_DISPLAY_HEXA_CODE
+ };
+
struct it_slice
{
Lisp_Object x;
@@ -2295,6 +2333,10 @@
PRODUCE_GLYPHS, this should be set beforehand too. */
int char_to_display;
+ /* If what == IT_GLYPHLESS, the method to display such a
+ character. */
+ enum glyphless_display_method glyphless_method;
+
/* If what == IT_IMAGE, the id of the image to display. */
int image_id;
@@ -2976,9 +3018,10 @@
extern Lisp_Object Vmouse_autoselect_window;
extern int unibyte_display_via_language_environment;
extern EMACS_INT underline_minimum_offset;
+extern Lisp_Object Vglyphless_char_display;
extern void reseat_at_previous_visible_line_start (struct it *);
-
+extern Lisp_Object lookup_glyphless_char_display (int, struct it *);
extern int calc_pixel_width_or_height (double *, struct it *, Lisp_Object,
struct font *, int, int *);
=== modified file 'src/nsterm.m'
--- a/src/nsterm.m 2010-10-14 14:32:27 +0000
+++ b/src/nsterm.m 2010-10-29 00:50:13 +0000
@@ -2983,6 +2983,22 @@
ns_unfocus (s->f);
break;
+ case GLYPHLESS_GLYPH:
+ n = ns_get_glyph_string_clip_rect (s, r);
+ ns_focus (s->f, r, n);
+
+ if (s->for_overlaps || (s->cmp_from > 0
+ && ! s->first_glyph->u.cmp.automatic))
+ s->background_filled_p = 1;
+ else
+ ns_maybe_dumpglyphs_background
+ (s, s->first_glyph->type == COMPOSITE_GLYPH);
+ /* ... */
+ /* Not yet implemented. */
+ /* ... */
+ ns_unfocus (s->f);
+ break;
+
default:
abort ();
}
=== modified file 'src/term.c'
--- a/src/term.c 2010-10-01 20:18:24 +0000
+++ b/src/term.c 2010-11-01 04:09:26 +0000
@@ -1501,6 +1501,8 @@
static void produce_stretch_glyph (struct it *);
static void append_composite_glyph (struct it *);
static void produce_composite_glyph (struct it *);
+static void append_glyphless_glyph (struct it *, int, char *);
+static void produce_glyphless_glyph (struct it *, int, Lisp_Object);
/* Append glyphs to IT's glyph_row. Called from produce_glyphs for
terminal frames if IT->glyph_row != NULL. IT->char_to_display is
@@ -1609,6 +1611,12 @@
goto done;
}
+ if (it->what == IT_GLYPHLESS)
+ {
+ produce_glyphless_glyph (it, 0, Qnil);
+ goto done;
+ }
+
if (it->char_to_display >= 040 && it->char_to_display < 0177)
{
it->pixel_width = it->nglyphs = 1;
@@ -1660,11 +1668,22 @@
}
else
{
- it->pixel_width = CHAR_WIDTH (it->char_to_display);
- it->nglyphs = it->pixel_width;
-
- if (it->glyph_row)
- append_glyph (it);
+ Lisp_Object charset_list = FRAME_TERMINAL (it->f)->charset_list;
+
+ if (char_charset (it->char_to_display, charset_list, NULL))
+ {
+ it->pixel_width = CHAR_WIDTH (it->char_to_display);
+ it->nglyphs = it->pixel_width;
+ if (it->glyph_row)
+ append_glyph (it);
+ }
+ else
+ {
+ Lisp_Object acronym = lookup_glyphless_char_display (-1, it);
+
+ xassert (it->what == IT_GLYPHLESS);
+ produce_glyphless_glyph (it, 1, acronym);
+ }
}
done:
@@ -1844,6 +1863,161 @@
}
+/* Append a glyph for a glyphless character to IT->glyph_row. FACE_ID
+ is a face ID to be used for the glyph. What actually appended are
+ glyphs of type CHAR_GLYPH of which characters are in STR
+ (it->nglyphs bytes). */
+
+static void
+append_glyphless_glyph (struct it *it, int face_id, char *str)
+{
+ struct glyph *glyph, *end;
+ bidi_type_t bidi_type;
+ int resolved_level;
+ int i;
+
+ xassert (it->glyph_row);
+ glyph = it->glyph_row->glyphs[it->area] + it->glyph_row->used[it->area];
+ end = it->glyph_row->glyphs[1 + it->area];
+
+ /* If the glyph row is reversed, we need to prepend the glyph rather
+ than append it. */
+ if (it->glyph_row->reversed_p && it->area == TEXT_AREA)
+ {
+ struct glyph *g;
+ int move_by = it->pixel_width;
+
+ /* Make room for the new glyphs. */
+ if (move_by > end - glyph) /* don't overstep end of this area */
+ move_by = end - glyph;
+ for (g = glyph - 1; g >= it->glyph_row->glyphs[it->area]; g--)
+ g[move_by] = *g;
+ glyph = it->glyph_row->glyphs[it->area];
+ end = glyph + move_by;
+ }
+
+ if (glyph >= end)
+ return;
+ glyph->type = CHAR_GLYPH;
+ glyph->pixel_width = 1;
+ glyph->face_id = face_id;
+ glyph->padding_p = 0;
+ glyph->charpos = CHARPOS (it->position);
+ glyph->object = it->object;
+ if (it->bidi_p)
+ {
+ glyph->resolved_level = it->bidi_it.resolved_level;
+ if ((it->bidi_it.type & 7) != it->bidi_it.type)
+ abort ();
+ glyph->bidi_type = it->bidi_it.type;
+ }
+ else
+ {
+ glyph->resolved_level = 0;
+ glyph->bidi_type = UNKNOWN_BT;
+ }
+
+ /* BIDI Note: we put the glyphs of characters left to right, even in
+ the REVERSED_P case because we write to the terminal
+ left-to-right. */
+ for (i = 0; i < it->nglyphs && glyph < end; ++i)
+ {
+ if (i > 0)
+ glyph[0] = glyph[-1];
+ glyph->u.ch = str[i];
+ ++it->glyph_row->used[it->area];
+ ++glyph;
+ }
+}
+
+/* Declared in xdisp.c */
+extern struct frame *last_glyphless_glyph_frame;
+extern unsigned last_glyphless_glyph_face_id;
+extern int last_glyphless_glyph_merged_face_id;
+extern Lisp_Object Qglyphless_char;
+
+/* Produce glyphs for a glyphless character for iterator IT.
+ IT->glyphless_method specifies which method to use for displaying
+ the character. See the description of enum
+ glyphless_display_method in dispextern.h for the detail.
+
+ FOR_NO_FONT is nonzero if and only if this is for a character that
+ is not supproted by the coding system of the terminal. ACRONYM, if
+ non-nil, is an acronym string for the character.
+
+ The glyphs actually produced are of type CHAR_GLYPH. */
+
+static void
+produce_glyphless_glyph (struct it *it, int for_no_font, Lisp_Object acronym)
+{
+ int face_id;
+ struct face *face;
+ int width, len;
+ char buf[9], *str = " ";
+
+ /* Get a face ID for the glyph by utilizing a cache (the same way as
+ doen for `escape-glyph' in get_next_display_element). */
+ if (it->f == last_glyphless_glyph_frame
+ && it->face_id == last_glyphless_glyph_face_id)
+ {
+ face_id = last_glyphless_glyph_merged_face_id;
+ }
+ else
+ {
+ /* Merge the `glyphless-char' face into the current face. */
+ face_id = merge_faces (it->f, Qglyphless_char, 0, it->face_id);
+ last_glyphless_glyph_frame = it->f;
+ last_glyphless_glyph_face_id = it->face_id;
+ last_glyphless_glyph_merged_face_id = face_id;
+ }
+
+ if (it->glyphless_method == GLYPHLESS_DISPLAY_THIN_SPACE)
+ {
+ /* As there's no way to produce a thin space, we produce
+ a space of canonical width.. */
+ len = 1;
+ }
+ else if (it->glyphless_method == GLYPHLESS_DISPLAY_EMPTY_BOX)
+ {
+ len = CHAR_WIDTH (it->c);
+ if (len == 0)
+ len = 1;
+ else if (width > 4)
+ len = 4;
+ }
+ else
+ {
+ if (it->glyphless_method == GLYPHLESS_DISPLAY_ACRONYM)
+ {
+ int i;
+
+ if (! STRINGP (acronym) && CHAR_TABLE_P (Vglyphless_char_display))
+ acronym = CHAR_TABLE_REF (Vglyphless_char_display, it->c);
+ buf[0] = '[';
+ str = STRINGP (acronym) ? (char *) SDATA (acronym) : "";
+ for (len = 0; len < 6 && str[len] && ASCII_BYTE_P (str[len]); len++)
+ buf[1 + len] = str[len];
+ buf[1 + len] = ']';
+ len += 2;
+ }
+ else
+ {
+ xassert (it->glyphless_method == GLYPHLESS_DISPLAY_HEXA_CODE);
+ len = (it->c < 0x100 ? sprintf (buf, "U+%02X", it->c)
+ : it->c < 0x10000 ? sprintf (buf, "U+%04X", it->c)
+ : it->c <= MAX_UNICODE_CHAR ? sprintf (buf, "U+%06X", it->c)
+ : sprintf (buf, "E+%06X", it->c));
+ }
+ str = buf;
+ }
+
+ it->pixel_width = len;
+ it->nglyphs = len;
+ if (len > 0 && it->glyph_row)
+ append_glyphless_glyph (it, face_id, str);
+}
+
+
/* Get information about special display element WHAT in an
environment described by IT. WHAT is one of IT_TRUNCATION or
IT_CONTINUATION. Maybe produce glyphs for WHAT if IT has a
=== modified file 'src/termhooks.h'
--- a/src/termhooks.h 2010-10-03 16:21:55 +0000
+++ b/src/termhooks.h 2010-11-01 04:09:26 +0000
@@ -328,6 +328,11 @@
/* Parameter alist of this terminal. */
Lisp_Object param_alist;
+ /* List of charsets supported by the terminal. It is set by
+ Fset_terminal_coding_system_internal along with
+ the member terminal_coding. */
+ Lisp_Object charset_list;
+
/* All fields before `next_terminal' should be Lisp_Object and are traced
by the GC. All fields afterwards are ignored by the GC. */
=== modified file 'src/w32gui.h'
--- a/src/w32gui.h 2010-07-25 00:20:51 +0000
+++ b/src/w32gui.h 2010-10-29 02:01:41 +0000
@@ -59,13 +59,13 @@
/* Dealing with bits of wchar_t as if they were an XChar2b. */
#define STORE_XCHAR2B(chp, byte1, byte2) \
- ((*chp) = ((XChar2b)((((byte1) & 0x00ff) << 8) | ((byte2) & 0x00ff))))
+ ((*(chp)) = ((XChar2b)((((byte1) & 0x00ff) << 8) | ((byte2) & 0x00ff))))
#define XCHAR2B_BYTE1(chp) \
- (((*chp) & 0xff00) >> 8)
+ (((*(chp)) & 0xff00) >> 8)
#define XCHAR2B_BYTE2(chp) \
- ((*chp) & 0x00ff)
+ ((*(chp)) & 0x00ff)
/* Windows equivalent of XImage. */
=== modified file 'src/w32term.c'
--- a/src/w32term.c 2010-10-24 01:22:37 +0000
+++ b/src/w32term.c 2010-11-01 07:35:04 +0000
@@ -1394,6 +1394,94 @@
}
+/* Draw the foreground of glyph string S for glyphless characters. */
+
+static void
+x_draw_glyphless_glyph_string_foreground (struct glyph_string *s)
+{
+ struct glyph *glyph = s->first_glyph;
+ XChar2b char2b[8];
+ int x, i, j;
+ int with_background;
+
+ /* If first glyph of S has a left box line, start drawing the text
+ of S to the right of that box line. */
+ if (s->face->box != FACE_NO_BOX
+ && s->first_glyph->left_box_line_p)
+ x = s->x + eabs (s->face->box_line_width);
+ else
+ x = s->x;
+
+ SetTextColor (s->hdc, s->gc->foreground);
+ SetBkColor (s->hdc, s->gc->background);
+ SetTextAlign (s->hdc, TA_BASELINE | TA_LEFT);
+
+ s->char2b = char2b;
+ with_background = ! (s->for_overlaps
+ || (s->background_filled_p && s->hl != DRAW_CURSOR));
+ for (i = 0; i < s->nchars; i++, glyph++)
+ {
+ char buf[7], *str = NULL;
+ int len = glyph->u.glyphless.len;
+
+ if (glyph->u.glyphless.method == GLYPHLESS_DISPLAY_ACRONYM)
+ {
+ if (len > 1
+ && CHAR_TABLE_P (Vglyphless_char_display)
+ && (CHAR_TABLE_EXTRA_SLOTS (XCHAR_TABLE (Vglyphless_char_display))
+ >= 1))
+ {
+ Lisp_Object acronym
+ = (! glyph->u.glyphless.for_no_font
+ ? CHAR_TABLE_REF (Vglyphless_char_display,
+ glyph->u.glyphless.ch)
+ : XCHAR_TABLE (Vglyphless_char_display)->extras[0]);
+ if (STRINGP (acronym))
+ str = (char *) SDATA (acronym);
+ }
+ }
+ else if (glyph->u.glyphless.method == GLYPHLESS_DISPLAY_HEXA_CODE)
+ {
+ sprintf ((char *) buf, "%0*X",
+ glyph->u.glyphless.ch < 0x10000 ? 4 : 6,
+ glyph->u.glyphless.ch);
+ str = buf;
+ }
+
+ if (str)
+ {
+ struct font *font = s->font;
+ int upper_len = (len + 1) / 2;
+ unsigned code;
+ HFONT old_font;
+
+ old_font = SelectObject (s->hdc, FONT_HANDLE (font));
+ /* It is assured that all LEN characters in STR is ASCII. */
+ for (j = 0; j < len; j++)
+ {
+ code = font->driver->encode_char (font, str[j]);
+ STORE_XCHAR2B (char2b + j, code >> 8, code & 0xFF);
+ }
+ font->driver->draw (s, 0, upper_len,
+ x + glyph->slice.glyphless.upper_xoff,
+ s->ybase + glyph->slice.glyphless.upper_yoff,
+ with_background);
+ font->driver->draw (s, upper_len, len,
+ x + glyph->slice.glyphless.lower_xoff,
+ s->ybase + glyph->slice.glyphless.lower_yoff,
+ with_background);
+ SelectObject (s->hdc, old_font);
+ }
+ if (glyph->u.glyphless.method != GLYPHLESS_DISPLAY_THIN_SPACE)
+ w32_draw_rectangle (s->hdc, s->gc,
+ x, s->ybase - glyph->ascent,
+ glyph->pixel_width - 1,
+ glyph->ascent + glyph->descent - 1);
+ x += glyph->pixel_width;
+ }
+}
+
+
/* Brightness beyond which a color won't have its highlight brightness
boosted.
@@ -2282,6 +2370,14 @@
x_draw_composite_glyph_string_foreground (s);
break;
+ case GLYPHLESS_GLYPH:
+ if (s->for_overlaps)
+ s->background_filled_p = 1;
+ else
+ x_draw_glyph_string_background (s, 0);
+ x_draw_glyphless_glyph_string_foreground (s);
+ break;
+
default:
abort ();
}
=== modified file 'src/xdisp.c'
--- a/src/xdisp.c 2010-10-23 21:19:02 +0000
+++ b/src/xdisp.c 2010-11-01 04:09:26 +0000
@@ -932,6 +932,21 @@
/* Number of seconds to wait before displaying an hourglass cursor. */
Lisp_Object Vhourglass_delay;
+/* Name of the face used to display glyphless characters. */
+Lisp_Object Qglyphless_char;
+
+/* Char-table to control the display of glyphless characters. */
+Lisp_Object Vglyphless_char_display;
+
+/* Symbol for the purpose of Vglyphless_char_display. */
+Lisp_Object Qglyphless_char_display;
+
+/* Method symbols for Vglyphless_char_display. */
+static Lisp_Object Qhexa_code, Qempty_box, Qthin_space, Qzero_width;
+
+/* Default pixel width of `thin-space' display method. */
+#define THIN_SPACE_WIDTH 1
+
/* Default number of seconds to wait before displaying an hourglass
cursor. */
#define DEFAULT_HOURGLASS_DELAY 1
@@ -5732,6 +5747,57 @@
(IT)->string)))
+/* Lookup the char-table Vglyphless_char_display for character C (-1
+ if we want information for no-font case), and return the display
+ method symbol. By side-effect, update it->what and
+ it->glyphless_method. This function is called from
+ get_next_display_element for each character element, and from
+ x_produce_glyphs when no suitable font was found. */
+
+Lisp_Object
+lookup_glyphless_char_display (int c, struct it *it)
+{
+ Lisp_Object glyphless_method = Qnil;
+
+ if (CHAR_TABLE_P (Vglyphless_char_display)
+ && CHAR_TABLE_EXTRA_SLOTS (XCHAR_TABLE (Vglyphless_char_display)) >= 1)
+ glyphless_method = (c >= 0
+ ? CHAR_TABLE_REF (Vglyphless_char_display, c)
+ : XCHAR_TABLE (Vglyphless_char_display)->extras[0]);
+ retry:
+ if (NILP (glyphless_method))
+ {
+ if (c >= 0)
+ /* The default is to display the character by a proper font. */
+ return Qnil;
+ /* The default for the no-font case is to display an empty box. */
+ glyphless_method = Qempty_box;
+ }
+ if (EQ (glyphless_method, Qzero_width))
+ {
+ if (c >= 0)
+ return glyphless_method;
+ /* This method can't be used for the no-font case. */
+ glyphless_method = Qempty_box;
+ }
+ if (EQ (glyphless_method, Qthin_space))
+ it->glyphless_method = GLYPHLESS_DISPLAY_THIN_SPACE;
+ else if (EQ (glyphless_method, Qempty_box))
+ it->glyphless_method = GLYPHLESS_DISPLAY_EMPTY_BOX;
+ else if (EQ (glyphless_method, Qhexa_code))
+ it->glyphless_method = GLYPHLESS_DISPLAY_HEXA_CODE;
+ else if (STRINGP (glyphless_method))
+ it->glyphless_method = GLYPHLESS_DISPLAY_ACRONYM;
+ else
+ {
+ /* Invalid value. We use the default method. */
+ glyphless_method = Qnil;
+ goto retry;
+ }
+ it->what = IT_GLYPHLESS;
+ return glyphless_method;
+}
+
/* Load IT's display element fields with information about the next
display element from the current position of IT. Value is zero if
end of buffer (or C string) is reached. */
@@ -5740,6 +5806,10 @@
static unsigned last_escape_glyph_face_id = (1 << FACE_ID_BITS);
static int last_escape_glyph_merged_face_id = 0;
+struct frame *last_glyphless_glyph_frame = NULL;
+unsigned last_glyphless_glyph_face_id = (1 << FACE_ID_BITS);
+int last_glyphless_glyph_merged_face_id = 0;
+
int
get_next_display_element (struct it *it)
{
@@ -5818,6 +5888,15 @@
goto get_next;
}
+ if (! NILP (lookup_glyphless_char_display (c, it)))
+ {
+ if (it->what == IT_GLYPHLESS)
+ goto done;
+ /* Don't display this character. */
+ set_iterator_to_next (it, 0);
+ goto get_next;
+ }
+
if (! ASCII_CHAR_P (c) && ! NILP (Vnobreak_char_display))
nbsp_or_shy = (c == 0xA0 ? char_is_nbsp
: c == 0xAD ? char_is_soft_hyphen
@@ -6032,6 +6111,7 @@
}
#endif
+ done:
/* Is this character the last one of a run of characters with
box? If yes, set IT->end_of_box_run_p to 1. */
if (it->face_box_p
@@ -11579,6 +11659,8 @@
reconsider_clip_changes (w, current_buffer);
last_escape_glyph_frame = NULL;
last_escape_glyph_face_id = (1 << FACE_ID_BITS);
+ last_glyphless_glyph_frame = NULL;
+ last_glyphless_glyph_face_id = (1 << FACE_ID_BITS);
/* If new fonts have been loaded that make a glyph matrix adjustment
necessary, do it. */
@@ -20657,6 +20739,42 @@
}
+/* Fill glyph string S from a sequence glyphs for glyphless characters.
+ See the comment of fill_glyph_string for arguments.
+ Value is the index of the first glyph not in S. */
+
+
+static int
+fill_glyphless_glyph_string (struct glyph_string *s, int face_id,
+ int start, int end, int overlaps)
+{
+ struct glyph *glyph, *last;
+ int voffset;
+
+ xassert (s->first_glyph->type == GLYPHLESS_GLYPH);
+ s->for_overlaps = overlaps;
+ glyph = s->row->glyphs[s->area] + start;
+ last = s->row->glyphs[s->area] + end;
+ voffset = glyph->voffset;
+ s->face = FACE_FROM_ID (s->f, face_id);
+ s->font = s->face->font;
+ s->nchars = 1;
+ s->width = glyph->pixel_width;
+ glyph++;
+ while (glyph < last
+ && glyph->type == GLYPHLESS_GLYPH
+ && glyph->voffset == voffset
+ && glyph->face_id == face_id)
+ {
+ s->nchars++;
+ s->width += glyph->pixel_width;
+ glyph++;
+ }
+ s->ybase += voffset;
+ return glyph - s->row->glyphs[s->area];
+}
+
+
/* Fill glyph string S from a sequence of character glyphs.
FACE_ID is the face id of the string. START is the index of the
@@ -21167,6 +21285,28 @@
} while (0)
+/* Add a glyph string for a sequence of glyphless character's glyphs
+ to the list of strings between HEAD and TAIL. The meanings of
+ arguments are the same as those of BUILD_CHAR_GLYPH_STRINGS. */
+
+#define BUILD_GLYPHLESS_GLYPH_STRING(START, END, HEAD, TAIL, HL, X, LAST_X) \
+ do \
+ { \
+ int face_id; \
+ XChar2b *char2b; \
+ \
+ face_id = (row)->glyphs[area][START].face_id; \
+ \
+ s = (struct glyph_string *) alloca (sizeof *s); \
+ INIT_GLYPH_STRING (s, NULL, w, row, area, START, HL); \
+ append_glyph_string (&HEAD, &TAIL, s); \
+ s->x = (X); \
+ START = fill_glyphless_glyph_string (s, face_id, START, END, \
+ overlaps); \
+ } \
+ while (0)
+
+
/* Build a list of glyph strings between HEAD and TAIL for the glyphs
of AREA of glyph row ROW on window W between indices START and END.
HL overrides the face for drawing glyph strings, e.g. it is
@@ -21190,7 +21330,7 @@
BUILD_CHAR_GLYPH_STRINGS (START, END, HEAD, TAIL, \
HL, X, LAST_X); \
break; \
- \
+ \
case COMPOSITE_GLYPH: \
if (first_glyph->u.cmp.automatic) \
BUILD_GSTRING_GLYPH_STRING (START, END, HEAD, TAIL, \
@@ -21199,21 +21339,26 @@
BUILD_COMPOSITE_GLYPH_STRING (START, END, HEAD, TAIL, \
HL, X, LAST_X); \
break; \
- \
+ \
case STRETCH_GLYPH: \
BUILD_STRETCH_GLYPH_STRING (START, END, HEAD, TAIL, \
HL, X, LAST_X); \
break; \
- \
+ \
case IMAGE_GLYPH: \
BUILD_IMAGE_GLYPH_STRING (START, END, HEAD, TAIL, \
HL, X, LAST_X); \
break; \
- \
+ \
+ case GLYPHLESS_GLYPH: \
+ BUILD_GLYPHLESS_GLYPH_STRING (START, END, HEAD, TAIL, \
+ HL, X, LAST_X); \
+ break; \
+ \
default: \
abort (); \
} \
- \
+ \
if (s) \
{ \
set_glyph_string_background_width (s, START, LAST_X); \
@@ -22109,6 +22254,229 @@
}
+/* Append a glyph for a glyphless character to IT->glyph_row. FACE_ID
+ is a face ID to be used for the glyph. FOR_NO_FONT is nonzero if
+ and only if this is for a character for which no font was found.
+
+ If the display method (it->glyphless_method) is
+ GLYPHLESS_DISPLAY_ACRONYM or GLYPHLESS_DISPLAY_HEXA_CODE, LEN is a
+ length of the acronym or the hexadecimal string, UPPER_XOFF and
+ UPPER_YOFF are pixel offsets for the upper part of the string,
+ LOWER_XOFF and LOWER_YOFF are for the lower part.
+
+ For the other display methods, LEN through LOWER_YOFF are zero. */
+
+static void
+append_glyphless_glyph (struct it *it, int face_id, int for_no_font, int len,
+ short upper_xoff, short upper_yoff,
+ short lower_xoff, short lower_yoff)
+{
+ struct glyph *glyph;
+ enum glyph_row_area area = it->area;
+
+ glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
+ if (glyph < it->glyph_row->glyphs[area + 1])
+ {
+ /* If the glyph row is reversed, we need to prepend the glyph
+ rather than append it. */
+ if (it->glyph_row->reversed_p && area == TEXT_AREA)
+ {
+ struct glyph *g;
+
+ /* Make room for the additional glyph. */
+ for (g = glyph - 1; g >= it->glyph_row->glyphs[area]; g--)
+ g[1] = *g;
+ glyph = it->glyph_row->glyphs[area];
+ }
+ glyph->charpos = CHARPOS (it->position);
+ glyph->object = it->object;
+ glyph->pixel_width = it->pixel_width;
+ glyph->ascent = it->ascent;
+ glyph->descent = it->descent;
+ glyph->voffset = it->voffset;
+ glyph->type = GLYPHLESS_GLYPH;
+ glyph->u.glyphless.method = it->glyphless_method;
+ glyph->u.glyphless.for_no_font = for_no_font;
+ glyph->u.glyphless.len = len;
+ glyph->u.glyphless.ch = it->c;
+ glyph->slice.glyphless.upper_xoff = upper_xoff;
+ glyph->slice.glyphless.upper_yoff = upper_yoff;
+ glyph->slice.glyphless.lower_xoff = lower_xoff;
+ glyph->slice.glyphless.lower_yoff = lower_yoff;
+ glyph->avoid_cursor_p = it->avoid_cursor_p;
+ glyph->multibyte_p = it->multibyte_p;
+ glyph->left_box_line_p = it->start_of_box_run_p;
+ glyph->right_box_line_p = it->end_of_box_run_p;
+ glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent
+ || it->phys_descent > it->descent);
+ glyph->padding_p = 0;
+ glyph->glyph_not_available_p = 0;
+ glyph->face_id = face_id;
+ glyph->font_type = FONT_TYPE_UNKNOWN;
+ if (it->bidi_p)
+ {
+ glyph->resolved_level = it->bidi_it.resolved_level;
+ if ((it->bidi_it.type & 7) != it->bidi_it.type)
+ abort ();
+ glyph->bidi_type = it->bidi_it.type;
+ }
+ ++it->glyph_row->used[area];
+ }
+ else
+ IT_EXPAND_MATRIX_WIDTH (it, area);
+}
+
+
+/* Produce a glyph for a glyphless character for iterator IT.
+ IT->glyphless_method specifies which method to use for displaying
+ the character. See the description of enum
+ glyphless_display_method in dispextern.h for the detail.
+
+ FOR_NO_FONT is nonzero if and only if this is for a character for
+ which no font was found. ACRONYM, if non-nil, is an acronym string
+ for the character. */
+
+static void
+produce_glyphless_glyph (struct it *it, int for_no_font, Lisp_Object acronym)
+{
+ int face_id;
+ struct face *face;
+ struct font *font;
+ int base_width, base_height, width, height;
+ short upper_xoff, upper_yoff, lower_xoff, lower_yoff;
+ int len;
+
+ /* Get the metrics of the base font. We always refer to the current
+ ASCII face. */
+ face = FACE_FROM_ID (it->f, it->face_id)->ascii_face;
+ font = face->font ? face->font : FRAME_FONT (it->f);
+ it->ascent = FONT_BASE (font) + font->baseline_offset;
+ it->descent = FONT_DESCENT (font) - font->baseline_offset;
+ base_height = it->ascent + it->descent;
+ base_width = font->average_width;
+
+ /* Get a face ID for the glyph by utilizing a cache (the same way as
+ doen for `escape-glyph' in get_next_display_element). */
+ if (it->f == last_glyphless_glyph_frame
+ && it->face_id == last_glyphless_glyph_face_id)
+ {
+ face_id = last_glyphless_glyph_merged_face_id;
+ }
+ else
+ {
+ /* Merge the `glyphless-char' face into the current face. */
+ face_id = merge_faces (it->f, Qglyphless_char, 0, it->face_id);
+ last_glyphless_glyph_frame = it->f;
+ last_glyphless_glyph_face_id = it->face_id;
+ last_glyphless_glyph_merged_face_id = face_id;
+ }
+
+ if (it->glyphless_method == GLYPHLESS_DISPLAY_THIN_SPACE)
+ {
+ it->pixel_width = THIN_SPACE_WIDTH;
+ len = 0;
+ upper_xoff = upper_yoff = lower_xoff = lower_yoff = 0;
+ }
+ else if (it->glyphless_method == GLYPHLESS_DISPLAY_EMPTY_BOX)
+ {
+ width = CHAR_WIDTH (it->c);
+ if (width == 0)
+ width = 1;
+ else if (width > 4)
+ width = 4;
+ it->pixel_width = base_width * width;
+ len = 0;
+ upper_xoff = upper_yoff = lower_xoff = lower_yoff = 0;
+ }
+ else
+ {
+ char buf[7], *str;
+ unsigned int code[6];
+ int upper_len;
+ int ascent, descent;
+ struct font_metrics metrics_upper, metrics_lower;
+
+ face = FACE_FROM_ID (it->f, face_id);
+ font = face->font ? face->font : FRAME_FONT (it->f);
+ PREPARE_FACE_FOR_DISPLAY (it->f, face);
+
+ if (it->glyphless_method == GLYPHLESS_DISPLAY_ACRONYM)
+ {
+ if (! STRINGP (acronym) && CHAR_TABLE_P (Vglyphless_char_display))
+ acronym = CHAR_TABLE_REF (Vglyphless_char_display, it->c);
+ str = STRINGP (acronym) ? (char *) SDATA (acronym) : "";
+ }
+ else
+ {
+ xassert (it->glyphless_method == GLYPHLESS_DISPLAY_HEXA_CODE);
+ sprintf (buf, "%0*X", it->c < 0x10000 ? 4 : 6, it->c);
+ str = buf;
+ }
+ for (len = 0; str[len] && ASCII_BYTE_P (str[len]); len++)
+ code[len] = font->driver->encode_char (font, str[len]);
+ upper_len = (len + 1) / 2;
+ font->driver->text_extents (font, code, upper_len,
+ &metrics_upper);
+ font->driver->text_extents (font, code + upper_len, len - upper_len,
+ &metrics_lower);
+
+
+
+ /* +4 is for vertical bars of a box plus 1-pixel spaces at both side. */
+ width = max (metrics_upper.width, metrics_lower.width) + 4;
+ upper_xoff = upper_yoff = 2; /* the typical case */
+ if (base_width >= width)
+ {
+ /* Align the upper to the left, the lower to the right. */
+ it->pixel_width = base_width;
+ lower_xoff = base_width - 2 - metrics_lower.width;
+ }
+ else
+ {
+ /* Center the shorter one. */
+ it->pixel_width = width;
+ if (metrics_upper.width >= metrics_lower.width)
+ lower_xoff = (width - metrics_lower.width) / 2;
+ else
+ upper_xoff = (width - metrics_upper.width) / 2;
+ }
+
+ /* +5 is for horizontal bars of a box plus 1-pixel spaces at
+ top, bottom, and between upper and lower strings. */
+ height = (metrics_upper.ascent + metrics_upper.descent
+ + metrics_lower.ascent + metrics_lower.descent) + 5;
+ /* Center vertically.
+ H:base_height, D:base_descent
+ h:height, ld:lower_descent, la:lower_ascent, ud:upper_descent
+
+ ascent = - (D - H/2 - h/2 + 1); "+ 1" for rounding up
+ descent = D - H/2 + h/2;
+ lower_yoff = descent - 2 - ld;
+ upper_yoff = lower_yoff - la - 1 - ud; */
+ ascent = - (it->descent - (base_height + height + 1) / 2);
+ descent = it->descent - (base_height - height) / 2;
+ lower_yoff = descent - 2 - metrics_lower.descent;
+ upper_yoff = (lower_yoff - metrics_lower.ascent - 1
+ - metrics_upper.descent);
+ /* Don't make the height shorter than the base height. */
+ if (height > base_height)
+ {
+ it->ascent = ascent;
+ it->descent = descent;
+ }
+ }
+
+ it->phys_ascent = it->ascent;
+ it->phys_descent = it->descent;
+ if (it->glyph_row)
+ append_glyphless_glyph (it, face_id, for_no_font, len,
+ upper_xoff, upper_yoff,
+ lower_xoff, lower_yoff);
+ it->nglyphs = 1;
+ take_vertical_position_into_account (it);
+}
+
+
/* RIF:
Produce glyphs/get display metrics for the display element IT is
loaded with. See the description of struct it in dispextern.h
@@ -22126,28 +22494,24 @@
XChar2b char2b;
struct face *face = FACE_FROM_ID (it->f, it->face_id);
struct font *font = face->font;
- int font_not_found_p = font == NULL;
struct font_metrics *pcm = NULL;
int boff; /* baseline offset */
- if (font_not_found_p)
- {
- /* When no suitable font found, display an empty box based
- on the metrics of the font of the default face (or what
- remapped). */
- struct face *no_font_face
- = FACE_FROM_ID (it->f,
- NILP (Vface_remapping_alist) ? DEFAULT_FACE_ID
- : lookup_basic_face (it->f, DEFAULT_FACE_ID));
- font = no_font_face->font;
- boff = font->baseline_offset;
- }
- else
- {
- boff = font->baseline_offset;
- if (font->vertical_centering)
- boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
- }
+ if (font == NULL)
+ {
+ /* When no suitable font is found, display this character by
+ the method specified in the first extra slot of
+ Vglyphless_char_display. */
+ Lisp_Object acronym = lookup_glyphless_char_display (-1, it);
+
+ xassert (it->what == IT_GLYPHLESS);
+ produce_glyphless_glyph (it, 1, STRINGP (acronym) ? acronym : Qnil);
+ goto done;
+ }
+
+ boff = font->baseline_offset;
+ if (font->vertical_centering)
+ boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
if (it->char_to_display != '\n' && it->char_to_display != '\t')
{
@@ -22167,8 +22531,7 @@
it->descent = FONT_DESCENT (font) - boff;
}
- if (! font_not_found_p
- && get_char_glyph_code (it->char_to_display, font, &char2b))
+ if (get_char_glyph_code (it->char_to_display, font, &char2b))
{
pcm = get_per_char_metric (it->f, font, &char2b);
if (pcm->width == 0
@@ -22758,11 +23121,14 @@
if (it->glyph_row)
append_composite_glyph (it);
}
+ else if (it->what == IT_GLYPHLESS)
+ produce_glyphless_glyph (it, 0, Qnil);
else if (it->what == IT_IMAGE)
produce_image_glyph (it);
else if (it->what == IT_STRETCH)
produce_stretch_glyph (it);
+ done:
/* Accumulate dimensions. Note: can't assume that it->descent > 0
because this isn't true for images with `:ascent 100'. */
xassert (it->ascent >= 0 && it->descent >= 0);
@@ -26592,6 +26958,35 @@
hourglass_atimer = NULL;
hourglass_shown_p = 0;
+
+ DEFSYM (Qglyphless_char, "glyphless-char");
+ DEFSYM (Qhexa_code, "hexa-code");
+ DEFSYM (Qempty_box, "empty-box");
+ DEFSYM (Qthin_space, "thin-space");
+ DEFSYM (Qzero_width, "zero-width");
+
+ DEFSYM (Qglyphless_char_display, "glyphless-char-display");
+ /* Intern this now in case it isn't already done.
+ Setting this variable twice is harmless.
+ But don't staticpro it here--that is done in alloc.c. */
+ Qchar_table_extra_slots = intern_c_string ("char-table-extra-slots");
+ Fput (Qglyphless_char_display, Qchar_table_extra_slots, make_number (1));
+
+ DEFVAR_LISP ("glyphless-char-display", &Vglyphless_char_display,
+ doc: /* Char-table to control displaying of glyphless characters.
+Each element, if non-nil, is an ASCII acronym string (displayed in a box)
+or one of these symbols:
+ hexa-code: display with hexadecimal character code in a box
+ empty-box: display with an empty box
+ thin-space: display with 1-pixel width space
+ zero-width: don't display
+
+It has one extra slot to control the display of a character for which
+no font is found. The value of the slot is `hexa-code' or `empty-box'.
+The default is `empty-box'. */);
+ Vglyphless_char_display = Fmake_char_table (Qglyphless_char_display, Qnil);
+ Fset_char_table_extra_slot (Vglyphless_char_display, make_number (0),
+ Qempty_box);
}
=== modified file 'src/xterm.c'
--- a/src/xterm.c 2010-10-31 22:35:44 +0000
+++ b/src/xterm.c 2010-11-01 07:53:08 +0000
@@ -1330,6 +1330,83 @@
}
+/* Draw the foreground of glyph string S for glyphless characters. */
+
+static void
+x_draw_glyphless_glyph_string_foreground (struct glyph_string *s)
+{
+ struct glyph *glyph = s->first_glyph;
+ XChar2b char2b[8];
+ int x, i, j;
+
+ /* If first glyph of S has a left box line, start drawing the text
+ of S to the right of that box line. */
+ if (s->face && s->face->box != FACE_NO_BOX
+ && s->first_glyph->left_box_line_p)
+ x = s->x + eabs (s->face->box_line_width);
+ else
+ x = s->x;
+
+ s->char2b = char2b;
+
+ for (i = 0; i < s->nchars; i++, glyph++)
+ {
+ char buf[7], *str = NULL;
+ int len = glyph->u.glyphless.len;
+
+ if (glyph->u.glyphless.method == GLYPHLESS_DISPLAY_ACRONYM)
+ {
+ if (len > 0
+ && CHAR_TABLE_P (Vglyphless_char_display)
+ && (CHAR_TABLE_EXTRA_SLOTS (XCHAR_TABLE (Vglyphless_char_display))
+ >= 1))
+ {
+ Lisp_Object acronym
+ = (! glyph->u.glyphless.for_no_font
+ ? CHAR_TABLE_REF (Vglyphless_char_display,
+ glyph->u.glyphless.ch)
+ : XCHAR_TABLE (Vglyphless_char_display)->extras[0]);
+ if (STRINGP (acronym))
+ str = (char *) SDATA (acronym);
+ }
+ }
+ else if (glyph->u.glyphless.method == GLYPHLESS_DISPLAY_HEXA_CODE)
+ {
+ sprintf ((char *) buf, "%0*X",
+ glyph->u.glyphless.ch < 0x10000 ? 4 : 6,
+ glyph->u.glyphless.ch);
+ str = buf;
+ }
+
+ if (str)
+ {
+ int upper_len = (len + 1) / 2;
+ unsigned code;
+
+ /* It is assured that all LEN characters in STR is ASCII. */
+ for (j = 0; j < len; j++)
+ {
+ code = s->font->driver->encode_char (s->font, str[j]);
+ STORE_XCHAR2B (char2b + j, code >> 8, code & 0xFF);
+ }
+ s->font->driver->draw (s, 0, upper_len,
+ x + glyph->slice.glyphless.upper_xoff,
+ s->ybase + glyph->slice.glyphless.upper_yoff,
+ 0);
+ s->font->driver->draw (s, upper_len, len,
+ x + glyph->slice.glyphless.lower_xoff,
+ s->ybase + glyph->slice.glyphless.lower_yoff,
+ 0);
+ }
+ if (glyph->u.glyphless.method != GLYPHLESS_DISPLAY_THIN_SPACE)
+ XDrawRectangle (s->display, s->window, s->gc,
+ x, s->ybase - glyph->ascent,
+ glyph->pixel_width - 1,
+ glyph->ascent + glyph->descent - 1);
+ x += glyph->pixel_width;
+ }
+}
+
#ifdef USE_X_TOOLKIT
static struct frame *x_frame_of_widget (Widget);
@@ -2656,6 +2733,14 @@
x_draw_composite_glyph_string_foreground (s);
break;
+ case GLYPHLESS_GLYPH:
+ if (s->for_overlaps)
+ s->background_filled_p = 1;
+ else
+ x_draw_glyph_string_background (s, 1);
+ x_draw_glyphless_glyph_string_foreground (s);
+ break;
+
default:
abort ();
}
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Emacs-diffs] /srv/bzr/emacs/trunk r102210: Implement various display methods for glyphless characters.,
Kenichi Handa <=