X-Git-Url: http://git.chise.org/gitweb/?a=blobdiff_plain;f=src%2Fdraw.c;h=6155d4a5bcb43ebf97fcbf9c149a698d8924e255;hb=1efb9743d0f36547560447cf4cf6ba9efb005fbb;hp=c4d3c4a26a232873d657f035fdf119b7678d109f;hpb=d152158a4a5259d8ea481aea510e887f86424f81;p=m17n%2Fm17n-lib.git diff --git a/src/draw.c b/src/draw.c index c4d3c4a..6155d4a 100644 --- a/src/draw.c +++ b/src/draw.c @@ -1,5 +1,5 @@ /* draw.c -- drawing module. - Copyright (C) 2003, 2004 + Copyright (C) 2003, 2004, 2005, 2006 National Institute of Advanced Industrial Science and Technology (AIST) Registration Number H15PRO112 @@ -17,7 +17,7 @@ You should have received a copy of the GNU Lesser General Public License along with the m17n library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 02111-1307, USA. */ /***en @@ -80,7 +80,7 @@ static MSymbol M_glyph_string; /* Special scripts */ -static MSymbol Minherited; +static MSymbol Mcommon; /* Special categories */ static MSymbol McatCc, McatCf; @@ -97,6 +97,7 @@ static MSymbol MbidiRLE; static MSymbol MbidiRLO; static MSymbol MbidiBN; static MSymbol MbidiS; +static MSymbol MbidiNSM; static void visual_order (MGlyphString *gstring) @@ -116,6 +117,8 @@ visual_order (MGlyphString *gstring) int *logical = alloca (sizeof (int) * len); int *indices; char *levels = alloca (len); + + memset (levels, 0, sizeof (int) * len); #endif /* not HAVE_FRIBIDI */ for (g = MGLYPH (1), i = 0; g->type != GLYPH_ANCHOR; g++, i++) @@ -136,6 +139,10 @@ visual_order (MGlyphString *gstring) levels[i] = 1; #endif /* not HAVE_FRIBIDI */ } +#ifndef HAVE_FRIBIDI + else if (bidi == MbidiNSM && i > 0 && levels[i - 1]) + levels[i] = 1; +#endif /* not HAVE_FRIBIDI */ } logical[i] = g->c; } @@ -183,7 +190,8 @@ visual_order (MGlyphString *gstring) /* Mirrored. */ g->c = visual[j]; if (g->rface->rfont) - g->code = mfont__encode_char (g->rface->rfont, g->c); + g->code = mfont__encode_char (NULL, (MFont *) g->rface->rfont, + NULL, g->c); } #endif /* HAVE_FRIBIDI */ g->bidi_level = levels[i]; @@ -236,7 +244,7 @@ compose_glyph_string (MFrame *frame, MText *mt, int from, int to, MGlyphString *gstring) { MRealizedFace *default_rface = frame->rface; - int stop, face_change, language_change, charset_change; + int stop, face_change, language_change, charset_change, font_change; MGlyph g_tmp, *g, *last_g; int pos; MSymbol language = Mnil, script = Mnil, charset = Mnil; @@ -257,7 +265,7 @@ compose_glyph_string (MFrame *frame, MText *mt, int from, int to, g_tmp.type = GLYPH_ANCHOR; g_tmp.pos = g_tmp.to = from; APPEND_GLYPH (gstring, g_tmp); - stop = face_change = pos = from; + stop = face_change = font_change = pos = from; while (1) { int c; @@ -267,24 +275,39 @@ compose_glyph_string (MFrame *frame, MText *mt, int from, int to, { if (pos == to) break; - if (pos == face_change) + if (pos < mtext_nchars (mt)) { - if (pos < mtext_nchars (mt)) - { - MFace *faces[64]; - int num = mtext_get_prop_values (mt, pos, Mface, - (void **) faces, 64); + MFont *font = rface->font; + MFace *faces[64]; + int num; + if (pos == font_change) + { + font = mtext_get_prop (mt, pos, Mfont); + mtext_prop_range (mt, Mfont, pos, NULL, &font_change, 0); + if (font_change == mtext_nchars (mt)) + font_change++; + } + if (pos == face_change) + { + 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); } else - rface = default_rface; + { + faces[0] = &rface->face; + num = 1; + } + rface = mface__realize (frame, faces, num, size, font); } + else + rface = default_rface; stop = to; + if (stop > font_change) + stop = font_change; if (stop > face_change) stop = face_change; } @@ -344,11 +367,11 @@ compose_glyph_string (MFrame *frame, MText *mt, int from, int to, else { this_script = (MSymbol) mchar_get_prop (c, Mscript); - if (this_script == Minherited || this_script == Mnil) + if (this_script == Minherited || this_script == Mcommon) this_script = script; - if (this_script == Mnil) + if (this_script == Mcommon) this_script = non_latin_script; - if (this_script == Mnil) + if (this_script == Mcommon) { /* Search forward for a character that explicitly specifies a non-latin script. */ @@ -357,7 +380,7 @@ compose_glyph_string (MFrame *frame, MText *mt, int from, int to, for (g1 = g + 1; g1->type != GLYPH_ANCHOR; g1++) if (g1->c >= 0x100 - && (sym = mchar_get_prop (g1->c, Mscript)) != Mnil + && (sym = mchar_get_prop (g1->c, Mscript)) != Mcommon && sym != Minherited) { this_script = sym; @@ -411,7 +434,7 @@ compose_glyph_string (MFrame *frame, MText *mt, int from, int to, { int start = i++; - if (this->rface->rfont->layouter != Mnil) + if (this->rface->layouter != Mnil) { MGlyph *prev; unsigned code; @@ -419,16 +442,25 @@ compose_glyph_string (MFrame *frame, MText *mt, int from, int to, for (prev = MGLYPH (start - 1); (prev->type == GLYPH_CHAR && prev->category == GLYPH_CATEGORY_FORMATTER - && (code = mfont__encode_char (this->rface->rfont, prev->c) + && (code = mfont__encode_char (NULL, + (MFont *) this->rface->rfont, + NULL, prev->c) != MCHAR_INVALID_CODE)); start--, prev--) - prev->code = code; + if (prev->rface->rfont != this->rface->rfont) + { + prev->rface->rfont = this->rface->rfont; + prev->code = code; + } for (g++; (g->type == GLYPH_CHAR + && g->rface->layouter == this->rface->layouter && (g->rface->rfont == this->rface->rfont || (g->category == GLYPH_CATEGORY_FORMATTER - && ((code = mfont__encode_char (this->rface->rfont, + && ((code = mfont__encode_char (NULL, + (MFont *) this->rface->rfont, + NULL, g->c)) != MCHAR_INVALID_CODE)))); i++, g++) @@ -556,7 +588,7 @@ layout_glyphs (MFrame *frame, MGlyphString *gstring, int from, int to, { MGlyph *base = g++; MRealizedFont *rfont = base->rface->rfont; - int size = rfont->font.property[MFONT_SIZE]; + int size = rfont->spec.size; int width, lbearing, rbearing; if (g == last_g || ! g->combining_code) @@ -580,7 +612,10 @@ layout_glyphs (MFrame *frame, MGlyphString *gstring, int from, int to, if (base->left_padding && base->lbearing < 0) { base->xoff = - base->lbearing; - base->width += base->xoff; + if (base->rbearing < 0) + base->width = base->rbearing - base->lbearing; + else + base->width += base->xoff; base->rbearing += base->xoff; base->lbearing = 0; } @@ -588,9 +623,8 @@ layout_glyphs (MFrame *frame, MGlyphString *gstring, int from, int to, { base->width = base->rbearing; } - lbearing = (base->xoff + base->lbearing < 0 - ? base->xoff + base->lbearing : 0); - rbearing = base->xoff + base->rbearing; + lbearing = base->lbearing; + rbearing = base->rbearing; } else { @@ -627,7 +661,7 @@ layout_glyphs (MFrame *frame, MGlyphString *gstring, int from, int to, (combining_code)); rfont = g->rface->rfont; - size = rfont->font.property[MFONT_SIZE]; + size = rfont->spec.size; off_x = (size * (COMBINING_CODE_OFF_X (combining_code) - 128) / 1000); off_y = (size * (COMBINING_CODE_OFF_Y (combining_code) - 128) @@ -692,6 +726,12 @@ layout_glyphs (MFrame *frame, MGlyphString *gstring, int from, int to, base[i].pos = begin; base[i].to = end; } + if (base->left_padding && lbearing < 0) + { + base->xoff -= lbearing; + base->width -= lbearing; + lbearing = 0; + } } g_physical_ascent = MAX (g_physical_ascent, base->ascent); @@ -1072,6 +1112,7 @@ draw_background (MFrame *frame, MDrawWindow win, int x, int y, } *from_idx = *to_idx = 0; + *to_x = x; while (g->type != GLYPH_ANCHOR) { if (g->pos >= from && g->pos < to) @@ -1240,7 +1281,8 @@ render_glyphs (MFrame *frame, MDrawWindow win, int x, int y, int width, gend--; } if (g != gend) - while (gend[-1].to == gend->to) gend++; + while (gend->type != GLYPH_ANCHOR && gend[-1].to == gend->to) + gend++; } } @@ -1351,23 +1393,30 @@ find_overlapping_glyphs (MGlyphString *gstring, int *left, int *right, static int -gstring_width (MGlyphString *gstring, int from, int to, int *rbearing) +gstring_width (MGlyphString *gstring, int from, int to, + int *lbearing, int *rbearing) { MGlyph *g; int width; if (from <= gstring->from && to >= gstring->to) { + if (lbearing) + *lbearing = gstring->lbearing; if (rbearing) *rbearing = gstring->rbearing; return gstring->width; } + if (lbearing) + *lbearing = 0; if (rbearing) *rbearing = 0; for (g = MGLYPH (1), width = 0; g->type != GLYPH_ANCHOR; g++) if (g->pos >= from && g->pos < to) { + if (lbearing && width + g->lbearing < *lbearing) + *lbearing = width + g->lbearing; if (rbearing && width + g->rbearing > *rbearing) *rbearing = width + g->rbearing; width += g->width; @@ -1386,8 +1435,10 @@ render_glyph_string (MFrame *frame, MDrawWindow win, int x, int y, int from_idx, to_idx; int to_x; + if (from == to) + return; if (control->orientation_reversed) - x -= gstring->indent + gstring_width (gstring, from, to, NULL); + x -= gstring->indent + gstring_width (gstring, from, to, NULL, NULL); else x += gstring->indent; @@ -1503,6 +1554,9 @@ alloc_gstring (MFrame *frame, MText *mt, int pos, MDrawControl *control, return gstring; } +static MGlyph *find_glyph_in_gstring (MGlyphString *gstring, int pos, + int forwardp); + /* Truncate the line width of GSTRING to GSTRING->width_limit. */ static void @@ -1536,16 +1590,26 @@ truncate_gstring (MFrame *frame, MText *mt, MGlyphString *gstring) if (gstring->control.line_break) { pos = (*gstring->control.line_break) (mt, gstring->from + i, - gstring->from, gstring->from + i, 0, 0); + gstring->from, gstring->from + i, + 0, 0); if (pos <= gstring->from) - pos = gstring->from + 1; + { + g = find_glyph_in_gstring (gstring, gstring->from, 1); + pos = g->to; + } 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); + { + g = find_glyph_in_gstring (gstring, gstring->from, 1); + pos = g->to; + } + if (pos < gstring->to) + { + compose_glyph_string (frame, mt, gstring->from, pos, gstring); + layout_glyph_string (frame, gstring); + } } @@ -1742,100 +1806,6 @@ find_glyph_in_gstring (MGlyphString *gstring, int pos, int forwardp) return g; } -#define GET_LB_TYPE(MT, POS, LB_TYPE) \ - do { \ - int c = mtext_ref_char ((MT), (POS)); \ - (LB_TYPE) = ((c == ' ' || c == '\t' || c == '\n') ? M_kinsoku_bol \ - : mchartable_lookup (linebreak_table, c)); \ - } while (0) - -static int -find_break_backward (MText *mt, int pos, int limit) -{ - MSymbol lb_type; - - if (pos <= limit) - return limit; - - GET_LB_TYPE (mt, pos, lb_type); - if (lb_type == M_kinsoku_bol) - return find_break_backward (mt, pos - 1, limit); - if (lb_type == Mnil) - { - while (pos > limit) - { - GET_LB_TYPE (mt, pos - 1, lb_type); - if (lb_type != Mnil) - break; - pos--; - } - } - else if (lb_type == M_break_at_word) - { - int beg = limit, end = mtext_nchars (mt); - int in_word = mtext__word_segment (mt, pos, &beg, &end); - - if (in_word) - pos = beg; - else if (beg > limit) - { - end = beg; - beg = limit; - mtext__word_segment (mt, beg - 1, &beg, &end); - pos = beg; - } - } - while (pos > limit) - { - GET_LB_TYPE (mt, pos - 1, lb_type); - if (lb_type != M_kinsoku_eol) - return pos; - pos--; - } - return limit; -} - -static int -find_break_forward (MText *mt, int pos, int limit) -{ - MSymbol lb_type; - - GET_LB_TYPE (mt, pos, lb_type); - if (lb_type == Mnil) - { - while (pos < limit) - { - pos++; - GET_LB_TYPE (mt, pos, lb_type); - } - } - else if (lb_type == M_break_at_word) - { - int beg = 0, end = mtext_nchars (mt); - int in_word = mtext__word_segment (mt, pos, &beg, &end); - - if (! in_word) - pos = end; - else if (end < limit) - { - beg = end; - pos = end = mtext_nchars (mt); - mtext__word_segment (mt, pos, &beg, &end); - pos = end; - } - } - else if (lb_type == M_kinsoku_bol) - pos++; - while (pos < limit) - { - GET_LB_TYPE (mt, pos, lb_type); - if (lb_type != M_kinsoku_bol) - return pos; - pos++; - } - return limit; -} - /* for debugging... */ char work[16]; @@ -1910,7 +1880,7 @@ mdraw__init () memset (&scratch_gstring, 0, sizeof (scratch_gstring)); MLIST_INIT1 (&scratch_gstring, glyphs, 3); - Minherited = msymbol ("inherited"); + Mcommon = msymbol ("common"); McatCc = msymbol ("Cc"); McatCf = msymbol ("Cf"); @@ -1921,6 +1891,7 @@ mdraw__init () MbidiRLO = msymbol ("RLO"); MbidiBN = msymbol ("BN"); MbidiS = msymbol ("S"); + MbidiNSM = msymbol ("NSM"); #ifdef HAVE_FRIBIDI fribidi_set_mirroring (TRUE); #endif @@ -2283,7 +2254,7 @@ mdraw_text_extents (MFrame *frame, { MGlyphString *gstring; int y = 0; - int width, rbearing; + int width, lbearing, rbearing; ASSURE_CONTROL (control); M_CHECK_POS_X (mt, from, -1); @@ -2295,52 +2266,49 @@ mdraw_text_extents (MFrame *frame, gstring = get_gstring (frame, mt, from, to, control); if (! gstring) MERROR (MERROR_DRAW, -1); - width = gstring_width (gstring, from, to, &rbearing); + width = gstring_width (gstring, from, to, &lbearing, &rbearing); if (overall_ink_return) - { - overall_ink_return->y = - gstring->physical_ascent; - overall_ink_return->x = gstring->lbearing; - } + overall_ink_return->y = - gstring->physical_ascent; if (overall_logical_return) - { - overall_logical_return->y = - gstring->ascent; - overall_logical_return->x = 0; - } + overall_logical_return->y = - gstring->ascent; if (overall_line_return) - { - overall_line_return->y = - gstring->line_ascent; - overall_line_return->x = gstring->lbearing; - } + overall_line_return->y = - gstring->line_ascent; for (from = gstring->to; from < to; from = gstring->to) { - int this_width, this_rbearing; + int this_width, this_lbearing, this_rbearing; y += gstring->line_descent; M17N_OBJECT_UNREF (gstring->top); gstring = get_gstring (frame, mt, from, to, control); - this_width = gstring_width (gstring, from, to, &this_rbearing); + this_width = gstring_width (gstring, from, to, + &this_lbearing, &this_rbearing); y += gstring->line_ascent; if (width < this_width) width = this_width; if (rbearing < this_rbearing) rbearing = this_rbearing; + if (lbearing > this_lbearing) + lbearing = this_lbearing; } if (overall_ink_return) { - overall_ink_return->width = rbearing; + overall_ink_return->x = lbearing; + overall_ink_return->width = rbearing - lbearing; overall_ink_return->height = y + gstring->physical_descent - overall_ink_return->y; } if (overall_logical_return) { + overall_logical_return->x = 0; overall_logical_return->width = width; overall_logical_return->height = y + gstring->descent - overall_logical_return->y; } if (overall_line_return) { - overall_line_return->width = MAX (width, rbearing); + overall_line_return->x = lbearing; + overall_line_return->width = MAX (width, rbearing - lbearing); overall_line_return->height = y + gstring->line_descent - overall_line_return->y; } @@ -2703,7 +2671,7 @@ mdraw_glyph_info (MFrame *frame, MText *mt, int from, int pos, info->metrics.height = gstring->height; info->metrics.width = - g->lbearing + g->width; if (g->rface->rfont) - info->font = &g->rface->rfont->font; + info->font = (MFont *) g->rface->rfont; else info->font = NULL; /* info->logical_width is calculated later. */ @@ -2715,7 +2683,8 @@ mdraw_glyph_info (MFrame *frame, MText *mt, int from, int pos, info->prev_from = g_tmp->pos; } - else if (info->line_from > 0) + else if (info->line_from > 0 + && gstring->from > 0) { /* The logically previous glyph is on the previous line. */ MGlyphString *gst = get_gstring (frame, mt, gstring->from - 1, @@ -2908,8 +2877,11 @@ mdraw_glyph_list (MFrame *frame, MText *mt, int from, int to, glyphs->y_advance = 0; if (g->rface->rfont) { - glyphs->font = &g->rface->rfont->font; - glyphs->font_type = g->rface->rfont->type; + glyphs->font = (MFont *) g->rface->rfont; + glyphs->font_type + = (glyphs->font->source == MFONT_SOURCE_X ? Mx + : g->rface->rfont->driver == &mfont__ft_driver ? Mfreetype + : Mxft); glyphs->fontp = g->rface->rfont->fontp; } else @@ -2975,23 +2947,33 @@ mdraw_text_items (MFrame *frame, MDrawWindow win, int x, int y, } /*=*/ -/***en - @brief calculate a line breaking position. - - The function mdraw_default_line_break () calculates a line - breaking position based on the line number $LINE and the - coordinate $Y, when a line is too long to fit within the width - limit. $POS is the position of the character next to the last - one that fits within the limit. $FROM is the position of the - first character of the line, and $TO is the position of the last - character displayed on the line if there were not width limit. - $LINE and $Y are reset to 0 when a line is broken by a newline - character, and incremented each time when a long line is broken - because of the width limit. +/***en + @brief Option of line breaking for drawing text. - @return - This function returns a character position to break the - line. + The variable #mdraw_line_break_option specifies line breaking + options by logical-or of the members of #MTextLineBreakOption. It + controls the line breaking algorithm of the function + mdraw_default_line_break (). */ + +int mdraw_line_break_option; + +/*=*/ +/***en + @brief Calculate a line breaking position. + + The function mdraw_default_line_break () calculates a line + breaking position based on the line number $LINE and the + coordinate $Y, when a line is too long to fit within the width + limit. $POS is the position of the character next to the last one + that fits within the limit. $FROM is the position of the first + character of the line, and $TO is the position of the last + character displayed on the line if there were not width limit. + $LINE and $Y are reset to 0 when a line is broken by a newline + character, and incremented each time when a long line is broken + because of the width limit. + + @return This function returns a character position to break the + line. */ /***ja @@ -3013,32 +2995,14 @@ int mdraw_default_line_break (MText *mt, int pos, int from, int to, int line, int y) { - int p; - - if (! linebreak_table) - { - MDatabase *mdb = mdatabase_find (Mchar_table, Msymbol, - msymbol ("linebreak"), Mnil); - - if (mdb) - linebreak_table = mdatabase_load (mdb); - if (! linebreak_table) - linebreak_table = mchartable (Msymbol, Mnil); - } - - if (pos > from) - { - p = find_break_backward (mt, pos, from); - if (p > from) - return p; - } - if (pos < to) - { - p = find_break_forward (mt, pos, to); - if (p < to) - return p; - } - return to; + int p, after; + + p = mtext_line_break (mt, pos, mdraw_line_break_option, &after); + if (p < from) + p = from; + else if (p >= to) + p = to; + return p; } /*=*/