static MSymbol M_glyph_string;
/* Special scripts */
-static MSymbol Mlatin, Minherited;
+static MSymbol Minherited;
/* Special categories */
static MSymbol McatCc, McatCf;
MGlyph *g;
int i;
#ifdef HAVE_FRIBIDI
- FriBidiCharType base = (gstring->control.orientation_reversed
- ? FRIBIDI_TYPE_RTL : FRIBIDI_TYPE_LTR);
+ FriBidiCharType base = bidi_sensitive ? FRIBIDI_TYPE_RTL : FRIBIDI_TYPE_LTR;
FriBidiChar *logical = alloca (sizeof (FriBidiChar) * len);
FriBidiChar *visual;
FriBidiStrIndex *indices;
for (g = MGLYPH (1), i = 0; g->type != GLYPH_ANCHOR; g++, i++)
{
- MSymbol bidi = (MSymbol) mchar_get_prop (g->c, Mbidi_category);
-
- if (bidi == MbidiR || bidi == MbidiAL
- || bidi == MbidiRLE || bidi == MbidiRLO)
+ if (! bidi_sensitive
+#ifndef HAVE_FRIBIDI
+ || 1
+#endif /* not HAVE_FRIBIDI */
+ )
{
- bidi_sensitive = 1;
+ MSymbol bidi = (MSymbol) mchar_get_prop (g->c, Mbidi_category);
+
+ if (bidi == MbidiR || bidi == MbidiAL
+ || bidi == MbidiRLE || bidi == MbidiRLO)
+ {
+ bidi_sensitive = 1;
#ifndef HAVE_FRIBIDI
- levels[i] = 1;
+ levels[i] = 1;
#endif /* not HAVE_FRIBIDI */
+ }
}
logical[i] = g->c;
}
}
#endif /* not HAVE_FRIBIDI */
- for (i = 0; i < len; i++)
+ for (i = 0; i < len;)
{
+ /* Index into gstring->glyphs plus 1 for GLYPHS[i]. */
int j = indices[i];
+ /* Length of grapheme-cluster */
+ int seglen;
- g = MGLYPH (j + 1);
- if (i != j)
- *g = glyphs[i];
- g->bidi_level = levels[i];
+ g = glyphs + i;
#ifdef HAVE_FRIBIDI
if (visual[j] != logical[i])
{
g->code = mfont__encode_char (g->rface->rfont, g->c);
}
#endif /* HAVE_FRIBIDI */
+ g->bidi_level = levels[i];
+ for (seglen = 1, g++;
+ i + seglen < len && (glyphs[i].pos == glyphs[i + seglen].pos
+ || glyphs[i + seglen].combining_code);
+ seglen++, g++)
+ {
+ g->bidi_level = levels[i];
+ if (indices[i + seglen] < j)
+ j = indices[i + seglen];
+ }
+ memcpy (MGLYPH (j + 1), glyphs + i, sizeof (MGlyph) * seglen);
+ i += seglen;
}
}
/** Scan M-text MT from FROM to TO, and compose glyphs in GSTRING for
displaying them on FRAME.
- This function fills members <type>, <rface>, <c>, <pos>, <to>,
- <code> of glyphs. The other members are filled by
- layout_glyph_string. */
+ This function fills these members:
+ pos, to, c, code, rface, bidi_level, categories, type, combining_code
+ The other members are filled by layout_glyph_string. */
static void
compose_glyph_string (MFrame *frame, MText *mt, int from, int to,
{
MRealizedFace *default_rface = frame->rface;
int stop, face_change, language_change, charset_change;
- MGlyph g_tmp, *g;
+ MGlyph g_tmp, *g, *last_g;
int pos;
MSymbol language = Mnil, script = Mnil, charset = Mnil;
MSymbol non_latin_script = Mnil;
MRealizedFace *rface = default_rface;
+ MRealizedFont *rfont;
int size = gstring->control.fixed_width;
int i;
- int last;
MLIST_RESET (gstring);
gstring->from = from;
- /* At first generate glyphs while using the member <enabled> as a
- flag for rface re-checking. */
+ /* At first generate glyphs with <pos>, <to>, <c>, <type>,
+ <category> and <rface> members.*/
INIT_GLYPH (g_tmp);
/** Put anchor glyphs at the head and tail. */
g_tmp.type = GLYPH_ANCHOR;
g_tmp.pos = g_tmp.to = from;
- g_tmp.c = 0;
APPEND_GLYPH (gstring, g_tmp);
-
- stop = face_change = charset_change = language_change = pos = from;
- last = 0;
+ stop = face_change = pos = from;
while (1)
{
int c;
- MSymbol this_script;
+ MSymbol category;
+
+ if (pos == stop)
+ {
+ if (pos == to)
+ break;
+ if (pos == face_change)
+ {
+ MFace *faces[64];
+ int num = mtext_get_prop_values (mt, pos, Mface,
+ (void **) faces, 64);
+
+ mtext_prop_range (mt, Mface, pos, NULL, &face_change, 1);
+ if (face_change == mtext_nchars (mt))
+ face_change++;
+ rface = (num > 0 ? mface__realize (frame, faces, num, size)
+ : default_rface);
+ }
+ stop = to;
+ if (stop > face_change)
+ stop = face_change;
+ }
if (pos < mtext_nchars (mt))
c = mtext_ref_char (mt, pos);
else
c = '\n';
- g_tmp.category = mchar_get_prop (c, Mcategory);
- if (c < 0x100)
+ g_tmp.type
+ = (c == ' ' || c == '\n' || c == '\t') ? GLYPH_SPACE : GLYPH_CHAR;
+ g_tmp.c = c;
+ g_tmp.pos = pos++;
+ g_tmp.to = pos;
+ g_tmp.rface = rface;
+ category = mchar_get_prop (c, Mcategory);
+ if (category == McatCf)
+ g_tmp.category = GLYPH_CATEGORY_FORMATTER;
+ else if (category != Mnil && MSYMBOL_NAME (category)[0] == 'M')
+ g_tmp.category = GLYPH_CATEGORY_MODIFIER;
+ else
+ g_tmp.category = GLYPH_CATEGORY_NORMAL;
+
+ if ((c <= ' ' || c == 127) && g_tmp.type == GLYPH_CHAR)
{
- /* Short cut for the obvious case. */
- g_tmp.type = (c == ' ' || c == '\n' || c == '\t'
- ? GLYPH_SPACE : GLYPH_CHAR);
- this_script = (MSYMBOL_NAME (g_tmp.category)[0] == 'L'
- ? Mlatin : Mnil);
+ MGlyph ctrl[2];
+
+ ctrl[0] = ctrl[1] = g_tmp;
+ ctrl[0].c = '^';
+ ctrl[1].c = c < ' ' ? c + 0x40 : '?';
+ APPEND_GLYPH (gstring, ctrl[0]);
+ APPEND_GLYPH (gstring, ctrl[1]);
}
else
+ APPEND_GLYPH (gstring, g_tmp);
+ if (c == '\n' && gstring->control.two_dimensional)
+ break;
+ }
+ /* Append an anchor glyph. */
+ INIT_GLYPH (g_tmp);
+ g_tmp.type = GLYPH_ANCHOR;
+ g_tmp.pos = g_tmp.to = pos;
+ APPEND_GLYPH (gstring, g_tmp);
+ gstring->to = pos;
+
+ /* The next loop is to change each <rface> member for non-ASCII
+ characters if necessary. */
+ stop = charset_change = language_change = from;
+ rfont = default_rface->rfont;
+ for (last_g = g = MGLYPH (1); g->type != GLYPH_ANCHOR; g++)
+ {
+ int c = g->c;
+ MSymbol this_script;
+
+ if (c < 0x100)
+ /* Short cut for the obvious case. */
+ this_script = Mlatin;
+ else
{
- g_tmp.type = GLYPH_CHAR;
this_script = (MSymbol) mchar_get_prop (c, Mscript);
if (this_script == Minherited || this_script == Mnil)
this_script = script;
{
/* Search forward for a character that explicitly
specifies a non-latin script. */
- int c1;
MSymbol sym;
+ MGlyph *g1;
- for (i = pos + 1; i < to; i++)
- if ((c1 = mtext_ref_char (mt, i)) >= 0x100
- && (sym = mchar_get_prop (c1, Mscript)) != Mnil
+ for (g1 = g + 1; g1->type != GLYPH_ANCHOR; g1++)
+ if (g1->c >= 0x100
+ && (sym = mchar_get_prop (g1->c, Mscript)) != Mnil
&& sym != Minherited)
{
this_script = sym;
}
}
- if (pos == stop || script != this_script
- || MGLYPH (last)->type != g_tmp.type)
+ pos = g->pos;
+ if (pos == stop || script != this_script || g->rface->rfont != rfont)
{
- g = MGLYPH (last);
- if (g->type != GLYPH_ANCHOR)
- while (g < gstring->glyphs + gstring->used)
- g = mface__for_chars (script == Mnil ? Mlatin : script,
- language, charset,
- g, gstring->glyphs + gstring->used, size);
- if (pos == to)
- break;
- last = gstring->used;
+ while (last_g < g)
+ last_g = mface__for_chars (script, language, charset,
+ last_g, g, size);
script = this_script;
if (script != Mnil && script != Mlatin)
non_latin_script = script;
+ rfont = g->rface->ascii_rface->rfont;
if (pos == stop)
{
if (pos < mtext_nchars (mt) && pos == language_change)
mtext_prop_range (mt, Mcharset, pos, NULL,
&charset_change, 0);
}
- if (pos < mtext_nchars (mt) && pos == face_change)
- {
- MFace *faces[64];
- int num = mtext_get_prop_values (mt, pos, Mface,
- (void **) faces, 64);
-
- mtext_prop_range (mt, Mface, pos, NULL, &face_change, 1);
- rface = (num > 0
- ? mface__realize (frame, faces, num,
- language, charset, size)
- : default_rface);
- }
stop = to;
if (stop > language_change)
stop = language_change;
if (stop > charset_change)
stop = charset_change;
- if (face_change < stop)
- stop = face_change;
}
}
-
- g_tmp.c = c;
- g_tmp.pos = pos++;
- g_tmp.to = pos;
- g_tmp.rface = rface;
-
- if ((c <= 32 || c == 127) && g_tmp.type == GLYPH_CHAR)
- {
- MGlyph ctrl[2];
-
- ctrl[0] = ctrl[1] = g_tmp;
- ctrl[0].c = '^';
- ctrl[1].c = c < ' ' ? c + 0x40 : '?';
- mface__for_chars (Mlatin, language, charset, ctrl, ctrl + 2, size);
- APPEND_GLYPH (gstring, ctrl[0]);
- APPEND_GLYPH (gstring, ctrl[1]);
- }
- else
- APPEND_GLYPH (gstring, g_tmp);
- if (c == '\n'
- && gstring->control.two_dimensional)
- break;
}
+ while (last_g < g)
+ last_g = mface__for_chars (script, language, charset, last_g, g, size);
- /* Append an anchor glyph. */
- g_tmp.type = GLYPH_ANCHOR;
- g_tmp.c = 0;
- g_tmp.code = MCHAR_INVALID_CODE;
- g_tmp.pos = g_tmp.to = pos;
- g_tmp.rface = NULL;
- APPEND_GLYPH (gstring, g_tmp);
-
- gstring->to = pos;
-
- /* Next, run FLT if necessary. */
- for (i = 1, g = MGLYPH (i); g->type != GLYPH_ANCHOR;)
+ /* The next loop is to run FLT or perform the default combining if
+ necessary. */
+ for (i = 1, g = MGLYPH (1); g->type != GLYPH_ANCHOR;)
{
MGlyph *this = g;
for (prev = MGLYPH (start - 1);
(prev->type == GLYPH_CHAR
- && prev->category == McatCf
+ && prev->category == GLYPH_CATEGORY_FORMATTER
&& (code = mfont__encode_char (this->rface->rfont, prev->c)
!= MCHAR_INVALID_CODE));
start--, prev--)
for (g++;
(g->type == GLYPH_CHAR
&& (g->rface->rfont == this->rface->rfont
- || (g->category == McatCf
+ || (g->category == GLYPH_CATEGORY_FORMATTER
&& ((code = mfont__encode_char (this->rface->rfont,
g->c))
!= MCHAR_INVALID_CODE))));
{
while (this->type == GLYPH_CHAR
&& this->c >= 0x100
- && this->category
- && MSYMBOL_NAME (this->category)[0] == 'M'
+ && this->category == GLYPH_CATEGORY_MODIFIER
&& this->rface->rfont
&& this->rface->rfont->layouter == Mnil)
{
}
+typedef struct {
+ int width, lbearing, rbearing;
+} MSubTextExtents;
+
static void
-layout_glyphs (MFrame *frame, MGlyphString *gstring, int from, int to)
+layout_glyphs (MFrame *frame, MGlyphString *gstring, int from, int to,
+ MSubTextExtents *extents)
{
int g_physical_ascent, g_physical_descent;
- int g_width, g_lbearing, g_rbearing;
MGlyph *g = MGLYPH (from);
MGlyph *last_g = MGLYPH (to);
int i;
g_physical_ascent = gstring->physical_ascent;
g_physical_descent = gstring->physical_descent;
- g_width = g_lbearing = g_rbearing = 0;
+ extents->width = extents->lbearing = extents->rbearing = 0;
for (i = from; i < to;)
{
}
}
- while (g < last_g)
- {
- MGlyph *base = g++;
-
- if ((base->combining_code || base->width == 0)
- && (base->bidi_level % 2))
- {
- MGlyph *g1 = base, *g2, temp;
-
- while (g->combining_code)
- g++;
- for (g2 = g; g1 < g2; g1++, g2--)
- temp = *g1, *g1 = *g2, *g2 = temp;
- g++;
- }
- }
g = MGLYPH (from);
while (g < last_g)
{
g_physical_ascent = MAX (g_physical_ascent, base->ascent);
g_physical_descent = MAX (g_physical_descent, base->descent);
- g_lbearing = MIN (g_lbearing, g_width + lbearing);
- g_rbearing = MAX (g_rbearing, g_width + rbearing);
- g_width += base->width;
+ extents->lbearing = MIN (extents->lbearing, extents->width + lbearing);
+ extents->rbearing = MAX (extents->rbearing, extents->width + rbearing);
+ extents->width += base->width;
}
gstring->physical_ascent = g_physical_ascent;
gstring->physical_descent = g_physical_descent;
- gstring->sub_width = g_width;
- gstring->sub_lbearing = g_lbearing;
- gstring->sub_rbearing = g_rbearing;
}
}
}
- if (g->category == McatCf && ignore_formatting_char)
+ if (g->category == GLYPH_CATEGORY_FORMATTER && ignore_formatting_char)
g->type = GLYPH_SPACE;
if (g->type == GLYPH_CHAR)
|| box != g->rface->box
|| ((fromg->code == MCHAR_INVALID_CODE)
!= (g->code == MCHAR_INVALID_CODE))
- || (g->category == McatCf && ignore_formatting_char))
+ || (g->category == GLYPH_CATEGORY_FORMATTER
+ && ignore_formatting_char))
break;
if (rfont && fromg->code != MCHAR_INVALID_CODE)
{
int extra_width;
int to = GLYPH_INDEX (g);
+ MSubTextExtents extents;
- layout_glyphs (frame, gstring, from, to);
- extra_width = - gstring->sub_lbearing;
+ layout_glyphs (frame, gstring, from, to, &extents);
+ extra_width = - extents.lbearing;
if (extra_width > 0
- && (GLYPH_INDEX (g) > 1
- || (! control->orientation_reversed && control->align_head)))
+ && ! control->disable_overlapping_adjustment
+ && (! control->orientation_reversed
+ ? ((to > 1 || control->align_head)
+ && g->type != GLYPH_ANCHOR)
+ : (((g->type && GLYPH_ANCHOR) || control->align_head)
+ && to > 1)))
{
g = MGLYPH (from);
pad = *g;
pad.left_padding = 1;
INSERT_GLYPH (gstring, from, pad);
to++;
- gstring->sub_lbearing = 0;
- gstring->sub_width += extra_width;
- gstring->sub_rbearing += extra_width;
+ extents.lbearing = 0;
+ extents.width += extra_width;
+ extents.rbearing += extra_width;
g = MGLYPH (from - 1);
if (g->type == GLYPH_SPACE)
}
g = MGLYPH (to);
- extra_width = gstring->sub_rbearing - gstring->sub_width;
+ extra_width = extents.rbearing - extents.width;
if (extra_width > 0
+ && ! control->disable_overlapping_adjustment
&& (GLYPH_INDEX (g) < gstring->used - 1
|| (control->orientation_reversed && control->align_head)))
{
pad.lbearing = 0;
pad.width = pad.rbearing = extra_width;
INSERT_GLYPH (gstring, to, pad);
+ to++;
+ g = MGLYPH (to);
}
else
g[-1].width += extra_width;
- gstring->sub_width += extra_width;
+ extents.width += extra_width;
}
- if (gstring->lbearing > gstring->width + gstring->sub_lbearing)
- gstring->lbearing = gstring->width + gstring->sub_lbearing;
- if (gstring->rbearing < gstring->width + gstring->sub_rbearing)
- gstring->rbearing = gstring->width + gstring->sub_rbearing;
- gstring->width += gstring->sub_width;
+ if (gstring->lbearing > gstring->width + extents.lbearing)
+ gstring->lbearing = gstring->width + extents.lbearing;
+ if (gstring->rbearing < gstring->width + extents.rbearing)
+ gstring->rbearing = gstring->width + extents.rbearing;
+ gstring->width += extents.width;
if (gstring->ascent < rface->ascent)
gstring->ascent = rface->ascent;
if (gstring->descent < rface->descent)
if (pos == mt->nchars)
{
+ MGlyph *g;
+
gstring = &scratch_gstring;
+ if (gstring->size == 0)
+ {
+ MGlyph g_tmp;
+
+ INIT_GLYPH (g_tmp);
+ g_tmp.type = GLYPH_ANCHOR;
+ APPEND_GLYPH (gstring, g_tmp);
+ APPEND_GLYPH (gstring, g_tmp);
+ APPEND_GLYPH (gstring, g_tmp);
+ gstring->glyphs[1].type = GLYPH_SPACE;
+ gstring->glyphs[1].c = '\n';
+ gstring->glyphs[1].code = '\n';
+ }
+ gstring->from = pos;
+ g = MGLYPH (0);
+ g->rface = frame->rface;
+ g->pos = g->to = pos;
+ g++;
+ g->rface = frame->rface;
+ g->pos = pos++, g->to = pos;
+ g++;
+ g->rface = frame->rface;
+ g->pos = g->to = pos;
+ gstring->to = pos;
}
else
{
gstring->frame = frame;
gstring->tick = frame->tick;
gstring->top = gstring;
- gstring->mt = mt;
gstring->control = *control;
gstring->indent = gstring->width_limit = 0;
if (control->format)
int pos;
/* Setup the array POS_WIDTH so that POS_WIDTH[I - GSTRING->from] is
- a width of glyphs for the character at I of GSTRING->mt. If I is
- not a beginning of a grapheme cluster, the corresponding element
- is 0. */
+ a width of glyphs for the character at I of MT. If I is not a
+ beginning of a grapheme cluster, the corresponding element is
+ 0. */
MTABLE_ALLOCA (pos_width, gstring->to - gstring->from, MERROR_DRAW);
memset (pos_width, 0, sizeof (int) * (gstring->to - gstring->from));
for (g = MGLYPH (1); g->type != GLYPH_ANCHOR; g++)
pos = gstring->from + i;
if (gstring->control.line_break)
{
- pos = (*gstring->control.line_break) (gstring->mt, gstring->from + i,
+ pos = (*gstring->control.line_break) (mt, gstring->from + i,
gstring->from, gstring->to, 0, 0);
- if (pos <= gstring->from || pos >= gstring->to)
- return;
+ if (pos <= gstring->from)
+ pos = gstring->from + 1;
+ else if (pos >= gstring->to)
+ pos = gstring->to;
}
+ else if (i == 0)
+ pos++;
compose_glyph_string (frame, mt, gstring->from, pos, gstring);
layout_glyph_string (frame, gstring);
}
int beg, end;
int line = 0, y = 0;
- if (control->two_dimensional)
+ if (pos < mtext_nchars (mt))
{
beg = mtext_character (mt, pos, 0, '\n');
if (beg < 0)
beg = 0;
else
beg++;
- end = mtext_nchars (mt) + (control->cursor_width != 0);
}
else
- {
- beg = pos;
- end = to;
- }
+ beg = pos;
+ end = mtext_nchars (mt) + (control->cursor_width != 0);
gstring = alloc_gstring (frame, mt, beg, control, line, y);
- compose_glyph_string (frame, mt, beg, end, gstring);
+ if (beg < mtext_nchars (mt))
+ compose_glyph_string (frame, mt, beg, end, gstring);
layout_glyph_string (frame, gstring);
end = gstring->to;
- if (control->two_dimensional
- && gstring->width_limit
+ if (gstring->width_limit
&& gstring->width > gstring->width_limit)
{
MGlyphString *gst = gstring;
memset (&scratch_gstring, 0, sizeof (scratch_gstring));
MLIST_INIT1 (&scratch_gstring, glyphs, 3);
- Mlatin = msymbol ("latin");
Minherited = msymbol ("inherited");
McatCc = msymbol ("Cc");
return 0;
}
- for (g = MGLYPH (1), x = 0; g->type != GLYPH_ANCHOR;)
+ for (g = MGLYPH (1), x = 0; g->type != GLYPH_ANCHOR; g++)
if (g->pos >= from && g->pos < to)
{
int start = g->pos;
int rbearing = g->rbearing;
int ascent = g->ascent;
int descent = g->descent;
- int logical_ascent = g->rface->rfont->ascent;
- int logical_descent = g->rface->rfont->descent;
+ int logical_ascent;
+ int logical_descent;
+ if (g->rface->rfont)
+ {
+ logical_ascent = g->rface->rfont->ascent;
+ logical_descent = g->rface->rfont->descent;
+ }
+ else
+ {
+ logical_ascent = g->rface->ascent;
+ logical_descent = g->rface->descent;
+ }
for (g++; g->type != GLYPH_ANCHOR && g->pos == start; g++)
{
if (lbearing < width + g->lbearing)
end = to;
while (start < end)
{
- ink_array_return[start - from].x = x + lbearing;
- ink_array_return[start - from].y = - ascent;
- ink_array_return[start - from].width = rbearing - lbearing;
- ink_array_return[start - from].height = ascent + descent;
- logical_array_return[start - from].x = x;
- logical_array_return[start - from].y = - logical_descent;
- logical_array_return[start - from].height
- = logical_ascent + logical_descent;
- logical_array_return[start - from].width = width;
+ if (ink_array_return)
+ {
+ ink_array_return[start - from].x = x + lbearing;
+ ink_array_return[start - from].y = - ascent;
+ ink_array_return[start - from].width = rbearing - lbearing;
+ ink_array_return[start - from].height = ascent + descent;
+ }
+ if (logical_array_return)
+ {
+ logical_array_return[start - from].x = x;
+ logical_array_return[start - from].y = - logical_descent;
+ logical_array_return[start - from].height
+ = logical_ascent + logical_descent;
+ logical_array_return[start - from].width = width;
+ }
start++;
}
x += width;
+ g--;
}
if (overall_ink_return)
if (! control->orientation_reversed)
{
width = gstring->indent;
- for (g = MGLYPH (1); g[1].type != GLYPH_ANCHOR; g++)
+ for (g = MGLYPH (1); g->type != GLYPH_ANCHOR; g++)
if (g->pos >= from && g->pos < to)
{
width += g->width;
break;
}
}
+ if (g->type == GLYPH_ANCHOR
+ && control->two_dimensional
+ && g[-1].c == '\n')
+ g--;
from = g->pos;
M17N_OBJECT_UNREF (gstring->top);