merge FLT after-FLT-merge
authorhanda <handa>
Tue, 13 Nov 2007 02:29:20 +0000 (02:29 +0000)
committerhanda <handa>
Tue, 13 Nov 2007 02:29:20 +0000 (02:29 +0000)
40 files changed:
ChangeLog
Makefile.am
configure.ac
example/.gdb.util
example/ChangeLog
example/Makefile.am
example/mdump.c
m17n-flt.pc.in [new file with mode: 0644]
src/ChangeLog
src/Makefile.am
src/character.c
src/charset.c
src/chartab.c
src/coding.c
src/database.c
src/database.h
src/draw.c
src/face.c
src/font-flt.c
src/font-ft.c
src/font.c
src/font.h
src/fontset.c
src/input.c
src/internal-flt.h [new file with mode: 0644]
src/internal-gui.h
src/internal.h
src/m17n-X.c
src/m17n-core.c
src/m17n-core.h
src/m17n-flt.c [new file with mode: 0644]
src/m17n-flt.h [new file with mode: 0644]
src/m17n-gd.c
src/m17n-gui.c
src/m17n-gui.h
src/m17n-misc.h
src/m17n.c
src/m17n.h
src/plist.c
src/symbol.c

index d65909f..c289940 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2007-10-12  Kenichi Handa  <handa@m17n.org>
+
+       * m17n-flt.pc.in: Don't require m17n-shell.
+
+2007-08-15  Kenichi Handa  <handa@m17n.org>
+
+       * m17n-flt.pc.in (prefix): New file.
+
+       * configure.ac (AC_CONFIG_FILES): Add m17n-flt.pc.
+
+       * Makefile.am (EXTRA_DIST): Add m17n-flt.pc.in.
+       (BASICDATA): Add m17n-flt.pc.
+
 2007-07-13  Kenichi Handa  <handa@m17n.org>
 
        * Version 1.4.0 released.
index 88a5aa0..10b0ea6 100644 (file)
@@ -27,11 +27,11 @@ SUBDIRS = intl po src example
 bin_SCRIPTS = m17n-config
 
 EXTRA_DIST = m4/ChangeLog config.rpath mkinstalldirs \
-       m17n-core.pc.in m17n-shell.pc.in m17n-gui.pc.in bootstrap.sh
+       m17n-core.pc.in m17n-shell.pc.in m17n-flt.pc.in m17n-gui.pc.in bootstrap.sh
 
 pkgconfigdir = ${libdir}/pkgconfig
 
-BASICDATA = m17n-core.pc m17n-shell.pc
+BASICDATA = m17n-core.pc m17n-shell.pc m17n-flt.pc
 if WITH_GUI
 PKGDATA = $(BASICDATA) m17n-gui.pc
 else
index 2f9dd87..9c84512 100644 (file)
@@ -436,6 +436,7 @@ AC_CONFIG_FILES([Makefile po/Makefile.in intl/Makefile
                 m17n-config
                 m17n-core.pc
                 m17n-shell.pc
+                m17n-flt.pc
                 m17n-gui.pc
                 ])
 
index 9fafb7c..efc3b4b 100644 (file)
@@ -39,7 +39,12 @@ echo \n
 end
 
 define xgstring
-set dump_gstring (gstring, 0)
+set dump_gstring (gstring, 0, 0)
+echo \n
+end
+
+define xgstr
+set dump_gstring ($arg0, 0, 1)
 echo \n
 end
 
index 9c415a0..cafa4f9 100644 (file)
@@ -1,3 +1,15 @@
+2007-10-29  Kenichi Handa  <handa@m17n.org>
+
+       * Makefile.am (common_ldflags_gui): Add
+       ${top_builddir}/src/libm17n-flt.la.
+
+       * .gdb.util (xgstring): Adjusted for the change of dump_gstring.
+       (xgtr): New command.
+
+2007-09-18  Kenichi Handa  <handa@m17n.org>
+
+       * mdump.c (main): Use "generic" fontset by default.
+
 2007-07-13  Kenichi Handa  <handa@m17n.org>
 
        * Version 1.4.0 released.
index d81069e..baceac3 100644 (file)
@@ -33,7 +33,7 @@ bin_PROGRAMS = $(BASICPROGS)
 endif
 
 common_ldflags = ${top_builddir}/src/libm17n-core.la ${top_builddir}/src/libm17n.la
-common_ldflags_gui = ${common_ldflags} ${top_builddir}/src/libm17n-gui.la
+common_ldflags_gui = ${common_ldflags} ${top_builddir}/src/libm17n-flt.la ${top_builddir}/src/libm17n-gui.la
 AM_CPPFLAGS=@CONFIG_FLAGS@
 
 m17n_date_SOURCES = mdate.c
index f05075b..a53cd7e 100644 (file)
@@ -486,7 +486,7 @@ main (int argc, char **argv)
   MDrawMetric rect;
   char *filename = "output";
   int len, from;
-  char *fontset_name = "truetype";
+  char *fontset_name = "generic";
 
 
   /* Parse the command line arguments.  */
diff --git a/m17n-flt.pc.in b/m17n-flt.pc.in
new file mode 100644 (file)
index 0000000..e6ceeb8
--- /dev/null
@@ -0,0 +1,12 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+version=@PACKAGE_VERSION@
+
+Name: m17n-flt
+Description: FLT API suport of the m17n library.
+Version: ${version}
+Requires: m17n-core = ${version}
+Libs: -L${libdir} -lm17n-core -lm17n-flt
+Cflags: -I${includedir}
index 19dd341..f6fdf8e 100644 (file)
@@ -1,6 +1,482 @@
-2007-08-14  Kenichi Handa  <handa@m17n.org>
+2007-11-12  Kenichi Handa  <handa@ni.aist.go.jp>
+
+       * font-ft.c (ft_check_otf): Fix arg to OTF_check_features.
+
+       * m17n-flt.c (Mcombining): New variable.
+       (Mfont_facility): Renamed from Mfont_has.  Referrer changed.
+       (enum FontLayoutCmdRuleSrcType): Delete SRC_EXIST, add
+       SRC_HAS_GLYPH and SRC_OTF_SPEC.
+       (FontLayoutCmdRule): Delete src.exist, add src.supported_glyph and
+       src.otf_spec.
+       (load_command): Adjusted for the above changes.
+       (run_rule): Likewise.
+       (combining_code_from_class): Delete it.
+       (mflt_get): Check flt->name against Mcombining, not Mt.
 
-       * font-ft.c (mfont__ft_drive_otf): Fix arg to OTF_check_features.
+       * internal-flt.h (Mcombining): Extern it.
+
+       * draw.c (compose_glyph_string): Call run_flt with Mcombining for
+       combining characters.
+
+2007-11-09  Kenichi Handa  <handa@ni.aist.go.jp>
+
+       * face.c (mface__realize): Reset measured flag before calling
+       mfont__get_metric.
+
+       * m17n-flt.c (run_stages): Fix handing of off_x and off_y.
+       (setup_combining_coverage): New function.
+       (setup_combining_flt): New function.
+       (mflt_get): If flt is not found, return NULL.  If name if Mt,
+       call setup_combining_flt.
+       (mflt_run): For debugging, print font family name.
+
+       * font-ft.c (ft_render): Fix handling of baseline_offset.
+       (ft_encapsulate): Set metrics in 26.6 fixed pixel.
+       (ft_render): Check pixel_mode to determine anti_alias.
+
+       * m17n-X.c (xfont_find_metric): Delete invalid "continue" line.
+       (xfont_find_metric): Set metrics in 26.6 fixed pixel.
+       (xfont_render): Set baseline_offset in pixel.
+       (xft_render): Fix handling of baseline_offset.
+
+       * draw.c (run_flt): Set font.font.family.
+       (compose_glyph_string): Fix handling of combining characters.
+
+       * fontset.c (try_font_list): Check if the named flt is surely
+       available.
+
+2007-11-07  Kenichi Handa  <handa@ni.aist.go.jp>
+
+       * draw.c (analyse_bidi_level): New function.
+       (visual_order): Do reordering using the already decided
+       bidi-level.
+       (compose_glyph_string): Decide bidi-level before calling flt.
+
+       * m17n-flt.c (mflt_run): Fix typo.
+
+       * font-ft.c (ft_drive_otf): Fix indexing gstring->glyphs.
+
+2007-11-06  Kenichi Handa  <handa@ni.aist.go.jp>
+
+       * draw.c (visual_order): Don't rely on the width of glyphs.
+       (run_flt): Fix culculation of g->g.to.
+
+       * m17n-flt.c (run_rule): Don't set error code here.
+       (run_cond): Likewise.
+       (run_otf): Fix culculation of xoff and yoff.
+       (run_command): Don't set error code here.
+       (PREV): New macro.
+       (NEXT): New macro.
+
+       * m17n-X.c (xfont_open): Keep rfont's metrics in 26.6 fixed pixels.
+       (xfont_find_metric): Set glyph's yadv to 0.
+       (xft_find_metric): Likewise.
+
+       * font-ft.c (ft_open): Keep rfont's metrics in 26.6 fixed pixels.
+       (ft_find_metric): Adjust glyph's metrics.
+       (ft_encapsulate): Keep rfont's metrics in 26.6 fixed pixels.
+       (ft_drive_otf): Set mark glyph's xadv to 0.
+
+       * face.c (mface__for_chars): Adjusts the unit of face's ascent and
+       descent.
+
+2007-10-29  Kenichi Handa  <handa@m17n.org>
+
+       * m17n-flt.h (struct _MFLTOtfSpec): Adjusted for the new FLT handling.
+       (mflt_get): Adjusted for the argument change.
+       (mflt_name): Adjusted for the return value change.
+
+       * m17n-flt.c (Mgenerator, Mend): New variables.
+       (flt_min_coverage, flt_max_coverage): New variables.
+       (GCPY): New macro.
+       (GDUP): Use it.
+       (Mfont_has): Renamed from Mexist.  Referrers chagned.
+       (gen_otf_tag): Handle the trailing whitespaces.
+       (otf_count_features, otf_store_features): Fix for negative features.
+       (parse_otf_command): Adjusted for the change of MFLTOtfSpec.
+       (load_otf_command): Likewise.
+       (free_flt_command): Adjusted for the change of MFLTOtfSpec.
+       (load_flt): Argument changed.  Caller changed.
+       (free_flt_list): New function.
+       (run_rule): Adjusted for the change of FontLayoutContext.
+       (mflt_run): Adjusted for the change of FontLayoutContext.
+
+       * m17n-gui.c (m17n_init_win): Call m17n_init_flt.
+       (m17n_fini_win): Call m17n_fini_flt.
+
+       * m17n-gui.h: Include m17n-flt.h.
+
+       * m17n-gd.c: Adusted for the change of MGlyph.
+
+       * m17n-X.c: Adusted for the change of MGlyph.
+       (xft_check_otf, xft_drive_otf): New functions.
+
+       * internal-gui.h (MGlyph): Modified for new FLT handling.
+
+       * fontset.c (try_font_list): Adusted for the change of MGlyph.
+
+       * font-ft.c: Adjusted for the change of MGlyph.
+       (ft_check_cap_otf): Renamed from ft_check_otf.  Callers changed.
+       (get_glyph_metric): Deleted.
+       (ft_check_otf): New function.
+       (ft_drive_otf): New fucntion.
+
+       * font.c: Adjusted for the change of MGlyph.
+       (mfont__init): Don't call mfont__flt_init.
+       (mfont__fini): Don't call mfont__flt_fini.
+       (mfont__get_glyph_id, mfont__get_metrics): New functions.
+
+       * font.h (struct MRealizedFont): New members x_ppem and y_ppem.
+       (MFLTFontForRealized): New struct.
+       (struct MFontDriver): New members check_otf and drive_otf.
+       (mfont__get_glyph_id, mfont__get_metrics): Extern them.
+
+       * face.c: Adjusted for the change of MGlyph.
+
+       * draw.c: Adjusted for the change of MGlyph.
+
+       * m17n.c (m17n_init): Don't call mchar_init.
+
+       * m17n-core.c (m17n_init_core): Call mchar_init.
+
+       * m17n-core.h (mchartable_min_char, mchartable_max_char): Extern them.
+
+       * input.c: Include "m17n.h" instead of "m17n-gui.h".
+
+       * chartab.c (mchartable): Initialize table->min_char to -1.
+       (mchartable_min_char): New function.
+       (mchartable_max_char): New function.
+
+       * Makefile.am (GUI_SOURCES): Delete font-flt.c.
+       (libm17n_gui_la_LIBADD): Add ${top_builddir}/src/libm17n-flt.la.
+
+2007-10-12  Kenichi Handa  <handa@m17n.org>
+
+       * m17n-core.h (Mcharset): Extern it.
+       Move detabase related declarations from m17n.h.
+
+       * m17n-flt.h: Include m17n-core.h instead of m17n.h.
+       (struct _MFLTOtfFeatures): New struct.
+       (struct _MFLTOtfSpec): Delete gsub, gpos, etc, add gsub_gpos.
+       (struct _MFLTFont): Delete otf, add check_otf.
+       (MCHAR_INVALID_CODE): Define it.
+
+       * plist.c (read_mtext_element): Simplify the code.
+
+       * m17n.h: Move database related declarations to m17n-core.h
+       (Mharset): Don't extern it.
+
+       * m17n.c (m17n_init): Don't call mdatabase__init.
+
+       * m17n-gd.c (read_rgb_txt): Check also /etc/X11/rgb.txt.  Downcase
+       color names.
+
+       * m17n-flt.c: Include m17n-core.h instead of m17n.h.
+       (Mexist): New variable.
+       (enum FontLayoutCmdRuleSrcType): New enum SRC_EXIST.
+       (FontLayoutCmdRule): New member src.exist.
+       (parse_otf_command): Handle gsub_count and gpos_count separately.
+       (load_otf_command): Adjusted for the change of MFLTOtfSpec.
+       (load_command): Handle the command "exist".
+       (free_flt_command): Adjusted for the change of MFLTOtfSpec.
+       (run_rule): Handle the case SRC_EXIST.
+       (run_otf): Adjusted for the change of MFLTOtfSpec.
+       (run_command): Check the range of FROM.
+       (check_otf_spec): Delete it.
+       (m17n_init_flt): Call m17n_init_core instead of m17n_init.
+       Initialize Mexist.
+       (m17n_fini_flt): Call m17n_fini_core instead of m17n_fiini.
+       (mflt_find): Call font->check_otf instead of check_otf_spec.
+       (mflt_run): Keep the metrics in 26.6 fixed point.
+
+       * m17n-core.c (mdatabase__finder, mdatabase__loader): Delete them.
+       (m17n_init_core): Call mdatabase__init.
+
+       * m17n-X.c (device_open): Use mplist_add, not mplist_push.
+
+       * internal.h (mdatabase__finder, mdatabase__loader): Delete externs
+       of them.
+
+       * font-flt.c (Mexist): New variable.
+       (enum FontLayoutCmdRuleSrcType): New enum SRC_EXIST.
+       (FontLayoutCmdRule): New member src.exist.
+       (load_category_table): Use isalnum, not isalpha.
+       (load_command): Check the command "exist".
+       (run_rule): Hande the case SRC_EXIST.
+       (run_command): Check the range of FROM.
+       (mfont__flt_init): Initialize Mexist.
+
+       * draw.c (layout_glyphs): Fix calculation of off_x and off_y.
+
+       * database.h (mdatabase__load_charset_func): Extern it.
+
+       * database.c: Include m17n-core.h instead of m17n.h.
+       (load_chartable): Use mtext__from_data.
+       (load_charset): Moved to charset.c
+       (load_database): Call mdatabase__load_charset_func instead of
+       load_charset.
+       (mdatabase__load_charset_func): New variable.
+       (mdatabase__init): Initialize mdatabase__load_charset_func and
+       Mcharset.  Don't set mdatabase__finder and mdatabase__loader.
+       (mdatabase__save): Use fwrite, not mconv_encode_stream.
+       (Mcharset): Declare it here.
+
+       * charset.c: Include "database.h.".
+       (load_charset): Moved from database.c.
+       (mcharset__init): Initialize mdatabase__load_charset_func, don't
+       initialize Mcharset.
+
+       * character.c (mchar_define_property): Call mdatabase_find directly.
+       (mchar_get_prop): Call mdatabase_add directly.
+       (mchar_put_prop): Call mdatabase_load directly.
+       (mchar_get_prop_table): Likewise.
+
+       * Makefile.am (libm17n_core_la_SOURCES): Add database.[ch].
+       (libm17n_la_SOURCES): Remove database.[ch].
+       (libm17n_flt_la_LIBADD): Delete libm17n.la, add libm17n-core.la.
+
+2007-09-18  Kenichi Handa  <handa@m17n.org>
+
+       * face.c (mface__realize): Try Freetype based font at first.
+
+       * font.c: Include <ctype.h>
+
+2007-09-16  Kenichi Handa  <handa@m17n.org>
+
+       * m17n-flt.c (load_flt): New arg full.  If full is zero, load only
+       coverage.
+       (run_otf): Call font->get_metrics, not font->get_metric.
+       (run_stages): Likewise.
+       (CHECK_FLT_COVERAGE): New macro.
+       (CHECK_FLT_STAGES): Call load_flt with the second arg 1.
+       (check_otf_spec): New function.
+       (m17n_fini_flt): Unref flt->coverage.
+       (mflt_find): Argument changed.
+       (mflt_name): New function.
+       (mflt_coverage): Use CHECK_FLT_COVERAGE.
+
+       * m17n-flt.h (MFLTFont): Member get_metrics renamed from get_metric.
+       (mflt_find): Prototype adjusted.
+       (mflt_name): Extern it.
+
+2007-09-14  Kenichi Handa  <handa@m17n.org>
+
+       * m17n-flt.h (struct _MFLTGlyph): Change signedness of members.
+
+       * font-flt.c (run_otf): Make debug info printing comaptible with
+       that of m17n-flt.c.
+       (run_command): Likewise.
+       (mfont__flt_run): Likewise.
+
+       * m17n-flt.c (UPDATE_CLUSTER_RANGE): ctx->cluster_begin_idx is
+       invalid only when it's negative.
+       (run_otf): Likewise.
+       (run_command): Likewise.
+       (mflt_run): Initialize ctx.cluster_begin_idx to -1.
+
+2007-09-10  Kenichi Handa  <handa@m17n.org>
+
+       * m17n-flt.h (struct _MFLTGlyph): New member encoded and measured.
+       (struct _MFLTFont): Prototype of get_glyph_id changed.
+
+       * m17n-flt.c (enum GlyphInfoMask): Delete EncodedMask and
+       PositionedMask.
+       (GAPPEND): Delete this macro.
+       (GET_ENCODED, SET_ENCODED, GET_MEASURED, SET_MEASURED): Adjusted
+       for the change of MFLTGlyph.  Caller changed.
+       (run_otf): Simply calls font->get_glyph_id.
+       (run_command): Reset g->encoded and g->measured for direct code.
+       (positioning): Delete this function.
+       (run_stages): Simply calls font->get_glyph_id and font->get_metric.
+
+2007-09-07  Kenichi Handa  <handa@m17n.org>
+
+       * draw.c (compose_glyph_string): Improve script detection.
+
+2007-09-06  Kenichi Handa  <handa@m17n.org>
+
+       * m17n-flt.h (mflt_get): Extern it.
+
+       * m17n-flt.c (run_stages): Call positioning only if
+       font->get_metric is non-NULL.
+       (CHECK_FLT_STAGES): Fix typo.
+       (mflt_get): New function.
+
+       * font-flt.c (mfont__flt_run): Improve debug info printing.
+
+2007-09-04  Kenichi Handa  <handa@m17n.org>
+
+       * m17n-flt.c (MFontLayoutTable): Delete this type.
+       (struct _MFLT): New member mdb and coverage.
+       (list_flt): Set flt->mdb.
+       (load_generator): Argument and return value changed.  Caller
+       changed.
+       (get_font_layout_table): Delete this function.
+       (run_stages): Argument changed.  Caller changed.
+       (CHECK_FLT_STAGES): New macro.
+       (mfont__flt_encode_char): Argument changed.
+       (mflt_find): Likewise.
+       (mflt_coverage): New function.
+       (mflt_run): Argument changed.
+       (mdebug_dump_flt): Likewise.
+
+       * m17n-flt.h (mflt_coverage): Extern it.
+       (mflt_find): Prototype adjusted.
+
+2007-09-03  Kenichi Handa  <handa@m17n.org>
+
+       * internal.h (MTABLE_CALLOC_SAFE, MSTRUCT_CALLOC_SAFE): New macros.
+
+       * database.c (mdatabase__props): New function.
+
+       * database.h (mdatabase__props): Extern it.
+
+       * m17n-flt.h (struct _MFLTGlyphString): Delete user_data, add
+       script and langsys.
+       (struct _MFLTFont): Add suitable_p.
+       (mflt_find): Extern it.
+
+       * m17n-flt.c: Include "database.h".
+       (struct _MFLT): New struct.
+       (list_flt): New function.
+       (load_flt): Don't update flt_list.
+       (get_font_layout_table): Use flt_list.
+       (m17n_init_flt): Don't initialize flt_list.
+       (m17n_fini_flt): Adjusted for the change of flt_list.
+       (mflt_find): New function.
+       (mflt_run): Fix debug printing.
+
+2007-08-23  Kenichi Handa  <handa@m17n.org>
+
+       * m17n-flt.c (run_otf): Remove #ifdef HAVE_OTF and #endi.
+       (run_stages): Print separator in encoded string as "|".
+
+2007-08-23  Kenichi Handa  <handa@m17n.org>
+
+       * font-flt.c (mfont__flt_run): Don't calculate a glyph metric if
+       the glyph is already handled by OTF.
+
+2007-08-21  Kenichi Handa  <handa@m17n.org>
+
+       * font-ft.c (ft_check_capability): Check cap->script_tag at first.
+
+2007-08-20  Kenichi Handa  <handa@m17n.org>
+
+       * font-flt.c (mfont__flt_run): Get glyph metrics before printing
+       debug information.
+
+2007-08-17  Kenichi Handa  <handa@m17n.org>
+
+       * m17n-flt.h (struct _MFLTGlyphString): Member pointer renamed to
+       user_data.
+       (MFLTOtfSpec): Renamed from MFLT_OTF_Spec.
+       (MFLTFont): Prototype of the member drive_otf adjusted.
+
+       * m17n-flt.c (run_stages): Fix handling of padding.
+
+       * font-ft.c (get_glyph_metric): New function.
+       (DEVICE_DELTA): Return 26.6 fixed point value.
+       (adjust_anchor): Likewise.
+       (mfont__ft_drive_otf): Use get_glyph_metric.
+
+       * font-flt.c (mfont__flt_run): Pay attention to padding on
+       printing debug info.
+
+2007-08-16  Kenichi Handa  <handa@m17n.org>
+
+       * m17n-flt.c (run_stages): Fix typo.
+
+       * font-ft.c (adjust_anchor): Argument changed.  Calculte based on
+       26.6 fixed point.
+       (mfont__ft_drive_otf): Don't call OTF_check_features for GPOS.
+       Adjusted for the argument change of adjust_anchor.  Calculte based
+       on 26.6 fixed point.
+
+2007-08-15  Kenichi Handa  <handa@m17n.org>
+
+       * charset.c (mcharset__load_from_database): Set mdebug_flag
+       instead of mdebug_mask.
+
+       * coding.c (mcoding__load_from_database): Set mdebug_flag instead
+       of mdebug_mask.
+
+       * database.c (load_database): Set mdebug_flag instead of
+       mdebug_mask.
+       (mdatabase__load_for_keys): Likewise.
+
+       * draw.c: Include "internal-flt.h".
+       (dump_combining_code): Don't subtract 128 from combining code
+       off_x/y.
+
+       * font-flt.c: Include "internal-flt.h".  Set mdebug_flag instead
+       of mdebug_mask.
+       (run_rule): Print debug info only when MDEBUG_FLAG is greater than
+       2.
+       (run_cond): Likewise.
+       (run_otf): Likewise.
+       (run_command): Likewise.
+       (mfont__flt_run): Change format of debug info.
+
+       * font-ft.c: Include "internal-flt.h".
+       Set mdebug_flag instead of mdebug_mask.
+       (mfont__ft_drive_otf): Fix arg to OTF_check_features.
+
+       * input.c: Set mdebug_flag instead of mdebug_mask.
+       (shift_state): New MDEBUG_FLAG macro.
+       (preedit_commit): Likewise.
+       (filter): Likewise.
+
+       * internal-flt.h: New file.
+
+       * internal-gui.h (MAKE_COMBINING_CODE, COMBINING_CODE_OFF_Y)
+       (COMBINING_CODE_OFF_X, COMBINING_CODE_BASE_X)
+       (COMBINING_CODE_BASE_Y, COMBINING_CODE_ADD_X)
+       (COMBINING_CODE_ADD_Y, MAKE_COMBINING_CODE_BY_CLASS)
+       (COMBINING_BY_CLASS_P, COMBINING_CODE_CLASS)
+       (MAKE_PRECOMPUTED_COMBINDING_CODE, COMBINING_PRECOMPUTED_P): Move
+       these macros to internal-flt.h.
+
+       * internal.h (M17N_OBJECT_ADD_ARRAY): Adjusted for the change of
+       mdebug__flags.
+       (M17N_OBJECT_REGISTER, M17N_OBJECT_UNREGISTER): Likewise.
+       (enum MDebugMaskBit): Delete this enum.
+       (enum MDebugFlag): New enum.
+       (mdebug__flag): Don't extern it.
+       (mdebug__flags): Extern it.
+       (MDEBUG_FLAG): New macro.
+       (MDEBUG_PRINT0): Use the macro MDEBUG_FLAG.
+       (MDEBUG_DUMP, MDEBUG_PUSH_TIME, MDEBUG_POP_TIME)
+       (MDEBUG_PRINT_TIME): Likewise.
+
+       * m17n-X.c (xfont_open): Set mdebug_flag instead of mdebug_mask.
+       (xfont_list): Likewise.
+
+       * m17n-core.c (mdebug__flag): Delete this variable.
+       (mdebug__flags): New variable.
+       (SET_DEBUG_FLAG): Make it a function.
+       (m17n_init_core): Set mdebug_flag instead of mdebug_mask.
+       (m17n_fini_core): Likewise.
+
+       * m17n-gui.c (m17n_init_win): Set mdebug_flag instead of mdebug_mask.
+       (m17n_fini_win): Likewise.
+
+       * m17n-misc.h (enum MErrorCode): Add MERROR_FLT.
+
+       * m17n.c (m17n_init): Set mdebug_flag instead of mdebug_mask.
+       (m17n_fini): Likewise.
+
+       * symbol.c (msymbol__free_table): Adjusted for the change of
+       mdebug__flags.
+
+       * Makefile.am (BASICBUILDS): Add libm17n-flt.la.
+       (BASICHEADERS): Add m17n-flt.h.
+       (FLT_SOURCES): New variable.
+       (libm17n_flt_la_SOURCES, libm17n_flt_la_LIBADD)
+       (libm17n_flt_la_LDFLAGS): Likewise.
+
+       * m17n-flt.h: New file.
+
+       * m17n-flt.c: New file created by modifying font-flt.c.
 
 2007-07-13  Kenichi Handa  <handa@m17n.org>
 
index 43407f8..d626b86 100644 (file)
@@ -21,7 +21,7 @@
 
 VINFO = -version-info @API_VERSION@
 
-BASICBUILDS = libm17n-core.la libm17n.la
+BASICBUILDS = libm17n-core.la libm17n.la libm17n-flt.la
 if WITH_GUI
 BUILD_LIBS = $(BASICBUILDS) libm17n-gui.la libm17n-X.la libm17n-gd.la
 else
@@ -33,6 +33,7 @@ lib_LTLIBRARIES = $(BUILD_LIBS)
 libm17n_core_la_SOURCES = \
        character.h character.c \
        chartab.h chartab.c \
+       database.h database.c \
        internal.h \
        plist.h plist.c \
        m17n-core.h m17n-core.c \
@@ -48,7 +49,6 @@ libm17n_core_la_LDFLAGS = -export-dynamic ${VINFO}
 libm17n_la_SOURCES = \
        charset.h charset.c \
        coding.h coding.c \
-       database.h database.c \
        input.h input.c \
        language.h language.c \
        mlocale.h locale.c \
@@ -56,9 +56,16 @@ libm17n_la_SOURCES = \
 libm17n_la_LIBADD = ${top_builddir}/src/libm17n-core.la -ldl
 libm17n_la_LDFLAGS = -export-dynamic ${VINFO}
 
+FLT_SOURCES = \
+       m17n-flt.h m17n-flt.c
+
+libm17n_flt_la_SOURCES = ${FLT_SOURCES}
+libm17n_flt_la_LIBADD = ${top_builddir}/src/libm17n-core.la
+libm17n_flt_la_LDFLAGS = -export-dynamic ${VINFO}
+
 GUI_SOURCES = \
        face.h face.c \
-       font.h font.c font-ft.c font-flt.c \
+       font.h font.c font-ft.c \
        fontset.h fontset.c \
        draw.c \
        input-gui.c \
@@ -72,7 +79,7 @@ OPTIONAL_LD_FLAGS = \
        @FONTCONFIG_LD_FLAGS@
 
 libm17n_gui_la_SOURCES = ${GUI_SOURCES}
-libm17n_gui_la_LIBADD = ${OPTIONAL_LD_FLAGS} ${top_builddir}/src/libm17n.la
+libm17n_gui_la_LIBADD = ${OPTIONAL_LD_FLAGS} ${top_builddir}/src/libm17n-flt.la ${top_builddir}/src/libm17n.la
 libm17n_gui_la_LDFLAGS = -export-dynamic ${VINFO}
 
 X_LD_FLAGS = ${X_PRE_LIBS} ${X_LIBS} @X11_LD_FLAGS@ ${X_EXTRA_LIBS}
@@ -88,7 +95,7 @@ libm17n_gd_la_LDFLAGS = -module ${VINFO}
 AM_CPPFLAGS = -DM17NDIR=\"@M17NDIR@\" -DGETTEXTDIR=\"@GETTEXTDIR@\"
 
 
-BASICHEADERS = m17n-core.h m17n.h m17n-misc.h
+BASICHEADERS = m17n-core.h m17n.h m17n-misc.h m17n-flt.h
 if WITH_GUI
 include_HEADERS = $(BASICHEADERS) m17n-gui.h m17n-X.h
 else
index 96ce01e..abc3c39 100644 (file)
@@ -407,10 +407,9 @@ mchar_define_property (const char *name, MSymbol type)
   MSymbol key = msymbol (name);
   void *mdb;
 
-  if (mdatabase__finder)
-    mdb = (*mdatabase__finder) (Mchar_table, type, key, Mnil);
-  else
-    mdb = NULL;
+  mdb = mdatabase_find (Mchar_table, type, key, Mnil);
+  if (! mdb)
+    return Mnil;
   mchar__define_prop (key, type, mdb);
   return key;
 }
@@ -459,7 +458,7 @@ mchar_get_prop (int c, MSymbol key)
     return NULL;
   if (record->mdb)
     {
-      record->table = (*mdatabase__loader) (record->mdb);
+      record->table = mdatabase_load (record->mdb);
       if (! record->table)
        MERROR (MERROR_DB, NULL);
       record->mdb = NULL;
@@ -506,7 +505,7 @@ mchar_put_prop (int c, MSymbol key, void *val)
     return -1;
   if (record->mdb)
     {
-      record->table = (*mdatabase__loader) (record->mdb);
+      record->table = mdatabase_load (record->mdb);
       if (! record->table)
        MERROR (MERROR_DB, -1);
       record->mdb = NULL;
@@ -553,7 +552,7 @@ mchar_get_prop_table (MSymbol key, MSymbol *type)
     return NULL;
   if (record->mdb)
     {
-      record->table = (*mdatabase__loader) (record->mdb);
+      record->table = mdatabase_load (record->mdb);
       if (! record->table)
        MERROR (MERROR_DB, NULL);
       record->mdb = NULL;
index bf3cfc2..8675a31 100644 (file)
 #include "m17n-misc.h"
 #include "internal.h"
 #include "symbol.h"
-#include "charset.h"
-#include "coding.h"
+#include "database.h"
 #include "chartab.h"
 #include "plist.h"
+#include "charset.h"
+#include "coding.h"
 
 static int unified_max;
 
@@ -322,6 +323,84 @@ load_charset_fully (MCharset *charset)
   return 0;
 }
 
+/** Load a data of type @c charset from the file FD.  */
+
+static void *
+load_charset (FILE *fp, MSymbol charset_name)
+{
+  MCharset *charset = MCHARSET (charset_name);
+  int *decoder;
+  MCharTable *encoder;
+  int size;
+  int i, c;
+  int found = 0;
+  MPlist *plist;
+
+  if (! charset)
+    MERROR (MERROR_DB, NULL);
+  size = (charset->code_range[15]
+         - (charset->min_code - charset->code_range_min_code));
+  MTABLE_MALLOC (decoder, size, MERROR_DB);
+  for (i = 0; i < size; i++)
+    decoder[i] = -1;
+  encoder = mchartable (Minteger, (void *) MCHAR_INVALID_CODE);
+
+  while ((c = getc (fp)) != EOF)
+    {
+      unsigned code1, code2, c1, c2;
+      int idx1, idx2;
+      char buf[256];
+
+      ungetc (c, fp);
+      fgets (buf, 256, fp);
+      if (c != '#')
+       {
+         if (sscanf (buf, "0x%x-0x%x 0x%x", &code1, &code2, &c1) == 3)
+           {
+             idx1 = CODE_POINT_TO_INDEX (charset, code1);
+             if (idx1 >= size)
+               continue;
+             idx2 = CODE_POINT_TO_INDEX (charset, code2);
+             if (idx2 >= size)
+               idx2 = size - 1;
+             c2 = c1 + (idx2 - idx1);
+           }
+         else if (sscanf (buf, "0x%x 0x%x", &code1, &c1) == 2)
+           {
+             idx1 = idx2 = CODE_POINT_TO_INDEX (charset, code1);
+             if (idx1 >= size)
+               continue;
+             c2 = c1;
+           }
+         else
+           continue;
+         if (idx1 >= 0 && idx2 >= 0)
+           {
+             decoder[idx1] = c1;
+             mchartable_set (encoder, c1, (void *) code1);
+             for (idx1++, c1++; idx1 <= idx2; idx1++, c1++)
+               {
+                 code1 = INDEX_TO_CODE_POINT (charset, idx1);
+                 decoder[idx1] = c1;
+                 mchartable_set (encoder, c1, (void *) code1);
+               }
+             found++;
+           }
+       }
+    }
+
+  if (! found)
+    {
+      free (decoder);
+      M17N_OBJECT_UNREF (encoder);
+      return NULL;
+    }
+  plist = mplist ();
+  mplist_add (plist, Mt, decoder);
+  mplist_add (plist, Mt, encoder);
+  return plist;
+}
+
 \f
 /* Internal API */
 
@@ -344,6 +423,7 @@ mcharset__init ()
 
   unified_max = MCHAR_MAX;
 
+  mdatabase__load_charset_func = load_charset;
   mcharset__cache = mplist ();
   mplist_set (mcharset__cache, Mt, NULL);
 
@@ -354,8 +434,6 @@ mcharset__init ()
   memset (mcharset__iso_2022_table.classified, 0,
          sizeof (mcharset__iso_2022_table.classified));
 
-  Mcharset = msymbol ("charset");
-
   Mmethod = msymbol ("method");
   Moffset = msymbol ("offset");
   Mmap = msymbol ("map");
@@ -587,7 +665,7 @@ mcharset__load_from_database ()
   MDatabase *mdb = mdatabase_find (msymbol ("charset-list"), Mnil, Mnil, Mnil);
   MPlist *def_list, *plist;
   MPlist *definitions = charset_definition_list;
-  int mdebug_mask = MDEBUG_CHARSET;
+  int mdebug_flag = MDEBUG_CHARSET;
 
   if (! mdb)
     return 0;
@@ -647,22 +725,7 @@ mcharset__load_from_database ()
 
 #define MCHAR_INVALID_CODE
 #endif
-/*=*/
-/***en
-    @brief The symbol @c Mcharset.
-
-    Any decoded M-text has a text property whose key is the predefined
-    symbol @c Mcharset.  The name of @c Mcharset is
-    <tt>"charset"</tt>.  */
-
-/***ja
-    @brief ¥·¥ó¥Ü¥ë @c Mcharset.
-
-    ¥Ç¥³¡¼¥É¤µ¤ì¤¿ M-text ¤Ï¡¢¥­¡¼¤¬ @c Mcharset
-    ¤Ç¤¢¤ë¤è¤¦¤Ê¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤ò»ý¤Ä¡£
-    ¥·¥ó¥Ü¥ë @c Mcharset ¤Ï <tt>"charset"</tt> ¤È¤¤¤¦Ì¾Á°¤ò»ý¤Ä¡£  */
 
-MSymbol Mcharset;
 /*=*/
 
 /***en
index 04b216f..3a03e80 100644 (file)
@@ -673,7 +673,7 @@ mchartable (MSymbol key, void *default_value)
   M17N_OBJECT (table, free_chartable, MERROR_CHARTABLE);
   M17N_OBJECT_REGISTER (chartable_table, table);
   table->key = key;
-  table->min_char = 0;
+  table->min_char = -1;
   table->max_char = -1;
   SET_DEPTH_MIN_CHAR (&table->subtable, 0, 0);
   table->subtable.default_value = default_value;
@@ -686,6 +686,38 @@ mchartable (MSymbol key, void *default_value)
 /*=*/
 
 /***en
+    @brief Return the minimum character whose value is set in a chartabe.
+
+    The mchartable_min_char () function return the minimum character
+    whose value is set in chartable $TABLE.  No character is set its
+    value, the function returns -1.
+ */
+
+int
+mchartable_min_char (MCharTable *table)
+{
+  return table->min_char;
+}
+
+/*=*/
+
+/***en
+    @brief Return the maximum character whose value is set in a chartabe.
+
+    The mchartable_max_char () function return the maximum character
+    whose value is set in chartable $TABLE.  No character is set its
+    value, the function returns -1.
+ */
+
+int
+mchartable_max_char (MCharTable *table)
+{
+  return table->max_char;
+}
+
+/*=*/
+
+/***en
     @brief Return the assigned value of a character in a chartable.
 
     The mchartable_lookup () function returns the value assigned to
index 2e9a46e..5b64635 100644 (file)
@@ -3035,7 +3035,7 @@ mcoding__load_from_database ()
   MDatabase *mdb = mdatabase_find (msymbol ("coding-list"), Mnil, Mnil, Mnil);
   MPlist *def_list, *plist;
   MPlist *definitions = coding_definition_list;
-  int mdebug_mask = MDEBUG_CODING;
+  int mdebug_flag = MDEBUG_CODING;
 
   if (! mdb)
     return 0;
index 8d734b8..e0f4451 100644 (file)
 #include <time.h>
 #include <libgen.h>
 
-#include "m17n.h"
+#include "m17n-core.h"
 #include "m17n-misc.h"
 #include "internal.h"
 #include "mtext.h"
 #include "character.h"
-#include "charset.h"
 #include "database.h"
-#include "coding.h"
 #include "plist.h"
 
 /** The file containing a list of databases.  */
@@ -298,9 +296,7 @@ load_chartable (FILE *fp, MSymbol type)
          /* VAL is an M-text.  */
          MText *mt;
          if (c == '"')
-           mt = mconv_decode_buffer (Mcoding_utf_8,
-                                     (unsigned char *) (buf + i),
-                                     len - i - 1);
+           mt = mtext__from_data (buf + i, len - i - 1, MTEXT_FORMAT_UTF_8, 1);
          else
            {
              mt = mtext ();
@@ -349,84 +345,6 @@ load_chartable (FILE *fp, MSymbol type)
 }
 
 
-/** Load a data of type @c charset from the file FD.  */
-
-static void *
-load_charset (FILE *fp, MSymbol charset_name)
-{
-  MCharset *charset = MCHARSET (charset_name);
-  int *decoder;
-  MCharTable *encoder;
-  int size;
-  int i, c;
-  int found = 0;
-  MPlist *plist;
-
-  if (! charset)
-    MERROR (MERROR_DB, NULL);
-  size = (charset->code_range[15]
-         - (charset->min_code - charset->code_range_min_code));
-  MTABLE_MALLOC (decoder, size, MERROR_DB);
-  for (i = 0; i < size; i++)
-    decoder[i] = -1;
-  encoder = mchartable (Minteger, (void *) MCHAR_INVALID_CODE);
-
-  while ((c = getc (fp)) != EOF)
-    {
-      unsigned code1, code2, c1, c2;
-      int idx1, idx2;
-      char buf[256];
-
-      ungetc (c, fp);
-      fgets (buf, 256, fp);
-      if (c != '#')
-       {
-         if (sscanf (buf, "0x%x-0x%x 0x%x", &code1, &code2, &c1) == 3)
-           {
-             idx1 = CODE_POINT_TO_INDEX (charset, code1);
-             if (idx1 >= size)
-               continue;
-             idx2 = CODE_POINT_TO_INDEX (charset, code2);
-             if (idx2 >= size)
-               idx2 = size - 1;
-             c2 = c1 + (idx2 - idx1);
-           }
-         else if (sscanf (buf, "0x%x 0x%x", &code1, &c1) == 2)
-           {
-             idx1 = idx2 = CODE_POINT_TO_INDEX (charset, code1);
-             if (idx1 >= size)
-               continue;
-             c2 = c1;
-           }
-         else
-           continue;
-         if (idx1 >= 0 && idx2 >= 0)
-           {
-             decoder[idx1] = c1;
-             mchartable_set (encoder, c1, (void *) code1);
-             for (idx1++, c1++; idx1 <= idx2; idx1++, c1++)
-               {
-                 code1 = INDEX_TO_CODE_POINT (charset, idx1);
-                 decoder[idx1] = c1;
-                 mchartable_set (encoder, c1, (void *) code1);
-               }
-             found++;
-           }
-       }
-    }
-
-  if (! found)
-    {
-      free (decoder);
-      M17N_OBJECT_UNREF (encoder);
-      return NULL;
-    }
-  plist = mplist ();
-  mplist_add (plist, Mt, decoder);
-  mplist_add (plist, Mt, encoder);
-  return plist;
-}
-
 static char *
 gen_database_name (char *buf, MSymbol *tags)
 {
@@ -489,7 +407,7 @@ load_database (MSymbol *tags, void *extra_info)
   void *value;
   char *filename = get_database_file (db_info, NULL, NULL);
   FILE *fp;
-  int mdebug_mask = MDEBUG_DATABASE;
+  int mdebug_flag = MDEBUG_DATABASE;
   char buf[256];
 
   MDEBUG_PRINT1 (" [DB] <%s>", gen_database_name (buf, tags));
@@ -507,7 +425,11 @@ load_database (MSymbol *tags, void *extra_info)
   if (tags[0] == Mchar_table)
     value = load_chartable (fp, tags[1]);
   else if (tags[0] == Mcharset)
-    value = load_charset (fp, tags[1]);
+    {
+      if (! mdatabase__load_charset_func)
+       MERROR (MERROR_DB, NULL);
+      value = (*mdatabase__load_charset_func) (fp, tags[1]);
+    }
   else
     value = mplist__from_file (fp, NULL);
   fclose (fp);
@@ -842,13 +764,18 @@ expand_wildcard_database (MPlist *plist)
 /** List of database directories.  */ 
 MPlist *mdatabase__dir_list;
 
+void *(*mdatabase__load_charset_func) (FILE *fp, MSymbol charset_name);
+
 int
 mdatabase__init ()
 {
   MDatabaseInfo *dir_info;
   char *path;
 
+  mdatabase__load_charset_func = NULL;
+
   Mchar_table = msymbol ("char-table");
+  Mcharset = msymbol ("charset");
   Masterisk = msymbol ("*");
   Mversion = msymbol ("version");
 
@@ -888,10 +815,6 @@ mdatabase__init ()
        mplist_push (mdatabase__dir_list, Mt, get_dir_info (NULL));
     }
 
-  mdatabase__finder = ((void *(*) (MSymbol, MSymbol, MSymbol, MSymbol))
-                      mdatabase_find);
-  mdatabase__loader = (void *(*) (void *)) mdatabase_load;
-
   mdatabase__list = mplist ();
   mdatabase__update ();
   return 0;
@@ -1074,7 +997,7 @@ mdatabase__update (void)
 MPlist *
 mdatabase__load_for_keys (MDatabase *mdb, MPlist *keys)
 {
-  int mdebug_mask = MDEBUG_DATABASE;
+  int mdebug_flag = MDEBUG_DATABASE;
   MDatabaseInfo *db_info;
   char *filename;
   FILE *fp;
@@ -1253,9 +1176,11 @@ mdatabase__save (MDatabase *mdb, MPlist *data)
       M17N_OBJECT_UNREF (mt);
       return -1;
     }
-  mconv_encode_stream (msymbol ("utf-8"), mt, fp);
-  M17N_OBJECT_UNREF (mt);
+  if (mt->format > MTEXT_FORMAT_UTF_8)
+    mtext__adjust_format (mt, MTEXT_FORMAT_UTF_8);
+  fwrite (MTEXT_DATA (mt), 1, mtext_nchars (mt), fp);
   fclose (fp);
+  M17N_OBJECT_UNREF (mt);
   if ((ret = rename (db_info->uniq_file, file)) < 0)
     unlink (db_info->uniq_file);
   free (db_info->uniq_file);
@@ -1284,12 +1209,45 @@ mdatabase__unlock (MDatabase *mdb)
   return 0;
 }
 
+MPlist *
+mdatabase__props (MDatabase *mdb)
+{
+  MDatabaseInfo *db_info;
+
+  if (mdb->loader != load_database)
+    return NULL;
+  db_info = mdb->extra_info;
+  return db_info->properties;
+}
+
 /*** @} */
 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
 
 \f
 /* External API */
 
+/*** @addtogroup m17nCharset */
+/*** @{ */
+
+/***en
+    @brief The symbol @c Mcharset.
+
+    Any decoded M-text has a text property whose key is the predefined
+    symbol @c Mcharset.  The name of @c Mcharset is
+    <tt>"charset"</tt>.  */
+
+/***ja
+    @brief ¥·¥ó¥Ü¥ë @c Mcharset.
+
+    ¥Ç¥³¡¼¥É¤µ¤ì¤¿ M-text ¤Ï¡¢¥­¡¼¤¬ @c Mcharset
+    ¤Ç¤¢¤ë¤è¤¦¤Ê¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤ò»ý¤Ä¡£
+    ¥·¥ó¥Ü¥ë @c Mcharset ¤Ï <tt>"charset"</tt> ¤È¤¤¤¦Ì¾Á°¤ò»ý¤Ä¡£  */
+
+MSymbol Mcharset;
+/*=*/
+/*** @} */
+/*=*/
+
 /*** @addtogroup m17nDatabase */
 /*** @{ */
 
index 263af52..bf9e774 100644 (file)
@@ -88,4 +88,8 @@ extern int mdatabase__save (MDatabase *mdb, MPlist *data);
 
 extern int mdatabase__unlock (MDatabase *mdb);
 
+extern MPlist *mdatabase__props (MDatabase *mdb);
+
+extern void *(*mdatabase__load_charset_func) (FILE *fp, MSymbol charset_name);
+
 #endif /* not _M17N_DATABASE_H_ */
index 6155d4a..976b58b 100644 (file)
@@ -67,6 +67,7 @@
 #include "mtext.h"
 #include "textprop.h"
 #include "internal-gui.h"
+#include "internal-flt.h"
 #include "face.h"
 #include "font.h"
 
@@ -99,23 +100,21 @@ static MSymbol MbidiBN;
 static MSymbol MbidiS;
 static MSymbol MbidiNSM;
 
-static void
-visual_order (MGlyphString *gstring)
+static int
+analyse_bidi_level (MGlyphString *gstring)
 {
   int len = gstring->used - 2;
-  MGlyph *glyphs;
   int bidi_sensitive = gstring->control.orientation_reversed;
+  int max_level;
   MGlyph *g;
   int i;
 #ifdef HAVE_FRIBIDI
   FriBidiCharType base = bidi_sensitive ? FRIBIDI_TYPE_RTL : FRIBIDI_TYPE_LTR;
   FriBidiChar *logical = alloca (sizeof (FriBidiChar) * len);
-  FriBidiChar *visual;
-  FriBidiStrIndex *indices;
   FriBidiLevel *levels;
+  FriBidiStrIndex *indices;
 #else  /* not HAVE_FRIBIDI */
   int *logical = alloca (sizeof (int) * len);
-  int *indices;
   char *levels = alloca (len);
 
   memset (levels, 0, sizeof (int) * len);
@@ -129,7 +128,7 @@ visual_order (MGlyphString *gstring)
 #endif /* not HAVE_FRIBIDI */
          )
        {
-         MSymbol bidi = (MSymbol) mchar_get_prop (g->c, Mbidi_category);
+         MSymbol bidi = (MSymbol) mchar_get_prop (g->g.c, Mbidi_category);
 
          if (bidi == MbidiR || bidi == MbidiAL
              || bidi == MbidiRLE || bidi == MbidiRLO)
@@ -144,71 +143,102 @@ visual_order (MGlyphString *gstring)
            levels[i] = 1;          
 #endif /* not HAVE_FRIBIDI */
        }
-      logical[i] = g->c;
+      logical[i] = g->g.c;
     }
 
   if (! bidi_sensitive)
-    return;
+    return 0;
 
-  glyphs = alloca (sizeof (MGlyph) * len);
-  memcpy (glyphs, gstring->glyphs + 1, sizeof (MGlyph) * len);
 #ifdef HAVE_FRIBIDI
-  visual = alloca (sizeof (FriBidiChar) * (len + 1));
-  indices = alloca (sizeof (FriBidiStrIndex) * (len + 1));
   levels = alloca (sizeof (FriBidiLevel) * (len + 1));
+  indices = alloca (sizeof (FriBidiStrIndex) * (len + 1));
 
-  fribidi_log2vis (logical, len, &base, visual, indices, NULL, levels);
-#else  /* not HAVE_FRIBIDI */
-  indices = alloca (sizeof (int) * len);
-  for (i = 0; i < len; i++)
+  fribidi_log2vis (logical, len, &base, NULL, NULL, indices, levels);
+#endif /* not HAVE_FRIBIDI */
+
+  MGLYPH (0)->bidi_level = 0;
+  max_level = 0;
+  for (g = MGLYPH (1), i = 0; i < len; g++, i++)
     {
-      if (levels[i])
+      g->bidi_level = levels[i];
+      if (max_level < g->bidi_level)
+       max_level = g->bidi_level;
+    }
+  MGLYPH (i)->bidi_level = 0;
+  return max_level;
+}
+
+static void
+visual_order (MGlyphString *gstring)
+{
+  MGlyph *glyphs = alloca (sizeof (MGlyph) * gstring->used);
+  int i, j, gidx;
+
+  memcpy (glyphs, gstring->glyphs, sizeof (MGlyph) * gstring->used);
+
+  for (i = gidx = 0; i < gstring->used; gidx++)
+    {
+      int level = glyphs[i].bidi_level;
+      
+      gstring->glyphs[gidx] = glyphs[i];
+      glyphs[i].rface = NULL;
+
+      if (level % 2)
        {
-         int j, k;
+         int prev_level = glyphs[i - 1].bidi_level;
 
-         for (j = i + 1; j < len && levels[j]; j++);
-         for (k = j--; i < k; i++, j--)
-           indices[i] = j;
-         i--;
+         if (prev_level == level)
+           i--;
+         else if (prev_level > level)
+           {
+             for (; glyphs[i - 1].bidi_level > level; i--);
+             if (glyphs[i].bidi_level % 2)
+               for (level = glyphs[i].bidi_level;
+                    glyphs[i + 1].bidi_level == level; i++);
+           }
+         else
+           for (i++; ! glyphs[i].rface; i++);
        }
       else
-       indices[i] = i;
-    }
-#endif /* not HAVE_FRIBIDI */
+       {
+         int next_level = glyphs[i + 1].bidi_level;
 
-  for (i = 0; i < len;)
-    {
-      /* Index into gstring->glyphs plus 1 for GLYPHS[i].  */
-      int j = indices[i];
-      /* Length of grapheme-cluster */
-      int seglen;
+         if (next_level == level)
+           i++;
+         else if (next_level > level)
+           {
+             for (; glyphs[i + 1].bidi_level > level; i++);
+             if ((glyphs[i].bidi_level % 2) == 0)
+               for (level = glyphs[i].bidi_level;
+                    glyphs[i - 1].bidi_level == level; i--);
+           }
+         else
+           {
+             int save = i + 1;
 
-      g = glyphs + i;
-#ifdef HAVE_FRIBIDI
-      if (visual[j] != logical[i])
-       {
-         /* Mirrored.  */
-         g->c = visual[j];
-         if (g->rface->rfont)
-           g->code = mfont__encode_char (NULL, (MFont *) g->rface->rfont,
-                                         NULL, g->c);
+             for (i--; glyphs[i].bidi_level >= level; i--);
+             if (! glyphs[i].rface)
+               for (i = save; ! glyphs[i].rface; i++);
+           }
        }
-#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++)
+    }
+  for (i = 1; i < gstring->used - 1; i++)
+    {
+      MGlyph *g = gstring->glyphs + i;
+
+      for (j = i; g->g.from == gstring->glyphs[j + 1].g.from; j++);
+      if (j > i)
        {
-         g->bidi_level = levels[i];
-         if (indices[i + seglen] < j)
-           j = indices[i + seglen];
+         memcpy (glyphs + i, gstring->glyphs + i,
+                 sizeof (MGlyph) * (j - i + 1));
+         for (; i <= j; i++)
+           g[j - i] = glyphs[i];
+         i--;
        }
-      memcpy (MGLYPH (j + 1), glyphs + i, sizeof (MGlyph) * seglen);
-      i += seglen;
     }
 }
 
+#if 0
 static void
 reorder_combining_chars (MGlyphString *gstring, int from, int to)
 {
@@ -230,7 +260,62 @@ reorder_combining_chars (MGlyphString *gstring, int from, int to)
          }
     }
 }
+#endif
+
+static int
+run_flt (MGlyphString *gstring, int from, int to, MRealizedFont *rfont,
+        MSymbol layouter)
+{
+  MFLTGlyphString flt_gstr;
+  MFLTFontForRealized font;
+  MFLT *flt;
+  int from_pos = MGLYPH (from)->g.from;
+  int len = to - from;
+  int i;
 
+  flt = mflt_get (layouter);
+  flt_gstr.glyph_size = sizeof (MGlyph);
+  flt_gstr.glyphs = (MFLTGlyph *) (gstring->glyphs);
+  flt_gstr.used = gstring->used;
+  flt_gstr.allocated = gstring->size;
+  flt_gstr.r2l = 0;
+  font.font.family = mfont_get_prop (rfont->font, Mfamily);
+  font.font.x_ppem = rfont->x_ppem;
+  font.font.y_ppem = rfont->y_ppem;
+  font.font.get_glyph_id = mfont__get_glyph_id;
+  font.font.get_metrics = mfont__get_metrics;
+  font.font.check_otf = rfont->driver->check_otf;
+  font.font.drive_otf = rfont->driver->drive_otf;
+  font.font.internal = NULL;
+  font.rfont = rfont;
+  for (i = 0; i < 3; i++)
+    {
+      to = mflt_run (&flt_gstr, from, to, &font.font, flt);
+      if (to != -2)
+       break;
+      APPEND_GLYPH (gstring, *MGLYPH (0));
+      APPEND_GLYPH (gstring, *MGLYPH (0));
+      gstring->used -= 2;
+    }
+  if (from + len != to)
+    gstring->used += to - (from + len);
+  for (i = from; i < to; i++)
+    {
+      MGlyph *g = MGLYPH (i);
+
+      g->g.from += from_pos - from;
+      g->g.to += from_pos - from + 1;
+      g->g.xadv >>= 6;
+      g->g.yadv >>= 6;
+      g->g.ascent >>= 6;
+      g->g.descent >>= 6;
+      g->g.lbearing >>= 6;
+      g->g.rbearing >>= 6;
+      g->g.xoff >>= 6;
+      g->g.yoff >>= 6;
+    }
+  return to;
+}
 
 /** Scan M-text MT from FROM to TO, and compose glyphs in GSTRING for
     displaying them on FRAME.
@@ -252,6 +337,7 @@ compose_glyph_string (MFrame *frame, MText *mt, int from, int to,
   MRealizedFace *rface = default_rface;
   MRealizedFont *rfont;
   int size = gstring->control.fixed_width;
+  int max_bidi_level = 0;
   int i;
 
   MLIST_RESET (gstring);
@@ -263,7 +349,7 @@ compose_glyph_string (MFrame *frame, MText *mt, int from, int to,
 
   /** Put anchor glyphs at the head and tail.  */
   g_tmp.type = GLYPH_ANCHOR;
-  g_tmp.pos = g_tmp.to = from;
+  g_tmp.g.from = g_tmp.g.to = from;
   APPEND_GLYPH (gstring, g_tmp);
   stop = face_change = font_change = pos = from;
   while (1)
@@ -318,9 +404,9 @@ compose_glyph_string (MFrame *frame, MText *mt, int from, int to,
        c = '\n';
       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.g.c = c;
+      g_tmp.g.from = pos++;
+      g_tmp.g.to = pos;
       g_tmp.rface = rface;
       category = mchar_get_prop (c, Mcategory);
       if (category == McatCf)
@@ -335,8 +421,8 @@ compose_glyph_string (MFrame *frame, MText *mt, int from, int to,
          MGlyph ctrl[2];
 
          ctrl[0] = ctrl[1] = g_tmp;
-         ctrl[0].c = '^';
-         ctrl[1].c = c < ' ' ? c + 0x40 : '?';
+         ctrl[0].g.c = '^';
+         ctrl[1].g.c = c < ' ' ? c + 0x40 : '?';
          APPEND_GLYPH (gstring, ctrl[0]);
          APPEND_GLYPH (gstring, ctrl[1]);
        }
@@ -348,17 +434,20 @@ compose_glyph_string (MFrame *frame, MText *mt, int from, int to,
   /* Append an anchor glyph.  */
   INIT_GLYPH (g_tmp);
   g_tmp.type = GLYPH_ANCHOR;
-  g_tmp.pos = g_tmp.to = pos;
+  g_tmp.g.from = g_tmp.g.to = pos;
   APPEND_GLYPH (gstring, g_tmp);
   gstring->to = pos;
 
+  if (gstring->control.enable_bidi)
+    max_bidi_level = analyse_bidi_level (gstring);
+
   /* 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;
+      int c = g->g.c;
       MSymbol this_script;
 
       if (c < 0x100)
@@ -368,8 +457,16 @@ compose_glyph_string (MFrame *frame, MText *mt, int from, int to,
        {
          this_script = (MSymbol) mchar_get_prop (c, Mscript);
          if (this_script == Minherited || this_script == Mcommon)
-           this_script = script;
-         if (this_script == Mcommon)
+           {
+             if (g > MGLYPH (1))
+               {
+                 MSymbol category = mchar_get_prop (g[-1].g.c, Mcategory);
+
+                 if (MSYMBOL_NAME (category)[0] != 'Z')
+                   this_script = script;
+               }
+           }
+         if (this_script == Mcommon && non_latin_script)
            this_script = non_latin_script;
          if (this_script == Mcommon)
            {
@@ -379,8 +476,8 @@ compose_glyph_string (MFrame *frame, MText *mt, int from, int to,
              MGlyph *g1;
 
              for (g1 = g + 1; g1->type != GLYPH_ANCHOR; g1++)
-               if (g1->c >= 0x100
-                   && (sym = mchar_get_prop (g1->c, Mscript)) != Mcommon
+               if (g1->g.c >= 0x100
+                   && (sym = mchar_get_prop (g1->g.c, Mscript)) != Mcommon
                    && sym != Minherited)
                  {
                    this_script = sym;
@@ -389,7 +486,7 @@ compose_glyph_string (MFrame *frame, MText *mt, int from, int to,
            }
        }
 
-      pos = g->pos;
+      pos = g->g.from;
       if (pos == stop || script != this_script || g->rface->rfont != rfont)
        {
          while (last_g < g)
@@ -436,59 +533,45 @@ compose_glyph_string (MFrame *frame, MText *mt, int from, int to,
 
          if (this->rface->layouter != Mnil)
            {
-             MGlyph *prev;
-             unsigned code;
-
-             for (prev = MGLYPH (start - 1);
-                  (prev->type == GLYPH_CHAR
-                   && prev->category == GLYPH_CATEGORY_FORMATTER
-                   && (code = mfont__encode_char (NULL,
-                                                  (MFont *) this->rface->rfont,
-                                                  NULL, prev->c)
-                       != MCHAR_INVALID_CODE));
-                  start--, prev--)
-               if (prev->rface->rfont != this->rface->rfont)
-                 {
-                   prev->rface->rfont = this->rface->rfont;
-                   prev->code = code;
-                 }
+             MGlyph *prev = MGLYPH (start - 1);
+
+             while (prev->type == GLYPH_CHAR
+                    && prev->category == GLYPH_CATEGORY_FORMATTER
+                    && (mfont__encode_char (NULL, (MFont *) this->rface->rfont,
+                                            NULL, prev->g.c)
+                        != MCHAR_INVALID_CODE))
+               {
+                 start--, prev--;
+                 prev->rface->rfont = this->rface->rfont;
+               }
 
              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 (NULL,
-                                                           (MFont *) this->rface->rfont,
-                                                           NULL,
-                                                           g->c))
+                           && (mfont__encode_char (NULL,
+                                                   (MFont *) this->rface->rfont,
+                                                   NULL, g->g.c)
                                != MCHAR_INVALID_CODE))));
                   i++, g++)
-               if (g->rface->rfont != this->rface->rfont)
-                 {
-                   g->rface->rfont = this->rface->rfont;
-                   g->code = code;
-                 }
-             i = mfont__flt_run (gstring, start, i, this->rface);
+               g->rface->rfont = this->rface->rfont;
+             i = run_flt (gstring, start, i, this->rface->rfont,
+                          this->rface->layouter);
            }
          else
            {
-             while (this->type == GLYPH_CHAR
-                    && this->c >= 0x100
-                    && this->category == GLYPH_CATEGORY_MODIFIER
-                    && this->rface->rfont
-                    && this->rface->rfont->layouter == Mnil)
-               {
-                 int class = (int) mchar_get_prop (this->c,
-                                                   Mcombining_class);
-                 this->combining_code
-                   = MAKE_COMBINING_CODE_BY_CLASS (class);
-                 i++, this++;
-               }
+             g++;
+             while (g->type == GLYPH_CHAR
+                    && g->g.c >= 0x100
+                    && g->category == GLYPH_CATEGORY_MODIFIER
+                    && g->rface->rfont
+                    && g->rface->rfont->layouter == Mnil)
+               i++, g++;
              if (start + 1 < i)
-               reorder_combining_chars (gstring, start, i);
-             if (this->type == GLYPH_ANCHOR)
-               break;
+               run_flt (gstring, start, i, this->rface->rfont, Mcombining);
+             else
+               mfont__get_metric (gstring, start, i);
            }
          g = MGLYPH (i);
        }
@@ -497,62 +580,10 @@ compose_glyph_string (MFrame *frame, MText *mt, int from, int to,
     }
 
   /* At last, reorder glyphs visually if necessary.  */
-  if (gstring->control.enable_bidi)
+  if (max_bidi_level > 0)
     visual_order (gstring);
 }
 
-
-static int
-combining_code_from_class (int class)
-{
-  int code;
-
-  if (class < 200)
-    code = MAKE_COMBINING_CODE (3, 1, 3, 1, 128, 128);
-  else if (class == 200)       /* below left attached */
-    code = MAKE_COMBINING_CODE (2, 0, 0, 1, 128, 128);
-  else if (class == 202)       /* below attached*/
-    code = MAKE_COMBINING_CODE (2, 1, 0, 1, 128, 128);
-  else if (class == 204)       /* below right attached */
-    code = MAKE_COMBINING_CODE (2, 2, 0, 1, 128, 128);
-  else if (class == 208)       /* left attached */
-    code = MAKE_COMBINING_CODE (3, 0, 3, 2, 128, 128);
-  else if (class == 210)       /* right attached */
-    code = MAKE_COMBINING_CODE (3, 2, 3, 0, 128, 128);
-  else if (class == 212)       /* above left attached */
-    code = MAKE_COMBINING_CODE (0, 0, 2, 1, 128, 128);
-  else if (class == 214)       /* above attached */
-    code = MAKE_COMBINING_CODE (0, 1, 2, 1, 128, 128);
-  else if (class == 216)       /* above right attached */
-    code = MAKE_COMBINING_CODE (0, 2, 2, 1, 128, 128);
-  else if (class == 218)       /* below left */
-    code = MAKE_COMBINING_CODE (2, 0, 0, 1, 122, 128);
-  else if (class == 220)       /* below */
-    code = MAKE_COMBINING_CODE (2, 1, 0, 1, 122, 128);
-  else if (class == 222)       /* below right */
-    code = MAKE_COMBINING_CODE (2, 2, 0, 1, 122, 128);
-  else if (class == 224)       /* left */
-    code = MAKE_COMBINING_CODE (3, 0, 3, 2, 128, 122);
-  else if (class == 226)       /* right */
-    code = MAKE_COMBINING_CODE (3, 2, 3, 0, 128, 133);
-  else if (class == 228)       /* above left */
-    code = MAKE_COMBINING_CODE (0, 0, 2, 1, 133, 128);
-  else if (class == 230)       /* above */
-    code = MAKE_COMBINING_CODE (0, 1, 2, 1, 133, 128);
-  else if (class == 232)       /* above right */
-    code = MAKE_COMBINING_CODE (0, 2, 2, 1, 133, 128);
-  else if (class == 233)       /* double below */
-    code = MAKE_COMBINING_CODE (2, 2, 0, 2, 122, 128);
-  else if (class == 234)       /* double above */
-    code = MAKE_COMBINING_CODE (0, 2, 2, 2, 133, 128);
-  else if (class == 240)       /* iota subscript */
-    code = MAKE_COMBINING_CODE (2, 1, 0, 1, 122, 128);
-  else                         /* unknown */
-    code = MAKE_COMBINING_CODE (3, 1, 3, 1, 128, 128);
-  return code;
-}
-
-
 typedef struct {
   int width, lbearing, rbearing;
 } MSubTextExtents;
@@ -564,181 +595,20 @@ layout_glyphs (MFrame *frame, MGlyphString *gstring, int from, int to,
   int g_physical_ascent, g_physical_descent;
   MGlyph *g = MGLYPH (from);
   MGlyph *last_g = MGLYPH (to);
-  int i;
 
   g_physical_ascent = gstring->physical_ascent;
   g_physical_descent = gstring->physical_descent;
   extents->width = extents->lbearing = extents->rbearing = 0;
 
-  for (i = from; i < to;)
+  for (g = MGLYPH (from); g < last_g; g++)
     {
-      if ( MGLYPH (i)->otf_encoded)
-       i++;
-      else
-       {
-         int j = i++;
-
-         while (i < to && ! MGLYPH (i)->otf_encoded) i++;
-         mfont__get_metric (gstring, j, i);
-       }
-    }
-
-  g = MGLYPH (from);
-  while (g < last_g)
-    {
-      MGlyph *base = g++;
-      MRealizedFont *rfont = base->rface->rfont;
-      int size = rfont->spec.size;
-      int width, lbearing, rbearing;
-
-      if (g == last_g || ! g->combining_code)
-       {
-         /* No combining.  */
-         if (base->width == 0 && ! base->left_padding && ! base->right_padding
-             && GLYPH_INDEX (base) > from)
-           {
-             MGlyph *prev = base - 1; 
-
-             if (base->pos < prev->pos)
-               prev->pos = base->pos;
-             else
-               base->pos = prev->pos;
-             if (base->to > prev->to)
-               prev->to = base->to;
-             else
-               base->to = prev->to;
-           }
-
-         if (base->left_padding && base->lbearing < 0)
-           {
-             base->xoff = - base->lbearing;
-             if (base->rbearing < 0)
-               base->width = base->rbearing - base->lbearing;
-             else
-               base->width += base->xoff;
-             base->rbearing += base->xoff;
-             base->lbearing = 0;
-           }
-         if (base->right_padding && base->rbearing > base->width)
-           {
-             base->width = base->rbearing;
-           }
-         lbearing = base->lbearing;
-         rbearing = base->rbearing;
-       }
-      else
-       {
-         /* With combining glyphs.  */
-         int left = -base->width;
-         int right = 0;
-         int top = - base->ascent;
-         int bottom = base->descent;
-         int height = bottom - top;
-         int begin = base->pos;
-         int end = base->to;
-         int i;
-
-         width = base->width;
-         lbearing = (base->lbearing < 0 ? base->lbearing : 0);
-         rbearing = base->rbearing;
-
-         while (g != last_g && g->combining_code)
-           {
-             int combining_code = g->combining_code;
-
-             if (begin > g->pos)
-               begin = g->pos;
-             else if (end < g->to)
-               end = g->to;
-               
-             if (! COMBINING_PRECOMPUTED_P (combining_code))
-               {
-                 int base_x, base_y, add_x, add_y, off_x, off_y;
-
-                 if (COMBINING_BY_CLASS_P (combining_code))
-                   g->combining_code = combining_code
-                     = combining_code_from_class (COMBINING_CODE_CLASS
-                                                  (combining_code));
-
-                 rfont = g->rface->rfont;
-                 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)
-                          / 1000);
-                 base_x = COMBINING_CODE_BASE_X (combining_code);
-                 base_y = COMBINING_CODE_BASE_Y (combining_code);
-                 add_x = COMBINING_CODE_ADD_X (combining_code);
-                 add_y = COMBINING_CODE_ADD_Y (combining_code);
-
-                 g->xoff = left + (width * base_x - g->width * add_x) / 2 + off_x;
-                 if (g->xoff < left)
-                   left = g->xoff;
-                 if (g->xoff + g->width > right)
-                   right = g->xoff + g->width;
-                 width = right - left;
-
-                 if (base_y < 3)
-                   g->yoff = top + height * base_y / 2;
-                 else
-                   g->yoff = 0;
-                 if (add_y < 3)
-                   g->yoff -= (g->ascent + g->descent) * add_y / 2 - g->ascent;
-                 g->yoff -= off_y;
-               }
-
-             if (g->xoff + g->lbearing < left + lbearing)
-               lbearing = g->xoff + g->lbearing - left;
-             if (g->xoff + g->rbearing > left + rbearing)
-               rbearing = g->xoff + g->rbearing - left;
-             if (g->yoff - g->ascent < top)
-               top = g->yoff - g->ascent;
-             if (g->yoff + g->descent > bottom)
-               bottom = g->yoff + g->descent;
-             height = bottom - top;
-
-             g->width = 0;
-             g++;
-           }
-
-         base->ascent = - top;
-         base->descent = bottom;
-         base->lbearing = lbearing;
-         base->rbearing = rbearing;
-         if (left < - base->width)
-           {
-             base->xoff = - base->width - left;
-             base->width += base->xoff;
-             base->rbearing += base->xoff;
-             base->lbearing += base->xoff;
-           }
-         if (right > 0)
-           {
-             base->width += right;
-             base->rbearing += right;
-             base->right_padding = 1;
-             for (i = 1; base + i != g; i++)
-               base[i].xoff -= right;
-           }
-
-         for (i = 0; base + i != g; i++)
-           {
-             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);
-      g_physical_descent = MAX (g_physical_descent, base->descent);
-      extents->lbearing = MIN (extents->lbearing, extents->width + lbearing);
-      extents->rbearing = MAX (extents->rbearing, extents->width + rbearing);
-      extents->width += base->width;
+      g_physical_ascent = MAX (g_physical_ascent, g->g.ascent);
+      g_physical_descent = MAX (g_physical_descent, g->g.descent);
+      extents->lbearing = MIN (extents->lbearing,
+                              extents->width + g->g.lbearing);
+      extents->rbearing = MAX (extents->rbearing,
+                              extents->width + g->g.rbearing);
+      extents->width += g->g.xadv;
     }
 
   gstring->physical_ascent = g_physical_ascent;
@@ -786,16 +656,16 @@ layout_glyph_string (MFrame *frame, MGlyphString *gstring)
              MGlyph box_glyph = g[-1];
 
              box_glyph.type = GLYPH_BOX;
-             box_glyph.width
+             box_glyph.g.xadv
                = (control->fixed_width
                   ? frame->space_width
                   : box->inner_hmargin + box->width + box->outer_hmargin);
-             box_glyph.lbearing = 0;
-             box_glyph.rbearing = box_glyph.width;
-             box_glyph.xoff = 0;
+             box_glyph.g.lbearing = 0;
+             box_glyph.g.rbearing = box_glyph.g.xadv;
+             box_glyph.g.xoff = 0;
              box_glyph.right_padding = 1;
-             gstring->width += box_glyph.width;
-             gstring->rbearing += box_glyph.width;
+             gstring->width += box_glyph.g.xadv;
+             gstring->rbearing += box_glyph.g.xadv;
              INSERT_GLYPH (gstring, gidx, box_glyph);
              gidx++;
              g = MGLYPH (gidx);
@@ -812,16 +682,16 @@ layout_glyph_string (MFrame *frame, MGlyphString *gstring)
              if (box_line_height < box_height)
                box_line_height = box_height;
              box_glyph.type = GLYPH_BOX;
-             box_glyph.width
+             box_glyph.g.xadv
                = (control->fixed_width
                   ? frame->space_width
                   : box->inner_hmargin + box->width + box->outer_hmargin);
-             box_glyph.lbearing = 0;
-             box_glyph.rbearing = box_glyph.width;
-             box_glyph.xoff = 0;
+             box_glyph.g.lbearing = 0;
+             box_glyph.g.rbearing = box_glyph.g.xadv;
+             box_glyph.g.xoff = 0;
              box_glyph.left_padding = 1;
-             gstring->width += box_glyph.width;
-             gstring->rbearing += box_glyph.width;
+             gstring->width += box_glyph.g.xadv;
+             gstring->rbearing += box_glyph.g.xadv;
              INSERT_GLYPH (gstring, gidx, box_glyph);
              gidx++;
              g = MGLYPH (gidx);
@@ -841,12 +711,12 @@ layout_glyph_string (MFrame *frame, MGlyphString *gstring)
          for (g++; g->type == GLYPH_CHAR; g++)
            if (! rfont != ! g->rface->rfont
                || box != g->rface->box
-               || ((fromg->code == MCHAR_INVALID_CODE)
-                   != (g->code == MCHAR_INVALID_CODE))
+               || ((fromg->g.code == MCHAR_INVALID_CODE)
+                   != (g->g.code == MCHAR_INVALID_CODE))
                || (g->category == GLYPH_CATEGORY_FORMATTER
                    && ignore_formatting_char))
              break;
-         if (rfont && fromg->code != MCHAR_INVALID_CODE)
+         if (rfont && fromg->g.code != MCHAR_INVALID_CODE)
            {
              int extra_width;
              int to = GLYPH_INDEX (g);
@@ -865,9 +735,9 @@ layout_glyph_string (MFrame *frame, MGlyphString *gstring)
                  g = MGLYPH (from);
                  pad = *g;
                  pad.type = GLYPH_PAD;
-                 pad.xoff = 0;
-                 pad.lbearing = 0;
-                 pad.width = pad.rbearing = extra_width;
+                 pad.g.xoff = 0;
+                 pad.g.lbearing = 0;
+                 pad.g.xadv = pad.g.rbearing = extra_width;
                  pad.left_padding = 1;
                  INSERT_GLYPH (gstring, from, pad);
                  to++;
@@ -886,14 +756,14 @@ layout_glyph_string (MFrame *frame, MGlyphString *gstring)
                         face, or a default value of the current
                         frame, which is, however, not yet
                         implemented.  */
-                     if (extra_width + 2 < g->width)
+                     if (extra_width + 2 < g->g.xadv)
                        {
-                         g->width -= extra_width;
+                         g->g.xadv -= extra_width;
                        }
                      else
                        {
-                         extra_width = g->width - 2;
-                         g->width = 2;
+                         extra_width = g->g.xadv - 2;
+                         g->g.xadv = 2;
                        }
                      gstring->width -= extra_width;
                      gstring->rbearing -= extra_width;
@@ -911,15 +781,15 @@ layout_glyph_string (MFrame *frame, MGlyphString *gstring)
                    {
                      pad = g[-1];
                      pad.type = GLYPH_PAD;
-                     pad.xoff = 0;
-                     pad.lbearing = 0;
-                     pad.width = pad.rbearing = extra_width;
+                     pad.g.xoff = 0;
+                     pad.g.lbearing = 0;
+                     pad.g.xadv = pad.g.rbearing = extra_width;
                      INSERT_GLYPH (gstring, to, pad);
                      to++;
                      g = MGLYPH (to);
                    }
                  else
-                   g[-1].width += extra_width;
+                   g[-1].g.xadv += extra_width;
                  extents.width += extra_width;
                }
 
@@ -937,15 +807,15 @@ layout_glyph_string (MFrame *frame, MGlyphString *gstring)
            {
              for (; fromg < g; fromg++)
                {
-                 if ((fromg->c >= 0x200B && fromg->c <= 0x200F)
-                     || (fromg->c >= 0x202A && fromg->c <= 0x202E))
-                   fromg->width = fromg->rbearing = 1;
+                 if ((fromg->g.c >= 0x200B && fromg->g.c <= 0x200F)
+                     || (fromg->g.c >= 0x202A && fromg->g.c <= 0x202E))
+                   fromg->g.xadv = fromg->g.rbearing = 1;
                  else
-                   fromg->width = fromg->rbearing = rface->space_width;
-                 fromg->xoff = fromg->lbearing = 0;
-                 fromg->ascent = fromg->descent = 0;
-                 gstring->width += fromg->width;
-                 gstring->rbearing += fromg->width;
+                   fromg->g.xadv = fromg->g.rbearing = rface->space_width;
+                 fromg->g.xoff = fromg->g.lbearing = 0;
+                 fromg->g.ascent = fromg->g.descent = 0;
+                 gstring->width += fromg->g.xadv;
+                 gstring->rbearing += fromg->g.xadv;
                }
              if (gstring->ascent < frame->rface->ascent)
                gstring->ascent = frame->rface->ascent;
@@ -955,40 +825,40 @@ layout_glyph_string (MFrame *frame, MGlyphString *gstring)
        }
       else if (g->type == GLYPH_SPACE)
        {
-         if (g->c == ' ')
-           g->width = g->rface->space_width;
-         else if (g->c == '\n')
+         if (g->g.c == ' ')
+           g->g.xadv = g->rface->space_width;
+         else if (g->g.c == '\n')
            {
-             g->width = control->cursor_width;
-             if (g->width)
+             g->g.xadv = control->cursor_width;
+             if (g->g.xadv)
                {
                  if (control->cursor_bidi)
-                   g->width = 3;
-                 else if (g->width < 0)
-                   g->width = g->rface->space_width;
+                   g->g.xadv = 3;
+                 else if (g->g.xadv < 0)
+                   g->g.xadv = g->rface->space_width;
                }
            }
-         else if (g->c == '\t')
+         else if (g->g.c == '\t')
            {
-             g->width = tab_width - ((gstring->indent + gstring->width)
-                                     % tab_width);
+             g->g.xadv = tab_width - ((gstring->indent + gstring->width)
+                                      % tab_width);
              tab_found = 1;
            }
          else
-           g->width = 1;
+           g->g.xadv = 1;
          if (g[-1].type == GLYPH_PAD)
            {
              /* This space glyph absorbs (maybe partially) the
                 previous padding glyph.  */
-             g->width -= g[-1].width;
-             if (g->width < 1)
+             g->g.xadv -= g[-1].g.xadv;
+             if (g->g.xadv < 1)
                /* But, keep at least some space width.  For the
                   moment, we use the arbitrary width 2-pixel.  */
-               g->width = 2;
+               g->g.xadv = 2;
            }
-         g->rbearing = g->width;
-         gstring->width += g->width;
-         gstring->rbearing += g->width;
+         g->g.rbearing = g->g.xadv;
+         gstring->width += g->g.xadv;
+         gstring->rbearing += g->g.xadv;
          if (g->rface->rfont)
            {
              if (gstring->ascent < g->rface->ascent)
@@ -1000,8 +870,8 @@ layout_glyph_string (MFrame *frame, MGlyphString *gstring)
        }
       else
        {
-         gstring->width += g->width;
-         gstring->rbearing += g->width;
+         gstring->width += g->g.xadv;
+         gstring->rbearing += g->g.xadv;
          g++;
        }
     }
@@ -1013,16 +883,16 @@ layout_glyph_string (MFrame *frame, MGlyphString *gstring)
       MGlyph box_glyph = g[-1];
 
       box_glyph.type = GLYPH_BOX;
-      box_glyph.width
+      box_glyph.g.xadv
        = (control->fixed_width
           ? frame->space_width
           : box->inner_hmargin + box->width + box->outer_hmargin);
-      box_glyph.lbearing = 0;
-      box_glyph.rbearing = box_glyph.width;
-      box_glyph.xoff = 0;
+      box_glyph.g.lbearing = 0;
+      box_glyph.g.rbearing = box_glyph.g.xadv;
+      box_glyph.g.xoff = 0;
       box_glyph.right_padding = 1;
-      gstring->width += box_glyph.width;
-      gstring->rbearing += box_glyph.width;
+      gstring->width += box_glyph.g.xadv;
+      gstring->rbearing += box_glyph.g.xadv;
       INSERT_GLYPH (gstring, gidx, box_glyph);
     }
 
@@ -1065,23 +935,23 @@ layout_glyph_string (MFrame *frame, MGlyphString *gstring)
 
       for (g = MGLYPH (gstring->used - 2); g->type != GLYPH_ANCHOR; g--)
        {
-         if (g->type == GLYPH_CHAR && g->c == '\t')
+         if (g->type == GLYPH_CHAR && g->g.c == '\t')
            {
              int this_width = tab_width - (width % tab_width);
 
              if (g[1].type == GLYPH_PAD)
-               this_width -= g[1].width;
+               this_width -= g[1].g.xadv;
              if (g[-1].type == GLYPH_PAD)
-               this_width -= g[-1].width;              
+               this_width -= g[-1].g.xadv;             
              if (this_width < 2)
                this_width = 2;
-             gstring->width += this_width - g->width;
-             gstring->rbearing += this_width - g->width;
-             g->width = this_width;
+             gstring->width += this_width - g->g.xadv;
+             gstring->rbearing += this_width - g->g.xadv;
+             g->g.xadv = this_width;
              width += this_width;
            }
          else
-           width += g->width;
+           width += g->g.xadv;
        }
     }
 }
@@ -1115,7 +985,7 @@ draw_background (MFrame *frame, MDrawWindow win, int x, int y,
   *to_x = x;
   while (g->type != GLYPH_ANCHOR)
     {
-      if (g->pos >= from && g->pos < to)
+      if (g->g.from >= from && g->g.from < to)
        {
          MGlyph *fromg = g, *cursor = NULL;
          MRealizedFace *rface = g->rface;
@@ -1125,18 +995,18 @@ draw_background (MFrame *frame, MDrawWindow win, int x, int y,
 
          if (! *from_idx)
            *from_idx = GLYPH_INDEX (g);
-         while (g->pos >= from && g->pos < to
+         while (g->g.from >= from && g->g.from < to
                 && g->rface == rface)
            {
              g->enabled = 1;
              if (g->type != GLYPH_BOX
-                 && g->pos <= cursor_pos && g->to > cursor_pos)
+                 && g->g.from <= cursor_pos && g->g.to > cursor_pos)
                {
                  if (! cursor)
                    cursor = g, cursor_x = x + width;
-                 cursor_width += g->width;
+                 cursor_width += g->g.xadv;
                }
-             width += g++->width;
+             width += g++->g.xadv;
            }
          if (width > 0
              && (control->as_image
@@ -1145,9 +1015,9 @@ draw_background (MFrame *frame, MDrawWindow win, int x, int y,
              int this_x = x, this_width = width;
 
              if (fromg->type == GLYPH_BOX)
-               this_x += fromg->width, this_width -= fromg->width;
+               this_x += fromg->g.xadv, this_width -= fromg->g.xadv;
              if (g[-1].type == GLYPH_BOX)
-               this_width -= g[-1].width;
+               this_width -= g[-1].g.xadv;
              (frame->driver->fill_space)
                (frame, win, rface, 0,
                 this_x, y - gstring->text_ascent, this_width,
@@ -1201,13 +1071,13 @@ draw_background (MFrame *frame, MDrawWindow win, int x, int y,
              while (fromg < g)
                {
                  if (fromg->type != GLYPH_BOX
-                     && fromg->pos <= prev_pos && fromg->to > prev_pos)
+                     && fromg->g.from <= prev_pos && fromg->g.to > prev_pos)
                    {
                      if (! cursor)
                        cursor = fromg, cursor_x = x + temp_width;
-                     cursor_width += fromg->width;
+                     cursor_width += fromg->g.xadv;
                    }
-                 temp_width += fromg++->width;
+                 temp_width += fromg++->g.xadv;
                }
              if (cursor)
                {
@@ -1262,10 +1132,10 @@ render_glyphs (MFrame *frame, MDrawWindow win, int x, int y, int width,
       (*frame->driver->region_to_rect) (region, &rect);
       if (rect.x > x)
        {
-         while (g != gend && x + g->rbearing <= rect.x)
+         while (g != gend && x + g->g.rbearing <= rect.x)
            {
-             x += g->width;
-             width -= g++->width;
+             x += g->g.xadv;
+             width -= g++->g.xadv;
              while (! g->enabled && g != gend)
                g++;
            }
@@ -1274,14 +1144,14 @@ render_glyphs (MFrame *frame, MDrawWindow win, int x, int y, int width,
       if (rect.x < x + width)
        {
          while (g != gend
-                && (x + width - gend[-1].width + gend[-1].lbearing >= rect.x))
+                && (x + width - gend[-1].g.xadv + gend[-1].g.lbearing >= rect.x))
            {
-             width -= (--gend)->width;
+             width -= (--gend)->g.xadv;
              while (! gend->enabled && g != gend)
                gend--;
            }
          if (g != gend)
-           while (gend->type != GLYPH_ANCHOR && gend[-1].to == gend->to)
+           while (gend->type != GLYPH_ANCHOR && gend[-1].g.to == gend->g.to)
              gend++;
        }
     }
@@ -1291,21 +1161,21 @@ render_glyphs (MFrame *frame, MDrawWindow win, int x, int y, int width,
       if (g->enabled)
        {
          MRealizedFace *rface = g->rface;
-         int width = g->width;
+         int width = g->g.xadv;
          MGlyph *from_g = g++;
 
          /* Handle the glyphs of the same type/face at once.  */
          while (g != gend
                 && g->type == from_g->type
                 && g->rface == rface
-                && ((g->code == MCHAR_INVALID_CODE)
-                    == (from_g->code == MCHAR_INVALID_CODE))
+                && ((g->g.code == MCHAR_INVALID_CODE)
+                    == (from_g->g.code == MCHAR_INVALID_CODE))
                 && g->enabled)
-           width += g++->width;
+           width += g++->g.xadv;
 
          if (from_g->type == GLYPH_CHAR)
            {
-             if (rface->rfont && from_g->code != MCHAR_INVALID_CODE)
+             if (rface->rfont && from_g->g.code != MCHAR_INVALID_CODE)
                (rface->rfont->driver->render) (win, x, y, gstring, from_g, g,
                                                reverse, region);
              else
@@ -1349,11 +1219,11 @@ find_overlapping_glyphs (MGlyphString *gstring, int *left, int *right,
 
   for (g = MGLYPH (*left) - 1, x = 0; g->type != GLYPH_ANCHOR; g--)
     {
-      x -= g->width;
-      if (x + g->rbearing > 0)
+      x -= g->g.xadv;
+      if (x + g->g.rbearing > 0)
        {
-         while (g[-1].pos == g->pos && g[-1].type != GLYPH_ANCHOR)
-           x -= (--g)->width;
+         while (g[-1].g.from == g->g.from && g[-1].type != GLYPH_ANCHOR)
+           x -= (--g)->g.xadv;
          left_idx = GLYPH_INDEX (g);
          left_x = x;
        }
@@ -1361,11 +1231,11 @@ find_overlapping_glyphs (MGlyphString *gstring, int *left, int *right,
 
   for (g = MGLYPH (*right), x = 0; g->type != GLYPH_ANCHOR; g++)
     {
-      x += g->width;
-      if (x - g->width + g->lbearing < 0)
+      x += g->g.xadv;
+      if (x - g->g.xadv + g->g.lbearing < 0)
        {
-         while (g->pos == g[1].pos && g[1].type != GLYPH_ANCHOR)
-           x += (++g)->width;
+         while (g->g.from == g[1].g.from && g[1].type != GLYPH_ANCHOR)
+           x += (++g)->g.xadv;
          right_idx = GLYPH_INDEX (g) + 1;
          right_x = x;
        }
@@ -1413,13 +1283,13 @@ gstring_width (MGlyphString *gstring, int from, int to,
   if (rbearing)
     *rbearing = 0;
   for (g = MGLYPH (1), width = 0; g->type != GLYPH_ANCHOR; g++)
-    if (g->pos >= from && g->pos < to)
+    if (g->g.from >= from && g->g.from < to)
       {
-       if (lbearing && width + g->lbearing < *lbearing)
-         *lbearing = width + g->lbearing;
-       if (rbearing && width + g->rbearing > *rbearing)
-         *rbearing = width + g->rbearing;
-       width += g->width;
+       if (lbearing && width + g->g.lbearing < *lbearing)
+         *lbearing = width + g->g.lbearing;
+       if (rbearing && width + g->g.rbearing > *rbearing)
+         *rbearing = width + g->g.rbearing;
+       width += g->g.xadv;
       }
   return width;
 }
@@ -1519,19 +1389,19 @@ alloc_gstring (MFrame *frame, MText *mt, int pos, MDrawControl *control,
          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->glyphs[1].g.c = '\n';
+         gstring->glyphs[1].g.code = '\n';
        }
       gstring->from = pos;
       g = MGLYPH (0);
       g->rface = frame->rface;
-      g->pos = g->to = pos;
+      g->g.from = g->g.to = pos;
       g++;
       g->rface = frame->rface;
-      g->pos = pos++, g->to = pos;
+      g->g.from = pos++, g->g.to = pos;
       g++;
       g->rface = frame->rface;
-      g->pos = g->to = pos;
+      g->g.from = g->g.to = pos;
       gstring->to = pos;
     }
   else
@@ -1575,7 +1445,7 @@ truncate_gstring (MFrame *frame, MText *mt, MGlyphString *gstring)
   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_width[g->pos - gstring->from] += g->width;
+    pos_width[g->g.from - gstring->from] += g->g.xadv;
   for (i = 0, width = 0; i < gstring->to - gstring->from; i++)
     {
       if (pos_width[i] > 0)
@@ -1595,7 +1465,7 @@ truncate_gstring (MFrame *frame, MText *mt, MGlyphString *gstring)
       if (pos <= gstring->from)
        {
          g = find_glyph_in_gstring (gstring, gstring->from, 1);
-         pos = g->to;
+         pos = g->g.to;
        }
       else if (pos >= gstring->to)
        pos = gstring->to;
@@ -1603,7 +1473,7 @@ truncate_gstring (MFrame *frame, MText *mt, MGlyphString *gstring)
   else if (i == 0)
     {
       g = find_glyph_in_gstring (gstring, gstring->from, 1);
-      pos = g->to;
+      pos = g->g.to;
     }
   if (pos < gstring->to)
     {
@@ -1672,8 +1542,8 @@ get_gstring (MFrame *frame, MText *mt, int pos, int to, MDrawControl *control)
            gst->to += offset;
            for (i = 0; i < gst->used; i++)
              {
-               gst->glyphs[i].pos += offset;
-               gst->glyphs[i].to += offset;
+               gst->glyphs[i].g.from += offset;
+               gst->glyphs[i].g.to += offset;
              }
          }
       M17N_OBJECT_REF (gstring);
@@ -1794,13 +1664,13 @@ find_glyph_in_gstring (MGlyphString *gstring, int pos, int forwardp)
   if (forwardp)
     {
       for (g = MGLYPH (1); g->type != GLYPH_ANCHOR; g++)
-       if (g->pos <= pos && g->to > pos)
+       if (g->g.from <= pos && g->g.to > pos)
          break;
     }
   else
     {
       for (g = MGLYPH (gstring->used - 2); g->type != GLYPH_ANCHOR; g--)
-       if (g->pos <= pos && g->to > pos)
+       if (g->g.from <= pos && g->g.to > pos)
          break;
     }
   return g;
@@ -1810,62 +1680,43 @@ find_glyph_in_gstring (MGlyphString *gstring, int pos, int forwardp)
 /* for debugging... */
 char work[16];
 
-char *
-dump_combining_code (int code)
-{
-  char *vallign = "tcbB";
-  char *hallign = "lcr";
-  char *p;
-  int off_x, off_y;
-
-  if (! code)
-    return "none";
-  if (COMBINING_BY_CLASS_P (code))
-    code = combining_code_from_class (COMBINING_CODE_CLASS (code));
-  work[0] = vallign[COMBINING_CODE_BASE_Y (code)];
-  work[1] = hallign[COMBINING_CODE_BASE_X (code)];
-  off_y = COMBINING_CODE_OFF_Y (code) - 128;
-  off_x = COMBINING_CODE_OFF_X (code) - 128;
-  if (off_y > 0)
-    sprintf (work + 2, "+%d", off_y);
-  else if (off_y < 0)
-    sprintf (work + 2, "%d", off_y);
-  else if (off_x == 0)
-    sprintf (work + 2, ".");
-  p = work + strlen (work);
-  if (off_x > 0)
-    sprintf (p, ">%d", off_x);
-  else if (off_x < 0)
-    sprintf (p, "<%d", -off_x);
-  p += strlen (p);
-  p[0] = vallign[COMBINING_CODE_ADD_Y (code)];
-  p[1] = hallign[COMBINING_CODE_ADD_X (code)];
-  p[2] = '\0';
-  return work;
-}
-
 void
-dump_gstring (MGlyphString *gstring, int indent)
+dump_gstring (MGlyphString *gstring, int indent, int type)
 {
   char *prefix = (char *) alloca (indent + 1);
-  MGlyph *g, *last_g = gstring->glyphs + gstring->used;
+  MGlyph *g, *first_g, *last_g;
 
   memset (prefix, 32, indent);
   prefix[indent] = 0;
 
   fprintf (stderr, "(glyph-string");
 
-  for (g = MGLYPH (0); g < last_g; g++)
-    fprintf (stderr,
-            "\n%s  (%02d %s pos:%d-%d c:%04X code:%04X face:%x cmb:%s w:%02d bidi:%d)",
-            prefix,
-            g - gstring->glyphs,
-            (g->type == GLYPH_SPACE ? "SPC": g->type == GLYPH_PAD ? "PAD"
-             : g->type == GLYPH_ANCHOR ? "ANC"
-             : g->type == GLYPH_BOX ? "BOX" : "CHR"),
-            g->pos, g->to, g->c, g->code, (unsigned) g->rface,
-            dump_combining_code (g->combining_code),
-            g->width, g->bidi_level);
+  if (type == 0)
+    {
+      first_g = MGLYPH (0);
+      last_g = first_g + gstring->used;
+    }
+  else
+    {
+      first_g = (MGlyph *) ((MFLTGlyphString *) gstring)->glyphs;
+      last_g = first_g + ((MFLTGlyphString *) gstring)->used;
+    }
+
+  for (g = first_g; g < last_g; g++)
+    {
+      fprintf (stderr,
+              "\n%s  (%02d %s pos:%d-%d c:%04X code:%04X face:%x w:%02d bidi:%d",
+              prefix,
+              g - first_g,
+              (g->type == GLYPH_SPACE ? "SPC": g->type == GLYPH_PAD ? "PAD"
+               : g->type == GLYPH_ANCHOR ? "ANC"
+               : g->type == GLYPH_BOX ? "BOX" : "CHR"),
+              g->g.from, g->g.to, g->g.c, g->g.code, (unsigned) g->rface,
+              g->g.xadv, g->bidi_level);
+      if (g->g.xoff || g->g.yoff)
+       fprintf (stderr, " off:%d,%d", g->g.xoff, g->g.yoff);
+      fprintf (stderr, ")");
+    }
   fprintf (stderr, ")");
 }
 \f
@@ -2403,15 +2254,15 @@ mdraw_text_per_char_extents (MFrame *frame,
     }
 
   for (g = MGLYPH (1), x = 0; g->type != GLYPH_ANCHOR; g++)
-    if (g->pos >= from && g->pos < to)
+    if (g->g.from >= from && g->g.from < to)
       {
-       int start = g->pos;
-       int end = g->to;
-       int width = g->width;
-       int lbearing = g->lbearing;
-       int rbearing = g->rbearing;
-       int ascent = g->ascent;
-       int descent = g->descent;
+       int start = g->g.from;
+       int end = g->g.to;
+       int width = g->g.xadv;
+       int lbearing = g->g.lbearing;
+       int rbearing = g->g.rbearing;
+       int ascent = g->g.ascent;
+       int descent = g->g.descent;
        int logical_ascent;
        int logical_descent;
 
@@ -2425,17 +2276,17 @@ mdraw_text_per_char_extents (MFrame *frame,
            logical_ascent = g->rface->ascent;
            logical_descent = g->rface->descent;
          }
-       for (g++; g->type != GLYPH_ANCHOR && g->pos == start; g++)
+       for (g++; g->type != GLYPH_ANCHOR && g->g.from == start; g++)
          {
-           if (lbearing < width + g->lbearing)
-             lbearing = width + g->lbearing;
-           if (rbearing < width + g->rbearing)
-             rbearing = width + g->rbearing;
-           width += g->width;
-           if (ascent < g->ascent)
-             ascent = g->ascent;
-           if (descent < g->descent)
-             descent = g->descent;
+           if (lbearing < width + g->g.lbearing)
+             lbearing = width + g->g.lbearing;
+           if (rbearing < width + g->g.rbearing)
+             rbearing = width + g->g.rbearing;
+           width += g->g.xadv;
+           if (ascent < g->g.ascent)
+             ascent = g->g.ascent;
+           if (descent < g->g.descent)
+             descent = g->g.descent;
          }
 
        if (end > to)
@@ -2568,9 +2419,9 @@ mdraw_coordinates_position (MFrame *frame, MText *mt, int from, int to,
     {
       width = gstring->indent;
       for (g = MGLYPH (1); g->type != GLYPH_ANCHOR; g++)
-       if (g->pos >= from && g->pos < to)
+       if (g->g.from >= from && g->g.from < to)
          {
-           width += g->width;
+           width += g->g.xadv;
            if (width > x_offset)
              break;
          }
@@ -2579,18 +2430,18 @@ mdraw_coordinates_position (MFrame *frame, MText *mt, int from, int to,
     {
       width = - gstring->indent;
       for (g = MGLYPH (gstring->used - 2); g->type != GLYPH_ANCHOR; g--)
-       if (g->pos >= from && g->pos < to)
+       if (g->g.from >= from && g->g.from < to)
          {
-           width -= g->width;
+           width -= g->g.xadv;
            if (width < x_offset)
              break;
          }
     }
   if (g->type == GLYPH_ANCHOR
       && control->two_dimensional
-      && g[-1].c == '\n')
+      && g[-1].g.c == '\n')
     g--;
-  from = g->pos;
+  from = g->g.from;
   M17N_OBJECT_UNREF (gstring->top);
 
   return from;
@@ -2653,23 +2504,23 @@ mdraw_glyph_info (MFrame *frame, MText *mt, int from, int pos,
   if (! control->orientation_reversed)
     {
       info->x = gstring->indent;
-      for (g = MGLYPH (1); g->pos > pos || g->to <= pos; g++)
-       info->x += g->width;
+      for (g = MGLYPH (1); g->g.from > pos || g->g.to <= pos; g++)
+       info->x += g->g.xadv;
     }
   else
     {
       info->x = - gstring->indent;
-      for (g = MGLYPH (gstring->used - 2); g->pos > pos || g->to <= pos; g--)
-       info->x -= g->width;
-      while (g[-1].to == g->to)
+      for (g = MGLYPH (gstring->used - 2); g->g.from > pos || g->g.to <= pos; g--)
+       info->x -= g->g.xadv;
+      while (g[-1].g.to == g->g.to)
        g--;
     }
-  info->from = g->pos;
-  info->to = g->to;
-  info->metrics.x = g->lbearing;
+  info->from = g->g.from;
+  info->to = g->g.to;
+  info->metrics.x = g->g.lbearing;
   info->metrics.y = - gstring->line_ascent;
   info->metrics.height = gstring->height;
-  info->metrics.width = - g->lbearing + g->width;
+  info->metrics.width = - g->g.lbearing + g->g.xadv;
   if (g->rface->rfont)
     info->font = (MFont *) g->rface->rfont;
   else
@@ -2681,7 +2532,7 @@ mdraw_glyph_info (MFrame *frame, MText *mt, int from, int pos,
       /* The logically previous glyph is on this line.  */
       MGlyph *g_tmp = find_glyph_in_gstring (gstring, info->from - 1, 1);
 
-      info->prev_from = g_tmp->pos;
+      info->prev_from = g_tmp->g.from;
     }
   else if (info->line_from > 0
           && gstring->from > 0)
@@ -2691,14 +2542,14 @@ mdraw_glyph_info (MFrame *frame, MText *mt, int from, int pos,
                                       gstring->from, control);
       MGlyph *g_tmp = find_glyph_in_gstring (gst, info->from - 1, 1);
 
-      info->prev_from = g_tmp->pos;
+      info->prev_from = g_tmp->g.from;
       M17N_OBJECT_UNREF (gst->top);
     }
   else
     info->prev_from = -1;
 
   if (GLYPH_INDEX (g) > 1)
-    info->left_from = g[-1].pos, info->left_to = g[-1].to;
+    info->left_from = g[-1].g.from, info->left_to = g[-1].g.to;
   else if (! control->orientation_reversed)
     {
       if (info->line_from > 0)
@@ -2709,7 +2560,7 @@ mdraw_glyph_info (MFrame *frame, MText *mt, int from, int pos,
 
          gst = get_gstring (frame, mt, p, gstring->from, control);
          g_tmp = gst->glyphs + (gst->used - 2);
-         info->left_from = g_tmp->pos, info->left_to = g_tmp->to;
+         info->left_from = g_tmp->g.from, info->left_to = g_tmp->g.to;
          M17N_OBJECT_UNREF (gst->top);
        }
       else
@@ -2725,7 +2576,7 @@ mdraw_glyph_info (MFrame *frame, MText *mt, int from, int pos,
 
          gst = get_gstring (frame, mt, p, p + 1, control);
          g_tmp = gst->glyphs + (gst->used - 2);
-         info->left_from = g_tmp->pos, info->left_to = g_tmp->to;
+         info->left_from = g_tmp->g.from, info->left_to = g_tmp->g.to;
          M17N_OBJECT_UNREF (gst->top);
        }
       else
@@ -2737,7 +2588,7 @@ mdraw_glyph_info (MFrame *frame, MText *mt, int from, int pos,
       /* The logically next glyph is on this line.   */
       MGlyph *g_tmp = find_glyph_in_gstring (gstring, info->to, 0);
 
-      info->next_to = g_tmp->to;
+      info->next_to = g_tmp->g.to;
     }
   else if (info->to + (control->cursor_width == 0) <= mtext_nchars (mt))
     {
@@ -2746,19 +2597,19 @@ mdraw_glyph_info (MFrame *frame, MText *mt, int from, int pos,
       MGlyphString *gst = get_gstring (frame, mt, p, p + 1, control);
       MGlyph *g_tmp = find_glyph_in_gstring (gst, p, 0);
 
-      info->next_to = g_tmp->to;
+      info->next_to = g_tmp->g.to;
       M17N_OBJECT_UNREF (gst->top);
     }
   else
     info->next_to = -1;
 
-  for (info->logical_width = (g++)->width;
-       g->pos == pos && g->type != GLYPH_ANCHOR;
-       info->metrics.width += g->width, info->logical_width += (g++)->width);
-  info->metrics.width += g[-1].rbearing - g[-1].width;
+  for (info->logical_width = (g++)->g.xadv;
+       g->g.from == pos && g->type != GLYPH_ANCHOR;
+       info->metrics.width += g->g.xadv, info->logical_width += (g++)->g.xadv);
+  info->metrics.width += g[-1].g.rbearing - g[-1].g.xadv;
 
   if (g->type != GLYPH_ANCHOR)
-    info->right_from = g->pos, info->right_to = g->to;
+    info->right_from = g->g.from, info->right_to = g->g.to;
   else if (! control->orientation_reversed)
     {
       if (gstring->to + (control->cursor_width == 0) <= mtext_nchars (mt))
@@ -2767,7 +2618,7 @@ mdraw_glyph_info (MFrame *frame, MText *mt, int from, int pos,
          M17N_OBJECT_UNREF (gstring->top);
          gstring = get_gstring (frame, mt, pos, pos + 1, control);
          g = MGLYPH (1);
-         info->right_from = g->pos, info->right_to = g->to;
+         info->right_from = g->g.from, info->right_to = g->g.to;
        }
       else
        info->right_from = info->right_to = -1;
@@ -2780,7 +2631,7 @@ mdraw_glyph_info (MFrame *frame, MText *mt, int from, int pos,
          M17N_OBJECT_UNREF (gstring->top);
          gstring = get_gstring (frame, mt, pos, pos + 1, control);
          g = MGLYPH (1);
-         info->right_from = g->pos, info->right_to = g->to;
+         info->right_from = g->g.from, info->right_to = g->g.to;
        }
       else
        info->right_from = info->right_to = -1;
@@ -2849,31 +2700,31 @@ mdraw_glyph_list (MFrame *frame, MText *mt, int from, int to,
   for (g = MGLYPH (1), n = 0; g->type != GLYPH_ANCHOR; g++)
     {
       if (g->type == GLYPH_BOX
-         || g->pos < from || g->pos >= to)
+         || g->g.from < from || g->g.from >= to)
        continue;
       if (g->type == GLYPH_PAD)
        {
          if (g->left_padding)
-           pad_width = g->width;
+           pad_width = g->g.xadv;
          else if (n > 0)
            {
              pad_width = 0;
-             glyphs[-1].x_advance += g->width;
+             glyphs[-1].x_advance += g->g.xadv;
            }
          continue;
        }
       if (n < array_size)
        {
-         glyphs->from = g->pos;
-         glyphs->to = g->to;
-         glyphs->glyph_code = g->code;
-         glyphs->x_off = g->xoff + pad_width;
-         glyphs->y_off = g->yoff;
-         glyphs->lbearing = g->lbearing;
-         glyphs->rbearing = g->rbearing;
-         glyphs->ascent = g->ascent;
-         glyphs->descent = g->descent;
-         glyphs->x_advance = g->width + pad_width;
+         glyphs->from = g->g.from;
+         glyphs->to = g->g.to;
+         glyphs->glyph_code = g->g.code;
+         glyphs->x_off = g->g.xoff + pad_width;
+         glyphs->y_off = g->g.yoff;
+         glyphs->lbearing = g->g.lbearing;
+         glyphs->rbearing = g->g.rbearing;
+         glyphs->ascent = g->g.ascent;
+         glyphs->descent = g->g.descent;
+         glyphs->x_advance = g->g.xadv + pad_width;
          glyphs->y_advance = 0;
          if (g->rface->rfont)
            {
index 5185d0f..983228c 100644 (file)
@@ -702,15 +702,15 @@ mface__realize (MFrame *frame, MFace **faces, int num, int size, MFont *font)
                                                font);
       rfont = NULL;
       mfont__set_spec_from_face (&spec, &merged_face);
-      mfont_put_prop (&spec, Mregistry, Miso8859_1);
-      spec.source = MFONT_SOURCE_X;
+      mfont_put_prop (&spec, Mregistry, Municode_bmp);
+      spec.source = MFONT_SOURCE_FT;
       font = mfont__select (frame, &spec, 0);
       if (font)
        rfont = mfont__open (frame, font, &spec);
       if (! rfont)
        {
-         mfont_put_prop (&spec, Mregistry, Municode_bmp);
-         spec.source = MFONT_SOURCE_FT;
+         mfont_put_prop (&spec, Mregistry, Miso8859_1);
+         spec.source = MFONT_SOURCE_X;
          font = mfont__select (frame, &spec, 0);
          if (font)
            rfont = mfont__open (frame, font, &spec);
@@ -729,29 +729,32 @@ mface__realize (MFrame *frame, MFace **faces, int num, int size, MFont *font)
       rface->layouter = rfont->layouter;
       rfont->layouter = Mnil;
       work_gstring.glyphs[0].rface = rface;
-      work_gstring.glyphs[0].code = MCHAR_INVALID_CODE;
+      work_gstring.glyphs[0].g.code = MCHAR_INVALID_CODE;
+      work_gstring.glyphs[0].g.measured = 0;
       mfont__get_metric (&work_gstring, 0, 1);
-      rface->ascent = work_gstring.glyphs[0].ascent;
-      rface->descent = work_gstring.glyphs[0].descent;
-      work_gstring.glyphs[0].code
+      rface->ascent = work_gstring.glyphs[0].g.ascent;
+      rface->descent = work_gstring.glyphs[0].g.descent;
+      work_gstring.glyphs[0].g.code
        = mfont__encode_char (frame, (MFont *) rfont, NULL, ' ');
-      if (work_gstring.glyphs[0].code != MCHAR_INVALID_CODE)
+      if (work_gstring.glyphs[0].g.code != MCHAR_INVALID_CODE)
        {
+         work_gstring.glyphs[0].g.measured = 0;
          mfont__get_metric (&work_gstring, 0, 1);
-         rface->space_width = work_gstring.glyphs[0].width;
+         rface->space_width = work_gstring.glyphs[0].g.xadv;
        }
       else
        rface->space_width = rfont->spec.size / 10;
       if (rfont->average_width)
-       rface->average_width = rfont->average_width;
+       rface->average_width = rfont->average_width >> 6;
       else
        {
-         work_gstring.glyphs[0].code
+         work_gstring.glyphs[0].g.code
            = mfont__encode_char (frame, (MFont *) rfont, NULL, 'x');
-         if (work_gstring.glyphs[0].code != MCHAR_INVALID_CODE)
+         if (work_gstring.glyphs[0].g.code != MCHAR_INVALID_CODE)
            {
+             work_gstring.glyphs[0].g.measured = 0;
              mfont__get_metric (&work_gstring, 0, 1);
-             rface->average_width = work_gstring.glyphs[0].width;
+             rface->average_width = work_gstring.glyphs[0].g.xadv;
            }
          else
            rface->average_width = rface->space_width;
@@ -818,7 +821,7 @@ mface__for_chars (MSymbol script, MSymbol language, MSymbol charset,
       if (! rfont)
        {
          for (; from_g < to_g && from_g->rface->font; from_g++)
-           from_g->code = MCHAR_INVALID_CODE;
+           from_g->g.code = MCHAR_INVALID_CODE;
        }
       else
        {
@@ -833,28 +836,33 @@ mface__for_chars (MSymbol script, MSymbol language, MSymbol charset,
              new->layouter = rfont->layouter;
              rfont->layouter = Mnil;
              new->non_ascii_list = NULL;
-             new->ascent = rfont->ascent;
-             new->descent = rfont->descent;
+             new->ascent = rfont->ascent >> 6;
+             new->descent = rfont->descent >> 6;
            } 
          for (; from_g < to_g && from_g->rface->font; from_g++)
            {
              from_g->rface = new;
              if (new->layouter)
                {
-                 from_g->code = mfont__flt_encode_char (new->layouter, 
-                                                        from_g->c);
-                 if (from_g->code == MCHAR_INVALID_CODE)
+                 MFLT *flt = mflt_get (new->layouter);
+                 MCharTable *coverage;
+
+                 if (! flt
+                     || ((coverage = mflt_coverage (flt))
+                         && ! (from_g->g.code
+                               = (unsigned) mchartable_lookup (coverage,
+                                                               from_g->g.c))))
                    {
                      from_g->rface = rface;
-                     from_g->code = mfont__encode_char (rfont->frame, 
-                                                        (MFont *) rfont,
-                                                        NULL, from_g->c);
+                     from_g->g.code = mfont__encode_char (rfont->frame, 
+                                                          (MFont *) rfont,
+                                                          NULL, from_g->g.c);
                    }
                }
              else
-               from_g->code = mfont__encode_char (rfont->frame, 
-                                                  (MFont *) rfont,
-                                                  NULL, from_g->c);
+               from_g->g.code = mfont__encode_char (rfont->frame, 
+                                                    (MFont *) rfont,
+                                                    NULL, from_g->g.c);
            }
        }
       return from_g;
@@ -865,10 +873,10 @@ mface__for_chars (MSymbol script, MSymbol language, MSymbol charset,
       for (i = 0; i < num; i++)
        {
          unsigned code = mfont__encode_char (rfont->frame, (MFont *) rfont,
-                                             NULL, from_g[i].c);
+                                             NULL, from_g[i].g.c);
          if (code == MCHAR_INVALID_CODE)
            break;
-         from_g[i].code = code;
+         from_g[i].g.code = code;
        }
       if (i == num || from_g[i].rface->font)
        return from_g + i;
@@ -883,7 +891,7 @@ mface__for_chars (MSymbol script, MSymbol language, MSymbol charset,
     }
   else
     {
-      from_g->code = MCHAR_INVALID_CODE;
+      from_g->g.code = MCHAR_INVALID_CODE;
       num = 1;
       rfont = NULL;
       layouter = Mnil;
@@ -919,8 +927,8 @@ mface__for_chars (MSymbol script, MSymbol language, MSymbol charset,
              new->non_ascii_list = NULL;
              if (rfont)
                {
-                 new->ascent = rfont->ascent;
-                 new->descent = rfont->descent;
+                 new->ascent = rfont->ascent >> 6;
+                 new->descent = rfont->descent >> 6;
                }
            }
          while (g < from_g)
index 4a11c0b..882463b 100644 (file)
@@ -35,6 +35,7 @@
 #include "mtext.h"
 #include "symbol.h"
 #include "plist.h"
+#include "internal-flt.h"
 #include "internal-gui.h"
 #include "font.h"
 #include "face.h"
@@ -222,7 +223,7 @@ MACRO-NAME ::= SYMBOL
 
 */
 
-static int mdebug_mask = MDEBUG_FONT_FLT;
+static int mdebug_flag = MDEBUG_FONT_FLT;
 
 MSymbol Mlayouter;
 
@@ -256,7 +257,7 @@ static MPlist *flt_list;
 #define CMD_ID_TO_INDEX(id) (CMD_ID_OFFSET_INDEX - (id))
 #define INDEX_TO_CMD_ID(idx) (CMD_ID_OFFSET_INDEX - (idx))
 
-static MSymbol Mcond, Mrange;
+static MSymbol Mcond, Mrange, Mexist;
 
 #define GLYPH_CODE_P(code)     \
   ((code) >= GLYPH_CODE_MIN && (code) <= GLYPH_CODE_MAX)
@@ -279,7 +280,8 @@ enum FontLayoutCmdRuleSrcType
     SRC_REGEX,
     SRC_INDEX,
     SRC_SEQ,
-    SRC_RANGE
+    SRC_RANGE,
+    SRC_EXIST
   };
 
 typedef struct
@@ -298,6 +300,9 @@ typedef struct
     struct {
       int from, to;
     } range;
+    struct {
+      int c;
+    } exist;
   } src;
 
   int n_cmds;
@@ -382,7 +387,7 @@ load_category_table (MPlist *plist)
            MERROR (MERROR_FONT, NULL);
          category_code = MPLIST_INTEGER (elt);
        }
-      if (! isalpha (category_code))
+      if (! isalnum (category_code))
        MERROR (MERROR_FONT, NULL);
 
       if (from == to)
@@ -686,6 +691,21 @@ load_command (FontLayoutStage *stage, MPlist *plist,
                  cmd->body.rule.src.range.to
                    = (unsigned) MPLIST_INTEGER (pl);
                }
+             else if (MPLIST_SYMBOL_P (pl) && size <= 2)
+               {
+                 if (MPLIST_SYMBOL (pl) != Mexist)
+                   MERROR (MERROR_FLT, INVALID_CMD_ID);
+                 cmd->body.rule.src_type = SRC_EXIST;
+                 if (size == 1)
+                   cmd->body.rule.src.exist.c = -1;
+                 else
+                   {
+                     pl = MPLIST_NEXT (pl);
+                     if (! MPLIST_INTEGER_P (pl))
+                       MERROR (MERROR_DRAW, INVALID_CMD_ID);
+                     cmd->body.rule.src.exist.c = MPLIST_INTEGER (pl);
+                   }
+               }
              else
                MERROR (MERROR_DRAW, INVALID_CMD_ID);
            }
@@ -993,8 +1013,9 @@ run_rule (int depth,
       if (i < len)
        return 0;
       to = from + len;
-      MDEBUG_PRINT3 ("\n [FLT] %*s(SEQ 0x%X", depth, "",
-                    rule->src.seq.codes[0]);
+      if (MDEBUG_FLAG () > 2)
+       MDEBUG_PRINT3 ("\n [FLT] %*s(SEQ 0x%X", depth, "",
+                      rule->src.seq.codes[0]);
     }
   else if (rule->src_type == SRC_RANGE)
     {
@@ -1007,8 +1028,9 @@ run_rule (int depth,
        return 0;
       ctx->code_offset = head - rule->src.range.from;
       to = from + 1;
-      MDEBUG_PRINT4 ("\n [FLT] %*s(RANGE 0x%X-0x%X", depth, "",
-                    rule->src.range.from, rule->src.range.to);
+      if (MDEBUG_FLAG () > 2)
+       MDEBUG_PRINT4 ("\n [FLT] %*s(RANGE 0x%X-0x%X", depth, "",
+                      rule->src.range.from, rule->src.range.to);
     }
   else if (rule->src_type == SRC_REGEX)
     {
@@ -1025,10 +1047,11 @@ run_rule (int depth,
                        NMATCH, pmatch, 0);
       if (result == 0 && pmatch[0].rm_so == 0)
        {
-         MDEBUG_PRINT5 ("\n [FLT] %*s(REGEX \"%s\" \"%s\" %d", depth, "",
-                        rule->src.re.pattern,
-                        ctx->encoded + from - ctx->encoded_offset,
-                        pmatch[0].rm_eo);
+         if (MDEBUG_FLAG () > 2)
+           MDEBUG_PRINT5 ("\n [FLT] %*s(REGEX \"%s\" \"%s\" %d", depth, "",
+                          rule->src.re.pattern,
+                          ctx->encoded + from - ctx->encoded_offset,
+                          pmatch[0].rm_eo);
          ctx->encoded[to - ctx->encoded_offset] = saved_code;
          for (i = 0; i < NMATCH; i++)
            {
@@ -1057,7 +1080,35 @@ run_rule (int depth,
       if (from < 0)
        return 0;
       to = ctx->match_indices[rule->src.match_idx * 2 + 1];
-      MDEBUG_PRINT3 ("\n [FLT] %*s(INDEX %d", depth, "", rule->src.match_idx);
+      if (MDEBUG_FLAG () > 2)
+       MDEBUG_PRINT3 ("\n [FLT] %*s(INDEX %d", depth, "", rule->src.match_idx);
+    }
+  else if (rule->src_type == SRC_EXIST)
+    {
+      MGlyph *g = MGLYPH (from);
+      int encoded = g->otf_encoded;
+      unsigned code;
+
+      if (rule->src.exist.c < 0)
+       {
+         if (from >= to)
+           return 0;
+         code = g->code;
+         to = from + 1;
+       }
+      else
+       {
+         code = rule->src.exist.c;
+         to = from;
+         encoded = 0;
+       }
+      if (! encoded)
+       {
+         code = (g->rface->rfont->driver->encode_char
+                 (NULL, (MFont *) g->rface->rfont, NULL, code));
+         if (code == MCHAR_INVALID_CODE)
+           return 0;
+       }
     }
 
   consumed = 0;
@@ -1081,7 +1132,8 @@ run_rule (int depth,
     }
 
   ctx->match_indices = saved_match_indices;
-  MDEBUG_PRINT (")");
+  if (MDEBUG_FLAG () > 2)
+    MDEBUG_PRINT (")");
   return (rule->src_type == SRC_INDEX ? orig_from : to);
 }
 
@@ -1092,7 +1144,8 @@ run_cond (int depth,
 {
   int i, pos = 0;
 
-  MDEBUG_PRINT2 ("\n [FLT] %*s(COND", depth, "");
+  if (MDEBUG_FLAG () > 2)
+    MDEBUG_PRINT2 ("\n [FLT] %*s(COND", depth, "");
   depth++;
   for (i = 0; i < cond->n_cmds; i++)
     {
@@ -1104,7 +1157,8 @@ run_cond (int depth,
     }
   if (pos < 0)
     MERROR (MERROR_DRAW, -1);
-  MDEBUG_PRINT (")");
+  if (MDEBUG_FLAG () > 2)
+    MDEBUG_PRINT (")");
   return (pos);
 }
 
@@ -1116,11 +1170,17 @@ run_otf (int depth,
 #ifdef HAVE_OTF
   int from_idx = gstring->used;
 
-  MDEBUG_PRINT4 ("\n [FLT] %*s(OTF %s,%s)", depth, "",
-                (! otf_cmd->features[MFONT_OTT_GSUB].str ? ""
-                 : otf_cmd->features[MFONT_OTT_GSUB].str),
-                (! otf_cmd->features[MFONT_OTT_GPOS].str ? ""
-                 : otf_cmd->features[MFONT_OTT_GPOS].str));
+  if (MDEBUG_FLAG () > 2)
+#if 0
+    MDEBUG_PRINT4 ("\n [FLT] %*s(OTF %s,%s)", depth, "",
+                  (! otf_cmd->features[MFONT_OTT_GSUB].str ? ""
+                   : otf_cmd->features[MFONT_OTT_GSUB].str),
+                  (! otf_cmd->features[MFONT_OTT_GPOS].str ? ""
+                   : otf_cmd->features[MFONT_OTT_GPOS].str));
+#else
+    MDEBUG_PRINT3 ("\n [FLT] %*s:otf=%s", depth, "",
+                  MSYMBOL_NAME (otf_cmd->otf));
+#endif
   to = mfont__ft_drive_otf (gstring, from, to, otf_cmd);
   if (ctx->cluster_begin_idx)
     for (; from_idx < gstring->used; from_idx++)
@@ -1143,13 +1203,14 @@ run_command (int depth, int id, MGlyphString *gstring, int from, int to,
 
       /* Direct code (== id + ctx->code_offset) output.
         The source is not consumed.  */
-      if (from < to)
+      if (from < to || from == 1)
        g = *(MGLYPH (from));
       else
        g = *(MGLYPH (from - 1));
       g.type = GLYPH_CHAR;
       g.code = ctx->code_offset + id;
-      MDEBUG_PRINT3 ("\n [FLT] %*s(DIRECT 0x%X", depth, "", g.code);
+      if (MDEBUG_FLAG () > 2)
+       MDEBUG_PRINT3 ("\n [FLT] %*s(DIRECT 0x%X", depth, "", g.code);
       if (ctx->combining_code)
        g.combining_code = ctx->combining_code;
       if (ctx->left_padding)
@@ -1166,7 +1227,8 @@ run_command (int depth, int id, MGlyphString *gstring, int from, int to,
       APPEND_GLYPH (gstring, g);
       UPDATE_CLUSTER_RANGE (ctx, g);
       ctx->code_offset = ctx->combining_code = ctx->left_padding = 0;
-      MDEBUG_PRINT (")");
+      if (MDEBUG_FLAG () > 2)
+       MDEBUG_PRINT (")");
       return (from);
     }
 
@@ -1193,8 +1255,9 @@ run_command (int depth, int id, MGlyphString *gstring, int from, int to,
   if (id <= CMD_ID_OFFSET_COMBINING)
     {
       ctx->combining_code = CMD_ID_TO_COMBINING_CODE (id);
-      MDEBUG_PRINT3 ("\n [FLT] %*s(CMB %s)", depth, "",
-                    dump_combining_code (ctx->combining_code));
+      if (MDEBUG_FLAG () > 2)
+       MDEBUG_PRINT3 ("\n [FLT] %*s(CMB %s)", depth, "",
+                      dump_combining_code (ctx->combining_code));
       return from;
     }
 
@@ -1211,7 +1274,13 @@ run_command (int depth, int id, MGlyphString *gstring, int from, int to,
          g.left_padding = ctx->left_padding;
        APPEND_GLYPH (gstring, g);
        UPDATE_CLUSTER_RANGE (ctx, g);
-       MDEBUG_PRINT3 ("\n [FLT] %*s(COPY 0x%X)", depth, "", g.code);
+       if (MDEBUG_FLAG () > 2)
+         {
+           if (g.type == GLYPH_PAD)
+             MDEBUG_PRINT2 ("\n [FLT] %*s(COPY |)", depth, "");
+           else
+             MDEBUG_PRINT3 ("\n [FLT] %*s(COPY 0x%X)", depth, "", g.code);
+         }
        ctx->code_offset = ctx->combining_code = ctx->left_padding = 0;
        return (from + 1);
       }
@@ -1219,7 +1288,8 @@ run_command (int depth, int id, MGlyphString *gstring, int from, int to,
     case CMD_ID_CLUSTER_BEGIN:
       if (! ctx->cluster_begin_idx)
        {
-         MDEBUG_PRINT3 ("\n [FLT] %*s<%d", depth, "", MGLYPH (from)->pos);
+         if (MDEBUG_FLAG () > 2)
+           MDEBUG_PRINT3 ("\n [FLT] %*s<%d", depth, "", MGLYPH (from)->pos);
          ctx->cluster_begin_idx = gstring->used;
          ctx->cluster_begin_pos = MGLYPH (from)->pos;
          ctx->cluster_end_pos = MGLYPH (from)->to;
@@ -1231,7 +1301,8 @@ run_command (int depth, int id, MGlyphString *gstring, int from, int to,
        {
          int i;
 
-         MDEBUG_PRINT1 (" %d>", ctx->cluster_end_pos);
+         if (MDEBUG_FLAG () > 2)
+           MDEBUG_PRINT1 (" %d>", ctx->cluster_end_pos);
          for (i = ctx->cluster_begin_idx; i < gstring->used; i++)
            {
              MGLYPH (i)->pos = ctx->cluster_begin_pos;
@@ -1255,14 +1326,16 @@ run_command (int depth, int id, MGlyphString *gstring, int from, int to,
       }
 
     case CMD_ID_LEFT_PADDING:
-      MDEBUG_PRINT2 ("\n [FLT] %*s[", depth, "");
+      if (MDEBUG_FLAG () > 2)
+       MDEBUG_PRINT2 ("\n [FLT] %*s[", depth, "");
       ctx->left_padding = 1;
       return from;
 
     case CMD_ID_RIGHT_PADDING:
       if (gstring->used > 0)
        {
-         MDEBUG_PRINT2 ("\n [FLT] %*s]", depth, "");
+         if (MDEBUG_FLAG () > 2)
+           MDEBUG_PRINT2 ("\n [FLT] %*s]", depth, "");
          gstring->glyphs[gstring->used - 1].right_padding = 1;
        }
       return from;
@@ -1280,6 +1353,7 @@ mfont__flt_init (void)
   Mcond = msymbol ("cond");
   Mrange = msymbol ("range");
   Mlayouter = msymbol ("layouter");
+  Mexist = msymbol ("exist");
   flt_list = mplist ();
   return 0;
 }
@@ -1383,26 +1457,36 @@ mfont__flt_run (MGlyphString *gstring, int from, int to, MRealizedFace *rface)
   from_pos = MGLYPH (from)->pos;
   to_pos = MGLYPH (to)->pos;
 
+  if (MDEBUG_FLAG ())
+    {
+      MDEBUG_PRINT ("\n [FLT]   (SOURCE");
+      for (i = from; i < to; i++)
+       {
+         if (i > from && (i - from) % 8 == 0)
+           MDEBUG_PRINT ("\n [FLT]          ");
+         MDEBUG_PRINT1 (" %04X", MGLYPH (i)->c);
+       }
+      MDEBUG_PRINT (")");
+    }
+
   for (stage_idx = 0; 1; stage_idx++)
     {
       int len = to - from;
       int result;
 
       ctx.code_offset = ctx.combining_code = ctx.left_padding = 0;
-      MDEBUG_PRINT2 ("\n [FLT]   (STAGE %d \"%s\"", stage_idx, ctx.encoded);
-      if (mdebug__flag & mdebug_mask
-         && ctx.encoded_offset < to)
+      if (MDEBUG_FLAG () > 2)
        {
-         if (gstring->glyphs[ctx.encoded_offset].type == GLYPH_PAD)
-           fprintf (stderr, " (|");
-         else
-           fprintf (stderr, " (%X", gstring->glyphs[ctx.encoded_offset].code);
-         for (i = ctx.encoded_offset + 1; i < to; i++)
+         MDEBUG_PRINT2 ("\n [FLT]   (STAGE %d \"%s\"", stage_idx,
+                        ctx.encoded + from - ctx.encoded_offset);
+         fprintf (stderr, " (");
+         for (i = from; i < to ; i++)
            {
              if (gstring->glyphs[i].type == GLYPH_PAD)
-               fprintf (stderr, " |");
+               fprintf (stderr, "%*s|", (i > from), "");
              else
-               fprintf (stderr, " %X", gstring->glyphs[i].code);
+               fprintf (stderr, "%*s%04X", (i > from), "",
+                        gstring->glyphs[i].code);
            }
          fprintf (stderr, ")");
        }
@@ -1412,7 +1496,8 @@ mfont__flt_run (MGlyphString *gstring, int from, int to, MRealizedFace *rface)
 
       result = run_command (4, INDEX_TO_CMD_ID (0), gstring,
                            ctx.encoded_offset, to, &ctx);
-      MDEBUG_PRINT (")");
+      if (MDEBUG_FLAG () > 2)
+       MDEBUG_PRINT (")");
       if (result < 0)
        return -1;
       to = from + (gstring->used - gidx);
@@ -1521,24 +1606,49 @@ mfont__flt_run (MGlyphString *gstring, int from, int to, MRealizedFace *rface)
            latest = glyphs[i];
        }
     }
-  MDEBUG_PRINT ("\n [FLT]   (RESULT (");
-  if (mdebug__flag & mdebug_mask
-      && ctx.encoded_offset < to)
+  if (MDEBUG_FLAG ())
     {
-      if (gstring->glyphs[from].type == GLYPH_PAD)
-       fprintf (stderr, "|");
-      else
-       fprintf (stderr, "%X", gstring->glyphs[from].code);
-      for (from++; from < to; from++)
+      MDEBUG_PRINT ("\n [FLT]   (RESULT");
+      for (i = from; i < to;)
        {
-         if (gstring->glyphs[from].type == GLYPH_PAD)
-           fprintf (stderr, " |");
+         if (MGLYPH (i)->otf_encoded)
+           i++;
          else
-           fprintf (stderr, " %X", gstring->glyphs[from].code);
+           {
+             int j = i++;
+
+             while (i < to && ! MGLYPH (i)->otf_encoded) i++;
+             mfont__get_metric (gstring, j, i);
+           }
        }
-      fprintf (stderr, "))");
+      if (MDEBUG_FLAG () > 1)
+       for (i = 0; from < to; from++, i++)
+         {
+           MGlyph *g;
+           int width, xoff, yoff;
+
+           if (i > 0 && i % 4 == 0)
+             MDEBUG_PRINT ("\n [FLT]          ");
+           g = MGLYPH (from);
+           g->otf_encoded = 1;
+           width = g->width, xoff = g->xoff, yoff = g->yoff;
+           if (g->right_padding && g->rbearing > g->width)
+             width = g->rbearing;
+           if (g->left_padding && g->lbearing < 0)
+             {
+               width += - g->lbearing;
+               xoff += - g->lbearing;
+             }
+           MDEBUG_PRINT4 (" (%04X %d %d %d)", g->code, width, xoff, yoff);
+         }
+      else
+       for (; from < to; from++)
+         {
+           MGLYPH (from)->otf_encoded = 1;
+           MDEBUG_PRINT1 (" %04X", MGLYPH (from)->code);
+         }
+      MDEBUG_PRINT ("))\n");
     }
-  MDEBUG_PRINT (")\n");
 
   return to;
 }
index 08f352d..1c59534 100644 (file)
@@ -37,6 +37,7 @@
 #include "plist.h"
 #include "symbol.h"
 #include "language.h"
+#include "internal-flt.h"
 #include "internal-gui.h"
 #include "font.h"
 #include "face.h"
@@ -47,7 +48,7 @@
 #include FT_BDF_H
 #endif
 
-static int mdebug_mask = MDEBUG_FONT;
+static int mdebug_flag = MDEBUG_FONT;
 
 #ifdef HAVE_FONTCONFIG
 #include <fontconfig/fcfreetype.h>
@@ -1032,7 +1033,7 @@ ft_list_script (MSymbol script)
 }
 
 static int
-ft_check_otf (MFontFT *ft_info, MFontCapability *cap, FT_Face ft_face)
+ft_check_cap_otf (MFontFT *ft_info, MFontCapability *cap, FT_Face ft_face)
 {
 #ifdef HAVE_OTF
   if (ft_info->otf == invalid_otf)
@@ -1262,7 +1263,7 @@ ft_list_capability (MSymbol capability)
        {
          for (pl = plist; ! MPLIST_TAIL_P (pl);)
            {
-             if (ft_check_otf (MPLIST_VAL (pl), cap, NULL) < 0)
+             if (ft_check_cap_otf (MPLIST_VAL (pl), cap, NULL) < 0)
                mplist_pop (pl);
              else
                pl = MPLIST_NEXT (pl);
@@ -1394,7 +1395,7 @@ ft_select (MFrame *frame, MFont *font, int limited_size)
 
       for (pl = plist; ! MPLIST_TAIL_P (pl);)
        {
-         if (cap->script_tag && ft_check_otf (MPLIST_VAL (pl), cap, NULL) < 0)
+         if (cap->script_tag && ft_check_cap_otf (MPLIST_VAL (pl), cap, NULL) < 0)
            {
              mplist_pop (pl);
              continue;
@@ -1540,10 +1541,12 @@ ft_open (MFrame *frame, MFont *font, MFont *spec, MRealizedFont *rfont)
   rfont->driver = &mfont__ft_driver;
   rfont->info = ft_rfont;
   rfont->fontp = ft_face;
-  rfont->ascent = ft_face->size->metrics.ascender >> 6;
-  rfont->descent = - ft_face->size->metrics.descender >> 6;
-  rfont->max_advance = ft_face->size->metrics.max_advance >> 6;
+  rfont->ascent = ft_face->size->metrics.ascender;
+  rfont->descent = - ft_face->size->metrics.descender;
+  rfont->max_advance = ft_face->size->metrics.max_advance;
   rfont->baseline_offset = 0;
+  rfont->x_ppem = ft_face->size->metrics.x_ppem;
+  rfont->y_ppem = ft_face->size->metrics.y_ppem;
 #ifdef HAVE_FTBDF_H
   {
     BDF_PropertyRec prop;
@@ -1551,16 +1554,16 @@ ft_open (MFrame *frame, MFont *font, MFont *spec, MRealizedFont *rfont)
     if (! FT_IS_SCALABLE (ft_face)
        && FT_Get_BDF_Property (ft_face, "_MULE_BASELINE_OFFSET", &prop) == 0)
       {
-       rfont->baseline_offset = prop.u.integer;
-       rfont->ascent += prop.u.integer;
-       rfont->descent -= prop.u.integer;
+       rfont->baseline_offset = prop.u.integer << 6;
+       rfont->ascent += prop.u.integer << 6;
+       rfont->descent -= prop.u.integer << 6;
       }
   }
 #endif /* HAVE_FTBDF_H */
   if (FT_IS_SCALABLE (ft_face))
     rfont->average_width = 0;
   else
-    rfont->average_width = ft_face->available_sizes->width;
+    rfont->average_width = ft_face->available_sizes->width << 6;
   rfont->next = MPLIST_VAL (frame->realized_font_list);
   MPLIST_VAL (frame->realized_font_list) = rfont;
   MDEBUG_PRINT ("  ok\n");
@@ -1578,18 +1581,17 @@ ft_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
 
   for (; g != gend; g++)
     {
-      if (g->code == MCHAR_INVALID_CODE)
+      if (g->g.measured)
+       continue;
+      if (g->g.code == MCHAR_INVALID_CODE)
        {
          if (FT_IS_SCALABLE (ft_face))
            {
-             unsigned unitsPerEm10 = ft_face->units_per_EM * 10;
-             int size = rfont->spec.size;
-
-             g->lbearing = 0;
-             g->rbearing = ft_face->max_advance_width * size / unitsPerEm10;
-             g->width = g->rbearing;
-             g->ascent = ft_face->ascender * size / unitsPerEm10;
-             g->descent = (- ft_face->descender) * size / unitsPerEm10;
+             g->g.lbearing = 0;
+             g->g.rbearing = ft_face->size->metrics.max_advance;
+             g->g.xadv = g->g.rbearing;
+             g->g.ascent = ft_face->size->metrics.ascender;
+             g->g.descent = - ft_face->size->metrics.descender;
            }
          else
            {
@@ -1597,26 +1599,26 @@ ft_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
              BDF_PropertyRec prop;
 #endif /* HAVE_FTBDF_H */
 
-             g->lbearing = 0;
-             g->rbearing = g->width = ft_face->available_sizes->width;
+             g->g.lbearing = 0;
+             g->g.rbearing = g->g.xadv = ft_face->available_sizes->width << 6;
 #ifdef HAVE_FTBDF_H
              if (FT_Get_BDF_Property (ft_face, "ASCENT", &prop) == 0)
                {
-                 g->ascent = prop.u.integer;
+                 g->g.ascent = prop.u.integer << 6;
                  FT_Get_BDF_Property (ft_face, "DESCENT", &prop);
-                 g->descent = prop.u.integer;
+                 g->g.descent = prop.u.integer << 6;
                  if (FT_Get_BDF_Property (ft_face, "_MULE_BASELINE_OFFSET",
                                           & prop) == 0)
                    {
-                     g->ascent += prop.u.integer;
-                     g->descent -= prop.u.integer;
+                     g->g.ascent += prop.u.integer << 6;
+                     g->g.descent -= prop.u.integer << 6;
                    }
                }
              else
 #endif /* HAVE_FTBDF_H */
                {
-                 g->ascent = ft_face->available_sizes->height;
-                 g->descent = 0;
+                 g->g.ascent = ft_face->available_sizes->height << 6;
+                 g->g.descent = 0;
                }
            }
        }
@@ -1624,16 +1626,18 @@ ft_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
        {
          FT_Glyph_Metrics *metrics;
 
-         FT_Load_Glyph (ft_face, (FT_UInt) g->code, FT_LOAD_DEFAULT);
+         FT_Load_Glyph (ft_face, (FT_UInt) g->g.code, FT_LOAD_DEFAULT);
          metrics = &ft_face->glyph->metrics;
-         g->lbearing = (metrics->horiBearingX >> 6);
-         g->rbearing = (metrics->horiBearingX + metrics->width) >> 6;
-         g->width = metrics->horiAdvance >> 6;
-         g->ascent = metrics->horiBearingY >> 6;
-         g->descent = (metrics->height - metrics->horiBearingY) >> 6;
+         g->g.lbearing = metrics->horiBearingX;
+         g->g.rbearing = metrics->horiBearingX + metrics->width;
+         g->g.xadv = metrics->horiAdvance;
+         g->g.ascent = metrics->horiBearingY;
+         g->g.descent = metrics->height - metrics->horiBearingY;
        }
-      g->ascent += rfont->baseline_offset;
-      g->descent -= rfont->baseline_offset;
+      g->g.yadv = 0;
+      g->g.ascent += rfont->baseline_offset;
+      g->g.descent -= rfont->baseline_offset;
+      g->g.measured = 1;
     }
 }
 
@@ -1745,6 +1749,7 @@ ft_render (MDrawWindow win, int x, int y,
   int i, j;
   MPointTable point_table[8];
   int baseline_offset;
+  int pixel_mode = -1;
 
   if (from == to)
     return;
@@ -1752,7 +1757,7 @@ ft_render (MDrawWindow win, int x, int y,
   /* It is assured that the all glyphs in the current range use the
      same realized face.  */
   ft_face = rface->rfont->fontp;
-  baseline_offset = rface->rfont->baseline_offset;
+  baseline_offset = rface->rfont->baseline_offset >> 6;
 
   if (! gstring->anti_alias)
     {
@@ -1766,7 +1771,7 @@ ft_render (MDrawWindow win, int x, int y,
   for (i = 0; i < 8; i++)
     point_table[i].p = point_table[i].points;
 
-  for (g = from; g < to; x += g++->width)
+  for (g = from; g < to; x += g++->g.xadv)
     {
       unsigned char *bmp;
       int intensity;
@@ -1774,21 +1779,19 @@ ft_render (MDrawWindow win, int x, int y,
       int xoff, yoff;
       int width, pitch;
 
-      FT_Load_Glyph (ft_face, (FT_UInt) g->code, load_flags);
-      yoff = y - ft_face->glyph->bitmap_top + g->yoff;
+      FT_Load_Glyph (ft_face, (FT_UInt) g->g.code, load_flags);
+      if (pixel_mode < 0)
+       pixel_mode = ft_face->glyph->bitmap.pixel_mode;
+      yoff = y - ft_face->glyph->bitmap_top + g->g.yoff;
       bmp = ft_face->glyph->bitmap.buffer;
       width = ft_face->glyph->bitmap.width;
       pitch = ft_face->glyph->bitmap.pitch;
-      if (! gstring->anti_alias)
-       pitch *= 8;
-      if (width > pitch)
-       width = pitch;
 
-      if (gstring->anti_alias)
+      if (pixel_mode != FT_PIXEL_MODE_MONO)
        for (i = 0; i < ft_face->glyph->bitmap.rows;
             i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
          {
-           xoff = x + ft_face->glyph->bitmap_left + g->xoff;
+           xoff = x + ft_face->glyph->bitmap_left + g->g.xoff;
            for (j = 0; j < width; j++, xoff++)
              {
                intensity = bmp[j] >> 5;
@@ -1813,7 +1816,7 @@ ft_render (MDrawWindow win, int x, int y,
        for (i = 0; i < ft_face->glyph->bitmap.rows;
             i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
          {
-           xoff = x + ft_face->glyph->bitmap_left + g->xoff;
+           xoff = x + ft_face->glyph->bitmap_left + g->g.xoff;
            for (j = 0; j < width; j++, xoff++)
              {
                intensity = bmp[j / 8] & (1 << (7 - (j % 8)));
@@ -1835,7 +1838,7 @@ ft_render (MDrawWindow win, int x, int y,
        }
     }
 
-  if (gstring->anti_alias)
+  if (pixel_mode != FT_PIXEL_MODE_MONO)
     {
       for (i = 1; i < 8; i++)
        if (point_table[i].p != point_table[i].points)
@@ -2037,14 +2040,17 @@ ft_check_capability (MRealizedFont *rfont, MSymbol capability)
   MRealizedFontFT *ft_rfont = rfont->info;
   MFontCapability *cap = mfont__get_capability (capability);
 
-  if (cap->script != Mnil
-      && ft_check_script (ft_info, cap->script, ft_rfont->ft_face) < 0)
+  if (cap->script_tag)
+    {
+      if (ft_check_cap_otf (ft_info, cap, ft_rfont->ft_face) < 0)
+       return -1;
+    }
+  else if (cap->script != Mnil
+          && ft_check_script (ft_info, cap->script, ft_rfont->ft_face) < 0)
     return -1;
   if (cap->language != Mnil
       && ft_check_language (ft_info, cap->language, ft_rfont->ft_face) < 0)
     return -1;
-  if (cap->script_tag && ft_check_otf (ft_info, cap, ft_rfont->ft_face) < 0)
-    return -1;
   return 0;
 }
 
@@ -2095,6 +2101,8 @@ ft_encapsulate (MFrame *frame, MSymbol data_type, void *data)
   rfont->descent = - ft_face->size->metrics.descender >> 6;
   rfont->max_advance = ft_face->size->metrics.max_advance >> 6;
   rfont->baseline_offset = 0;
+  rfont->x_ppem = ft_face->size->metrics.x_ppem;
+  rfont->y_ppem = ft_face->size->metrics.y_ppem;
 #ifdef HAVE_FTBDF_H
   {
     BDF_PropertyRec prop;
@@ -2102,16 +2110,16 @@ ft_encapsulate (MFrame *frame, MSymbol data_type, void *data)
     if (! FT_IS_SCALABLE (ft_face)
        && FT_Get_BDF_Property (ft_face, "_MULE_BASELINE_OFFSET", &prop) == 0)
       {
-       rfont->baseline_offset = prop.u.integer;
-       rfont->ascent += prop.u.integer;
-       rfont->descent -= prop.u.integer;
+       rfont->baseline_offset = prop.u.integer << 6;
+       rfont->ascent += prop.u.integer << 6;
+       rfont->descent -= prop.u.integer << 6;
       }
   }
 #endif /* HAVE_FTBDF_H */
   if (FT_IS_SCALABLE (ft_face))
     rfont->average_width = 0;
   else
-    rfont->average_width = ft_face->available_sizes->width;
+    rfont->average_width = ft_face->available_sizes->width << 6;
   rfont->next = MPLIST_VAL (frame->realized_font_list);
   MPLIST_VAL (frame->realized_font_list) = rfont;
 
@@ -2128,6 +2136,359 @@ ft_close (MRealizedFont *rfont)
   free (rfont);
 }
 
+static int 
+ft_check_otf (MFLTFont *font, MFLTOtfSpec *spec)
+{
+#ifdef HAVE_OTF
+  MRealizedFont *rfont = ((MFLTFontForRealized *) font)->rfont;
+  MFontFT *ft_info = (MFontFT *) rfont->font;
+  OTF *otf;
+  OTF_Tag *tags;
+  int i, n, negative;
+
+  if (ft_info->otf == invalid_otf)
+    goto not_otf;
+  otf = ft_info->otf;
+  if (! otf)
+    {
+      MRealizedFontFT *ft_rfont = rfont->info;
+
+#if (LIBOTF_MAJOR_VERSION > 0 || LIBOTF_MINOR_VERSION > 9 || LIBOTF_RELEASE_NUMBER > 4)
+      otf = OTF_open_ft_face (ft_rfont->ft_face);
+#else
+      otf = OTF_open (MSYMBOL_NAME (ft_info->font.file));
+#endif
+      if (! otf)
+       {
+         ft_info->otf = invalid_otf;
+         goto not_otf;
+       }
+      ft_info->otf = otf;
+    }
+
+  for (i = 0; i < 2; i++)
+    {
+      if (! spec->features[i])
+       continue;
+      for (n = 0; spec->features[i][n]; n++);
+      tags = alloca (sizeof (OTF_Tag) * n);
+      for (n = 0, negative = 0; spec->features[i][n]; n++)
+       {
+         if (spec->features[i][n] == 0xFFFFFFFF)
+           negative = 1;
+         else if (negative)
+           tags[n - 1] = spec->features[i][n] | 0x80000000;
+         else
+           tags[n] = spec->features[i][n];
+       }
+      if (n - negative > 0
+         && OTF_check_features (otf, i == 0, spec->script, spec->langsys,
+                                tags, n - negative) != 1)
+       return 0;
+    }
+  return 1;
+#endif /* HAVE_OTF */
+ not_otf:
+  return ((! spec->features[0] || spec->features[0][0] == 0xFFFFFFFF)
+         && (! spec->features[1] || spec->features[1][0] == 0xFFFFFFFF));
+}
+
+#ifdef HAVE_OTF
+
+#define DEVICE_DELTA(table, size)                              \
+  (((size) >= (table).StartSize && (size) <= (table).EndSize)  \
+   ? (table).DeltaValue[(size) - (table).StartSize] << 6       \
+   : 0)
+
+void
+adjust_anchor (OTF_Anchor *anchor, FT_Face ft_face,
+              unsigned code, int x_ppem, int y_ppem, int *x, int *y)
+{
+  if (anchor->AnchorFormat == 2)
+    {
+      FT_Outline *outline;
+      int ap = anchor->f.f1.AnchorPoint;
+
+      FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
+      outline = &ft_face->glyph->outline;
+      if (ap < outline->n_points)
+       {
+         *x = outline->points[ap].x << 6;
+         *y = outline->points[ap].y << 6;
+       }
+    }
+  else if (anchor->AnchorFormat == 3)
+    {
+      if (anchor->f.f2.XDeviceTable.offset)
+       *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, x_ppem);
+      if (anchor->f.f2.YDeviceTable.offset)
+       *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, y_ppem);
+    }
+}
+#endif /* HAVE_OTF */
+
+static int 
+ft_drive_otf (MFLTFont *font, MFLTOtfSpec *spec,
+             MFLTGlyphString *in, int from, int to,
+             MFLTGlyphString *out, MFLTGlyphAdjustment *adjustment)
+{
+  int len = to - from;
+  int i, j, gidx;
+  MRealizedFont *rfont = ((MFLTFontForRealized *) font)->rfont;
+  MRealizedFontFT *ft_rfont = rfont->info;
+  MFontFT *ft_info = (MFontFT *) rfont->font;
+#ifdef HAVE_OTF
+  MGlyph *in_glyphs = (MGlyph *) (in->glyphs);
+  MGlyph *out_glyphs = (MGlyph *) (out->glyphs);
+  OTF *otf;
+  OTF_GlyphString otf_gstring;
+  OTF_Glyph *otfg;
+  char script[5], *langsys = NULL;
+  char *gsub_features = NULL, *gpos_features = NULL;
+
+  if (len == 0)
+    return from;
+  if (ft_info->otf == invalid_otf)
+    goto simple_copy;
+  otf = ft_info->otf;
+  if (! otf)
+    {
+      MRealizedFontFT *ft_rfont = rfont->info;
+
+#if (LIBOTF_MAJOR_VERSION > 0 || LIBOTF_MINOR_VERSION > 9 || LIBOTF_RELEASE_NUMBER > 4)
+      otf = OTF_open_ft_face (ft_rfont->ft_face);
+#else
+      otf = OTF_open (MSYMBOL_NAME (ft_info->font.file));
+#endif
+      if (! otf)
+       {
+         ft_info->otf = invalid_otf;
+         goto simple_copy;
+       }
+      ft_info->otf = otf;
+    }
+
+  if (OTF_get_table (otf, "head") < 0)
+    {
+      OTF_close (otf);
+      ft_info->otf = invalid_otf;
+      goto simple_copy;
+    }
+
+  OTF_tag_name (spec->script, script);
+  if (spec->langsys)
+    {
+      langsys = alloca (5);
+      OTF_tag_name (spec->langsys, langsys);
+    }
+  for (i = 0; i < 2; i++)
+    {
+      char *p;
+
+      if (spec->features[i] && spec->features[i][1] != 0xFFFFFFFF)
+       {
+         for (j = 0; spec->features[i][j]; j++);
+         if (i == 0)
+           p = gsub_features = alloca (6 * j);
+         else
+           p = gpos_features = alloca (6 * j);
+         for (j = 0; spec->features[i][j]; j++)
+           {
+             if (spec->features[i][j] == 0xFFFFFFFF)
+               *p++ = '*', *p++ = ',';
+             else
+               {
+                 OTF_tag_name (spec->features[i][j], p);
+                 p[4] = ',';
+                 p += 5;
+               }
+           }
+         *--p = '\0';
+       }
+    }
+
+  otf_gstring.size = otf_gstring.used = len;
+  otf_gstring.glyphs = (OTF_Glyph *) malloc (sizeof (OTF_Glyph) * len);
+  memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
+  for (i = 0; i < len; i++)
+    {
+      otf_gstring.glyphs[i].c = ((MGlyph *)in->glyphs)[from + i].g.c;
+      otf_gstring.glyphs[i].glyph_id = ((MGlyph *)in->glyphs)[from + i].g.code;
+    }
+
+  OTF_drive_gdef (otf, &otf_gstring);
+  gidx = out->used;
+
+  if (gsub_features)
+    {
+      if (OTF_drive_gsub (otf, &otf_gstring, script, langsys, gsub_features)
+         < 0)
+       goto simple_copy;
+      if (out->allocated < out->used + otf_gstring.used)
+       return -2;
+      for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++, otfg++)
+       {
+         MGlyph *g = out_glyphs + out->used;
+         int j;
+
+         *g = in_glyphs[from + otfg->f.index.from];
+         g->g.c = 0;
+         for (j = from + otfg->f.index.from; j <= from + otfg->f.index.to; j++)
+           if (in_glyphs[j].g.code == otfg->glyph_id)
+             {
+               g->g.c = in_glyphs[j].g.c;
+               break;
+             }
+         if (g->g.code != otfg->glyph_id)
+           {
+             g->g.code = otfg->glyph_id;
+             g->g.measured = 0;
+           }
+         out->used++;
+       }
+    }
+  else
+    {
+      if (out->allocated < out->used + len)
+       return -2;
+      for (i = 0; i < len; i++)
+       out_glyphs[out->used++] = in_glyphs[from + i];
+    }
+
+  if (gpos_features)
+    {
+      FT_Face face;
+      MGlyph *base = NULL, *mark = NULL, *g;
+      int x_ppem, y_ppem, x_scale, y_scale;
+
+      if (OTF_drive_gpos (otf, &otf_gstring, script, langsys, gpos_features)
+         < 0)
+       return to;
+
+      face = ft_rfont->ft_face;
+      x_ppem = face->size->metrics.x_ppem;
+      y_ppem = face->size->metrics.y_ppem;
+      x_scale = face->size->metrics.x_scale;
+      y_scale = face->size->metrics.y_scale;
+
+      for (i = 0, otfg = otf_gstring.glyphs, g = out_glyphs + gidx;
+          i < otf_gstring.used; i++, otfg++, g++)
+       {
+         MGlyph *prev;
+
+         if (! otfg->glyph_id)
+           continue;
+         switch (otfg->positioning_type)
+           {
+           case 0:
+             break;
+           case 1:             /* Single */
+           case 2:             /* Pair */
+             {
+               int format = otfg->f.f1.format;
+
+               if (format & OTF_XPlacement)
+                 adjustment[i].xoff
+                   = otfg->f.f1.value->XPlacement * x_scale / 0x10000;
+               if (format & OTF_XPlaDevice)
+                 adjustment[i].xoff
+                   += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
+               if (format & OTF_YPlacement)
+                 adjustment[i].yoff
+                   = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000);
+               if (format & OTF_YPlaDevice)
+                 adjustment[i].yoff
+                   -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
+               if (format & OTF_XAdvance)
+                 adjustment[i].xadv
+                   += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
+               if (format & OTF_XAdvDevice)
+                 adjustment[i].xadv
+                   += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
+               if (format & OTF_YAdvance)
+                 adjustment[i].yadv
+                   += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
+               if (format & OTF_YAdvDevice)
+                 adjustment[i].yadv
+                   += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
+               adjustment[i].set = 1;
+             }
+             break;
+           case 3:             /* Cursive */
+             /* Not yet supported.  */
+             break;
+           case 4:             /* Mark-to-Base */
+           case 5:             /* Mark-to-Ligature */
+             if (! base)
+               break;
+             prev = base;
+             goto label_adjust_anchor;
+           default:            /* i.e. case 6 Mark-to-Mark */
+             if (! mark)
+               break;
+             prev = mark;
+
+           label_adjust_anchor:
+             {
+               int base_x, base_y, mark_x, mark_y;
+               int this_from, this_to;
+
+               base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
+               base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
+               mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
+               mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;;
+
+               if (otfg->f.f4.base_anchor->AnchorFormat != 1)
+                 adjust_anchor (otfg->f.f4.base_anchor, face, prev->g.code,
+                                x_ppem, y_ppem, &base_x, &base_y);
+               if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
+                 adjust_anchor (otfg->f.f4.mark_anchor, face, g->g.code,
+                                x_ppem, y_ppem, &mark_x, &mark_y);
+               adjustment[i].xoff = (base_x - mark_x);
+               adjustment[i].yoff = - (base_y - mark_y);
+               adjustment[i].back = (g - prev);
+               adjustment[i].xadv = 0;
+               adjustment[i].advance_is_absolute = 1;
+               adjustment[i].set = 1;
+               this_from = g->g.from;
+               this_to = g->g.to;
+               for (j = 0; prev + j < g; j++)
+                 {
+                   if (this_from > prev[j].g.from)
+                     this_from = prev[j].g.from;
+                   if (this_to < prev[j].g.to)
+                     this_to = prev[j].g.to;
+                 }
+               for (; prev <= g; prev++)
+                 {
+                   prev->g.from = this_from;
+                   prev->g.to = this_to;
+                 }
+             }
+           }
+         if (otfg->GlyphClass == OTF_GlyphClass0)
+           base = mark = g;
+         else if (otfg->GlyphClass == OTF_GlyphClassMark)
+           mark = g;
+         else
+           base = g;
+       }
+    }
+  free (otf_gstring.glyphs);
+  return to;
+
+ simple_copy:
+#endif /* HAVE_OTF */
+  if (out->allocated < out->used + len)
+    return -2;
+  font->get_metrics (font, in, from, to);
+  memcpy ((MGlyph *)out->glyphs + out->used, (MGlyph *) in->glyphs + from,
+         sizeof (MGlyph) * len);
+  out->used += len;
+  if (otf_gstring.glyphs)
+    free (otf_gstring.glyphs);
+  return to;
+}
 
 \f
 /* Internal API */
@@ -2135,7 +2496,7 @@ ft_close (MRealizedFont *rfont)
 MFontDriver mfont__ft_driver =
   { ft_select, ft_open, ft_find_metric, ft_has_char, ft_encode_char,
     ft_render, ft_list, ft_list_family_names, ft_check_capability,
-    ft_encapsulate, ft_close };
+    ft_encapsulate, ft_close, ft_check_otf, ft_drive_otf };
 
 int
 mfont__ft_init ()
@@ -2207,7 +2568,7 @@ mfont__ft_init ()
     msymbol_put (monospace, Mgeneric_family, monospace);
     msymbol_put (msymbol ("mono"), Mgeneric_family, monospace);
   }
-#endif
+#endif /* HAVE_FONTCONFIG */
 
   return 0;
 }
@@ -2339,297 +2700,4 @@ mfont__ft_unparse_name (MFont *font)
 }
 #endif /* HAVE_FONTCONFIG */
 
-\f
-#ifdef HAVE_OTF
-
-#define DEVICE_DELTA(table, size)                              \
-  (((size) >= (table).StartSize && (size) <= (table).EndSize)  \
-   ? (table).DeltaValue[(size) - (table).StartSize]            \
-   : 0)
-
-void
-adjust_anchor (OTF_Anchor *anchor, FT_Face ft_face,
-              unsigned code, int size, int *x, int *y)
-{
-  if (anchor->AnchorFormat == 2)
-    {
-      FT_Outline *outline;
-      int ap = anchor->f.f1.AnchorPoint;
-
-      FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
-      outline = &ft_face->glyph->outline;
-      if (ap < outline->n_points)
-       {
-         *x = outline->points[ap].x;
-         *y = outline->points[ap].y;
-       }
-    }
-  else if (anchor->AnchorFormat == 3)
-    {
-      if (anchor->f.f2.XDeviceTable.offset)
-       *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, size);
-      if (anchor->f.f2.YDeviceTable.offset)
-      *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, size);
-    }
-}
-
-int
-mfont__ft_drive_otf (MGlyphString *gstring, int from, int to,
-                    MFontCapability *cap)
-{
-  int len = to - from;
-  MGlyph *g = MGLYPH (from);
-  int i, gidx;
-  MRealizedFont *rfont;
-  MFontFT *ft_info;
-  OTF *otf;
-  OTF_GlyphString otf_gstring;
-  OTF_Glyph *otfg;
-  char *script, *langsys;
-  char *gsub_features, *gpos_features;
-  int need_cmap;
-
-  if (len == 0)
-    return from;
-
-  otf_gstring.glyphs = NULL;
-  rfont = g->rface->rfont;
-  ft_info = (MFontFT *) rfont->font;
-  if (ft_info->otf == invalid_otf)
-    goto simple_copy;
-  otf = ft_info->otf;
-  if (! otf)
-    {
-      MRealizedFontFT *ft_rfont = rfont->info;
-
-#if (LIBOTF_MAJOR_VERSION > 0 || LIBOTF_MINOR_VERSION > 9 || LIBOTF_RELEASE_NUMBER > 4)
-      otf = OTF_open_ft_face (ft_rfont->ft_face);
-#else
-      otf = OTF_open (MSYMBOL_NAME (ft_info->font.file));
-#endif
-      if (! otf)
-       {
-         ft_info->otf = invalid_otf;
-         goto simple_copy;
-       }
-      ft_info->otf = otf;
-    }
-  if (OTF_get_table (otf, "head") < 0)
-    {
-      OTF_close (otf);
-      ft_info->otf = invalid_otf;
-      goto simple_copy;
-    }
-
-  if (cap->script_tag)
-    {
-      script = alloca (5);
-      OTF_tag_name (cap->script_tag, script);
-    }
-  else
-    script = NULL;
-  if (cap->langsys_tag)
-    {
-      langsys = alloca (5);
-      OTF_tag_name (cap->langsys_tag, langsys);
-    }
-  else
-    langsys = NULL;
-  gsub_features = cap->features[MFONT_OTT_GSUB].str;
-  if (gsub_features && OTF_check_table (otf, "GSUB") < 0)
-    gsub_features = NULL;
-  gpos_features = cap->features[MFONT_OTT_GPOS].str;
-  if (gpos_features && OTF_check_table (otf, "GPOS") < 0)
-    gpos_features = NULL;
-
-  otf_gstring.size = otf_gstring.used = len;
-  otf_gstring.glyphs = (OTF_Glyph *) malloc (sizeof (OTF_Glyph) * len);
-  memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
-  for (i = 0, need_cmap = 0; i < len; i++)
-    {
-      if (gstring->glyphs[from + i].otf_encoded)
-       {
-         otf_gstring.glyphs[i].c = gstring->glyphs[from + i].c;
-         otf_gstring.glyphs[i].glyph_id = gstring->glyphs[from + i].code;
-       }
-      else
-       {
-         otf_gstring.glyphs[i].c = gstring->glyphs[from + i].code;
-         need_cmap++;
-       }
-    }
-  if (need_cmap
-      && OTF_drive_cmap (otf, &otf_gstring) < 0)
-    goto simple_copy;
-
-  OTF_drive_gdef (otf, &otf_gstring);
-  gidx = gstring->used;
-
-  if (gsub_features)
-    {
-      if (OTF_drive_gsub (otf, &otf_gstring, script, langsys, gsub_features)
-         < 0)
-       goto simple_copy;
-      for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++, otfg++)
-       {
-         MGlyph temp = *(MGLYPH (from + otfg->f.index.from));
-
-         temp.c = otfg->c;
-         temp.combining_code = 0;
-         if (otfg->glyph_id)
-           {
-             temp.code = otfg->glyph_id;
-             temp.otf_encoded = 1;
-           }
-         else
-           {
-             temp.code = temp.c;
-             temp.otf_encoded = 0;
-           }
-         temp.to = MGLYPH (from + otfg->f.index.to)->to;
-         MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
-       }
-    }
-  else
-    for (i = 0; i < len; i++)
-      {
-       MGlyph temp = gstring->glyphs[from + i];
-
-       if (otf_gstring.glyphs[i].glyph_id)
-         {
-           temp.code = otf_gstring.glyphs[i].glyph_id;
-           temp.otf_encoded = 1;
-         }
-       MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
-      }
-
-  (rfont->driver->find_metric) (rfont, gstring, gidx, gstring->used);
-
-  if (gpos_features)
-    {
-      int u;
-      int size10, size;
-      MGlyph *base = NULL, *mark = NULL;
-
-      if (OTF_check_features (otf, 0,
-                             cap->script_tag, cap->langsys_tag,
-                             cap->features[MFONT_OTT_GPOS].tags,
-                             cap->features[MFONT_OTT_GPOS].nfeatures) != 1
-         || (OTF_drive_gpos (otf, &otf_gstring, script, langsys,
-                             gpos_features) < 0))
-       return to;
-
-      u = otf->head->unitsPerEm;
-      size10 = rfont->spec.size;
-      size = size10 / 10;
-
-      for (i = 0, otfg = otf_gstring.glyphs, g = MGLYPH (gidx);
-          i < otf_gstring.used; i++, otfg++, g++)
-       {
-         MGlyph *prev;
-
-         if (! otfg->glyph_id)
-           continue;
-         switch (otfg->positioning_type)
-           {
-           case 0:
-             break;
-           case 1: case 2:
-             {
-               int format = otfg->f.f1.format;
-
-               if (format & OTF_XPlacement)
-                 g->xoff = otfg->f.f1.value->XPlacement * size10 / u / 10;
-               if (format & OTF_XPlaDevice)
-                 g->xoff += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, size);
-               if (format & OTF_YPlacement)
-                 g->yoff = - (otfg->f.f1.value->YPlacement * size10 / u / 10);
-               if (format & OTF_YPlaDevice)
-                 g->yoff -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, size);
-               if (format & OTF_XAdvance)
-                 g->width += otfg->f.f1.value->XAdvance * size10 / u / 10;
-               if (format & OTF_XAdvDevice)
-                 g->width += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, size);
-             }
-             break;
-           case 3:
-             /* Not yet supported.  */
-             break;
-           case 4: case 5:
-             if (! base)
-               break;
-             prev = base;
-             goto label_adjust_anchor;
-           default:            /* i.e. case 6 */
-             if (! mark)
-               break;
-             prev = mark;
-
-           label_adjust_anchor:
-             {
-               int base_x, base_y, mark_x, mark_y;
-
-               base_x = otfg->f.f4.base_anchor->XCoordinate * size10 / u / 10;
-               base_y = otfg->f.f4.base_anchor->YCoordinate * size10 / u / 10;
-               mark_x = otfg->f.f4.mark_anchor->XCoordinate * size10 / u / 10;
-               mark_y = otfg->f.f4.mark_anchor->YCoordinate * size10 / u / 10;
-
-               if (otfg->f.f4.base_anchor->AnchorFormat != 1)
-                 adjust_anchor (otfg->f.f4.base_anchor, rfont->fontp,
-                                prev->code, size, &base_x, &base_y);
-               if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
-                 adjust_anchor (otfg->f.f4.mark_anchor, rfont->fontp,
-                                g->code, size, &mark_x, &mark_y);
-               g->xoff = prev->xoff + (base_x - prev->width) - mark_x;
-               g->yoff = prev->yoff + mark_y - base_y;
-               g->combining_code = MAKE_PRECOMPUTED_COMBINDING_CODE ();
-             }
-           }
-         if (otfg->GlyphClass == OTF_GlyphClass0)
-           base = mark = g;
-         else if (otfg->GlyphClass == OTF_GlyphClassMark)
-           mark = g;
-         else
-           base = g;
-       }
-    }
-  free (otf_gstring.glyphs);
-  return to;
-
- simple_copy:
-  for (i = 0; i < len; i++)
-    {
-      MGlyph *g = MGLYPH (from + i);
-
-      if (! g->otf_encoded)
-       {
-         g->code = rfont->driver->encode_char (gstring->frame, (MFont *) rfont,
-                                               NULL, g->code);
-         g->otf_encoded = 1;
-       }
-    }
-
-  rfont->driver->find_metric (rfont, gstring, from, to);
-  for (i = 0; i < len; i++)
-    {
-      MGlyph temp = gstring->glyphs[from + i];
-      MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
-    }
-  if (otf_gstring.glyphs)
-    free (otf_gstring.glyphs);
-  return to;
-}
-
-
-int
-mfont__ft_decode_otf (MGlyph *g)
-{
-  MFontFT *ft_info = (MFontFT *) g->rface->rfont->font;
-  int c = OTF_get_unicode (ft_info->otf, (OTF_GlyphID) g->code);
-
-  return (c ? c : -1);
-}
-
-#endif /* HAVE_OTF */
-
 #endif /* HAVE_FREETYPE */
index 8f03529..b01dcc0 100644 (file)
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <ctype.h>
 
 #include "m17n-gui.h"
 #include "m17n-misc.h"
@@ -1177,8 +1178,6 @@ mfont__init ()
   if (mfont__ft_init () < 0)
     return -1;
 #endif /* HAVE_FREETYPE */
-  if (mfont__flt_init () < 0)
-    return -1;
 
   return 0;
 }
@@ -1189,7 +1188,6 @@ mfont__fini ()
   MPlist *plist;
   int i;
 
-  mfont__flt_fini ();
 #ifdef HAVE_FREETYPE
   mfont__ft_fini ();
 #endif /* HAVE_FREETYPE */
@@ -1644,19 +1642,91 @@ mfont__get_metric (MGlyphString *gstring, int from, int to)
   MGlyph *from_g = MGLYPH (from), *to_g = MGLYPH (to), *g;
   MRealizedFont *rfont = from_g->rface->rfont;
 
-  for (g = from_g; g != to_g; g++)
-    if (g->rface->rfont != rfont)
+  for (g = from_g; ; g++)
+    if (g == to_g || g->rface->rfont != rfont)
       {
        int idx = GLYPH_INDEX (g);
 
        (rfont->driver->find_metric) (rfont, gstring, from, idx);
-       from_g = g;
+       while (from_g < g)
+         {
+           from_g->g.xadv >>= 6;
+           from_g->g.yadv >>= 6;
+           from_g->g.xoff >>= 6;
+           from_g->g.yoff >>= 6;
+           from_g->g.ascent >>= 6;
+           from_g->g.descent >>= 6;
+           from_g->g.lbearing >>= 6;
+           from_g->g.rbearing >>= 6;
+           from_g++;
+         }
+       if (g == to_g)
+         break;
        rfont = g->rface->rfont;
        from = idx;
       }
-  (rfont->driver->find_metric) (rfont, gstring, from, GLYPH_INDEX (g));
 }
 
+int
+mfont__get_glyph_id (MFLTFont *font, MFLTGlyphString *gstring,
+                    int from, int to)
+{
+  MFont *mfont = (MFont *) ((MFLTFontForRealized *) font)->rfont;
+  MRealizedFont *rfont = ((MFLTFontForRealized *) font)->rfont;
+  MFontEncoding *encoding;
+  MFontDriver *driver = NULL;
+  MGlyph *glyphs = (MGlyph *) gstring->glyphs;
+
+  encoding = mfont->encoding ? mfont->encoding : find_encoding (mfont);
+  for (; from < to; from++)
+    {
+      MGlyph *g = glyphs + from;
+
+      if (g->g.encoded)
+       continue;
+      if (! encoding->encoding_charset)
+       g->g.code = MCHAR_INVALID_CODE;
+      else if (mfont->source == MFONT_SOURCE_X && encoding->repertory_charset)
+       g->g.code = ENCODE_CHAR (encoding->repertory_charset, g->g.c);
+      else
+       {
+         g->g.code = ENCODE_CHAR (encoding->encoding_charset, g->g.c);
+         if (g->g.code != MCHAR_INVALID_CODE)
+           {
+             if (! driver)
+               {
+                 if (mfont->type == MFONT_TYPE_REALIZED)
+                   driver = rfont->driver;
+                 else
+                   {
+                     driver = mplist_get (rfont->frame->font_driver_list,
+                                          mfont->source == MFONT_SOURCE_X
+                                          ? Mx : Mfreetype);
+                     if (! driver)
+                       MFATAL (MERROR_FONT);
+                   }
+               }
+             g->g.code
+               = (driver->encode_char) (rfont->frame, rfont->font, mfont,
+                                        g->g.code);
+           }
+       }
+      g->g.encoded = 1;
+    }
+  return 0;
+}
+
+int
+mfont__get_metrics (MFLTFont *font, MFLTGlyphString *gstring,
+                   int from, int to)
+{
+  MRealizedFont *rfont = ((MFLTFontForRealized *) font)->rfont;
+  MGlyphString gstr;
+
+  gstr.glyphs = (MGlyph *) gstring->glyphs;
+  (rfont->driver->find_metric) (rfont, &gstr, from, to);
+  return 0;
+}
 
 /* KEY <= MFONT_REGISTRY */
 
index 3932dfc..437800d 100644 (file)
@@ -159,6 +159,8 @@ struct MRealizedFont
      non-NULL, it must be a pointer to a managed object.  */
   void *info;
 
+  int x_ppem, y_ppem;
+
   int ascent, descent, max_advance, average_width, baseline_offset;
 
   /* Pointer to the font structure.  */
@@ -167,6 +169,11 @@ struct MRealizedFont
   MRealizedFont *next;
 };
 
+typedef struct MFLTFontForRealized {
+  MFLTFont font;
+  MRealizedFont *rfont;
+} MFLTFontForRealized;
+
 typedef struct {
   MFont *font;
   int score;
@@ -227,6 +234,12 @@ struct MFontDriver
   MRealizedFont *(*encapsulate) (MFrame *frame, MSymbol source, void *data);
 
   void (*close) (MRealizedFont *rfont);
+
+  int (*check_otf) (MFLTFont *font, MFLTOtfSpec *spec);
+
+  int (*drive_otf) (MFLTFont *font, MFLTOtfSpec *spec,
+                   MFLTGlyphString *in, int from, int to,
+                   MFLTGlyphString *out, MFLTGlyphAdjustment *adjustment);
 };
 
 /** Initialize the members of FONT.  */
@@ -313,6 +326,9 @@ extern int mfont__has_char (MFrame *frame, MFont *font, MFont *spec, int c);
 extern unsigned mfont__encode_char (MFrame *frame, MFont *font, MFont *spec,
                                    int c);
 
+extern int mfont__get_glyph_id (MFLTFont *font, MFLTGlyphString *gstring,
+                               int from, int to);
+
 extern MFont *mfont__select (MFrame *frame, MFont *font, int max_size);
 
 extern MFontList *mfont__list (MFrame *frame, MFont *spec, MFont *request,
@@ -322,6 +338,9 @@ extern MRealizedFont *mfont__open (MFrame *frame, MFont *font, MFont *spec);
 
 extern void mfont__get_metric (MGlyphString *gstring, int from, int to);
 
+extern int mfont__get_metrics (MFLTFont *font, MFLTGlyphString *gstring,
+                              int from, int to);
+
 extern void mfont__set_property (MFont *font, enum MFontProperty key,
                                 MSymbol val);
 
index 917cb44..7a431f3 100644 (file)
@@ -580,9 +580,15 @@ try_font_list (MFrame *frame, MFontList *font_list, MFont *request,
       /* Check if this font can display all glyphs.  */
       for (j = 0; j < *num; j++)
        {
-         int c = g[j].type == GLYPH_CHAR ? g[j].c : ' ';
+         int c = g[j].type == GLYPH_CHAR ? g[j].g.c : ' ';
+         MFLT *flt;
+         MCharTable *coverage;
+
          if (layouter != Mt
-             ? mfont__flt_encode_char (layouter, c) == MCHAR_INVALID_CODE
+             ? ((flt = mflt_get (layouter))
+                ? (coverage = mflt_coverage (flt),
+                   ! mchartable_lookup (coverage, c))
+                : 0)
              : ! mfont__has_char (frame, font, &font_list->object, c))
            break;
        }
@@ -590,6 +596,8 @@ try_font_list (MFrame *frame, MFontList *font_list, MFont *request,
        continue;
       if (j == *num || !all)
        {
+         MCharTable *coverage = NULL;
+
          /* We found a font that can display the requested range of
             glyphs.  */
          if (font->type == MFONT_TYPE_REALIZED)
@@ -602,15 +610,22 @@ try_font_list (MFrame *frame, MFontList *font_list, MFont *request,
              font_list->fonts[i].font = (MFont *) rfont;
            }
          rfont->layouter = layouter == Mt ? Mnil : layouter;
+         if (rfont->layouter)
+           {
+             MFLT *flt = mflt_get (rfont->layouter);
+
+             if (flt)
+               coverage = mflt_coverage (flt);
+           }
          *num = j;
          for (j = 0; j < *num; j++)
            {
-             int c = g[j].type == GLYPH_CHAR ? g[j].c : ' ';
+             int c = g[j].type == GLYPH_CHAR ? g[j].g.c : ' ';
 
-             g[j].code = (rfont->layouter
-                          ? mfont__flt_encode_char (rfont->layouter, c)
-                          : mfont__encode_char (frame, (MFont *) rfont,
-                                                &font_list->object, c));
+             g[j].g.code = (coverage
+                            ? (unsigned ) mchartable_lookup (coverage, c)
+                            : mfont__encode_char (frame, (MFont *) rfont,
+                                                  &font_list->object, c));
            }
          return rfont;
        }
index fb2f224..be065bd 100644 (file)
 #include <dlfcn.h>
 #endif
 
-#include "m17n-gui.h"
+#include "m17n.h"
 #include "m17n-misc.h"
 #include "internal.h"
 #include "mtext.h"
 #include "database.h"
 #include "charset.h"
 
-static int mdebug_mask = MDEBUG_INPUT;
+static int mdebug_flag = MDEBUG_INPUT;
 
 static int fully_initialized;
 
@@ -2354,7 +2354,7 @@ shift_state (MInputContext *ic, MSymbol state_name)
        state = (MIMState *) MPLIST_VAL (im_info->states);
     }
 
-  if (mdebug__flag & mdebug_mask)
+  if (MDEBUG_FLAG ())
     {
       if (orig_state)
        MDEBUG_PRINT2 ("\n  [IM] [%s] (shift %s)\n",
@@ -2537,7 +2537,7 @@ preedit_commit (MInputContext *ic, int need_prefix)
       mtext_put_prop_values (ic->preedit, 0, mtext_nchars (ic->preedit),
                             Mcandidate_index, NULL, 0);
       mtext_cat (ic->produced, ic->preedit);
-      if (mdebug__flag & mdebug_mask)
+      if (MDEBUG_FLAG ())
        {
          int i;
 
@@ -3845,7 +3845,7 @@ filter (MInputContext *ic, MSymbol key, void *arg)
 
   if (mtext_nchars (ic->produced) > 0)
     {
-      if (mdebug__flag & mdebug_mask)
+      if (MDEBUG_FLAG ())
        {
          MDEBUG_PRINT1 ("\n  [IM] [%s] (produced",
                         MSYMBOL_NAME (ic_info->state->name));
diff --git a/src/internal-flt.h b/src/internal-flt.h
new file mode 100644 (file)
index 0000000..e47dbb1
--- /dev/null
@@ -0,0 +1,53 @@
+/* internal-flt.h -- common header file for the internal FLT API.
+   Copyright (C) 2007
+     National Institute of Advanced Industrial Science and Technology (AIST)
+     Registration Number H15PRO112
+
+   This file is part of the m17n library.
+
+   The m17n library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License
+   as published by the Free Software Foundation; either version 2.1 of
+   the License, or (at your option) any later version.
+
+   The m17n library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   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., 51 Franklin Street, Fifth Floor,
+   02111-1307, USA.  */
+
+#ifndef _M_INTERNAL_FLT_H
+#define _M_INTERNAL_FLT_H
+
+#define MAKE_COMBINING_CODE(base_y, base_x, add_y, add_x, off_y, off_x)        \
+  (((off_y) << 16)                                                     \
+   | ((off_x) << 8)                                                    \
+   | ((base_x) << 6)                                                   \
+   | ((base_y) << 4)                                                   \
+   | ((add_x) << 2)                                                    \
+   | (add_y))
+
+#define COMBINING_CODE_OFF_Y(code) ((((code) >> 16) & 0xFF) - 128)
+#define COMBINING_CODE_OFF_X(code) ((((code) >> 8) & 0xFF) - 128)
+#define COMBINING_CODE_BASE_X(code) (((code) >> 6) & 0x3)
+#define COMBINING_CODE_BASE_Y(code) (((code) >> 4) & 0x3)
+#define COMBINING_CODE_ADD_X(code) (((code) >> 2) & 0x3)
+#define COMBINING_CODE_ADD_Y(code) ((code) & 0x3)
+
+#define MAKE_COMBINING_CODE_BY_CLASS(class) (0x1000000 | class)
+
+#define COMBINING_BY_CLASS_P(code) ((code) & 0x1000000)
+
+#define COMBINING_CODE_CLASS(code) ((code) & 0xFFFFFF)
+
+#define MAKE_PRECOMPUTED_COMBINDING_CODE() (0x2000000)
+
+#define COMBINING_PRECOMPUTED_P(code) ((code) & 0x2000000)
+
+extern MSymbol Mcombining;
+
+#endif /* _M_INTERNAL_FLT_H */
index 398e5f3..07a6d70 100644 (file)
@@ -124,20 +124,14 @@ enum glyph_category
 
 typedef struct
 {
-  int pos, to;
-  int c;
-  unsigned code;
+  MFLTGlyph g;
   MRealizedFace *rface;
-  short width, ascent, descent, lbearing, rbearing;
-  short xoff, yoff;
-  unsigned enabled : 1;
   unsigned left_padding : 1;
   unsigned right_padding : 1;
-  unsigned otf_encoded : 1;
+  unsigned enabled : 1;
   unsigned bidi_level : 6;
   unsigned category : 2;
   unsigned type : 3;
-  int combining_code;
 } MGlyph;
 
 struct MGlyphString
@@ -201,31 +195,6 @@ struct MGlyphString
     (gstring)->used -= newlen;                                           \
   } while (0)
 
-#define MAKE_COMBINING_CODE(base_y, base_x, add_y, add_x, off_y, off_x)        \
-  (((off_y) << 16)                                                     \
-   | ((off_x) << 8)                                                    \
-   | ((base_x) << 6)                                                   \
-   | ((base_y) << 4)                                                   \
-   | ((add_x) << 2)                                                    \
-   | (add_y))
-
-#define COMBINING_CODE_OFF_Y(code) (((code) >> 16) & 0xFF)
-#define COMBINING_CODE_OFF_X(code) (((code) >> 8) & 0xFF)
-#define COMBINING_CODE_BASE_X(code) (((code) >> 6) & 0x3)
-#define COMBINING_CODE_BASE_Y(code) (((code) >> 4) & 0x3)
-#define COMBINING_CODE_ADD_X(code) (((code) >> 2) & 0x3)
-#define COMBINING_CODE_ADD_Y(code) ((code) & 0x3)
-
-#define MAKE_COMBINING_CODE_BY_CLASS(class) (0x1000000 | class)
-
-#define COMBINING_BY_CLASS_P(code) ((code) & 0x1000000)
-
-#define COMBINING_CODE_CLASS(code) ((code) & 0xFFFFFF)
-
-#define MAKE_PRECOMPUTED_COMBINDING_CODE() (0x2000000)
-
-#define COMBINING_PRECOMPUTED_P(code) ((code) & 0x2000000)
-
 typedef struct MGlyphString MGlyphString;
 
 typedef struct
index 53ba6a5..dd59fa6 100644 (file)
@@ -117,6 +117,9 @@ extern int mdebug_hook ();
       MEMORY_FULL (err);                                       \
   } while (0)
 
+#define MTABLE_CALLOC_SAFE(p, size)    \
+  ((p) = (void *) calloc (sizeof (*(p)), (size)))
+
 
 /** The macro MTABLE_REALLOC () changes the size of memory block
     pointed to by P to a size suitable for an array of SIZE objects.
@@ -162,6 +165,8 @@ extern int mdebug_hook ();
 
 #define MSTRUCT_CALLOC(p, err) MTABLE_CALLOC ((p), 1, (err))
 
+#define MSTRUCT_CALLOC_SAFE(p) MTABLE_CALLOC_SAFE ((p), 1)
+
 #define USE_SAFE_ALLOCA \
   int sa_must_free = 0, sa_size = 0
 
@@ -410,21 +415,21 @@ struct _M17NObjectArray
 extern void mdebug__add_object_array (M17NObjectArray *array, char *name);
 
 #define M17N_OBJECT_ADD_ARRAY(array, name)     \
-  if (mdebug__flag & MDEBUG_FINI)              \
+  if (mdebug__flags[MDEBUG_FINI])              \
     mdebug__add_object_array (&array, name);   \
   else
 
 extern void mdebug__register_object (M17NObjectArray *array, void *object);
 
 #define M17N_OBJECT_REGISTER(array, object)    \
-  if (mdebug__flag & MDEBUG_FINI)              \
+  if (mdebug__flags[MDEBUG_FINI])              \
     mdebug__register_object (&array, object);  \
   else
 
 extern void mdebug__unregister_object (M17NObjectArray *array, void *object);
 
 #define M17N_OBJECT_UNREGISTER(array, object)  \
-  if (mdebug__flag & MDEBUG_FINI)              \
+  if (mdebug__flags[MDEBUG_FINI])              \
     mdebug__unregister_object (&array, object);        \
   else
 
@@ -535,30 +540,32 @@ struct MText
 
 \f
 
-enum MDebugMaskBit
+enum MDebugFlag
   {
-    MDEBUG_INIT =      0x01,
-    MDEBUG_FINI =      0x02,
-    MDEBUG_CHARSET =   0x04,
-    MDEBUG_CODING =    0x08,
-    MDEBUG_DATABASE =  0x10,
-    MDEBUG_FONT =      0x0100,
-    MDEBUG_FONT_FLT =  0x0200,
-    MDEBUG_FONT_OTF =  0x0400,
-    MDEBUG_INPUT =     0x0800,
-    MDEBUG_ALL =       0xFFFF,
-    MDEBUG_MAX
+    MDEBUG_INIT,
+    MDEBUG_FINI,
+    MDEBUG_CHARSET,
+    MDEBUG_CODING,
+    MDEBUG_DATABASE,
+    MDEBUG_FONT,
+    MDEBUG_FONT_FLT,
+    MDEBUG_FONT_OTF,
+    MDEBUG_INPUT,
+    MDEBUG_ALL,
+    MDEBUG_MAX = MDEBUG_ALL
   };
 
-extern int mdebug__flag;
+extern int mdebug__flags[MDEBUG_MAX];
 extern FILE *mdebug__output;
 extern void mdebug__push_time ();
 extern void mdebug__pop_time ();
 extern void mdebug__print_time ();
 
+#define MDEBUG_FLAG() mdebug__flags[mdebug_flag]
+
 #define MDEBUG_PRINT0(FPRINTF)         \
   do {                                 \
-    if (mdebug__flag & mdebug_mask)    \
+    if (MDEBUG_FLAG ())                        \
       {                                        \
        FPRINTF;                        \
        fflush (mdebug__output);        \
@@ -585,7 +592,7 @@ extern void mdebug__print_time ();
 
 #define MDEBUG_DUMP(prefix, postfix, call)             \
   do {                                                 \
-    if (mdebug__flag & mdebug_mask)                    \
+    if (MDEBUG_FLAG ())                                        \
       {                                                        \
        fprintf (mdebug__output, "%s", prefix);         \
        call;                                           \
@@ -594,23 +601,23 @@ extern void mdebug__print_time ();
       }                                                        \
   } while (0)
 
-#define MDEBUG_PUSH_TIME()             \
-  do {                                 \
-    if (mdebug__flag & mdebug_mask)    \
-      mdebug__push_time ();            \
+#define MDEBUG_PUSH_TIME()     \
+  do {                         \
+    if (MDEBUG_FLAG ())                \
+      mdebug__push_time ();    \
   } while (0)
 
 
-#define MDEBUG_POP_TIME()              \
-  do {                                 \
-    if (mdebug__flag & mdebug_mask)    \
-      mdebug__pop_time ();             \
+#define MDEBUG_POP_TIME()      \
+  do {                         \
+    if (MDEBUG_FLAG ())                \
+      mdebug__pop_time ();     \
   } while (0)
 
 
 #define MDEBUG_PRINT_TIME(tag, ARG_LIST)               \
   do {                                                 \
-    if (mdebug__flag & mdebug_mask)                    \
+    if (MDEBUG_FLAG ())                                        \
       {                                                        \
        fprintf (mdebug__output, " [%s] ", tag);        \
        mdebug__print_time ();                          \
@@ -627,10 +634,6 @@ extern void mdebug__print_time ();
    | (((c) & 0xFF00) << 8) | (((c) & 0xFF) << 24))
 
 
-extern void *(*mdatabase__finder) (MSymbol tag1, MSymbol tag2,
-                                  MSymbol tag3, MSymbol tag4);
-extern void *(*mdatabase__loader) (void *);
-
 /* Initialize/finalize function.  */
 
 extern int msymbol__init ();
index 80cbeb3..0af354d 100644 (file)
@@ -421,7 +421,8 @@ static int xfont_check_capability (MRealizedFont *rfont, MSymbol capability);
 static MFontDriver xfont_driver =
   { xfont_select, xfont_open,
     xfont_find_metric, xfont_has_char, xfont_encode_char,
-    xfont_render, xfont_list, xfont_list_family_names, xfont_check_capability };
+    xfont_render, xfont_list, xfont_list_family_names, xfont_check_capability
+  };
 
 static int
 font_compare (const void *p1, const void *p2)
@@ -598,7 +599,7 @@ xfont_open (MFrame *frame, MFont *font, MFont *spec, MRealizedFont *rfont)
   char *name;
   Display *display = FRAME_DISPLAY (frame);
   XFontStruct *xfont;
-  int mdebug_mask = MDEBUG_FONT;
+  int mdebug_flag = MDEBUG_FONT;
   MFont this;
 
   size = spec->size;
@@ -675,14 +676,15 @@ xfont_open (MFrame *frame, MFont *font, MFont *spec, MRealizedFont *rfont)
 
     rfont->baseline_offset
       = (XGetFontProperty (xfont, disp_info->MULE_BASELINE_OFFSET, &value)
-        ? (int) value : 0);
+        ? (int) (value << 6) : 0);
     rfont->average_width
       = (XGetFontProperty (xfont, disp_info->AVERAGE_WIDTH, &value)
-        ? (int) value / 10 : 0);
+        ? (int) (value << 6) / 10 : 0);
   }
-  rfont->ascent = xfont->ascent + rfont->baseline_offset;
-  rfont->descent = xfont->descent - rfont->baseline_offset;
-  rfont->max_advance = xfont->max_bounds.width;
+  rfont->ascent = (xfont->ascent << 6) + rfont->baseline_offset;
+  rfont->descent = (xfont->descent << 6) - rfont->baseline_offset;
+  rfont->max_advance = xfont->max_bounds.width << 6;
+  rfont->x_ppem = rfont->y_ppem = size / 10;
   rfont->fontp = xfont;
   rfont->next = MPLIST_VAL (frame->realized_font_list);
   MPLIST_VAL (frame->realized_font_list) = rfont;
@@ -700,69 +702,72 @@ xfont_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
   MGlyph *g = MGLYPH (from), *gend = MGLYPH (to);
 
   for (; g != gend; g++)
-    {
-      if (g->code == MCHAR_INVALID_CODE)
-       {
-         g->lbearing = xfont->max_bounds.lbearing;
-         g->rbearing = xfont->max_bounds.rbearing;
-         g->width = xfont->max_bounds.width;
-         g->ascent = xfont->ascent;
-         g->descent = xfont->descent;
-       }
-      else
-       {
-         int byte1 = g->code >> 8, byte2 = g->code & 0xFF;
-         XCharStruct *pcm = NULL;
-
-         if (xfont->per_char != NULL)
-           {
-             if (xfont->min_byte1 == 0 && xfont->max_byte1 == 0)
-               {
-                 if (byte1 == 0
-                     && byte2 >= xfont->min_char_or_byte2
-                     && byte2 <= xfont->max_char_or_byte2)
-                   pcm = xfont->per_char + byte2 - xfont->min_char_or_byte2;
-               }
-             else
-               {
-                 if (byte1 >= xfont->min_byte1
-                     && byte1 <= xfont->max_byte1
-                     && byte2 >= xfont->min_char_or_byte2
-                     && byte2 <= xfont->max_char_or_byte2)
-                   {
-                     pcm = (xfont->per_char
-                            + ((xfont->max_char_or_byte2
-                                - xfont->min_char_or_byte2 + 1)
-                               * (byte1 - xfont->min_byte1))
-                            + (byte2 - xfont->min_char_or_byte2));
-                   }
-               }
-           }
-
-         if (pcm)
-           {
-             g->lbearing = pcm->lbearing;
-             g->rbearing = pcm->rbearing;
-             g->width = pcm->width;
-             g->ascent = pcm->ascent;
-             g->descent = pcm->descent;
-           }
-         else
-           {
-             /* If the per_char pointer is null, all glyphs between
-                the first and last character indexes inclusive have
-                the same information, as given by both min_bounds and
-                max_bounds.  */
-             g->lbearing = 0;
-             g->rbearing = xfont->max_bounds.width;
-             g->width = xfont->max_bounds.width;
-             g->ascent = xfont->ascent;
-             g->descent = xfont->descent;
-           }
-       }
-      g->ascent += rfont->baseline_offset;
-      g->descent -= rfont->baseline_offset;
-    }
+    if (! g->g.measured)
+      {
+       if (g->g.code == MCHAR_INVALID_CODE)
+         {
+           g->g.lbearing = xfont->max_bounds.lbearing << 6;
+           g->g.rbearing = xfont->max_bounds.rbearing << 6;
+           g->g.xadv = xfont->max_bounds.width << 6;
+           g->g.ascent = xfont->ascent << 6;
+           g->g.descent = xfont->descent << 6;
+         }
+       else
+         {
+           int byte1 = g->g.code >> 8, byte2 = g->g.code & 0xFF;
+           XCharStruct *pcm = NULL;
+
+           if (xfont->per_char != NULL)
+             {
+               if (xfont->min_byte1 == 0 && xfont->max_byte1 == 0)
+                 {
+                   if (byte1 == 0
+                       && byte2 >= xfont->min_char_or_byte2
+                       && byte2 <= xfont->max_char_or_byte2)
+                     pcm = xfont->per_char + byte2 - xfont->min_char_or_byte2;
+                 }
+               else
+                 {
+                   if (byte1 >= xfont->min_byte1
+                       && byte1 <= xfont->max_byte1
+                       && byte2 >= xfont->min_char_or_byte2
+                       && byte2 <= xfont->max_char_or_byte2)
+                     {
+                       pcm = (xfont->per_char
+                              + ((xfont->max_char_or_byte2
+                                  - xfont->min_char_or_byte2 + 1)
+                                 * (byte1 - xfont->min_byte1))
+                              + (byte2 - xfont->min_char_or_byte2));
+                     }
+                 }
+             }
+
+           if (pcm)
+             {
+               g->g.lbearing = pcm->lbearing << 6;
+               g->g.rbearing = pcm->rbearing << 6;
+               g->g.xadv = pcm->width << 6;
+               g->g.ascent = pcm->ascent << 6;
+               g->g.descent = pcm->descent << 6;
+             }
+           else
+             {
+               /* If the per_char pointer is null, all glyphs between
+                  the first and last character indexes inclusive have
+                  the same information, as given by both min_bounds and
+                  max_bounds.  */
+               g->g.lbearing = 0;
+               g->g.rbearing = xfont->max_bounds.width << 6;
+               g->g.xadv = xfont->max_bounds.width << 6;
+               g->g.ascent = xfont->ascent << 6;
+               g->g.descent = xfont->descent << 6;
+             }
+         }
+       g->g.yadv = 0;
+       g->g.ascent += rfont->baseline_offset;
+       g->g.descent -= rfont->baseline_offset;
+       g->g.measured = 1;
+      }
 }
 
 
@@ -853,35 +858,35 @@ xfont_render (MDrawWindow win, int x, int y, MGlyphString *gstring,
   if (from == to)
     return;
 
-  baseline_offset = rface->rfont->baseline_offset;
+  baseline_offset = rface->rfont->baseline_offset >> 6;
   if (region)
     gc = set_region (rface->frame, gc, region);
   XSetFont (display, gc, ((XFontStruct *) rface->rfont->fontp)->fid);
   code = (XChar2b *) alloca (sizeof (XChar2b) * (to - from));
   for (i = 0, g = from; g < to; i++, g++)
     {
-      code[i].byte1 = g->code >> 8;
-      code[i].byte2 = g->code & 0xFF;
+      code[i].byte1 = g->g.code >> 8;
+      code[i].byte2 = g->g.code & 0xFF;
     }
 
   g = from;
   while (g < to)
     {
       if (g->type == GLYPH_PAD)
-       x += g++->width;
+       x += g++->g.xadv;
       else if (g->type == GLYPH_SPACE)
        for (; g < to && g->type == GLYPH_SPACE; g++)
-         x += g->width;
+         x += g->g.xadv;
       else if (! g->rface->rfont)
        {
-         if ((g->c >= 0x200B && g->c <= 0x200F)
-             || (g->c >= 0x202A && g->c <= 0x202E))
-           x += g++->width;
+         if ((g->g.c >= 0x200B && g->g.c <= 0x200F)
+             || (g->g.c >= 0x202A && g->g.c <= 0x202E))
+           x += g++->g.xadv;
          else
            {
              /* As a font is not found for this character, draw an
                 empty box.  */
-             int box_width = g->width;
+             int box_width = g->g.xadv;
              int box_height = gstring->ascent + gstring->descent;
 
              if (box_width > 4)
@@ -890,15 +895,15 @@ xfont_render (MDrawWindow win, int x, int y, MGlyphString *gstring,
                box_height -= 2;
              XDrawRectangle (display, (Window) win, gc,
                              x, y - gstring->ascent, box_width, box_height);
-             x += g++->width;
+             x += g++->g.xadv;
            }
        }
-      else if (g->xoff != 0 || g->yoff != 0 || g->right_padding)
+      else if (g->g.xoff != 0 || g->g.yoff != 0 || g->right_padding)
        {
          XDrawString16 (display, (Window) win, gc,
-                        x + g->xoff, y + g->yoff - baseline_offset,
+                        x + g->g.xoff, y + g->g.yoff - baseline_offset,
                         code + (g - from), 1);
-         x += g->width;
+         x += g->g.xadv;
          g++;
        }
       else
@@ -907,9 +912,9 @@ xfont_render (MDrawWindow win, int x, int y, MGlyphString *gstring,
          int code_idx = g - from;
 
          for (i = 0;
-              g < to && g->type == GLYPH_CHAR && g->xoff == 0 && g->yoff == 0;
+              g < to && g->type == GLYPH_CHAR && g->g.xoff == 0 && g->g.yoff == 0;
               i++, g++)
-             x += g->width;
+             x += g->g.xadv;
          XDrawString16 (display, (Window) win, gc,
                         orig_x, y - baseline_offset, code + code_idx, i);
        }
@@ -925,7 +930,7 @@ xfont_list (MFrame *frame, MPlist *plist, MFont *font, int maxnum)
   int size = font ? font->size : 0;
   MPlist *pl, *p;
   int num = 0;
-  int mdebug_mask = MDEBUG_FONT;
+  int mdebug_flag = MDEBUG_FONT;
 
   MDEBUG_PRINT2 (" [X-FONT] listing %s-%s...",
                 family ? msymbol_name (family) : "*",
@@ -1045,11 +1050,16 @@ static void xft_find_metric (MRealizedFont *, MGlyphString *, int, int);
 static void xft_render (MDrawWindow, int, int, MGlyphString *,
                        MGlyph *, MGlyph *, int, MDrawRegion);
 static int xft_check_capability (MRealizedFont *rfont, MSymbol capability);
+static int xft_check_otf (MFLTFont *font, MFLTOtfSpec *spec);
+static int xft_drive_otf (MFLTFont *font, MFLTOtfSpec *spec,
+                         MFLTGlyphString *in, int from, int to,
+                         MFLTGlyphString *out,
+                         MFLTGlyphAdjustment *adjustment);
 
 static MFontDriver xft_driver =
   { NULL, xft_open,
     xft_find_metric, xft_has_char, xft_encode_char, xft_render, NULL, NULL,
-    xft_check_capability
+    xft_check_capability, NULL, NULL, xft_check_otf, xft_drive_otf
   };
 
 static void
@@ -1157,6 +1167,8 @@ xft_open (MFrame *frame, MFont *font, MFont *spec, MRealizedFont *rfont)
   rfont->max_advance = max_advance;
   rfont->average_width = average_width;
   rfont->baseline_offset = baseline_offset;
+  rfont->x_ppem = ft_face->size->metrics.x_ppem;
+  rfont->y_ppem = ft_face->size->metrics.y_ppem;
   rfont->fontp = xft_font;
   rfont->next = MPLIST_VAL (frame->realized_font_list);
   MPLIST_VAL (frame->realized_font_list) = rfont;
@@ -1172,27 +1184,30 @@ xft_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
   MGlyph *g = MGLYPH (from), *gend = MGLYPH (to);
 
   for (; g != gend; g++)
-    {
-      if (g->code == MCHAR_INVALID_CODE)
-       {
-         g->lbearing = 0;
-         g->rbearing = xft_font->max_advance_width;
-         g->width = g->rbearing;
-         g->ascent = xft_font->ascent;
-         g->descent = xft_font->descent;
-       }
-      else
-       {
-         XGlyphInfo extents;
-
-         XftGlyphExtents (display, xft_font, &g->code, 1, &extents);
-         g->lbearing = - extents.x;
-         g->rbearing = extents.width - extents.x;
-         g->width = extents.xOff;
-         g->ascent = extents.y;
-         g->descent = extents.height - extents.y;
-       }
-    }
+    if (! g->g.measured)
+      {
+       if (g->g.code == MCHAR_INVALID_CODE)
+         {
+           g->g.lbearing = 0;
+           g->g.rbearing = xft_font->max_advance_width << 6;
+           g->g.xadv = g->g.rbearing << 6;
+           g->g.ascent = xft_font->ascent << 6;
+           g->g.descent = xft_font->descent << 6;
+         }
+       else
+         {
+           XGlyphInfo extents;
+
+           XftGlyphExtents (display, xft_font, &g->g.code, 1, &extents);
+           g->g.lbearing = (- extents.x) << 6;
+           g->g.rbearing = (extents.width - extents.x) << 6;
+           g->g.xadv = extents.xOff << 6;
+           g->g.ascent = extents.y << 6;
+           g->g.descent = (extents.height - extents.y) << 6;
+         }
+       g->g.yadv = 0;
+       g->g.measured = 0;
+      }
 }
 
 static int
@@ -1292,12 +1307,12 @@ xft_render (MDrawWindow win, int x, int y,
   XftDrawChange (xft_draw, (Drawable) win);
   XftDrawSetClip (xft_draw, (Region) region);
       
-  y -= rfont->baseline_offset;
+  y -= rfont->baseline_offset >> 6;
   glyphs = alloca (sizeof (FT_UInt) * (to - from));
-  for (last_x = x, nglyphs = 0, g = from; g < to; x += g++->width)
+  for (last_x = x, nglyphs = 0, g = from; g < to; x += g++->g.xadv)
     {
-      if (g->xoff == 0 && g->yoff == 0 && !g->left_padding && !g->right_padding)
-       glyphs[nglyphs++] = g->code;
+      if (g->g.xoff == 0 && g->g.yoff == 0 && !g->left_padding && !g->right_padding)
+       glyphs[nglyphs++] = g->g.code;
       else
        {
          if (nglyphs > 0)
@@ -1305,8 +1320,8 @@ xft_render (MDrawWindow win, int x, int y,
                           last_x, y, glyphs, nglyphs);
          nglyphs = 0;
          XftDrawGlyphs (xft_draw, xft_color, xft_font,
-                        x + g->xoff, y + g->yoff, (FT_UInt *) &g->code, 1);
-         last_x = x + g->width;
+                        x + g->g.xoff, y + g->g.yoff, (FT_UInt *) &g->g.code, 1);
+         last_x = x + g->g.xadv;
        }
     }
   if (nglyphs > 0)
@@ -1325,6 +1340,36 @@ xft_check_capability (MRealizedFont *rfont, MSymbol capability)
   return result;
 }
 
+static int
+xft_check_otf (MFLTFont *font, MFLTOtfSpec *spec)
+{
+  MRealizedFont *rfont = ((MFLTFontForRealized *) font)->rfont;
+  MRealizedFontXft *rfont_xft = rfont->info;
+  int result;
+      
+  rfont->info = rfont_xft->info;
+  result = mfont__ft_driver.check_otf (font, spec);
+  rfont->info = rfont_xft;
+  return result;
+}
+
+static int
+xft_drive_otf (MFLTFont *font, MFLTOtfSpec *spec,
+              MFLTGlyphString *in, int from, int to,
+              MFLTGlyphString *out,
+              MFLTGlyphAdjustment *adjustment)
+{
+  MRealizedFont *rfont = ((MFLTFontForRealized *) font)->rfont;
+  MRealizedFontXft *rfont_xft = rfont->info;
+  int result;
+      
+  rfont->info = rfont_xft->info;
+  result = mfont__ft_driver.drive_otf (font, spec, in, from, to, out,
+                                      adjustment);
+  rfont->info = rfont_xft;
+  return result;
+}
+
 #endif /* HAVE_XFT2 */
 
 \f
@@ -1490,9 +1535,9 @@ mwin__draw_empty_boxes (MDrawWindow win, int x, int y,
   for (; from < to; from++)
     {
       XDrawRectangle (display, (Window) win, gc,
-                     x, y - gstring->ascent + 1, from->width - 1,
+                     x, y - gstring->ascent + 1, from->g.xadv - 1,
                      gstring->ascent + gstring->descent - 2);
-      x += from->width;
+      x += from->g.xadv;
     }
 }
 
@@ -1553,9 +1598,9 @@ mwin__draw_box (MFrame *frame, MDrawWindow win, MGlyphString *gstring,
       int x0, x1;
 
       if (g->left_padding)
-       x0 = x + box->outer_hmargin, x1 = x + g->width - 1;
+       x0 = x + box->outer_hmargin, x1 = x + g->g.xadv - 1;
       else
-       x0 = x, x1 = x + g->width - box->outer_hmargin - 1;
+       x0 = x, x1 = x + g->g.xadv - box->outer_hmargin - 1;
 
       /* Draw the top side.  */
       for (i = 0; i < box->width; i++)
@@ -2257,7 +2302,7 @@ device_open (MFrame *frame, MPlist *param)
     mplist_add (frame->font_driver_list, Mfreetype, &mfont__ft_driver);
 #endif /* HAVE_FREETYPE */
   if (use_xfont || MPLIST_TAIL_P (frame->font_driver_list))
-    mplist_push (frame->font_driver_list, Mx, &xfont_driver);
+    mplist_add (frame->font_driver_list, Mx, &xfont_driver);
 
   frame->realized_font_list = device->realized_font_list;
   frame->realized_face_list = device->realized_face_list;
index 6257ad9..2094258 100644 (file)
@@ -416,11 +416,7 @@ int m17n__core_initialized;
 int m17n__shell_initialized;
 int m17n__gui_initialized;
 
-void *(*mdatabase__finder) (MSymbol tag1, MSymbol tag2,
-                          MSymbol tag3, MSymbol tag4);
-void *(*mdatabase__loader) (void *);
-
-int mdebug__flag;
+int mdebug__flags[MDEBUG_MAX];
 FILE *mdebug__output;
 
 void
@@ -451,19 +447,25 @@ mdebug__print_time ()
   time_stack[time_stack_index - 1] = tv;
 }
 
-#define SET_DEBUG_FLAG(env_name, mask)         \
-  do {                                         \
-    char *env_value = getenv (env_name);       \
-                                               \
-    if (env_value)                             \
-      {                                                \
-       if (env_value[0] == '1')                \
-         mdebug__flag |= (mask);               \
-       else if (env_value[0] == '0')           \
-         mdebug__flag &= ~(mask);              \
-      }                                                \
-  } while (0)
+static void
+SET_DEBUG_FLAG (char *env_name, enum MDebugFlag flag)
+{
+  char *env_value = getenv (env_name);
 
+  if (env_value)
+    {
+      int int_value = atoi (env_value);
+
+      if (flag == MDEBUG_ALL)
+       {
+         int i;
+         for (i = 0; i < MDEBUG_MAX; i++)
+           mdebug__flags[i] = int_value;
+       }
+      else
+       mdebug__flags[flag] = int_value;
+    }
+}
 
 void
 mdebug__add_object_array (M17NObjectArray *array, char *name)
@@ -515,7 +517,7 @@ mdebug__unregister_object (M17NObjectArray *array, void *object)
 void
 m17n_init_core (void)
 {
-  int mdebug_mask = MDEBUG_INIT;
+  int mdebug_flag = MDEBUG_INIT;
 
   merror_code = MERROR_NONE;
   if (m17n__core_initialized++)
@@ -523,7 +525,6 @@ m17n_init_core (void)
 
   m17n_memory_full_handler = default_error_handler;
 
-  mdebug__flag = 0;
   SET_DEBUG_FLAG ("MDEBUG_ALL", MDEBUG_ALL);
   SET_DEBUG_FLAG ("MDEBUG_INIT", MDEBUG_INIT);
   SET_DEBUG_FLAG ("MDEBUG_FINI", MDEBUG_FINI);
@@ -557,17 +558,18 @@ m17n_init_core (void)
   if  (mplist__init () < 0)
     goto err;
   MDEBUG_PRINT_TIME ("INIT", (stderr, " to initialize plist module."));
+  if (mchar__init () < 0)
+    goto err;
+  MDEBUG_PRINT_TIME ("INIT", (stderr, " to initialize character module."));
   if  (mchartable__init () < 0)
     goto err;
   MDEBUG_PRINT_TIME ("INIT", (stderr, " to initialize chartable module."));
-  if (mtext__init () < 0)
-    goto err;
-  if (mtext__prop_init () < 0)
+  if (mtext__init () < 0 || mtext__prop_init () < 0)
     goto err;
   MDEBUG_PRINT_TIME ("INIT", (stderr, " to initialize mtext module."));
-
-  mdatabase__finder = NULL;
-  mdatabase__loader = NULL;
+  if (mdatabase__init () < 0)
+    goto err;
+  MDEBUG_PRINT_TIME ("INIT", (stderr, " to initialize database module."));
 
 #if ENABLE_NLS
   bindtextdomain ("m17n-lib", GETTEXTDIR);
@@ -587,7 +589,7 @@ m17n_init_core (void)
 void
 m17n_fini_core (void)
 {
-  int mdebug_mask = MDEBUG_FINI;
+  int mdebug_flag = MDEBUG_FINI;
 
   if (m17n__core_initialized == 0
       || --m17n__core_initialized > 0)
@@ -610,7 +612,7 @@ m17n_fini_core (void)
   MDEBUG_POP_TIME ();
   MDEBUG_PRINT_TIME ("FINI", (stderr, " to finalize the core modules."));
   MDEBUG_POP_TIME ();
-  if (mdebug__flag & MDEBUG_FINI)
+  if (mdebug__flags[MDEBUG_FINI])
     report_object_array ();
   msymbol__free_table ();
   if (mdebug__output != stderr)
index 3ee6028..2d8a1de 100644 (file)
@@ -197,6 +197,7 @@ extern MSymbol Mt;
 extern MSymbol Mstring;
 extern MSymbol Msymbol;
 extern MSymbol Mtext;
+extern MSymbol Mcharset;
 
 /* Return a symbol of name NAME.  */
 extern MSymbol msymbol (const char *name);
@@ -338,6 +339,10 @@ typedef struct MCharTable MCharTable;
 
 extern MCharTable *mchartable (MSymbol key, void *default_value);
 
+extern int mchartable_min_char (MCharTable *table);
+
+extern int mchartable_max_char (MCharTable *table);
+
 extern void *mchartable_lookup (MCharTable *table, int c);
 
 extern int mchartable_set (MCharTable *table, int c, void *val);
@@ -778,6 +783,51 @@ extern MText *mtext_serialize (MText *mt, int from, int to,
 
 extern MText *mtext_deserialize (MText *mt);
 
+/*** @ingroup m17nCore */
+/***en @defgroup m17nDatabase Database */
+/***ja @defgroup m17nDatabase ¥Ç¡¼¥¿¥Ù¡¼¥¹ */
+/*=*/
+
+/* Directory of an application specific databases.  */
+extern char *mdatabase_dir;
+/*=*/
+/***
+    @ingroup m17nDatabase  */ 
+/***en
+    @brief Type of database.
+
+    The type #MDatabase is for a database object.  Its internal
+    structure is concealed from an application program.  */
+/***ja 
+    @brief ¥Ç¡¼¥¿¥Ù¡¼¥¹¤Î·¿Àë¸À.
+
+    #MDatabase ·¿¤Ï¥Ç¡¼¥¿¥Ù¡¼¥¹¥ª¥Ö¥¸¥§¥¯¥ÈÍѤι½Â¤ÂΤǤ¢¤ë¡£
+    ÆâÉô¹½Â¤¤Ï¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é¥à¤«¤é¤Ï¸«¤¨¤Ê¤¤¡£
+    */
+
+typedef struct MDatabase MDatabase;
+
+/*=*/
+
+/* Look for a data.  */
+extern MDatabase *mdatabase_find (MSymbol tag1, MSymbol tag2,
+                                 MSymbol tag3, MSymbol tag4);
+
+extern MPlist *mdatabase_list (MSymbol tag0, MSymbol tag1,
+                              MSymbol tag2, MSymbol tag3);
+
+/* Load a data.  */
+void *mdatabase_load (MDatabase *mdb);
+
+/* Get tags of a data.  */
+extern MSymbol *mdatabase_tag (MDatabase *mdb);
+
+/* Define a data.  */
+extern MDatabase *mdatabase_define (MSymbol tag1, MSymbol tag2,
+                                   MSymbol tag3, MSymbol tag4,
+                                   void *(*loader) (MSymbol *, void *),
+                                   void *extra_info);
+
 M17N_END_HEADER
 
 #endif /* _M17N_CORE_H_ */
diff --git a/src/m17n-flt.c b/src/m17n-flt.c
new file mode 100644 (file)
index 0000000..b72dfac
--- /dev/null
@@ -0,0 +1,2630 @@
+/* m17n-flt.c -- Font Layout Table sub-module.
+   Copyright (C) 2003, 2004, 2007
+     National Institute of Advanced Industrial Science and Technology (AIST)
+     Registration Number H15PRO112
+
+   This file is part of the m17n library.
+
+   The m17n library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License
+   as published by the Free Software Foundation; either version 2.1 of
+   the License, or (at your option) any later version.
+
+   The m17n library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   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., 51 Franklin Street, Fifth Floor,
+   02111-1307, USA.  */
+
+/***en
+    @addtogroup m17nFLT
+    @brief FLT support for a window system.
+
+    This section defines the m17n FLT API concerning character
+    layouting facility using FLT (Font Layout Table).  */
+
+/*=*/
+
+#if !defined (FOR_DOXYGEN) || defined (DOXYGEN_INTERNAL_MODULE)
+/*** @addtogroup m17nInternal
+     @{ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <regex.h>
+
+#include "m17n-core.h"
+#include "m17n-flt.h"
+#include "m17n-misc.h"
+#include "internal.h"
+#include "mtext.h"
+#include "symbol.h"
+#include "plist.h"
+#include "database.h"
+#include "internal-flt.h"
+
+/* Font Layouter */
+
+/* Font Layout Table (FLT)
+
+Predefined terms: SYMBOL, INTEGER, STRING
+
+FLT ::=        '(' STAGE + ')'
+
+STAGE ::= CATEGORY-TABLE ? FONT-LAYOUT-RULE
+
+;; Each STAGE consumes a source (code sequence) and produces another
+;; code sequence that is given to the next STAGE as a source.  The
+;; source given to the first stage is a sequence of character codes
+;; that are assigned category codes by CATEGORY-TABLE.  The output of
+;; the last stage is a glyph code sequence given to the renderer.
+
+CATEGORY-TABLE ::=
+       '(' 'category' CATEGORY-SPEC + ')'
+CATEGORY-SPEC ::=
+       '(' CODE [ CODE ] CATEGORY ')'
+CODE ::= INTEGER
+CATEGORY ::= INTEGER
+;; ASCII character codes of alphabet ('A' .. 'Z' 'a' .. 'z').
+;; Ex: CATEGORY-TABLE
+;; (category
+;;   (0x0900 0x097F    ?E)     ; All Devanagari characters
+;;   (0x093C           ?N))    ; DEVANAGARI-LETTER NUKTA
+;;     Assign the category 'E' to all Devanagari characters but 0x093C,
+;;     assign the category 'N' to 0x093C.
+
+FONT-LAYOUT-RULE ::=
+       '(' 'generator' RULE MACRO-DEF * ')'
+
+RULE ::= COMMAND | REGEXP-RULE | MATCH-RULE | MAP-RULE
+        | COND-STRUCT | MACRO-NAME
+
+COMMAND ::=
+       DIRECT-CODE | COMBINING | PREDEFIND-COMMAND | OTF-COMMAND
+
+DIRECT-CODE ::= INTEGER
+;; Always succeed.  Produce the code.  Consume no source.
+
+PREDEFIND-COMMAND ::=
+       '=' | '*' | '<' | '>' | '|'
+
+;; '=': Succeed when the current run contains at least one code.
+;; Consume the first code in the current run, and produce it as is.
+
+;; '*': If the the previous command succeeded, repeat it until it
+;; fails.  
+
+;; '<': Produce a special code that indicates the start of grapheme
+;; cluster.  Succeed always, consume nothing.
+
+;; '>': Produce a special code that indicates the end of grapheme
+;; cluster.  Succeed always, consume nothing.
+
+;; '|': Produce a special code whose category is ' '.  Succeed always,
+;; consume nothing.
+
+OTF-COMMAND ::=
+       'otf:''SCRIPT'[':'['LANGSYS'][':'[GSUB-FEATURES][':'GPOS-FEATURES]]]
+;; Run the Open Type Layout Table on the current run.  Succeed always,
+;; consume nothing.
+
+SCRIPT ::= OTF-TAG
+;;     OTF's ScriptTag name (four letters) listed at:
+;;     <http://www.microsoft.om/typograph/otspec/scripttags.htm>
+LANGSYS ::= OTF-TAG
+;;     OTF's Language System name (four letters) listed at:
+;;     <http://www.microsoft.om/typograph/otspec/languagetags.htm>
+
+GSUB-FEATURES ::= [FEATURE[,FEATURE]*] | ' '
+GPOS-FEATURES ::= [FEATURE[,FEATURE]*] | ' '
+FEATURE ::= OTF-TAG
+;;     OTF's Feature name (four letters) listed at:
+;;     <http://www.microsoft.om/typograph/otspec/???.htm>
+
+OTF-TAG ::= PRINTABLE-CHAR PRINTABLE-CHAR PRINTABLE-CHAR PRINTABLE-CHAR
+
+;; Ex. OTF-COMMAND
+;; 'otf:deva'
+;;     Run all features in the default langsys of 'deva' script.
+;; 'otf:deva::nukt:haln'
+;;     Run all GSUB features, run 'nukt' and 'haln' GPOS features.
+;; 'otf:deva:: :'
+;;     Run all GSUB features, run no GPOS features.
+
+REGEXP-RULE ::=
+       '(' REGEXP RULE * ')'
+
+;; Succeed if REGXP matches the head of source.  Run RULEs while
+;; limiting the source to the matching part.  Consume that part.
+
+REGEXP ::= STRING
+;; Must be composed only from ASCII characters.  'A' - 'Z', 'a' - 'z'
+;; correspond to CATEGORY.
+
+;; Ex: REGEXP-RULE
+;; ("VA?"
+;;   < | vowel * | >)
+
+MATCH-RULE ::=
+       '(' MATCH-IDX RULE * ')'
+
+;; Succeed if the previous REGEXP-RULE found a matching part for
+;; MATCH-IDX.  Run RULEs while limiting the source to the matching
+;; part.  If MATCH-IDX is zero, consume the whole part, else consume
+;; nothing.
+
+MATCH-IDX ::= INTEGER
+;; Must be 0..20.
+
+;; Ex. MATCH-RULE
+;; (2 consonant *)
+
+MAP-RULE ::=
+       '(' ( SOURCE-SEQ | SOURCE-RANGE ) RULE * ')'
+
+;; Succeed if the source matches SOURCE-SEQ or SOURCE-RANGE.  Run
+;; RULEs while limiting the source to the matching part.  Consume that
+;; part.
+
+SOURCE-SEQ ::=
+       '(' CODE + ')'
+SOURCE-RANGE ::=
+       '(' 'range' CODE CODE ')'
+;; Ex. MAP-RULE
+;; ((0x0915 0x094D)            0x43)
+;;     If the source code sequence is 0x0915 0x094D, produce 0x43.
+;; ((range 0x0F40 0x0F6A)      0x2221)
+;;     If the first source code CODE is in the range 0x0F40..0x0F6A, 
+;;     produce (0x2221 + (CODE - 0x0F40)).
+
+COND-STRUCT ::=
+       '(' 'cond' RULE + ')'
+
+;; Try each rule in sequence until one succeeds.  Succeed if one
+;; succeeds.  Consume nothing.
+
+;; Ex. COND-STRUCT
+;; (cond
+;;  ((0x0915 0x094D)           0x43)
+;;  ((range 0x0F40 0x0F6A)     0x2221)
+;;  = )
+
+COMBINING ::= 'V''H''O''V''H'
+V ::= ( 't' | 'c' | 'b' | 'B' )
+H ::= ( 'l' | 'c' | 'r' )
+O ::= ( '.' | XOFF | YOFF | XOFF YOFF )
+XOFF ::= '<'INTEGER | '>'INTEGER 
+YOFF ::= '+'INTEGER | '-'INTEGER
+;; INTEGER must be integer 0..127
+
+;; VH pair indicates 12 reference points of a glyph as below:
+;;
+;;   0----1----2 <---- ascent   0:tl (top-left)
+;;   |         |                1:tc (top-center)
+;;   |         |                2:tr (top-right)
+;;   |         |                3:Bl (base-left)
+;;   9   10   11 <---- center   4:Bc (base-center)
+;;   |         |                5:Br (base-right)
+;; --3----4----5-- <-- baseline         6:bl (bottom-left)
+;;   |         |                7:bc (bottom-center)
+;;   6----7----8 <---- descent  8:br (bottom-right)
+;;                              9:cl (center-left)
+;;   |    |    |               10:cc (center-center)
+;; left center right           11:cr (center-right)
+;;
+;; Ex. COMBINING
+;; 'tc.bc':
+;;     Align top-left point of the previous glyph and bottom-center
+;;     point of the current glyph.
+;; 'Bl<20-10Br'
+;;     Align 20% left and 10% below of base-left point of the previous
+;;     glyph and base-right point of the current glyph.
+
+MACRO-DEF ::=
+       '(' MACRO-NAME RULE + ')'
+MACRO-NAME ::= SYMBOL
+
+*/
+
+static int mdebug_flag = MDEBUG_FONT_FLT;
+
+MSymbol Mfont, Mlayouter, Mcombining;
+
+static MSymbol Mgenerator, Mend;
+
+static MPlist *flt_list;
+static int flt_min_coverage, flt_max_coverage;
+
+enum GlyphInfoMask
+{
+  CombiningCodeMask = 0xFFFFFFF,
+  LeftPaddingMask = 1 << 28,
+  RightPaddingMask = 1 << 29
+};
+
+#define SET_GLYPH_INFO(g, mask, ctx, info)                     \
+  ((g)->internal = (((g)->internal & ~(mask)) | (info)),       \
+   (ctx)->check_mask |= (mask))
+
+#define GET_COMBINING_CODE(g) ((g)->internal & CombiningCodeMask)
+#define SET_COMBINING_CODE(g, ctx, code)       \
+  SET_GLYPH_INFO (g, CombiningCodeMask, ctx, code)
+#define GET_LEFT_PADDING(g) ((g)->internal & LeftPaddingMask)
+#define SET_LEFT_PADDING(g, ctx, flag) \
+  SET_GLYPH_INFO (g, LeftPaddingMask, ctx, flag)
+#define GET_RIGHT_PADDING(g) ((g)->internal & RightPaddingMask)
+#define SET_RIGHT_PADDING(g, ctx, flag)        \
+  SET_GLYPH_INFO (g, RightPaddingMask, ctx, flag)
+#define GET_ENCODED(g) ((g)->encoded)
+#define SET_ENCODED(g, flag) ((g)->encoded = (flag))
+#define GET_MEASURED(g) ((g)->measured)
+#define SET_MEASURED(g, flag) ((g)->measured = (flag))
+
+#define GINIT(gstring, n)                                      \
+  do {                                                         \
+    if (! (gstring)->glyph_size)                               \
+      (gstring)->glyph_size = sizeof (MFLTGlyph);              \
+    (gstring)->glyphs = alloca ((gstring)->glyph_size * (n));  \
+    (gstring)->allocated = (n);                                        \
+    (gstring)->used = 0;                                       \
+  } while (0)
+
+#define GALLOCA (gstring)      \
+  ((MFLTGlyph *) alloca ((gstring)->glyph_size))
+
+#define GREF(gstring, idx)     \
+  ((MFLTGlyph *) ((char *) ((gstring)->glyphs) + (gstring)->glyph_size * (idx)))
+
+#define PREV(gstring, g)       \
+  ((MFLTGlyph *) ((char *) (g) - (gstring)->glyph_size))
+
+#define NEXT(gstring, g)       \
+  ((MFLTGlyph *) ((char *) (g) + (gstring)->glyph_size))
+
+#define GCPY(src, src_idx, n, tgt, tgt_idx)                            \
+  do {                                                                 \
+    memcpy ((char *) ((tgt)->glyphs) + (tgt)->glyph_size * (tgt_idx),  \
+           (char *) ((src)->glyphs) + (src)->glyph_size * (src_idx),   \
+           (src)->glyph_size * (n));                                   \
+  } while (0)
+
+#define GDUP(ctx, idx)                         \
+  do {                                         \
+    MFLTGlyphString *src = (ctx)->in;          \
+    MFLTGlyphString *tgt = (ctx)->out;         \
+    if (tgt->allocated <= tgt->used)           \
+      return -2;                               \
+    GCPY (src, (idx), 1, tgt, tgt->used);      \
+    tgt->used++;                               \
+  } while (0)
+
+static int
+GREPLACE (MFLTGlyphString *src, int src_from, int src_to,
+         MFLTGlyphString *tgt, int tgt_from, int tgt_to)
+{
+  int src_len = src_to - src_from;
+  int tgt_len = tgt_to - tgt_from;
+  int inc = src_len - tgt_len;
+
+  if (tgt->allocated < tgt->used + inc)
+    return -2;
+  if (inc != 0 && tgt_to < tgt->used)
+    memmove ((char *) tgt->glyphs + tgt->glyph_size * (tgt_from + src_len),
+            (char *) tgt->glyphs + tgt->glyph_size * tgt_to,
+            tgt->glyph_size * (tgt->used - tgt_to));
+  if (src_len)
+    memcpy ((char *) tgt->glyphs + tgt->glyph_size * tgt_from,
+           (char *) src->glyphs + src->glyph_size * src_from,
+           src->glyph_size * src_len);
+  tgt->used += inc;
+  return 0;
+}
+
+
+/* Command ID:
+                0 ...          : direct code
+                  -1           : invalid
+            -0x0F .. -2        : builtin commands
+       -0x100000F .. -0x10     : combining code
+                 ... -0x1000010: index to FontLayoutStage->cmds
+ */
+
+#define INVALID_CMD_ID -1
+#define CMD_ID_OFFSET_BUILTIN  -3
+#define CMD_ID_OFFSET_COMBINING        -0x10
+#define CMD_ID_OFFSET_INDEX    -0x1000010
+
+/* Builtin commands. */
+#define CMD_ID_COPY            -3 /* '=' */
+#define CMD_ID_REPEAT          -4 /* '*' */
+#define CMD_ID_CLUSTER_BEGIN   -5 /* '<' */
+#define CMD_ID_CLUSTER_END     -6 /* '>' */
+#define CMD_ID_SEPARATOR       -7 /* '|' */
+#define CMD_ID_LEFT_PADDING    -8 /* '[' */
+#define CMD_ID_RIGHT_PADDING   -9 /* ']' */
+
+#define CMD_ID_TO_COMBINING_CODE(id) (CMD_ID_OFFSET_COMBINING - (id))
+#define COMBINING_CODE_TO_CMD_ID(code) (CMD_ID_OFFSET_COMBINING - (code))
+
+#define CMD_ID_TO_INDEX(id) (CMD_ID_OFFSET_INDEX - (id))
+#define INDEX_TO_CMD_ID(idx) (CMD_ID_OFFSET_INDEX - (idx))
+
+static MSymbol Mcond, Mrange, Mfont_facility;
+
+#define GLYPH_CODE_P(code)     \
+  ((code) >= GLYPH_CODE_MIN && (code) <= GLYPH_CODE_MAX)
+
+#define GLYPH_CODE_INDEX(code) ((code) - GLYPH_CODE_MIN)
+
+#define UPDATE_CLUSTER_RANGE(ctx, g)           \
+  do {                                         \
+    if ((ctx)->cluster_begin_idx >= 0)         \
+      {                                                \
+       if (ctx->cluster_begin_pos > (g)->from) \
+         ctx->cluster_begin_pos = (g)->from;   \
+       if (ctx->cluster_end_pos < (g)->to)     \
+         ctx->cluster_end_pos = (g)->to;       \
+      }                                                \
+  } while (0)
+
+enum FontLayoutCmdRuleSrcType
+  {
+    SRC_REGEX,
+    SRC_INDEX,
+    SRC_SEQ,
+    SRC_RANGE,
+    SRC_HAS_GLYPH,
+    SRC_OTF_SPEC
+  };
+
+typedef struct
+{
+  enum FontLayoutCmdRuleSrcType src_type;
+  union {
+    struct {
+      char *pattern;
+      regex_t preg;
+    } re;
+    int match_idx;
+    struct {
+      int n_codes;
+      int *codes;
+    } seq;
+    struct {
+      int from, to;
+    } range;
+    int supported_glyph;
+    MFLTOtfSpec otf_spec;
+  } src;
+
+  int n_cmds;
+  int *cmd_ids;
+} FontLayoutCmdRule;
+
+typedef struct
+{
+  /* Beginning and end indices of series of SEQ commands.  */
+  int seq_beg, seq_end;
+  /* Range of the first character appears in the above series.  */
+  int seq_from, seq_to;
+
+  int n_cmds;
+  int *cmd_ids;
+} FontLayoutCmdCond;
+
+enum FontLayoutCmdType
+  {
+    FontLayoutCmdTypeRule,
+    FontLayoutCmdTypeCond,
+    FontLayoutCmdTypeOTF,
+    FontLayoutCmdTypeMAX
+  };
+
+typedef struct
+{
+  enum FontLayoutCmdType type;
+  union {
+    FontLayoutCmdRule rule;
+    FontLayoutCmdCond cond;
+    MFLTOtfSpec otf;
+  } body;
+} FontLayoutCmd;
+
+typedef struct 
+{
+  MCharTable *category;
+  int size, inc, used;
+  FontLayoutCmd *cmds;
+} FontLayoutStage;
+
+struct _MFLT
+{
+  MSymbol name;
+  MSymbol family;
+  MSymbol registry;
+  MFLTOtfSpec otf;
+  MDatabase *mdb;
+  MCharTable *coverage;
+  MPlist *stages;
+};
+
+/* Font layout table loader */
+
+static int parse_otf_command (MSymbol symbol, MFLTOtfSpec *spec);
+
+/* Load a category table from PLIST.  PLIST has this form:
+      PLIST ::= ( FROM-CODE TO-CODE ? CATEGORY-CHAR ) *
+*/
+
+static MCharTable *
+load_category_table (MPlist *plist)
+{
+  MCharTable *table;
+
+  table = mchartable (Minteger, (void *) 0);
+
+  MPLIST_DO (plist, plist)
+    {
+      MPlist *elt;
+      int from, to, category_code;
+
+      if (! MPLIST_PLIST (plist))
+       MERROR (MERROR_FONT, NULL);
+      elt = MPLIST_PLIST (plist);
+      if (! MPLIST_INTEGER_P (elt))
+       MERROR (MERROR_FONT, NULL);
+      from = MPLIST_INTEGER (elt);
+      elt = MPLIST_NEXT (elt);
+      if (! MPLIST_INTEGER_P (elt))
+       MERROR (MERROR_FONT, NULL);
+      to = MPLIST_INTEGER (elt);
+      elt = MPLIST_NEXT (elt);
+      if (MPLIST_TAIL_P (elt))
+       {
+         category_code = to;
+         to = from;
+       }
+      else
+       {
+         if (! MPLIST_INTEGER_P (elt))
+           MERROR (MERROR_FONT, NULL);
+         category_code = MPLIST_INTEGER (elt);
+       }
+      if (! isalnum (category_code))
+       MERROR (MERROR_FONT, NULL);
+
+      if (from == to)
+       mchartable_set (table, from, (void *) category_code);
+      else
+       mchartable_set_range (table, from, to, (void *) category_code);
+    }
+
+  return table;
+}
+
+static unsigned int
+gen_otf_tag (char *p)
+{
+  unsigned int tag = 0;
+  int i;
+
+  for (i = 0; i < 4 && *p; i++, p++)
+    tag = (tag << 8) | *p;
+  for (; i < 4; i++)
+    tag = (tag << 8) | 0x20;
+  return tag;
+}
+
+static char *
+otf_count_features (char *p, char *end, char stopper, int *count)
+{
+  int negative = 0;
+
+  *count = 0;
+  if (*p != stopper && *p != '\0')
+    while (1)
+      {
+       (*count)++;
+       if (*p == '*')
+         {
+           p++;
+           if (*p == stopper || *p == '\0')
+             break;
+           return NULL;
+         }
+       if (*p == '~')
+         {
+           if (negative++ == 0)
+             (*count)++;
+           p += 5;
+         }
+       else 
+         p += 4;
+       if (p > end)
+         return NULL;
+       if (*p == stopper || *p == '\0')
+         break;
+       if (*p != ',')
+         return NULL;
+       p++;
+       if (! *p)
+         return NULL;
+      }
+  return p;
+}
+
+static void
+otf_store_features (char *p, char *end, unsigned *buf)
+{
+  int negative = 0;
+  int i;
+
+  for (i = 0; p < end;)
+    {
+      if (*p == '*')
+       buf[i++] = 0xFFFFFFFF, p += 2, negative = 1;
+      else if (*p == '~')
+       {
+         if (negative++ == 0)
+           buf[i++] = 0xFFFFFFFF;
+         buf[i++] = gen_otf_tag (p + 1), p += 6;
+       }
+      else
+       buf[i++] = gen_otf_tag (p), p += 5;
+    }
+  buf[i] = 0;
+}
+
+static int
+parse_otf_command (MSymbol symbol, MFLTOtfSpec *spec)
+{
+  char *str = MSYMBOL_NAME (symbol);
+  char *end = str + MSYMBOL_NAMELEN (symbol);
+  unsigned int script, langsys;
+  char *gsub, *gpos;
+  int gsub_count = 0, gpos_count = 0;
+  char *p;
+
+  memset (spec, 0, sizeof (MFLTOtfSpec));
+
+  spec->sym = symbol;
+  str += 5;                    /* skip the heading ":otf=" */
+  script = gen_otf_tag (str);
+  str += 4;
+  if (*str == '/')
+    {
+      langsys = gen_otf_tag (str);
+      str += 4;
+    }
+  else
+    langsys = 0;
+  gsub = str;
+  if (*str != '=')
+    /* Apply all GSUB features.  */
+      gsub_count = 1;
+  else
+    {
+      p = str + 1;
+      str = otf_count_features (p, end, '+', &gsub_count);
+      if (! str)
+       MERROR (MERROR_FLT, -1);
+    }
+  gpos = str;
+  if (*str != '+')
+    /* Apply all GPOS features.  */
+    gpos_count = 1;
+  else
+    {
+      p = str + 1;
+      str = otf_count_features (p, end, '\0', &gpos_count);
+      if (! str)
+       MERROR (MERROR_FLT, -1);
+    }
+
+  spec->script = script;
+  spec->langsys = langsys;
+  if (gsub_count > 0)
+    {
+      spec->features[0] = malloc (sizeof (int) * (gsub_count + 1));
+      if (! spec->features[0])
+       return -2;
+      if (*gsub == '=')
+       otf_store_features (gsub + 1, gpos, spec->features[0]);
+      else
+       spec->features[0][0] = 0xFFFFFFFF, spec->features[0][1] = 0;
+    }
+  if (gpos_count > 0)
+    {
+      spec->features[1] = malloc (sizeof (int) * (gpos_count + 1));
+      if (! spec->features[1])
+       {
+         if (spec->features[0])
+           free (spec->features[0]);
+         return -2;
+       }
+      if (*gpos == '+')
+       otf_store_features (gpos + 1, str, spec->features[1]);
+      else
+       spec->features[1][0] = 0xFFFFFFFF, spec->features[1][1] = 0;
+    }
+  return 0;
+}
+
+
+/* Parse OTF command name NAME and store the result in CMD.
+   NAME has this form:
+       :SCRIPT[/[LANGSYS][=[GSUB-FEATURES][+GPOS-FEATURES]]]
+   where GSUB-FEATURES and GPOS-FEATURES have this form:
+       [FEATURE[,FEATURE]*] | ' '  */
+
+static int
+load_otf_command (FontLayoutCmd *cmd, MSymbol sym)
+{
+  char *name = MSYMBOL_NAME (sym);
+  int result;
+
+  if (name[0] != ':')
+    {
+      /* This is old format of "otf:...".  Change it to ":otf=...".  */
+      char *str = alloca (MSYMBOL_NAMELEN (sym) + 2);
+
+      sprintf (str, ":otf=");
+      strcat (str, name + 4);
+      sym = msymbol (str);
+    }
+
+  result = parse_otf_command (sym, &cmd->body.otf);
+  if (result == -2)
+    return result;
+  cmd->type = FontLayoutCmdTypeOTF;
+  return 0;
+}
+
+
+/* Read a decimal number from STR preceded by one of "+-><".  '+' and
+   '>' means a plus sign, '-' and '<' means a minus sign.  If the
+   number is greater than 127, limit it to 127.  */
+
+static int
+read_decimal_number (char **str)
+{
+  char *p = *str;
+  int sign = (*p == '-' || *p == '<') ? -1 : 1;
+  int n = 0;
+
+  p++;
+  while (*p >= '0' && *p <= '9')
+    n = n * 10 + *p++ - '0';
+  *str = p;
+  if (n == 0)
+    n = 5;
+  return (n < 127 ? n * sign : 127 * sign);
+}
+
+
+/* Read a horizontal and vertical combining positions from STR, and
+   store them in the place pointed by X and Y.  The horizontal
+   position left, center, and right are represented by 0, 1, and 2
+   respectively.  The vertical position top, center, bottom, and base
+   are represented by 0, 1, 2, and 3 respectively.  If successfully
+   read, return 0, else return -1.  */
+
+static int
+read_combining_position (char *str, int *x, int *y)
+{
+  int c = *str++;
+  int i;
+
+  /* Vertical position comes first.  */
+  for (i = 0; i < 4; i++)
+    if (c == "tcbB"[i])
+      {
+       *y = i;
+       break;
+      }
+  if (i == 4)
+    return -1;
+  c = *str;
+  /* Then comse horizontal position.  */
+  for (i = 0; i < 3; i++)
+    if (c == "lcr"[i])
+      {
+       *x = i;
+       return 0;
+      }
+  return -1;
+}
+
+
+/* Return a combining code corresponding to SYM.  */
+
+static int
+get_combining_command (MSymbol sym)
+{
+  char *str = msymbol_name (sym);
+  int base_x, base_y, add_x, add_y, off_x, off_y;
+  int c;
+
+  if (read_combining_position (str, &base_x, &base_y) < 0)
+    return 0;
+  str += 2;
+  c = *str;
+  if (c == '.')
+    {
+      off_x = off_y = 128;
+      str++;
+    }
+  else
+    {
+      if (c == '+' || c == '-')
+       {
+         off_y = read_decimal_number (&str) + 128;
+         c = *str;
+       }
+      else
+       off_y = 128;
+      if (c == '<' || c == '>')
+       off_x = read_decimal_number (&str) + 128;
+      else
+       off_x = 128;
+    }
+  if (read_combining_position (str, &add_x, &add_y) < 0)
+    return 0;
+
+  c = MAKE_COMBINING_CODE (base_y, base_x, add_y, add_x, off_y, off_x);
+  return (COMBINING_CODE_TO_CMD_ID (c));
+}
+
+
+/* Load a command from PLIST into STAGE, and return that
+   identification number.  If ID is not INVALID_CMD_ID, that means we
+   are loading a top level command or a macro.  In that case, use ID
+   as the identification number of the command.  Otherwise, generate a
+   new id number for the command.  MACROS is a list of raw macros.  */
+
+static int
+load_command (FontLayoutStage *stage, MPlist *plist,
+             MPlist *macros, int id)
+{
+  int i;
+  int result;
+
+  if (MPLIST_INTEGER_P (plist))
+    {
+      int code = MPLIST_INTEGER (plist);
+
+      if (code < 0)
+       MERROR (MERROR_DRAW, INVALID_CMD_ID);
+      return code;
+    }
+  else if (MPLIST_PLIST_P (plist))
+    {
+      /* PLIST ::= ( cond ... ) | ( STRING ... ) | ( INTEGER ... )
+                  | ( ( INTEGER INTEGER ) ... )
+                  | ( ( range INTEGER INTEGER ) ... )
+                  | ( ( font-facilty [ INTEGER ] ) ... )
+                  | ( ( font-facilty OTF-SPEC ) ... )  */
+      MPlist *elt = MPLIST_PLIST (plist);
+      int len = MPLIST_LENGTH (elt) - 1;
+      FontLayoutCmd *cmd;
+
+      if (id == INVALID_CMD_ID)
+       {
+         FontLayoutCmd dummy;
+         id = INDEX_TO_CMD_ID (stage->used);
+         MLIST_APPEND1 (stage, cmds, dummy, MERROR_DRAW);
+       }
+      cmd = stage->cmds + CMD_ID_TO_INDEX (id);
+
+      if (MPLIST_SYMBOL_P (elt))
+       {
+         FontLayoutCmdCond *cond;
+
+         if (MPLIST_SYMBOL (elt) != Mcond)
+           MERROR (MERROR_DRAW, INVALID_CMD_ID);
+         elt = MPLIST_NEXT (elt);
+         cmd->type = FontLayoutCmdTypeCond;
+         cond = &cmd->body.cond;
+         cond->seq_beg = cond->seq_end = -1;
+         cond->seq_from = cond->seq_to = 0;
+         cond->n_cmds = len;
+         MTABLE_CALLOC (cond->cmd_ids, len, MERROR_DRAW);
+         for (i = 0; i < len; i++, elt = MPLIST_NEXT (elt))
+           {
+             int this_id = load_command (stage, elt, macros, INVALID_CMD_ID);
+
+             if (this_id == INVALID_CMD_ID || this_id == -2)
+               MERROR (MERROR_DRAW, this_id);
+             /* The above load_command may relocate stage->cmds.  */
+             cmd = stage->cmds + CMD_ID_TO_INDEX (id);
+             cond = &cmd->body.cond;
+             cond->cmd_ids[i] = this_id;
+             if (this_id <= CMD_ID_OFFSET_INDEX)
+               {
+                 FontLayoutCmd *this_cmd
+                   = stage->cmds + CMD_ID_TO_INDEX (this_id);
+
+                 if (this_cmd->type == FontLayoutCmdTypeRule
+                     && this_cmd->body.rule.src_type == SRC_SEQ)
+                   {
+                     int first_char = this_cmd->body.rule.src.seq.codes[0];
+
+                     if (cond->seq_beg < 0)
+                       {
+                         /* The first SEQ command.  */
+                         cond->seq_beg = i;
+                         cond->seq_from = cond->seq_to = first_char;
+                       }
+                     else if (cond->seq_end < 0)
+                       {
+                         /* The following SEQ command.  */
+                         if (cond->seq_from > first_char)
+                           cond->seq_from = first_char;
+                         else if (cond->seq_to < first_char)
+                           cond->seq_to = first_char;
+                       }
+                   }
+                 else
+                   {
+                     if (cond->seq_beg >= 0 && cond->seq_end < 0)
+                       /* The previous one is the last SEQ command.  */
+                       cond->seq_end = i;
+                   }
+               }
+             else
+               {
+                 if (cond->seq_beg >= 0 && cond->seq_end < 0)
+                   /* The previous one is the last SEQ command.  */
+                   cond->seq_end = i;
+               }
+           }
+         if (cond->seq_beg >= 0 && cond->seq_end < 0)
+           /* The previous one is the last SEQ command.  */
+           cond->seq_end = i;
+       }
+      else
+       {
+         cmd->type = FontLayoutCmdTypeRule;
+         if (MPLIST_MTEXT_P (elt))
+           {
+             MText *mt = MPLIST_MTEXT (elt);
+             char *str = (char *) MTEXT_DATA (mt);
+
+             if (str[0] != '^')
+               {
+                 mtext_ins_char (mt, 0, '^', 1);
+                 str = (char *) MTEXT_DATA (mt);
+               }
+             if (regcomp (&cmd->body.rule.src.re.preg, str, REG_EXTENDED))
+               MERROR (MERROR_FONT, INVALID_CMD_ID);
+             cmd->body.rule.src_type = SRC_REGEX;
+             cmd->body.rule.src.re.pattern = strdup (str);
+           }
+         else if (MPLIST_INTEGER_P (elt))
+           {
+             cmd->body.rule.src_type = SRC_INDEX;
+             cmd->body.rule.src.match_idx = MPLIST_INTEGER (elt);
+           }
+         else if (MPLIST_PLIST_P (elt))
+           {
+             MPlist *pl = MPLIST_PLIST (elt);
+             int size = MPLIST_LENGTH (pl);
+
+             if (MPLIST_INTEGER_P (pl))
+               {
+                 int i;
+
+                 cmd->body.rule.src_type = SRC_SEQ;
+                 cmd->body.rule.src.seq.n_codes = size;
+                 MTABLE_CALLOC (cmd->body.rule.src.seq.codes, size,
+                                MERROR_FONT);
+                 for (i = 0; i < size; i++, pl = MPLIST_NEXT (pl))
+                   {
+                     if (! MPLIST_INTEGER_P (pl))
+                       MERROR (MERROR_DRAW, INVALID_CMD_ID);
+                     cmd->body.rule.src.seq.codes[i]
+                       = (unsigned) MPLIST_INTEGER (pl);
+                   }
+               }
+             else if (MPLIST_SYMBOL_P (pl) && size == 3)
+               {
+                 if (MPLIST_SYMBOL (pl) != Mrange)
+                   MERROR (MERROR_FLT, INVALID_CMD_ID);
+                 cmd->body.rule.src_type = SRC_RANGE;
+                 pl = MPLIST_NEXT (pl);
+                 if (! MPLIST_INTEGER_P (pl))
+                   MERROR (MERROR_DRAW, INVALID_CMD_ID);
+                 cmd->body.rule.src.range.from
+                   = (unsigned) MPLIST_INTEGER (pl);
+                 pl = MPLIST_NEXT (pl);
+                 if (! MPLIST_INTEGER_P (pl))
+                   MERROR (MERROR_DRAW, INVALID_CMD_ID);
+                 cmd->body.rule.src.range.to
+                   = (unsigned) MPLIST_INTEGER (pl);
+               }
+             else if (MPLIST_SYMBOL_P (pl) && size <= 2)
+               {
+                 if (MPLIST_SYMBOL (pl) != Mfont_facility)
+                   MERROR (MERROR_FLT, INVALID_CMD_ID);
+                 pl = MPLIST_NEXT (pl);
+                 if (MPLIST_SYMBOL_P (pl))
+                   {
+                     MSymbol sym = MPLIST_SYMBOL (pl);
+                     char *otf_spec = MSYMBOL_NAME (sym);
+
+                     if (otf_spec[0] == ':' && otf_spec[1] == 'o'
+                         && otf_spec[2] == 't' && otf_spec[3] == 'f')
+                       parse_otf_command (sym, &cmd->body.rule.src.otf_spec);
+                     else
+                       MERROR (MERROR_FLT, INVALID_CMD_ID);
+                     cmd->body.rule.src_type = SRC_OTF_SPEC;
+                   }
+                 else
+                   {
+                     cmd->body.rule.src_type = SRC_HAS_GLYPH;
+                     if (MPLIST_INTEGER_P (pl))
+                       cmd->body.rule.src.supported_glyph
+                         = MPLIST_INTEGER (pl);
+                     else
+                       cmd->body.rule.src.supported_glyph = -1;
+                   }
+               }
+             else
+               MERROR (MERROR_DRAW, INVALID_CMD_ID);
+           }
+         else
+           MERROR (MERROR_DRAW, INVALID_CMD_ID);
+
+         elt = MPLIST_NEXT (elt);
+         cmd->body.rule.n_cmds = len;
+         MTABLE_CALLOC (cmd->body.rule.cmd_ids, len, MERROR_DRAW);
+         for (i = 0; i < len; i++, elt = MPLIST_NEXT (elt))
+           {
+             int this_id = load_command (stage, elt, macros, INVALID_CMD_ID);
+
+             if (this_id == INVALID_CMD_ID || this_id == -2)
+               MERROR (MERROR_DRAW, this_id);
+             /* The above load_command may relocate stage->cmds.  */
+             cmd = stage->cmds + CMD_ID_TO_INDEX (id);
+             cmd->body.rule.cmd_ids[i] = this_id;
+           }
+       }
+    }
+  else if (MPLIST_SYMBOL_P (plist))
+    {
+      MPlist *elt;
+      MSymbol sym = MPLIST_SYMBOL (plist);
+      char *name = msymbol_name (sym);
+      int len = strlen (name);
+      FontLayoutCmd cmd;
+
+      if (len > 4
+         && ((name[0] == 'o' && name[1] == 't'
+              && name[2] == 'f' && name[3] == ':')
+             || (name[0] == ':' && name[1] == 'o' && name[2] == 't'
+                 && name[3] == 'f' && name[4] == '=')))
+       {
+         result = load_otf_command (&cmd, sym);
+         if (result < 0)
+           return result;
+         if (id == INVALID_CMD_ID)
+           {
+             id = INDEX_TO_CMD_ID (stage->used);
+             MLIST_APPEND1 (stage, cmds, cmd, MERROR_DRAW);
+           }
+         else
+           stage->cmds[CMD_ID_TO_INDEX (id)] = cmd;
+         return id;
+       }
+
+      if (len == 1)
+       {
+         if (*name == '=')
+           return CMD_ID_COPY;
+         else if (*name == '*')
+           return CMD_ID_REPEAT;
+         else if (*name == '<')
+           return CMD_ID_CLUSTER_BEGIN;
+         else if (*name == '>')
+           return CMD_ID_CLUSTER_END;
+         else if (*name == '|')
+           return CMD_ID_SEPARATOR;
+         else if (*name == '[')
+           return CMD_ID_LEFT_PADDING;
+         else if (*name == ']')
+           return CMD_ID_RIGHT_PADDING;
+         else
+           id = 0;
+       }
+      else
+       {
+         id = get_combining_command (sym);
+         if (id)
+           return id;
+       }
+
+      i = 1;
+      MPLIST_DO (elt, macros)
+       {
+         if (sym == MPLIST_SYMBOL (MPLIST_PLIST (elt)))
+           {
+             id = INDEX_TO_CMD_ID (i);
+             if (stage->cmds[i].type == FontLayoutCmdTypeMAX)
+               id = load_command (stage, MPLIST_NEXT (MPLIST_PLIST (elt)),
+                                  macros, id);
+             return id;
+           }
+         i++;
+       }
+      MERROR (MERROR_DRAW, INVALID_CMD_ID);
+    }
+  else
+    MERROR (MERROR_DRAW, INVALID_CMD_ID);
+
+  return id;
+}
+
+static void
+free_flt_command (FontLayoutCmd *cmd)
+{
+  if (cmd->type == FontLayoutCmdTypeRule)
+    {
+      FontLayoutCmdRule *rule = &cmd->body.rule;
+
+      if (rule->src_type == SRC_REGEX)
+       {
+         free (rule->src.re.pattern);
+         regfree (&rule->src.re.preg);
+       }
+      else if (rule->src_type == SRC_SEQ)
+       free (rule->src.seq.codes);
+      free (rule->cmd_ids);
+    }
+  else if (cmd->type == FontLayoutCmdTypeCond)
+    free (cmd->body.cond.cmd_ids);
+  else if (cmd->type == FontLayoutCmdTypeOTF)
+    {
+      if (cmd->body.otf.features[0])
+       free (cmd->body.otf.features[0]);
+      if (cmd->body.otf.features[1])
+       free (cmd->body.otf.features[1]);
+    }
+}
+
+/* Load a generator from PLIST into a newly allocated FontLayoutStage,
+   and return it.  PLIST has this form:
+      PLIST ::= ( COMMAND ( CMD-NAME COMMAND ) * )
+*/
+
+static FontLayoutStage *
+load_generator (MPlist *plist)
+{
+  FontLayoutStage *stage;
+  MPlist *elt, *pl;
+  FontLayoutCmd dummy;
+  int result;
+
+  MSTRUCT_CALLOC (stage, MERROR_DRAW);
+  MLIST_INIT1 (stage, cmds, 32);
+  dummy.type = FontLayoutCmdTypeMAX;
+  MLIST_APPEND1 (stage, cmds, dummy, MERROR_FONT);
+  MPLIST_DO (elt, MPLIST_NEXT (plist))
+    {
+      if (! MPLIST_PLIST_P (elt))
+       MERROR (MERROR_FONT, NULL);
+      pl = MPLIST_PLIST (elt);
+      if (! MPLIST_SYMBOL_P (pl))
+       MERROR (MERROR_FONT, NULL);
+      MLIST_APPEND1 (stage, cmds, dummy, MERROR_FONT);
+    }
+
+  /* Load the first command from PLIST into STAGE->cmds[0].  Macros
+     called in the first command are also loaded from MPLIST_NEXT
+     (PLIST) into STAGE->cmds[n].  */
+  result = load_command (stage, plist, MPLIST_NEXT (plist),
+                        INDEX_TO_CMD_ID (0));
+  if (result == INVALID_CMD_ID || result == -2)
+    {
+      MLIST_FREE1 (stage, cmds);
+      free (stage);
+      return NULL;
+    }
+
+  return stage;
+}
+
+
+/* Load stages of the font layout table FLT.  */
+
+static int
+load_flt (MFLT *flt, MPlist *key_list)
+{
+  MPlist *top, *plist, *pl, *p;
+  MCharTable *category = NULL;
+  MSymbol sym;
+
+  if (key_list)
+    top = (MPlist *) mdatabase__load_for_keys (flt->mdb, key_list);
+  else
+    top = (MPlist *) mdatabase_load (flt->mdb);
+  if (! top)
+    return -1;
+  if (! MPLIST_PLIST_P (top))
+    {
+      M17N_OBJECT_UNREF (top);
+      MERROR (MERROR_FLT, -1);
+    }
+
+  if (key_list)
+    {
+      plist = mdatabase__props (flt->mdb);
+      if (! plist)
+       MERROR (MERROR_FLT, -1);
+      MPLIST_DO (plist, plist)
+       if (MPLIST_PLIST_P (plist))
+         {
+           pl = MPLIST_PLIST (plist);
+           if (! MPLIST_SYMBOL_P (pl)
+               || MPLIST_SYMBOL (pl) != Mfont)
+             continue;
+           pl = MPLIST_NEXT (pl);
+           if (! MPLIST_PLIST_P (pl))
+             continue;
+           p = MPLIST_PLIST (pl);
+           if (! MPLIST_SYMBOL_P (p))
+             continue;
+           p = MPLIST_NEXT (p);
+           if (! MPLIST_SYMBOL_P (p))
+             continue;
+           flt->family = MPLIST_SYMBOL (p);
+           MPLIST_DO (p, MPLIST_NEXT (p))
+             if (MPLIST_SYMBOL_P (p))
+               {
+                 sym = MPLIST_SYMBOL (p);
+                 if (MSYMBOL_NAME (sym)[0] != ':')
+                   flt->registry = sym, sym = Mnil;
+                 else
+                   break;
+               }
+           if (sym)
+             {
+               char *otf_spec = MSYMBOL_NAME (sym);
+
+               if (otf_spec[0] == ':' && otf_spec[1] == 'o'
+                   && otf_spec[2] == 't' && otf_spec[3] == 'f')
+                 parse_otf_command (sym, &flt->otf);
+             }
+           break;
+         }
+    }
+  MPLIST_DO (plist, top)
+    {
+      if (MPLIST_SYMBOL_P (plist)
+         && MPLIST_SYMBOL (plist) == Mend)
+       {
+         mplist_set (plist, Mnil, NULL);
+         break;
+       }
+      if (! MPLIST_PLIST (plist))
+       continue;
+      pl = MPLIST_PLIST (plist);
+      if (! MPLIST_SYMBOL_P (pl))
+       continue;
+      sym = MPLIST_SYMBOL (pl);
+      pl = MPLIST_NEXT (pl);
+      if (! pl)
+       continue;
+      if (sym == Mcategory)
+       {
+         if (category)
+           M17N_OBJECT_UNREF (category);
+         else if (flt->coverage)
+           {
+             category = flt->coverage;
+             continue;
+           }
+         category = load_category_table (pl);
+         if (! flt->coverage)
+           {
+             flt->coverage = category;
+             M17N_OBJECT_REF (category);
+           }
+       }
+      else if (sym == Mgenerator)
+       {
+         FontLayoutStage *stage;
+
+         if (! category)
+           break;
+         stage = load_generator (pl);
+         if (! stage)
+           break;
+         stage->category = category;
+         M17N_OBJECT_REF (category);
+         if (! flt->stages)
+           flt->stages = mplist ();
+         mplist_add (flt->stages, Mt, stage);
+       }
+    }
+  if (category)
+    M17N_OBJECT_UNREF (category);
+  M17N_OBJECT_UNREF (top);
+  if (! MPLIST_TAIL_P (plist))
+    {
+      M17N_OBJECT_UNREF (flt->stages);
+      MERROR (MERROR_FLT, -1);
+    }
+  return 0;
+}
+
+
+static void
+free_flt_stage (FontLayoutStage *stage)
+{
+  int i;
+
+  M17N_OBJECT_UNREF (stage->category);
+  for (i = 0; i < stage->used; i++)
+    free_flt_command (stage->cmds + i);
+  MLIST_FREE1 (stage, cmds);
+  free (stage);
+}
+
+static void
+free_flt_list ()
+{
+  if (flt_list)
+    {
+      MPlist *plist, *pl;
+
+      MPLIST_DO (plist, flt_list)
+       {
+         MFLT *flt = MPLIST_VAL (plist);
+
+         if (flt->coverage)
+           M17N_OBJECT_UNREF (flt->coverage);
+         if (flt->stages)
+           {
+             MPLIST_DO (pl, MPLIST_NEXT (flt->stages))
+               free_flt_stage (MPLIST_VAL (pl));
+             M17N_OBJECT_UNREF (flt->stages);
+           }
+       }
+      M17N_OBJECT_UNREF (flt_list);
+    }
+}
+
+static int
+list_flt ()
+{
+  MPlist *plist, *key_list = NULL;
+  MPlist *pl;
+  int result = 0;
+
+  if (! (plist = mdatabase_list (Mfont, Mlayouter, Mnil, Mnil)))
+    return -1;
+  if (! (flt_list = mplist ()))
+    goto err;
+  if (! (key_list = mplist ()))
+    goto err;
+  if (! mplist_add (key_list, Mcategory, Mt))
+    goto err;
+
+  MPLIST_DO (pl, plist)
+    {
+      MDatabase *mdb = MPLIST_VAL (pl);
+      MSymbol *tags = mdatabase_tag (mdb);
+      MFLT *flt;
+
+      if (! MSTRUCT_CALLOC_SAFE (flt))
+       goto err;
+      flt->name = tags[2];
+      flt->mdb = mdb;
+      if (load_flt (flt, key_list) < 0)
+       free (flt);
+      else
+       {
+         if (MPLIST_TAIL_P (flt_list))
+           {
+             flt_min_coverage = mchartable_min_char (flt->coverage);
+             flt_max_coverage = mchartable_max_char (flt->coverage);
+           }
+         else
+           {
+             int c;
+
+             c = mchartable_min_char (flt->coverage);
+             if (flt_min_coverage > c)
+               flt_min_coverage = c;
+             c = mchartable_max_char (flt->coverage);
+             if (flt_max_coverage < c)
+               flt_max_coverage = c;
+           }
+         if (! mplist_push (flt_list, flt->name, flt))
+           goto err;
+       }
+    }
+  goto end;
+
+ err:
+  free_flt_list ();
+  result = -1;
+ end:
+  M17N_OBJECT_UNREF (plist);  
+  M17N_OBJECT_UNREF (key_list);
+  return result;
+}
+
+/* FLS (Font Layout Service) */
+
+/* Structure to hold information about a context of FLS.  */
+
+typedef struct
+{
+  /* Pointer to the current stage.  */
+  FontLayoutStage *stage;
+
+  /* Pointer to the font.  */
+  MFLTFont *font;
+
+  /* Input and output glyph string.  */
+  MFLTGlyphString *in, *out;
+
+  /* Encode each character or code of a glyph by the current category
+     table into this array.  An element is a category letter used for
+     a regular expression matching.  */
+  char *encoded;
+  int *match_indices;
+  int code_offset;
+  int cluster_begin_idx;
+  int cluster_begin_pos;
+  int cluster_end_pos;
+  int combining_code;
+  int left_padding;
+  int check_mask;
+} FontLayoutContext;
+
+static int run_command (int, int, int, int, FontLayoutContext *);
+
+#define NMATCH 20
+
+static int
+run_rule (int depth,
+         FontLayoutCmdRule *rule, int from, int to, FontLayoutContext *ctx)
+{
+  int *saved_match_indices = ctx->match_indices;
+  int match_indices[NMATCH * 2];
+  int consumed;
+  int i;
+  int orig_from = from;
+
+  if (rule->src_type == SRC_SEQ)
+    {
+      int len;
+
+      len = rule->src.seq.n_codes;
+      if (len > (to - from))
+       return 0;
+      for (i = 0; i < len; i++)
+       if (rule->src.seq.codes[i] != GREF (ctx->in, from + i)->code)
+         break;
+      if (i < len)
+       return 0;
+      to = from + len;
+      if (MDEBUG_FLAG () > 2)
+       MDEBUG_PRINT3 ("\n [FLT] %*s(SEQ 0x%X", depth, "",
+                      rule->src.seq.codes[0]);
+    }
+  else if (rule->src_type == SRC_RANGE)
+    {
+      int head;
+
+      if (from >= to)
+       return 0;
+      head = GREF (ctx->in, from)->code;
+      if (head < rule->src.range.from || head > rule->src.range.to)
+       return 0;
+      ctx->code_offset = head - rule->src.range.from;
+      to = from + 1;
+      if (MDEBUG_FLAG () > 2)
+       MDEBUG_PRINT4 ("\n [FLT] %*s(RANGE 0x%X-0x%X", depth, "",
+                      rule->src.range.from, rule->src.range.to);
+    }
+  else if (rule->src_type == SRC_REGEX)
+    {
+      regmatch_t pmatch[NMATCH];
+      char saved_code;
+      int result;
+
+      if (from > to)
+       return 0;
+      saved_code = ctx->encoded[to];
+      ctx->encoded[to] = '\0';
+      result = regexec (&(rule->src.re.preg),
+                       ctx->encoded + from, NMATCH, pmatch, 0);
+      if (result == 0 && pmatch[0].rm_so == 0)
+       {
+         if (MDEBUG_FLAG () > 2)
+           MDEBUG_PRINT5 ("\n [FLT] %*s(REGEX \"%s\" \"%s\" %d", depth, "",
+                          rule->src.re.pattern,
+                          ctx->encoded + from,
+                          pmatch[0].rm_eo);
+         ctx->encoded[to] = saved_code;
+         for (i = 0; i < NMATCH; i++)
+           {
+             if (pmatch[i].rm_so < 0)
+               match_indices[i * 2] = match_indices[i * 2 + 1] = -1;
+             else
+               {
+                 match_indices[i * 2] = from + pmatch[i].rm_so;
+                 match_indices[i * 2 + 1] = from + pmatch[i].rm_eo;
+               }
+           }
+         ctx->match_indices = match_indices;
+         to = match_indices[1];
+       }
+      else
+       {
+         ctx->encoded[to] = saved_code;
+         return 0;
+       }
+    }
+  else if (rule->src_type == SRC_INDEX)
+    {
+      if (rule->src.match_idx >= NMATCH)
+       return 0;
+      from = ctx->match_indices[rule->src.match_idx * 2];
+      if (from < 0)
+       return 0;
+      to = ctx->match_indices[rule->src.match_idx * 2 + 1];
+      if (MDEBUG_FLAG () > 2)
+       MDEBUG_PRINT3 ("\n [FLT] %*s(INDEX %d", depth, "", rule->src.match_idx);
+    }
+  else if (rule->src_type == SRC_HAS_GLYPH)
+    {
+      int encoded;
+      unsigned code;
+
+      if (rule->src.supported_glyph < 0)
+       {
+         if (from >= to)
+           return 0;
+         code = GREF (ctx->in, from)->code;
+         to = from + 1;
+         encoded = GREF (ctx->in, from)->encoded;
+       }
+      else
+       {
+         code = rule->src.supported_glyph;
+         to = from;
+         encoded = 0;
+       }
+      if (! encoded)
+       {
+         static MFLTGlyphString gstring;
+
+         if (! gstring.glyph_size)
+           {
+             gstring.glyph_size = ctx->in->glyph_size;
+             gstring.glyphs = calloc (1, gstring.glyph_size);
+             gstring.allocated = 1;
+             gstring.used = 1;
+           }
+         gstring.glyphs[0].code = code;
+         if (ctx->font->get_glyph_id (ctx->font, &gstring, 0, 1) < 0
+             || ! gstring.glyphs[0].encoded)
+           return 0;
+       }
+    }
+  else if (rule->src_type == SRC_OTF_SPEC)
+    {
+      MFLTOtfSpec *spec = &rule->src.otf_spec;
+
+      if (! ctx->font->check_otf)
+       {
+         if ((spec->features[0] && spec->features[0][0] != 0xFFFFFFFF)
+             || (spec->features[1] && spec->features[1][0] != 0xFFFFFFFF))
+           return 0;
+       }
+      else if (! ctx->font->check_otf (ctx->font, spec))
+       return 0;
+    }
+
+  consumed = 0;
+  depth++;
+  for (i = 0; i < rule->n_cmds; i++)
+    {
+      int pos;
+
+      if (rule->cmd_ids[i] == CMD_ID_REPEAT)
+       {
+         if (! consumed)
+           continue;
+         i--;
+       }
+      pos = run_command (depth, rule->cmd_ids[i], from, to, ctx);
+      if (pos < 0)
+       return pos;
+      consumed = pos > from;
+      if (consumed)
+       from = pos;
+    }
+
+  ctx->match_indices = saved_match_indices;
+  if (MDEBUG_FLAG () > 2)
+    MDEBUG_PRINT (")");
+  return (rule->src_type == SRC_INDEX ? orig_from : to);
+}
+
+static int
+run_cond (int depth,
+         FontLayoutCmdCond *cond, int from, int to, FontLayoutContext *ctx)
+{
+  int i, pos = 0;
+
+  if (MDEBUG_FLAG () > 2)
+    MDEBUG_PRINT2 ("\n [FLT] %*s(COND", depth, "");
+  depth++;
+  for (i = 0; i < cond->n_cmds; i++)
+    {
+      /* TODO: Write a code for optimization utilizaing the info
+        cond->seq_XXX.  */
+      if ((pos = run_command (depth, cond->cmd_ids[i], from, to, ctx))
+         != 0)
+       break;
+    }
+  if (pos < 0)
+    return pos;
+  if (MDEBUG_FLAG () > 2)
+    MDEBUG_PRINT (")");
+  return (pos);
+}
+
+static int
+run_otf (int depth,
+        MFLTOtfSpec *otf_spec, int from, int to, FontLayoutContext *ctx)
+{
+  MFLTFont *font = ctx->font;
+  int from_idx = ctx->out->used;
+
+  if (MDEBUG_FLAG () > 2)
+    MDEBUG_PRINT3 ("\n [FLT] %*s%s", depth, "", MSYMBOL_NAME (otf_spec->sym));
+
+  font->get_glyph_id (font, ctx->in, from, to);
+  if (! font->drive_otf)
+    {
+      if (ctx->out->used + (to - from) > ctx->out->allocated)
+       return -2;
+      font->get_metrics (font, ctx->in, from, to);
+      GCPY (ctx->in, from, to - from, ctx->out, ctx->out->used);
+      ctx->out->used += to - from;
+    }
+  else
+    {
+      MFLTGlyphAdjustment *adjustment;
+      int out_len;
+      int i;
+
+      adjustment = alloca ((sizeof *adjustment)
+                          * (ctx->out->allocated - ctx->out->used));
+      if (! adjustment)
+       MERROR (MERROR_FLT, -1);
+      memset (adjustment, 0,
+             (sizeof *adjustment) * (ctx->out->allocated - ctx->out->used));
+      to = font->drive_otf (font, otf_spec, ctx->in, from, to, ctx->out,
+                           adjustment);
+      if (to < 0)
+       return to;
+      out_len = ctx->out->used - from_idx;
+      if (otf_spec->features[1])
+       {
+         MFLTGlyphAdjustment *a;
+         MFLTGlyph *g;
+         
+         for (i = 0, a = adjustment; i < out_len; i++, a++)
+           if (a->set)
+             break;
+         if (i < out_len)
+           {
+             font->get_metrics (font, ctx->out, from_idx, ctx->out->used);
+             for (i = 0, g = GREF (ctx->out, from_idx + i), a = adjustment;
+                  i < out_len; i++, a++, g = NEXT (ctx->out, g))
+               {
+                 SET_MEASURED (g, 1);
+                 if (a->advance_is_absolute)
+                   {
+                     g->xadv = a->xadv;
+                     g->yadv = a->yadv;
+                   }
+                 else if (a->xadv || a->yadv)
+                   {
+                     g->xadv += a->xadv;
+                     g->yadv += a->yadv;
+                   }
+                 if (a->xoff || a->yoff)
+                   {
+                     int j;
+                     MFLTGlyph *gg = PREV (ctx->out, g);
+                     MFLTGlyphAdjustment *aa = a;
+
+                     g->xoff = a->xoff;
+                     g->yoff = a->yoff;
+                     while (aa->back > 0)
+                       {
+                         for (j = 0; j < aa->back;
+                              j++, gg = PREV (ctx->out, gg))
+                           g->xoff -= gg->xadv;
+                         aa = aa - aa->back;
+                         g->xoff += aa->xoff;
+                         g->yoff += aa->yoff;
+                       }
+                   }
+               }
+           }
+       }
+    }
+
+  if (ctx->cluster_begin_idx >= 0)
+    for (; from_idx < ctx->out->used; from_idx++)
+      {
+       MFLTGlyph *g = GREF (ctx->out, from_idx);
+       UPDATE_CLUSTER_RANGE (ctx, g);
+      }
+  return to;
+}
+
+static char work[16];
+
+static char *
+dump_combining_code (int code)
+{
+  char *vallign = "tcbB";
+  char *hallign = "lcr";
+  char *p;
+  int off_x, off_y;
+
+  if (! code)
+    return "none";
+  work[0] = vallign[COMBINING_CODE_BASE_Y (code)];
+  work[1] = hallign[COMBINING_CODE_BASE_X (code)];
+  off_y = COMBINING_CODE_OFF_Y (code);
+  off_x = COMBINING_CODE_OFF_X (code);
+  if (off_y > 0)
+    sprintf (work + 2, "+%d", off_y);
+  else if (off_y < 0)
+    sprintf (work + 2, "%d", off_y);
+  else if (off_x == 0)
+    sprintf (work + 2, ".");
+  p = work + strlen (work);
+  if (off_x > 0)
+    sprintf (p, ">%d", off_x);
+  else if (off_x < 0)
+    sprintf (p, "<%d", -off_x);
+  p += strlen (p);
+  p[0] = vallign[COMBINING_CODE_ADD_Y (code)];
+  p[1] = hallign[COMBINING_CODE_ADD_X (code)];
+  p[2] = '\0';
+  return work;
+}
+
+static int
+run_command (int depth, int id, int from, int to, FontLayoutContext *ctx)
+{
+  MFLTGlyph *g;
+
+  if (id >= 0)
+    {
+      int i;
+
+      /* Direct code (== ctx->code_offset + id) output.
+        The source is not consumed.  */
+      if (MDEBUG_FLAG () > 2)
+       MDEBUG_PRINT3 ("\n [FLT] %*s(DIRECT 0x%X", depth, "",
+                      ctx->code_offset + id);
+      i = (from < to || from == 0) ? from : from - 1;
+      GDUP (ctx, i);
+      g = GREF (ctx->out, ctx->out->used - 1);
+      g->code = ctx->code_offset + id;
+      SET_ENCODED (g, 0);
+      SET_MEASURED (g, 0);
+      if (ctx->combining_code)
+       SET_COMBINING_CODE (g, ctx, ctx->combining_code);
+      if (ctx->left_padding)
+       SET_LEFT_PADDING (g, ctx, LeftPaddingMask);
+      for (i = from; i < to; i++)
+       {
+         MFLTGlyph *tmp = GREF (ctx->in, i);
+
+         if (g->from > tmp->from)
+           g->from = tmp->from;
+         else if (g->to < tmp->to)
+           g->to = tmp->to;
+       }
+      UPDATE_CLUSTER_RANGE (ctx, g);
+      ctx->code_offset = ctx->combining_code = ctx->left_padding = 0;
+      if (MDEBUG_FLAG () > 2)
+       MDEBUG_PRINT (")");
+      return (from);
+    }
+
+  if (id <= CMD_ID_OFFSET_INDEX)
+    {
+      int idx = CMD_ID_TO_INDEX (id);
+      FontLayoutCmd *cmd;
+
+      if (idx >= ctx->stage->used)
+       MERROR (MERROR_DRAW, -1);
+      cmd = ctx->stage->cmds + idx;
+      if (cmd->type == FontLayoutCmdTypeRule)
+       to = run_rule (depth, &cmd->body.rule, from, to, ctx);
+      else if (cmd->type == FontLayoutCmdTypeCond)
+       to = run_cond (depth, &cmd->body.cond, from, to, ctx);
+      else if (cmd->type == FontLayoutCmdTypeOTF)
+       to = run_otf (depth, &cmd->body.otf, from, to, ctx);
+      return to;
+    }
+
+  if (id <= CMD_ID_OFFSET_COMBINING)
+    {
+      ctx->combining_code = CMD_ID_TO_COMBINING_CODE (id);
+      if (MDEBUG_FLAG () > 2)
+       MDEBUG_PRINT3 ("\n [FLT] %*s(CMB %s)", depth, "",
+                      dump_combining_code (ctx->combining_code));
+      return from;
+    }
+
+  switch (id)
+    {
+    case CMD_ID_COPY:
+      {
+       if (from >= to)
+         return from;
+       GDUP (ctx, from);
+       g = GREF (ctx->out, ctx->out->used - 1);
+       if (ctx->combining_code)
+         SET_COMBINING_CODE (g, ctx, ctx->combining_code);
+       if (ctx->left_padding)
+         SET_LEFT_PADDING (g, ctx, LeftPaddingMask);
+       UPDATE_CLUSTER_RANGE (ctx, g);
+       if (MDEBUG_FLAG () > 2)
+         {
+           if (g->c < 0)
+             MDEBUG_PRINT2 ("\n [FLT] %*s(COPY |)", depth, "");
+           else
+             MDEBUG_PRINT3 ("\n [FLT] %*s(COPY 0x%X)", depth, "", g->code);
+         }
+       ctx->code_offset = ctx->combining_code = ctx->left_padding = 0;
+       return (from + 1);
+      }
+
+    case CMD_ID_CLUSTER_BEGIN:
+      if (ctx->cluster_begin_idx < 0)
+       {
+         if (MDEBUG_FLAG () > 2)
+           MDEBUG_PRINT3 ("\n [FLT] %*s<%d", depth, "",
+                          GREF (ctx->in, from)->from);
+         ctx->cluster_begin_idx = ctx->out->used;
+         ctx->cluster_begin_pos = GREF (ctx->in, from)->from;
+         ctx->cluster_end_pos = GREF (ctx->in, from)->to;
+       }
+      return from;
+
+    case CMD_ID_CLUSTER_END:
+      if (ctx->cluster_begin_idx >= 0
+         && ctx->cluster_begin_idx < ctx->out->used)
+       {
+         int i;
+
+         if (MDEBUG_FLAG () > 2)
+           MDEBUG_PRINT1 (" %d>", ctx->cluster_end_pos + 1);
+         for (i = ctx->cluster_begin_idx; i < ctx->out->used; i++)
+           {
+             GREF (ctx->out, i)->from = ctx->cluster_begin_pos;
+             GREF (ctx->out, i)->to = ctx->cluster_end_pos;
+           }
+         ctx->cluster_begin_idx = -1;
+       }
+      return from;
+
+    case CMD_ID_SEPARATOR:
+      {
+       int i;
+
+       i = from < to ? from : from - 1;
+       GDUP (ctx, i);
+       g = GREF (ctx->out, ctx->out->used - 1);
+       g->c = -1, g->code = 0;
+       g->xadv = g->yadv = 0;
+       SET_ENCODED (g, 0);
+       SET_MEASURED (g, 0);
+       return from;
+      }
+
+    case CMD_ID_LEFT_PADDING:
+      if (MDEBUG_FLAG () > 2)
+       MDEBUG_PRINT2 ("\n [FLT] %*s[", depth, "");
+      ctx->left_padding = 1;
+      return from;
+
+    case CMD_ID_RIGHT_PADDING:
+      if (ctx->out->used > 0)
+       {
+         if (MDEBUG_FLAG () > 2)
+           MDEBUG_PRINT2 ("\n [FLT] %*s]", depth, "");
+         g = GREF (ctx->out, ctx->out->used - 1);
+         SET_RIGHT_PADDING (g, ctx, RightPaddingMask);
+       }
+      return from;
+    }
+
+  MERROR (MERROR_DRAW, -1);
+}
+
+static int
+run_stages (MFLTGlyphString *gstring, int from, int to,
+           MFLT *flt, FontLayoutContext *ctx)
+{
+  MFLTGlyphString buf, *temp;
+  int stage_idx = 0;
+  int orig_from = from, orig_to = to;
+  int from_pos, to_pos, len;
+  int i, j;
+  MFLTGlyph *g;
+  MPlist *stages = flt->stages;
+
+  from_pos = GREF (ctx->in, from)->from;
+  to_pos = GREF (ctx->in, to - 1)->to;
+  len = to_pos - from_pos;
+
+  buf = *(ctx->in);
+  buf.glyphs = NULL;
+  GINIT (ctx->out, ctx->out->allocated);
+  ctx->encoded = alloca (ctx->out->allocated);
+  if (! ctx->out->glyphs || ! ctx->encoded)
+    return -1;
+
+  for (stage_idx = 0; 1; stage_idx++)
+    {
+      MCharTable *table;
+      int result;
+
+      ctx->stage = (FontLayoutStage *) MPLIST_VAL (stages);
+      table = ctx->stage->category;
+      ctx->code_offset = ctx->combining_code = ctx->left_padding = 0;
+      for (i = from; i < to; i++)
+       {
+         MFLTGlyph *g = GREF (ctx->in, i);
+         char enc = (GET_ENCODED (g)
+                     ? (g->c > 0 ? (int) mchartable_lookup (table, g->c) : 1)
+                     : g->code
+                     ? (int) mchartable_lookup (table, g->code)
+                     : ' ');
+
+         ctx->encoded[i] = enc;
+         if (! enc && stage_idx == 0)
+           {
+             to = i;
+             break;
+           }
+       }
+      ctx->encoded[i] = '\0';
+      ctx->match_indices[0] = from;
+      ctx->match_indices[1] = to;
+      for (i = 2; i < NMATCH; i++)
+       ctx->match_indices[i] = -1;
+
+      if (MDEBUG_FLAG () > 2)
+       {
+         MDEBUG_PRINT2 ("\n [FLT]   (STAGE %d \"%s\"", stage_idx,
+                        ctx->encoded + from);
+         MDEBUG_PRINT (" (");
+         for (i = from; i < to; i++)
+           {
+             g = GREF (ctx->in, i);
+             if (g->c == -1)
+               MDEBUG_PRINT2 ("%*s|", (i > 0), "");
+             else
+               MDEBUG_PRINT3 ("%*s%04X", (i > 0), "", GREF (ctx->in, i)->code);
+           }
+         MDEBUG_PRINT (")");
+       }
+      result = run_command (4, INDEX_TO_CMD_ID (0), from, to, ctx);
+      if (MDEBUG_FLAG () > 2)
+       MDEBUG_PRINT (")");
+      if (result < 0)
+       return result;
+
+      stages = MPLIST_NEXT (stages);
+      /* If this is the last stage, break the loop. */
+      if (MPLIST_TAIL_P (stages))
+       break;
+
+      /* Otherwise, prepare for the next stage.   */
+      temp = ctx->in;
+      ctx->in = ctx->out;
+      if (buf.glyphs)
+       ctx->out = temp;
+      else
+       {
+         GINIT (&buf, ctx->out->allocated);
+         ctx->out = &buf;
+       }
+      ctx->out->used = 0;
+
+      from = 0;
+      to = ctx->in->used;
+    }
+
+  if (ctx->out->used > 0)
+    {
+      int *g_indices;
+      int x_ppem = ctx->font->x_ppem << 6, y_ppem = ctx->font->y_ppem << 6;
+
+      /* Remove separator glyphs.  */
+      for (i = 0; i < ctx->out->used;)
+       {
+         g = GREF (ctx->out, i);
+         if (g->c < 0)
+           GREPLACE (NULL, 0, 0, ctx->out, i, i + 1);
+         else
+           i++;
+       }
+
+      /* Get actual glyph IDs of glyphs.  */
+      ctx->font->get_glyph_id (ctx->font, ctx->out, 0, ctx->out->used);
+
+      /* Check if all characters in the range are covered by some
+        glyph(s).  If not, change <from> and <to> of glyphs to cover
+        uncovered characters.  */
+      g_indices = alloca (sizeof (int) * len);
+      if (! g_indices)
+       return -1;
+      for (i = 0; i < len; i++) g_indices[i] = -1;
+      for (i = 0; i < ctx->out->used; i++)
+       {
+         int pos;
+
+         g = GREF (ctx->out, i);
+         for (pos = g->from; pos <= g->to; pos++)
+           if (g_indices[pos - orig_from] < 0)
+             g_indices[pos - orig_from] = i;
+       }
+      for (i = 0; i < len; i++)
+       if (g_indices[i] < 0)
+         {
+           if (i == 0)
+             {
+               int this_from;
+
+               for (i++; i < len && g_indices[i] < 0; i++);
+               j = g_indices[i];
+               g = GREF (ctx->out, j);
+               this_from = g->from;
+               do {
+                 g->from = orig_from + i;
+               } while (++j < ctx->out->used
+                        && (g = GREF (ctx->out, j))
+                        && g->from == this_from);
+             }
+           else
+             {
+               int this_to;
+
+               j = g_indices[i - 1];
+               g = GREF (ctx->out, j);
+               this_to = g->to;
+               do {
+                 g->to = orig_from + i + 1;
+               } while (--j >= 0
+                        && (g = GREF (ctx->out, j))
+                        && g->to == this_to);
+             }
+         }
+
+      ctx->font->get_metrics (ctx->font, ctx->out, 0, ctx->out->used);
+
+      /* Handle combining.  */
+      if (ctx->check_mask & CombiningCodeMask)
+       {
+         MFLTGlyph *base = GREF (ctx->out, 0);
+         int base_height = base->ascent + base->descent;
+         int combining_code;
+
+         for (i = 1; i < ctx->out->used; i++)
+           {
+             if ((g = GREF (ctx->out, i))
+                 && (combining_code = GET_COMBINING_CODE (g)))
+               {
+                 int height = g->ascent + g->descent;
+                 int base_x, base_y, add_x, add_y, off_x, off_y;
+
+                 if (base->from > g->from)
+                   base->from = g->from;
+                 else if (base->to < g->to)
+                   base->to = g->to;
+               
+                 base_x = COMBINING_CODE_BASE_X (combining_code);
+                 base_y = COMBINING_CODE_BASE_Y (combining_code);
+                 add_x = COMBINING_CODE_ADD_X (combining_code);
+                 add_y = COMBINING_CODE_ADD_Y (combining_code);
+                 off_x = COMBINING_CODE_OFF_X (combining_code);
+                 off_y = COMBINING_CODE_OFF_Y (combining_code);
+
+                 g->xoff = ((base->xadv * base_x - g->xadv * add_x) / 2
+                            + x_ppem * off_x / 100 - base->xadv);
+                 if (base_y < 3)
+                   g->yoff = base_height * base_y / 2 - base->ascent;
+                 else
+                   g->yoff = 0;
+                 if (add_y < 3)
+                   g->yoff -= height * add_y / 2 - g->ascent;
+                 g->yoff -= y_ppem * off_y / 100;
+                 if (base->lbearing > base->xadv + g->lbearing + g->xoff)
+                   base->lbearing = base->xadv + g->lbearing + g->xoff;
+                 if (base->rbearing < base->xadv + g->xadv + g->xoff)
+                   base->rbearing = base->xadv + g->xadv + g->xoff;
+                 if (base->ascent < g->ascent - g->yoff)
+                   base->ascent = g->ascent - g->yoff;
+                 if (base->descent < g->descent - g->yoff)
+                   base->descent = g->descent - g->yoff;
+                 g->xadv = g->yadv = 0;
+                 if (GET_RIGHT_PADDING (g))
+                   SET_RIGHT_PADDING (base, ctx, RightPaddingMask);
+               }
+             else
+               {
+                 base = g;
+                 base_height = g->ascent + g->descent;
+               }
+           }
+       }
+
+      /* Handle padding */
+      if (ctx->check_mask & (LeftPaddingMask | RightPaddingMask))
+       for (i = 0; i < ctx->out->used; i++)
+         {
+           g = GREF (ctx->out, i);
+           if (! GET_COMBINING_CODE (g))
+             {
+               if (GET_RIGHT_PADDING (g) && g->rbearing > g->xadv)
+                 {
+                   g->xadv = g->rbearing;
+                 }
+               if (GET_LEFT_PADDING (g) && g->lbearing < 0)
+                 {
+                   g->xoff += - g->lbearing;
+                   g->xadv += - g->lbearing;
+                   g->rbearing += - g->lbearing;
+                   g->lbearing = 0;
+                 }
+             }
+         }
+    }
+
+  GREPLACE (ctx->out, 0, ctx->out->used, gstring, orig_from, orig_to);
+  to = orig_from + ctx->out->used;
+  return to;
+}
+
+static void
+setup_combining_coverage (int from, int to, void *val, void *arg)
+{
+  int combining_class = (int) val;
+  int category = 0;
+
+  if (combining_class < 200)
+    category = 'a';
+  else if (combining_class <= 204)
+    {
+      if ((combining_class % 2) == 0)
+       category = "bcd"[(combining_class - 200) / 2];
+    }
+  else if (combining_class <= 232)
+    {
+      if ((combining_class % 2) == 0)
+       category = "efghijklmnopq"[(combining_class - 208) / 2];
+    }
+  else if (combining_class == 233)
+    category = 'r';
+  else if (combining_class == 234)
+    category = 's';
+  else if (combining_class == 240)
+    category = 't';
+  mchartable_set_range ((MCharTable *) arg, from, to, (void *) category);
+}
+
+static void
+setup_combining_flt (MFLT *flt)
+{
+  MSymbol type;
+  MCharTable *combininig_class_table
+    = mchar_get_prop_table (Mcombining_class, &type);
+
+  mchartable_set_range (flt->coverage, 0, 0x10FFFF, (void *) 'u');
+  if (combininig_class_table)
+    mchartable_map (combininig_class_table, (void *) 0,
+                   setup_combining_coverage, flt->coverage);
+}
+
+#define CHECK_FLT_STAGES(flt) ((flt)->stages || load_flt (flt, NULL) == 0)
+
+\f
+/* Internal API */
+
+int m17n__flt_initialized;
+
+\f
+/* External API */
+
+/* The following two are actually not exposed to a user but concealed
+   by the macro M17N_INIT (). */
+
+void
+m17n_init_flt (void)
+{
+  int mdebug_flag = MDEBUG_INIT;
+
+  merror_code = MERROR_NONE;
+  if (m17n__flt_initialized++)
+    return;
+  m17n_init_core ();
+  if (merror_code != MERROR_NONE)
+    {
+      m17n__flt_initialized--;
+      return;
+    }
+
+  MDEBUG_PUSH_TIME ();
+
+  Mcond = msymbol ("cond");
+  Mrange = msymbol ("range");
+  Mfont = msymbol ("font");
+  Mlayouter = msymbol ("layouter");
+  Mcombining = msymbol ("combining");
+  Mfont_facility = msymbol ("font-facility");
+  Mgenerator = msymbol ("generator");
+  Mend = msymbol ("end");
+
+  MDEBUG_PRINT_TIME ("INIT", (stderr, " to initialize the flt modules."));
+  MDEBUG_POP_TIME ();
+}
+
+void
+m17n_fini_flt (void)
+{
+  int mdebug_flag = MDEBUG_FINI;
+
+  if (m17n__flt_initialized == 0
+      || --m17n__flt_initialized > 0)
+    return;
+
+  MDEBUG_PUSH_TIME ();
+  free_flt_list ();
+  MDEBUG_PRINT_TIME ("FINI", (stderr, " to finalize the flt modules."));
+  MDEBUG_POP_TIME ();
+  m17n_fini_core ();
+}
+
+/*** @} */ 
+#endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
+
+/*** @addtogroup m17nFLT */
+/*** @{ */
+/*=*/
+
+/*=*/
+/***en
+    @brief Return a FLT object whose name is NAME.
+
+    The mflt_get () function returns a FLT object whose name is $NAME.
+
+    @return
+    If the operation was successfully, mflt_get () returns a pointer
+    to a FLT object.  Otherwise, it returns @c NULL.  */
+
+MFLT *
+mflt_get (MSymbol name)
+{
+  MFLT *flt;
+
+  if (! flt_list && list_flt () < 0)
+    return NULL;
+  flt = mplist_get (flt_list, name);
+  if (! flt || ! CHECK_FLT_STAGES (flt))
+    return NULL;
+  if (flt->name == Mcombining
+      && ! mchartable_lookup (flt->coverage, 0))
+    setup_combining_flt (flt);
+
+  return flt;
+}
+
+/*=*/
+/***en
+    @brief Find a FLT suitable for a specified character and font.
+
+    The mflt_find () function returns the most appropriate FLT for
+    rendering the character $C by font $FONT.
+
+    @return
+    If the operation was successfully, mflt_find () returns a pointer
+    to a FLT object.  Otherwise, it returns @c NULL.  */
+
+MFLT *
+mflt_find (int c, MFLTFont *font)
+{
+  MPlist *plist;
+  MFLT *flt;
+  static MSymbol unicode_bmp = NULL, unicode_full = NULL;
+
+  if (! unicode_bmp)
+    {
+      unicode_bmp = msymbol ("unicode-bmp");
+      unicode_full = msymbol ("unicode-full");
+    }
+
+  if (! flt_list && list_flt () < 0)
+    return NULL;
+  if (font)
+    {
+      MFLT *best = NULL;
+
+      MPLIST_DO (plist, flt_list)
+       {
+         flt = MPLIST_VAL (plist);
+         if (flt->registry != unicode_bmp
+             && flt->registry != unicode_full)
+           continue;
+         if (flt->family && flt->family != font->family)
+           continue;
+         if (c >= 0
+             && ! mchartable_lookup (flt->coverage, c))
+           continue;
+         if (flt->otf.sym)
+           {
+             MFLTOtfSpec *spec = &flt->otf;
+
+             if (! font->check_otf)
+               {
+                 if ((spec->features[0] && spec->features[0][0] != 0xFFFFFFFF)
+                     || (spec->features[1] && spec->features[1][0] != 0xFFFFFFFF))
+                   continue;
+               }
+             else if (! font->check_otf (font, spec))
+               continue;
+             return flt;
+           }
+         best = flt;
+       }
+      return best;
+    }
+  if (c >= 0)
+    {
+      MPLIST_DO (plist, flt_list)
+       {
+         flt = MPLIST_VAL (plist);
+         if (mchartable_lookup (flt->coverage, c))
+           return flt;
+       }
+    }
+  return NULL;
+}
+
+/*=*/
+/***en
+    @brief Return a name of a FLT.
+
+    The mflt_name () function returns the name of $FLT.  */
+
+const char *
+mflt_name (MFLT *flt)
+{
+  return MSYMBOL_NAME (flt->name);
+}
+
+/*=*/
+/***en
+    @brief Return a coverage of a FLT.
+
+    The mflt_coverage () function returns a char-table that contains
+    nonzero value for characters supported by $FLT.  */
+
+MCharTable *
+mflt_coverage (MFLT *flt)
+{
+  return flt->coverage;
+}
+
+/*=*/
+/***en
+    @brief Layout characters by Font Layout Table.
+
+    The mflt_run () function layout characters in $GSTRING between
+    $FROM (inclusive) and $TO (exclusive) by $FONT.  If $FLT is
+    nonzero, it is used for all the charaters.  Otherwise, appropriate
+    FLTs are automatically chosen.
+
+    @retval >=0
+    The operation was successful.  The value is an index to the
+    $GSTRING->glyphs which was previously indexed by $TO.
+
+    @retval -2
+    $GSTRING->glyphs is too short to store the result.  A caller can
+    call this fucntion again with the larger $GSTRING->glyphs.
+
+    @retval -1
+    Some other error occurred.  */
+
+int
+mflt_run (MFLTGlyphString *gstring, int from, int to,
+         MFLTFont *font, MFLT *flt)
+{
+  FontLayoutContext ctx;
+  int match_indices[NMATCH];
+  MFLTGlyph *g;
+  MFLTGlyphString out;
+  int auto_flt = ! flt;
+  int c, i, j, k;
+  int this_from, this_to;
+
+  out = *gstring;
+  out.glyphs = NULL;
+  /* This is usually sufficient, but if not, we retry with the larger
+     values at most 3 times.  This value is also used for the
+     allocating size of ctx.encoded.  */
+  out.allocated = (to - from) * 4;
+
+  for (i = from; i < to; i++)
+    {
+      g = GREF (gstring, i);
+      c = g->c;
+      memset (g, 0, sizeof (MFLTGlyph));
+      g->code = g->c = c;
+      g->from = g->to = i;
+    }
+
+  for (this_from = from; this_from < to;)
+    {
+      if (! auto_flt)
+       {
+         for (this_to = this_from; this_to < to; this_to++)
+           if (mchartable_lookup (flt->coverage, GREF (gstring, this_to)->c))
+             break;
+       }
+      else
+       {
+         if (! flt_list && list_flt () < 0)
+           {
+             font->get_glyph_id (font, gstring, this_from, to);
+             font->get_metrics (font, gstring, this_from, to);
+             this_from = to;
+             break;
+           }
+         for (this_to = this_from; this_to < to; this_to++)
+           {
+             c = GREF (gstring, this_to)->c;
+             if (c >= flt_min_coverage && c <= flt_max_coverage)
+               break;
+           }
+         for (; this_to < to; this_to++)
+           {
+             c = GREF (gstring, this_to)->c;
+             if (font->internal
+                 && mchartable_lookup (((MFLT *) font->internal)->coverage, c))
+               {
+                 flt = font->internal;
+                 break;
+               }
+             flt = mflt_find (c, font);
+             if (flt)
+               {
+                 if (CHECK_FLT_STAGES (flt))
+                   {
+                     font->internal = flt;
+                     break;
+                   }
+               }
+           }
+       }
+
+      if (this_from < this_to)
+       {
+         font->get_glyph_id (font, gstring, this_from, this_to);
+         font->get_metrics (font, gstring, this_from, this_to);
+         this_from = this_to;
+       }
+      if (this_to == to)
+       break;
+
+      MDEBUG_PRINT1 (" [FLT] (%s", MSYMBOL_NAME (flt->name));
+
+      for (; this_to < to; this_to++)
+       if (! mchartable_lookup (flt->coverage, GREF (gstring, this_to)->c))
+         break;
+
+      if (MDEBUG_FLAG ())
+       {
+         if (font->family)
+           MDEBUG_PRINT1 (" (%s)", MSYMBOL_NAME (font->family));
+         MDEBUG_PRINT ("\n [FLT]   (SOURCE");
+         for (i = this_from, j = 0; i < this_to; i++, j++)
+           {
+             if (j > 0 && j % 8 == 0)
+               MDEBUG_PRINT ("\n [FLT]          ");
+             MDEBUG_PRINT1 (" %04X", GREF (gstring, i)->c);
+           }
+         MDEBUG_PRINT (")");
+       }
+
+      for (i = 0; i < 3; i++)
+       {
+         /* Setup CTX.  */
+         memset (&ctx, 0, sizeof ctx);
+         ctx.match_indices = match_indices;
+         ctx.font = font;
+         ctx.cluster_begin_idx = -1;
+         ctx.in = gstring;
+         ctx.out = &out;
+         j = run_stages (gstring, this_from, this_to, flt, &ctx);
+         if (j != -2)
+           break;
+         out.allocated *= 2;
+       }
+
+      if (j < 0)
+       return j;
+
+      to += j - this_to;
+      this_to = j;
+
+      if (MDEBUG_FLAG ())
+       {
+         MDEBUG_PRINT ("\n [FLT]   (RESULT");
+         if (MDEBUG_FLAG () > 1)
+           for (i = 0; this_from < this_to; this_from++, i++)
+             {
+               if (i > 0 && i % 4 == 0)
+                 MDEBUG_PRINT ("\n [FLT]          ");
+               g = GREF (gstring, this_from);
+               MDEBUG_PRINT4 (" (%04X %d %d %d)",
+                              g->code, g->xadv, g->xoff, g->yoff);
+             }
+         else
+           for (; this_from < this_to; this_from++)
+             MDEBUG_PRINT1 (" %04X", GREF (gstring, this_from)->code);
+         MDEBUG_PRINT ("))\n");
+       }
+      this_from = this_to;
+    }
+
+  if (gstring->r2l)
+    {
+      int len = to - from;
+
+      GINIT (&out, len);
+      memcpy (((char *) out.glyphs),
+             ((char *) gstring->glyphs) + gstring->glyph_size * from,
+             gstring->glyph_size * len);
+      for (i = from, j = to; i < to;)
+       {
+         for (k = i + 1, j--; k < to && GREF (&out, k)->xadv == 0;
+              k++, j--);
+         GCPY (&out, i, (k - i), gstring, j);
+         i = k;
+       }
+    }
+
+  return to;
+}
+
+\f
+/* for debugging... */
+
+static void
+dump_flt_cmd (FontLayoutStage *stage, int id, int indent)
+{
+  char *prefix = (char *) alloca (indent + 1);
+
+  memset (prefix, 32, indent);
+  prefix[indent] = 0;
+
+  if (id >= 0)
+    fprintf (stderr, "0x%02X", id);
+  else if (id <= CMD_ID_OFFSET_INDEX)
+    {
+      int idx = CMD_ID_TO_INDEX (id);
+      FontLayoutCmd *cmd = stage->cmds + idx;
+
+      if (cmd->type == FontLayoutCmdTypeRule)
+       {
+         FontLayoutCmdRule *rule = &cmd->body.rule;
+         int i;
+
+         fprintf (stderr, "(rule ");
+         if (rule->src_type == SRC_REGEX)
+           fprintf (stderr, "\"%s\"", rule->src.re.pattern);
+         else if (rule->src_type == SRC_INDEX)
+           fprintf (stderr, "%d", rule->src.match_idx);
+         else if (rule->src_type == SRC_SEQ)
+           fprintf (stderr, "(seq)");
+         else if (rule->src_type == SRC_RANGE)
+           fprintf (stderr, "(range)");
+         else
+           fprintf (stderr, "(invalid src)");
+
+         for (i = 0; i < rule->n_cmds; i++)
+           {
+             fprintf (stderr, "\n%s  ", prefix);
+             dump_flt_cmd (stage, rule->cmd_ids[i], indent + 2);
+           }
+         fprintf (stderr, ")");
+       }
+      else if (cmd->type == FontLayoutCmdTypeCond)
+       {
+         FontLayoutCmdCond *cond = &cmd->body.cond;
+         int i;
+
+         fprintf (stderr, "(cond");
+         for (i = 0; i < cond->n_cmds; i++)
+           {
+             fprintf (stderr, "\n%s  ", prefix);
+             dump_flt_cmd (stage, cond->cmd_ids[i], indent + 2);
+           }
+         fprintf (stderr, ")");
+       }
+      else if (cmd->type == FontLayoutCmdTypeOTF)
+       {
+         fprintf (stderr, "(otf)");
+       }
+      else
+       fprintf (stderr, "(error-command)");
+    }
+  else if (id <= CMD_ID_OFFSET_COMBINING)
+    fprintf (stderr, "cominging-code");
+  else
+    fprintf (stderr, "(predefiend %d)", id);
+}
+
+void
+mdebug_dump_flt (MFLT *flt, int indent)
+{
+  char *prefix = (char *) alloca (indent + 1);
+  MPlist *plist;
+  int stage_idx = 0;
+
+  memset (prefix, 32, indent);
+  prefix[indent] = 0;
+  fprintf (stderr, "(flt");
+  MPLIST_DO (plist, flt->stages)
+    {
+      FontLayoutStage *stage = (FontLayoutStage *) MPLIST_VAL (plist);
+      int i;
+
+      fprintf (stderr, "\n%s  (stage %d", prefix, stage_idx);
+      for (i = 0; i < stage->used; i++)
+       {
+         fprintf (stderr, "\n%s    ", prefix);
+         dump_flt_cmd (stage, INDEX_TO_CMD_ID (i), indent + 4);
+       }
+      fprintf (stderr, ")");
+      stage_idx++;
+    }
+  fprintf (stderr, ")");
+}
+
+/*** @} */
+
+/*
+ Local Variables:
+ coding: euc-japan
+ End:
+*/
diff --git a/src/m17n-flt.h b/src/m17n-flt.h
new file mode 100644 (file)
index 0000000..526978c
--- /dev/null
@@ -0,0 +1,261 @@
+/* m17n-flt.h -- header file for the FLT API of the m17n library.
+   Copyright (C) 2007
+     National Institute of Advanced Industrial Science and Technology (AIST)
+     Registration Number H15PRO112
+
+   This file is part of the m17n library.
+
+   The m17n library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License
+   as published by the Free Software Foundation; either version 2.1 of
+   the License, or (at your option) any later version.
+
+   The m17n library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   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., 51 Franklin Street, Fifth Floor,
+   02111-1307, USA.  */
+
+#ifndef _M17N_FLT_H_
+#define _M17N_FLT_H_
+
+#ifndef _M17N_CORE_H_
+#include <m17n-core.h>
+#endif
+
+M17N_BEGIN_HEADER
+
+#if !defined (FOR_DOXYGEN) || defined (DOXYGEN_INTERNAL_MODULE)
+
+extern void m17n_init_flt (void);
+#undef M17N_INIT
+#define M17N_INIT() m17n_init_flt ()
+
+extern void m17n_fini_flt (void);
+#undef M17N_FINI
+#define M17N_FINI() m17n_fini_flt ()
+
+#endif
+
+/***en @defgroup m17nFLT FLT API */
+/***ja @defgroup m17nFLT FLT API */
+/*=*/
+
+/*** @addtogroup m17nFLT */
+/*** @{ */
+/*=*/
+
+/***en
+    @brief Type of information about a glyph.
+
+    The type #MFLTGlyph is the structure that contains information
+    about a glyph.  */
+
+typedef struct _MFLTGlyph MFLTGlyph;
+
+struct _MFLTGlyph
+{
+  /***en @brief Character code (Unicode) of the glyph.  This is the sole
+      member to be set before calling the functions mflt_find () and
+      mflt_run ().  */
+  int c;
+  /***en Glyph-id of the font of the glyph.  */
+  unsigned int code;
+  /***en Glyph indices indicating the start of the original glyphs.  */
+  int from;
+  /***en Glyph indices indicating the end of the original glyphs.  */
+  int to;
+  /***en Advance width for horizontal layout expressed in 26.6
+      fractional pixel format.  */
+  int xadv;
+  /***en Advance height for vertical layout expressed in 26.6
+      fractional pixel format.  */
+  int yadv;
+  /***en Ink metrics of the glyph expressed in 26.6 fractional pixel
+      format.  */
+  int ascent, descent, lbearing, rbearing;
+  /***en Horizontal and vertical adjustments for the glyph positioning
+      expressed in 26.6 fractional pixel format.  */
+  int xoff, yoff;
+  /***en Flag to tell if the member <code> is already encoded into a
+      glyph ID of a font.  */
+  unsigned encoded : 1;
+  /***en Flag to tell if the metrics of the glyph (members <xadv> thru
+      <rbearing>) are already calculated.  */
+  unsigned measured : 1;
+  /***en For m17n-lib's internal use only.  */
+  unsigned internal : 30;
+
+  /* Arbitrary data can follow.  */
+};
+
+/*=*/
+
+/***en
+    @brief Type of information about a glyph position adjustment.
+
+    The type #MFLTGlyphAdjustment is the structure to store
+    information about a glyph metrics/position adjustment.  It is
+    given to the callback function #drive_otf of #MFLTFont.  */
+
+typedef struct _MFLTGlyphAdjustment MFLTGlyphAdjustment;
+
+struct _MFLTGlyphAdjustment
+{
+  /***en Adjustments for advance width for horizontal layout and
+      advance height for vertical layout expressed in 26.6 fractional
+      pixel format.  */
+  int xadv, yadv;
+  /***en Horizontal and vertical adjustments for a glyph positioning
+      expressed in 26.6 fractional pixel format.  */
+  int xoff, yoff;
+  /***en Number of glyphs to go back for drawing a glyph.  */
+  short back;
+  /***en If nonzero, the member <xadv> and <yadv> are absolute, i.e.,
+      they should not be added to a glyph's origianl advance width and
+      height.  */
+  unsigned advance_is_absolute : 1;
+  /***en Should be set to 1 iff at least one of the other members has
+      a nonzero value.  */
+  unsigned set : 1;
+};
+
+/***en
+    @brief Type of information about a glyph sequence.
+
+    The type #MFLTGlyphString is the structure that contains
+    information about a sequence of glyphs.  */
+
+typedef struct _MFLTGlyphString MFLTGlyphString;
+
+struct _MFLTGlyphString
+{
+  /***en The actual byte size of elements of the array pointed by the
+      member #glyphs.  It must be equal to or greater than "sizeof
+      (MFLTGlyph)".  */
+  int glyph_size;
+  /***en Array of glyphs.  */
+  MFLTGlyph *glyphs;
+  /***en How many elements are allocated in #glyphs.  */
+  int allocated;
+  /***en How many elements in #glyphs are in use.  */
+  int used;
+  /***en Flag to tell if the glyphs should be drawn from right-to-left
+      or not.  */
+  unsigned int r2l;
+};
+
+/***en
+    @brief Type of specification of GSUB and GPOS OpenType tables.
+
+    The type #MFLTOtfSpec is the structure that contains information
+    about GSUB and GPOS features of a specific script and language
+    system to be applied to a glyph sequence.  */
+
+typedef struct _MFLTOtfSpec MFLTOtfSpec;
+
+struct _MFLTOtfSpec
+{
+  /***en Unique symbol representing the spec.  This is the same as the
+      #OTF-SPEC of the FLT.  */
+  MSymbol sym;
+
+  /***en Tags for script and language system.  */
+  unsigned int script, langsys;
+
+  /***en Array of GSUB (1st element) and GPOS (2nd element) features.
+      Each array is terminated by 0.  If an element is 0xFFFFFFFF,
+      apply the previous features in that order, and apply all the
+      other features except those appearing in the following elements.
+      It may be NULL if there's no feature.  */
+  unsigned int *features[2];
+};
+
+/***en
+    @brief Type of font to be used by the FLT driver.
+
+    The type #MFLTFont is the structure that contains information
+    about a font used by the FLT driver.  */
+
+typedef struct _MFLTFont MFLTFont;
+
+struct _MFLTFont
+{
+  /***en Family name of the font.  It may be #Mnil if the family name
+     is not important in finding a Font Layout Table suitable for the
+     font (for instance, in the case that the font is an OpenType
+     font).  */
+  MSymbol family;
+
+  /***en Horizontal and vertical font sizes in pixel per EM.  */
+  int x_ppem, y_ppem;
+
+  /***en Callback function to get glyph IDs for glyphs between FROM
+     (inclusive) and TO (exclusive) of GSTRING.  If <encoded> member
+     of a glyph is zero, the <code> member of the glyph is a character
+     code.  The function must convert it to the glyph ID of FONT.  */
+  int (*get_glyph_id) (MFLTFont *font, MFLTGlyphString *gstring,
+                      int from, int to);
+
+  /*** Callback function to get metrics of glyphs between FROM
+     (inclusive) and TO (exclusive) of GSTRING.  If <measured> member
+     of a glyph is zero, the function must set members <xadv>, <yadv>,
+     <ascent>, <descent>, <lbearing>, and <rbearing> of the glyph.  */
+  int (*get_metrics) (MFLTFont *font, MFLTGlyphString *gstring,
+                    int from, int to);
+
+  /***en Callback function to check if the font has OpenType GSUB/GPOS
+     features for a specific script/language.  The function must
+     return 1 if the font satisfy SPEC, else return 0.  It must be
+     NULL if the font doesn't have OpenType tables.  */
+  int (*check_otf) (MFLTFont *font, MFLTOtfSpec *spec);
+
+  /*** Callback function to apply OpenType features in SPEC to glyphs
+     between FROM (inclusive) and TO (exclusive) of IN.  The resulting
+     glyphs should be appended to the tail of OUT.  If OUT doesn't
+     have a room to store all resulting glyphs, it must return -2.
+     It must be NULL if the font doesn't have OpenType tables.  */
+  int (*drive_otf) (MFLTFont *font, MFLTOtfSpec *spec,
+                   MFLTGlyphString *in, int from, int to,
+                   MFLTGlyphString *out, MFLTGlyphAdjustment *adjustment);
+
+  /***en For m17n-lib's internal use only.  It should be initialized
+      to NULL.  */
+  void *internal;
+};
+
+/***en
+    @brief Type of FLT (Font Layout Table).
+
+    The type #MFLT is for a FLT object.  Its internal structure is
+    concealed from application program.  */
+
+typedef struct _MFLT MFLT;
+
+extern MFLT *mflt_get (MSymbol name);
+
+extern MFLT *mflt_find (int c, MFLTFont *font);
+
+extern const char *mflt_name (MFLT *flt);
+
+extern MCharTable *mflt_coverage (MFLT *flt);
+
+extern int mflt_run (MFLTGlyphString *gstring, int from, int to,
+                    MFLTFont *font, MFLT *flt);
+
+/*=*/
+/*** @} */
+
+M17N_END_HEADER
+
+#endif /* _M17N_FLT_H_ */
+
+/*
+  Local Variables:
+  coding: euc-japan
+  End:
+*/
index 600b049..fedf1c6 100644 (file)
@@ -68,7 +68,7 @@ static void
 read_rgb_txt ()
 {
   FILE *fp;
-  int r, g, b;
+  int r, g, b, i;
 
   /* At first, support HTML 4.0 color names. */
   msymbol_put (msymbol ("black"), M_rgb, (void *) 0x000000);
@@ -88,11 +88,18 @@ read_rgb_txt ()
   msymbol_put (msymbol ("teal"), M_rgb, (void *) 0x008080);
   msymbol_put (msymbol ("aqua"), M_rgb, (void *) 0x00FFFF);
 
-  fp = fopen ("/usr/lib/X11/rgb.txt", "r");
-  if (! fp)
-    fp = fopen ("/usr/X11R6/lib/X11/rgb.txt", "r");
-  if (! fp)
-    return;
+  {
+    char *rgb_path[]
+      =  {"/usr/lib/X11/rgb.txt", "/usr/X11R6/lib/X11/rgb.txt",
+         "/etc/X11/rgb.txt" };
+
+    fp = NULL;
+    for (i = 0; i < (sizeof rgb_path) / (sizeof rgb_path[0]); i++)
+      if ((fp = fopen ("/usr/lib/X11/rgb.txt", "r")))
+       break;
+    if (! fp)
+      return;
+  }
   while (1)
     {
       char buf[256];
@@ -114,6 +121,8 @@ read_rgb_txt ()
       buf[0] = c;
       fgets (buf + 1, 255, fp);
       len = strlen (buf);
+      for (i = 0; i < len; i++)
+       buf[i] = tolower (buf[i]);
       if (buf[len - 1] == '\n')
        buf[len - 1] = '\0';
       b |= (r << 16) | (g << 8);
@@ -319,14 +328,14 @@ gd_render (MDrawWindow win, int x, int y,
 #endif
     }
 
-  for (; from < to; x += from++->width)
+  for (; from < to; x += from++->g.xadv)
     {
       unsigned char *bmp;
       int xoff, yoff;
       int width, pitch;
 
-      FT_Load_Glyph (ft_face, (FT_UInt) from->code, load_flags);
-      yoff = y - ft_face->glyph->bitmap_top + from->yoff;
+      FT_Load_Glyph (ft_face, (FT_UInt) from->g.code, load_flags);
+      yoff = y - ft_face->glyph->bitmap_top + from->g.yoff;
       bmp = ft_face->glyph->bitmap.buffer;
       width = ft_face->glyph->bitmap.width;
       pitch = ft_face->glyph->bitmap.pitch;
@@ -339,7 +348,7 @@ gd_render (MDrawWindow win, int x, int y,
        for (i = 0; i < ft_face->glyph->bitmap.rows;
             i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
          {
-           xoff = x + ft_face->glyph->bitmap_left + from->xoff;
+           xoff = x + ft_face->glyph->bitmap_left + from->g.xoff;
            for (j = 0; j < width; j++, xoff++)
              if (bmp[j] > 0)
                {
@@ -373,7 +382,7 @@ gd_render (MDrawWindow win, int x, int y,
        for (i = 0; i < ft_face->glyph->bitmap.rows;
             i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
          {
-           xoff = x + ft_face->glyph->bitmap_left + from->xoff;
+           xoff = x + ft_face->glyph->bitmap_left + from->g.xoff;
            for (j = 0; j < width; j++, xoff++)
              if (bmp[j / 8] & (1 << (7 - (j % 8))))
                gdImageSetPixel (img, xoff, yoff, pixel);
@@ -505,15 +514,15 @@ gd_draw_empty_boxes (MDrawWindow win, int x, int y,
   y -= gstring->ascent - 1;
   height = gstring->ascent + gstring->descent - 2;
   if (! region)
-    for (; from < to; x += from++->width)
-      gdImageRectangle (img, x, y, x + from->width - 2, y + height - 1, color);
+    for (; from < to; x += from++->g.xadv)
+      gdImageRectangle (img, x, y, x + from->g.xadv - 2, y + height - 1, color);
   else
     {
       gdImagePtr cpy;
       MGlyph *g;
       int width, x1;
 
-      for (g = from, width = 0; g < to; width += g++->width);
+      for (g = from, width = 0; g < to; width += g++->g.xadv);
       cpy = get_scrach_image (img, width, height);
       MPLIST_DO (plist, region_list)
        {
@@ -521,8 +530,8 @@ gd_draw_empty_boxes (MDrawWindow win, int x, int y,
          gdImageCopy (cpy, img, rect->x - x, rect->y - y, rect->x, rect->y,
                       rect->x + rect->width, rect->y + rect->height);
        }
-      for (x1 = 0; from < to; x1 += from++->width)
-       gdImageRectangle (cpy, x1, 0, x1 + from->width - 2, height - 1, color);
+      for (x1 = 0; from < to; x1 += from++->g.xadv)
+       gdImageRectangle (cpy, x1, 0, x1 + from->g.xadv - 2, height - 1, color);
       MPLIST_DO (plist, region_list)
        {
          MDrawMetric *rect = MPLIST_VAL (plist);
@@ -596,7 +605,7 @@ gd_draw_box (MFrame *frame, MDrawWindow win, MGlyphString *gstring,
       gdImagePtr cpy;
 
       if (g->type == GLYPH_BOX)
-       width = g->width;
+       width = g->g.xadv;
       cpy = get_scrach_image (img, width, height);
       MPLIST_DO (plist, region_list)
        {
@@ -619,9 +628,9 @@ gd_draw_box (MFrame *frame, MDrawWindow win, MGlyphString *gstring,
       int x0, x1;
 
       if (g->left_padding)
-       x0 = x + box->outer_hmargin, x1 = x + g->width - 1;
+       x0 = x + box->outer_hmargin, x1 = x + g->g.xadv - 1;
       else
-       x0 = x, x1 = x + g->width - box->outer_hmargin - 1;
+       x0 = x, x1 = x + g->g.xadv - box->outer_hmargin - 1;
 
       /* Draw the top side.  */
       color = RESOLVE_COLOR (img, colors[COLOR_BOX_TOP]);
@@ -806,6 +815,8 @@ device_init ()
   gd_font_driver.has_char = mfont__ft_driver.has_char;
   gd_font_driver.encode_char = mfont__ft_driver.encode_char;
   gd_font_driver.list = mfont__ft_driver.list;
+  gd_font_driver.check_otf = mfont__ft_driver.check_otf;
+  gd_font_driver.drive_otf = mfont__ft_driver.drive_otf;
 
   return 0;
 }
index c0bd14a..2b31927 100644 (file)
@@ -237,12 +237,13 @@ static MDeviceLibraryInterface null_interface =
 void
 m17n_init_win (void)
 {
-  int mdebug_mask = MDEBUG_INIT;
+  int mdebug_flag = MDEBUG_INIT;
 
   merror_code = MERROR_NONE;
   if (m17n__gui_initialized++)
     return;
   m17n_init ();
+  m17n_init_flt ();
   if (merror_code != MERROR_NONE)
     {
       m17n__gui_initialized--;
@@ -297,7 +298,7 @@ m17n_init_win (void)
 void
 m17n_fini_win (void)
 {
-  int mdebug_mask = MDEBUG_FINI;
+  int mdebug_flag = MDEBUG_FINI;
   MPlist *plist;
 
   if (m17n__gui_initialized == 0
@@ -341,6 +342,7 @@ m17n_fini_win (void)
   MDEBUG_POP_TIME ();
   MDEBUG_PRINT_TIME ("FINI", (stderr, " to finalize the gui modules."));
   MDEBUG_POP_TIME ();
+  m17n_fini_flt ();
   m17n_fini ();
 }
 
index 81ba902..b3f3dd2 100644 (file)
 #ifndef _M17N_GUI_H_
 #define _M17N_GUI_H_
 
+#ifndef _M17N_FLT_H_
+#include <m17n-flt.h>
+#endif
+
 #ifndef _M17N_H_
 #include <m17n.h>
 #endif
index 39ea41c..0101192 100644 (file)
@@ -83,6 +83,7 @@ enum MErrorCode
     MERROR_FRAME,
     MERROR_FACE,
     MERROR_DRAW,
+    MERROR_FLT,
     MERROR_FONT,
     MERROR_FONTSET,
     MERROR_FONT_OTF,
index 952ad55..c3d18e8 100644 (file)
@@ -40,7 +40,7 @@
 void
 m17n_init (void)
 {
-  int mdebug_mask = MDEBUG_INIT;
+  int mdebug_flag = MDEBUG_INIT;
 
   merror_code = MERROR_NONE;
   if (m17n__shell_initialized++)
@@ -59,18 +59,12 @@ m17n_init (void)
   if (mcoding__init () < 0)
     goto err;
   MDEBUG_PRINT_TIME ("INIT", (stderr, " to initialize conv module."));
-  if (mdatabase__init () < 0)
-    goto err;
-  MDEBUG_PRINT_TIME ("INIT", (stderr, " to initialize database module."));
   if (mcharset__load_from_database () < 0)
     goto err;
   MDEBUG_PRINT_TIME ("INIT", (stderr, " to load charset definitions."));
   if (mcoding__load_from_database () < 0)
     goto err;
   MDEBUG_PRINT_TIME ("INIT", (stderr, " to load coding definitions."));
-  if (mchar__init () < 0)
-    goto err;
-  MDEBUG_PRINT_TIME ("INIT", (stderr, " to initialize character module."));
   if (mlang__init () < 0)
     goto err;
   MDEBUG_PRINT_TIME ("INIT", (stderr, " to initialize language module"));
@@ -90,7 +84,7 @@ m17n_init (void)
 void
 m17n_fini (void)
 {
-  int mdebug_mask = MDEBUG_FINI;
+  int mdebug_flag = MDEBUG_FINI;
 
   if (m17n__shell_initialized == 0
       || --m17n__shell_initialized > 0)
index da3338b..5e5d278 100644 (file)
@@ -52,51 +52,6 @@ extern void m17n_fini (void);
  */
 /*=*/
 
-/*** @ingroup m17nShell */
-/***en @defgroup m17nDatabase Database */
-/***ja @defgroup m17nDatabase ¥Ç¡¼¥¿¥Ù¡¼¥¹ */
-/*=*/
-
-/* Directory of an application specific databases.  */
-extern char *mdatabase_dir;
-/*=*/
-/***
-    @ingroup m17nDatabase  */ 
-/***en
-    @brief Type of database.
-
-    The type #MDatabase is for a database object.  Its internal
-    structure is concealed from an application program.  */
-/***ja 
-    @brief ¥Ç¡¼¥¿¥Ù¡¼¥¹¤Î·¿Àë¸À.
-
-    #MDatabase ·¿¤Ï¥Ç¡¼¥¿¥Ù¡¼¥¹¥ª¥Ö¥¸¥§¥¯¥ÈÍѤι½Â¤ÂΤǤ¢¤ë¡£
-    ÆâÉô¹½Â¤¤Ï¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é¥à¤«¤é¤Ï¸«¤¨¤Ê¤¤¡£
-    */
-
-typedef struct MDatabase MDatabase;
-
-/*=*/
-
-/* Look for a data.  */
-extern MDatabase *mdatabase_find (MSymbol tag1, MSymbol tag2,
-                                 MSymbol tag3, MSymbol tag4);
-
-extern MPlist *mdatabase_list (MSymbol tag0, MSymbol tag1,
-                              MSymbol tag2, MSymbol tag3);
-
-/* Load a data.  */
-void *mdatabase_load (MDatabase *mdb);
-
-/* Get tags of a data.  */
-extern MSymbol *mdatabase_tag (MDatabase *mdb);
-
-/* Define a data.  */
-extern MDatabase *mdatabase_define (MSymbol tag1, MSymbol tag2,
-                                   MSymbol tag3, MSymbol tag4,
-                                   void *(*loader) (MSymbol *, void *),
-                                   void *extra_info);
-
 /*=*/
 /* (S2) Charset staffs */
 /*=*/
@@ -142,8 +97,6 @@ extern MSymbol Msubset;
 extern MSymbol Msuperset;
 
 /* etc. */
-extern MSymbol Mcharset;
-
 extern MSymbol mchar_define_charset (const char *name, MPlist *plist);
 
 extern MSymbol mchar_resolve_charset (MSymbol symbol);
index 6c74c56..2e3cd22 100644 (file)
@@ -233,15 +233,9 @@ read_hexadesimal (MStream *st)
 static MPlist *
 read_mtext_element (MPlist *plist, MStream *st, int skip)
 {
-  union {
-    int chars[READ_MTEXT_BUF_SIZE];
-    unsigned char bytes[sizeof (int) * READ_MTEXT_BUF_SIZE];
-  } buffer;
-  unsigned char *bytes = buffer.bytes;
-  int nbytes = sizeof (int) * READ_MTEXT_BUF_SIZE;
-  int *chars = NULL;
-  int nchars = 0;
-  int c, i, j;
+  unsigned char buffer[READ_MTEXT_BUF_SIZE], *buf = buffer;
+  int nbytes = READ_MTEXT_BUF_SIZE;
+  int c, i;
 
   i = 0;
   while ((c = GETC (st)) != EOF && c != '"')
@@ -272,46 +266,25 @@ read_mtext_element (MPlist *plist, MStream *st, int skip)
 
       if (! skip)
        {
-         if (is_char && ! chars)
+         if (i + MAX_UTF8_CHAR_BYTES >= nbytes)
            {
-             chars = buffer.chars;
-             for (j = i - 1; j >= 0; j--)
-               chars[j] = bytes[j];
-             nchars = READ_MTEXT_BUF_SIZE;
-             if (bytes != buffer.bytes)
-               free (bytes);
-           }
-
-         if (chars)
-           {
-             if (i + 1 >= nchars)
+             if (buf == buffer)
                {
-                 nchars *= 2;
-                 if (chars == buffer.chars)
-                   {
-                     MTABLE_MALLOC (chars, nchars, MERROR_PLIST);
-                     memcpy (chars, buffer.chars, sizeof (int) * i);
-                   }
-                 else
-                   MTABLE_REALLOC (chars, nchars, MERROR_PLIST);
+                 nbytes *= 2;
+                 buf = malloc (nbytes);
+                 memcpy (buf, buffer, i);
                }
-             chars[i++] = c;
-           }
-         else
-           {
-             if (i + MAX_UTF8_CHAR_BYTES >= nbytes)
+             else
                {
-                 nbytes *= 2;
-                 if (bytes == buffer.bytes)
-                   {
-                     MTABLE_MALLOC (bytes, nbytes, MERROR_PLIST);
-                     memcpy (bytes, buffer.bytes, i);
-                   }
-                 else
-                   MTABLE_REALLOC (bytes, nbytes, MERROR_PLIST);
+                 nbytes += READ_MTEXT_BUF_SIZE;
+                 buf = realloc (buf, nbytes);
                }
-             bytes[i++] = c;
            }
+
+         if (is_char)
+           i += CHAR_STRING_UTF8 (c, buf);
+         else
+           buf[i++] = c;
        }
     }
 
@@ -319,17 +292,12 @@ read_mtext_element (MPlist *plist, MStream *st, int skip)
     {
       MText *mt;
 
-      if (chars)
-       {
-         mt = mtext__from_data (chars, i, MTEXT_FORMAT_UTF_32, 1);
-         if (chars != buffer.chars)
-           free (chars);
-       }         
+      if (buf == buffer)
+       mt = mtext__from_data (buf, i, MTEXT_FORMAT_UTF_8, 1);
       else
        {
-         mt = mtext__from_data (bytes, i, MTEXT_FORMAT_UTF_8, 1);
-         if (bytes != buffer.bytes)
-           free (bytes);
+         mt = mtext__from_data (buf, i, MTEXT_FORMAT_UTF_8, 0);
+         free (buf);
        }
       MPLIST_SET_ADVANCE (plist, Mtext, mt);
     }
index c3bf5c8..0884332 100644 (file)
@@ -179,7 +179,7 @@ msymbol__free_table ()
        }
       symbol_table[i] = NULL;
     }
-  if (mdebug__flag & MDEBUG_FINI)
+  if (mdebug__flags[MDEBUG_FINI])
     fprintf (stderr, "%16s %7d %7d %7d\n", "Symbol",
             num_symbols, freed_symbols, num_symbols - freed_symbols);
   num_symbols = 0;