Commit 133c764e authored by Kim F. Storm's avatar Kim F. Storm
Browse files

Consolidate gui-independent "glyph string" code here.

(dump_glyph_string): Moved here.
(init_glyph_string, append_glyph_string_lists, append_glyph_string)
(prepend_glyph_string_lists, get_glyph_face_and_encoding)
(fill_composite_glyph_string, fill_glyph_string)
(fill_image_glyph_string, fill_stretch_glyph_string)
(left_overwritten, left_overwriting, right_overwritten)
(right_overwriting, get_char_face_and_encoding)
(set_glyph_string_background_width, compute_overhangs_and_x)
(append_glyph, append_composite_glyph, produce_image_glyph)
(take_vertical_position_into_account, append_stretch_glyph)
(produce_stretch_glyph): New generic functions (based on X version).
Call platform specific functions through rif.
(INIT_GLYPH_STRING): New macro, hides W32 details.
(BUILD_STRETCH_GLYPH_STRING, BUILD_IMAGE_GLYPH_STRING)
(BUILD_CHAR_GLYPH_STRINGS, BUILD_COMPOSITE_GLYPH_STRING)
(BUILD_GLYPH_STRINGS): Generic macros (based on X version).
(x_draw_glyphs, x_get_glyph_overhangs, x_produce_glyphs)
(notice_overwritten_cursor):
Generic functions exported to platform modules.  Users changed.
parent d5cc60b8
......@@ -280,6 +280,7 @@ Lisp_Object Qspace, QCalign_to, QCrelative_width, QCrelative_height;
Lisp_Object Qleft_margin, Qright_margin, Qspace_width, Qraise;
Lisp_Object Qmargin;
extern Lisp_Object Qheight;
extern Lisp_Object QCwidth, QCheight, QCascent;
 
/* Non-nil means highlight trailing whitespace. */
 
......@@ -15658,6 +15659,1996 @@ invisible_p (propval, list)
return 0;
}
 
