From d68a1ef5c7dc1dd24430bfb11dac9a9035c11428 Mon Sep 17 00:00:00 2001 From: handa Date: Tue, 13 Nov 2007 02:29:20 +0000 Subject: [PATCH] merge FLT --- ChangeLog | 13 + Makefile.am | 4 +- configure.ac | 1 + example/.gdb.util | 7 +- example/ChangeLog | 12 + example/Makefile.am | 2 +- example/mdump.c | 2 +- m17n-flt.pc.in | 12 + src/ChangeLog | 480 +++++++++- src/Makefile.am | 17 +- src/character.c | 13 +- src/charset.c | 103 +- src/chartab.c | 34 +- src/coding.c | 2 +- src/database.c | 144 +-- src/database.h | 4 + src/draw.c | 949 ++++++++----------- src/face.c | 70 +- src/font-flt.c | 220 +++-- src/font-ft.c | 770 ++++++++------- src/font.c | 84 +- src/font.h | 19 + src/fontset.c | 29 +- src/input.c | 10 +- src/internal-flt.h | 53 ++ src/internal-gui.h | 35 +- src/internal.h | 65 +- src/m17n-X.c | 283 +++--- src/m17n-core.c | 56 +- src/m17n-core.h | 50 + src/m17n-flt.c | 2630 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/m17n-flt.h | 261 +++++ src/m17n-gd.c | 49 +- src/m17n-gui.c | 6 +- src/m17n-gui.h | 4 + src/m17n-misc.h | 1 + src/m17n.c | 10 +- src/m17n.h | 47 - src/plist.c | 72 +- src/symbol.c | 2 +- 40 files changed, 5147 insertions(+), 1478 deletions(-) create mode 100644 m17n-flt.pc.in create mode 100644 src/internal-flt.h create mode 100644 src/m17n-flt.c create mode 100644 src/m17n-flt.h diff --git a/ChangeLog b/ChangeLog index d65909f..c289940 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2007-10-12 Kenichi Handa + + * m17n-flt.pc.in: Don't require m17n-shell. + +2007-08-15 Kenichi Handa + + * 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 * Version 1.4.0 released. diff --git a/Makefile.am b/Makefile.am index 88a5aa0..10b0ea6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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 diff --git a/configure.ac b/configure.ac index 2f9dd87..9c84512 100644 --- a/configure.ac +++ b/configure.ac @@ -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 ]) diff --git a/example/.gdb.util b/example/.gdb.util index 9fafb7c..efc3b4b 100644 --- a/example/.gdb.util +++ b/example/.gdb.util @@ -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 diff --git a/example/ChangeLog b/example/ChangeLog index 9c415a0..cafa4f9 100644 --- a/example/ChangeLog +++ b/example/ChangeLog @@ -1,3 +1,15 @@ +2007-10-29 Kenichi Handa + + * 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 + + * mdump.c (main): Use "generic" fontset by default. + 2007-07-13 Kenichi Handa * Version 1.4.0 released. diff --git a/example/Makefile.am b/example/Makefile.am index d81069e..baceac3 100644 --- a/example/Makefile.am +++ b/example/Makefile.am @@ -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 diff --git a/example/mdump.c b/example/mdump.c index f05075b..a53cd7e 100644 --- a/example/mdump.c +++ b/example/mdump.c @@ -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 index 0000000..e6ceeb8 --- /dev/null +++ b/m17n-flt.pc.in @@ -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} diff --git a/src/ChangeLog b/src/ChangeLog index 19dd341..f6fdf8e 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,6 +1,482 @@ -2007-08-14 Kenichi Handa +2007-11-12 Kenichi Handa + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * face.c (mface__realize): Try Freetype based font at first. + + * font.c: Include + +2007-09-16 Kenichi Handa + + * 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 + + * 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 + + * 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 + + * draw.c (compose_glyph_string): Improve script detection. + +2007-09-06 Kenichi Handa + + * 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 + + * 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 + + * 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 + + * m17n-flt.c (run_otf): Remove #ifdef HAVE_OTF and #endi. + (run_stages): Print separator in encoded string as "|". + +2007-08-23 Kenichi Handa + + * 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 + + * font-ft.c (ft_check_capability): Check cap->script_tag at first. + +2007-08-20 Kenichi Handa + + * font-flt.c (mfont__flt_run): Get glyph metrics before printing + debug information. + +2007-08-17 Kenichi Handa + + * 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 + + * 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 + + * 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 diff --git a/src/Makefile.am b/src/Makefile.am index 43407f8..d626b86 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 diff --git a/src/character.c b/src/character.c index 96ce01e..abc3c39 100644 --- a/src/character.c +++ b/src/character.c @@ -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; diff --git a/src/charset.c b/src/charset.c index bf3cfc2..8675a31 100644 --- a/src/charset.c +++ b/src/charset.c @@ -91,10 +91,11 @@ #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; +} + /* 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 - "charset". */ - -/***ja - @brief ¥·¥ó¥Ü¥ë @c Mcharset. - - ¥Ç¥³¡¼¥É¤µ¤ì¤¿ M-text ¤Ï¡¢¥­¡¼¤¬ @c Mcharset - ¤Ç¤¢¤ë¤è¤¦¤Ê¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤ò»ý¤Ä¡£ - ¥·¥ó¥Ü¥ë @c Mcharset ¤Ï "charset" ¤È¤¤¤¦Ì¾Á°¤ò»ý¤Ä¡£ */ -MSymbol Mcharset; /*=*/ /***en diff --git a/src/chartab.c b/src/chartab.c index 04b216f..3a03e80 100644 --- a/src/chartab.c +++ b/src/chartab.c @@ -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 diff --git a/src/coding.c b/src/coding.c index 2e9a46e..5b64635 100644 --- a/src/coding.c +++ b/src/coding.c @@ -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; diff --git a/src/database.c b/src/database.c index 8d734b8..e0f4451 100644 --- a/src/database.c +++ b/src/database.c @@ -136,14 +136,12 @@ #include #include -#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 */ /* 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 + "charset". */ + +/***ja + @brief ¥·¥ó¥Ü¥ë @c Mcharset. + + ¥Ç¥³¡¼¥É¤µ¤ì¤¿ M-text ¤Ï¡¢¥­¡¼¤¬ @c Mcharset + ¤Ç¤¢¤ë¤è¤¦¤Ê¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤ò»ý¤Ä¡£ + ¥·¥ó¥Ü¥ë @c Mcharset ¤Ï "charset" ¤È¤¤¤¦Ì¾Á°¤ò»ý¤Ä¡£ */ + +MSymbol Mcharset; +/*=*/ +/*** @} */ +/*=*/ + /*** @addtogroup m17nDatabase */ /*** @{ */ diff --git a/src/database.h b/src/database.h index 263af52..bf9e774 100644 --- a/src/database.h +++ b/src/database.h @@ -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_ */ diff --git a/src/draw.c b/src/draw.c index 6155d4a..976b58b 100644 --- a/src/draw.c +++ b/src/draw.c @@ -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 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, ")"); } @@ -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) { diff --git a/src/face.c b/src/face.c index 5185d0f..983228c 100644 --- a/src/face.c +++ b/src/face.c @@ -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) diff --git a/src/font-flt.c b/src/font-flt.c index 4a11c0b..882463b 100644 --- a/src/font-flt.c +++ b/src/font-flt.c @@ -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; } diff --git a/src/font-ft.c b/src/font-ft.c index 08f352d..1c59534 100644 --- a/src/font-ft.c +++ b/src/font-ft.c @@ -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 @@ -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; +} /* 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 */ - -#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 */ diff --git a/src/font.c b/src/font.c index 8f03529..b01dcc0 100644 --- a/src/font.c +++ b/src/font.c @@ -328,6 +328,7 @@ #include #include #include +#include #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 */ diff --git a/src/font.h b/src/font.h index 3932dfc..437800d 100644 --- a/src/font.h +++ b/src/font.h @@ -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); diff --git a/src/fontset.c b/src/fontset.c index 917cb44..7a431f3 100644 --- a/src/fontset.c +++ b/src/fontset.c @@ -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; } diff --git a/src/input.c b/src/input.c index fb2f224..be065bd 100644 --- a/src/input.c +++ b/src/input.c @@ -153,7 +153,7 @@ #include #endif -#include "m17n-gui.h" +#include "m17n.h" #include "m17n-misc.h" #include "internal.h" #include "mtext.h" @@ -163,7 +163,7 @@ #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 index 0000000..e47dbb1 --- /dev/null +++ b/src/internal-flt.h @@ -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 */ diff --git a/src/internal-gui.h b/src/internal-gui.h index 398e5f3..07a6d70 100644 --- a/src/internal-gui.h +++ b/src/internal-gui.h @@ -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 diff --git a/src/internal.h b/src/internal.h index 53ba6a5..dd59fa6 100644 --- a/src/internal.h +++ b/src/internal.h @@ -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 -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 (); diff --git a/src/m17n-X.c b/src/m17n-X.c index 80cbeb3..0af354d 100644 --- a/src/m17n-X.c +++ b/src/m17n-X.c @@ -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 */ @@ -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; diff --git a/src/m17n-core.c b/src/m17n-core.c index 6257ad9..2094258 100644 --- a/src/m17n-core.c +++ b/src/m17n-core.c @@ -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) diff --git a/src/m17n-core.h b/src/m17n-core.h index 3ee6028..2d8a1de 100644 --- a/src/m17n-core.h +++ b/src/m17n-core.h @@ -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 index 0000000..b72dfac --- /dev/null +++ b/src/m17n-flt.c @@ -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 +#include +#include +#include +#include +#include + +#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: +;; +LANGSYS ::= OTF-TAG +;; OTF's Language System name (four letters) listed at: +;; + +GSUB-FEATURES ::= [FEATURE[,FEATURE]*] | ' ' +GPOS-FEATURES ::= [FEATURE[,FEATURE]*] | ' ' +FEATURE ::= OTF-TAG +;; OTF's Feature name (four letters) listed at: +;; + +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 and 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) + + +/* Internal API */ + +int m17n__flt_initialized; + + +/* 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; +} + + +/* 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 index 0000000..526978c --- /dev/null +++ b/src/m17n-flt.h @@ -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 +#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 is already encoded into a + glyph ID of a font. */ + unsigned encoded : 1; + /***en Flag to tell if the metrics of the glyph (members thru + ) 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 and 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 member + of a glyph is zero, the 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 member + of a glyph is zero, the function must set members , , + , , , and 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: +*/ diff --git a/src/m17n-gd.c b/src/m17n-gd.c index 600b049..fedf1c6 100644 --- a/src/m17n-gd.c +++ b/src/m17n-gd.c @@ -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; } diff --git a/src/m17n-gui.c b/src/m17n-gui.c index c0bd14a..2b31927 100644 --- a/src/m17n-gui.c +++ b/src/m17n-gui.c @@ -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 (); } diff --git a/src/m17n-gui.h b/src/m17n-gui.h index 81ba902..b3f3dd2 100644 --- a/src/m17n-gui.h +++ b/src/m17n-gui.h @@ -23,6 +23,10 @@ #ifndef _M17N_GUI_H_ #define _M17N_GUI_H_ +#ifndef _M17N_FLT_H_ +#include +#endif + #ifndef _M17N_H_ #include #endif diff --git a/src/m17n-misc.h b/src/m17n-misc.h index 39ea41c..0101192 100644 --- a/src/m17n-misc.h +++ b/src/m17n-misc.h @@ -83,6 +83,7 @@ enum MErrorCode MERROR_FRAME, MERROR_FACE, MERROR_DRAW, + MERROR_FLT, MERROR_FONT, MERROR_FONTSET, MERROR_FONT_OTF, diff --git a/src/m17n.c b/src/m17n.c index 952ad55..c3d18e8 100644 --- a/src/m17n.c +++ b/src/m17n.c @@ -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) diff --git a/src/m17n.h b/src/m17n.h index da3338b..5e5d278 100644 --- a/src/m17n.h +++ b/src/m17n.h @@ -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); diff --git a/src/plist.c b/src/plist.c index 6c74c56..2e3cd22 100644 --- a/src/plist.c +++ b/src/plist.c @@ -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); } diff --git a/src/symbol.c b/src/symbol.c index c3bf5c8..0884332 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -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; -- 1.7.10.4