Commit dc43ef94 authored by Karl Heuer's avatar Karl Heuer

Include charset.h, ccl.h, and fontset.h.

(PER_CHAR_METRIC): New macro.
(dumpglyphs): New argument CMPCHARP.  Handle multibyte characters.
(XTwrite_glyphs, redraw_previous_char, redraw_following_char):
Supply argument CMPCHARP to dumpglyphs.
(dumprectangle): Display whole glyph of wide-column characters.
Supply argument CMPCHARP to dumpglyphs.
(show_mouse_face): Supply argument CMPCHARP to dumpglyphs.
(x_draw_box): Pay attention to wide-column characters.
(x_draw_single_glyph): Supply argument CMPCHARP to dumpglyphs.
(x_new_font): Call fs_load_font for actual font loading work.
(x_new_fontset): New function.
(x_get_font_info, x_list_fonts, x_load_font, x_query_font): New
functions providing API to fontset handler.
(x_term_init): Initialize several new members of struct x_display_info.
parent e6c7c988
......@@ -68,6 +68,9 @@ Boston, MA 02111-1307, USA. */
/* Caused redefinition of DBL_DIG on Netbsd; seems not to be needed. */
/* #include <sys/param.h> */
#include "charset.h"
#include "ccl.h"
#include "fontset.h"
#include "frame.h"
#include "dispextern.h"
#include "termhooks.h"
......@@ -490,6 +493,19 @@ XTcursor_to (row, col)
}
}
/* Return a pointer to per char metric information in FONT of a
character pointed by B (*XChar2b). */
#define PER_CHAR_METRIC(font, b) \
((font)->per_char \
? ((font)->per_char + (b)->byte2 - (font)->min_char_or_byte2 \
+ (((font)->min_byte1 || (font)->max_byte1) \
? (((b)->byte1 - (font)->min_byte1) \
* ((font)->max_char_or_byte2 - (font)->min_char_or_byte2 + 1)) \
: 0)) \
: &((font)->max_bounds))
/* Display a sequence of N glyphs found at GP.
WINDOW is the x-window to output to. LEFT and TOP are starting coords.
HL is 1 if this text is highlighted, 2 if the cursor is on it,
......@@ -497,6 +513,11 @@ XTcursor_to (row, col)
JUST_FOREGROUND if 1 means draw only the foreground;
don't alter the background.
CMPCHARP if non NULL is a pointer to the struct cmpchar_info, which
means drawing glyphs on the same column. This is set to non NULL
only when recursively called within dumpglyphs to draw a composite
character specified by CMPCHAR.
FONT is the default font to use (for glyphs whose font-code is 0).
Since the display generation code is responsible for calling
......@@ -504,62 +525,122 @@ XTcursor_to (row, col)
the display structure, we can assume that the face code on each
glyph is a valid index into FRAME_COMPUTED_FACES (f), and the one
to which we can actually apply intern_face.
Call this function with input blocked. */
Call this function with input blocked.
Return overall pixel width of the drawn glyphs. */
#if 1
/* This is the multi-face code. */
static void
dumpglyphs (f, left, top, gp, n, hl, just_foreground)
static int
dumpglyphs (f, left, top, gp, n, hl, just_foreground, cmpcharp)
struct frame *f;
int left, top;
register GLYPH *gp; /* Points to first GLYPH. */
register int n; /* Number of glyphs to display. */
int hl;
int just_foreground;
struct cmpchar_info *cmpcharp;
{
/* Holds characters to be displayed. */
char *buf = (char *) alloca (FRAME_WINDOW_WIDTH (f) * sizeof (*buf));
register char *cp; /* Steps through buf[]. */
XChar2b *buf = (XChar2b *) alloca (FRAME_WINDOW_WIDTH (f) * sizeof (*buf));
register XChar2b *cp; /* Steps through buf[]. */
register int tlen = GLYPH_TABLE_LENGTH;
register Lisp_Object *tbase = GLYPH_TABLE_BASE;
Window window = FRAME_X_WINDOW (f);
int orig_left = left;
int gidx = 0;
int pixel_width;
while (n > 0)
{
/* Get the face-code of the next GLYPH. */
int cf, len;
GLYPH g = *gp;
int ch, charset;
/* HIGHEST and LOWEST are used while drawing a composite
character. The meanings are described later. */
int highest, lowest;
GLYPH_FOLLOW_ALIASES (tbase, tlen, g);
cf = FAST_GLYPH_FACE (g);
cf = (cmpcharp ? cmpcharp->face_work : FAST_GLYPH_FACE (g));
ch = FAST_GLYPH_CHAR (g);
charset = CHAR_CHARSET (ch);
if (charset == CHARSET_COMPOSITION)
{
/* We must draw components of the composite character on the
same column. */
cmpcharp = cmpchar_table[COMPOSITE_CHAR_ID (ch)];
/* Set the face in the slot for work. */
cmpcharp->face_work = cf;
/* We don't need the return value ... */
dumpglyphs (f, left, top, cmpcharp->glyph, cmpcharp->glyph_len,
hl, just_foreground, cmpcharp);
/* ... because the width of just drawn text can be
calculated as follows. */
left += FONT_WIDTH (f->output_data.x->font) * cmpcharp->width;
++gp, --n;
while (gp && (*gp & GLYPH_MASK_PADDING)) ++gp, --n;
cmpcharp = NULL;
continue;
}
/* Find the run of consecutive glyphs with the same face-code.
Extract their character codes into BUF. */
/* Find the run of consecutive glyphs which can be drawn with
the same GC (i.e. the same charset and the same face-code).
Extract their character codes into BUF.
If CMPCHARP is not NULL, face-code is not checked because we
use only the face specified in `cmpcharp->face_work'. */
cp = buf;
while (n > 0)
{
int this_charset, c1, c2;
g = *gp;
GLYPH_FOLLOW_ALIASES (tbase, tlen, g);
if (FAST_GLYPH_FACE (g) != cf)
ch = FAST_GLYPH_CHAR (g);
SPLIT_CHAR (ch, this_charset, c1, c2);
if (this_charset != charset
|| (cmpcharp == NULL && FAST_GLYPH_FACE (g) != cf))
break;
*cp++ = FAST_GLYPH_CHAR (g);
--n;
++gp;
if (c2)
cp->byte1 = c1, cp->byte2 = c2;
else
cp->byte1 = 0, cp->byte2 = c1;
++cp;
++gp, --n;
while (gp && (*gp & GLYPH_MASK_PADDING))
++gp, --n;
}
/* LEN gets the length of the run. */
len = cp - buf;
/* PIXEL_WIDTH get the pixcel width of the run. */
pixel_width
= (FONT_WIDTH (f->output_data.x->font)
* (cmpcharp ? cmpcharp->width : len * CHARSET_WIDTH (charset)));
/* Now output this run of chars, with the font and pixel values
determined by the face code CF. */
{
struct face *face = FRAME_DEFAULT_FACE (f);
XFontStruct *font = FACE_FONT (face);
GC gc = FACE_GC (face);
XFontStruct *font = NULL;
GC gc;
int stippled = 0;
/* A flag to tell if we have already filled background. We
fill background in advance in the following cases:
1) A face has stipple.
2) A height of font is different from that of the current line.
3) Drawing a composite character.
After filling background, we draw glyphs by XDrawString16. */
int background_filled;
/* Baseline position of a character, offset from TOP. */
int baseline;
/* The property value of `_MULE_RELATIVE_COMPOSE'. */
int relative_compose = 0;
/* HL = 3 means use a mouse face previously chosen. */
if (hl == 3)
......@@ -578,8 +659,6 @@ dumpglyphs (f, left, top, gp, n, hl, just_foreground)
face = FRAME_MODE_LINE_FACE (f);
else
face = intern_face (f, FRAME_COMPUTED_FACES (f) [cf]);
font = FACE_FONT (face);
gc = FACE_GC (face);
if (FACE_STIPPLE (face))
stippled = 1;
}
......@@ -590,12 +669,78 @@ dumpglyphs (f, left, top, gp, n, hl, just_foreground)
else if (hl == 1)
{
face = FRAME_MODE_LINE_FACE (f);
font = FACE_FONT (face);
gc = FACE_GC (face);
if (FACE_STIPPLE (face))
stippled = 1;
}
/* Setting appropriate font and gc for this charset. */
if (charset != CHARSET_ASCII)
{
int font_id;
int fontset = FACE_FONTSET (face);
struct font_info *fontp;
if ((fontset < 0 && (fontset = FRAME_FONTSET (f)) < 0)
|| !(fontp = fs_load_font (f, FRAME_X_FONT_TABLE (f),
charset, NULL, fontset)))
goto font_not_found;
font = (XFontStruct *) (fontp->font);
gc = FACE_NON_ASCII_GC (face);
XSetFont (FRAME_X_DISPLAY (f), gc, font->fid);
if (font->max_byte1 != 0)
baseline = (f->output_data.x->line_height
+ font->ascent - font->descent) / 2;
else
baseline = (f->output_data.x->font_baseline
- fontp->baseline_offset);
if (cmpcharp && cmpcharp->cmp_rule == NULL)
relative_compose = fontp->relative_compose;
/* We have to change code points in the following cases. */
if (fontp->font_encoder)
{
/* This font requires CCL program to calculate code
point of characters. */
struct ccl_program *ccl = fontp->font_encoder;
if (CHARSET_DIMENSION (charset) == 1)
for (cp = buf; cp < buf + len; cp++)
{
ccl->reg[0] = charset;
ccl->reg[1] = cp->byte2;
ccl_driver (ccl, NULL, NULL, 0, 0, NULL);
cp->byte2 = ccl->reg[1];
}
else
for (cp = buf; cp < buf + len; cp++)
{
ccl->reg[0] = charset;
ccl->reg[1] = cp->byte1, ccl->reg[2] = cp->byte2;
ccl_driver (ccl, NULL, NULL, 0, 0, NULL);
cp->byte1 = ccl->reg[1], cp->byte2 = ccl->reg[2];
}
}
else if (fontp->encoding[charset])
{
int enc = fontp->encoding[charset];
if ((enc == 1 || enc == 2) && CHARSET_DIMENSION (charset) == 2)
for (cp = buf; cp < buf + len; cp++)
cp->byte1 |= 0x80;
if (enc == 1 || enc == 3)
for (cp = buf; cp < buf + len; cp++)
cp->byte2 |= 0x80;
}
}
else
{
font = FACE_FONT (face);
baseline = FONT_BASE (font);
font_not_found:
gc = FACE_GC (face);
}
#define FACE_DEFAULT (~0)
/* Now override that if the cursor's on this character. */
......@@ -604,9 +749,10 @@ dumpglyphs (f, left, top, gp, n, hl, just_foreground)
/* The cursor overrides stippling. */
stippled = 0;
if ((!face->font
|| face->font == (XFontStruct *) FACE_DEFAULT
|| face->font == f->output_data.x->font)
if (!cmpcharp
&& (!font
|| font == (XFontStruct *) FACE_DEFAULT
|| font == f->output_data.x->font)
&& face->background == f->output_data.x->background_pixel
&& face->foreground == f->output_data.x->foreground_pixel)
{
......@@ -635,7 +781,10 @@ dumpglyphs (f, left, top, gp, n, hl, just_foreground)
xgcv.background = face->foreground;
xgcv.foreground = face->background;
}
xgcv.font = face->font->fid;
if (font)
xgcv.font = font->fid;
else
xgcv.font = FACE_FONT (face)->fid;
xgcv.graphics_exposures = 0;
mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
if (FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc)
......@@ -658,35 +807,130 @@ dumpglyphs (f, left, top, gp, n, hl, just_foreground)
if (font == (XFontStruct *) FACE_DEFAULT)
font = f->output_data.x->font;
if (just_foreground)
XDrawString (FRAME_X_DISPLAY (f), window, gc,
left, top + FONT_BASE (font), buf, len);
if (font && (just_foreground || (cmpcharp && gidx > 0)))
background_filled = 1;
else if (!font
|| stippled
|| f->output_data.x->line_height != FONT_HEIGHT (font)
|| cmpcharp)
{
if (!stippled)
/* This is to fill a rectangle with background color. */
XSetStipple (FRAME_X_DISPLAY (f), gc,
FRAME_X_DISPLAY_INFO (f)->null_pixel);
/* Turn stipple on. */
XSetFillStyle (FRAME_X_DISPLAY (f), gc, FillOpaqueStippled);
/* Draw stipple or background color on background. */
XFillRectangle (FRAME_X_DISPLAY (f), window, gc,
left, top, pixel_width,
f->output_data.x->line_height);
/* Turn stipple off. */
XSetFillStyle (FRAME_X_DISPLAY (f), gc, FillSolid);
background_filled = 1;
if (cmpcharp)
/* To assure not to fill background while drawing
remaining components. */
just_foreground = 1;
}
else
background_filled = 0;
if (font)
{
if (stippled)
if (cmpcharp)
{
/* Turn stipple on. */
XSetFillStyle (FRAME_X_DISPLAY (f), gc, FillOpaqueStippled);
XCharStruct *pcm; /* Pointer to per char metric info. */
int i;
/* Draw stipple on background. */
XFillRectangle (FRAME_X_DISPLAY (f), window, gc,
left, top,
FONT_WIDTH (font) * len,
FONT_HEIGHT (font));
if ((cmpcharp->cmp_rule || relative_compose)
&& gidx == 0)
{
/* This is the first character. Initialize variables.
HIGHEST is the highest position of glyphs ever
written, LOWEST the lowest position. */
int x_offset = 0;
pcm = PER_CHAR_METRIC (font, buf);
highest = pcm->ascent + 1;
lowest = - pcm->descent;
if (cmpcharp->cmp_rule)
x_offset = (cmpcharp->col_offset[0]
* FONT_WIDTH (f->output_data.x->font));
/* Draw the first character at the normal position. */
XDrawString16 (FRAME_X_DISPLAY (f), window, gc,
left + x_offset, top + baseline, buf, 1);
i = 1;
gidx++;
}
else
i = 0;
/* Turn stipple off. */
XSetFillStyle (FRAME_X_DISPLAY (f), gc, FillSolid);
for (; i < len; i++, gidx++)
{
int x_offset = 0, y_offset = 0;
/* Draw the text, solidly, onto the stipple pattern. */
XDrawString (FRAME_X_DISPLAY (f), window, gc,
left, top + FONT_BASE (font), buf, len);
if (relative_compose)
{
pcm = PER_CHAR_METRIC (font, buf + i);
if (- pcm->descent >= relative_compose)
{
/* Draw above the current glyphs. */
y_offset = highest + pcm->descent;
highest += pcm->ascent + pcm->descent;
}
else if (pcm->ascent <= 0)
{
/* Draw beneath the current glyphs. */
y_offset = lowest - pcm->ascent;
lowest -= pcm->ascent + pcm->descent;
}
}
else if (cmpcharp->cmp_rule)
{
int gref = (cmpcharp->cmp_rule[gidx] - 0xA0) / 9;
int nref = (cmpcharp->cmp_rule[gidx] - 0xA0) % 9;
int bottom, top;
/* Re-encode GREF and NREF so that they specify
only Y-axis information:
0:top, 1:base, 2:bottom, 3:center */
gref = gref / 3 + (gref == 4) * 2;
nref = nref / 3 + (nref == 4) * 2;
pcm = PER_CHAR_METRIC (font, buf + i);
bottom = ((gref == 0 ? highest : gref == 1 ? 0
: gref == 2 ? lowest
: (highest + lowest) / 2)
- (nref == 0 ? pcm->ascent + pcm->descent
: nref == 1 ? pcm->descent : nref == 2 ? 0
: (pcm->ascent + pcm->descent) / 2));
top = bottom + (pcm->ascent + pcm->descent);
if (top > highest)
highest = top;
if (bottom < lowest)
lowest = bottom;
y_offset = bottom + pcm->descent;
x_offset = (cmpcharp->col_offset[gidx]
* FONT_WIDTH (f->output_data.x->font));
}
XDrawString16 (FRAME_X_DISPLAY (f), window, gc,
left + x_offset, top + baseline - y_offset,
buf + i, 1);
}
}
else if (background_filled)
XDrawString16 (FRAME_X_DISPLAY (f), window, gc,
left, top + baseline, buf, len);
else
XDrawImageString (FRAME_X_DISPLAY (f), window, gc,
left, top + FONT_BASE (font), buf, len);
XDrawImageString16 (FRAME_X_DISPLAY (f), window, gc,
left, top + baseline, buf, len);
/* Clear the rest of the line's height. */
if (f->output_data.x->line_height != FONT_HEIGHT (font))
if (f->output_data.x->line_height > FONT_HEIGHT (font))
XClearArea (FRAME_X_DISPLAY (f), window, left,
top + FONT_HEIGHT (font),
FONT_WIDTH (font) * len,
......@@ -694,42 +938,70 @@ dumpglyphs (f, left, top, gp, n, hl, just_foreground)
we have to clear. */
f->output_data.x->line_height - FONT_HEIGHT (font),
False);
}
#if 0 /* Doesn't work, because it uses FRAME_CURRENT_GLYPHS,
which often is not up to date yet. */
if (!just_foreground)
if (!just_foreground)
{
if (left == orig_left)
redraw_previous_char (f, PIXEL_TO_CHAR_COL (f, left),
PIXEL_TO_CHAR_ROW (f, top), hl == 1);
if (n == 0)
redraw_following_char (f, PIXEL_TO_CHAR_COL (f, left + len * FONT_WIDTH (font)),
PIXEL_TO_CHAR_ROW (f, top), hl == 1);
}
#endif
}
else
{
if (left == orig_left)
redraw_previous_char (f, PIXEL_TO_CHAR_COL (f, left),
PIXEL_TO_CHAR_ROW (f, top), hl == 1);
if (n == 0)
redraw_following_char (f, PIXEL_TO_CHAR_COL (f, left + len * FONT_WIDTH (font)),
PIXEL_TO_CHAR_ROW (f, top), hl == 1);
/* There's no appropriate font for this glyph. Just show
rectangles. */
if (cmpcharp)
XDrawRectangle
(FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
left, top + 1,
pixel_width - 2, f->output_data.x->line_height - 3);
else
{
int left_offset;
int left_skip_step = (FONT_WIDTH (f->output_data.x->font)
* CHARSET_WIDTH (charset));
for (left_offset = 0; left_offset < pixel_width;
left_offset += left_skip_step)
XDrawRectangle
(FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
left + left_offset, top + 1,
left_skip_step - 2, f->output_data.x->line_height - 3);
}
}
#endif
/* We should probably check for XA_UNDERLINE_POSITION and
XA_UNDERLINE_THICKNESS properties on the font, but let's
just get the thing working, and come back to that. */
{
int underline_position = 1;
/* Setting underline position based on the metric of the
current font results in shaky underline if it strides
over different fonts. So, we set the position based only
on the default font of this frame. */
int underline_position = f->output_data.x->font_baseline + 1;
if (font->descent <= underline_position)
underline_position = font->descent - 1;
if (underline_position >= f->output_data.x->line_height)
underline_position = f->output_data.x->line_height - 1;
if (face->underline)
XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
FACE_GC (face),
left, (top
+ FONT_BASE (font)
+ underline_position),
len * FONT_WIDTH (font), 1);
left, top + underline_position, pixel_width, 1);
}
left += len * FONT_WIDTH (font);
if (!cmpcharp)
left += pixel_width;
}
}
return (left - orig_left);
}
#endif /* 1 */
......@@ -796,7 +1068,7 @@ XTwrite_glyphs (start, len)
dumpglyphs (f,
CHAR_TO_PIXEL_COL (f, curs_x),
CHAR_TO_PIXEL_ROW (f, curs_y),
start, len, highlight, 0);
start, len, highlight, 0, NULL);
/* If we drew on top of the cursor, note that it is turned off. */
if (curs_y == f->phys_cursor_y
......@@ -923,7 +1195,7 @@ redraw_previous_char (f, x, y, highlight_flag)
dumpglyphs (f, CHAR_TO_PIXEL_COL (f, start_x),
CHAR_TO_PIXEL_ROW (f, y),
&FRAME_CURRENT_GLYPHS (f)->glyphs[y][start_x],
x - start_x, highlight_flag, 1);
x - start_x, highlight_flag, 1, NULL);
}
}
......@@ -959,7 +1231,7 @@ redraw_following_char (f, x, y, highlight_flag)
dumpglyphs (f, CHAR_TO_PIXEL_COL (f, x),
CHAR_TO_PIXEL_ROW (f, y),
&FRAME_CURRENT_GLYPHS (f)->glyphs[y][x],
end_x - x, highlight_flag, 1);
end_x - x, highlight_flag, 1, NULL);
}
}
#endif /* 0 */
......@@ -1476,11 +1748,19 @@ dumprectangle (f, left, top, cols, rows)
if (! active_frame->enable[y] || left > active_frame->used[y])
continue;
while (*line & GLYPH_MASK_PADDING)
{
/* We must display the whole glyph of a wide-column
character. */
left--;
line--;
cols++;
}
dumpglyphs (f,
CHAR_TO_PIXEL_COL (f, left),
CHAR_TO_PIXEL_ROW (f, y),
line, min (cols, active_frame->used[y] - left),
active_frame->highlight[y], 0);
active_frame->highlight[y], 0, NULL);
}
/* Turn the cursor on if we turned it off. */
......@@ -2234,7 +2514,7 @@ show_mouse_face (dpyinfo, hl)
FRAME_CURRENT_GLYPHS (f)->glyphs[i] + column,
endcolumn - column,
/* Highlight with mouse face if hl > 0. */
hl > 0 ? 3 : 0, 0);
hl > 0 ? 3 : 0, 0, NULL);
}
/* If we turned the cursor off, turn it back on. */
......@@ -4254,7 +4534,13 @@ x_draw_box (f, x, y)
int top = CHAR_TO_PIXEL_ROW (f, y);
int width = FONT_WIDTH (f->output_data.x->font);
int height = f->output_data.x->line_height;
int c = FAST_GLYPH_CHAR (f->phys_cursor_glyph);
int charset = CHAR_CHARSET (c);
/* If cursor is on a multi-column character, multiply WIDTH by columns. */
width *= (charset == CHARSET_COMPOSITION
? cmpchar_table[COMPOSITE_CHAR_ID (c)]->width
: CHARSET_WIDTH (charset));
XDrawRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
f->output_data.x->cursor_gc,
left, top, width - 1, height - 1);
......@@ -4293,7 +4579,7 @@ x_draw_single_glyph (f, row, column, glyph, highlight)
dumpglyphs (f,
CHAR_TO_PIXEL_COL (f, column),
CHAR_TO_PIXEL_ROW (f, row),
&glyph, 1, highlight, 0);
&glyph, 1, highlight, 0, NULL);
}
static void
......@@ -4825,140 +5111,17 @@ x_new_font (f, fontname)
struct frame *f;
register char *fontname;
{
int already_loaded;
int n_matching_fonts;
XFontStruct *font_info;
char **font_names;
/* Get a list of all the fonts that match this name. Once we
have a list of matching fonts, we compare them against the fonts
we already have by comparing font ids. */
font_names = (char **) XListFonts (FRAME_X_DISPLAY (f), fontname,
1024, &n_matching_fonts);
/* Apparently it doesn't set n_matching_fonts to zero when it can't
find any matches; font_names == 0 is the only clue. */
if (! font_names)
n_matching_fonts = 0;
/* Don't just give up if n_matching_fonts is 0.
Apparently there's a bug on Suns: XListFontsWithInfo can
fail to find a font, but XLoadQueryFont may still find it. */
/* See if we've already loaded a matching font. */
already_loaded = -1;
if (n_matching_fonts != 0)
{
int i, j;
for (i = 0; i < FRAME_X_DISPLAY_INFO (f)->n_fonts; i++)
for (j = 0; j < n_matching_fonts; j++)
if (!strcmp (FRAME_X_DISPLAY_INFO (f)->font_table[i].name, font_names[j])
|| !strcmp (FRAME_X_DISPLAY_INFO (f)->font_table[i].full_name, font_names[j]))
{
already_loaded = i;
fontname = FRAME_X_DISPLAY_INFO (f)->font_table[i].full_name;
goto found_font;
}
}
found_font:
/* If we have, just return it from the table. */
if (already_loaded >= 0)
f->output_data.x->font = FRAME_X_DISPLAY_INFO (f)->font_table[already_loaded].font;
/* Otherwise, load the font and add it to the table. */
else
{
int i;