(mdebug_dump_flt): Change return value to (MFLT *).
[m17n/m17n-lib.git] / src / m17n-flt.c
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
5
6    This file is part of the m17n library.
7
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.
12
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.
17
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,
21    02111-1307, USA.  */
22
23 /***en
24     @addtogroup m17nFLT
25     @brief FLT support for a window system.
26
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.  */
30
31 /***ja
32     @addtogroup m17nFLT
33     @brief ¥¦¥£¥ó¥É¥¦¥·¥¹¥Æ¥à¤Î¤¿¤á¤Î FLT ¥µ¥Ý¡¼¥È.
34
35     ¤³¤Î¥»¥¯¥·¥ç¥ó¤Ç¤Ï¡¢FLT (Font Layout Table)
36     ¤òÍѤ¤¤¿Ê¸»ú¥ì¥¤¥¢¥¦¥Èµ¡Ç½¤Ë´Ø¤¹¤ë m17n FLT API ¤òÄêµÁ¤¹¤ë¡£
37     FLT ¤Î·Á¼°¤Ï @ref mdbFLT ¤Ëµ­½Ò¤µ¤ì¤Æ¤¤¤ë¡£  */
38
39 /*=*/
40
41 #if !defined (FOR_DOXYGEN) || defined (DOXYGEN_INTERNAL_MODULE)
42 /*** @addtogroup m17nInternal
43      @{ */
44
45 #include "config.h"
46
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <ctype.h>
51 #include <sys/types.h>
52 #include <regex.h>
53
54 #include "m17n-core.h"
55 #include "m17n-flt.h"
56 #include "m17n-misc.h"
57 #include "internal.h"
58 #include "mtext.h"
59 #include "symbol.h"
60 #include "plist.h"
61 #include "database.h"
62 #include "internal-flt.h"
63
64 /* Font Layouter */
65
66 /* Font Layout Table (FLT)
67
68 Predefined terms: SYMBOL, INTEGER, STRING
69
70 FLT ::= '(' STAGE + ')'
71
72 STAGE ::= CATEGORY-TABLE ? FONT-LAYOUT-RULE
73
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.
79
80 CATEGORY-TABLE ::=
81         '(' 'category' CATEGORY-SPEC + ')'
82 CATEGORY-SPEC ::=
83         '(' CODE [ CODE ] CATEGORY ')'
84 CODE ::= INTEGER
85 CATEGORY ::= INTEGER
86 ;; ASCII character codes of alphabet ('A' .. 'Z' 'a' .. 'z').
87 ;; Ex: CATEGORY-TABLE
88 ;; (category
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.
93
94 FONT-LAYOUT-RULE ::=
95         '(' 'generator' RULE MACRO-DEF * ')'
96
97 RULE ::= COMMAND | REGEXP-RULE | MATCH-RULE | MAP-RULE
98          | COND-STRUCT | MACRO-NAME
99
100 COMMAND ::=
101         DIRECT-CODE | COMBINING | PREDEFIND-COMMAND | OTF-COMMAND
102
103 DIRECT-CODE ::= INTEGER
104 ;; Always succeed.  Produce the code.  Consume no source.
105
106 PREDEFIND-COMMAND ::=
107         '=' | '*' | '<' | '>' | '|'
108
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.
111
112 ;; '*': If the the previous command succeeded, repeat it until it
113 ;; fails.  
114
115 ;; '<': Produce a special code that indicates the start of grapheme
116 ;; cluster.  Succeed always, consume nothing.
117
118 ;; '>': Produce a special code that indicates the end of grapheme
119 ;; cluster.  Succeed always, consume nothing.
120
121 ;; '|': Produce a special code whose category is ' '.  Succeed always,
122 ;; consume nothing.
123
124 OTF-COMMAND ::=
125         'otf:''SCRIPT'[':'['LANGSYS'][':'[GSUB-FEATURES][':'GPOS-FEATURES]]]
126 ;; Run the Open Type Layout Table on the current run.  Succeed always,
127 ;; consume nothing.
128
129 SCRIPT ::= OTF-TAG
130 ;;      OTF's ScriptTag name (four letters) listed at:
131 ;;      <http://www.microsoft.om/typograph/otspec/scripttags.htm>
132 LANGSYS ::= OTF-TAG
133 ;;      OTF's Language System name (four letters) listed at:
134 ;;      <http://www.microsoft.om/typograph/otspec/languagetags.htm>
135
136 GSUB-FEATURES ::= [FEATURE[,FEATURE]*] | ' '
137 GPOS-FEATURES ::= [FEATURE[,FEATURE]*] | ' '
138 FEATURE ::= OTF-TAG
139 ;;      OTF's Feature name (four letters) listed at:
140 ;;      <http://www.microsoft.om/typograph/otspec/???.htm>
141
142 OTF-TAG ::= PRINTABLE-CHAR PRINTABLE-CHAR PRINTABLE-CHAR PRINTABLE-CHAR
143
144 ;; Ex. OTF-COMMAND
145 ;; 'otf:deva'
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.
149 ;; 'otf:deva:: :'
150 ;;      Run all GSUB features, run no GPOS features.
151
152 REGEXP-RULE ::=
153         '(' REGEXP RULE * ')'
154
155 ;; Succeed if REGXP matches the head of source.  Run RULEs while
156 ;; limiting the source to the matching part.  Consume that part.
157
158 REGEXP ::= STRING
159 ;; Must be composed only from ASCII characters.  'A' - 'Z', 'a' - 'z'
160 ;; correspond to CATEGORY.
161
162 ;; Ex: REGEXP-RULE
163 ;; ("VA?"
164 ;;   < | vowel * | >)
165
166 MATCH-RULE ::=
167         '(' MATCH-IDX RULE * ')'
168
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
172 ;; nothing.
173
174 MATCH-IDX ::= INTEGER
175 ;; Must be 0..20.
176
177 ;; Ex. MATCH-RULE
178 ;; (2 consonant *)
179
180 MAP-RULE ::=
181         '(' ( SOURCE-SEQ | SOURCE-RANGE ) RULE * ')'
182
183 ;; Succeed if the source matches SOURCE-SEQ or SOURCE-RANGE.  Run
184 ;; RULEs while limiting the source to the matching part.  Consume that
185 ;; part.
186
187 SOURCE-SEQ ::=
188         '(' CODE + ')'
189 SOURCE-RANGE ::=
190         '(' 'range' CODE CODE ')'
191 ;; Ex. MAP-RULE
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)).
197
198 COND-STRUCT ::=
199         '(' 'cond' RULE + ')'
200
201 ;; Try each rule in sequence until one succeeds.  Succeed if one
202 ;; succeeds.  Consume nothing.
203
204 ;; Ex. COND-STRUCT
205 ;; (cond
206 ;;  ((0x0915 0x094D)            0x43)
207 ;;  ((range 0x0F40 0x0F6A)      0x2221)
208 ;;  = )
209
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
217
218 ;; VH pair indicates 12 reference points of a glyph as below:
219 ;;
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)
232 ;;
233 ;; Ex. COMBINING
234 ;; 'tc.bc':
235 ;;      Align top-left point of the previous glyph and bottom-center
236 ;;      point of the current glyph.
237 ;; 'Bl<20-10Br'
238 ;;      Align 20% left and 10% below of base-left point of the previous
239 ;;      glyph and base-right point of the current glyph.
240
241 MACRO-DEF ::=
242         '(' MACRO-NAME RULE + ')'
243 MACRO-NAME ::= SYMBOL
244
245 */
246
247 static int mdebug_flag = MDEBUG_FLT;
248
249 MSymbol Mfont, Mlayouter, Mcombining;
250
251 static MSymbol Mgenerator, Mend;
252
253 static MPlist *flt_list;
254 static int flt_min_coverage, flt_max_coverage;
255
256 enum GlyphInfoMask
257 {
258   CombiningCodeMask = 0xFFFFFFF,
259   LeftPaddingMask = 1 << 28,
260   RightPaddingMask = 1 << 29
261 };
262
263 #define SET_GLYPH_INFO(g, mask, ctx, info)                      \
264   ((g)->internal = (((g)->internal & ~(mask)) | (info)),        \
265    (ctx)->check_mask |= (mask))
266
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))
280
281 #define GINIT(gstring, n)                                       \
282   do {                                                          \
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;                                        \
288   } while (0)
289
290 #define GALLOCA (gstring)       \
291   ((MFLTGlyph *) alloca ((gstring)->glyph_size))
292
293 #define GREF(gstring, idx)      \
294   ((MFLTGlyph *) ((char *) ((gstring)->glyphs) + (gstring)->glyph_size * (idx)))
295
296 #define PREV(gstring, g)        \
297   ((MFLTGlyph *) ((char *) (g) - (gstring)->glyph_size))
298
299 #define NEXT(gstring, g)        \
300   ((MFLTGlyph *) ((char *) (g) + (gstring)->glyph_size))
301
302 #define GCPY(src, src_idx, n, tgt, tgt_idx)                             \
303   do {                                                                  \
304     memcpy ((char *) ((tgt)->glyphs) + (tgt)->glyph_size * (tgt_idx),   \
305             (char *) ((src)->glyphs) + (src)->glyph_size * (src_idx),   \
306             (src)->glyph_size * (n));                                   \
307   } while (0)
308
309 #define GDUP(ctx, idx)                          \
310   do {                                          \
311     MFLTGlyphString *src = (ctx)->in;           \
312     MFLTGlyphString *tgt = (ctx)->out;          \
313     if (tgt->allocated <= tgt->used)            \
314       return -2;                                \
315     GCPY (src, (idx), 1, tgt, tgt->used);       \
316     tgt->used++;                                \
317   } while (0)
318
319 static int
320 GREPLACE (MFLTGlyphString *src, int src_from, int src_to,
321           MFLTGlyphString *tgt, int tgt_from, int tgt_to)
322 {
323   int src_len = src_to - src_from;
324   int tgt_len = tgt_to - tgt_from;
325   int inc = src_len - tgt_len;
326
327   if (tgt->allocated < tgt->used + inc)
328     return -2;
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));
333   if (src_len)
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);
337   tgt->used += inc;
338   return 0;
339 }
340
341
342 /* Command ID:
343                  0 ...          : direct code
344                    -1           : invalid
345              -0x0F .. -2        : builtin commands
346         -0x100000F .. -0x10     : combining code
347                   ... -0x1000010: index to FontLayoutStage->cmds
348  */
349
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
354
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 /* ']' */
363
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))
366
367 #define CMD_ID_TO_INDEX(id) (CMD_ID_OFFSET_INDEX - (id))
368 #define INDEX_TO_CMD_ID(idx) (CMD_ID_OFFSET_INDEX - (idx))
369
370 static MSymbol Mcond, Mrange, Mfont_facility, Mequal;
371
372 #define GLYPH_CODE_P(code)      \
373   ((code) >= GLYPH_CODE_MIN && (code) <= GLYPH_CODE_MAX)
374
375 #define GLYPH_CODE_INDEX(code) ((code) - GLYPH_CODE_MIN)
376
377 #define UPDATE_CLUSTER_RANGE(ctx, g)            \
378   do {                                          \
379     if (ctx->cluster_begin_pos > (g)->from)     \
380       ctx->cluster_begin_pos = (g)->from;       \
381     if (ctx->cluster_end_pos < (g)->to)         \
382       ctx->cluster_end_pos = (g)->to;           \
383   } while (0)
384
385 enum FontLayoutCmdRuleSrcType
386   {
387     SRC_REGEX,
388     SRC_INDEX,
389     SRC_SEQ,
390     SRC_RANGE,
391     SRC_HAS_GLYPH,
392     SRC_OTF_SPEC
393   };
394
395 typedef struct
396 {
397   enum FontLayoutCmdRuleSrcType src_type;
398   union {
399     struct {
400       char *pattern;
401       regex_t preg;
402     } re;
403     int match_idx;
404     struct {
405       int n_codes;
406       int *codes;
407     } seq;
408     struct {
409       int from, to;
410     } range;
411     struct {
412       int len;
413       MPlist *codes;
414       MFLTOtfSpec otf_spec;
415     } facility;
416   } src;
417
418   int n_cmds;
419   int *cmd_ids;
420 } FontLayoutCmdRule;
421
422 typedef struct
423 {
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;
428
429   int n_cmds;
430   int *cmd_ids;
431 } FontLayoutCmdCond;
432
433 enum FontLayoutCmdType
434   {
435     FontLayoutCmdTypeRule,
436     FontLayoutCmdTypeCond,
437     FontLayoutCmdTypeOTF,
438     FontLayoutCmdTypeMAX
439   };
440
441 typedef struct
442 {
443   enum FontLayoutCmdType type;
444   union {
445     FontLayoutCmdRule rule;
446     FontLayoutCmdCond cond;
447     MFLTOtfSpec otf;
448   } body;
449 } FontLayoutCmd;
450
451 typedef struct 
452 {
453   MCharTable *category;
454   int size, inc, used;
455   FontLayoutCmd *cmds;
456 } FontLayoutStage;
457
458 struct _MFLT
459 {
460   MSymbol name;
461   MSymbol family;
462   MSymbol registry;
463   MFLTOtfSpec otf;
464   MDatabase *mdb;
465   MCharTable *coverage;
466   MPlist *stages;
467 };
468
469 /* Font layout table loader */
470
471 static int parse_otf_command (MSymbol symbol, MFLTOtfSpec *spec);
472
473 /* Load a category table from PLIST.  PLIST has this form:
474       PLIST ::= ( FROM-CODE TO-CODE ? CATEGORY-CHAR ) *
475 */
476
477 static MCharTable *
478 load_category_table (MPlist *plist)
479 {
480   MCharTable *table;
481
482   table = mchartable (Minteger, (void *) 0);
483
484   MPLIST_DO (plist, plist)
485     {
486       MPlist *elt;
487       int from, to, category_code;
488
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))
501         {
502           category_code = to;
503           to = from;
504         }
505       else
506         {
507           if (! MPLIST_INTEGER_P (elt))
508             MERROR (MERROR_FONT, NULL);
509           category_code = MPLIST_INTEGER (elt);
510         }
511       if (! isalnum (category_code))
512         MERROR (MERROR_FONT, NULL);
513
514       if (from == to)
515         mchartable_set (table, from, (void *) category_code);
516       else
517         mchartable_set_range (table, from, to, (void *) category_code);
518     }
519
520   return table;
521 }
522
523 static unsigned int
524 gen_otf_tag (char *p)
525 {
526   unsigned int tag = 0;
527   int i;
528
529   for (i = 0; i < 4 && *p; i++, p++)
530     tag = (tag << 8) | *p;
531   for (; i < 4; i++)
532     tag = (tag << 8) | 0x20;
533   return tag;
534 }
535
536 static char *
537 otf_count_features (char *p, char *end, char stopper, int *count)
538 {
539   int negative = 0;
540
541   *count = 0;
542   if (*p != stopper && *p != '\0')
543     while (1)
544       {
545         (*count)++;
546         if (*p == '*')
547           {
548             p++;
549             if (*p == stopper || *p == '\0')
550               break;
551             return NULL;
552           }
553         if (*p == '~')
554           {
555             if (negative++ == 0)
556               (*count)++;
557             p += 5;
558           }
559         else 
560           p += 4;
561         if (p > end)
562           return NULL;
563         if (*p == stopper || *p == '\0')
564           break;
565         if (*p != ',')
566           return NULL;
567         p++;
568         if (! *p)
569           return NULL;
570       }
571   return p;
572 }
573
574 static void
575 otf_store_features (char *p, char *end, unsigned *buf)
576 {
577   int negative = 0;
578   int i;
579
580   for (i = 0; p < end;)
581     {
582       if (*p == '*')
583         buf[i++] = 0xFFFFFFFF, p += 2, negative = 1;
584       else if (*p == '~')
585         {
586           if (negative++ == 0)
587             buf[i++] = 0xFFFFFFFF;
588           buf[i++] = gen_otf_tag (p + 1), p += 6;
589         }
590       else
591         buf[i++] = gen_otf_tag (p), p += 5;
592     }
593   buf[i] = 0;
594 }
595
596 static int
597 parse_otf_command (MSymbol symbol, MFLTOtfSpec *spec)
598 {
599   char *str = MSYMBOL_NAME (symbol);
600   char *end = str + MSYMBOL_NAMELEN (symbol);
601   unsigned int script, langsys;
602   char *gsub, *gpos;
603   int gsub_count = 0, gpos_count = 0;
604   char *p;
605
606   memset (spec, 0, sizeof (MFLTOtfSpec));
607
608   spec->sym = symbol;
609   str += 5;                     /* skip the heading ":otf=" */
610   script = gen_otf_tag (str);
611   str += 4;
612   if (*str == '/')
613     {
614       langsys = gen_otf_tag (str);
615       str += 4;
616     }
617   else
618     langsys = 0;
619   gsub = str;
620   if (*str != '=')
621     /* Apply all GSUB features.  */
622       gsub_count = 1;
623   else
624     {
625       p = str + 1;
626       str = otf_count_features (p, end, '+', &gsub_count);
627       if (! str)
628         MERROR (MERROR_FLT, -1);
629     }
630   gpos = str;
631   if (*str != '+')
632     /* Apply all GPOS features.  */
633     gpos_count = 1;
634   else
635     {
636       p = str + 1;
637       str = otf_count_features (p, end, '\0', &gpos_count);
638       if (! str)
639         MERROR (MERROR_FLT, -1);
640     }
641
642   spec->script = script;
643   spec->langsys = langsys;
644   if (gsub_count > 0)
645     {
646       spec->features[0] = malloc (sizeof (int) * (gsub_count + 1));
647       if (! spec->features[0])
648         return -2;
649       if (*gsub == '=')
650         otf_store_features (gsub + 1, gpos, spec->features[0]);
651       else
652         spec->features[0][0] = 0xFFFFFFFF, spec->features[0][1] = 0;
653     }
654   if (gpos_count > 0)
655     {
656       spec->features[1] = malloc (sizeof (int) * (gpos_count + 1));
657       if (! spec->features[1])
658         {
659           if (spec->features[0])
660             free (spec->features[0]);
661           return -2;
662         }
663       if (*gpos == '+')
664         otf_store_features (gpos + 1, str, spec->features[1]);
665       else
666         spec->features[1][0] = 0xFFFFFFFF, spec->features[1][1] = 0;
667     }
668   return 0;
669 }
670
671
672 /* Parse OTF command name NAME and store the result in CMD.
673    NAME has this form:
674         :SCRIPT[/[LANGSYS][=[GSUB-FEATURES][+GPOS-FEATURES]]]
675    where GSUB-FEATURES and GPOS-FEATURES have this form:
676         [FEATURE[,FEATURE]*] | ' '  */
677
678 static int
679 load_otf_command (FontLayoutCmd *cmd, MSymbol sym)
680 {
681   char *name = MSYMBOL_NAME (sym);
682   int result;
683
684   if (name[0] != ':')
685     {
686       /* This is old format of "otf:...".  Change it to ":otf=...".  */
687       char *str = alloca (MSYMBOL_NAMELEN (sym) + 2);
688
689       sprintf (str, ":otf=");
690       strcat (str, name + 4);
691       sym = msymbol (str);
692     }
693
694   result = parse_otf_command (sym, &cmd->body.otf);
695   if (result == -2)
696     return result;
697   cmd->type = FontLayoutCmdTypeOTF;
698   return 0;
699 }
700
701
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.  */
705
706 static int
707 read_decimal_number (char **str)
708 {
709   char *p = *str;
710   int sign = (*p == '-' || *p == '<') ? -1 : 1;
711   int n = 0;
712
713   p++;
714   while (*p >= '0' && *p <= '9')
715     n = n * 10 + *p++ - '0';
716   *str = p;
717   if (n == 0)
718     n = 5;
719   return (n < 127 ? n * sign : 127 * sign);
720 }
721
722
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.  */
729
730 static int
731 read_combining_position (char *str, int *x, int *y)
732 {
733   int c = *str++;
734   int i;
735
736   /* Vertical position comes first.  */
737   for (i = 0; i < 4; i++)
738     if (c == "tcbB"[i])
739       {
740         *y = i;
741         break;
742       }
743   if (i == 4)
744     return -1;
745   c = *str;
746   /* Then comse horizontal position.  */
747   for (i = 0; i < 3; i++)
748     if (c == "lcr"[i])
749       {
750         *x = i;
751         return 0;
752       }
753   return -1;
754 }
755
756
757 /* Return a combining code corresponding to SYM.  */
758
759 static int
760 get_combining_command (MSymbol sym)
761 {
762   char *str = msymbol_name (sym);
763   int base_x, base_y, add_x, add_y, off_x, off_y;
764   int c;
765
766   if (read_combining_position (str, &base_x, &base_y) < 0)
767     return 0;
768   str += 2;
769   c = *str;
770   if (c == '.')
771     {
772       off_x = off_y = 128;
773       str++;
774     }
775   else
776     {
777       if (c == '+' || c == '-')
778         {
779           off_y = read_decimal_number (&str) + 128;
780           c = *str;
781         }
782       else
783         off_y = 128;
784       if (c == '<' || c == '>')
785         off_x = read_decimal_number (&str) + 128;
786       else
787         off_x = 128;
788     }
789   if (read_combining_position (str, &add_x, &add_y) < 0)
790     return 0;
791
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));
794 }
795
796
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.  */
802
803 static int
804 load_command (FontLayoutStage *stage, MPlist *plist,
805               MPlist *macros, int id)
806 {
807   int i;
808   int result;
809
810   if (MPLIST_INTEGER_P (plist))
811     {
812       int code = MPLIST_INTEGER (plist);
813
814       if (code < 0)
815         MERROR (MERROR_DRAW, INVALID_CMD_ID);
816       return code;
817     }
818   else if (MPLIST_PLIST_P (plist))
819     {
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;
827       FontLayoutCmd *cmd;
828
829       if (id == INVALID_CMD_ID)
830         {
831           FontLayoutCmd dummy;
832           id = INDEX_TO_CMD_ID (stage->used);
833           MLIST_APPEND1 (stage, cmds, dummy, MERROR_DRAW);
834         }
835       cmd = stage->cmds + CMD_ID_TO_INDEX (id);
836
837       if (MPLIST_SYMBOL_P (elt))
838         {
839           FontLayoutCmdCond *cond;
840
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;
848           cond->n_cmds = len;
849           MTABLE_CALLOC (cond->cmd_ids, len, MERROR_DRAW);
850           for (i = 0; i < len; i++, elt = MPLIST_NEXT (elt))
851             {
852               int this_id = load_command (stage, elt, macros, INVALID_CMD_ID);
853
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)
861                 {
862                   FontLayoutCmd *this_cmd
863                     = stage->cmds + CMD_ID_TO_INDEX (this_id);
864
865                   if (this_cmd->type == FontLayoutCmdTypeRule
866                       && this_cmd->body.rule.src_type == SRC_SEQ)
867                     {
868                       int first_char = this_cmd->body.rule.src.seq.codes[0];
869
870                       if (cond->seq_beg < 0)
871                         {
872                           /* The first SEQ command.  */
873                           cond->seq_beg = i;
874                           cond->seq_from = cond->seq_to = first_char;
875                         }
876                       else if (cond->seq_end < 0)
877                         {
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;
883                         }
884                     }
885                   else
886                     {
887                       if (cond->seq_beg >= 0 && cond->seq_end < 0)
888                         /* The previous one is the last SEQ command.  */
889                         cond->seq_end = i;
890                     }
891                 }
892               else
893                 {
894                   if (cond->seq_beg >= 0 && cond->seq_end < 0)
895                     /* The previous one is the last SEQ command.  */
896                     cond->seq_end = i;
897                 }
898             }
899           if (cond->seq_beg >= 0 && cond->seq_end < 0)
900             /* The previous one is the last SEQ command.  */
901             cond->seq_end = i;
902         }
903       else
904         {
905           cmd->type = FontLayoutCmdTypeRule;
906           if (MPLIST_MTEXT_P (elt))
907             {
908               MText *mt = MPLIST_MTEXT (elt);
909               char *str = (char *) MTEXT_DATA (mt);
910
911               if (str[0] != '^')
912                 {
913                   mtext_ins_char (mt, 0, '^', 1);
914                   str = (char *) MTEXT_DATA (mt);
915                 }
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);
920             }
921           else if (MPLIST_INTEGER_P (elt))
922             {
923               cmd->body.rule.src_type = SRC_INDEX;
924               cmd->body.rule.src.match_idx = MPLIST_INTEGER (elt);
925             }
926           else if (MPLIST_PLIST_P (elt))
927             {
928               MPlist *pl = MPLIST_PLIST (elt), *p;
929               int size = MPLIST_LENGTH (pl);
930
931               if (MPLIST_INTEGER_P (pl))
932                 {
933                   int i;
934
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,
938                                  MERROR_FONT);
939                   for (i = 0; i < size; i++, pl = MPLIST_NEXT (pl))
940                     {
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);
945                     }
946                 }
947               else if (MPLIST_SYMBOL_P (pl))
948                 {
949                   if (MPLIST_SYMBOL (pl) == Mrange)
950                     {
951                       if (size != 3)
952                         MERROR (MERROR_FLT, INVALID_CMD_ID);
953                       cmd->body.rule.src_type = SRC_RANGE;
954                       pl = MPLIST_NEXT (pl);
955                       if (! MPLIST_INTEGER_P (pl))
956                         MERROR (MERROR_DRAW, INVALID_CMD_ID);
957                       cmd->body.rule.src.range.from
958                         = (unsigned) MPLIST_INTEGER (pl);
959                       pl = MPLIST_NEXT (pl);
960                       if (! MPLIST_INTEGER_P (pl))
961                         MERROR (MERROR_DRAW, INVALID_CMD_ID);
962                       cmd->body.rule.src.range.to
963                         = (unsigned) MPLIST_INTEGER (pl);
964                     }
965                   else if (MPLIST_SYMBOL (pl) == Mfont_facility)
966                     {
967                       FontLayoutCmdRule *rule = &cmd->body.rule;
968
969                       pl = MPLIST_NEXT (pl);
970                       if (MPLIST_SYMBOL_P (pl))
971                         {
972                           MSymbol sym = MPLIST_SYMBOL (pl);
973                           char *otf_spec = MSYMBOL_NAME (sym);
974
975                           if (otf_spec[0] == ':' && otf_spec[1] == 'o'
976                               && otf_spec[2] == 't' && otf_spec[3] == 'f')
977                             parse_otf_command (sym, &rule->src.facility.otf_spec);
978                           else
979                             MERROR (MERROR_FLT, INVALID_CMD_ID);
980                           rule->src_type = SRC_OTF_SPEC;
981                           pl = MPLIST_NEXT (pl);
982                         }
983                       else if (MPLIST_TAIL_P (pl))
984                         MERROR (MERROR_FLT, INVALID_CMD_ID);
985                       else
986                         rule->src_type = SRC_HAS_GLYPH;
987                       rule->src.facility.len = 0;
988                       MPLIST_DO (p, pl)
989                         {
990                           if (! MPLIST_INTEGER_P (p)
991                               && (MPLIST_SYMBOL_P (p)
992                                   ? MPLIST_SYMBOL (p) != Mequal
993                                   : 1))
994                             MERROR (MERROR_FLT, INVALID_CMD_ID);
995                           rule->src.facility.len++;
996                         }
997                       rule->src.facility.codes = pl;
998                       M17N_OBJECT_REF (pl);
999                     }
1000                 }
1001               else
1002                 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1003             }
1004           else
1005             MERROR (MERROR_DRAW, INVALID_CMD_ID);
1006
1007           elt = MPLIST_NEXT (elt);
1008           cmd->body.rule.n_cmds = len;
1009           MTABLE_CALLOC (cmd->body.rule.cmd_ids, len, MERROR_DRAW);
1010           for (i = 0; i < len; i++, elt = MPLIST_NEXT (elt))
1011             {
1012               int this_id = load_command (stage, elt, macros, INVALID_CMD_ID);
1013
1014               if (this_id == INVALID_CMD_ID || this_id == -2)
1015                 MERROR (MERROR_DRAW, this_id);
1016               /* The above load_command may relocate stage->cmds.  */
1017               cmd = stage->cmds + CMD_ID_TO_INDEX (id);
1018               cmd->body.rule.cmd_ids[i] = this_id;
1019             }
1020         }
1021     }
1022   else if (MPLIST_SYMBOL_P (plist))
1023     {
1024       MPlist *elt;
1025       MSymbol sym = MPLIST_SYMBOL (plist);
1026       char *name = msymbol_name (sym);
1027       int len = strlen (name);
1028       FontLayoutCmd cmd;
1029
1030       if (len > 4
1031           && ((name[0] == 'o' && name[1] == 't'
1032                && name[2] == 'f' && name[3] == ':')
1033               || (name[0] == ':' && name[1] == 'o' && name[2] == 't'
1034                   && name[3] == 'f' && name[4] == '=')))
1035         {
1036           result = load_otf_command (&cmd, sym);
1037           if (result < 0)
1038             return result;
1039           if (id == INVALID_CMD_ID)
1040             {
1041               id = INDEX_TO_CMD_ID (stage->used);
1042               MLIST_APPEND1 (stage, cmds, cmd, MERROR_DRAW);
1043             }
1044           else
1045             stage->cmds[CMD_ID_TO_INDEX (id)] = cmd;
1046           return id;
1047         }
1048
1049       if (len == 1)
1050         {
1051           if (*name == '=')
1052             return CMD_ID_COPY;
1053           else if (*name == '*')
1054             return CMD_ID_REPEAT;
1055           else if (*name == '<')
1056             return CMD_ID_CLUSTER_BEGIN;
1057           else if (*name == '>')
1058             return CMD_ID_CLUSTER_END;
1059           else if (*name == '|')
1060             return CMD_ID_SEPARATOR;
1061           else if (*name == '[')
1062             return CMD_ID_LEFT_PADDING;
1063           else if (*name == ']')
1064             return CMD_ID_RIGHT_PADDING;
1065           else
1066             id = 0;
1067         }
1068       else
1069         {
1070           id = get_combining_command (sym);
1071           if (id)
1072             return id;
1073         }
1074
1075       i = 1;
1076       MPLIST_DO (elt, macros)
1077         {
1078           if (sym == MPLIST_SYMBOL (MPLIST_PLIST (elt)))
1079             {
1080               id = INDEX_TO_CMD_ID (i);
1081               if (stage->cmds[i].type == FontLayoutCmdTypeMAX)
1082                 id = load_command (stage, MPLIST_NEXT (MPLIST_PLIST (elt)),
1083                                    macros, id);
1084               return id;
1085             }
1086           i++;
1087         }
1088       MERROR (MERROR_DRAW, INVALID_CMD_ID);
1089     }
1090   else
1091     MERROR (MERROR_DRAW, INVALID_CMD_ID);
1092
1093   return id;
1094 }
1095
1096 static void
1097 free_flt_command (FontLayoutCmd *cmd)
1098 {
1099   if (cmd->type == FontLayoutCmdTypeRule)
1100     {
1101       FontLayoutCmdRule *rule = &cmd->body.rule;
1102
1103       if (rule->src_type == SRC_REGEX)
1104         {
1105           free (rule->src.re.pattern);
1106           regfree (&rule->src.re.preg);
1107         }
1108       else if (rule->src_type == SRC_SEQ)
1109         free (rule->src.seq.codes);
1110       free (rule->cmd_ids);
1111     }
1112   else if (cmd->type == FontLayoutCmdTypeCond)
1113     free (cmd->body.cond.cmd_ids);
1114   else if (cmd->type == FontLayoutCmdTypeOTF)
1115     {
1116       if (cmd->body.otf.features[0])
1117         free (cmd->body.otf.features[0]);
1118       if (cmd->body.otf.features[1])
1119         free (cmd->body.otf.features[1]);
1120     }
1121 }
1122
1123 /* Load a generator from PLIST into a newly allocated FontLayoutStage,
1124    and return it.  PLIST has this form:
1125       PLIST ::= ( COMMAND ( CMD-NAME COMMAND ) * )
1126 */
1127
1128 static FontLayoutStage *
1129 load_generator (MPlist *plist)
1130 {
1131   FontLayoutStage *stage;
1132   MPlist *elt, *pl;
1133   FontLayoutCmd dummy;
1134   int result;
1135
1136   MSTRUCT_CALLOC (stage, MERROR_DRAW);
1137   MLIST_INIT1 (stage, cmds, 32);
1138   dummy.type = FontLayoutCmdTypeMAX;
1139   MLIST_APPEND1 (stage, cmds, dummy, MERROR_FONT);
1140   MPLIST_DO (elt, MPLIST_NEXT (plist))
1141     {
1142       if (! MPLIST_PLIST_P (elt))
1143         MERROR (MERROR_FONT, NULL);
1144       pl = MPLIST_PLIST (elt);
1145       if (! MPLIST_SYMBOL_P (pl))
1146         MERROR (MERROR_FONT, NULL);
1147       MLIST_APPEND1 (stage, cmds, dummy, MERROR_FONT);
1148     }
1149
1150   /* Load the first command from PLIST into STAGE->cmds[0].  Macros
1151      called in the first command are also loaded from MPLIST_NEXT
1152      (PLIST) into STAGE->cmds[n].  */
1153   result = load_command (stage, plist, MPLIST_NEXT (plist),
1154                          INDEX_TO_CMD_ID (0));
1155   if (result == INVALID_CMD_ID || result == -2)
1156     {
1157       MLIST_FREE1 (stage, cmds);
1158       free (stage);
1159       return NULL;
1160     }
1161
1162   return stage;
1163 }
1164
1165
1166 /* Load stages of the font layout table FLT.  */
1167
1168 static int
1169 load_flt (MFLT *flt, MPlist *key_list)
1170 {
1171   MPlist *top, *plist, *pl, *p;
1172   MCharTable *category = NULL;
1173   MSymbol sym;
1174
1175   if (key_list)
1176     top = (MPlist *) mdatabase__load_for_keys (flt->mdb, key_list);
1177   else
1178     top = (MPlist *) mdatabase_load (flt->mdb);
1179   if (! top)
1180     return -1;
1181   if (! MPLIST_PLIST_P (top))
1182     {
1183       M17N_OBJECT_UNREF (top);
1184       MERROR (MERROR_FLT, -1);
1185     }
1186
1187   if (key_list)
1188     {
1189       plist = mdatabase__props (flt->mdb);
1190       if (! plist)
1191         MERROR (MERROR_FLT, -1);
1192       MPLIST_DO (plist, plist)
1193         if (MPLIST_PLIST_P (plist))
1194           {
1195             pl = MPLIST_PLIST (plist);
1196             if (! MPLIST_SYMBOL_P (pl)
1197                 || MPLIST_SYMBOL (pl) != Mfont)
1198               continue;
1199             pl = MPLIST_NEXT (pl);
1200             if (! MPLIST_PLIST_P (pl))
1201               continue;
1202             p = MPLIST_PLIST (pl);
1203             if (! MPLIST_SYMBOL_P (p))
1204               continue;
1205             p = MPLIST_NEXT (p);
1206             if (! MPLIST_SYMBOL_P (p))
1207               continue;
1208             flt->family = MPLIST_SYMBOL (p);
1209             MPLIST_DO (p, MPLIST_NEXT (p))
1210               if (MPLIST_SYMBOL_P (p))
1211                 {
1212                   sym = MPLIST_SYMBOL (p);
1213                   if (MSYMBOL_NAME (sym)[0] != ':')
1214                     flt->registry = sym, sym = Mnil;
1215                   else
1216                     break;
1217                 }
1218             if (sym)
1219               {
1220                 char *otf_spec = MSYMBOL_NAME (sym);
1221
1222                 if (otf_spec[0] == ':' && otf_spec[1] == 'o'
1223                     && otf_spec[2] == 't' && otf_spec[3] == 'f')
1224                   parse_otf_command (sym, &flt->otf);
1225               }
1226             break;
1227           }
1228     }
1229   MPLIST_DO (plist, top)
1230     {
1231       if (MPLIST_SYMBOL_P (plist)
1232           && MPLIST_SYMBOL (plist) == Mend)
1233         {
1234           mplist_set (plist, Mnil, NULL);
1235           break;
1236         }
1237       if (! MPLIST_PLIST (plist))
1238         continue;
1239       pl = MPLIST_PLIST (plist);
1240       if (! MPLIST_SYMBOL_P (pl))
1241         continue;
1242       sym = MPLIST_SYMBOL (pl);
1243       pl = MPLIST_NEXT (pl);
1244       if (! pl)
1245         continue;
1246       if (sym == Mcategory)
1247         {
1248           if (category)
1249             M17N_OBJECT_UNREF (category);
1250           else if (flt->coverage)
1251             {
1252               category = flt->coverage;
1253               continue;
1254             }
1255           category = load_category_table (pl);
1256           if (! flt->coverage)
1257             {
1258               flt->coverage = category;
1259               M17N_OBJECT_REF (category);
1260             }
1261         }
1262       else if (sym == Mgenerator)
1263         {
1264           FontLayoutStage *stage;
1265
1266           if (! category)
1267             break;
1268           stage = load_generator (pl);
1269           if (! stage)
1270             break;
1271           stage->category = category;
1272           M17N_OBJECT_REF (category);
1273           if (! flt->stages)
1274             flt->stages = mplist ();
1275           mplist_add (flt->stages, Mt, stage);
1276         }
1277     }
1278   if (category)
1279     M17N_OBJECT_UNREF (category);
1280   if (! MPLIST_TAIL_P (plist))
1281     {
1282       M17N_OBJECT_UNREF (top);
1283       M17N_OBJECT_UNREF (flt->stages);
1284       MERROR (MERROR_FLT, -1);
1285     }
1286   M17N_OBJECT_UNREF (top);
1287   return 0;
1288 }
1289
1290
1291 static void
1292 free_flt_stage (FontLayoutStage *stage)
1293 {
1294   int i;
1295
1296   M17N_OBJECT_UNREF (stage->category);
1297   for (i = 0; i < stage->used; i++)
1298     free_flt_command (stage->cmds + i);
1299   MLIST_FREE1 (stage, cmds);
1300   free (stage);
1301 }
1302
1303 static void
1304 free_flt_list ()
1305 {
1306   if (flt_list)
1307     {
1308       MPlist *plist, *pl;
1309
1310       MPLIST_DO (plist, flt_list)
1311         {
1312           MFLT *flt = MPLIST_VAL (plist);
1313
1314           if (flt->coverage)
1315             M17N_OBJECT_UNREF (flt->coverage);
1316           if (flt->stages)
1317             {
1318               MPLIST_DO (pl, MPLIST_NEXT (flt->stages))
1319                 free_flt_stage (MPLIST_VAL (pl));
1320               M17N_OBJECT_UNREF (flt->stages);
1321             }
1322         }
1323       M17N_OBJECT_UNREF (flt_list);
1324     }
1325 }
1326
1327 static int
1328 list_flt ()
1329 {
1330   MPlist *plist, *key_list = NULL;
1331   MPlist *pl;
1332   int result = 0;
1333
1334   if (! (plist = mdatabase_list (Mfont, Mlayouter, Mnil, Mnil)))
1335     return -1;
1336   if (! (flt_list = mplist ()))
1337     goto err;
1338   if (! (key_list = mplist ()))
1339     goto err;
1340   if (! mplist_add (key_list, Mcategory, Mt))
1341     goto err;
1342
1343   MPLIST_DO (pl, plist)
1344     {
1345       MDatabase *mdb = MPLIST_VAL (pl);
1346       MSymbol *tags = mdatabase_tag (mdb);
1347       MFLT *flt;
1348
1349       if (! MSTRUCT_CALLOC_SAFE (flt))
1350         goto err;
1351       flt->name = tags[2];
1352       flt->mdb = mdb;
1353       if (load_flt (flt, key_list) < 0)
1354         free (flt);
1355       else
1356         {
1357           if (MPLIST_TAIL_P (flt_list))
1358             {
1359               flt_min_coverage = mchartable_min_char (flt->coverage);
1360               flt_max_coverage = mchartable_max_char (flt->coverage);
1361             }
1362           else
1363             {
1364               int c;
1365
1366               c = mchartable_min_char (flt->coverage);
1367               if (flt_min_coverage > c)
1368                 flt_min_coverage = c;
1369               c = mchartable_max_char (flt->coverage);
1370               if (flt_max_coverage < c)
1371                 flt_max_coverage = c;
1372             }
1373           if (! mplist_push (flt_list, flt->name, flt))
1374             goto err;
1375         }
1376     }
1377   goto end;
1378
1379  err:
1380   free_flt_list ();
1381   result = -1;
1382  end:
1383   M17N_OBJECT_UNREF (plist);  
1384   M17N_OBJECT_UNREF (key_list);
1385   return result;
1386 }
1387
1388 /* FLS (Font Layout Service) */
1389
1390 /* Structure to hold information about a context of FLS.  */
1391
1392 typedef struct
1393 {
1394   /* Pointer to the current stage.  */
1395   FontLayoutStage *stage;
1396
1397   /* Pointer to the font.  */
1398   MFLTFont *font;
1399
1400   /* Input and output glyph string.  */
1401   MFLTGlyphString *in, *out;
1402
1403   /* Encode each character or code of a glyph by the current category
1404      table into this array.  An element is a category letter used for
1405      a regular expression matching.  */
1406   char *encoded;
1407   int encoded_offset;
1408   int *match_indices;
1409   int code_offset;
1410   int cluster_begin_idx;
1411   int cluster_begin_pos;
1412   int cluster_end_pos;
1413   int combining_code;
1414   int left_padding;
1415   int check_mask;
1416 } FontLayoutContext;
1417
1418 static int run_command (int, int, int, int, FontLayoutContext *);
1419
1420 #define NMATCH 20
1421
1422 static int
1423 run_rule (int depth,
1424           FontLayoutCmdRule *rule, int from, int to, FontLayoutContext *ctx)
1425 {
1426   int *saved_match_indices = ctx->match_indices;
1427   int match_indices[NMATCH * 2];
1428   int consumed;
1429   int i;
1430   int orig_from = from;
1431   int need_cluster_update = 0;
1432
1433   if (rule->src_type == SRC_REGEX)
1434     {
1435       regmatch_t pmatch[NMATCH];
1436       char saved_code;
1437       int result;
1438
1439       if (from > to)
1440         return 0;
1441       saved_code = ctx->encoded[to - ctx->encoded_offset];
1442       ctx->encoded[to - ctx->encoded_offset] = '\0';
1443       result = regexec (&(rule->src.re.preg),
1444                         ctx->encoded + (from - ctx->encoded_offset),
1445                         NMATCH, pmatch, 0);
1446       if (result == 0 && pmatch[0].rm_so == 0)
1447         {
1448           if (MDEBUG_FLAG () > 2)
1449             MDEBUG_PRINT5 ("\n [FLT] %*s(REGEX \"%s\" \"%s\" %d", depth, "",
1450                            rule->src.re.pattern,
1451                            ctx->encoded + (from - ctx->encoded_offset),
1452                            pmatch[0].rm_eo);
1453           ctx->encoded[to - ctx->encoded_offset] = saved_code;
1454           for (i = 0; i < NMATCH; i++)
1455             {
1456               if (pmatch[i].rm_so < 0)
1457                 match_indices[i * 2] = match_indices[i * 2 + 1] = -1;
1458               else
1459                 {
1460                   match_indices[i * 2] = from + pmatch[i].rm_so;
1461                   match_indices[i * 2 + 1] = from + pmatch[i].rm_eo;
1462                 }
1463             }
1464           ctx->match_indices = match_indices;
1465           to = match_indices[1];
1466         }
1467       else
1468         {
1469           ctx->encoded[to - ctx->encoded_offset] = saved_code;
1470           return 0;
1471         }
1472       need_cluster_update = 1;
1473     }
1474   else if (rule->src_type == SRC_SEQ)
1475     {
1476       int len;
1477
1478       len = rule->src.seq.n_codes;
1479       if (len > (to - from))
1480         return 0;
1481       for (i = 0; i < len; i++)
1482         if (rule->src.seq.codes[i] != GREF (ctx->in, from + i)->code)
1483           break;
1484       if (i < len)
1485         return 0;
1486       to = from + len;
1487       if (MDEBUG_FLAG () > 2)
1488         MDEBUG_PRINT3 ("\n [FLT] %*s(SEQ 0x%X", depth, "",
1489                        rule->src.seq.codes[0]);
1490       need_cluster_update = 1;
1491     }
1492   else if (rule->src_type == SRC_RANGE)
1493     {
1494       int head;
1495
1496       if (from >= to)
1497         return 0;
1498       head = GREF (ctx->in, from)->code;
1499       if (head < rule->src.range.from || head > rule->src.range.to)
1500         return 0;
1501       ctx->code_offset = head - rule->src.range.from;
1502       to = from + 1;
1503       if (MDEBUG_FLAG () > 2)
1504         MDEBUG_PRINT4 ("\n [FLT] %*s(RANGE 0x%X-0x%X", depth, "",
1505                        rule->src.range.from, rule->src.range.to);
1506       need_cluster_update = 1;
1507     }
1508   else if (rule->src_type == SRC_INDEX)
1509     {
1510       if (rule->src.match_idx >= NMATCH)
1511         return 0;
1512       from = ctx->match_indices[rule->src.match_idx * 2];
1513       if (from < 0)
1514         return 0;
1515       to = ctx->match_indices[rule->src.match_idx * 2 + 1];
1516       if (MDEBUG_FLAG () > 2)
1517         MDEBUG_PRINT3 ("\n [FLT] %*s(SUBPART %d", depth, "",
1518                        rule->src.match_idx);
1519       need_cluster_update = 1;
1520     }
1521   else if (rule->src_type == SRC_HAS_GLYPH
1522            || rule->src_type == SRC_OTF_SPEC)
1523     {
1524       static MFLTGlyphString gstring;
1525       MPlist *p;
1526       int idx;
1527
1528       if (rule->src.facility.len > 0)
1529         {
1530           if (! gstring.glyph_size)
1531             {
1532               gstring.glyph_size = ctx->in->glyph_size;
1533               gstring.glyphs = calloc (rule->src.facility.len,
1534                                        gstring.glyph_size);
1535               gstring.allocated = rule->src.facility.len;
1536               gstring.used = rule->src.facility.len;
1537             }
1538           else if (rule->src.facility.len < gstring.allocated)
1539             {
1540               gstring.glyphs = realloc (gstring.glyphs,
1541                                         gstring.glyph_size
1542                                         * rule->src.facility.len);
1543               gstring.allocated = rule->src.facility.len;
1544               gstring.used = rule->src.facility.len;
1545             }
1546
1547           for (i = 0, p = rule->src.facility.codes, idx = from;
1548                i < rule->src.facility.len; i++, p = MPLIST_NEXT (p))
1549             {
1550               if (MPLIST_INTEGER_P (p))
1551                 {
1552                   GREF (&gstring, i)->code = MPLIST_INTEGER (p);
1553                   GREF (&gstring, i)->encoded = 0;
1554                 }
1555               else
1556                 {
1557                   GREF (&gstring, i)->code = GREF (ctx->in, idx)->code;
1558                   GREF (&gstring, i)->encoded = GREF (ctx->in, idx)->encoded;
1559                   idx++;
1560                 }
1561             }
1562         }
1563
1564       if (MDEBUG_FLAG () > 2)
1565         {
1566           if (rule->src_type == SRC_HAS_GLYPH)
1567             MDEBUG_PRINT2 ("\n [FLT] %*s(HAS-GLYPH", depth, "");
1568           else
1569             MDEBUG_PRINT2 ("\n [FLT] %*s(OTF-SPEC", depth, "");
1570           for (i = 0; i < rule->src.facility.len; i++)
1571             MDEBUG_PRINT1 (" %04X", GREF (&gstring, i)->code);
1572         }
1573       if (ctx->font->get_glyph_id (ctx->font, &gstring, 0,
1574                                    rule->src.facility.len) < 0)
1575         {
1576           MDEBUG_PRINT (") FAIL!");
1577           return 0;
1578         }
1579       if (rule->src_type == SRC_OTF_SPEC)
1580         {
1581           MFLTOtfSpec *spec = &rule->src.facility.otf_spec;
1582
1583           if (! ctx->font->check_otf)
1584             {
1585               if ((spec->features[0] && spec->features[0][0] != 0xFFFFFFFF)
1586                   || (spec->features[1] && spec->features[1][0] != 0xFFFFFFFF))
1587                 return 0;
1588             }
1589           else
1590             {
1591               if (rule->src.facility.len == 0)
1592                 {
1593                   if (! ctx->font->check_otf (ctx->font, spec))
1594                     return 0;
1595                 }
1596               else
1597                 {
1598                   int prev_out_used = ctx->out->used, out_used;
1599                   MFLTGlyphAdjustment *adjustment;
1600
1601                   adjustment = alloca ((sizeof *adjustment)
1602                                        * (ctx->out->allocated - ctx->out->used));
1603                   if (! adjustment)
1604                     MERROR (MERROR_FLT, -1);
1605                   memset (adjustment, 0,
1606                           (sizeof *adjustment)
1607                           * (ctx->out->allocated - ctx->out->used));
1608                   ctx->font->drive_otf (ctx->font, &rule->src.facility.otf_spec,
1609                                         &gstring, 0, rule->src.facility.len,
1610                                         ctx->out,
1611                                         adjustment);
1612                   out_used = ctx->out->used;
1613                   ctx->out->used = prev_out_used;
1614                   if (rule->src.facility.len == out_used - prev_out_used)
1615                     {
1616                       for (i = prev_out_used; i < out_used; i++)
1617                         {
1618                           if (GREF (&gstring, i - prev_out_used)->code
1619                               != GREF (ctx->out, i)->code)
1620                             break;
1621                           if (adjustment[i - prev_out_used].set)
1622                             break;
1623                         }
1624                       if (i == out_used)
1625                         return 0;
1626                     }
1627                 }
1628             }
1629         }
1630     }
1631
1632   if (need_cluster_update && ctx->cluster_begin_idx >= 0)
1633     {
1634       for (i = from; i < to; i++)
1635         {
1636           MFLTGlyph *g = GREF (ctx->in, i);
1637           UPDATE_CLUSTER_RANGE (ctx, g);
1638         }
1639     }
1640
1641   consumed = 0;
1642   depth++;
1643   for (i = 0; i < rule->n_cmds; i++)
1644     {
1645       int pos;
1646
1647       if (rule->cmd_ids[i] == CMD_ID_REPEAT)
1648         {
1649           if (! consumed)
1650             continue;
1651           i--;
1652         }
1653       pos = run_command (depth, rule->cmd_ids[i], from, to, ctx);
1654       if (pos < 0)
1655         return pos;
1656       consumed = pos > from;
1657       if (consumed)
1658         from = pos;
1659     }
1660
1661   ctx->match_indices = saved_match_indices;
1662   if (MDEBUG_FLAG () > 2)
1663     MDEBUG_PRINT (")");
1664   return (rule->src_type == SRC_INDEX ? orig_from : to);
1665 }
1666
1667 static int
1668 run_cond (int depth,
1669           FontLayoutCmdCond *cond, int from, int to, FontLayoutContext *ctx)
1670 {
1671   int i, pos = 0;
1672
1673   if (MDEBUG_FLAG () > 2)
1674     MDEBUG_PRINT2 ("\n [FLT] %*s(COND", depth, "");
1675   depth++;
1676   for (i = 0; i < cond->n_cmds; i++)
1677     {
1678       /* TODO: Write a code for optimization utilizaing the info
1679          cond->seq_XXX.  */
1680       if ((pos = run_command (depth, cond->cmd_ids[i], from, to, ctx))
1681           != 0)
1682         break;
1683     }
1684   if (pos < 0)
1685     return pos;
1686   if (MDEBUG_FLAG () > 2)
1687     MDEBUG_PRINT (")");
1688   return (pos);
1689 }
1690
1691 static int
1692 run_otf (int depth,
1693          MFLTOtfSpec *otf_spec, int from, int to, FontLayoutContext *ctx)
1694 {
1695   MFLTFont *font = ctx->font;
1696   int from_idx = ctx->out->used;
1697
1698   if (MDEBUG_FLAG () > 2)
1699     MDEBUG_PRINT3 ("\n [FLT] %*s%s", depth, "", MSYMBOL_NAME (otf_spec->sym));
1700
1701   font->get_glyph_id (font, ctx->in, from, to);
1702   if (! font->drive_otf)
1703     {
1704       if (ctx->out->used + (to - from) > ctx->out->allocated)
1705         return -2;
1706       font->get_metrics (font, ctx->in, from, to);
1707       GCPY (ctx->in, from, to - from, ctx->out, ctx->out->used);
1708       ctx->out->used += to - from;
1709     }
1710   else
1711     {
1712       MFLTGlyphAdjustment *adjustment;
1713       int out_len;
1714       int i;
1715
1716       adjustment = alloca ((sizeof *adjustment)
1717                            * (ctx->out->allocated - ctx->out->used));
1718       if (! adjustment)
1719         MERROR (MERROR_FLT, -1);
1720       memset (adjustment, 0,
1721               (sizeof *adjustment) * (ctx->out->allocated - ctx->out->used));
1722       to = font->drive_otf (font, otf_spec, ctx->in, from, to, ctx->out,
1723                             adjustment);
1724       if (to < 0)
1725         return to;
1726       out_len = ctx->out->used - from_idx;
1727       if (otf_spec->features[1])
1728         {
1729           MFLTGlyphAdjustment *a;
1730           MFLTGlyph *g;
1731           
1732           for (i = 0, a = adjustment; i < out_len; i++, a++)
1733             if (a->set)
1734               break;
1735           if (i < out_len)
1736             {
1737               font->get_metrics (font, ctx->out, from_idx, ctx->out->used);
1738               for (g = GREF (ctx->out, from_idx + i);
1739                    i < out_len; i++, a++, g = NEXT (ctx->out, g))
1740                 if (a->set)
1741                   {
1742                     if (a->advance_is_absolute)
1743                       {
1744                         g->xadv = a->xadv;
1745                         g->yadv = a->yadv;
1746                       }
1747                     else if (a->xadv || a->yadv)
1748                       {
1749                         g->xadv += a->xadv;
1750                         g->yadv += a->yadv;
1751                       }
1752                     if (a->xoff || a->yoff || a->back)
1753                       {
1754                         int j;
1755                         MFLTGlyph *gg = PREV (ctx->out, g);
1756                         MFLTGlyphAdjustment *aa = a;
1757
1758                         g->xoff = a->xoff;
1759                         g->yoff = a->yoff;
1760                         while (aa->back > 0)
1761                           {
1762                             for (j = 0; j < aa->back;
1763                                  j++, gg = PREV (ctx->out, gg))
1764                               {
1765                                 g->xoff -= gg->xadv;
1766                                 g->lbearing -= gg->xadv;
1767                                 g->rbearing -= gg->xadv;
1768                               }
1769                             aa = aa - aa->back;
1770                             g->xoff += aa->xoff;
1771                             g->yoff += aa->yoff;
1772                             g->lbearing += aa->xoff;
1773                             g->rbearing += aa->xoff;
1774                             g->ascent -= aa->yoff;
1775                             g->descent -= aa->yoff;
1776                           }
1777                       }
1778                     g->adjusted = 1;
1779                   }
1780             }
1781         }
1782     }
1783
1784   if (ctx->cluster_begin_idx >= 0)
1785     for (; from_idx < ctx->out->used; from_idx++)
1786       {
1787         MFLTGlyph *g = GREF (ctx->out, from_idx);
1788         UPDATE_CLUSTER_RANGE (ctx, g);
1789       }
1790   return to;
1791 }
1792
1793 static char work[16];
1794
1795 static char *
1796 dump_combining_code (int code)
1797 {
1798   char *vallign = "tcbB";
1799   char *hallign = "lcr";
1800   char *p;
1801   int off_x, off_y;
1802
1803   if (! code)
1804     return "none";
1805   work[0] = vallign[COMBINING_CODE_BASE_Y (code)];
1806   work[1] = hallign[COMBINING_CODE_BASE_X (code)];
1807   off_y = COMBINING_CODE_OFF_Y (code);
1808   off_x = COMBINING_CODE_OFF_X (code);
1809   if (off_y > 0)
1810     sprintf (work + 2, "+%d", off_y);
1811   else if (off_y < 0)
1812     sprintf (work + 2, "%d", off_y);
1813   else if (off_x == 0)
1814     sprintf (work + 2, ".");
1815   p = work + strlen (work);
1816   if (off_x > 0)
1817     sprintf (p, ">%d", off_x);
1818   else if (off_x < 0)
1819     sprintf (p, "<%d", -off_x);
1820   p += strlen (p);
1821   p[0] = vallign[COMBINING_CODE_ADD_Y (code)];
1822   p[1] = hallign[COMBINING_CODE_ADD_X (code)];
1823   p[2] = '\0';
1824   return work;
1825 }
1826
1827 static int
1828 run_command (int depth, int id, int from, int to, FontLayoutContext *ctx)
1829 {
1830   MFLTGlyph *g;
1831
1832   if (id >= 0)
1833     {
1834       int i;
1835
1836       /* Direct code (== ctx->code_offset + id) output.
1837          The source is not consumed.  */
1838       if (MDEBUG_FLAG () > 2)
1839         MDEBUG_PRINT3 ("\n [FLT] %*s(DIRECT 0x%X", depth, "",
1840                        ctx->code_offset + id);
1841       i = (from < to || from == 0) ? from : from - 1;
1842       GDUP (ctx, i);
1843       g = GREF (ctx->out, ctx->out->used - 1);
1844       g->c = g->code = ctx->code_offset + id;
1845       SET_ENCODED (g, 0);
1846       SET_MEASURED (g, 0);
1847       if (ctx->combining_code)
1848         SET_COMBINING_CODE (g, ctx, ctx->combining_code);
1849       if (ctx->left_padding)
1850         SET_LEFT_PADDING (g, ctx, LeftPaddingMask);
1851       for (i = from; i < to; i++)
1852         {
1853           MFLTGlyph *tmp = GREF (ctx->in, i);
1854
1855           if (g->from > tmp->from)
1856             g->from = tmp->from;
1857           else if (g->to < tmp->to)
1858             g->to = tmp->to;
1859         }
1860       if (ctx->cluster_begin_idx >= 0)
1861         UPDATE_CLUSTER_RANGE (ctx, g);
1862       ctx->code_offset = ctx->combining_code = ctx->left_padding = 0;
1863       if (MDEBUG_FLAG () > 2)
1864         MDEBUG_PRINT (")");
1865       return (from);
1866     }
1867
1868   if (id <= CMD_ID_OFFSET_INDEX)
1869     {
1870       int idx = CMD_ID_TO_INDEX (id);
1871       FontLayoutCmd *cmd;
1872
1873       if (idx >= ctx->stage->used)
1874         MERROR (MERROR_DRAW, -1);
1875       cmd = ctx->stage->cmds + idx;
1876       if (cmd->type == FontLayoutCmdTypeRule)
1877         to = run_rule (depth, &cmd->body.rule, from, to, ctx);
1878       else if (cmd->type == FontLayoutCmdTypeCond)
1879         to = run_cond (depth, &cmd->body.cond, from, to, ctx);
1880       else if (cmd->type == FontLayoutCmdTypeOTF)
1881         to = run_otf (depth, &cmd->body.otf, from, to, ctx);
1882       return to;
1883     }
1884
1885   if (id <= CMD_ID_OFFSET_COMBINING)
1886     {
1887       ctx->combining_code = CMD_ID_TO_COMBINING_CODE (id);
1888       if (MDEBUG_FLAG () > 2)
1889         MDEBUG_PRINT3 ("\n [FLT] %*s(CMB %s)", depth, "",
1890                        dump_combining_code (ctx->combining_code));
1891       return from;
1892     }
1893
1894   switch (id)
1895     {
1896     case CMD_ID_COPY:
1897       {
1898         if (from >= to)
1899           return from;
1900         GDUP (ctx, from);
1901         g = GREF (ctx->out, ctx->out->used - 1);
1902         if (ctx->combining_code)
1903           SET_COMBINING_CODE (g, ctx, ctx->combining_code);
1904         if (ctx->left_padding)
1905           SET_LEFT_PADDING (g, ctx, LeftPaddingMask);
1906         if (ctx->cluster_begin_idx >= 0)
1907           UPDATE_CLUSTER_RANGE (ctx, g);
1908         if (MDEBUG_FLAG () > 2)
1909           {
1910             if (g->c < 0)
1911               MDEBUG_PRINT2 ("\n [FLT] %*s(COPY |)", depth, "");
1912             else
1913               MDEBUG_PRINT3 ("\n [FLT] %*s(COPY 0x%X)", depth, "", g->code);
1914           }
1915         ctx->code_offset = ctx->combining_code = ctx->left_padding = 0;
1916         return (from + 1);
1917       }
1918
1919     case CMD_ID_CLUSTER_BEGIN:
1920       if (ctx->cluster_begin_idx < 0)
1921         {
1922           if (MDEBUG_FLAG () > 2)
1923             MDEBUG_PRINT3 ("\n [FLT] %*s<%d", depth, "",
1924                            GREF (ctx->in, from)->from);
1925           ctx->cluster_begin_idx = ctx->out->used;
1926           ctx->cluster_begin_pos = GREF (ctx->in, from)->from;
1927           ctx->cluster_end_pos = GREF (ctx->in, from)->to;
1928         }
1929       return from;
1930
1931     case CMD_ID_CLUSTER_END:
1932       if (ctx->cluster_begin_idx >= 0
1933           && ctx->cluster_begin_idx < ctx->out->used)
1934         {
1935           int i;
1936
1937           if (MDEBUG_FLAG () > 2)
1938             MDEBUG_PRINT1 (" %d>", ctx->cluster_end_pos + 1);
1939           for (i = ctx->cluster_begin_idx; i < ctx->out->used; i++)
1940             {
1941               GREF (ctx->out, i)->from = ctx->cluster_begin_pos;
1942               GREF (ctx->out, i)->to = ctx->cluster_end_pos;
1943             }
1944           ctx->cluster_begin_idx = -1;
1945         }
1946       return from;
1947
1948     case CMD_ID_SEPARATOR:
1949       {
1950         int i;
1951
1952         i = from < to ? from : from - 1;
1953         GDUP (ctx, i);
1954         g = GREF (ctx->out, ctx->out->used - 1);
1955         g->c = -1, g->code = 0;
1956         g->xadv = g->yadv = 0;
1957         SET_ENCODED (g, 0);
1958         SET_MEASURED (g, 0);
1959         return from;
1960       }
1961
1962     case CMD_ID_LEFT_PADDING:
1963       if (MDEBUG_FLAG () > 2)
1964         MDEBUG_PRINT2 ("\n [FLT] %*s[", depth, "");
1965       ctx->left_padding = 1;
1966       return from;
1967
1968     case CMD_ID_RIGHT_PADDING:
1969       if (ctx->out->used > 0)
1970         {
1971           if (MDEBUG_FLAG () > 2)
1972             MDEBUG_PRINT2 ("\n [FLT] %*s]", depth, "");
1973           g = GREF (ctx->out, ctx->out->used - 1);
1974           SET_RIGHT_PADDING (g, ctx, RightPaddingMask);
1975         }
1976       return from;
1977     }
1978
1979   MERROR (MERROR_DRAW, -1);
1980 }
1981
1982 static int
1983 run_stages (MFLTGlyphString *gstring, int from, int to,
1984             MFLT *flt, FontLayoutContext *ctx)
1985 {
1986   MFLTGlyphString buf, *temp;
1987   int stage_idx = 0;
1988   int orig_from = from, orig_to = to;
1989   int from_pos, to_pos, len;
1990   int i, j;
1991   MFLTGlyph *g;
1992   MPlist *stages = flt->stages;
1993
1994   from_pos = GREF (ctx->in, from)->from;
1995   to_pos = GREF (ctx->in, to - 1)->to;
1996   len = to_pos - from_pos;
1997
1998   buf = *(ctx->in);
1999   buf.glyphs = NULL;
2000   GINIT (ctx->out, ctx->out->allocated);
2001   ctx->encoded = alloca (ctx->out->allocated);
2002   if (! ctx->out->glyphs || ! ctx->encoded)
2003     return -1;
2004
2005   for (stage_idx = 0; 1; stage_idx++)
2006     {
2007       MCharTable *table;
2008       int result;
2009
2010       ctx->stage = (FontLayoutStage *) MPLIST_VAL (stages);
2011       table = ctx->stage->category;
2012       ctx->code_offset = ctx->combining_code = ctx->left_padding = 0;
2013       ctx->encoded_offset = from;
2014       for (i = from; i < to; i++)
2015         {
2016           MFLTGlyph *g = GREF (ctx->in, i);
2017           char enc = (GET_ENCODED (g)
2018                       ? (g->c > 0 ? (int) mchartable_lookup (table, g->c) : 1)
2019                       : g->code
2020                       ? (int) mchartable_lookup (table, g->code)
2021                       : ' ');
2022
2023           ctx->encoded[i - from] = enc;
2024           if (! enc && stage_idx == 0)
2025             {
2026               to = i;
2027               break;
2028             }
2029         }
2030       ctx->encoded[i - from] = '\0';
2031       ctx->match_indices[0] = from;
2032       ctx->match_indices[1] = to;
2033       for (i = 2; i < NMATCH; i++)
2034         ctx->match_indices[i] = -1;
2035
2036       if (MDEBUG_FLAG () > 2)
2037         {
2038           MDEBUG_PRINT2 ("\n [FLT]   (STAGE %d \"%s\"", stage_idx,
2039                          ctx->encoded);
2040           MDEBUG_PRINT (" (");
2041           for (i = from; i < to; i++)
2042             {
2043               g = GREF (ctx->in, i);
2044               if (g->c == -1)
2045                 MDEBUG_PRINT2 ("%*s|", (i > 0), "");
2046               else
2047                 MDEBUG_PRINT3 ("%*s%04X", (i > 0), "", GREF (ctx->in, i)->code);
2048             }
2049           MDEBUG_PRINT (")");
2050         }
2051       result = run_command (4, INDEX_TO_CMD_ID (0), from, to, ctx);
2052       if (MDEBUG_FLAG () > 2)
2053         MDEBUG_PRINT (")");
2054       if (result < 0)
2055         return result;
2056
2057       stages = MPLIST_NEXT (stages);
2058       /* If this is the last stage, break the loop. */
2059       if (MPLIST_TAIL_P (stages))
2060         break;
2061
2062       /* Otherwise, prepare for the next stage.   */
2063       temp = ctx->in;
2064       ctx->in = ctx->out;
2065       if (buf.glyphs)
2066         ctx->out = temp;
2067       else
2068         {
2069           GINIT (&buf, ctx->out->allocated);
2070           ctx->out = &buf;
2071         }
2072       ctx->out->used = 0;
2073
2074       from = 0;
2075       to = ctx->in->used;
2076     }
2077
2078   if (ctx->out->used > 0)
2079     {
2080       int *g_indices;
2081       int x_ppem = ctx->font->x_ppem << 6, y_ppem = ctx->font->y_ppem << 6;
2082
2083       /* Remove separator glyphs.  */
2084       for (i = 0; i < ctx->out->used;)
2085         {
2086           g = GREF (ctx->out, i);
2087           if (g->c < 0)
2088             GREPLACE (NULL, 0, 0, ctx->out, i, i + 1);
2089           else
2090             i++;
2091         }
2092
2093       /* Get actual glyph IDs of glyphs.  */
2094       ctx->font->get_glyph_id (ctx->font, ctx->out, 0, ctx->out->used);
2095
2096       /* Check if all characters in the range are covered by some
2097          glyph(s).  If not, change <from> and <to> of glyphs to cover
2098          uncovered characters.  */
2099       g_indices = alloca (sizeof (int) * len);
2100       if (! g_indices)
2101         return -1;
2102       for (i = 0; i < len; i++) g_indices[i] = -1;
2103       for (i = 0; i < ctx->out->used; i++)
2104         {
2105           int pos;
2106
2107           g = GREF (ctx->out, i);
2108           for (pos = g->from; pos <= g->to; pos++)
2109             if (g_indices[pos - from_pos] < 0)
2110               g_indices[pos - from_pos] = i;
2111         }
2112       for (i = 0; i < len; i++)
2113         if (g_indices[i] < 0)
2114           {
2115             if (i == 0)
2116               {
2117                 int this_from;
2118
2119                 for (i++; i < len && g_indices[i] < 0; i++);
2120                 j = g_indices[i];
2121                 g = GREF (ctx->out, j);
2122                 this_from = g->from;
2123                 do {
2124                   g->from = orig_from + i;
2125                 } while (++j < ctx->out->used
2126                          && (g = GREF (ctx->out, j))
2127                          && g->from == this_from);
2128               }
2129             else
2130               {
2131                 int this_to;
2132
2133                 j = g_indices[i - 1];
2134                 g = GREF (ctx->out, j);
2135                 this_to = g->to;
2136                 do {
2137                   g->to = orig_from + i + 1;
2138                 } while (--j >= 0
2139                          && (g = GREF (ctx->out, j))
2140                          && g->to == this_to);
2141               }
2142           }
2143
2144       ctx->font->get_metrics (ctx->font, ctx->out, 0, ctx->out->used);
2145
2146       /* Handle combining.  */
2147       if (ctx->check_mask & CombiningCodeMask)
2148         {
2149           MFLTGlyph *base = GREF (ctx->out, 0);
2150           int base_height = base->ascent + base->descent;
2151           int combining_code;
2152
2153           for (i = 1; i < ctx->out->used; i++)
2154             {
2155               if ((g = GREF (ctx->out, i))
2156                   && (combining_code = GET_COMBINING_CODE (g)))
2157                 {
2158                   int height = g->ascent + g->descent;
2159                   int base_x, base_y, add_x, add_y, off_x, off_y;
2160
2161                   if (base->from > g->from)
2162                     base->from = g->from;
2163                   else if (base->to < g->to)
2164                     base->to = g->to;
2165                 
2166                   base_x = COMBINING_CODE_BASE_X (combining_code);
2167                   base_y = COMBINING_CODE_BASE_Y (combining_code);
2168                   add_x = COMBINING_CODE_ADD_X (combining_code);
2169                   add_y = COMBINING_CODE_ADD_Y (combining_code);
2170                   off_x = COMBINING_CODE_OFF_X (combining_code);
2171                   off_y = COMBINING_CODE_OFF_Y (combining_code);
2172
2173                   g->xoff = ((base->xadv * base_x - g->xadv * add_x) / 2
2174                              + x_ppem * off_x / 100 - base->xadv);
2175                   if (base_y < 3)
2176                     g->yoff = base_height * base_y / 2 - base->ascent;
2177                   else
2178                     g->yoff = 0;
2179                   if (add_y < 3)
2180                     g->yoff -= height * add_y / 2 - g->ascent;
2181                   g->yoff -= y_ppem * off_y / 100;
2182                   if (base->lbearing > base->xadv + g->lbearing + g->xoff)
2183                     base->lbearing = base->xadv + g->lbearing + g->xoff;
2184                   if (base->rbearing < base->xadv + g->xadv + g->xoff)
2185                     base->rbearing = base->xadv + g->xadv + g->xoff;
2186                   if (base->ascent < g->ascent - g->yoff)
2187                     base->ascent = g->ascent - g->yoff;
2188                   if (base->descent < g->descent - g->yoff)
2189                     base->descent = g->descent - g->yoff;
2190                   g->xadv = g->yadv = 0;
2191                   if (GET_RIGHT_PADDING (g))
2192                     SET_RIGHT_PADDING (base, ctx, RightPaddingMask);
2193                   g->adjusted = 1;
2194                 }
2195               else
2196                 {
2197                   base = g;
2198                   base_height = g->ascent + g->descent;
2199                 }
2200             }
2201         }
2202
2203       /* Handle padding */
2204       if (ctx->check_mask & (LeftPaddingMask | RightPaddingMask))
2205         for (i = 0; i < ctx->out->used; i++)
2206           {
2207             g = GREF (ctx->out, i);
2208             if (! GET_COMBINING_CODE (g))
2209               {
2210                 if (GET_RIGHT_PADDING (g) && g->rbearing > g->xadv)
2211                   {
2212                     g->xadv = g->rbearing;
2213                     g->adjusted = 1;
2214                   }
2215                 if (GET_LEFT_PADDING (g) && g->lbearing < 0)
2216                   {
2217                     g->xoff += - g->lbearing;
2218                     g->xadv += - g->lbearing;
2219                     g->rbearing += - g->lbearing;
2220                     g->lbearing = 0;
2221                     g->adjusted = 1;
2222                   }
2223               }
2224           }
2225     }
2226
2227   GREPLACE (ctx->out, 0, ctx->out->used, gstring, orig_from, orig_to);
2228   to = orig_from + ctx->out->used;
2229   return to;
2230 }
2231
2232 static void
2233 setup_combining_coverage (int from, int to, void *val, void *arg)
2234 {
2235   int combining_class = (int) val;
2236   int category = 0;
2237
2238   if (combining_class < 200)
2239     category = 'a';
2240   else if (combining_class <= 204)
2241     {
2242       if ((combining_class % 2) == 0)
2243         category = "bcd"[(combining_class - 200) / 2];
2244     }
2245   else if (combining_class <= 232)
2246     {
2247       if ((combining_class % 2) == 0)
2248         category = "efghijklmnopq"[(combining_class - 208) / 2];
2249     }
2250   else if (combining_class == 233)
2251     category = 'r';
2252   else if (combining_class == 234)
2253     category = 's';
2254   else if (combining_class == 240)
2255     category = 't';
2256   mchartable_set_range ((MCharTable *) arg, from, to, (void *) category);
2257 }
2258
2259 static void
2260 setup_combining_flt (MFLT *flt)
2261 {
2262   MSymbol type;
2263   MCharTable *combininig_class_table
2264     = mchar_get_prop_table (Mcombining_class, &type);
2265
2266   mchartable_set_range (flt->coverage, 0, 0x10FFFF, (void *) 'u');
2267   if (combininig_class_table)
2268     mchartable_map (combininig_class_table, (void *) 0,
2269                     setup_combining_coverage, flt->coverage);
2270 }
2271
2272 #define CHECK_FLT_STAGES(flt) ((flt)->stages || load_flt (flt, NULL) == 0)
2273
2274 \f
2275 /* Internal API */
2276
2277 int m17n__flt_initialized;
2278
2279 \f
2280 /* External API */
2281
2282 /* The following two are actually not exposed to a user but concealed
2283    by the macro M17N_INIT (). */
2284
2285 void
2286 m17n_init_flt (void)
2287 {
2288   int mdebug_flag = MDEBUG_INIT;
2289
2290   merror_code = MERROR_NONE;
2291   if (m17n__flt_initialized++)
2292     return;
2293   m17n_init_core ();
2294   if (merror_code != MERROR_NONE)
2295     {
2296       m17n__flt_initialized--;
2297       return;
2298     }
2299
2300   MDEBUG_PUSH_TIME ();
2301
2302   Mcond = msymbol ("cond");
2303   Mrange = msymbol ("range");
2304   Mfont = msymbol ("font");
2305   Mlayouter = msymbol ("layouter");
2306   Mcombining = msymbol ("combining");
2307   Mfont_facility = msymbol ("font-facility");
2308   Mequal = msymbol ("=");
2309   Mgenerator = msymbol ("generator");
2310   Mend = msymbol ("end");
2311
2312   MDEBUG_PRINT_TIME ("INIT", (stderr, " to initialize the flt modules."));
2313   MDEBUG_POP_TIME ();
2314 }
2315
2316 void
2317 m17n_fini_flt (void)
2318 {
2319   int mdebug_flag = MDEBUG_FINI;
2320
2321   if (m17n__flt_initialized == 0
2322       || --m17n__flt_initialized > 0)
2323     return;
2324
2325   MDEBUG_PUSH_TIME ();
2326   free_flt_list ();
2327   MDEBUG_PRINT_TIME ("FINI", (stderr, " to finalize the flt modules."));
2328   MDEBUG_POP_TIME ();
2329   m17n_fini_core ();
2330 }
2331
2332 /*** @} */ 
2333 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
2334
2335 /*** @addtogroup m17nFLT */
2336 /*** @{ */
2337 /*=*/
2338
2339 /*=*/
2340 /***en
2341     @brief Return an FLT object that has a specified name.
2342
2343     The mflt_get () function returns an FLT object whose name is $NAME.
2344
2345     @return
2346     If the operation was successful, mflt_get () returns a pointer
2347     to the found FLT object.  Otherwise, it returns @c NULL.  */
2348
2349 /***ja
2350     @brief »ØÄꤵ¤ì¤¿Ì¾Á°¤ò»ý¤Ä FLT ¥ª¥Ö¥¸¥§¥¯¥È¤òÊÖ¤¹.
2351
2352     ´Ø¿ô mflt_get () ¤Ï¡¢$NAME ¤È¤¤¤¦Ì¾Á°¤ò»ý¤Ä FLT ¥ª¥Ö¥¸¥§¥¯¥È¤òÊÖ¤¹¡£
2353
2354     @return
2355     ¤â¤·À®¸ù¤¹¤ì¤Ð¡¢mflt_get () ¤Ï¸«¤Ä¤«¤Ã¤¿ FLT
2356     ¥ª¥Ö¥¸¥§¥¯¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¼ºÇÔ¤·¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤¹¡£  */
2357
2358 MFLT *
2359 mflt_get (MSymbol name)
2360 {
2361   MFLT *flt;
2362
2363   if (! flt_list && list_flt () < 0)
2364     return NULL;
2365   flt = mplist_get (flt_list, name);
2366   if (! flt || ! CHECK_FLT_STAGES (flt))
2367     return NULL;
2368   if (flt->name == Mcombining
2369       && ! mchartable_lookup (flt->coverage, 0))
2370     setup_combining_flt (flt);
2371
2372   return flt;
2373 }
2374
2375 /*=*/
2376 /***en
2377     @brief Find an FLT suitable for the specified character and font.
2378
2379     The mflt_find () function returns the most appropriate FLT for
2380     layouting character $C with font $FONT.
2381
2382     @return
2383     If the operation was successful, mflt_find () returns a pointer
2384     to the found FLT object.  Otherwise, it returns @c NULL.  */
2385
2386 /***ja
2387     @brief »ØÄꤵ¤ì¤¿Ê¸»ú¤È¥Õ¥©¥ó¥È¤Ë¹ç¤Ã¤¿ FLT ¤òõ¤¹.
2388
2389     ´Ø¿ô mflt_find () ¤Ï¡¢Ê¸»ú $C ¤ò¥Õ¥©¥ó¥È $FONT
2390     ¤Ç¥ì¥¤¥¢¥¦¥È¤¹¤ë¤¿¤á¤ËºÇ¤âŬÀڤʠFLT ¤òÊÖ¤¹¡£
2391
2392     @return
2393     ¤â¤·À®¸ù¤¹¤ì¤Ð¡¢mflt_find () ¤Ï¸«¤Ä¤«¤Ã¤¿ FLT
2394     ¥ª¥Ö¥¸¥§¥¯¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¼ºÇÔ¤·¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤¹¡£  */
2395
2396 MFLT *
2397 mflt_find (int c, MFLTFont *font)
2398 {
2399   MPlist *plist;
2400   MFLT *flt;
2401   static MSymbol unicode_bmp = NULL, unicode_full = NULL;
2402
2403   if (! unicode_bmp)
2404     {
2405       unicode_bmp = msymbol ("unicode-bmp");
2406       unicode_full = msymbol ("unicode-full");
2407     }
2408
2409   if (! flt_list && list_flt () < 0)
2410     return NULL;
2411   if (font)
2412     {
2413       MFLT *best = NULL;
2414
2415       MPLIST_DO (plist, flt_list)
2416         {
2417           flt = MPLIST_VAL (plist);
2418           if (flt->registry != unicode_bmp
2419               && flt->registry != unicode_full)
2420             continue;
2421           if (flt->family && flt->family != font->family)
2422             continue;
2423           if (c >= 0
2424               && ! mchartable_lookup (flt->coverage, c))
2425             continue;
2426           if (flt->otf.sym)
2427             {
2428               MFLTOtfSpec *spec = &flt->otf;
2429
2430               if (! font->check_otf)
2431                 {
2432                   if ((spec->features[0] && spec->features[0][0] != 0xFFFFFFFF)
2433                       || (spec->features[1] && spec->features[1][0] != 0xFFFFFFFF))
2434                     continue;
2435                 }
2436               else if (! font->check_otf (font, spec))
2437                 continue;
2438               return flt;
2439             }
2440           best = flt;
2441         }
2442       return best;
2443     }
2444   if (c >= 0)
2445     {
2446       MPLIST_DO (plist, flt_list)
2447         {
2448           flt = MPLIST_VAL (plist);
2449           if (mchartable_lookup (flt->coverage, c))
2450             return flt;
2451         }
2452     }
2453   return NULL;
2454 }
2455
2456 /*=*/
2457 /***en
2458     @brief Return the name of an FLT.
2459
2460     The mflt_name () function returns the name of $FLT.  */
2461
2462 /***ja
2463     @brief FLT ¤Î̾Á°¤òÊÖ¤¹.
2464
2465     ´Ø¿ô mflt_name () ¤Ï $FLT ¤Î̾Á°¤òÊÖ¤¹¡£  */
2466
2467 const char *
2468 mflt_name (MFLT *flt)
2469 {
2470   return MSYMBOL_NAME (flt->name);
2471 }
2472
2473 /*=*/
2474 /***en
2475     @brief Return a coverage of a FLT.
2476
2477     The mflt_coverage () function returns a char-table that contains
2478     nonzero values for characters supported by $FLT.  */
2479
2480 /***ja
2481     @brief FLT ¤ÎÈϰϤòÊÖ¤¹.
2482
2483     ´Ø¿ô mflt_coverage () ¤Ï¡¢$FLT ¤¬¥µ¥Ý¡¼¥È¤¹¤ëʸ»ú¤ËÂФ·¤Æ
2484     0 ¤Ç¤Ê¤¤Ãͤò´Þ¤àʸ»ú¥Æ¡¼¥Ö¥ë¤òÊÖ¤¹¡£  */
2485
2486 MCharTable *
2487 mflt_coverage (MFLT *flt)
2488 {
2489   return flt->coverage;
2490 }
2491
2492 /*=*/
2493 /***en
2494     @brief Layout characters with an FLT.
2495
2496     The mflt_run () function layouts characters in $GSTRING between
2497     $FROM (inclusive) and $TO (exclusive) with $FONT.  If $FLT is
2498     nonzero, it is used for all the charaters.  Otherwise, appropriate
2499     FLTs are automatically chosen.
2500
2501     @retval >=0
2502     The operation was successful.  The value is the index to the
2503     glyph, which was previously indexed by $TO, in $GSTRING->glyphs.
2504
2505     @retval -2
2506     $GSTRING->glyphs is too short to store the result.  The caller can
2507     call this fucntion again with a longer $GSTRING->glyphs.
2508
2509     @retval -1
2510     Some other error occurred.  */
2511
2512 /***ja
2513     @brief FLT ¤ò»È¤Ã¤Æʸ»ú¤ò¥ì¥¤¥¢¥¦¥È¤¹¤ë.
2514
2515     ´Ø¿ô mflt_run () ¤Ï¡¢$GSTRING Ãæ¤Î $FROM ¤«¤é $TO Ä¾Á°¤Þ¤Ç¤Îʸ»ú¤ò
2516     $FONT ¤òÍѤ¤¤Æ¥ì¥¤¥¢¥¦¥È¤¹¤ë¡£¤â¤· $FLT
2517     ¤¬¥¼¥í¤Ç¤Ê¤±¤ì¤Ð¡¢¤½¤ÎÃͤò¤¹¤Ù¤Æ¤Îʸ»ú¤ËÂФ·¤ÆÍѤ¤¤ë¡£
2518     ¤½¤¦¤Ç¤Ê¤±¤ì¤ÐŬÀڤʠFLT ¤ò¼«Æ°Åª¤ËÁªÂò¤¹¤ë¡£
2519
2520     @retval >=0
2521     ¼Â¹ÔÀ®¸ù¤ò¼¨¤¹¡£ÊÖ¤µ¤ì¤ëÃͤϡ¢$GSTRING->glyphs Ãæ¤Ç°ÊÁ° $TO
2522     ¤Ë¤è¤Ã¤Æ¼¨¤µ¤ì¤Æ¤¤¤¿¥°¥ê¥Õ¤Ø¤Î¥¤¥ó¥Ç¥¯¥¹¤Ç¤¢¤ë¡£
2523
2524     @retval -2
2525     ·ë²Ì¤ò³ÊǼ¤¹¤ë¤Ë¤Ï $GSTRING->glyphs ¤¬Ã»¤¹¤®¤ë¤³¤È¤ò¼¨¤¹¡£
2526     ¸Æ¤Ó½Ð¤·Â¦¤Ï¡¢¤è¤êŤ¤ $GSTRING->glyphs
2527     ¤òÍѤ¤¤ÆºÆÅÙ¤³¤Î´Ø¿ô¤ò¸Æ¤Ö¤³¤È¤¬¤Ç¤­¤ë¡£
2528
2529     @retval -1
2530     ¤½¤Î¾¤Î¥¨¥é¡¼¤¬µ¯¤­¤¿¤³¤È¤ò¼¨¤¹¡£  */
2531
2532 int
2533 mflt_run (MFLTGlyphString *gstring, int from, int to,
2534           MFLTFont *font, MFLT *flt)
2535 {
2536   FontLayoutContext ctx;
2537   int match_indices[NMATCH];
2538   MFLTGlyph *g;
2539   MFLTGlyphString out;
2540   int auto_flt = ! flt;
2541   int c, i, j, k;
2542   int this_from, this_to;
2543
2544   out = *gstring;
2545   out.glyphs = NULL;
2546   /* This is usually sufficient, but if not, we retry with the larger
2547      values at most 3 times.  This value is also used for the
2548      allocating size of ctx.encoded.  */
2549   out.allocated = (to - from) * 4;
2550
2551   for (i = from; i < to; i++)
2552     {
2553       g = GREF (gstring, i);
2554       c = g->c;
2555       memset (g, 0, sizeof (MFLTGlyph));
2556       g->code = g->c = c;
2557       g->from = g->to = i;
2558     }
2559
2560   for (this_from = from; this_from < to;)
2561     {
2562       if (! auto_flt)
2563         {
2564           for (this_to = this_from; this_to < to; this_to++)
2565             if (mchartable_lookup (flt->coverage, GREF (gstring, this_to)->c))
2566               break;
2567         }
2568       else
2569         {
2570           if (! flt_list && list_flt () < 0)
2571             {
2572               font->get_glyph_id (font, gstring, this_from, to);
2573               font->get_metrics (font, gstring, this_from, to);
2574               this_from = to;
2575               break;
2576             }
2577           for (this_to = this_from; this_to < to; this_to++)
2578             {
2579               c = GREF (gstring, this_to)->c;
2580               if (c >= flt_min_coverage && c <= flt_max_coverage)
2581                 break;
2582             }
2583           for (; this_to < to; this_to++)
2584             {
2585               c = GREF (gstring, this_to)->c;
2586               if (font->internal
2587                   && mchartable_lookup (((MFLT *) font->internal)->coverage, c))
2588                 {
2589                   flt = font->internal;
2590                   break;
2591                 }
2592               flt = mflt_find (c, font);
2593               if (flt)
2594                 {
2595                   if (CHECK_FLT_STAGES (flt))
2596                     {
2597                       font->internal = flt;
2598                       break;
2599                     }
2600                 }
2601             }
2602         }
2603
2604       if (this_from < this_to)
2605         {
2606           font->get_glyph_id (font, gstring, this_from, this_to);
2607           font->get_metrics (font, gstring, this_from, this_to);
2608           this_from = this_to;
2609         }
2610       if (this_to == to)
2611         break;
2612
2613       MDEBUG_PRINT1 (" [FLT] (%s", MSYMBOL_NAME (flt->name));
2614
2615       for (; this_to < to; this_to++)
2616         if (! mchartable_lookup (flt->coverage, GREF (gstring, this_to)->c))
2617           break;
2618
2619       if (MDEBUG_FLAG ())
2620         {
2621           if (font->family)
2622             MDEBUG_PRINT1 (" (%s)", MSYMBOL_NAME (font->family));
2623           MDEBUG_PRINT ("\n [FLT]   (SOURCE");
2624           for (i = this_from, j = 0; i < this_to; i++, j++)
2625             {
2626               if (j > 0 && j % 8 == 0)
2627                 MDEBUG_PRINT ("\n [FLT]          ");
2628               MDEBUG_PRINT1 (" %04X", GREF (gstring, i)->c);
2629             }
2630           MDEBUG_PRINT (")");
2631         }
2632
2633       for (i = 0; i < 3; i++)
2634         {
2635           /* Setup CTX.  */
2636           memset (&ctx, 0, sizeof ctx);
2637           ctx.match_indices = match_indices;
2638           ctx.font = font;
2639           ctx.cluster_begin_idx = -1;
2640           ctx.in = gstring;
2641           ctx.out = &out;
2642           j = run_stages (gstring, this_from, this_to, flt, &ctx);
2643           if (j != -2)
2644             break;
2645           out.allocated *= 2;
2646         }
2647
2648       if (j < 0)
2649         return j;
2650
2651       to += j - this_to;
2652       this_to = j;
2653
2654       if (MDEBUG_FLAG ())
2655         {
2656           MDEBUG_PRINT ("\n [FLT]   (RESULT");
2657           if (MDEBUG_FLAG () > 1)
2658             for (i = 0; this_from < this_to; this_from++, i++)
2659               {
2660                 if (i > 0 && i % 4 == 0)
2661                   MDEBUG_PRINT ("\n [FLT]          ");
2662                 g = GREF (gstring, this_from);
2663                 MDEBUG_PRINT4 (" (%04X %d %d %d)",
2664                                g->code, g->xadv, g->xoff, g->yoff);
2665               }
2666           else
2667             for (; this_from < this_to; this_from++)
2668               MDEBUG_PRINT1 (" %04X", GREF (gstring, this_from)->code);
2669           MDEBUG_PRINT ("))\n");
2670         }
2671       this_from = this_to;
2672     }
2673
2674   if (gstring->r2l)
2675     {
2676       int len = to - from;
2677
2678       GINIT (&out, len);
2679       memcpy (((char *) out.glyphs),
2680               ((char *) gstring->glyphs) + gstring->glyph_size * from,
2681               gstring->glyph_size * len);
2682       for (i = from, j = to; i < to;)
2683         {
2684           for (k = i + 1, j--; k < to && GREF (&out, k)->xadv == 0;
2685                k++, j--);
2686           GCPY (&out, i, (k - i), gstring, j);
2687           i = k;
2688         }
2689     }
2690
2691   return to;
2692 }
2693
2694 \f
2695 /* for debugging... */
2696
2697 static void
2698 dump_flt_cmd (FontLayoutStage *stage, int id, int indent)
2699 {
2700   char *prefix = (char *) alloca (indent + 1);
2701
2702   memset (prefix, 32, indent);
2703   prefix[indent] = 0;
2704
2705   if (id >= 0)
2706     fprintf (stderr, "0x%02X", id);
2707   else if (id <= CMD_ID_OFFSET_INDEX)
2708     {
2709       int idx = CMD_ID_TO_INDEX (id);
2710       FontLayoutCmd *cmd = stage->cmds + idx;
2711
2712       if (cmd->type == FontLayoutCmdTypeRule)
2713         {
2714           FontLayoutCmdRule *rule = &cmd->body.rule;
2715           int i;
2716
2717           fprintf (stderr, "(rule ");
2718           if (rule->src_type == SRC_REGEX)
2719             fprintf (stderr, "\"%s\"", rule->src.re.pattern);
2720           else if (rule->src_type == SRC_INDEX)
2721             fprintf (stderr, "%d", rule->src.match_idx);
2722           else if (rule->src_type == SRC_SEQ)
2723             fprintf (stderr, "(seq)");
2724           else if (rule->src_type == SRC_RANGE)
2725             fprintf (stderr, "(range)");
2726           else
2727             fprintf (stderr, "(invalid src)");
2728
2729           for (i = 0; i < rule->n_cmds; i++)
2730             {
2731               fprintf (stderr, "\n%s  ", prefix);
2732               dump_flt_cmd (stage, rule->cmd_ids[i], indent + 2);
2733             }
2734           fprintf (stderr, ")");
2735         }
2736       else if (cmd->type == FontLayoutCmdTypeCond)
2737         {
2738           FontLayoutCmdCond *cond = &cmd->body.cond;
2739           int i;
2740
2741           fprintf (stderr, "(cond");
2742           for (i = 0; i < cond->n_cmds; i++)
2743             {
2744               fprintf (stderr, "\n%s  ", prefix);
2745               dump_flt_cmd (stage, cond->cmd_ids[i], indent + 2);
2746             }
2747           fprintf (stderr, ")");
2748         }
2749       else if (cmd->type == FontLayoutCmdTypeOTF)
2750         {
2751           fprintf (stderr, "(otf)");
2752         }
2753       else
2754         fprintf (stderr, "(error-command)");
2755     }
2756   else if (id <= CMD_ID_OFFSET_COMBINING)
2757     fprintf (stderr, "cominging-code");
2758   else
2759     fprintf (stderr, "(predefiend %d)", id);
2760 }
2761
2762 /***en
2763     @brief Dump a Font Layout Table.
2764
2765     The mdebug_dump_flt () function prints the Font Layout Table $FLT
2766     in a human readable way to the stderr.  $INDENT specifies how many
2767     columns to indent the lines but the first one.
2768
2769     @return
2770     This function returns $FLT.  */
2771
2772 MFLT *
2773 mdebug_dump_flt (MFLT *flt, int indent)
2774 {
2775   char *prefix = (char *) alloca (indent + 1);
2776   MPlist *plist;
2777   int stage_idx = 0;
2778
2779   memset (prefix, 32, indent);
2780   prefix[indent] = 0;
2781   fprintf (stderr, "(flt");
2782   MPLIST_DO (plist, flt->stages)
2783     {
2784       FontLayoutStage *stage = (FontLayoutStage *) MPLIST_VAL (plist);
2785       int i;
2786
2787       fprintf (stderr, "\n%s  (stage %d", prefix, stage_idx);
2788       for (i = 0; i < stage->used; i++)
2789         {
2790           fprintf (stderr, "\n%s    ", prefix);
2791           dump_flt_cmd (stage, INDEX_TO_CMD_ID (i), indent + 4);
2792         }
2793       fprintf (stderr, ")");
2794       stage_idx++;
2795     }
2796   fprintf (stderr, ")");
2797   return flt;
2798 }
2799
2800 /*** @} */
2801
2802 /*
2803  Local Variables:
2804  coding: euc-japan
2805  End:
2806 */