#include "m17n-misc.h"
#include "internal.h"
#include "symbol.h"
+#include "mtext.h"
#include "textprop.h"
#include "internal-gui.h"
#include "face.h"
/* Special categories */
static MSymbol McatCc, McatCf;
+static MCharTable *linebreak_table;
+static MSymbol M_break_at_space, M_break_at_word, M_break_at_any;
+static MSymbol M_kinsoku_bol, M_kinsoku_eol;
+
\f
/* Glyph-string composer. */
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);
+ if (pos < mtext_nchars (mt))
+ {
+ 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);
+ }
+ else
+ rface = default_rface;
}
stop = to;
if (stop > face_change)
if (gstring->control.line_break)
{
pos = (*gstring->control.line_break) (mt, gstring->from + i,
- gstring->from, gstring->to, 0, 0);
+ gstring->from, gstring->from + i, 0, 0);
if (pos <= gstring->from)
pos = gstring->from + 1;
else if (pos >= gstring->to)
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;
+}
+
\f
/* for debugging... */
char work[16];
fribidi_set_mirroring (TRUE);
#endif
+ M_break_at_space = msymbol ("bs");
+ M_break_at_word = msymbol ("bw");
+ M_break_at_any = msymbol ("ba");
+ M_kinsoku_bol = msymbol ("kb");
+ M_kinsoku_eol = msymbol ("ke");
+
return 0;
}
mdraw__fini ()
{
MLIST_FREE1 (&scratch_gstring, glyphs);
+ M17N_OBJECT_UNREF (linebreak_table);
+ linebreak_table = NULL;
}
/*** @} */
mdraw_default_line_break (MText *mt, int pos,
int from, int to, int line, int y)
{
- int c = mtext_ref_char (mt, pos);
- int orig_pos = pos;
+ int p;
- if (c == ' ' || c == '\t')
+ if (! linebreak_table)
{
- pos++;
- while (pos < to
- && ((c = mtext_ref_char (mt, pos)) == ' ' || c == '\t'))
- pos++;
+ 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);
}
- else
+
+ if (pos > from)
{
- while (pos > from)
- {
- if (c == ' ' || c == '\t')
- break;
- pos--;
- c = mtext_ref_char (mt, pos);
- }
- if (pos == from)
- pos = orig_pos;
- else
- pos++;
+ 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 pos;
+ return to;
}
/*=*/