1 /* m17n-flt.c -- Font Layout Table sub-module.
2 Copyright (C) 2003, 2004, 2007
3 National Institute of Advanced Industrial Science and Technology (AIST)
4 Registration Number H15PRO112
6 This file is part of the m17n library.
8 The m17n library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Lesser General Public License
10 as published by the Free Software Foundation; either version 2.1 of
11 the License, or (at your option) any later version.
13 The m17n library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public
19 License along with the m17n library; if not, write to the Free
20 Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
25 @brief FLT support for a window system.
27 This section defines the m17n FLT API concerning character
28 layouting facility using FLT (Font Layout Table). The format of
29 FLT is described in @ref mdbFLT. */
33 @brief ¥¦¥£¥ó¥É¥¦¥·¥¹¥Æ¥à¤Î¤¿¤á¤Î FLT ¥µ¥Ý¡¼¥È.
35 ¤³¤Î¥»¥¯¥·¥ç¥ó¤Ç¤Ï¡¢FLT (Font Layout Table)
36 ¤òÍѤ¤¤¿Ê¸»ú¥ì¥¤¥¢¥¦¥Èµ¡Ç½¤Ë´Ø¤¹¤ë m17n FLT API ¤òÄêµÁ¤¹¤ë¡£
37 FLT ¤Î·Á¼°¤Ï @ref mdbFLT ¤Ëµ½Ò¤µ¤ì¤Æ¤¤¤ë¡£ */
41 #if !defined (FOR_DOXYGEN) || defined (DOXYGEN_INTERNAL_MODULE)
42 /*** @addtogroup m17nInternal
51 #include <sys/types.h>
54 #include "m17n-core.h"
56 #include "m17n-misc.h"
62 #include "internal-flt.h"
66 /* Font Layout Table (FLT)
68 Predefined terms: SYMBOL, INTEGER, STRING
70 FLT ::= '(' STAGE + ')'
72 STAGE ::= CATEGORY-TABLE ? FONT-LAYOUT-RULE
74 ;; Each STAGE consumes a source (code sequence) and produces another
75 ;; code sequence that is given to the next STAGE as a source. The
76 ;; source given to the first stage is a sequence of character codes
77 ;; that are assigned category codes by CATEGORY-TABLE. The output of
78 ;; the last stage is a glyph code sequence given to the renderer.
81 '(' 'category' CATEGORY-SPEC + ')'
83 '(' CODE [ CODE ] CATEGORY ')'
86 ;; ASCII character codes of alphabet ('A' .. 'Z' 'a' .. 'z').
89 ;; (0x0900 0x097F ?E) ; All Devanagari characters
90 ;; (0x093C ?N)) ; DEVANAGARI-LETTER NUKTA
91 ;; Assign the category 'E' to all Devanagari characters but 0x093C,
92 ;; assign the category 'N' to 0x093C.
95 '(' 'generator' RULE MACRO-DEF * ')'
97 RULE ::= COMMAND | REGEXP-RULE | MATCH-RULE | MAP-RULE
98 | COND-STRUCT | MACRO-NAME
101 DIRECT-CODE | COMBINING | PREDEFIND-COMMAND | OTF-COMMAND
103 DIRECT-CODE ::= INTEGER
104 ;; Always succeed. Produce the code. Consume no source.
106 PREDEFIND-COMMAND ::=
107 '=' | '*' | '<' | '>' | '|'
109 ;; '=': Succeed when the current run contains at least one code.
110 ;; Consume the first code in the current run, and produce it as is.
112 ;; '*': If the the previous command succeeded, repeat it until it
115 ;; '<': Produce a special code that indicates the start of grapheme
116 ;; cluster. Succeed always, consume nothing.
118 ;; '>': Produce a special code that indicates the end of grapheme
119 ;; cluster. Succeed always, consume nothing.
121 ;; '|': Produce a special code whose category is ' '. Succeed always,
125 'otf:''SCRIPT'[':'['LANGSYS'][':'[GSUB-FEATURES][':'GPOS-FEATURES]]]
126 ;; Run the Open Type Layout Table on the current run. Succeed always,
130 ;; OTF's ScriptTag name (four letters) listed at:
131 ;; <http://www.microsoft.om/typograph/otspec/scripttags.htm>
133 ;; OTF's Language System name (four letters) listed at:
134 ;; <http://www.microsoft.om/typograph/otspec/languagetags.htm>
136 GSUB-FEATURES ::= [FEATURE[,FEATURE]*] | ' '
137 GPOS-FEATURES ::= [FEATURE[,FEATURE]*] | ' '
139 ;; OTF's Feature name (four letters) listed at:
140 ;; <http://www.microsoft.om/typograph/otspec/???.htm>
142 OTF-TAG ::= PRINTABLE-CHAR PRINTABLE-CHAR PRINTABLE-CHAR PRINTABLE-CHAR
146 ;; Run all features in the default langsys of 'deva' script.
147 ;; 'otf:deva::nukt:haln'
148 ;; Run all GSUB features, run 'nukt' and 'haln' GPOS features.
150 ;; Run all GSUB features, run no GPOS features.
153 '(' REGEXP RULE * ')'
155 ;; Succeed if REGXP matches the head of source. Run RULEs while
156 ;; limiting the source to the matching part. Consume that part.
159 ;; Must be composed only from ASCII characters. 'A' - 'Z', 'a' - 'z'
160 ;; correspond to CATEGORY.
167 '(' MATCH-IDX RULE * ')'
169 ;; Succeed if the previous REGEXP-RULE found a matching part for
170 ;; MATCH-IDX. Run RULEs while limiting the source to the matching
171 ;; part. If MATCH-IDX is zero, consume the whole part, else consume
174 MATCH-IDX ::= INTEGER
181 '(' ( SOURCE-SEQ | SOURCE-RANGE ) RULE * ')'
183 ;; Succeed if the source matches SOURCE-SEQ or SOURCE-RANGE. Run
184 ;; RULEs while limiting the source to the matching part. Consume that
190 '(' 'range' CODE CODE ')'
192 ;; ((0x0915 0x094D) 0x43)
193 ;; If the source code sequence is 0x0915 0x094D, produce 0x43.
194 ;; ((range 0x0F40 0x0F6A) 0x2221)
195 ;; If the first source code CODE is in the range 0x0F40..0x0F6A,
196 ;; produce (0x2221 + (CODE - 0x0F40)).
199 '(' 'cond' RULE + ')'
201 ;; Try each rule in sequence until one succeeds. Succeed if one
202 ;; succeeds. Consume nothing.
206 ;; ((0x0915 0x094D) 0x43)
207 ;; ((range 0x0F40 0x0F6A) 0x2221)
210 COMBINING ::= 'V''H''O''V''H'
211 V ::= ( 't' | 'c' | 'b' | 'B' )
212 H ::= ( 'l' | 'c' | 'r' )
213 O ::= ( '.' | XOFF | YOFF | XOFF YOFF )
214 XOFF ::= '<'INTEGER | '>'INTEGER
215 YOFF ::= '+'INTEGER | '-'INTEGER
216 ;; INTEGER must be integer 0..127
218 ;; VH pair indicates 12 reference points of a glyph as below:
220 ;; 0----1----2 <---- ascent 0:tl (top-left)
221 ;; | | 1:tc (top-center)
222 ;; | | 2:tr (top-right)
223 ;; | | 3:Bl (base-left)
224 ;; 9 10 11 <---- center 4:Bc (base-center)
225 ;; | | 5:Br (base-right)
226 ;; --3----4----5-- <-- baseline 6:bl (bottom-left)
227 ;; | | 7:bc (bottom-center)
228 ;; 6----7----8 <---- descent 8:br (bottom-right)
229 ;; 9:cl (center-left)
230 ;; | | | 10:cc (center-center)
231 ;; left center right 11:cr (center-right)
235 ;; Align top-left point of the previous glyph and bottom-center
236 ;; point of the current glyph.
238 ;; Align 20% left and 10% below of base-left point of the previous
239 ;; glyph and base-right point of the current glyph.
242 '(' MACRO-NAME RULE + ')'
243 MACRO-NAME ::= SYMBOL
247 static int mdebug_flag = MDEBUG_FLT;
249 MSymbol Mfont, Mlayouter, Mcombining;
251 static MSymbol Mgenerator, Mend;
253 static MPlist *flt_list;
254 static int flt_min_coverage, flt_max_coverage;
258 CombiningCodeMask = 0xFFFFFFF,
259 LeftPaddingMask = 1 << 28,
260 RightPaddingMask = 1 << 29
263 #define SET_GLYPH_INFO(g, mask, ctx, info) \
264 ((g)->internal = (((g)->internal & ~(mask)) | (info)), \
265 (ctx)->check_mask |= (mask))
267 #define GET_COMBINING_CODE(g) ((g)->internal & CombiningCodeMask)
268 #define SET_COMBINING_CODE(g, ctx, code) \
269 SET_GLYPH_INFO (g, CombiningCodeMask, ctx, code)
270 #define GET_LEFT_PADDING(g) ((g)->internal & LeftPaddingMask)
271 #define SET_LEFT_PADDING(g, ctx, flag) \
272 SET_GLYPH_INFO (g, LeftPaddingMask, ctx, flag)
273 #define GET_RIGHT_PADDING(g) ((g)->internal & RightPaddingMask)
274 #define SET_RIGHT_PADDING(g, ctx, flag) \
275 SET_GLYPH_INFO (g, RightPaddingMask, ctx, flag)
276 #define GET_ENCODED(g) ((g)->encoded)
277 #define SET_ENCODED(g, flag) ((g)->encoded = (flag))
278 #define GET_MEASURED(g) ((g)->measured)
279 #define SET_MEASURED(g, flag) ((g)->measured = (flag))
281 #define GINIT(gstring, n) \
283 if (! (gstring)->glyph_size) \
284 (gstring)->glyph_size = sizeof (MFLTGlyph); \
285 (gstring)->glyphs = alloca ((gstring)->glyph_size * (n)); \
286 (gstring)->allocated = (n); \
287 (gstring)->used = 0; \
290 #define GALLOCA (gstring) \
291 ((MFLTGlyph *) alloca ((gstring)->glyph_size))
293 #define GREF(gstring, idx) \
294 ((MFLTGlyph *) ((char *) ((gstring)->glyphs) + (gstring)->glyph_size * (idx)))
296 #define PREV(gstring, g) \
297 ((MFLTGlyph *) ((char *) (g) - (gstring)->glyph_size))
299 #define NEXT(gstring, g) \
300 ((MFLTGlyph *) ((char *) (g) + (gstring)->glyph_size))
302 #define GCPY(src, src_idx, n, tgt, tgt_idx) \
304 memcpy ((char *) ((tgt)->glyphs) + (tgt)->glyph_size * (tgt_idx), \
305 (char *) ((src)->glyphs) + (src)->glyph_size * (src_idx), \
306 (src)->glyph_size * (n)); \
309 #define GDUP(ctx, idx) \
311 MFLTGlyphString *src = (ctx)->in; \
312 MFLTGlyphString *tgt = (ctx)->out; \
313 if (tgt->allocated <= tgt->used) \
315 GCPY (src, (idx), 1, tgt, tgt->used); \
320 GREPLACE (MFLTGlyphString *src, int src_from, int src_to,
321 MFLTGlyphString *tgt, int tgt_from, int tgt_to)
323 int src_len = src_to - src_from;
324 int tgt_len = tgt_to - tgt_from;
325 int inc = src_len - tgt_len;
327 if (tgt->allocated < tgt->used + inc)
329 if (inc != 0 && tgt_to < tgt->used)
330 memmove ((char *) tgt->glyphs + tgt->glyph_size * (tgt_from + src_len),
331 (char *) tgt->glyphs + tgt->glyph_size * tgt_to,
332 tgt->glyph_size * (tgt->used - tgt_to));
334 memcpy ((char *) tgt->glyphs + tgt->glyph_size * tgt_from,
335 (char *) src->glyphs + src->glyph_size * src_from,
336 src->glyph_size * src_len);
345 -0x0F .. -2 : builtin commands
346 -0x100000F .. -0x10 : combining code
347 ... -0x1000010: index to FontLayoutStage->cmds
350 #define INVALID_CMD_ID -1
351 #define CMD_ID_OFFSET_BUILTIN -3
352 #define CMD_ID_OFFSET_COMBINING -0x10
353 #define CMD_ID_OFFSET_INDEX -0x1000010
355 /* Builtin commands. */
356 #define CMD_ID_COPY -3 /* '=' */
357 #define CMD_ID_REPEAT -4 /* '*' */
358 #define CMD_ID_CLUSTER_BEGIN -5 /* '<' */
359 #define CMD_ID_CLUSTER_END -6 /* '>' */
360 #define CMD_ID_SEPARATOR -7 /* '|' */
361 #define CMD_ID_LEFT_PADDING -8 /* '[' */
362 #define CMD_ID_RIGHT_PADDING -9 /* ']' */
364 #define CMD_ID_TO_COMBINING_CODE(id) (CMD_ID_OFFSET_COMBINING - (id))
365 #define COMBINING_CODE_TO_CMD_ID(code) (CMD_ID_OFFSET_COMBINING - (code))
367 #define CMD_ID_TO_INDEX(id) (CMD_ID_OFFSET_INDEX - (id))
368 #define INDEX_TO_CMD_ID(idx) (CMD_ID_OFFSET_INDEX - (idx))
370 static MSymbol Mcond, Mrange, Mfont_facility;
372 #define GLYPH_CODE_P(code) \
373 ((code) >= GLYPH_CODE_MIN && (code) <= GLYPH_CODE_MAX)
375 #define GLYPH_CODE_INDEX(code) ((code) - GLYPH_CODE_MIN)
377 #define UPDATE_CLUSTER_RANGE(ctx, g) \
379 if ((ctx)->cluster_begin_idx >= 0) \
381 if (ctx->cluster_begin_pos > (g)->from) \
382 ctx->cluster_begin_pos = (g)->from; \
383 if (ctx->cluster_end_pos < (g)->to) \
384 ctx->cluster_end_pos = (g)->to; \
388 enum FontLayoutCmdRuleSrcType
400 enum FontLayoutCmdRuleSrcType src_type;
415 MFLTOtfSpec otf_spec;
424 /* Beginning and end indices of series of SEQ commands. */
425 int seq_beg, seq_end;
426 /* Range of the first character appears in the above series. */
427 int seq_from, seq_to;
433 enum FontLayoutCmdType
435 FontLayoutCmdTypeRule,
436 FontLayoutCmdTypeCond,
437 FontLayoutCmdTypeOTF,
443 enum FontLayoutCmdType type;
445 FontLayoutCmdRule rule;
446 FontLayoutCmdCond cond;
453 MCharTable *category;
465 MCharTable *coverage;
469 /* Font layout table loader */
471 static int parse_otf_command (MSymbol symbol, MFLTOtfSpec *spec);
473 /* Load a category table from PLIST. PLIST has this form:
474 PLIST ::= ( FROM-CODE TO-CODE ? CATEGORY-CHAR ) *
478 load_category_table (MPlist *plist)
482 table = mchartable (Minteger, (void *) 0);
484 MPLIST_DO (plist, plist)
487 int from, to, category_code;
489 if (! MPLIST_PLIST (plist))
490 MERROR (MERROR_FONT, NULL);
491 elt = MPLIST_PLIST (plist);
492 if (! MPLIST_INTEGER_P (elt))
493 MERROR (MERROR_FONT, NULL);
494 from = MPLIST_INTEGER (elt);
495 elt = MPLIST_NEXT (elt);
496 if (! MPLIST_INTEGER_P (elt))
497 MERROR (MERROR_FONT, NULL);
498 to = MPLIST_INTEGER (elt);
499 elt = MPLIST_NEXT (elt);
500 if (MPLIST_TAIL_P (elt))
507 if (! MPLIST_INTEGER_P (elt))
508 MERROR (MERROR_FONT, NULL);
509 category_code = MPLIST_INTEGER (elt);
511 if (! isalnum (category_code))
512 MERROR (MERROR_FONT, NULL);
515 mchartable_set (table, from, (void *) category_code);
517 mchartable_set_range (table, from, to, (void *) category_code);
524 gen_otf_tag (char *p)
526 unsigned int tag = 0;
529 for (i = 0; i < 4 && *p; i++, p++)
530 tag = (tag << 8) | *p;
532 tag = (tag << 8) | 0x20;
537 otf_count_features (char *p, char *end, char stopper, int *count)
542 if (*p != stopper && *p != '\0')
549 if (*p == stopper || *p == '\0')
563 if (*p == stopper || *p == '\0')
575 otf_store_features (char *p, char *end, unsigned *buf)
580 for (i = 0; p < end;)
583 buf[i++] = 0xFFFFFFFF, p += 2, negative = 1;
587 buf[i++] = 0xFFFFFFFF;
588 buf[i++] = gen_otf_tag (p + 1), p += 6;
591 buf[i++] = gen_otf_tag (p), p += 5;
597 parse_otf_command (MSymbol symbol, MFLTOtfSpec *spec)
599 char *str = MSYMBOL_NAME (symbol);
600 char *end = str + MSYMBOL_NAMELEN (symbol);
601 unsigned int script, langsys;
603 int gsub_count = 0, gpos_count = 0;
606 memset (spec, 0, sizeof (MFLTOtfSpec));
609 str += 5; /* skip the heading ":otf=" */
610 script = gen_otf_tag (str);
614 langsys = gen_otf_tag (str);
621 /* Apply all GSUB features. */
626 str = otf_count_features (p, end, '+', &gsub_count);
628 MERROR (MERROR_FLT, -1);
632 /* Apply all GPOS features. */
637 str = otf_count_features (p, end, '\0', &gpos_count);
639 MERROR (MERROR_FLT, -1);
642 spec->script = script;
643 spec->langsys = langsys;
646 spec->features[0] = malloc (sizeof (int) * (gsub_count + 1));
647 if (! spec->features[0])
650 otf_store_features (gsub + 1, gpos, spec->features[0]);
652 spec->features[0][0] = 0xFFFFFFFF, spec->features[0][1] = 0;
656 spec->features[1] = malloc (sizeof (int) * (gpos_count + 1));
657 if (! spec->features[1])
659 if (spec->features[0])
660 free (spec->features[0]);
664 otf_store_features (gpos + 1, str, spec->features[1]);
666 spec->features[1][0] = 0xFFFFFFFF, spec->features[1][1] = 0;
672 /* Parse OTF command name NAME and store the result in CMD.
674 :SCRIPT[/[LANGSYS][=[GSUB-FEATURES][+GPOS-FEATURES]]]
675 where GSUB-FEATURES and GPOS-FEATURES have this form:
676 [FEATURE[,FEATURE]*] | ' ' */
679 load_otf_command (FontLayoutCmd *cmd, MSymbol sym)
681 char *name = MSYMBOL_NAME (sym);
686 /* This is old format of "otf:...". Change it to ":otf=...". */
687 char *str = alloca (MSYMBOL_NAMELEN (sym) + 2);
689 sprintf (str, ":otf=");
690 strcat (str, name + 4);
694 result = parse_otf_command (sym, &cmd->body.otf);
697 cmd->type = FontLayoutCmdTypeOTF;
702 /* Read a decimal number from STR preceded by one of "+-><". '+' and
703 '>' means a plus sign, '-' and '<' means a minus sign. If the
704 number is greater than 127, limit it to 127. */
707 read_decimal_number (char **str)
710 int sign = (*p == '-' || *p == '<') ? -1 : 1;
714 while (*p >= '0' && *p <= '9')
715 n = n * 10 + *p++ - '0';
719 return (n < 127 ? n * sign : 127 * sign);
723 /* Read a horizontal and vertical combining positions from STR, and
724 store them in the place pointed by X and Y. The horizontal
725 position left, center, and right are represented by 0, 1, and 2
726 respectively. The vertical position top, center, bottom, and base
727 are represented by 0, 1, 2, and 3 respectively. If successfully
728 read, return 0, else return -1. */
731 read_combining_position (char *str, int *x, int *y)
736 /* Vertical position comes first. */
737 for (i = 0; i < 4; i++)
746 /* Then comse horizontal position. */
747 for (i = 0; i < 3; i++)
757 /* Return a combining code corresponding to SYM. */
760 get_combining_command (MSymbol sym)
762 char *str = msymbol_name (sym);
763 int base_x, base_y, add_x, add_y, off_x, off_y;
766 if (read_combining_position (str, &base_x, &base_y) < 0)
777 if (c == '+' || c == '-')
779 off_y = read_decimal_number (&str) + 128;
784 if (c == '<' || c == '>')
785 off_x = read_decimal_number (&str) + 128;
789 if (read_combining_position (str, &add_x, &add_y) < 0)
792 c = MAKE_COMBINING_CODE (base_y, base_x, add_y, add_x, off_y, off_x);
793 return (COMBINING_CODE_TO_CMD_ID (c));
797 /* Load a command from PLIST into STAGE, and return that
798 identification number. If ID is not INVALID_CMD_ID, that means we
799 are loading a top level command or a macro. In that case, use ID
800 as the identification number of the command. Otherwise, generate a
801 new id number for the command. MACROS is a list of raw macros. */
804 load_command (FontLayoutStage *stage, MPlist *plist,
805 MPlist *macros, int id)
810 if (MPLIST_INTEGER_P (plist))
812 int code = MPLIST_INTEGER (plist);
815 MERROR (MERROR_DRAW, INVALID_CMD_ID);
818 else if (MPLIST_PLIST_P (plist))
820 /* PLIST ::= ( cond ... ) | ( STRING ... ) | ( INTEGER ... )
821 | ( ( INTEGER INTEGER ) ... )
822 | ( ( range INTEGER INTEGER ) ... )
823 | ( ( font-facilty [ INTEGER ] ) ... )
824 | ( ( font-facilty OTF-SPEC ) ... ) */
825 MPlist *elt = MPLIST_PLIST (plist);
826 int len = MPLIST_LENGTH (elt) - 1;
829 if (id == INVALID_CMD_ID)
832 id = INDEX_TO_CMD_ID (stage->used);
833 MLIST_APPEND1 (stage, cmds, dummy, MERROR_DRAW);
835 cmd = stage->cmds + CMD_ID_TO_INDEX (id);
837 if (MPLIST_SYMBOL_P (elt))
839 FontLayoutCmdCond *cond;
841 if (MPLIST_SYMBOL (elt) != Mcond)
842 MERROR (MERROR_DRAW, INVALID_CMD_ID);
843 elt = MPLIST_NEXT (elt);
844 cmd->type = FontLayoutCmdTypeCond;
845 cond = &cmd->body.cond;
846 cond->seq_beg = cond->seq_end = -1;
847 cond->seq_from = cond->seq_to = 0;
849 MTABLE_CALLOC (cond->cmd_ids, len, MERROR_DRAW);
850 for (i = 0; i < len; i++, elt = MPLIST_NEXT (elt))
852 int this_id = load_command (stage, elt, macros, INVALID_CMD_ID);
854 if (this_id == INVALID_CMD_ID || this_id == -2)
855 MERROR (MERROR_DRAW, this_id);
856 /* The above load_command may relocate stage->cmds. */
857 cmd = stage->cmds + CMD_ID_TO_INDEX (id);
858 cond = &cmd->body.cond;
859 cond->cmd_ids[i] = this_id;
860 if (this_id <= CMD_ID_OFFSET_INDEX)
862 FontLayoutCmd *this_cmd
863 = stage->cmds + CMD_ID_TO_INDEX (this_id);
865 if (this_cmd->type == FontLayoutCmdTypeRule
866 && this_cmd->body.rule.src_type == SRC_SEQ)
868 int first_char = this_cmd->body.rule.src.seq.codes[0];
870 if (cond->seq_beg < 0)
872 /* The first SEQ command. */
874 cond->seq_from = cond->seq_to = first_char;
876 else if (cond->seq_end < 0)
878 /* The following SEQ command. */
879 if (cond->seq_from > first_char)
880 cond->seq_from = first_char;
881 else if (cond->seq_to < first_char)
882 cond->seq_to = first_char;
887 if (cond->seq_beg >= 0 && cond->seq_end < 0)
888 /* The previous one is the last SEQ command. */
894 if (cond->seq_beg >= 0 && cond->seq_end < 0)
895 /* The previous one is the last SEQ command. */
899 if (cond->seq_beg >= 0 && cond->seq_end < 0)
900 /* The previous one is the last SEQ command. */
905 cmd->type = FontLayoutCmdTypeRule;
906 if (MPLIST_MTEXT_P (elt))
908 MText *mt = MPLIST_MTEXT (elt);
909 char *str = (char *) MTEXT_DATA (mt);
913 mtext_ins_char (mt, 0, '^', 1);
914 str = (char *) MTEXT_DATA (mt);
916 if (regcomp (&cmd->body.rule.src.re.preg, str, REG_EXTENDED))
917 MERROR (MERROR_FONT, INVALID_CMD_ID);
918 cmd->body.rule.src_type = SRC_REGEX;
919 cmd->body.rule.src.re.pattern = strdup (str);
921 else if (MPLIST_INTEGER_P (elt))
923 cmd->body.rule.src_type = SRC_INDEX;
924 cmd->body.rule.src.match_idx = MPLIST_INTEGER (elt);
926 else if (MPLIST_PLIST_P (elt))
928 MPlist *pl = MPLIST_PLIST (elt);
929 int size = MPLIST_LENGTH (pl);
931 if (MPLIST_INTEGER_P (pl))
935 cmd->body.rule.src_type = SRC_SEQ;
936 cmd->body.rule.src.seq.n_codes = size;
937 MTABLE_CALLOC (cmd->body.rule.src.seq.codes, size,
939 for (i = 0; i < size; i++, pl = MPLIST_NEXT (pl))
941 if (! MPLIST_INTEGER_P (pl))
942 MERROR (MERROR_DRAW, INVALID_CMD_ID);
943 cmd->body.rule.src.seq.codes[i]
944 = (unsigned) MPLIST_INTEGER (pl);
947 else if (MPLIST_SYMBOL_P (pl) && size == 3)
949 if (MPLIST_SYMBOL (pl) != Mrange)
950 MERROR (MERROR_FLT, INVALID_CMD_ID);
951 cmd->body.rule.src_type = SRC_RANGE;
952 pl = MPLIST_NEXT (pl);
953 if (! MPLIST_INTEGER_P (pl))
954 MERROR (MERROR_DRAW, INVALID_CMD_ID);
955 cmd->body.rule.src.range.from
956 = (unsigned) MPLIST_INTEGER (pl);
957 pl = MPLIST_NEXT (pl);
958 if (! MPLIST_INTEGER_P (pl))
959 MERROR (MERROR_DRAW, INVALID_CMD_ID);
960 cmd->body.rule.src.range.to
961 = (unsigned) MPLIST_INTEGER (pl);
963 else if (MPLIST_SYMBOL_P (pl) && size <= 2)
965 if (MPLIST_SYMBOL (pl) != Mfont_facility)
966 MERROR (MERROR_FLT, INVALID_CMD_ID);
967 pl = MPLIST_NEXT (pl);
968 if (MPLIST_SYMBOL_P (pl))
970 MSymbol sym = MPLIST_SYMBOL (pl);
971 char *otf_spec = MSYMBOL_NAME (sym);
973 if (otf_spec[0] == ':' && otf_spec[1] == 'o'
974 && otf_spec[2] == 't' && otf_spec[3] == 'f')
975 parse_otf_command (sym, &cmd->body.rule.src.otf_spec);
977 MERROR (MERROR_FLT, INVALID_CMD_ID);
978 cmd->body.rule.src_type = SRC_OTF_SPEC;
982 cmd->body.rule.src_type = SRC_HAS_GLYPH;
983 if (MPLIST_INTEGER_P (pl))
984 cmd->body.rule.src.supported_glyph
985 = MPLIST_INTEGER (pl);
987 cmd->body.rule.src.supported_glyph = -1;
991 MERROR (MERROR_DRAW, INVALID_CMD_ID);
994 MERROR (MERROR_DRAW, INVALID_CMD_ID);
996 elt = MPLIST_NEXT (elt);
997 cmd->body.rule.n_cmds = len;
998 MTABLE_CALLOC (cmd->body.rule.cmd_ids, len, MERROR_DRAW);
999 for (i = 0; i < len; i++, elt = MPLIST_NEXT (elt))
1001 int this_id = load_command (stage, elt, macros, INVALID_CMD_ID);
1003 if (this_id == INVALID_CMD_ID || this_id == -2)
1004 MERROR (MERROR_DRAW, this_id);
1005 /* The above load_command may relocate stage->cmds. */
1006 cmd = stage->cmds + CMD_ID_TO_INDEX (id);
1007 cmd->body.rule.cmd_ids[i] = this_id;
1011 else if (MPLIST_SYMBOL_P (plist))
1014 MSymbol sym = MPLIST_SYMBOL (plist);
1015 char *name = msymbol_name (sym);
1016 int len = strlen (name);
1020 && ((name[0] == 'o' && name[1] == 't'
1021 && name[2] == 'f' && name[3] == ':')
1022 || (name[0] == ':' && name[1] == 'o' && name[2] == 't'
1023 && name[3] == 'f' && name[4] == '=')))
1025 result = load_otf_command (&cmd, sym);
1028 if (id == INVALID_CMD_ID)
1030 id = INDEX_TO_CMD_ID (stage->used);
1031 MLIST_APPEND1 (stage, cmds, cmd, MERROR_DRAW);
1034 stage->cmds[CMD_ID_TO_INDEX (id)] = cmd;
1042 else if (*name == '*')
1043 return CMD_ID_REPEAT;
1044 else if (*name == '<')
1045 return CMD_ID_CLUSTER_BEGIN;
1046 else if (*name == '>')
1047 return CMD_ID_CLUSTER_END;
1048 else if (*name == '|')
1049 return CMD_ID_SEPARATOR;
1050 else if (*name == '[')
1051 return CMD_ID_LEFT_PADDING;
1052 else if (*name == ']')
1053 return CMD_ID_RIGHT_PADDING;
1059 id = get_combining_command (sym);
1065 MPLIST_DO (elt, macros)
1067 if (sym == MPLIST_SYMBOL (MPLIST_PLIST (elt)))
1069 id = INDEX_TO_CMD_ID (i);
1070 if (stage->cmds[i].type == FontLayoutCmdTypeMAX)
1071 id = load_command (stage, MPLIST_NEXT (MPLIST_PLIST (elt)),
1077 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1080 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1086 free_flt_command (FontLayoutCmd *cmd)
1088 if (cmd->type == FontLayoutCmdTypeRule)
1090 FontLayoutCmdRule *rule = &cmd->body.rule;
1092 if (rule->src_type == SRC_REGEX)
1094 free (rule->src.re.pattern);
1095 regfree (&rule->src.re.preg);
1097 else if (rule->src_type == SRC_SEQ)
1098 free (rule->src.seq.codes);
1099 free (rule->cmd_ids);
1101 else if (cmd->type == FontLayoutCmdTypeCond)
1102 free (cmd->body.cond.cmd_ids);
1103 else if (cmd->type == FontLayoutCmdTypeOTF)
1105 if (cmd->body.otf.features[0])
1106 free (cmd->body.otf.features[0]);
1107 if (cmd->body.otf.features[1])
1108 free (cmd->body.otf.features[1]);
1112 /* Load a generator from PLIST into a newly allocated FontLayoutStage,
1113 and return it. PLIST has this form:
1114 PLIST ::= ( COMMAND ( CMD-NAME COMMAND ) * )
1117 static FontLayoutStage *
1118 load_generator (MPlist *plist)
1120 FontLayoutStage *stage;
1122 FontLayoutCmd dummy;
1125 MSTRUCT_CALLOC (stage, MERROR_DRAW);
1126 MLIST_INIT1 (stage, cmds, 32);
1127 dummy.type = FontLayoutCmdTypeMAX;
1128 MLIST_APPEND1 (stage, cmds, dummy, MERROR_FONT);
1129 MPLIST_DO (elt, MPLIST_NEXT (plist))
1131 if (! MPLIST_PLIST_P (elt))
1132 MERROR (MERROR_FONT, NULL);
1133 pl = MPLIST_PLIST (elt);
1134 if (! MPLIST_SYMBOL_P (pl))
1135 MERROR (MERROR_FONT, NULL);
1136 MLIST_APPEND1 (stage, cmds, dummy, MERROR_FONT);
1139 /* Load the first command from PLIST into STAGE->cmds[0]. Macros
1140 called in the first command are also loaded from MPLIST_NEXT
1141 (PLIST) into STAGE->cmds[n]. */
1142 result = load_command (stage, plist, MPLIST_NEXT (plist),
1143 INDEX_TO_CMD_ID (0));
1144 if (result == INVALID_CMD_ID || result == -2)
1146 MLIST_FREE1 (stage, cmds);
1155 /* Load stages of the font layout table FLT. */
1158 load_flt (MFLT *flt, MPlist *key_list)
1160 MPlist *top, *plist, *pl, *p;
1161 MCharTable *category = NULL;
1165 top = (MPlist *) mdatabase__load_for_keys (flt->mdb, key_list);
1167 top = (MPlist *) mdatabase_load (flt->mdb);
1170 if (! MPLIST_PLIST_P (top))
1172 M17N_OBJECT_UNREF (top);
1173 MERROR (MERROR_FLT, -1);
1178 plist = mdatabase__props (flt->mdb);
1180 MERROR (MERROR_FLT, -1);
1181 MPLIST_DO (plist, plist)
1182 if (MPLIST_PLIST_P (plist))
1184 pl = MPLIST_PLIST (plist);
1185 if (! MPLIST_SYMBOL_P (pl)
1186 || MPLIST_SYMBOL (pl) != Mfont)
1188 pl = MPLIST_NEXT (pl);
1189 if (! MPLIST_PLIST_P (pl))
1191 p = MPLIST_PLIST (pl);
1192 if (! MPLIST_SYMBOL_P (p))
1194 p = MPLIST_NEXT (p);
1195 if (! MPLIST_SYMBOL_P (p))
1197 flt->family = MPLIST_SYMBOL (p);
1198 MPLIST_DO (p, MPLIST_NEXT (p))
1199 if (MPLIST_SYMBOL_P (p))
1201 sym = MPLIST_SYMBOL (p);
1202 if (MSYMBOL_NAME (sym)[0] != ':')
1203 flt->registry = sym, sym = Mnil;
1209 char *otf_spec = MSYMBOL_NAME (sym);
1211 if (otf_spec[0] == ':' && otf_spec[1] == 'o'
1212 && otf_spec[2] == 't' && otf_spec[3] == 'f')
1213 parse_otf_command (sym, &flt->otf);
1218 MPLIST_DO (plist, top)
1220 if (MPLIST_SYMBOL_P (plist)
1221 && MPLIST_SYMBOL (plist) == Mend)
1223 mplist_set (plist, Mnil, NULL);
1226 if (! MPLIST_PLIST (plist))
1228 pl = MPLIST_PLIST (plist);
1229 if (! MPLIST_SYMBOL_P (pl))
1231 sym = MPLIST_SYMBOL (pl);
1232 pl = MPLIST_NEXT (pl);
1235 if (sym == Mcategory)
1238 M17N_OBJECT_UNREF (category);
1239 else if (flt->coverage)
1241 category = flt->coverage;
1244 category = load_category_table (pl);
1245 if (! flt->coverage)
1247 flt->coverage = category;
1248 M17N_OBJECT_REF (category);
1251 else if (sym == Mgenerator)
1253 FontLayoutStage *stage;
1257 stage = load_generator (pl);
1260 stage->category = category;
1261 M17N_OBJECT_REF (category);
1263 flt->stages = mplist ();
1264 mplist_add (flt->stages, Mt, stage);
1268 M17N_OBJECT_UNREF (category);
1269 if (! MPLIST_TAIL_P (plist))
1271 M17N_OBJECT_UNREF (top);
1272 M17N_OBJECT_UNREF (flt->stages);
1273 MERROR (MERROR_FLT, -1);
1275 M17N_OBJECT_UNREF (top);
1281 free_flt_stage (FontLayoutStage *stage)
1285 M17N_OBJECT_UNREF (stage->category);
1286 for (i = 0; i < stage->used; i++)
1287 free_flt_command (stage->cmds + i);
1288 MLIST_FREE1 (stage, cmds);
1299 MPLIST_DO (plist, flt_list)
1301 MFLT *flt = MPLIST_VAL (plist);
1304 M17N_OBJECT_UNREF (flt->coverage);
1307 MPLIST_DO (pl, MPLIST_NEXT (flt->stages))
1308 free_flt_stage (MPLIST_VAL (pl));
1309 M17N_OBJECT_UNREF (flt->stages);
1312 M17N_OBJECT_UNREF (flt_list);
1319 MPlist *plist, *key_list = NULL;
1323 if (! (plist = mdatabase_list (Mfont, Mlayouter, Mnil, Mnil)))
1325 if (! (flt_list = mplist ()))
1327 if (! (key_list = mplist ()))
1329 if (! mplist_add (key_list, Mcategory, Mt))
1332 MPLIST_DO (pl, plist)
1334 MDatabase *mdb = MPLIST_VAL (pl);
1335 MSymbol *tags = mdatabase_tag (mdb);
1338 if (! MSTRUCT_CALLOC_SAFE (flt))
1340 flt->name = tags[2];
1342 if (load_flt (flt, key_list) < 0)
1346 if (MPLIST_TAIL_P (flt_list))
1348 flt_min_coverage = mchartable_min_char (flt->coverage);
1349 flt_max_coverage = mchartable_max_char (flt->coverage);
1355 c = mchartable_min_char (flt->coverage);
1356 if (flt_min_coverage > c)
1357 flt_min_coverage = c;
1358 c = mchartable_max_char (flt->coverage);
1359 if (flt_max_coverage < c)
1360 flt_max_coverage = c;
1362 if (! mplist_push (flt_list, flt->name, flt))
1372 M17N_OBJECT_UNREF (plist);
1373 M17N_OBJECT_UNREF (key_list);
1377 /* FLS (Font Layout Service) */
1379 /* Structure to hold information about a context of FLS. */
1383 /* Pointer to the current stage. */
1384 FontLayoutStage *stage;
1386 /* Pointer to the font. */
1389 /* Input and output glyph string. */
1390 MFLTGlyphString *in, *out;
1392 /* Encode each character or code of a glyph by the current category
1393 table into this array. An element is a category letter used for
1394 a regular expression matching. */
1399 int cluster_begin_idx;
1400 int cluster_begin_pos;
1401 int cluster_end_pos;
1405 } FontLayoutContext;
1407 static int run_command (int, int, int, int, FontLayoutContext *);
1412 run_rule (int depth,
1413 FontLayoutCmdRule *rule, int from, int to, FontLayoutContext *ctx)
1415 int *saved_match_indices = ctx->match_indices;
1416 int match_indices[NMATCH * 2];
1419 int orig_from = from;
1421 if (rule->src_type == SRC_SEQ)
1425 len = rule->src.seq.n_codes;
1426 if (len > (to - from))
1428 for (i = 0; i < len; i++)
1429 if (rule->src.seq.codes[i] != GREF (ctx->in, from + i)->code)
1434 if (MDEBUG_FLAG () > 2)
1435 MDEBUG_PRINT3 ("\n [FLT] %*s(SEQ 0x%X", depth, "",
1436 rule->src.seq.codes[0]);
1438 else if (rule->src_type == SRC_RANGE)
1444 head = GREF (ctx->in, from)->code;
1445 if (head < rule->src.range.from || head > rule->src.range.to)
1447 ctx->code_offset = head - rule->src.range.from;
1449 if (MDEBUG_FLAG () > 2)
1450 MDEBUG_PRINT4 ("\n [FLT] %*s(RANGE 0x%X-0x%X", depth, "",
1451 rule->src.range.from, rule->src.range.to);
1453 else if (rule->src_type == SRC_REGEX)
1455 regmatch_t pmatch[NMATCH];
1461 saved_code = ctx->encoded[to - ctx->encoded_offset];
1462 ctx->encoded[to - ctx->encoded_offset] = '\0';
1463 result = regexec (&(rule->src.re.preg),
1464 ctx->encoded + (from - ctx->encoded_offset),
1466 if (result == 0 && pmatch[0].rm_so == 0)
1468 if (MDEBUG_FLAG () > 2)
1469 MDEBUG_PRINT5 ("\n [FLT] %*s(REGEX \"%s\" \"%s\" %d", depth, "",
1470 rule->src.re.pattern,
1471 ctx->encoded + (from - ctx->encoded_offset),
1473 ctx->encoded[to - ctx->encoded_offset] = saved_code;
1474 for (i = 0; i < NMATCH; i++)
1476 if (pmatch[i].rm_so < 0)
1477 match_indices[i * 2] = match_indices[i * 2 + 1] = -1;
1480 match_indices[i * 2] = from + pmatch[i].rm_so;
1481 match_indices[i * 2 + 1] = from + pmatch[i].rm_eo;
1484 ctx->match_indices = match_indices;
1485 to = match_indices[1];
1489 ctx->encoded[to - ctx->encoded_offset] = saved_code;
1493 else if (rule->src_type == SRC_INDEX)
1495 if (rule->src.match_idx >= NMATCH)
1497 from = ctx->match_indices[rule->src.match_idx * 2];
1500 to = ctx->match_indices[rule->src.match_idx * 2 + 1];
1501 if (MDEBUG_FLAG () > 2)
1502 MDEBUG_PRINT3 ("\n [FLT] %*s(SUBPART %d", depth, "",
1503 rule->src.match_idx);
1505 else if (rule->src_type == SRC_HAS_GLYPH)
1510 if (rule->src.supported_glyph < 0)
1514 code = GREF (ctx->in, from)->code;
1515 encoded = GREF (ctx->in, from)->encoded;
1519 code = rule->src.supported_glyph;
1524 static MFLTGlyphString gstring;
1526 if (! gstring.glyph_size)
1528 gstring.glyph_size = ctx->in->glyph_size;
1529 gstring.glyphs = calloc (1, gstring.glyph_size);
1530 gstring.allocated = 1;
1533 gstring.glyphs[0].code = code;
1534 ctx->font->get_glyph_id (ctx->font, &gstring, 0, 1);
1535 if (gstring.glyphs[0].code == 0xFFFFFFFF
1536 || ! gstring.glyphs[0].encoded)
1539 if (MDEBUG_FLAG () > 2)
1540 MDEBUG_PRINT3 ("\n [FLT] %*s(HAS-GLYPH %04X", depth, "", code);
1542 else if (rule->src_type == SRC_OTF_SPEC)
1544 MFLTOtfSpec *spec = &rule->src.otf_spec;
1546 if (! ctx->font->check_otf)
1548 if ((spec->features[0] && spec->features[0][0] != 0xFFFFFFFF)
1549 || (spec->features[1] && spec->features[1][0] != 0xFFFFFFFF))
1552 else if (! ctx->font->check_otf (ctx->font, spec))
1558 for (i = 0; i < rule->n_cmds; i++)
1562 if (rule->cmd_ids[i] == CMD_ID_REPEAT)
1568 pos = run_command (depth, rule->cmd_ids[i], from, to, ctx);
1571 consumed = pos > from;
1576 ctx->match_indices = saved_match_indices;
1577 if (MDEBUG_FLAG () > 2)
1579 return (rule->src_type == SRC_INDEX ? orig_from : to);
1583 run_cond (int depth,
1584 FontLayoutCmdCond *cond, int from, int to, FontLayoutContext *ctx)
1588 if (MDEBUG_FLAG () > 2)
1589 MDEBUG_PRINT2 ("\n [FLT] %*s(COND", depth, "");
1591 for (i = 0; i < cond->n_cmds; i++)
1593 /* TODO: Write a code for optimization utilizaing the info
1595 if ((pos = run_command (depth, cond->cmd_ids[i], from, to, ctx))
1601 if (MDEBUG_FLAG () > 2)
1608 MFLTOtfSpec *otf_spec, int from, int to, FontLayoutContext *ctx)
1610 MFLTFont *font = ctx->font;
1611 int from_idx = ctx->out->used;
1613 if (MDEBUG_FLAG () > 2)
1614 MDEBUG_PRINT3 ("\n [FLT] %*s%s", depth, "", MSYMBOL_NAME (otf_spec->sym));
1616 font->get_glyph_id (font, ctx->in, from, to);
1617 if (! font->drive_otf)
1619 if (ctx->out->used + (to - from) > ctx->out->allocated)
1621 font->get_metrics (font, ctx->in, from, to);
1622 GCPY (ctx->in, from, to - from, ctx->out, ctx->out->used);
1623 ctx->out->used += to - from;
1627 MFLTGlyphAdjustment *adjustment;
1631 adjustment = alloca ((sizeof *adjustment)
1632 * (ctx->out->allocated - ctx->out->used));
1634 MERROR (MERROR_FLT, -1);
1635 memset (adjustment, 0,
1636 (sizeof *adjustment) * (ctx->out->allocated - ctx->out->used));
1637 to = font->drive_otf (font, otf_spec, ctx->in, from, to, ctx->out,
1641 out_len = ctx->out->used - from_idx;
1642 if (otf_spec->features[1])
1644 MFLTGlyphAdjustment *a;
1647 for (i = 0, a = adjustment; i < out_len; i++, a++)
1652 font->get_metrics (font, ctx->out, from_idx, ctx->out->used);
1653 for (g = GREF (ctx->out, from_idx + i);
1654 i < out_len; i++, a++, g = NEXT (ctx->out, g))
1657 if (a->advance_is_absolute)
1662 else if (a->xadv || a->yadv)
1667 if (a->xoff || a->yoff)
1670 MFLTGlyph *gg = PREV (ctx->out, g);
1671 MFLTGlyphAdjustment *aa = a;
1675 while (aa->back > 0)
1677 for (j = 0; j < aa->back;
1678 j++, gg = PREV (ctx->out, gg))
1679 g->xoff -= gg->xadv;
1681 g->xoff += aa->xoff;
1682 g->yoff += aa->yoff;
1691 if (ctx->cluster_begin_idx >= 0)
1692 for (; from_idx < ctx->out->used; from_idx++)
1694 MFLTGlyph *g = GREF (ctx->out, from_idx);
1695 UPDATE_CLUSTER_RANGE (ctx, g);
1700 static char work[16];
1703 dump_combining_code (int code)
1705 char *vallign = "tcbB";
1706 char *hallign = "lcr";
1712 work[0] = vallign[COMBINING_CODE_BASE_Y (code)];
1713 work[1] = hallign[COMBINING_CODE_BASE_X (code)];
1714 off_y = COMBINING_CODE_OFF_Y (code);
1715 off_x = COMBINING_CODE_OFF_X (code);
1717 sprintf (work + 2, "+%d", off_y);
1719 sprintf (work + 2, "%d", off_y);
1720 else if (off_x == 0)
1721 sprintf (work + 2, ".");
1722 p = work + strlen (work);
1724 sprintf (p, ">%d", off_x);
1726 sprintf (p, "<%d", -off_x);
1728 p[0] = vallign[COMBINING_CODE_ADD_Y (code)];
1729 p[1] = hallign[COMBINING_CODE_ADD_X (code)];
1735 run_command (int depth, int id, int from, int to, FontLayoutContext *ctx)
1743 /* Direct code (== ctx->code_offset + id) output.
1744 The source is not consumed. */
1745 if (MDEBUG_FLAG () > 2)
1746 MDEBUG_PRINT3 ("\n [FLT] %*s(DIRECT 0x%X", depth, "",
1747 ctx->code_offset + id);
1748 i = (from < to || from == 0) ? from : from - 1;
1750 g = GREF (ctx->out, ctx->out->used - 1);
1751 g->c = g->code = ctx->code_offset + id;
1753 SET_MEASURED (g, 0);
1754 if (ctx->combining_code)
1755 SET_COMBINING_CODE (g, ctx, ctx->combining_code);
1756 if (ctx->left_padding)
1757 SET_LEFT_PADDING (g, ctx, LeftPaddingMask);
1758 for (i = from; i < to; i++)
1760 MFLTGlyph *tmp = GREF (ctx->in, i);
1762 if (g->from > tmp->from)
1763 g->from = tmp->from;
1764 else if (g->to < tmp->to)
1767 UPDATE_CLUSTER_RANGE (ctx, g);
1768 ctx->code_offset = ctx->combining_code = ctx->left_padding = 0;
1769 if (MDEBUG_FLAG () > 2)
1774 if (id <= CMD_ID_OFFSET_INDEX)
1776 int idx = CMD_ID_TO_INDEX (id);
1779 if (idx >= ctx->stage->used)
1780 MERROR (MERROR_DRAW, -1);
1781 cmd = ctx->stage->cmds + idx;
1782 if (cmd->type == FontLayoutCmdTypeRule)
1783 to = run_rule (depth, &cmd->body.rule, from, to, ctx);
1784 else if (cmd->type == FontLayoutCmdTypeCond)
1785 to = run_cond (depth, &cmd->body.cond, from, to, ctx);
1786 else if (cmd->type == FontLayoutCmdTypeOTF)
1787 to = run_otf (depth, &cmd->body.otf, from, to, ctx);
1791 if (id <= CMD_ID_OFFSET_COMBINING)
1793 ctx->combining_code = CMD_ID_TO_COMBINING_CODE (id);
1794 if (MDEBUG_FLAG () > 2)
1795 MDEBUG_PRINT3 ("\n [FLT] %*s(CMB %s)", depth, "",
1796 dump_combining_code (ctx->combining_code));
1807 g = GREF (ctx->out, ctx->out->used - 1);
1808 if (ctx->combining_code)
1809 SET_COMBINING_CODE (g, ctx, ctx->combining_code);
1810 if (ctx->left_padding)
1811 SET_LEFT_PADDING (g, ctx, LeftPaddingMask);
1812 UPDATE_CLUSTER_RANGE (ctx, g);
1813 if (MDEBUG_FLAG () > 2)
1816 MDEBUG_PRINT2 ("\n [FLT] %*s(COPY |)", depth, "");
1818 MDEBUG_PRINT3 ("\n [FLT] %*s(COPY 0x%X)", depth, "", g->code);
1820 ctx->code_offset = ctx->combining_code = ctx->left_padding = 0;
1824 case CMD_ID_CLUSTER_BEGIN:
1825 if (ctx->cluster_begin_idx < 0)
1827 if (MDEBUG_FLAG () > 2)
1828 MDEBUG_PRINT3 ("\n [FLT] %*s<%d", depth, "",
1829 GREF (ctx->in, from)->from);
1830 ctx->cluster_begin_idx = ctx->out->used;
1831 ctx->cluster_begin_pos = GREF (ctx->in, from)->from;
1832 ctx->cluster_end_pos = GREF (ctx->in, from)->to;
1836 case CMD_ID_CLUSTER_END:
1837 if (ctx->cluster_begin_idx >= 0
1838 && ctx->cluster_begin_idx < ctx->out->used)
1842 if (MDEBUG_FLAG () > 2)
1843 MDEBUG_PRINT1 (" %d>", ctx->cluster_end_pos + 1);
1844 for (i = ctx->cluster_begin_idx; i < ctx->out->used; i++)
1846 GREF (ctx->out, i)->from = ctx->cluster_begin_pos;
1847 GREF (ctx->out, i)->to = ctx->cluster_end_pos;
1849 ctx->cluster_begin_idx = -1;
1853 case CMD_ID_SEPARATOR:
1857 i = from < to ? from : from - 1;
1859 g = GREF (ctx->out, ctx->out->used - 1);
1860 g->c = -1, g->code = 0;
1861 g->xadv = g->yadv = 0;
1863 SET_MEASURED (g, 0);
1867 case CMD_ID_LEFT_PADDING:
1868 if (MDEBUG_FLAG () > 2)
1869 MDEBUG_PRINT2 ("\n [FLT] %*s[", depth, "");
1870 ctx->left_padding = 1;
1873 case CMD_ID_RIGHT_PADDING:
1874 if (ctx->out->used > 0)
1876 if (MDEBUG_FLAG () > 2)
1877 MDEBUG_PRINT2 ("\n [FLT] %*s]", depth, "");
1878 g = GREF (ctx->out, ctx->out->used - 1);
1879 SET_RIGHT_PADDING (g, ctx, RightPaddingMask);
1884 MERROR (MERROR_DRAW, -1);
1888 run_stages (MFLTGlyphString *gstring, int from, int to,
1889 MFLT *flt, FontLayoutContext *ctx)
1891 MFLTGlyphString buf, *temp;
1893 int orig_from = from, orig_to = to;
1894 int from_pos, to_pos, len;
1897 MPlist *stages = flt->stages;
1899 from_pos = GREF (ctx->in, from)->from;
1900 to_pos = GREF (ctx->in, to - 1)->to;
1901 len = to_pos - from_pos;
1905 GINIT (ctx->out, ctx->out->allocated);
1906 ctx->encoded = alloca (ctx->out->allocated);
1907 if (! ctx->out->glyphs || ! ctx->encoded)
1910 for (stage_idx = 0; 1; stage_idx++)
1915 ctx->stage = (FontLayoutStage *) MPLIST_VAL (stages);
1916 table = ctx->stage->category;
1917 ctx->code_offset = ctx->combining_code = ctx->left_padding = 0;
1918 ctx->encoded_offset = from;
1919 for (i = from; i < to; i++)
1921 MFLTGlyph *g = GREF (ctx->in, i);
1922 char enc = (GET_ENCODED (g)
1923 ? (g->c > 0 ? (int) mchartable_lookup (table, g->c) : 1)
1925 ? (int) mchartable_lookup (table, g->code)
1928 ctx->encoded[i - from] = enc;
1929 if (! enc && stage_idx == 0)
1935 ctx->encoded[i - from] = '\0';
1936 ctx->match_indices[0] = from;
1937 ctx->match_indices[1] = to;
1938 for (i = 2; i < NMATCH; i++)
1939 ctx->match_indices[i] = -1;
1941 if (MDEBUG_FLAG () > 2)
1943 MDEBUG_PRINT2 ("\n [FLT] (STAGE %d \"%s\"", stage_idx,
1945 MDEBUG_PRINT (" (");
1946 for (i = from; i < to; i++)
1948 g = GREF (ctx->in, i);
1950 MDEBUG_PRINT2 ("%*s|", (i > 0), "");
1952 MDEBUG_PRINT3 ("%*s%04X", (i > 0), "", GREF (ctx->in, i)->code);
1956 result = run_command (4, INDEX_TO_CMD_ID (0), from, to, ctx);
1957 if (MDEBUG_FLAG () > 2)
1962 stages = MPLIST_NEXT (stages);
1963 /* If this is the last stage, break the loop. */
1964 if (MPLIST_TAIL_P (stages))
1967 /* Otherwise, prepare for the next stage. */
1974 GINIT (&buf, ctx->out->allocated);
1983 if (ctx->out->used > 0)
1986 int x_ppem = ctx->font->x_ppem << 6, y_ppem = ctx->font->y_ppem << 6;
1988 /* Remove separator glyphs. */
1989 for (i = 0; i < ctx->out->used;)
1991 g = GREF (ctx->out, i);
1993 GREPLACE (NULL, 0, 0, ctx->out, i, i + 1);
1998 /* Get actual glyph IDs of glyphs. */
1999 ctx->font->get_glyph_id (ctx->font, ctx->out, 0, ctx->out->used);
2001 /* Check if all characters in the range are covered by some
2002 glyph(s). If not, change <from> and <to> of glyphs to cover
2003 uncovered characters. */
2004 g_indices = alloca (sizeof (int) * len);
2007 for (i = 0; i < len; i++) g_indices[i] = -1;
2008 for (i = 0; i < ctx->out->used; i++)
2012 g = GREF (ctx->out, i);
2013 for (pos = g->from; pos <= g->to; pos++)
2014 if (g_indices[pos - orig_from] < 0)
2015 g_indices[pos - orig_from] = i;
2017 for (i = 0; i < len; i++)
2018 if (g_indices[i] < 0)
2024 for (i++; i < len && g_indices[i] < 0; i++);
2026 g = GREF (ctx->out, j);
2027 this_from = g->from;
2029 g->from = orig_from + i;
2030 } while (++j < ctx->out->used
2031 && (g = GREF (ctx->out, j))
2032 && g->from == this_from);
2038 j = g_indices[i - 1];
2039 g = GREF (ctx->out, j);
2042 g->to = orig_from + i + 1;
2044 && (g = GREF (ctx->out, j))
2045 && g->to == this_to);
2049 ctx->font->get_metrics (ctx->font, ctx->out, 0, ctx->out->used);
2051 /* Handle combining. */
2052 if (ctx->check_mask & CombiningCodeMask)
2054 MFLTGlyph *base = GREF (ctx->out, 0);
2055 int base_height = base->ascent + base->descent;
2058 for (i = 1; i < ctx->out->used; i++)
2060 if ((g = GREF (ctx->out, i))
2061 && (combining_code = GET_COMBINING_CODE (g)))
2063 int height = g->ascent + g->descent;
2064 int base_x, base_y, add_x, add_y, off_x, off_y;
2066 if (base->from > g->from)
2067 base->from = g->from;
2068 else if (base->to < g->to)
2071 base_x = COMBINING_CODE_BASE_X (combining_code);
2072 base_y = COMBINING_CODE_BASE_Y (combining_code);
2073 add_x = COMBINING_CODE_ADD_X (combining_code);
2074 add_y = COMBINING_CODE_ADD_Y (combining_code);
2075 off_x = COMBINING_CODE_OFF_X (combining_code);
2076 off_y = COMBINING_CODE_OFF_Y (combining_code);
2078 g->xoff = ((base->xadv * base_x - g->xadv * add_x) / 2
2079 + x_ppem * off_x / 100 - base->xadv);
2081 g->yoff = base_height * base_y / 2 - base->ascent;
2085 g->yoff -= height * add_y / 2 - g->ascent;
2086 g->yoff -= y_ppem * off_y / 100;
2087 if (base->lbearing > base->xadv + g->lbearing + g->xoff)
2088 base->lbearing = base->xadv + g->lbearing + g->xoff;
2089 if (base->rbearing < base->xadv + g->xadv + g->xoff)
2090 base->rbearing = base->xadv + g->xadv + g->xoff;
2091 if (base->ascent < g->ascent - g->yoff)
2092 base->ascent = g->ascent - g->yoff;
2093 if (base->descent < g->descent - g->yoff)
2094 base->descent = g->descent - g->yoff;
2095 g->xadv = g->yadv = 0;
2096 if (GET_RIGHT_PADDING (g))
2097 SET_RIGHT_PADDING (base, ctx, RightPaddingMask);
2103 base_height = g->ascent + g->descent;
2108 /* Handle padding */
2109 if (ctx->check_mask & (LeftPaddingMask | RightPaddingMask))
2110 for (i = 0; i < ctx->out->used; i++)
2112 g = GREF (ctx->out, i);
2113 if (! GET_COMBINING_CODE (g))
2115 if (GET_RIGHT_PADDING (g) && g->rbearing > g->xadv)
2117 g->xadv = g->rbearing;
2120 if (GET_LEFT_PADDING (g) && g->lbearing < 0)
2122 g->xoff += - g->lbearing;
2123 g->xadv += - g->lbearing;
2124 g->rbearing += - g->lbearing;
2132 GREPLACE (ctx->out, 0, ctx->out->used, gstring, orig_from, orig_to);
2133 to = orig_from + ctx->out->used;
2138 setup_combining_coverage (int from, int to, void *val, void *arg)
2140 int combining_class = (int) val;
2143 if (combining_class < 200)
2145 else if (combining_class <= 204)
2147 if ((combining_class % 2) == 0)
2148 category = "bcd"[(combining_class - 200) / 2];
2150 else if (combining_class <= 232)
2152 if ((combining_class % 2) == 0)
2153 category = "efghijklmnopq"[(combining_class - 208) / 2];
2155 else if (combining_class == 233)
2157 else if (combining_class == 234)
2159 else if (combining_class == 240)
2161 mchartable_set_range ((MCharTable *) arg, from, to, (void *) category);
2165 setup_combining_flt (MFLT *flt)
2168 MCharTable *combininig_class_table
2169 = mchar_get_prop_table (Mcombining_class, &type);
2171 mchartable_set_range (flt->coverage, 0, 0x10FFFF, (void *) 'u');
2172 if (combininig_class_table)
2173 mchartable_map (combininig_class_table, (void *) 0,
2174 setup_combining_coverage, flt->coverage);
2177 #define CHECK_FLT_STAGES(flt) ((flt)->stages || load_flt (flt, NULL) == 0)
2182 int m17n__flt_initialized;
2187 /* The following two are actually not exposed to a user but concealed
2188 by the macro M17N_INIT (). */
2191 m17n_init_flt (void)
2193 int mdebug_flag = MDEBUG_INIT;
2195 merror_code = MERROR_NONE;
2196 if (m17n__flt_initialized++)
2199 if (merror_code != MERROR_NONE)
2201 m17n__flt_initialized--;
2205 MDEBUG_PUSH_TIME ();
2207 Mcond = msymbol ("cond");
2208 Mrange = msymbol ("range");
2209 Mfont = msymbol ("font");
2210 Mlayouter = msymbol ("layouter");
2211 Mcombining = msymbol ("combining");
2212 Mfont_facility = msymbol ("font-facility");
2213 Mgenerator = msymbol ("generator");
2214 Mend = msymbol ("end");
2216 MDEBUG_PRINT_TIME ("INIT", (stderr, " to initialize the flt modules."));
2221 m17n_fini_flt (void)
2223 int mdebug_flag = MDEBUG_FINI;
2225 if (m17n__flt_initialized == 0
2226 || --m17n__flt_initialized > 0)
2229 MDEBUG_PUSH_TIME ();
2231 MDEBUG_PRINT_TIME ("FINI", (stderr, " to finalize the flt modules."));
2237 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
2239 /*** @addtogroup m17nFLT */
2245 @brief Return an FLT object that has a specified name.
2247 The mflt_get () function returns an FLT object whose name is $NAME.
2250 If the operation was successful, mflt_get () returns a pointer
2251 to the found FLT object. Otherwise, it returns @c NULL. */
2254 @brief »ØÄꤵ¤ì¤¿Ì¾Á°¤ò»ý¤Ä FLT ¥ª¥Ö¥¸¥§¥¯¥È¤òÊÖ¤¹.
2256 ´Ø¿ô mflt_get () ¤Ï¡¢$NAME ¤È¤¤¤¦Ì¾Á°¤ò»ý¤Ä FLT ¥ª¥Ö¥¸¥§¥¯¥È¤òÊÖ¤¹¡£
2259 ¤â¤·À®¸ù¤¹¤ì¤Ð¡¢mflt_get () ¤Ï¸«¤Ä¤«¤Ã¤¿ FLT
2260 ¥ª¥Ö¥¸¥§¥¯¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¼ºÇÔ¤·¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤¹¡£ */
2263 mflt_get (MSymbol name)
2267 if (! flt_list && list_flt () < 0)
2269 flt = mplist_get (flt_list, name);
2270 if (! flt || ! CHECK_FLT_STAGES (flt))
2272 if (flt->name == Mcombining
2273 && ! mchartable_lookup (flt->coverage, 0))
2274 setup_combining_flt (flt);
2281 @brief Find an FLT suitable for the specified character and font.
2283 The mflt_find () function returns the most appropriate FLT for
2284 layouting character $C with font $FONT.
2287 If the operation was successful, mflt_find () returns a pointer
2288 to the found FLT object. Otherwise, it returns @c NULL. */
2291 @brief »ØÄꤵ¤ì¤¿Ê¸»ú¤È¥Õ¥©¥ó¥È¤Ë¹ç¤Ã¤¿ FLT ¤òõ¤¹.
2293 ´Ø¿ô mflt_find () ¤Ï¡¢Ê¸»ú $C ¤ò¥Õ¥©¥ó¥È $FONT
2294 ¤Ç¥ì¥¤¥¢¥¦¥È¤¹¤ë¤¿¤á¤ËºÇ¤âŬÀÚ¤Ê FLT ¤òÊÖ¤¹¡£
2297 ¤â¤·À®¸ù¤¹¤ì¤Ð¡¢mflt_find () ¤Ï¸«¤Ä¤«¤Ã¤¿ FLT
2298 ¥ª¥Ö¥¸¥§¥¯¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¼ºÇÔ¤·¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤¹¡£ */
2301 mflt_find (int c, MFLTFont *font)
2305 static MSymbol unicode_bmp = NULL, unicode_full = NULL;
2309 unicode_bmp = msymbol ("unicode-bmp");
2310 unicode_full = msymbol ("unicode-full");
2313 if (! flt_list && list_flt () < 0)
2319 MPLIST_DO (plist, flt_list)
2321 flt = MPLIST_VAL (plist);
2322 if (flt->registry != unicode_bmp
2323 && flt->registry != unicode_full)
2325 if (flt->family && flt->family != font->family)
2328 && ! mchartable_lookup (flt->coverage, c))
2332 MFLTOtfSpec *spec = &flt->otf;
2334 if (! font->check_otf)
2336 if ((spec->features[0] && spec->features[0][0] != 0xFFFFFFFF)
2337 || (spec->features[1] && spec->features[1][0] != 0xFFFFFFFF))
2340 else if (! font->check_otf (font, spec))
2350 MPLIST_DO (plist, flt_list)
2352 flt = MPLIST_VAL (plist);
2353 if (mchartable_lookup (flt->coverage, c))
2362 @brief Return the name of an FLT.
2364 The mflt_name () function returns the name of $FLT. */
2367 @brief FLT ¤Î̾Á°¤òÊÖ¤¹.
2369 ´Ø¿ô mflt_name () ¤Ï $FLT ¤Î̾Á°¤òÊÖ¤¹¡£ */
2372 mflt_name (MFLT *flt)
2374 return MSYMBOL_NAME (flt->name);
2379 @brief Return a coverage of a FLT.
2381 The mflt_coverage () function returns a char-table that contains
2382 nonzero values for characters supported by $FLT. */
2385 @brief FLT ¤ÎÈϰϤòÊÖ¤¹.
2387 ´Ø¿ô mflt_coverage () ¤Ï¡¢$FLT ¤¬¥µ¥Ý¡¼¥È¤¹¤ëʸ»ú¤ËÂФ·¤Æ
2388 0 ¤Ç¤Ê¤¤Ãͤò´Þ¤àʸ»ú¥Æ¡¼¥Ö¥ë¤òÊÖ¤¹¡£ */
2391 mflt_coverage (MFLT *flt)
2393 return flt->coverage;
2398 @brief Layout characters with an FLT.
2400 The mflt_run () function layouts characters in $GSTRING between
2401 $FROM (inclusive) and $TO (exclusive) with $FONT. If $FLT is
2402 nonzero, it is used for all the charaters. Otherwise, appropriate
2403 FLTs are automatically chosen.
2406 The operation was successful. The value is the index to the
2407 glyph, which was previously indexed by $TO, in $GSTRING->glyphs.
2410 $GSTRING->glyphs is too short to store the result. The caller can
2411 call this fucntion again with a longer $GSTRING->glyphs.
2414 Some other error occurred. */
2417 @brief FLT ¤ò»È¤Ã¤Æʸ»ú¤ò¥ì¥¤¥¢¥¦¥È¤¹¤ë.
2419 ´Ø¿ô mflt_run () ¤Ï¡¢$GSTRING Ãæ¤Î $FROM ¤«¤é $TO ľÁ°¤Þ¤Ç¤Îʸ»ú¤ò
2420 $FONT ¤òÍѤ¤¤Æ¥ì¥¤¥¢¥¦¥È¤¹¤ë¡£¤â¤· $FLT
2421 ¤¬¥¼¥í¤Ç¤Ê¤±¤ì¤Ð¡¢¤½¤ÎÃͤò¤¹¤Ù¤Æ¤Îʸ»ú¤ËÂФ·¤ÆÍѤ¤¤ë¡£
2422 ¤½¤¦¤Ç¤Ê¤±¤ì¤ÐŬÀÚ¤Ê FLT ¤ò¼«Æ°Åª¤ËÁªÂò¤¹¤ë¡£
2425 ¼Â¹ÔÀ®¸ù¤ò¼¨¤¹¡£ÊÖ¤µ¤ì¤ëÃͤϡ¢$GSTRING->glyphs Ãæ¤Ç°ÊÁ° $TO
2426 ¤Ë¤è¤Ã¤Æ¼¨¤µ¤ì¤Æ¤¤¤¿¥°¥ê¥Õ¤Ø¤Î¥¤¥ó¥Ç¥¯¥¹¤Ç¤¢¤ë¡£
2429 ·ë²Ì¤ò³ÊǼ¤¹¤ë¤Ë¤Ï $GSTRING->glyphs ¤¬Ã»¤¹¤®¤ë¤³¤È¤ò¼¨¤¹¡£
2430 ¸Æ¤Ó½Ð¤·Â¦¤Ï¡¢¤è¤êŤ¤ $GSTRING->glyphs
2431 ¤òÍѤ¤¤ÆºÆÅÙ¤³¤Î´Ø¿ô¤ò¸Æ¤Ö¤³¤È¤¬¤Ç¤¤ë¡£
2434 ¤½¤Î¾¤Î¥¨¥é¡¼¤¬µ¯¤¤¿¤³¤È¤ò¼¨¤¹¡£ */
2437 mflt_run (MFLTGlyphString *gstring, int from, int to,
2438 MFLTFont *font, MFLT *flt)
2440 FontLayoutContext ctx;
2441 int match_indices[NMATCH];
2443 MFLTGlyphString out;
2444 int auto_flt = ! flt;
2446 int this_from, this_to;
2450 /* This is usually sufficient, but if not, we retry with the larger
2451 values at most 3 times. This value is also used for the
2452 allocating size of ctx.encoded. */
2453 out.allocated = (to - from) * 4;
2455 for (i = from; i < to; i++)
2457 g = GREF (gstring, i);
2459 memset (g, 0, sizeof (MFLTGlyph));
2461 g->from = g->to = i;
2464 for (this_from = from; this_from < to;)
2468 for (this_to = this_from; this_to < to; this_to++)
2469 if (mchartable_lookup (flt->coverage, GREF (gstring, this_to)->c))
2474 if (! flt_list && list_flt () < 0)
2476 font->get_glyph_id (font, gstring, this_from, to);
2477 font->get_metrics (font, gstring, this_from, to);
2481 for (this_to = this_from; this_to < to; this_to++)
2483 c = GREF (gstring, this_to)->c;
2484 if (c >= flt_min_coverage && c <= flt_max_coverage)
2487 for (; this_to < to; this_to++)
2489 c = GREF (gstring, this_to)->c;
2491 && mchartable_lookup (((MFLT *) font->internal)->coverage, c))
2493 flt = font->internal;
2496 flt = mflt_find (c, font);
2499 if (CHECK_FLT_STAGES (flt))
2501 font->internal = flt;
2508 if (this_from < this_to)
2510 font->get_glyph_id (font, gstring, this_from, this_to);
2511 font->get_metrics (font, gstring, this_from, this_to);
2512 this_from = this_to;
2517 MDEBUG_PRINT1 (" [FLT] (%s", MSYMBOL_NAME (flt->name));
2519 for (; this_to < to; this_to++)
2520 if (! mchartable_lookup (flt->coverage, GREF (gstring, this_to)->c))
2526 MDEBUG_PRINT1 (" (%s)", MSYMBOL_NAME (font->family));
2527 MDEBUG_PRINT ("\n [FLT] (SOURCE");
2528 for (i = this_from, j = 0; i < this_to; i++, j++)
2530 if (j > 0 && j % 8 == 0)
2531 MDEBUG_PRINT ("\n [FLT] ");
2532 MDEBUG_PRINT1 (" %04X", GREF (gstring, i)->c);
2537 for (i = 0; i < 3; i++)
2540 memset (&ctx, 0, sizeof ctx);
2541 ctx.match_indices = match_indices;
2543 ctx.cluster_begin_idx = -1;
2546 j = run_stages (gstring, this_from, this_to, flt, &ctx);
2560 MDEBUG_PRINT ("\n [FLT] (RESULT");
2561 if (MDEBUG_FLAG () > 1)
2562 for (i = 0; this_from < this_to; this_from++, i++)
2564 if (i > 0 && i % 4 == 0)
2565 MDEBUG_PRINT ("\n [FLT] ");
2566 g = GREF (gstring, this_from);
2567 MDEBUG_PRINT4 (" (%04X %d %d %d)",
2568 g->code, g->xadv, g->xoff, g->yoff);
2571 for (; this_from < this_to; this_from++)
2572 MDEBUG_PRINT1 (" %04X", GREF (gstring, this_from)->code);
2573 MDEBUG_PRINT ("))\n");
2575 this_from = this_to;
2580 int len = to - from;
2583 memcpy (((char *) out.glyphs),
2584 ((char *) gstring->glyphs) + gstring->glyph_size * from,
2585 gstring->glyph_size * len);
2586 for (i = from, j = to; i < to;)
2588 for (k = i + 1, j--; k < to && GREF (&out, k)->xadv == 0;
2590 GCPY (&out, i, (k - i), gstring, j);
2599 /* for debugging... */
2602 dump_flt_cmd (FontLayoutStage *stage, int id, int indent)
2604 char *prefix = (char *) alloca (indent + 1);
2606 memset (prefix, 32, indent);
2610 fprintf (stderr, "0x%02X", id);
2611 else if (id <= CMD_ID_OFFSET_INDEX)
2613 int idx = CMD_ID_TO_INDEX (id);
2614 FontLayoutCmd *cmd = stage->cmds + idx;
2616 if (cmd->type == FontLayoutCmdTypeRule)
2618 FontLayoutCmdRule *rule = &cmd->body.rule;
2621 fprintf (stderr, "(rule ");
2622 if (rule->src_type == SRC_REGEX)
2623 fprintf (stderr, "\"%s\"", rule->src.re.pattern);
2624 else if (rule->src_type == SRC_INDEX)
2625 fprintf (stderr, "%d", rule->src.match_idx);
2626 else if (rule->src_type == SRC_SEQ)
2627 fprintf (stderr, "(seq)");
2628 else if (rule->src_type == SRC_RANGE)
2629 fprintf (stderr, "(range)");
2631 fprintf (stderr, "(invalid src)");
2633 for (i = 0; i < rule->n_cmds; i++)
2635 fprintf (stderr, "\n%s ", prefix);
2636 dump_flt_cmd (stage, rule->cmd_ids[i], indent + 2);
2638 fprintf (stderr, ")");
2640 else if (cmd->type == FontLayoutCmdTypeCond)
2642 FontLayoutCmdCond *cond = &cmd->body.cond;
2645 fprintf (stderr, "(cond");
2646 for (i = 0; i < cond->n_cmds; i++)
2648 fprintf (stderr, "\n%s ", prefix);
2649 dump_flt_cmd (stage, cond->cmd_ids[i], indent + 2);
2651 fprintf (stderr, ")");
2653 else if (cmd->type == FontLayoutCmdTypeOTF)
2655 fprintf (stderr, "(otf)");
2658 fprintf (stderr, "(error-command)");
2660 else if (id <= CMD_ID_OFFSET_COMBINING)
2661 fprintf (stderr, "cominging-code");
2663 fprintf (stderr, "(predefiend %d)", id);
2667 mdebug_dump_flt (MFLT *flt, int indent)
2669 char *prefix = (char *) alloca (indent + 1);
2673 memset (prefix, 32, indent);
2675 fprintf (stderr, "(flt");
2676 MPLIST_DO (plist, flt->stages)
2678 FontLayoutStage *stage = (FontLayoutStage *) MPLIST_VAL (plist);
2681 fprintf (stderr, "\n%s (stage %d", prefix, stage_idx);
2682 for (i = 0; i < stage->used; i++)
2684 fprintf (stderr, "\n%s ", prefix);
2685 dump_flt_cmd (stage, INDEX_TO_CMD_ID (i), indent + 4);
2687 fprintf (stderr, ")");
2690 fprintf (stderr, ")");