/***********************************************************************
Glyph Display
***********************************************************************/
#if GLYPH_DEBUG
void
dump_glyph_string (s)
struct glyph_string *s;
{
fprintf (stderr, "glyph string\n");
fprintf (stderr, " x, y, w, h = %d, %d, %d, %d\n",
s->x, s->y, s->width, s->height);
fprintf (stderr, " ybase = %d\n", s->ybase);
fprintf (stderr, " hl = %d\n", s->hl);
fprintf (stderr, " left overhang = %d, right = %d\n",
s->left_overhang, s->right_overhang);
fprintf (stderr, " nchars = %d\n", s->nchars);
fprintf (stderr, " extends to end of line = %d\n",
s->extends_to_end_of_line_p);
fprintf (stderr, " font height = %d\n", FONT_HEIGHT (s->font));
fprintf (stderr, " bg width = %d\n", s->background_width);
}
#endif /* GLYPH_DEBUG */
/* Initialize glyph string S. CHAR2B is a suitably allocated vector
of XChar2b structures for S; it can't be allocated in
init_glyph_string because it must be allocated via `alloca'. W
is the window on which S is drawn. ROW and AREA are the glyph row
and area within the row from which S is constructed. START is the
index of the first glyph structure covered by S. HL is a
face-override for drawing S. */
#ifdef HAVE_NTGUI
#define OPTIONAL_HDC(hdc) hdc,
#define DECLARE_HDC(hdc) HDC hdc;
#define ALLOCATE_HDC(hdc, f) hdc = get_frame_dc ((f))
#define RELEASE_HDC(hdc, f) release_frame_dc ((f), (hdc))
#endif
#ifndef OPTIONAL_HDC
#define OPTIONAL_HDC(hdc)
#define DECLARE_HDC(hdc)
#define ALLOCATE_HDC(hdc, f)
#define RELEASE_HDC(hdc, f)
#endif
static void
init_glyph_string (s, OPTIONAL_HDC (hdc) char2b, w, row, area, start, hl)
struct glyph_string *s;
DECLARE_HDC (hdc)
XChar2b *char2b;
struct window *w;
struct glyph_row *row;
enum glyph_row_area area;
int start;
enum draw_glyphs_face hl;
{
bzero (s, sizeof *s);
s->w = w;
s->f = XFRAME (w->frame);
#ifdef HAVE_NTGUI
s->hdc = hdc;
#endif
s->display = FRAME_X_DISPLAY (s->f);
s->window = FRAME_X_WINDOW (s->f);
s->char2b = char2b;
s->hl = hl;
s->row = row;
s->area = area;
s->first_glyph = row->glyphs[area] + start;
s->height = row->height;
s->y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
/* Display the internal border below the tool-bar window. */
if (s->w == XWINDOW (s->f->tool_bar_window))
s->y -= FRAME_INTERNAL_BORDER_WIDTH (s->f);
s->ybase = s->y + row->ascent;
}
/* Append the list of glyph strings with head H and tail T to the list
with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the result. */
static INLINE void
append_glyph_string_lists (head, tail, h, t)
struct glyph_string **head, **tail;
struct glyph_string *h, *t;
{
if (h)
{
if (*head)
(*tail)->next = h;
else
*head = h;
h->prev = *tail;
*tail = t;
}
}
/* Prepend the list of glyph strings with head H and tail T to the
list with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the
result. */
static INLINE void
prepend_glyph_string_lists (head, tail, h, t)
struct glyph_string **head, **tail;
struct glyph_string *h, *t;
{
if (h)
{
if (*head)
(*head)->prev = t;
else
*tail = t;
t->next = *head;
*head = h;
}
}
/* Append glyph string S to the list with head *HEAD and tail *TAIL.
Set *HEAD and *TAIL to the resulting list. */
static INLINE void
append_glyph_string (head, tail, s)
struct glyph_string **head, **tail;
struct glyph_string *s;
{
s->next = s->prev = NULL;
append_glyph_string_lists (head, tail, s, s);
}
/* Get face and two-byte form of character glyph GLYPH on frame F.
The encoding of GLYPH->u.ch is returned in *CHAR2B. Value is
a pointer to a realized face that is ready for display. */
static INLINE struct face *
get_glyph_face_and_encoding (f, glyph, char2b, two_byte_p)
struct frame *f;
struct glyph *glyph;
XChar2b *char2b;
int *two_byte_p;
{
struct face *face;
xassert (glyph->type == CHAR_GLYPH);
face = FACE_FROM_ID (f, glyph->face_id);
if (two_byte_p)
*two_byte_p = 0;
if (!glyph->multibyte_p)
{
/* Unibyte case. We don't have to encode, but we have to make
sure to use a face suitable for unibyte. */
STORE_XCHAR2B (char2b, 0, glyph->u.ch);
}
else if (glyph->u.ch < 128
&& glyph->face_id < BASIC_FACE_ID_SENTINEL)
{
/* Case of ASCII in a face known to fit ASCII. */
STORE_XCHAR2B (char2b, 0, glyph->u.ch);
}
else
{
int c1, c2, charset;
/* Split characters into bytes. If c2 is -1 afterwards, C is
really a one-byte character so that byte1 is zero. */
SPLIT_CHAR (glyph->u.ch, charset, c1, c2);
if (c2 > 0)
STORE_XCHAR2B (char2b, c1, c2);
else
STORE_XCHAR2B (char2b, 0, c1);
/* Maybe encode the character in *CHAR2B. */
if (charset != CHARSET_ASCII)
{
struct font_info *font_info
= FONT_INFO_FROM_ID (f, face->font_info_id);
if (font_info)
glyph->font_type
= rif->encode_char (glyph->u.ch, char2b, font_info, two_byte_p);
}
}
/* Make sure X resources of the face are allocated. */
xassert (face != NULL);
PREPARE_FACE_FOR_DISPLAY (f, face);
return face;
}
/* Fill glyph string S with composition components specified by S->cmp.
FACES is an array of faces for all components of this composition.
S->gidx is the index of the first component for S.
OVERLAPS_P non-zero means S should draw the foreground only, and
use its physical height for clipping.
Value is the index of a component not in S. */
static int
fill_composite_glyph_string (s, faces, overlaps_p)
struct glyph_string *s;
struct face **faces;
int overlaps_p;
{
int i;
xassert (s);
s->for_overlaps_p = overlaps_p;
s->face = faces[s->gidx];
s->font = s->face->font;
s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
/* For all glyphs of this composition, starting at the offset
S->gidx, until we reach the end of the definition or encounter a
glyph that requires the different face, add it to S. */
++s->nchars;
for (i = s->gidx + 1; i < s->cmp->glyph_len && faces[i] == s->face; ++i)
++s->nchars;
/* All glyph strings for the same composition has the same width,
i.e. the width set for the first component of the composition. */
s->width = s->first_glyph->pixel_width;
/* If the specified font could not be loaded, use the frame's
default font, but record the fact that we couldn't load it in
the glyph string so that we can draw rectangles for the
characters of the glyph string. */
if (s->font == NULL)
{
s->font_not_found_p = 1;
s->font = FRAME_FONT (s->f);
}
/* Adjust base line for subscript/superscript text. */
s->ybase += s->first_glyph->voffset;
xassert (s->face && s->face->gc);
/* This glyph string must always be drawn with 16-bit functions. */
s->two_byte_p = 1;
return s->gidx + s->nchars;
}
/* 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
first glyph to consider, END is the index of the last + 1.
OVERLAPS_P non-zero means S should draw the foreground only, and
use its physical height for clipping.
Value is the index of the first glyph not in S. */
static int
fill_glyph_string (s, face_id, start, end, overlaps_p)
struct glyph_string *s;
int face_id;
int start, end, overlaps_p;
{
struct glyph *glyph, *last;
int voffset;
int glyph_not_available_p;
xassert (s->f == XFRAME (s->w->frame));
xassert (s->nchars == 0);
xassert (start >= 0 && end > start);
s->for_overlaps_p = overlaps_p,
glyph = s->row->glyphs[s->area] + start;
last = s->row->glyphs[s->area] + end;
voffset = glyph->voffset;
glyph_not_available_p = glyph->glyph_not_available_p;
while (glyph < last
&& glyph->type == CHAR_GLYPH
&& glyph->voffset == voffset
/* Same face id implies same font, nowadays. */
&& glyph->face_id == face_id
&& glyph->glyph_not_available_p == glyph_not_available_p)
{
int two_byte_p;
s->face = get_glyph_face_and_encoding (s->f, glyph,
s->char2b + s->nchars,
&two_byte_p);
s->two_byte_p = two_byte_p;
++s->nchars;
xassert (s->nchars <= end - start);
s->width += glyph->pixel_width;
++glyph;
}
s->font = s->face->font;
s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
/* If the specified font could not be loaded, use the frame's font,
but record the fact that we couldn't load it in
S->font_not_found_p so that we can draw rectangles for the
characters of the glyph string. */
if (s->font == NULL || glyph_not_available_p)
{
s->font_not_found_p = 1;
s->font = FRAME_FONT (s->f);
}
/* Adjust base line for subscript/superscript text. */
s->ybase += voffset;
xassert (s->face && s->face->gc);
return glyph - s->row->glyphs[s->area];
}
/* Fill glyph string S from image glyph S->first_glyph. */
static void
fill_image_glyph_string (s)
struct glyph_string *s;
{
xassert (s->first_glyph->type == IMAGE_GLYPH);
s->img = IMAGE_FROM_ID (s->f, s->first_glyph->u.img_id);
xassert (s->img);
s->face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
s->font = s->face->font;
s->width = s->first_glyph->pixel_width;
/* Adjust base line for subscript/superscript text. */
s->ybase += s->first_glyph->voffset;
}
/* Fill glyph string S from a sequence of stretch glyphs.
ROW is the glyph row in which the glyphs are found, AREA is the
area within the row. START is the index of the first glyph to
consider, END is the index of the last + 1.
Value is the index of the first glyph not in S. */
static int
fill_stretch_glyph_string (s, row, area, start, end)
struct glyph_string *s;
struct glyph_row *row;
enum glyph_row_area area;
int start, end;
{
struct glyph *glyph, *last;
int voffset, face_id;
xassert (s->first_glyph->type == STRETCH_GLYPH);
glyph = s->row->glyphs[s->area] + start;
last = s->row->glyphs[s->area] + end;
face_id = glyph->face_id;
s->face = FACE_FROM_ID (s->f, face_id);
s->font = s->face->font;
s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
s->width = glyph->pixel_width;
voffset = glyph->voffset;
for (++glyph;
(glyph < last
&& glyph->type == STRETCH_GLYPH
&& glyph->voffset == voffset
&& glyph->face_id == face_id);
++glyph)
s->width += glyph->pixel_width;
/* Adjust base line for subscript/superscript text. */
s->ybase += voffset;
/* The case that face->gc == 0 is handled when drawing the glyph
string by calling PREPARE_FACE_FOR_DISPLAY. */
xassert (s->face);
return glyph - s->row->glyphs[s->area];
}
/* EXPORT for RIF:
Set *LEFT and *RIGHT to the left and right overhang of GLYPH on
frame F. Overhangs of glyphs other than type CHAR_GLYPH are
assumed to be zero. */
void
x_get_glyph_overhangs (glyph, f, left, right)
struct glyph *glyph;
struct frame *f;
int *left, *right;
{
*left = *right = 0;
if (glyph->type == CHAR_GLYPH)
{
XFontStruct *font;
struct face *face;
struct font_info *font_info;
XChar2b char2b;
XCharStruct *pcm;
face = get_glyph_face_and_encoding (f, glyph, &char2b, NULL);
font = face->font;
font_info = FONT_INFO_FROM_ID (f, face->font_info_id);
if (font /* ++KFS: Should this be font_info ? */
&& (pcm = rif->per_char_metric (font, &char2b, glyph->font_type)))
{
if (pcm->rbearing > pcm->width)
*right = pcm->rbearing - pcm->width;
if (pcm->lbearing < 0)
*left = -pcm->lbearing;
}
}
}
/* Return the index of the first glyph preceding glyph string S that
is overwritten by S because of S's left overhang. Value is -1
if no glyphs are overwritten. */
static int
left_overwritten (s)
struct glyph_string *s;
{
int k;
if (s->left_overhang)
{
int x = 0, i;
struct glyph *glyphs = s->row->glyphs[s->area];
int first = s->first_glyph - glyphs;
for (i = first - 1; i >= 0 && x > -s->left_overhang; --i)
x -= glyphs[i].pixel_width;
k = i + 1;
}
else
k = -1;
return k;
}
/* Return the index of the first glyph preceding glyph string S that
is overwriting S because of its right overhang. Value is -1 if no
glyph in front of S overwrites S. */
static int
left_overwriting (s)
struct glyph_string *s;
{
int i, k, x;
struct glyph *glyphs = s->row->glyphs[s->area];
int first = s->first_glyph - glyphs;
k = -1;
x = 0;
for (i = first - 1; i >= 0; --i)
{
int left, right;
x_get_glyph_overhangs (glyphs + i, s->f, &left, &right);
if (x + right > 0)
k = i;
x -= glyphs[i].pixel_width;
}
return k;
}
/* Return the index of the last glyph following glyph string S that is
not overwritten by S because of S's right overhang. Value is -1 if
no such glyph is found. */
static int
right_overwritten (s)
struct glyph_string *s;
{
int k = -1;
if (s->right_overhang)
{
int x = 0, i;
struct glyph *glyphs = s->row->glyphs[s->area];
int first = (s->first_glyph - glyphs) + (s->cmp ? 1 : s->nchars);
int end = s->row->used[s->area];
for (i = first; i < end && s->right_overhang > x; ++i)
x += glyphs[i].pixel_width;
k = i;
}
return k;
}
/* Return the index of the last glyph following glyph string S that
overwrites S because of its left overhang. Value is negative
if no such glyph is found. */
static int
right_overwriting (s)
struct glyph_string *s;
{
int i, k, x;
int end = s->row->used[s->area];
struct glyph *glyphs = s->row->glyphs[s->area];
int first = (s->first_glyph - glyphs) + (s->cmp ? 1 : s->nchars);
k = -1;
x = 0;
for (i = first; i < end; ++i)
{
int left, right;
x_get_glyph_overhangs (glyphs + i, s->f, &left, &right);
if (x - left < 0)
k = i;
x += glyphs[i].pixel_width;
}
return k;
}
/* Get face and two-byte form of character C in face FACE_ID on frame
F. The encoding of C is returned in *CHAR2B. MULTIBYTE_P non-zero
means we want to display multibyte text. DISPLAY_P non-zero means
make sure that X resources for the face returned are allocated.
Value is a pointer to a realized face that is ready for display if
DISPLAY_P is non-zero. */
static INLINE struct face *
get_char_face_and_encoding (f, c, face_id, char2b, multibyte_p, display_p)
struct frame *f;
int c, face_id;
XChar2b *char2b;
int multibyte_p, display_p;
{
struct face *face = FACE_FROM_ID (f, face_id);
if (!multibyte_p)
{
/* Unibyte case. We don't have to encode, but we have to make
sure to use a face suitable for unibyte. */
STORE_XCHAR2B (char2b, 0, c);
face_id = FACE_FOR_CHAR (f, face, c);
face = FACE_FROM_ID (f, face_id);
}
else if (c < 128 && face_id < BASIC_FACE_ID_SENTINEL)
{
/* Case of ASCII in a face known to fit ASCII. */
STORE_XCHAR2B (char2b, 0, c);
}
else
{
int c1, c2, charset;
/* Split characters into bytes. If c2 is -1 afterwards, C is
really a one-byte character so that byte1 is zero. */
SPLIT_CHAR (c, charset, c1, c2);
if (c2 > 0)
STORE_XCHAR2B (char2b, c1, c2);
else
STORE_XCHAR2B (char2b, 0, c1);
/* Maybe encode the character in *CHAR2B. */
if (face->font != NULL)
{
struct font_info *font_info
= FONT_INFO_FROM_ID (f, face->font_info_id);
if (font_info)
rif->encode_char (c, char2b, font_info, 0);
}
}
/* Make sure X resources of the face are allocated. */
#ifdef HAVE_X_WINDOWS
if (display_p)
#endif
{
xassert (face != NULL);
PREPARE_FACE_FOR_DISPLAY (f, face);
}
return face;
}
/* Set background width of glyph string S. START is the index of the
first glyph following S. LAST_X is the right-most x-position + 1
in the drawing area. */
static INLINE void
set_glyph_string_background_width (s, start, last_x)
struct glyph_string *s;
int start;
int last_x;
{
/* If the face of this glyph string has to be drawn to the end of
the drawing area, set S->extends_to_end_of_line_p. */
struct face *default_face = FACE_FROM_ID (s->f, DEFAULT_FACE_ID);
if (start == s->row->used[s->area]
&& s->area == TEXT_AREA
&& ((s->hl == DRAW_NORMAL_TEXT
&& (s->row->fill_line_p
|| s->face->background != default_face->background
|| s->face->stipple != default_face->stipple
|| s->row->mouse_face_p))
|| s->hl == DRAW_MOUSE_FACE
|| ((s->hl == DRAW_IMAGE_RAISED || s->hl == DRAW_IMAGE_SUNKEN)
&& s->row->fill_line_p)))
s->extends_to_end_of_line_p = 1;
/* If S extends its face to the end of the line, set its
background_width to the distance to the right edge of the drawing
area. */
if (s->extends_to_end_of_line_p)
s->background_width = last_x - s->x + 1;
else
s->background_width = s->width;
}
/* Compute overhangs and x-positions for glyph string S and its
predecessors, or successors. X is the starting x-position for S.
BACKWARD_P non-zero means process predecessors. */
static void
compute_overhangs_and_x (s, x, backward_p)
struct glyph_string *s;
int x;
int backward_p;
{
if (backward_p)
{
while (s)