Fix comment on parse_otf_command.
[m17n/m17n-lib.git] / src / m17n-flt.c
1 /* m17n-flt.c -- Font Layout Table sub-module.
2    Copyright (C) 2003, 2004, 2007, 2008, 2009, 2010
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 all glyphs in the current range.
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   CategoryCodeMask = 0x7F,
259   CombiningCodeMask = 0xFFFFFF,
260   CombinedMask = 1 << 28,
261   LeftPaddingMask = 1 << 29,
262   RightPaddingMask = 1 << 30
263 };
264
265 #define SET_GLYPH_INFO(g, mask, ctx, info)                      \
266   ((g)->internal = (((g)->internal & ~(mask)) | (info)),        \
267    (ctx)->check_mask |= (mask))
268
269 #define GET_CATEGORY_CODE(g) ((g)->internal & CategoryCodeMask)
270 #define SET_CATEGORY_CODE(g, code)                                       \
271   ((g)->internal = (((g)->internal & ~(CombiningCodeMask | CombinedMask)) \
272                     | (code)))
273 #define GET_COMBINED(g) ((g)->internal & CombinedMask)
274 #define GET_COMBINING_CODE(g) ((g)->internal & CombiningCodeMask)
275 #define SET_COMBINING_CODE(g, ctx, code)                        \
276   SET_GLYPH_INFO (g, CombiningCodeMask | CombinedMask, ctx,     \
277                   (code) | CombinedMask)
278 #define GET_LEFT_PADDING(g) ((g)->internal & LeftPaddingMask)
279 #define SET_LEFT_PADDING(g, ctx, flag)  \
280   SET_GLYPH_INFO (g, LeftPaddingMask, ctx, flag)
281 #define GET_RIGHT_PADDING(g) ((g)->internal & RightPaddingMask)
282 #define SET_RIGHT_PADDING(g, ctx, flag) \
283   SET_GLYPH_INFO (g, RightPaddingMask, ctx, flag)
284 #define GET_ENCODED(g) ((g)->encoded)
285 #define SET_ENCODED(g, flag) ((g)->encoded = (flag))
286 #define GET_MEASURED(g) ((g)->measured)
287 #define SET_MEASURED(g, flag) ((g)->measured = (flag))
288
289 #define GINIT(gstring, n)                                       \
290   do {                                                          \
291     if (! (gstring)->glyph_size)                                \
292       (gstring)->glyph_size = sizeof (MFLTGlyph);               \
293     (gstring)->glyphs = alloca ((gstring)->glyph_size * (n));   \
294     (gstring)->allocated = (n);                                 \
295     (gstring)->used = 0;                                        \
296   } while (0)
297
298 #define GALLOCA (gstring)       \
299   ((MFLTGlyph *) alloca ((gstring)->glyph_size))
300
301 #define GREF(gstring, idx)      \
302   ((MFLTGlyph *) ((char *) ((gstring)->glyphs) + (gstring)->glyph_size * (idx)))
303
304 #define PREV(gstring, g)        \
305   ((MFLTGlyph *) ((char *) (g) - (gstring)->glyph_size))
306
307 #define NEXT(gstring, g)        \
308   ((MFLTGlyph *) ((char *) (g) + (gstring)->glyph_size))
309
310 #define GCPY(src, src_idx, n, tgt, tgt_idx)                             \
311   do {                                                                  \
312     memcpy ((char *) ((tgt)->glyphs) + (tgt)->glyph_size * (tgt_idx),   \
313             (char *) ((src)->glyphs) + (src)->glyph_size * (src_idx),   \
314             (src)->glyph_size * (n));                                   \
315   } while (0)
316
317 #define GDUP(ctx, idx)                          \
318   do {                                          \
319     MFLTGlyphString *src = (ctx)->in;           \
320     MFLTGlyphString *tgt = (ctx)->out;          \
321     if (tgt->allocated <= tgt->used)            \
322       return -2;                                \
323     GCPY (src, (idx), 1, tgt, tgt->used);       \
324     tgt->used++;                                \
325   } while (0)
326
327 static int
328 GREPLACE (MFLTGlyphString *src, int src_from, int src_to,
329           MFLTGlyphString *tgt, int tgt_from, int tgt_to)
330 {
331   int src_len = src_to - src_from;
332   int tgt_len = tgt_to - tgt_from;
333   int inc = src_len - tgt_len;
334
335   if (tgt->allocated < tgt->used + inc)
336     return -2;
337   if (inc != 0 && tgt_to < tgt->used)
338     memmove ((char *) tgt->glyphs + tgt->glyph_size * (tgt_from + src_len),
339              (char *) tgt->glyphs + tgt->glyph_size * tgt_to,
340              tgt->glyph_size * (tgt->used - tgt_to));
341   if (src_len)
342     memcpy ((char *) tgt->glyphs + tgt->glyph_size * tgt_from,
343             (char *) src->glyphs + src->glyph_size * src_from,
344             src->glyph_size * src_len);
345   tgt->used += inc;
346   return 0;
347 }
348
349
350 /* Command ID:
351                  0 ...          : direct code
352                    -1           : invalid
353              -0x0F .. -2        : builtin commands
354         -0x100000F .. -0x10     : combining code
355                   ... -0x1000010: index to FontLayoutStage->cmds
356  */
357
358 #define INVALID_CMD_ID -1
359 #define CMD_ID_OFFSET_BUILTIN   -3
360 #define CMD_ID_OFFSET_COMBINING -0x10
361 #define CMD_ID_OFFSET_INDEX     -0x1000010
362
363 /* Builtin commands. */
364 #define CMD_ID_COPY             -3 /* '=' */
365 #define CMD_ID_REPEAT           -4 /* '*' */
366 #define CMD_ID_CLUSTER_BEGIN    -5 /* '<' */
367 #define CMD_ID_CLUSTER_END      -6 /* '>' */
368 #define CMD_ID_SEPARATOR        -7 /* '|' */
369 #define CMD_ID_LEFT_PADDING     -8 /* '[' */
370 #define CMD_ID_RIGHT_PADDING    -9 /* ']' */
371
372 #define CMD_ID_TO_COMBINING_CODE(id) (CMD_ID_OFFSET_COMBINING - (id))
373 #define COMBINING_CODE_TO_CMD_ID(code) (CMD_ID_OFFSET_COMBINING - (code))
374
375 #define CMD_ID_TO_INDEX(id) (CMD_ID_OFFSET_INDEX - (id))
376 #define INDEX_TO_CMD_ID(idx) (CMD_ID_OFFSET_INDEX - (idx))
377
378 static MSymbol Mcond, Mrange, Mfont_facility, Mequal;
379
380 #define GLYPH_CODE_P(code)      \
381   ((code) >= GLYPH_CODE_MIN && (code) <= GLYPH_CODE_MAX)
382
383 #define GLYPH_CODE_INDEX(code) ((code) - GLYPH_CODE_MIN)
384
385 #define UPDATE_CLUSTER_RANGE(ctx, g)            \
386   do {                                          \
387     if (ctx->cluster_begin_pos > (g)->from)     \
388       ctx->cluster_begin_pos = (g)->from;       \
389     if (ctx->cluster_end_pos < (g)->to)         \
390       ctx->cluster_end_pos = (g)->to;           \
391   } while (0)
392
393 enum FontLayoutCmdRuleSrcType
394   {
395     SRC_REGEX,
396     SRC_INDEX,
397     SRC_SEQ,
398     SRC_RANGE,
399     SRC_HAS_GLYPH,
400     SRC_OTF_SPEC
401   };
402
403 typedef struct
404 {
405   enum FontLayoutCmdRuleSrcType src_type;
406   union {
407     struct {
408       char *pattern;
409       regex_t preg;
410     } re;
411     int match_idx;
412     struct {
413       int n_codes;
414       int *codes;
415     } seq;
416     struct {
417       int from, to;
418     } range;
419     struct {
420       int len;
421       MPlist *codes;
422       MFLTOtfSpec otf_spec;
423     } facility;
424   } src;
425
426   int n_cmds;
427   int *cmd_ids;
428 } FontLayoutCmdRule;
429
430 typedef struct
431 {
432   /* Beginning and end indices of series of SEQ commands.  */
433   int seq_beg, seq_end;
434   /* Range of the first character appears in the above series.  */
435   int seq_from, seq_to;
436
437   int n_cmds;
438   int *cmd_ids;
439 } FontLayoutCmdCond;
440
441 enum FontLayoutCmdType
442   {
443     FontLayoutCmdTypeRule,
444     FontLayoutCmdTypeCond,
445     FontLayoutCmdTypeOTF,
446     FontLayoutCmdTypeOTFCategory,
447     FontLayoutCmdTypeMAX
448   };
449
450 typedef struct
451 {
452   enum FontLayoutCmdType type;
453   union {
454     FontLayoutCmdRule rule;
455     FontLayoutCmdCond cond;
456     MFLTOtfSpec otf;
457   } body;
458 } FontLayoutCmd;
459
460 typedef struct
461 {
462   int size;
463   unsigned int *tag;
464   char *code;
465 } FeatureCodeTable;
466
467 typedef struct
468 {
469   MCharTable *table;
470   FeatureCodeTable feature_table;
471   /* Non-null if the table must be re-configured by OTF specs included
472      in the definition.  */
473   MPlist *definition;
474 } FontLayoutCategory;
475
476 typedef struct 
477 {
478   FontLayoutCategory *category;
479   int size, inc, used;
480   FontLayoutCmd *cmds;
481 } FontLayoutStage;
482
483 struct _MFLT
484 {
485   MSymbol name;
486   MSymbol family;
487   MSymbol registry;
488   MFLTOtfSpec otf;
489   MDatabase *mdb;
490   FontLayoutCategory *coverage;
491   MPlist *stages;
492   int need_config;
493   /* Font for which coverage or some of categories are configured.  */
494   MSymbol font_id;
495 };
496
497 /* Font layout table loader */
498
499 static int parse_otf_command (MSymbol symbol, MFLTOtfSpec *spec);
500
501 static void
502 apply_otf_feature (MFLTFont *font, MFLTOtfSpec *spec,
503                    int from, int to, MCharTable *table, int category)
504 {
505   unsigned char *buf;
506   int i;
507
508   if (! mflt_iterate_otf_feature)
509     return;
510   buf = alloca (to + 1 - from);
511   memset (buf, 0, to + 1 - from);
512   if (mflt_iterate_otf_feature (font, spec, from, to, buf) < 0)
513     return;
514   for (i = to - from; i >= 0; i--)
515     if (buf[i])
516       mchartable_set (table, from + i, (void *) category);
517 }
518
519 static unsigned int gen_otf_tag (char *p, int shift);
520
521 /* Load a category table from PLIST.  PLIST has this form:
522       PLIST ::= ( FROM-CODE TO-CODE ? CATEGORY-CHAR ) *
523 */
524
525 static FontLayoutCategory *
526 load_category_table (MPlist *plist, MFLTFont *font)
527 {
528   FontLayoutCategory *category;
529   MCharTable *table;
530   MPlist *feature_table_head = NULL;
531   int feature_table_size = 0;
532   MPlist *p;
533   int need_otf = 0;
534
535   table = mchartable (Minteger, (void *) 0);
536   MPLIST_DO (p, plist)
537     {
538       MPlist *elt;
539       int from, to, category_code;
540
541       if (! MPLIST_PLIST_P (p))
542         MERROR_GOTO (MERROR_FLT, end);
543       elt = MPLIST_PLIST (p);
544       if (MPLIST_SYMBOL_P (elt))
545         {
546           MPlist *next;
547
548           if (! mflt_enable_new_feature)
549             {
550               M17N_OBJECT_UNREF (table);
551               return NULL;
552             }
553           next = MPLIST_NEXT (elt);
554           if (! MPLIST_INTEGER_P (next))
555             MERROR_GOTO (MERROR_FLT, end);
556           if (! feature_table_head)
557             feature_table_head = p;
558           feature_table_size++;
559           continue;
560         }
561       if (! MPLIST_INTEGER_P (elt))
562         MERROR_GOTO (MERROR_FLT, end);
563       from = MPLIST_INTEGER (elt);
564       elt = MPLIST_NEXT (elt);
565       if (! MPLIST_INTEGER_P (elt))
566         MERROR_GOTO (MERROR_FLT, end);
567       to = MPLIST_INTEGER (elt);
568       elt = MPLIST_NEXT (elt);
569       if (MPLIST_TAIL_P (elt))
570         {
571           category_code = to;
572           to = from;
573         }
574       else if (MPLIST_SYMBOL_P (elt))
575         {
576           if (! mflt_enable_new_feature)
577             {
578               M17N_OBJECT_UNREF (table);
579               return NULL;
580             }
581           if (font)
582             {
583               MFLTOtfSpec spec;
584               if (parse_otf_command (MPLIST_SYMBOL (elt), &spec) < 0)
585                 MERROR_GOTO (MERROR_FLT, end);
586               elt = MPLIST_NEXT (elt);
587               if (! MPLIST_INTEGER_P (elt))
588                 MERROR_GOTO (MERROR_FLT, end);
589               category_code = MPLIST_INTEGER (elt);
590               if (! isalnum (category_code))
591                 MERROR_GOTO (MERROR_FLT, end);
592               apply_otf_feature (font, &spec, from, to, table, category_code);
593             }
594           else
595             need_otf = 1;
596           continue;
597         }
598       else
599         {
600           if (! MPLIST_INTEGER_P (elt))
601             MERROR_GOTO (MERROR_FLT, end);
602           category_code = MPLIST_INTEGER (elt);
603         }
604       if (! isalnum (category_code))
605         MERROR_GOTO (MERROR_FLT, end);
606
607       if (from == to)
608         mchartable_set (table, from, (void *) category_code);
609       else
610         mchartable_set_range (table, from, to, (void *) category_code);
611     }
612
613  end:
614   category = calloc (1, sizeof (FontLayoutCategory));
615   category->table = table;
616   if (need_otf)
617     {
618       category->definition = plist;
619       M17N_OBJECT_REF (plist);
620     }
621   else
622     category->definition = NULL;
623   if (feature_table_head)
624     {
625       int i = 0;
626       category->feature_table.size = feature_table_size;
627       category->feature_table.tag = malloc (sizeof (unsigned int)
628                                             * feature_table_size);
629       category->feature_table.code = malloc (feature_table_size);
630
631       MPLIST_DO (p, feature_table_head)
632         {
633           MPlist *elt;
634           MSymbol feature;
635           if (! MPLIST_PLIST_P (p))
636             continue;
637           elt = MPLIST_PLIST (p);
638           if (! MPLIST_SYMBOL_P (elt))
639             continue;
640           feature = MPLIST_SYMBOL (elt);
641           elt = MPLIST_NEXT (elt);
642           if (! MPLIST_INTEGER_P (elt))
643             continue;
644           category->feature_table.tag[i]
645             = gen_otf_tag (MSYMBOL_NAME (feature), 7);
646           category->feature_table.code[i] = MPLIST_INTEGER (elt);
647           i++;
648         }
649     }
650   return category;
651 }
652
653 #define ref_category_table(CATEGORY) M17N_OBJECT_REF ((CATEGORY)->table)
654
655 static void
656 unref_category_table (FontLayoutCategory *category)
657 {
658   M17N_OBJECT_UNREF (category->table);
659   if (! category->table)
660     {
661       if (category->definition)
662         M17N_OBJECT_UNREF (category->definition);
663       if (category->feature_table.size > 0)
664         {
665           free (category->feature_table.tag);
666           free (category->feature_table.code);
667         }
668       free (category);
669     }
670 }
671
672 static unsigned int
673 gen_otf_tag (char *p, int shift)
674 {
675   unsigned int tag = 0;
676   int i;
677
678   for (i = 0; i < 4 && *p; i++, p++)
679     tag = (tag << shift) | *p;
680   for (; i < 4; i++)
681     tag = (tag << shift) | 0x20;
682   return tag;
683 }
684
685 static char *
686 otf_count_features (char *p, char *end, char stopper, int *count)
687 {
688   int negative = 0;
689
690   *count = 0;
691   if (*p != stopper && *p != '\0')
692     while (1)
693       {
694         (*count)++;
695         if (*p == '*')
696           {
697             p++;
698             if (*p == stopper || *p == '\0')
699               break;
700             return NULL;
701           }
702         if (*p == '~')
703           {
704             if (negative++ == 0)
705               (*count)++;
706             p += 5;
707           }
708         else 
709           p += 4;
710         if (p > end)
711           return NULL;
712         if (*p == stopper || *p == '\0')
713           break;
714         if (*p != ',')
715           return NULL;
716         p++;
717         if (! *p)
718           return NULL;
719       }
720   return p;
721 }
722
723 static void
724 otf_store_features (char *p, char *end, unsigned *buf)
725 {
726   int negative = 0;
727   int i;
728
729   for (i = 0; p < end;)
730     {
731       if (*p == '*')
732         buf[i++] = 0xFFFFFFFF, p += 2, negative = 1;
733       else if (*p == '~')
734         {
735           if (negative++ == 0)
736             buf[i++] = 0xFFFFFFFF;
737           buf[i++] = gen_otf_tag (p + 1, 8), p += 6;
738         }
739       else
740         buf[i++] = gen_otf_tag (p, 8), p += 5;
741     }
742   buf[i] = 0;
743 }
744
745 /* SYMBOL's name        features[0]             for checking    for applying
746                                features[1]      GSUB     GPOS   GSUB    GPOS
747    -------------        ------------------      -------------   ------------
748    SCRIPT               [-1,0]      [-1,0]         any | any       all  all
749    SCRIPT=              NULL        [-1,0]        none & 1        none  all
750    SCRIPT+              [-1,0]        NULL           1 & none      all  none
751    SCRIPT=+             NULL          NULL        none & none     none  none
752    SCRIPT=F1            [F1,0]      [-1,0]          F1 & 1          F1  all
753    SCRIPT+F1            [-1][0]     [F1,0]           1 & F1       none  F1
754    SCRIPT=F1+           [F1,0]        NULL          F1 & none       F1  none
755    SCRIPT=~F2           [-1,F2,0]   [-1,0]         ~F2 & 1      all~F2  all
756    SCRIPT=F1,~F2        [F1,-1,F2,0][-1,0]      F1&~F2 & 1      F1 (*1) all
757
758    (*1) Invalid specification
759  */
760
761 static int
762 parse_otf_command (MSymbol symbol, MFLTOtfSpec *spec)
763 {
764   char *str = MSYMBOL_NAME (symbol);
765   char *end = str + MSYMBOL_NAMELEN (symbol);
766   unsigned int script, langsys;
767   char *features[3];
768   int feature_count[2];         /* [0]:GSUB, [1]:GPOS */
769   int i;
770   char *p;
771
772   memset (spec, 0, sizeof (MFLTOtfSpec));
773
774   spec->sym = symbol;
775   str += 5;                     /* skip the heading ":otf=" or ":otf?" */
776   if (str[-1] == '?')
777     {
778       if (! mflt_enable_new_feature)
779         /* The client can't use this command.  */
780         return -1;
781       if (! *str)
782         /* This is a spec to reset category codes.  */
783         return 0;
784     }
785   spec->script = gen_otf_tag (str, 8);
786   str += 4;
787   if (*str == '/')
788     {
789       spec->langsys = gen_otf_tag (str, 8);
790       str += 4;
791     }
792   else
793     spec->langsys = 0;
794   features[0] = str;
795   if (*str != '=')
796     /* Apply all GSUB features.  */
797       feature_count[0] = -1;
798   else
799     {
800       p = str + 1;
801       str = otf_count_features (p, end, '+', feature_count);
802       if (! str)
803         MERROR (MERROR_FLT, -1);
804     }
805   features[1] = str;
806   if (*str != '+')
807     /* Apply all GPOS features.  */
808     feature_count[1] = -1;
809   else
810     {
811       p = str + 1;
812       str = otf_count_features (p, end, '\0', feature_count + 1);
813       if (! str)
814         MERROR (MERROR_FLT, -1);
815     }
816   features[2] = str;
817   for (i = 0; i < 2; i++)
818     if (feature_count[i])
819       {
820         spec->features[i] = malloc (sizeof (int)
821                                     * (feature_count[i] < 0 ? 2
822                                        : feature_count[i] + 1));
823         if (! spec->features[i])
824           return -2;
825         if (feature_count[i] > 0)
826           otf_store_features (features[i] + 1, features[i + 1],
827                               spec->features[i]);
828         else
829           spec->features[i][0] = 0xFFFFFFFF, spec->features[i][1] = 0;
830       }
831
832   return 0;
833 }
834
835
836 /* Parse OTF command name NAME and store the result in CMD.
837    NAME has this form:
838         :SCRIPT[/[LANGSYS][=[GSUB-FEATURES][+GPOS-FEATURES]]]
839    where GSUB-FEATURES and GPOS-FEATURES have this form:
840         [FEATURE[,FEATURE]*] | ' '  */
841
842 static int
843 load_otf_command (FontLayoutCmd *cmd, MSymbol sym)
844 {
845   char *name = MSYMBOL_NAME (sym);
846   int result;
847
848   if (name[0] != ':')
849     {
850       /* This is old format of "otf:...".  Change it to ":otf=...".  */
851       char *str = alloca (MSYMBOL_NAMELEN (sym) + 2);
852
853       sprintf (str, ":otf=");
854       strcat (str, name + 4);
855       sym = msymbol (str);
856     }
857
858   result = parse_otf_command (sym, &cmd->body.otf);
859   if (result == -2)
860     return result;
861   cmd->type = (name[4] == '?' ? FontLayoutCmdTypeOTFCategory
862                : FontLayoutCmdTypeOTF);
863   return 0;
864 }
865
866
867 /* Read a decimal number from STR preceded by one of "+-><".  '+' and
868    '>' means a plus sign, '-' and '<' means a minus sign.  If the
869    number is greater than 127, limit it to 127.  */
870
871 static int
872 read_decimal_number (char **str)
873 {
874   char *p = *str;
875   int sign = (*p == '-' || *p == '<') ? -1 : 1;
876   int n = 0;
877
878   p++;
879   while (*p >= '0' && *p <= '9')
880     n = n * 10 + *p++ - '0';
881   *str = p;
882   if (n == 0)
883     n = 5;
884   return (n < 127 ? n * sign : 127 * sign);
885 }
886
887
888 /* Read a horizontal and vertical combining positions from STR, and
889    store them in the place pointed by X and Y.  The horizontal
890    position left, center, and right are represented by 0, 1, and 2
891    respectively.  The vertical position top, center, bottom, and base
892    are represented by 0, 1, 2, and 3 respectively.  If successfully
893    read, return 0, else return -1.  */
894
895 static int
896 read_combining_position (char *str, int *x, int *y)
897 {
898   int c = *str++;
899   int i;
900
901   /* Vertical position comes first.  */
902   for (i = 0; i < 4; i++)
903     if (c == "tcbB"[i])
904       {
905         *y = i;
906         break;
907       }
908   if (i == 4)
909     return -1;
910   c = *str;
911   /* Then comse horizontal position.  */
912   for (i = 0; i < 3; i++)
913     if (c == "lcr"[i])
914       {
915         *x = i;
916         return 0;
917       }
918   return -1;
919 }
920
921
922 /* Return a combining code corresponding to SYM.  */
923
924 static int
925 get_combining_command (MSymbol sym)
926 {
927   char *str = msymbol_name (sym);
928   int base_x, base_y, add_x, add_y, off_x, off_y;
929   int c;
930
931   if (read_combining_position (str, &base_x, &base_y) < 0)
932     return 0;
933   str += 2;
934   c = *str;
935   if (c == '.')
936     {
937       off_x = off_y = 128;
938       str++;
939     }
940   else
941     {
942       if (c == '+' || c == '-')
943         {
944           off_y = read_decimal_number (&str) + 128;
945           c = *str;
946         }
947       else
948         off_y = 128;
949       if (c == '<' || c == '>')
950         off_x = read_decimal_number (&str) + 128;
951       else
952         off_x = 128;
953     }
954   if (read_combining_position (str, &add_x, &add_y) < 0)
955     return 0;
956
957   c = MAKE_COMBINING_CODE (base_y, base_x, add_y, add_x, off_y, off_x);
958   return (COMBINING_CODE_TO_CMD_ID (c));
959 }
960
961
962 /* Load a command from PLIST into STAGE, and return that
963    identification number.  If ID is not INVALID_CMD_ID, that means we
964    are loading a top level command or a macro.  In that case, use ID
965    as the identification number of the command.  Otherwise, generate a
966    new id number for the command.  MACROS is a list of raw macros.  */
967
968 static int
969 load_command (FontLayoutStage *stage, MPlist *plist,
970               MPlist *macros, int id)
971 {
972   int i;
973   int result;
974
975   if (MPLIST_INTEGER_P (plist))
976     {
977       int code = MPLIST_INTEGER (plist);
978
979       if (code < 0)
980         MERROR (MERROR_DRAW, INVALID_CMD_ID);
981       return code;
982     }
983   else if (MPLIST_PLIST_P (plist))
984     {
985       /* PLIST ::= ( cond ... ) | ( STRING ... ) | ( INTEGER ... )
986                    | ( ( INTEGER INTEGER ) ... )
987                    | ( ( range INTEGER INTEGER ) ... )
988                    | ( ( SYMBOL STRING ) ... )
989                    | ( ( font-facilty [ INTEGER ] ) ... )
990                    | ( ( font-facilty OTF-SPEC ) ... )  */
991       MPlist *elt = MPLIST_PLIST (plist);
992       int len = MPLIST_LENGTH (elt) - 1;
993       FontLayoutCmd *cmd;
994
995       if (id == INVALID_CMD_ID)
996         {
997           FontLayoutCmd dummy;
998           id = INDEX_TO_CMD_ID (stage->used);
999           MLIST_APPEND1 (stage, cmds, dummy, MERROR_DRAW);
1000         }
1001       cmd = stage->cmds + CMD_ID_TO_INDEX (id);
1002
1003       if (MPLIST_SYMBOL_P (elt))
1004         {
1005           FontLayoutCmdCond *cond;
1006
1007           if (MPLIST_SYMBOL (elt) != Mcond)
1008             MERROR (MERROR_DRAW, INVALID_CMD_ID);
1009           elt = MPLIST_NEXT (elt);
1010           cmd->type = FontLayoutCmdTypeCond;
1011           cond = &cmd->body.cond;
1012           cond->seq_beg = cond->seq_end = -1;
1013           cond->seq_from = cond->seq_to = 0;
1014           cond->n_cmds = len;
1015           MTABLE_CALLOC (cond->cmd_ids, len, MERROR_DRAW);
1016           for (i = 0; i < len; i++, elt = MPLIST_NEXT (elt))
1017             {
1018               int this_id = load_command (stage, elt, macros, INVALID_CMD_ID);
1019
1020               if (this_id == INVALID_CMD_ID || this_id == -2)
1021                 MERROR (MERROR_DRAW, this_id);
1022               /* The above load_command may relocate stage->cmds.  */
1023               cmd = stage->cmds + CMD_ID_TO_INDEX (id);
1024               cond = &cmd->body.cond;
1025               cond->cmd_ids[i] = this_id;
1026               if (this_id <= CMD_ID_OFFSET_INDEX)
1027                 {
1028                   FontLayoutCmd *this_cmd
1029                     = stage->cmds + CMD_ID_TO_INDEX (this_id);
1030
1031                   if (this_cmd->type == FontLayoutCmdTypeRule
1032                       && this_cmd->body.rule.src_type == SRC_SEQ)
1033                     {
1034                       int first_char = this_cmd->body.rule.src.seq.codes[0];
1035
1036                       if (cond->seq_beg < 0)
1037                         {
1038                           /* The first SEQ command.  */
1039                           cond->seq_beg = i;
1040                           cond->seq_from = cond->seq_to = first_char;
1041                         }
1042                       else if (cond->seq_end < 0)
1043                         {
1044                           /* The following SEQ command.  */
1045                           if (cond->seq_from > first_char)
1046                             cond->seq_from = first_char;
1047                           else if (cond->seq_to < first_char)
1048                             cond->seq_to = first_char;
1049                         }
1050                     }
1051                   else
1052                     {
1053                       if (cond->seq_beg >= 0 && cond->seq_end < 0)
1054                         /* The previous one is the last SEQ command.  */
1055                         cond->seq_end = i;
1056                     }
1057                 }
1058               else
1059                 {
1060                   if (cond->seq_beg >= 0 && cond->seq_end < 0)
1061                     /* The previous one is the last SEQ command.  */
1062                     cond->seq_end = i;
1063                 }
1064             }
1065           if (cond->seq_beg >= 0 && cond->seq_end < 0)
1066             /* The previous one is the last SEQ command.  */
1067             cond->seq_end = i;
1068         }
1069       else
1070         {
1071           cmd->type = FontLayoutCmdTypeRule;
1072           if (MPLIST_MTEXT_P (elt))
1073             {
1074               MText *mt = MPLIST_MTEXT (elt);
1075               char *str = (char *) MTEXT_DATA (mt);
1076
1077               if (str[0] != '^')
1078                 {
1079                   mtext_ins_char (mt, 0, '^', 1);
1080                   str = (char *) MTEXT_DATA (mt);
1081                 }
1082               if (regcomp (&cmd->body.rule.src.re.preg, str, REG_EXTENDED))
1083                 MERROR (MERROR_FONT, INVALID_CMD_ID);
1084               cmd->body.rule.src_type = SRC_REGEX;
1085               cmd->body.rule.src.re.pattern = strdup (str);
1086             }
1087           else if (MPLIST_INTEGER_P (elt))
1088             {
1089               cmd->body.rule.src_type = SRC_INDEX;
1090               cmd->body.rule.src.match_idx = MPLIST_INTEGER (elt);
1091             }
1092           else if (MPLIST_PLIST_P (elt))
1093             {
1094               MPlist *pl = MPLIST_PLIST (elt), *p;
1095               int size = MPLIST_LENGTH (pl);
1096
1097               if (MPLIST_INTEGER_P (pl))
1098                 {
1099                   int i;
1100
1101                   cmd->body.rule.src_type = SRC_SEQ;
1102                   cmd->body.rule.src.seq.n_codes = size;
1103                   MTABLE_CALLOC (cmd->body.rule.src.seq.codes, size,
1104                                  MERROR_FONT);
1105                   for (i = 0; i < size; i++, pl = MPLIST_NEXT (pl))
1106                     {
1107                       if (! MPLIST_INTEGER_P (pl))
1108                         MERROR (MERROR_DRAW, INVALID_CMD_ID);
1109                       cmd->body.rule.src.seq.codes[i]
1110                         = (unsigned) MPLIST_INTEGER (pl);
1111                     }
1112                 }
1113               else if (MPLIST_SYMBOL_P (pl))
1114                 {
1115                   if (MPLIST_SYMBOL (pl) == Mrange)
1116                     {
1117                       if (size != 3)
1118                         MERROR (MERROR_FLT, INVALID_CMD_ID);
1119                       cmd->body.rule.src_type = SRC_RANGE;
1120                       pl = MPLIST_NEXT (pl);
1121                       if (! MPLIST_INTEGER_P (pl))
1122                         MERROR (MERROR_DRAW, INVALID_CMD_ID);
1123                       cmd->body.rule.src.range.from
1124                         = (unsigned) MPLIST_INTEGER (pl);
1125                       pl = MPLIST_NEXT (pl);
1126                       if (! MPLIST_INTEGER_P (pl))
1127                         MERROR (MERROR_DRAW, INVALID_CMD_ID);
1128                       cmd->body.rule.src.range.to
1129                         = (unsigned) MPLIST_INTEGER (pl);
1130                     }
1131                   else if (MPLIST_SYMBOL (pl) == Mfont_facility)
1132                     {
1133                       FontLayoutCmdRule *rule = &cmd->body.rule;
1134
1135                       pl = MPLIST_NEXT (pl);
1136                       if (MPLIST_SYMBOL_P (pl))
1137                         {
1138                           MSymbol sym = MPLIST_SYMBOL (pl);
1139                           char *otf_spec = MSYMBOL_NAME (sym);
1140
1141                           if (otf_spec[0] == ':' && otf_spec[1] == 'o'
1142                               && otf_spec[2] == 't' && otf_spec[3] == 'f')
1143                             parse_otf_command (sym, &rule->src.facility.otf_spec);
1144                           else
1145                             MERROR (MERROR_FLT, INVALID_CMD_ID);
1146                           rule->src_type = SRC_OTF_SPEC;
1147                           pl = MPLIST_NEXT (pl);
1148                         }
1149                       else if (MPLIST_TAIL_P (pl))
1150                         MERROR (MERROR_FLT, INVALID_CMD_ID);
1151                       else
1152                         rule->src_type = SRC_HAS_GLYPH;
1153                       rule->src.facility.len = 0;
1154                       MPLIST_DO (p, pl)
1155                         {
1156                           if (! MPLIST_INTEGER_P (p)
1157                               && (MPLIST_SYMBOL_P (p)
1158                                   ? MPLIST_SYMBOL (p) != Mequal
1159                                   : 1))
1160                             MERROR (MERROR_FLT, INVALID_CMD_ID);
1161                           rule->src.facility.len++;
1162                         }
1163                       rule->src.facility.codes = pl;
1164                       M17N_OBJECT_REF (pl);
1165                     }
1166                 }
1167               else
1168                 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1169             }
1170           else
1171             MERROR (MERROR_DRAW, INVALID_CMD_ID);
1172
1173           elt = MPLIST_NEXT (elt);
1174           cmd->body.rule.n_cmds = len;
1175           MTABLE_CALLOC (cmd->body.rule.cmd_ids, len, MERROR_DRAW);
1176           for (i = 0; i < len; i++, elt = MPLIST_NEXT (elt))
1177             {
1178               int this_id = load_command (stage, elt, macros, INVALID_CMD_ID);
1179
1180               if (this_id == INVALID_CMD_ID || this_id == -2)
1181                 MERROR (MERROR_DRAW, this_id);
1182               /* The above load_command may relocate stage->cmds.  */
1183               cmd = stage->cmds + CMD_ID_TO_INDEX (id);
1184               cmd->body.rule.cmd_ids[i] = this_id;
1185             }
1186         }
1187     }
1188   else if (MPLIST_SYMBOL_P (plist))
1189     {
1190       MPlist *elt;
1191       MSymbol sym = MPLIST_SYMBOL (plist);
1192       char *name = msymbol_name (sym);
1193       int len = strlen (name);
1194       FontLayoutCmd cmd;
1195
1196       if (len > 4
1197           && ((name[0] == 'o' && name[1] == 't'
1198                && name[2] == 'f' && name[3] == ':')
1199               || (name[0] == ':' && name[1] == 'o' && name[2] == 't'
1200                   && name[3] == 'f' && (name[4] == '=' || name[4] == '?'))))
1201         {
1202           result = load_otf_command (&cmd, sym);
1203           if (result < 0)
1204             return result;
1205           if (id == INVALID_CMD_ID)
1206             {
1207               id = INDEX_TO_CMD_ID (stage->used);
1208               MLIST_APPEND1 (stage, cmds, cmd, MERROR_DRAW);
1209             }
1210           else
1211             stage->cmds[CMD_ID_TO_INDEX (id)] = cmd;
1212           return id;
1213         }
1214
1215       if (len == 1)
1216         {
1217           if (*name == '=')
1218             return CMD_ID_COPY;
1219           else if (*name == '*')
1220             return CMD_ID_REPEAT;
1221           else if (*name == '<')
1222             return CMD_ID_CLUSTER_BEGIN;
1223           else if (*name == '>')
1224             return CMD_ID_CLUSTER_END;
1225           else if (*name == '|')
1226             return CMD_ID_SEPARATOR;
1227           else if (*name == '[')
1228             return CMD_ID_LEFT_PADDING;
1229           else if (*name == ']')
1230             return CMD_ID_RIGHT_PADDING;
1231           else
1232             id = 0;
1233         }
1234       else
1235         {
1236           id = get_combining_command (sym);
1237           if (id)
1238             return id;
1239         }
1240
1241       i = 1;
1242       MPLIST_DO (elt, macros)
1243         {
1244           if (sym == MPLIST_SYMBOL (MPLIST_PLIST (elt)))
1245             {
1246               id = INDEX_TO_CMD_ID (i);
1247               if (stage->cmds[i].type == FontLayoutCmdTypeMAX)
1248                 id = load_command (stage, MPLIST_NEXT (MPLIST_PLIST (elt)),
1249                                    macros, id);
1250               return id;
1251             }
1252           i++;
1253         }
1254       MERROR (MERROR_DRAW, INVALID_CMD_ID);
1255     }
1256   else
1257     MERROR (MERROR_DRAW, INVALID_CMD_ID);
1258
1259   return id;
1260 }
1261
1262 static void
1263 free_flt_command (FontLayoutCmd *cmd)
1264 {
1265   if (cmd->type == FontLayoutCmdTypeRule)
1266     {
1267       FontLayoutCmdRule *rule = &cmd->body.rule;
1268
1269       if (rule->src_type == SRC_REGEX)
1270         {
1271           free (rule->src.re.pattern);
1272           regfree (&rule->src.re.preg);
1273         }
1274       else if (rule->src_type == SRC_SEQ)
1275         free (rule->src.seq.codes);
1276       free (rule->cmd_ids);
1277     }
1278   else if (cmd->type == FontLayoutCmdTypeCond)
1279     free (cmd->body.cond.cmd_ids);
1280   else if (cmd->type == FontLayoutCmdTypeOTF
1281            || cmd->type == FontLayoutCmdTypeOTFCategory)
1282     {
1283       if (cmd->body.otf.features[0])
1284         free (cmd->body.otf.features[0]);
1285       if (cmd->body.otf.features[1])
1286         free (cmd->body.otf.features[1]);
1287     }
1288 }
1289
1290 /* Load a generator from PLIST into a newly allocated FontLayoutStage,
1291    and return it.  PLIST has this form:
1292       PLIST ::= ( COMMAND ( CMD-NAME COMMAND ) * )
1293 */
1294
1295 static FontLayoutStage *
1296 load_generator (MPlist *plist)
1297 {
1298   FontLayoutStage *stage;
1299   MPlist *elt, *pl;
1300   FontLayoutCmd dummy;
1301   int result;
1302
1303   MSTRUCT_CALLOC (stage, MERROR_DRAW);
1304   MLIST_INIT1 (stage, cmds, 32);
1305   dummy.type = FontLayoutCmdTypeMAX;
1306   MLIST_APPEND1 (stage, cmds, dummy, MERROR_FONT);
1307   MPLIST_DO (elt, MPLIST_NEXT (plist))
1308     {
1309       if (! MPLIST_PLIST_P (elt))
1310         MERROR (MERROR_FONT, NULL);
1311       pl = MPLIST_PLIST (elt);
1312       if (! MPLIST_SYMBOL_P (pl))
1313         MERROR (MERROR_FONT, NULL);
1314       MLIST_APPEND1 (stage, cmds, dummy, MERROR_FONT);
1315     }
1316
1317   /* Load the first command from PLIST into STAGE->cmds[0].  Macros
1318      called in the first command are also loaded from MPLIST_NEXT
1319      (PLIST) into STAGE->cmds[n].  */
1320   result = load_command (stage, plist, MPLIST_NEXT (plist),
1321                          INDEX_TO_CMD_ID (0));
1322   if (result == INVALID_CMD_ID || result == -2)
1323     {
1324       MLIST_FREE1 (stage, cmds);
1325       free (stage);
1326       return NULL;
1327     }
1328
1329   return stage;
1330 }
1331
1332
1333 /* Load stages of the font layout table FLT.  */
1334
1335 static int
1336 load_flt (MFLT *flt, MPlist *key_list)
1337 {
1338   MPlist *top, *plist, *pl, *p;
1339   FontLayoutCategory *category = NULL;
1340   MSymbol sym;
1341
1342   if (key_list)
1343     top = (MPlist *) mdatabase__load_for_keys (flt->mdb, key_list);
1344   else
1345     top = (MPlist *) mdatabase_load (flt->mdb);
1346   if (! top)
1347     return -1;
1348   if (! MPLIST_PLIST_P (top))
1349     {
1350       M17N_OBJECT_UNREF (top);
1351       MERROR (MERROR_FLT, -1);
1352     }
1353
1354   if (key_list)
1355     {
1356       plist = mdatabase__props (flt->mdb);
1357       if (! plist)
1358         MERROR (MERROR_FLT, -1);
1359       MPLIST_DO (plist, plist)
1360         if (MPLIST_PLIST_P (plist))
1361           {
1362             pl = MPLIST_PLIST (plist);
1363             if (! MPLIST_SYMBOL_P (pl)
1364                 || MPLIST_SYMBOL (pl) != Mfont)
1365               continue;
1366             pl = MPLIST_NEXT (pl);
1367             if (! MPLIST_PLIST_P (pl))
1368               continue;
1369             p = MPLIST_PLIST (pl);
1370             if (! MPLIST_SYMBOL_P (p))
1371               continue;
1372             p = MPLIST_NEXT (p);
1373             if (! MPLIST_SYMBOL_P (p))
1374               continue;
1375             flt->family = MPLIST_SYMBOL (p);
1376             MPLIST_DO (p, MPLIST_NEXT (p))
1377               if (MPLIST_SYMBOL_P (p))
1378                 {
1379                   sym = MPLIST_SYMBOL (p);
1380                   if (MSYMBOL_NAME (sym)[0] != ':')
1381                     flt->registry = sym, sym = Mnil;
1382                   else
1383                     break;
1384                 }
1385             if (sym)
1386               {
1387                 char *otf_spec = MSYMBOL_NAME (sym);
1388
1389                 if (otf_spec[0] == ':' && otf_spec[1] == 'o'
1390                     && otf_spec[2] == 't' && otf_spec[3] == 'f')
1391                   parse_otf_command (sym, &flt->otf);
1392               }
1393             break;
1394           }
1395     }
1396   MPLIST_DO (plist, top)
1397     {
1398       if (MPLIST_SYMBOL_P (plist)
1399           && MPLIST_SYMBOL (plist) == Mend)
1400         {
1401           mplist_set (plist, Mnil, NULL);
1402           break;
1403         }
1404       if (! MPLIST_PLIST (plist))
1405         continue;
1406       pl = MPLIST_PLIST (plist);
1407       if (! MPLIST_SYMBOL_P (pl))
1408         continue;
1409       sym = MPLIST_SYMBOL (pl);
1410       pl = MPLIST_NEXT (pl);
1411       if (! pl)
1412         continue;
1413       if (sym == Mcategory)
1414         {
1415           if (category)
1416             unref_category_table (category);
1417           else if (flt->coverage)
1418             {
1419               category = flt->coverage;
1420               ref_category_table (category);
1421               continue;
1422             }
1423           category = load_category_table (pl, NULL);
1424           if (! category)
1425             goto err;
1426           if (! flt->coverage)
1427             {
1428               flt->coverage = category;
1429               ref_category_table (category);
1430             }
1431           if (category->definition)
1432             flt->need_config = 1;
1433         }
1434       else if (sym == Mgenerator)
1435         {
1436           FontLayoutStage *stage;
1437
1438           if (! category)
1439             break;
1440           stage = load_generator (pl);
1441           if (! stage)
1442             break;
1443           stage->category = category;
1444           M17N_OBJECT_REF (category->table);
1445           if (! flt->stages)
1446             flt->stages = mplist ();
1447           mplist_add (flt->stages, Mt, stage);
1448         }
1449     }
1450   if (category)
1451     unref_category_table (category);
1452  err:
1453   if (! MPLIST_TAIL_P (plist))
1454     {
1455       M17N_OBJECT_UNREF (top);
1456       M17N_OBJECT_UNREF (flt->stages);
1457       MERROR (MERROR_FLT, -1);
1458     }
1459   M17N_OBJECT_UNREF (top);
1460   return 0;
1461 }
1462
1463
1464 static void
1465 free_flt_stage (MFLT *flt, FontLayoutStage *stage)
1466 {
1467   int i;
1468
1469   unref_category_table (stage->category);
1470   if (! flt->font_id)
1471     {
1472       for (i = 0; i < stage->used; i++)
1473         free_flt_command (stage->cmds + i);
1474       MLIST_FREE1 (stage, cmds);
1475     }
1476   free (stage);
1477 }
1478
1479 static void
1480 free_flt_list ()
1481 {
1482   if (flt_list)
1483     {
1484       MPlist *plist, *pl;
1485
1486       MPLIST_DO (plist, flt_list)
1487         {
1488           MFLT *flt = MPLIST_VAL (plist);
1489
1490           if (flt->coverage)
1491             unref_category_table (flt->coverage);
1492           if (flt->stages)
1493             {
1494               MPLIST_DO (pl, MPLIST_NEXT (flt->stages))
1495                 free_flt_stage (flt, MPLIST_VAL (pl));
1496               M17N_OBJECT_UNREF (flt->stages);
1497             }
1498           free (flt);
1499           MPLIST_VAL (plist) = NULL;
1500         }
1501       M17N_OBJECT_UNREF (flt_list);
1502     }
1503 }
1504
1505 static int
1506 list_flt ()
1507 {
1508   MPlist *plist, *key_list = NULL;
1509   MPlist *pl;
1510   int result = 0;
1511
1512   if (! (plist = mdatabase_list (Mfont, Mlayouter, Mnil, Mnil)))
1513     return -1;
1514   if (! (flt_list = mplist ()))
1515     goto err;
1516   if (! (key_list = mplist ()))
1517     goto err;
1518   if (! mplist_add (key_list, Mcategory, Mt))
1519     goto err;
1520
1521   MPLIST_DO (pl, plist)
1522     {
1523       MDatabase *mdb = MPLIST_VAL (pl);
1524       MSymbol *tags = mdatabase_tag (mdb);
1525       MFLT *flt;
1526
1527       if (! MSTRUCT_CALLOC_SAFE (flt))
1528         goto err;
1529       flt->name = tags[2];
1530       flt->mdb = mdb;
1531       if (load_flt (flt, key_list) < 0)
1532         free (flt);
1533       else
1534         {
1535           if (MPLIST_TAIL_P (flt_list))
1536             {
1537               flt_min_coverage = mchartable_min_char (flt->coverage->table);
1538               flt_max_coverage = mchartable_max_char (flt->coverage->table);
1539             }
1540           else
1541             {
1542               int c;
1543
1544               c = mchartable_min_char (flt->coverage->table);
1545               if (flt_min_coverage > c)
1546                 flt_min_coverage = c;
1547               c = mchartable_max_char (flt->coverage->table);
1548               if (flt_max_coverage < c)
1549                 flt_max_coverage = c;
1550             }
1551           if (! mplist_push (flt_list, flt->name, flt))
1552             goto err;
1553         }
1554     }
1555   goto end;
1556
1557  err:
1558   free_flt_list ();
1559   result = -1;
1560  end:
1561   M17N_OBJECT_UNREF (plist);  
1562   M17N_OBJECT_UNREF (key_list);
1563   return result;
1564 }
1565
1566 /* FLS (Font Layout Service) */
1567
1568 /* Structure to hold information about a context of FLS.  */
1569
1570 typedef struct
1571 {
1572   /* Pointer to the current stage.  */
1573   FontLayoutStage *stage;
1574
1575   /* Pointer to the category table of the next stage or NULL if none.  */
1576   FontLayoutCategory *category;
1577
1578   /* Pointer to the font.  */
1579   MFLTFont *font;
1580
1581   /* Input and output glyph string.  */
1582   MFLTGlyphString *in, *out;
1583
1584   /* Encode each character or code of a glyph by the current category
1585      table into this array.  An element is a category letter used for
1586      a regular expression matching.  */
1587   char *encoded;
1588   int encoded_offset;
1589   int *match_indices;
1590   int code_offset;
1591   int cluster_begin_idx;
1592   int cluster_begin_pos;
1593   int cluster_end_pos;
1594   int combining_code;
1595   int left_padding;
1596   int check_mask;
1597 } FontLayoutContext;
1598
1599 static int run_command (int, int, int, int, FontLayoutContext *);
1600 static int run_otf (int, MFLTOtfSpec *, int, int, FontLayoutContext *);
1601 static int try_otf (int, MFLTOtfSpec *, int, int, FontLayoutContext *);
1602
1603 #define NMATCH 20
1604
1605 static int
1606 run_rule (int depth,
1607           FontLayoutCmdRule *rule, int from, int to, FontLayoutContext *ctx)
1608 {
1609   int *saved_match_indices = ctx->match_indices;
1610   int match_indices[NMATCH * 2];
1611   int consumed;
1612   int i;
1613   int orig_from = from;
1614   int need_cluster_update = 0;
1615
1616   if (rule->src_type == SRC_REGEX)
1617     {
1618       regmatch_t pmatch[NMATCH];
1619       char saved_code;
1620       int result;
1621
1622       if (from > to)
1623         return 0;
1624       saved_code = ctx->encoded[to - ctx->encoded_offset];
1625       ctx->encoded[to - ctx->encoded_offset] = '\0';
1626       result = regexec (&(rule->src.re.preg),
1627                         ctx->encoded + (from - ctx->encoded_offset),
1628                         NMATCH, pmatch, 0);
1629       if (result == 0 && pmatch[0].rm_so == 0)
1630         {
1631           if (MDEBUG_FLAG () > 2)
1632             MDEBUG_PRINT5 ("\n [FLT] %*s(REGEX \"%s\" \"%s\" %d", depth, "",
1633                            rule->src.re.pattern,
1634                            ctx->encoded + (from - ctx->encoded_offset),
1635                            pmatch[0].rm_eo);
1636           ctx->encoded[to - ctx->encoded_offset] = saved_code;
1637           for (i = 0; i < NMATCH; i++)
1638             {
1639               if (pmatch[i].rm_so < 0)
1640                 match_indices[i * 2] = match_indices[i * 2 + 1] = -1;
1641               else
1642                 {
1643                   match_indices[i * 2] = from + pmatch[i].rm_so;
1644                   match_indices[i * 2 + 1] = from + pmatch[i].rm_eo;
1645                 }
1646             }
1647           ctx->match_indices = match_indices;
1648           to = match_indices[1];
1649         }
1650       else
1651         {
1652           ctx->encoded[to - ctx->encoded_offset] = saved_code;
1653           return 0;
1654         }
1655       need_cluster_update = 1;
1656     }
1657   else if (rule->src_type == SRC_SEQ)
1658     {
1659       int len;
1660
1661       len = rule->src.seq.n_codes;
1662       if (len > (to - from))
1663         return 0;
1664       for (i = 0; i < len; i++)
1665         if (rule->src.seq.codes[i] != GREF (ctx->in, from + i)->c)
1666           break;
1667       if (i < len)
1668         return 0;
1669       to = from + len;
1670       if (MDEBUG_FLAG () > 2)
1671         MDEBUG_PRINT3 ("\n [FLT] %*s(SEQ 0x%X", depth, "",
1672                        rule->src.seq.codes[0]);
1673       need_cluster_update = 1;
1674     }
1675   else if (rule->src_type == SRC_RANGE)
1676     {
1677       int head;
1678
1679       if (from >= to)
1680         return 0;
1681       head = GREF (ctx->in, from)->c;
1682       if (head < rule->src.range.from || head > rule->src.range.to)
1683         return 0;
1684       ctx->code_offset = head - rule->src.range.from;
1685       to = from + 1;
1686       if (MDEBUG_FLAG () > 2)
1687         MDEBUG_PRINT4 ("\n [FLT] %*s(RANGE 0x%X-0x%X", depth, "",
1688                        rule->src.range.from, rule->src.range.to);
1689       need_cluster_update = 1;
1690     }
1691   else if (rule->src_type == SRC_INDEX)
1692     {
1693       if (rule->src.match_idx >= NMATCH)
1694         return 0;
1695       from = ctx->match_indices[rule->src.match_idx * 2];
1696       if (from < 0)
1697         return 0;
1698       to = ctx->match_indices[rule->src.match_idx * 2 + 1];
1699       if (MDEBUG_FLAG () > 2)
1700         MDEBUG_PRINT3 ("\n [FLT] %*s(SUBPART %d", depth, "",
1701                        rule->src.match_idx);
1702       need_cluster_update = 1;
1703     }
1704   else if (rule->src_type == SRC_HAS_GLYPH
1705            || rule->src_type == SRC_OTF_SPEC)
1706     {
1707       static MFLTGlyphString gstring;
1708       MPlist *p;
1709       int idx;
1710
1711       if (rule->src.facility.len > 0)
1712         {
1713           if (! gstring.glyph_size)
1714             {
1715               gstring.glyph_size = ctx->in->glyph_size;
1716               gstring.glyphs = calloc (rule->src.facility.len,
1717                                        gstring.glyph_size);
1718               gstring.allocated = rule->src.facility.len;
1719               gstring.used = rule->src.facility.len;
1720             }
1721           else if (rule->src.facility.len < gstring.allocated)
1722             {
1723               gstring.glyphs = realloc (gstring.glyphs,
1724                                         gstring.glyph_size
1725                                         * rule->src.facility.len);
1726               gstring.allocated = rule->src.facility.len;
1727               gstring.used = rule->src.facility.len;
1728             }
1729
1730           for (i = 0, p = rule->src.facility.codes, idx = from;
1731                i < rule->src.facility.len; i++, p = MPLIST_NEXT (p))
1732             {
1733               if (MPLIST_INTEGER_P (p))
1734                 {
1735                   GREF (&gstring, i)->c = MPLIST_INTEGER (p);
1736                   GREF (&gstring, i)->encoded = 0;
1737                 }
1738               else
1739                 {
1740                   GREF (&gstring, i)->c = GREF (ctx->in, idx)->code;
1741                   GREF (&gstring, i)->encoded = GREF (ctx->in, idx)->encoded;
1742                   idx++;
1743                 }
1744             }
1745         }
1746
1747       if (MDEBUG_FLAG () > 2)
1748         {
1749           if (rule->src_type == SRC_HAS_GLYPH)
1750             MDEBUG_PRINT2 ("\n [FLT] %*s(HAS-GLYPH", depth, "");
1751           else
1752             MDEBUG_PRINT2 ("\n [FLT] %*s(OTF-SPEC", depth, "");
1753           for (i = 0; i < rule->src.facility.len; i++)
1754             MDEBUG_PRINT1 (" %04X", GREF (&gstring, i)->code);
1755         }
1756       if (ctx->font->get_glyph_id (ctx->font, &gstring, 0,
1757                                    rule->src.facility.len) < 0)
1758         {
1759           MDEBUG_PRINT (") FAIL!");
1760           return 0;
1761         }
1762       if (rule->src_type == SRC_OTF_SPEC)
1763         {
1764           MFLTOtfSpec *spec = &rule->src.facility.otf_spec;
1765
1766           if (! ctx->font->check_otf)
1767             {
1768               if ((spec->features[0] && spec->features[0][0] != 0xFFFFFFFF)
1769                   || (spec->features[1] && spec->features[1][0] != 0xFFFFFFFF))
1770                 return 0;
1771             }
1772           else
1773             {
1774               if (rule->src.facility.len == 0)
1775                 {
1776                   if (! ctx->font->check_otf (ctx->font, spec))
1777                     return 0;
1778                 }
1779               else
1780                 {
1781                   int prev_out_used = ctx->out->used, out_used;
1782                   MFLTGlyphAdjustment *adjustment;
1783
1784                   adjustment = alloca ((sizeof *adjustment)
1785                                        * (ctx->out->allocated - ctx->out->used));
1786                   if (! adjustment)
1787                     MERROR (MERROR_FLT, -1);
1788                   memset (adjustment, 0,
1789                           (sizeof *adjustment)
1790                           * (ctx->out->allocated - ctx->out->used));
1791                   ctx->font->drive_otf (ctx->font, &rule->src.facility.otf_spec,
1792                                         &gstring, 0, rule->src.facility.len,
1793                                         ctx->out,
1794                                         adjustment);
1795                   out_used = ctx->out->used;
1796                   ctx->out->used = prev_out_used;
1797                   if (rule->src.facility.len == out_used - prev_out_used)
1798                     {
1799                       for (i = prev_out_used; i < out_used; i++)
1800                         {
1801                           if (GREF (&gstring, i - prev_out_used)->code
1802                               != GREF (ctx->out, i)->code)
1803                             break;
1804                           if (adjustment[i - prev_out_used].set)
1805                             break;
1806                         }
1807                       if (i == out_used)
1808                         return 0;
1809                     }
1810                 }
1811             }
1812         }
1813     }
1814
1815   if (need_cluster_update && ctx->cluster_begin_idx >= 0)
1816     {
1817       for (i = from; i < to; i++)
1818         {
1819           MFLTGlyph *g = GREF (ctx->in, i);
1820           UPDATE_CLUSTER_RANGE (ctx, g);
1821         }
1822     }
1823
1824   consumed = 0;
1825   depth++;
1826   for (i = 0; i < rule->n_cmds; i++)
1827     {
1828       int pos;
1829
1830       if (rule->cmd_ids[i] == CMD_ID_REPEAT)
1831         {
1832           if (! consumed)
1833             continue;
1834           i--;
1835         }
1836       pos = run_command (depth, rule->cmd_ids[i], from, to, ctx);
1837       if (pos < 0)
1838         return pos;
1839       consumed = pos > from;
1840       if (consumed)
1841         from = pos;
1842     }
1843
1844   ctx->match_indices = saved_match_indices;
1845   if (MDEBUG_FLAG () > 2)
1846     MDEBUG_PRINT (")");
1847   return (rule->src_type == SRC_INDEX ? orig_from : to);
1848 }
1849
1850 static int
1851 run_cond (int depth,
1852           FontLayoutCmdCond *cond, int from, int to, FontLayoutContext *ctx)
1853 {
1854   int i, pos = 0;
1855
1856   if (MDEBUG_FLAG () > 2)
1857     MDEBUG_PRINT2 ("\n [FLT] %*s(COND", depth, "");
1858   depth++;
1859   for (i = 0; i < cond->n_cmds; i++)
1860     {
1861       /* TODO: Write a code for optimization utilizaing the info
1862          cond->seq_XXX.  */
1863       if ((pos = run_command (depth, cond->cmd_ids[i], from, to, ctx))
1864           != 0)
1865         break;
1866     }
1867   if (pos < 0)
1868     return pos;
1869   if (MDEBUG_FLAG () > 2)
1870     MDEBUG_PRINT (")");
1871   return (pos);
1872 }
1873
1874 static void
1875 decode_packed_otf_tag (FontLayoutContext *ctx, MFLTGlyphString *gstring,
1876                        int from, int to, FontLayoutCategory *category)
1877 {
1878   for (; from < to; from++)
1879     {
1880       MFLTGlyph *g = GREF (gstring, from);
1881       unsigned int tag = g->internal & 0xFFFFFFF;
1882       char enc;
1883
1884       if (GET_COMBINED (g))
1885         continue;
1886       if (! category)
1887         {
1888           SET_CATEGORY_CODE (g, 0);
1889           continue;
1890         }
1891       enc = '\0';
1892       if (tag & 0xFFFFF80)
1893         {
1894           int i;
1895
1896           /* Clear the feature tag code.  */
1897           g->internal &= ~0xFFFFFFF;
1898           for (i = 0; i < category->feature_table.size; i++)
1899             if (category->feature_table.tag[i] == tag)
1900               {
1901                 enc = category->feature_table.code[i];
1902                 if (ctx->in == gstring)
1903                   ctx->encoded[from - ctx->encoded_offset] = enc;
1904                 break;
1905               }
1906         }
1907       if (! enc)
1908         enc = (g->c > 0 ? (int) mchartable_lookup (category->table, g->c)
1909                : g->c == 0 ? 1 : ' ');
1910       SET_CATEGORY_CODE (g, enc);
1911     }
1912 }
1913
1914 static int
1915 run_otf (int depth,
1916          MFLTOtfSpec *otf_spec, int from, int to, FontLayoutContext *ctx)
1917 {
1918   MFLTFont *font = ctx->font;
1919   int from_idx = ctx->out->used;
1920
1921   if (MDEBUG_FLAG () > 2)
1922     MDEBUG_PRINT3 ("\n [FLT] %*s%s", depth, "", MSYMBOL_NAME (otf_spec->sym));
1923
1924   font->get_glyph_id (font, ctx->in, from, to);
1925   if (! font->drive_otf)
1926     {
1927       if (ctx->out->used + (to - from) > ctx->out->allocated)
1928         return -2;
1929       font->get_metrics (font, ctx->in, from, to);
1930       GCPY (ctx->in, from, to - from, ctx->out, ctx->out->used);
1931       ctx->out->used += to - from;
1932     }
1933   else
1934     {
1935       MFLTGlyphAdjustment *adjustment;
1936       int out_len;
1937       int i;
1938
1939       adjustment = alloca ((sizeof *adjustment)
1940                            * (ctx->out->allocated - ctx->out->used));
1941       if (! adjustment)
1942         MERROR (MERROR_FLT, -1);
1943       memset (adjustment, 0,
1944               (sizeof *adjustment) * (ctx->out->allocated - ctx->out->used));
1945       to = font->drive_otf (font, otf_spec, ctx->in, from, to, ctx->out,
1946                             adjustment);
1947       if (to < 0)
1948         return to;
1949       decode_packed_otf_tag (ctx, ctx->out, from_idx, ctx->out->used,
1950                              ctx->category);
1951       out_len = ctx->out->used - from_idx;
1952       if (otf_spec->features[1])
1953         {
1954           MFLTGlyphAdjustment *a;
1955           MFLTGlyph *g;
1956           
1957           for (i = 0, a = adjustment; i < out_len; i++, a++)
1958             if (a->set)
1959               break;
1960           if (i < out_len)
1961             {
1962               font->get_metrics (font, ctx->out, from_idx, ctx->out->used);
1963               for (g = GREF (ctx->out, from_idx + i);
1964                    i < out_len; i++, a++, g = NEXT (ctx->out, g))
1965                 if (a->set)
1966                   {
1967                     if (a->advance_is_absolute)
1968                       {
1969                         g->xadv = a->xadv;
1970                         g->yadv = a->yadv;
1971                       }
1972                     else if (a->xadv || a->yadv)
1973                       {
1974                         g->xadv += a->xadv;
1975                         g->yadv += a->yadv;
1976                       }
1977                     if (a->xoff || a->yoff || a->back)
1978                       {
1979                         int j;
1980                         MFLTGlyph *gg = PREV (ctx->out, g);
1981                         MFLTGlyphAdjustment *aa = a;
1982
1983                         g->xoff = a->xoff;
1984                         g->yoff = a->yoff;
1985                         g->lbearing += a->xoff;
1986                         g->rbearing += a->xoff;
1987                         g->ascent -= a->yoff;
1988                         g->descent -= a->yoff;
1989                         while (aa->back > 0)
1990                           {
1991                             for (j = 0; j < aa->back;
1992                                  j++, gg = PREV (ctx->out, gg))
1993                               {
1994                                 g->xoff -= gg->xadv;
1995                                 g->lbearing -= gg->xadv;
1996                                 g->rbearing -= gg->xadv;
1997                               }
1998                             aa = aa - aa->back;
1999                             g->xoff += aa->xoff;
2000                             g->yoff += aa->yoff;
2001                             g->lbearing += aa->xoff;
2002                             g->rbearing += aa->xoff;
2003                             g->ascent -= aa->yoff;
2004                             g->descent -= aa->yoff;
2005                           }
2006                       }
2007                     g->adjusted = 1;
2008                   }
2009             }
2010         }
2011     }
2012
2013   if (ctx->cluster_begin_idx >= 0)
2014     for (; from_idx < ctx->out->used; from_idx++)
2015       {
2016         MFLTGlyph *g = GREF (ctx->out, from_idx);
2017         UPDATE_CLUSTER_RANGE (ctx, g);
2018       }
2019   return to;
2020 }
2021
2022 static int
2023 try_otf (int depth, MFLTOtfSpec *otf_spec, int from, int to,
2024          FontLayoutContext *ctx)
2025 {
2026   MFLTFont *font = ctx->font;
2027
2028   if (MDEBUG_FLAG () > 2)
2029     MDEBUG_PRINT3 ("\n [FLT] %*s%s", depth, "", MSYMBOL_NAME (otf_spec->sym));
2030
2031   if (! otf_spec->features[0] && ! otf_spec->features[1])
2032     {
2033       /* Reset categories.  */
2034       MCharTable *table = ctx->category->table;
2035       int i;
2036
2037       for (i = from; i < to; i++)
2038         {
2039           MFLTGlyph *g = GREF (ctx->in, i);
2040
2041           if (! GET_COMBINED (g))
2042             {
2043               char enc = (GET_ENCODED (g)
2044                           ? (g->c > 0 ? (int) mchartable_lookup (table, g->c)
2045                              : 1)
2046                           : g->code
2047                           ? (int) mchartable_lookup (table, g->code)
2048                           : ' ');
2049               SET_CATEGORY_CODE (g, enc);
2050               ctx->encoded[i - ctx->encoded_offset] = enc;
2051             }
2052         }
2053       return from;
2054     }
2055
2056   if (ctx->stage->category->feature_table.size == 0)
2057     return from;
2058
2059   font->get_glyph_id (font, ctx->in, from, to);
2060   if (mflt_try_otf)
2061     {
2062       to = mflt_try_otf (font, otf_spec, ctx->in, from, to);
2063       if (to < 0)
2064         return from;
2065       decode_packed_otf_tag (ctx, ctx->in, from, to, ctx->stage->category);
2066     }
2067   return from;
2068 }
2069
2070 static char work[16];
2071
2072 static char *
2073 dump_combining_code (int code)
2074 {
2075   char *vallign = "tcbB";
2076   char *hallign = "lcr";
2077   char *p;
2078   int off_x, off_y;
2079
2080   if (! code)
2081     return "none";
2082   work[0] = vallign[COMBINING_CODE_BASE_Y (code)];
2083   work[1] = hallign[COMBINING_CODE_BASE_X (code)];
2084   off_y = COMBINING_CODE_OFF_Y (code);
2085   off_x = COMBINING_CODE_OFF_X (code);
2086   if (off_y > 0)
2087     sprintf (work + 2, "+%d", off_y);
2088   else if (off_y < 0)
2089     sprintf (work + 2, "%d", off_y);
2090   else if (off_x == 0)
2091     sprintf (work + 2, ".");
2092   p = work + strlen (work);
2093   if (off_x > 0)
2094     sprintf (p, ">%d", off_x);
2095   else if (off_x < 0)
2096     sprintf (p, "<%d", -off_x);
2097   p += strlen (p);
2098   p[0] = vallign[COMBINING_CODE_ADD_Y (code)];
2099   p[1] = hallign[COMBINING_CODE_ADD_X (code)];
2100   p[2] = '\0';
2101   return work;
2102 }
2103
2104 static int
2105 run_command (int depth, int id, int from, int to, FontLayoutContext *ctx)
2106 {
2107   MFLTGlyph *g;
2108
2109   if (id >= 0)
2110     {
2111       int i;
2112       MCharTable *table = ctx->category ? ctx->category->table : NULL;
2113       char enc;
2114
2115       /* Direct code (== ctx->code_offset + id) output.
2116          The source is not consumed.  */
2117       if (MDEBUG_FLAG () > 2)
2118         MDEBUG_PRINT3 ("\n [FLT] %*s(DIRECT 0x%X", depth, "",
2119                        ctx->code_offset + id);
2120       i = (from < to || from == 0) ? from : from - 1;
2121       GDUP (ctx, i);
2122       g = GREF (ctx->out, ctx->out->used - 1);
2123       g->c = g->code = ctx->code_offset + id;
2124       if (ctx->combining_code)
2125         SET_COMBINING_CODE (g, ctx, ctx->combining_code);
2126       else if (table)
2127         {
2128           enc = (GET_ENCODED (g)
2129                  ? (g->c > 0 ? (int) mchartable_lookup (table, g->c) : 1)
2130                  : g->code
2131                  ? (int) mchartable_lookup (table, g->code)
2132                  : ' ');
2133           SET_CATEGORY_CODE (g, enc);
2134         }
2135       SET_ENCODED (g, 0);
2136       SET_MEASURED (g, 0);
2137       if (ctx->left_padding)
2138         SET_LEFT_PADDING (g, ctx, LeftPaddingMask);
2139       for (i = from; i < to; i++)
2140         {
2141           MFLTGlyph *tmp = GREF (ctx->in, i);
2142
2143           if (g->from > tmp->from)
2144             g->from = tmp->from;
2145           else if (g->to < tmp->to)
2146             g->to = tmp->to;
2147         }
2148       if (ctx->cluster_begin_idx >= 0)
2149         UPDATE_CLUSTER_RANGE (ctx, g);
2150       ctx->code_offset = ctx->combining_code = ctx->left_padding = 0;
2151       if (MDEBUG_FLAG () > 2)
2152         MDEBUG_PRINT (")");
2153       return (from);
2154     }
2155
2156   if (id <= CMD_ID_OFFSET_INDEX)
2157     {
2158       int idx = CMD_ID_TO_INDEX (id);
2159       FontLayoutCmd *cmd;
2160
2161       if (idx >= ctx->stage->used)
2162         MERROR (MERROR_DRAW, -1);
2163       cmd = ctx->stage->cmds + idx;
2164       if (cmd->type == FontLayoutCmdTypeRule)
2165         to = run_rule (depth, &cmd->body.rule, from, to, ctx);
2166       else if (cmd->type == FontLayoutCmdTypeCond)
2167         to = run_cond (depth, &cmd->body.cond, from, to, ctx);
2168       else if (cmd->type == FontLayoutCmdTypeOTF)
2169         to = run_otf (depth, &cmd->body.otf, from, to, ctx);
2170       else if (cmd->type == FontLayoutCmdTypeOTFCategory)
2171         to = try_otf (depth, &cmd->body.otf, from, to, ctx);
2172       return to;
2173     }
2174
2175   if (id <= CMD_ID_OFFSET_COMBINING)
2176     {
2177       ctx->combining_code = CMD_ID_TO_COMBINING_CODE (id);
2178       if (MDEBUG_FLAG () > 2)
2179         MDEBUG_PRINT3 ("\n [FLT] %*s(CMB %s)", depth, "",
2180                        dump_combining_code (ctx->combining_code));
2181       return from;
2182     }
2183
2184   switch (id)
2185     {
2186     case CMD_ID_COPY:
2187       {
2188         if (from >= to)
2189           return from;
2190         GDUP (ctx, from);
2191         g = GREF (ctx->out, ctx->out->used - 1);
2192         if (ctx->combining_code)
2193           SET_COMBINING_CODE (g, ctx, ctx->combining_code);
2194         if (ctx->left_padding)
2195           SET_LEFT_PADDING (g, ctx, LeftPaddingMask);
2196         if (ctx->cluster_begin_idx >= 0)
2197           UPDATE_CLUSTER_RANGE (ctx, g);
2198         if (MDEBUG_FLAG () > 2)
2199           {
2200             if (g->c < 0)
2201               MDEBUG_PRINT2 ("\n [FLT] %*s(COPY |)", depth, "");
2202             else
2203               MDEBUG_PRINT3 ("\n [FLT] %*s(COPY 0x%X)", depth, "", g->c);
2204           }
2205         ctx->code_offset = ctx->combining_code = ctx->left_padding = 0;
2206         return (from + 1);
2207       }
2208
2209     case CMD_ID_CLUSTER_BEGIN:
2210       if (ctx->cluster_begin_idx < 0)
2211         {
2212           if (MDEBUG_FLAG () > 2)
2213             MDEBUG_PRINT3 ("\n [FLT] %*s<%d", depth, "",
2214                            GREF (ctx->in, from)->from);
2215           ctx->cluster_begin_idx = ctx->out->used;
2216           ctx->cluster_begin_pos = GREF (ctx->in, from)->from;
2217           ctx->cluster_end_pos = GREF (ctx->in, from)->to;
2218         }
2219       return from;
2220
2221     case CMD_ID_CLUSTER_END:
2222       if (ctx->cluster_begin_idx >= 0
2223           && ctx->cluster_begin_idx < ctx->out->used)
2224         {
2225           int i;
2226
2227           if (MDEBUG_FLAG () > 2)
2228             MDEBUG_PRINT1 (" %d>", ctx->cluster_end_pos + 1);
2229           for (i = ctx->cluster_begin_idx; i < ctx->out->used; i++)
2230             {
2231               GREF (ctx->out, i)->from = ctx->cluster_begin_pos;
2232               GREF (ctx->out, i)->to = ctx->cluster_end_pos;
2233             }
2234           ctx->cluster_begin_idx = -1;
2235         }
2236       return from;
2237
2238     case CMD_ID_SEPARATOR:
2239       {
2240         int i;
2241
2242         if (MDEBUG_FLAG () > 2)
2243           MDEBUG_PRINT2 ("\n [FLT] %*s|", depth, "");
2244         i = from < to ? from : from - 1;
2245         GDUP (ctx, i);
2246         g = GREF (ctx->out, ctx->out->used - 1);
2247         g->c = -1, g->code = 0;
2248         g->xadv = g->yadv = 0;
2249         SET_ENCODED (g, 1);
2250         SET_MEASURED (g, 0);
2251         SET_CATEGORY_CODE (g, ' ');
2252         return from;
2253       }
2254
2255     case CMD_ID_LEFT_PADDING:
2256       if (MDEBUG_FLAG () > 2)
2257         MDEBUG_PRINT2 ("\n [FLT] %*s[", depth, "");
2258       ctx->left_padding = 1;
2259       return from;
2260
2261     case CMD_ID_RIGHT_PADDING:
2262       if (ctx->out->used > 0)
2263         {
2264           if (MDEBUG_FLAG () > 2)
2265             MDEBUG_PRINT2 ("\n [FLT] %*s]", depth, "");
2266           g = GREF (ctx->out, ctx->out->used - 1);
2267           SET_RIGHT_PADDING (g, ctx, RightPaddingMask);
2268         }
2269       return from;
2270     }
2271
2272   MERROR (MERROR_DRAW, -1);
2273 }
2274
2275 static int
2276 run_stages (MFLTGlyphString *gstring, int from, int to,
2277             MFLT *flt, FontLayoutContext *ctx)
2278 {
2279   MFLTGlyphString buf, *temp;
2280   int stage_idx = 0;
2281   int orig_from = from, orig_to = to;
2282   int from_pos, to_pos, len;
2283   int i, j;
2284   MFLTGlyph *g;
2285   MPlist *stages = flt->stages;
2286   FontLayoutCategory *prev_category = NULL;
2287
2288   from_pos = GREF (ctx->in, from)->from;
2289   to_pos = GREF (ctx->in, to - 1)->to;
2290   len = to_pos - from_pos;
2291
2292   buf = *(ctx->in);
2293   buf.glyphs = NULL;
2294   GINIT (ctx->out, ctx->out->allocated);
2295   ctx->encoded = alloca (ctx->out->allocated);
2296   if (! ctx->out->glyphs || ! ctx->encoded)
2297     return -1;
2298
2299   for (stage_idx = 0; 1; stage_idx++)
2300     {
2301       MCharTable *table;
2302       int result;
2303
2304       ctx->stage = (FontLayoutStage *) MPLIST_VAL (stages);
2305       table = ctx->stage->category->table;
2306       stages = MPLIST_NEXT (stages);
2307       if (MPLIST_TAIL_P (stages))
2308         ctx->category = NULL;
2309       else
2310         ctx->category = ((FontLayoutStage *) MPLIST_VAL (stages))->category;
2311       ctx->code_offset = ctx->combining_code = ctx->left_padding = 0;
2312       ctx->encoded_offset = from;
2313       for (i = from; i < to; i++)
2314         {
2315           MFLTGlyph *g = GREF (ctx->in, i);
2316           char enc;
2317
2318           if (GET_COMBINED (g)
2319               || (prev_category && prev_category != ctx->stage->category))
2320             {
2321               enc = (GET_ENCODED (g)
2322                      ? (g->c > 0 ? (int) mchartable_lookup (table, g->c) : 1)
2323                      : g->code
2324                      ? (int) mchartable_lookup (table, g->code)
2325                      : ' ');
2326               if (! GET_COMBINED (g))
2327                 SET_CATEGORY_CODE (g, enc);
2328             }
2329           else
2330             enc = GET_CATEGORY_CODE (g);
2331           ctx->encoded[i - from] = enc;
2332           if (! enc && stage_idx == 0)
2333             {
2334               to = i;
2335               break;
2336             }
2337         }
2338       ctx->encoded[i - from] = '\0';
2339       ctx->match_indices[0] = from;
2340       ctx->match_indices[1] = to;
2341       for (i = 2; i < NMATCH; i++)
2342         ctx->match_indices[i] = -1;
2343
2344       if (MDEBUG_FLAG () > 2)
2345         {
2346           MDEBUG_PRINT2 ("\n [FLT]   (STAGE %d \"%s\"", stage_idx,
2347                          ctx->encoded);
2348           MDEBUG_PRINT (" (");
2349           for (i = from; i < to; i++)
2350             {
2351               g = GREF (ctx->in, i);
2352               if (g->c == -1)
2353                 MDEBUG_PRINT2 ("%*s|", (i > 0), "");
2354               else
2355                 MDEBUG_PRINT3 ("%*s%04X", (i > 0), "", GREF (ctx->in, i)->code);
2356             }
2357           MDEBUG_PRINT (")");
2358         }
2359       result = run_command (4, INDEX_TO_CMD_ID (0), from, to, ctx);
2360       if (MDEBUG_FLAG () > 2)
2361         MDEBUG_PRINT (")");
2362       if (result < 0)
2363         return result;
2364
2365       /* If this is the last stage, break the loop. */
2366       if (MPLIST_TAIL_P (stages))
2367         break;
2368
2369       /* Otherwise, prepare for the next stage.   */
2370       prev_category = ctx->stage->category;
2371       temp = ctx->in;
2372       ctx->in = ctx->out;
2373       if (buf.glyphs)
2374         ctx->out = temp;
2375       else
2376         {
2377           GINIT (&buf, ctx->out->allocated);
2378           ctx->out = &buf;
2379         }
2380       ctx->out->used = 0;
2381
2382       from = 0;
2383       to = ctx->in->used;
2384     }
2385
2386   if (ctx->out->used > 0)
2387     {
2388       int *g_indices;
2389       int x_ppem = ctx->font->x_ppem << 6, y_ppem = ctx->font->y_ppem << 6;
2390
2391       /* Remove separator glyphs.  */
2392       for (i = 0; i < ctx->out->used;)
2393         {
2394           g = GREF (ctx->out, i);
2395           if (g->c < 0)
2396             GREPLACE (NULL, 0, 0, ctx->out, i, i + 1);
2397           else
2398             i++;
2399         }
2400
2401       /* Get actual glyph IDs of glyphs.  */
2402       ctx->font->get_glyph_id (ctx->font, ctx->out, 0, ctx->out->used);
2403
2404       /* Check if all characters in the range are covered by some
2405          glyph(s).  If not, change <from> and <to> of glyphs to cover
2406          uncovered characters.  */
2407       g_indices = alloca (sizeof (int) * len);
2408       if (! g_indices)
2409         return -1;
2410       for (i = 0; i < len; i++) g_indices[i] = -1;
2411       for (i = 0; i < ctx->out->used; i++)
2412         {
2413           int pos;
2414
2415           g = GREF (ctx->out, i);
2416           for (pos = g->from; pos <= g->to; pos++)
2417             if (g_indices[pos - from_pos] < 0)
2418               g_indices[pos - from_pos] = i;
2419         }
2420       for (i = 0; i < len; i++)
2421         if (g_indices[i] < 0)
2422           {
2423             if (i == 0)
2424               {
2425                 int this_from;
2426
2427                 for (i++; i < len && g_indices[i] < 0; i++);
2428                 j = g_indices[i];
2429                 g = GREF (ctx->out, j);
2430                 this_from = g->from;
2431                 do {
2432                   g->from = orig_from + i;
2433                 } while (++j < ctx->out->used
2434                          && (g = GREF (ctx->out, j))
2435                          && g->from == this_from);
2436               }
2437             else
2438               {
2439                 int this_to;
2440
2441                 j = g_indices[i - 1];
2442                 g = GREF (ctx->out, j);
2443                 this_to = g->to;
2444                 do {
2445                   g->to = orig_from + i + 1;
2446                 } while (--j >= 0
2447                          && (g = GREF (ctx->out, j))
2448                          && g->to == this_to);
2449               }
2450           }
2451
2452       ctx->font->get_metrics (ctx->font, ctx->out, 0, ctx->out->used);
2453
2454       /* Handle combining.  */
2455       if (ctx->check_mask & CombinedMask)
2456         {
2457           MFLTGlyph *base = GREF (ctx->out, 0);
2458           int base_height = base->ascent + base->descent;
2459           int base_width = base->rbearing - base->lbearing;
2460           int combining_code;
2461
2462           for (i = 1; i < ctx->out->used; i++)
2463             {
2464               if ((g = GREF (ctx->out, i))
2465                   && GET_COMBINED (g)
2466                   && (combining_code = GET_COMBINING_CODE (g)))
2467                 {
2468                   int height = g->ascent + g->descent;
2469                   int width = g->rbearing - g->lbearing;
2470                   int base_x, base_y, add_x, add_y, off_x, off_y;
2471
2472                   if (base->from > g->from)
2473                     base->from = g->from;
2474                   else if (base->to < g->to)
2475                     base->to = g->to;
2476                 
2477                   base_x = COMBINING_CODE_BASE_X (combining_code);
2478                   base_y = COMBINING_CODE_BASE_Y (combining_code);
2479                   add_x = COMBINING_CODE_ADD_X (combining_code);
2480                   add_y = COMBINING_CODE_ADD_Y (combining_code);
2481                   off_x = COMBINING_CODE_OFF_X (combining_code);
2482                   off_y = COMBINING_CODE_OFF_Y (combining_code);
2483
2484                   g->xoff = ((base_width * base_x - width * add_x) / 2
2485                              + x_ppem * off_x / 100
2486                              - (base->xadv - base->lbearing) - g->lbearing);
2487                   if (base_y < 3)
2488                     g->yoff = base_height * base_y / 2 - base->ascent;
2489                   else
2490                     g->yoff = 0;
2491                   if (add_y < 3)
2492                     g->yoff -= height * add_y / 2 - g->ascent;
2493                   g->yoff -= y_ppem * off_y / 100;
2494                   if (base->lbearing > base->xadv + g->lbearing + g->xoff)
2495                     base->lbearing = base->xadv + g->lbearing + g->xoff;
2496                   if (base->rbearing < base->xadv + g->rbearing + g->xoff)
2497                     base->rbearing = base->xadv + g->rbearing + g->xoff;
2498                   if (base->ascent < g->ascent - g->yoff)
2499                     base->ascent = g->ascent - g->yoff;
2500                   if (base->descent < g->descent - g->yoff)
2501                     base->descent = g->descent - g->yoff;
2502                   g->xadv = g->yadv = 0;
2503                   if (GET_RIGHT_PADDING (g))
2504                     SET_RIGHT_PADDING (base, ctx, RightPaddingMask);
2505                   g->adjusted = 1;
2506                 }
2507               else
2508                 {
2509                   base = g;
2510                   base_height = g->ascent + g->descent;
2511                   base_width = g->rbearing - g->lbearing;
2512                 }
2513             }
2514         }
2515
2516       /* Handle padding */
2517       if (ctx->check_mask & (LeftPaddingMask | RightPaddingMask))
2518         for (i = 0; i < ctx->out->used; i++)
2519           {
2520             g = GREF (ctx->out, i);
2521             if (! GET_COMBINED (g))
2522               {
2523                 if (GET_RIGHT_PADDING (g) && g->rbearing > g->xadv)
2524                   {
2525                     g->xadv = g->rbearing;
2526                     g->adjusted = 1;
2527                   }
2528                 if (GET_LEFT_PADDING (g) && g->lbearing < 0)
2529                   {
2530                     g->xoff += - g->lbearing;
2531                     g->xadv += - g->lbearing;
2532                     g->rbearing += - g->lbearing;
2533                     g->lbearing = 0;
2534                     g->adjusted = 1;
2535                   }
2536               }
2537           }
2538     }
2539
2540   GREPLACE (ctx->out, 0, ctx->out->used, gstring, orig_from, orig_to);
2541   to = orig_from + ctx->out->used;
2542   return to;
2543 }
2544
2545 static void
2546 setup_combining_coverage (int from, int to, void *val, void *arg)
2547 {
2548   int combining_class = (int) val;
2549   int category = 0;
2550
2551   if (combining_class < 200)
2552     category = 'a';
2553   else if (combining_class <= 204)
2554     {
2555       if ((combining_class % 2) == 0)
2556         category = "bcd"[(combining_class - 200) / 2];
2557     }
2558   else if (combining_class <= 232)
2559     {
2560       if ((combining_class % 2) == 0)
2561         category = "efghijklmnopq"[(combining_class - 208) / 2];
2562     }
2563   else if (combining_class == 233)
2564     category = 'r';
2565   else if (combining_class == 234)
2566     category = 's';
2567   else if (combining_class == 240)
2568     category = 't';
2569   mchartable_set_range ((MCharTable *) arg, from, to, (void *) category);
2570 }
2571
2572 static void
2573 setup_combining_flt (MFLT *flt)
2574 {
2575   MSymbol type;
2576   MCharTable *combininig_class_table
2577     = mchar_get_prop_table (Mcombining_class, &type);
2578
2579   mchartable_set_range (flt->coverage->table, 0, 0x10FFFF, (void *) 'u');
2580   if (combininig_class_table)
2581     mchartable_map (combininig_class_table, (void *) 0,
2582                     setup_combining_coverage, flt->coverage->table);
2583 }
2584
2585 #define CHECK_FLT_STAGES(flt) ((flt)->stages || load_flt (flt, NULL) == 0)
2586
2587 static FontLayoutCategory *
2588 configure_category (FontLayoutCategory *category, MFLTFont *font)
2589 {
2590   if (! mflt_font_id || ! mflt_iterate_otf_feature)
2591     {
2592       FontLayoutCategory *new = malloc (sizeof (FontLayoutCategory));
2593       new->definition = NULL;
2594       new->table = category->table;
2595       M17N_OBJECT_REF (new->table);
2596       return new;
2597     }
2598   return load_category_table (category->definition, font);
2599 }
2600
2601 static MFLT *
2602 configure_flt (MFLT *flt, MFLTFont *font, MSymbol font_id)
2603 {
2604   MPlist *plist;
2605   MFLT *configured;
2606
2607   if (! mflt_font_id || ! mflt_iterate_otf_feature)
2608     return flt;
2609   MPLIST_DO (plist, flt_list)
2610     {
2611       configured = MPLIST_VAL (plist);
2612       if (! configured->font_id)
2613         break;
2614       if (configured->name == flt->name
2615           && configured->font_id == font_id)
2616         return configured;
2617     }
2618   if (! MSTRUCT_CALLOC_SAFE (configured))
2619     return flt;
2620   *configured = *flt;
2621   configured->stages = mplist_copy (flt->stages);
2622   MPLIST_DO (plist, configured->stages)
2623     {
2624       FontLayoutStage *stage = MPLIST_VAL (plist);
2625       if (stage->category->definition)
2626         {
2627           MSTRUCT_CALLOC (stage, MERROR_FLT);
2628           *stage = *((FontLayoutStage *) MPLIST_VAL (plist));
2629           stage->category = configure_category (stage->category, font);
2630           MPLIST_VAL (plist) = stage;
2631         }
2632       else
2633         M17N_OBJECT_REF (stage->category->table);
2634     }
2635   configured->need_config = 0;
2636   configured->font_id = font_id;
2637   mplist_push (flt_list, flt->name, configured);
2638   return configured;
2639 }
2640 \f
2641 /* Internal API */
2642
2643 int m17n__flt_initialized;
2644
2645 \f
2646 /* External API */
2647
2648 /* The following two are actually not exposed to a user but concealed
2649    by the macro M17N_INIT (). */
2650
2651 void
2652 m17n_init_flt (void)
2653 {
2654   int mdebug_flag = MDEBUG_INIT;
2655
2656   merror_code = MERROR_NONE;
2657   if (m17n__flt_initialized++)
2658     return;
2659   m17n_init_core ();
2660   if (merror_code != MERROR_NONE)
2661     {
2662       m17n__flt_initialized--;
2663       return;
2664     }
2665
2666   MDEBUG_PUSH_TIME ();
2667
2668   Mcond = msymbol ("cond");
2669   Mrange = msymbol ("range");
2670   Mfont = msymbol ("font");
2671   Mlayouter = msymbol ("layouter");
2672   Mcombining = msymbol ("combining");
2673   Mfont_facility = msymbol ("font-facility");
2674   Mequal = msymbol ("=");
2675   Mgenerator = msymbol ("generator");
2676   Mend = msymbol ("end");
2677
2678   mflt_enable_new_feature = 0;
2679   mflt_iterate_otf_feature = NULL;
2680   mflt_font_id = NULL;
2681   mflt_try_otf = NULL;
2682
2683   MDEBUG_PRINT_TIME ("INIT", (mdebug__output, " to initialize the flt modules."));
2684   MDEBUG_POP_TIME ();
2685 }
2686
2687 void
2688 m17n_fini_flt (void)
2689 {
2690   int mdebug_flag = MDEBUG_FINI;
2691
2692   if (m17n__flt_initialized == 0
2693       || --m17n__flt_initialized > 0)
2694     return;
2695
2696   MDEBUG_PUSH_TIME ();
2697   free_flt_list ();
2698   MDEBUG_PRINT_TIME ("FINI", (mdebug__output, " to finalize the flt modules."));
2699   MDEBUG_POP_TIME ();
2700   m17n_fini_core ();
2701 }
2702
2703 /*** @} */ 
2704 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
2705
2706 /*** @addtogroup m17nFLT */
2707 /*** @{ */
2708 /*=*/
2709
2710 /*=*/
2711 /***en
2712     @brief Return an FLT object that has a specified name.
2713
2714     The mflt_get () function returns an FLT object whose name is $NAME.
2715
2716     @return
2717     If the operation was successful, mflt_get () returns a pointer
2718     to the found FLT object.  Otherwise, it returns @c NULL.  */
2719
2720 /***ja
2721     @brief »ØÄꤵ¤ì¤¿Ì¾Á°¤ò»ý¤Ä FLT ¥ª¥Ö¥¸¥§¥¯¥È¤òÊÖ¤¹.
2722
2723     ´Ø¿ô mflt_get () ¤Ï¡¢$NAME ¤È¤¤¤¦Ì¾Á°¤ò»ý¤Ä FLT ¥ª¥Ö¥¸¥§¥¯¥È¤òÊÖ¤¹¡£
2724
2725     @return
2726     ¤â¤·À®¸ù¤¹¤ì¤Ð¡¢mflt_get () ¤Ï¸«¤Ä¤«¤Ã¤¿ FLT
2727     ¥ª¥Ö¥¸¥§¥¯¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¼ºÇÔ¤·¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤¹¡£  */
2728
2729 MFLT *
2730 mflt_get (MSymbol name)
2731 {
2732   MFLT *flt;
2733   MPlist *plist;
2734
2735   if (! flt_list && list_flt () < 0)
2736     return NULL;
2737   for (plist = flt_list; plist; plist = plist->next)
2738     if (((MFLT *) MPLIST_VAL (plist))->font_id == Mnil)
2739       break;
2740   flt = mplist_get (plist, name);
2741   if (! flt || ! CHECK_FLT_STAGES (flt))
2742     return NULL;
2743   if (flt->name == Mcombining
2744       && ! mchartable_lookup (flt->coverage->table, 0))
2745     setup_combining_flt (flt);
2746
2747   return flt;
2748 }
2749
2750 /*=*/
2751 /***en
2752     @brief Find an FLT suitable for the specified character and font.
2753
2754     The mflt_find () function returns the most appropriate FLT for
2755     layouting character $C with font $FONT.
2756
2757     @return
2758     If the operation was successful, mflt_find () returns a pointer
2759     to the found FLT object.  Otherwise, it returns @c NULL.  */
2760
2761 /***ja
2762     @brief »ØÄꤵ¤ì¤¿Ê¸»ú¤È¥Õ¥©¥ó¥È¤Ë¹ç¤Ã¤¿ FLT ¤òõ¤¹.
2763
2764     ´Ø¿ô mflt_find () ¤Ï¡¢Ê¸»ú $C ¤ò¥Õ¥©¥ó¥È $FONT
2765     ¤Ç¥ì¥¤¥¢¥¦¥È¤¹¤ë¤¿¤á¤ËºÇ¤âŬÀڤʠFLT ¤òÊÖ¤¹¡£
2766
2767     @return
2768     ¤â¤·À®¸ù¤¹¤ì¤Ð¡¢mflt_find () ¤Ï¸«¤Ä¤«¤Ã¤¿ FLT
2769     ¥ª¥Ö¥¸¥§¥¯¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¼ºÇÔ¤·¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤¹¡£  */
2770
2771 MFLT *
2772 mflt_find (int c, MFLTFont *font)
2773 {
2774   MPlist *plist, *pl;
2775   MFLT *flt;
2776   static MSymbol unicode_bmp = NULL, unicode_full = NULL;
2777
2778   if (! unicode_bmp)
2779     {
2780       unicode_bmp = msymbol ("unicode-bmp");
2781       unicode_full = msymbol ("unicode-full");
2782     }
2783
2784   if (! flt_list && list_flt () < 0)
2785     return NULL;
2786   /* Skip configured FLTs.  */
2787   MPLIST_DO (plist, flt_list)
2788     if (((MFLT *) MPLIST_VAL (plist))->font_id == Mnil)
2789       break;
2790   if (font)
2791     {
2792       MFLT *best = NULL;
2793
2794       MPLIST_DO (pl, plist)
2795         {
2796           flt = MPLIST_VAL (pl);
2797           if (flt->registry != unicode_bmp
2798               && flt->registry != unicode_full)
2799             continue;
2800           if (flt->family && flt->family != font->family)
2801             continue;
2802           if (flt->name == Mcombining
2803               && ! mchartable_lookup (flt->coverage->table, 0))
2804             setup_combining_flt (flt);
2805           if (c >= 0
2806               && ! mchartable_lookup (flt->coverage->table, c))
2807             continue;
2808           if (flt->otf.sym)
2809             {
2810               MFLTOtfSpec *spec = &flt->otf;
2811
2812               if (! font->check_otf)
2813                 {
2814                   if ((spec->features[0] && spec->features[0][0] != 0xFFFFFFFF)
2815                       || (spec->features[1] && spec->features[1][0] != 0xFFFFFFFF))
2816                     continue;
2817                 }
2818               else if (! font->check_otf (font, spec))
2819                 continue;
2820               goto found;
2821             }
2822           best = flt;
2823         }
2824       if (best == NULL)
2825         return NULL;
2826       flt = best;
2827       goto found;
2828     }
2829   if (c >= 0)
2830     {
2831       MPLIST_DO (pl, plist)
2832         {
2833           flt = MPLIST_VAL (pl);
2834           if (mchartable_lookup (flt->coverage->table, c))
2835             goto found;
2836         }
2837     }
2838   return NULL;
2839
2840  found:
2841   if (! CHECK_FLT_STAGES (flt))
2842     return NULL;
2843   if (font && flt->need_config && mflt_font_id)
2844     flt = configure_flt (flt, font, mflt_font_id (font));
2845   return flt;
2846 }
2847
2848 /*=*/
2849 /***en
2850     @brief Return the name of an FLT.
2851
2852     The mflt_name () function returns the name of $FLT.  */
2853
2854 /***ja
2855     @brief FLT ¤Î̾Á°¤òÊÖ¤¹.
2856
2857     ´Ø¿ô mflt_name () ¤Ï $FLT ¤Î̾Á°¤òÊÖ¤¹¡£  */
2858
2859 const char *
2860 mflt_name (MFLT *flt)
2861 {
2862   return MSYMBOL_NAME (flt->name);
2863 }
2864
2865 /*=*/
2866 /***en
2867     @brief Return a coverage of a FLT.
2868
2869     The mflt_coverage () function returns a char-table that contains
2870     nonzero values for characters supported by $FLT.  */
2871
2872 /***ja
2873     @brief FLT ¤ÎÈϰϤòÊÖ¤¹.
2874
2875     ´Ø¿ô mflt_coverage () ¤Ï¡¢$FLT ¤¬¥µ¥Ý¡¼¥È¤¹¤ëʸ»ú¤ËÂФ·¤Æ
2876     0 ¤Ç¤Ê¤¤Ãͤò´Þ¤àʸ»ú¥Æ¡¼¥Ö¥ë¤òÊÖ¤¹¡£  */
2877
2878 MCharTable *
2879 mflt_coverage (MFLT *flt)
2880 {
2881   return flt->coverage->table;
2882 }
2883
2884 /*=*/
2885 /***en
2886     @brief Layout characters with an FLT.
2887
2888     The mflt_run () function layouts characters in $GSTRING between
2889     $FROM (inclusive) and $TO (exclusive) with $FONT.  If $FLT is
2890     nonzero, it is used for all the charaters.  Otherwise, appropriate
2891     FLTs are automatically chosen.
2892
2893     @retval >=0
2894     The operation was successful.  The value is the index to the
2895     glyph, which was previously indexed by $TO, in $GSTRING->glyphs.
2896
2897     @retval -2
2898     $GSTRING->glyphs is too short to store the result.  The caller can
2899     call this fucntion again with a longer $GSTRING->glyphs.
2900
2901     @retval -1
2902     Some other error occurred.  */
2903
2904 /***ja
2905     @brief FLT ¤ò»È¤Ã¤Æʸ»ú¤ò¥ì¥¤¥¢¥¦¥È¤¹¤ë.
2906
2907     ´Ø¿ô mflt_run () ¤Ï¡¢$GSTRING Ãæ¤Î $FROM ¤«¤é $TO Ä¾Á°¤Þ¤Ç¤Îʸ»ú¤ò
2908     $FONT ¤òÍѤ¤¤Æ¥ì¥¤¥¢¥¦¥È¤¹¤ë¡£¤â¤· $FLT
2909     ¤¬¥¼¥í¤Ç¤Ê¤±¤ì¤Ð¡¢¤½¤ÎÃͤò¤¹¤Ù¤Æ¤Îʸ»ú¤ËÂФ·¤ÆÍѤ¤¤ë¡£
2910     ¤½¤¦¤Ç¤Ê¤±¤ì¤ÐŬÀڤʠFLT ¤ò¼«Æ°Åª¤ËÁªÂò¤¹¤ë¡£
2911
2912     @retval >=0
2913     ¼Â¹ÔÀ®¸ù¤ò¼¨¤¹¡£ÊÖ¤µ¤ì¤ëÃͤϡ¢$GSTRING->glyphs Ãæ¤Ç°ÊÁ° $TO
2914     ¤Ë¤è¤Ã¤Æ¼¨¤µ¤ì¤Æ¤¤¤¿¥°¥ê¥Õ¤Ø¤Î¥¤¥ó¥Ç¥¯¥¹¤Ç¤¢¤ë¡£
2915
2916     @retval -2
2917     ·ë²Ì¤ò³ÊǼ¤¹¤ë¤Ë¤Ï $GSTRING->glyphs ¤¬Ã»¤¹¤®¤ë¤³¤È¤ò¼¨¤¹¡£
2918     ¸Æ¤Ó½Ð¤·Â¦¤Ï¡¢¤è¤êŤ¤ $GSTRING->glyphs
2919     ¤òÍѤ¤¤ÆºÆÅÙ¤³¤Î´Ø¿ô¤ò¸Æ¤Ö¤³¤È¤¬¤Ç¤­¤ë¡£
2920
2921     @retval -1
2922     ¤½¤Î¾¤Î¥¨¥é¡¼¤¬µ¯¤­¤¿¤³¤È¤ò¼¨¤¹¡£  */
2923
2924 int
2925 mflt_run (MFLTGlyphString *gstring, int from, int to,
2926           MFLTFont *font, MFLT *flt)
2927 {
2928   FontLayoutContext ctx;
2929   int match_indices[NMATCH];
2930   MFLTGlyph *g;
2931   MFLTGlyphString out;
2932   int auto_flt = ! flt;
2933   int c, i, j, k;
2934   int this_from, this_to;
2935   MSymbol font_id = mflt_font_id ? mflt_font_id (font) : Mnil;
2936
2937   out = *gstring;
2938   out.glyphs = NULL;
2939   /* This is usually sufficient, but if not, we retry with the larger
2940      values at most 3 times.  This value is also used for the
2941      allocating size of ctx.encoded.  */
2942   out.allocated = (to - from) * 4;
2943
2944   for (i = from; i < to; i++)
2945     {
2946       g = GREF (gstring, i);
2947       if (! g->encoded)
2948         {
2949           c = g->c;
2950           memset (g, 0, sizeof (MFLTGlyph));
2951           g->code = g->c = c;
2952         }
2953       g->from = g->to = i;
2954     }
2955
2956   for (this_from = from; this_from < to;)
2957     {
2958       if (! auto_flt)
2959         {
2960           for (this_to = this_from; this_to < to; this_to++)
2961             if (mchartable_lookup (flt->coverage->table,
2962                                    GREF (gstring, this_to)->c))
2963               break;
2964         }
2965       else
2966         {
2967           if (! flt_list && list_flt () < 0)
2968             {
2969               font->get_glyph_id (font, gstring, this_from, to);
2970               font->get_metrics (font, gstring, this_from, to);
2971               this_from = to;
2972               break;
2973             }
2974           for (this_to = this_from; this_to < to; this_to++)
2975             {
2976               c = GREF (gstring, this_to)->c;
2977               if (c >= flt_min_coverage && c <= flt_max_coverage)
2978                 break;
2979             }
2980           for (; this_to < to; this_to++)
2981             {
2982               c = GREF (gstring, this_to)->c;
2983               if (font->internal
2984                   && mchartable_lookup (((MFLT *) font->internal)->coverage->table, c))
2985                 {
2986                   flt = font->internal;
2987                   break;
2988                 }
2989               flt = mflt_find (c, font);
2990               if (flt)
2991                 {
2992                   if (CHECK_FLT_STAGES (flt))
2993                     {
2994                       font->internal = flt;
2995                       break;
2996                     }
2997                 }
2998             }
2999         }
3000
3001       if (this_from < this_to)
3002         {
3003           font->get_glyph_id (font, gstring, this_from, this_to);
3004           font->get_metrics (font, gstring, this_from, this_to);
3005           this_from = this_to;
3006         }
3007       if (this_to == to)
3008         break;
3009
3010       MDEBUG_PRINT1 (" [FLT] (%s", MSYMBOL_NAME (flt->name));
3011
3012       if (flt->need_config && font_id != Mnil)
3013         flt = configure_flt (flt, font, font_id);
3014
3015       for (; this_to < to; this_to++)
3016         {
3017           char enc;
3018           g = GREF (gstring, this_to);
3019           enc = (int) mchartable_lookup (flt->coverage->table, g->c);
3020           if (! enc)
3021             break;
3022           SET_CATEGORY_CODE (g, enc);
3023         }
3024
3025       if (MDEBUG_FLAG ())
3026         {
3027           if (font->family)
3028             MDEBUG_PRINT1 (" (%s)", MSYMBOL_NAME (font->family));
3029           MDEBUG_PRINT ("\n [FLT]   (SOURCE");
3030           for (i = this_from, j = 0; i < this_to; i++, j++)
3031             {
3032               if (j > 0 && j % 8 == 0)
3033                 MDEBUG_PRINT ("\n [FLT]          ");
3034               MDEBUG_PRINT1 (" %04X", GREF (gstring, i)->c);
3035             }
3036           MDEBUG_PRINT (")");
3037         }
3038
3039       for (i = 0; i < 3; i++)
3040         {
3041           /* Setup CTX.  */
3042           memset (&ctx, 0, sizeof ctx);
3043           ctx.match_indices = match_indices;
3044           ctx.font = font;
3045           ctx.cluster_begin_idx = -1;
3046           ctx.in = gstring;
3047           ctx.out = &out;
3048           j = run_stages (gstring, this_from, this_to, flt, &ctx);
3049           if (j != -2)
3050             break;
3051           out.allocated *= 2;
3052         }
3053
3054       if (j < 0)
3055         return j;
3056
3057       to += j - this_to;
3058       this_to = j;
3059
3060       if (MDEBUG_FLAG ())
3061         {
3062           MDEBUG_PRINT ("\n [FLT]   (RESULT");
3063           if (MDEBUG_FLAG () > 1)
3064             {
3065               int idx = -1;
3066               for (i = 0; this_from < this_to; i++, this_from++)
3067                 {
3068                   g = GREF (gstring, this_from);
3069                   if (g->from != idx)
3070                     {
3071                       if (i > 0)
3072                         MDEBUG_PRINT2 ("\n [FLT]           %02d-%02d",
3073                                        g->from, g->to);
3074                       else
3075                         MDEBUG_PRINT2 (" %02d-%02d", g->from, g->to);
3076                       idx = g->from;
3077                     }
3078                   MDEBUG_PRINT4 (" (%04X %d %d %d)",
3079                                  g->code, g->xadv, g->xoff, g->yoff);
3080                 }
3081             }
3082           else
3083             for (; this_from < this_to; this_from++)
3084               MDEBUG_PRINT1 (" %04X", GREF (gstring, this_from)->code);
3085           MDEBUG_PRINT ("))\n");
3086         }
3087       this_from = this_to;
3088     }
3089
3090   if (gstring->r2l)
3091     {
3092       int len = to - from;
3093
3094       GINIT (&out, len);
3095       memcpy (((char *) out.glyphs),
3096               ((char *) gstring->glyphs) + gstring->glyph_size * from,
3097               gstring->glyph_size * len);
3098       for (i = from, j = to; i < to;)
3099         {
3100           for (k = i + 1, j--; k < to && GREF (&out, k)->xadv == 0;
3101                k++, j--);
3102           GCPY (&out, i, (k - i), gstring, j);
3103           i = k;
3104         }
3105     }
3106
3107   return to;
3108 }
3109
3110 int mflt_enable_new_feature;
3111
3112 int (*mflt_iterate_otf_feature) (struct _MFLTFont *font,
3113                                  MFLTOtfSpec *spec,
3114                                  int from, int to,
3115                                  unsigned char *table);
3116
3117 MSymbol (*mflt_font_id) (struct _MFLTFont *font);
3118
3119 int (*mflt_try_otf) (struct _MFLTFont *font, MFLTOtfSpec *spec,
3120                      MFLTGlyphString *gstring, int from, int to);
3121
3122 \f
3123 /* for debugging... */
3124
3125 static void
3126 dump_flt_cmd (FontLayoutStage *stage, int id, int indent)
3127 {
3128   char *prefix = (char *) alloca (indent + 1);
3129
3130   memset (prefix, 32, indent);
3131   prefix[indent] = 0;
3132
3133   if (id >= 0)
3134     fprintf (mdebug__output, "0x%02X", id);
3135   else if (id <= CMD_ID_OFFSET_INDEX)
3136     {
3137       int idx = CMD_ID_TO_INDEX (id);
3138       FontLayoutCmd *cmd = stage->cmds + idx;
3139
3140       if (cmd->type == FontLayoutCmdTypeRule)
3141         {
3142           FontLayoutCmdRule *rule = &cmd->body.rule;
3143           int i;
3144
3145           fprintf (mdebug__output, "(rule ");
3146           if (rule->src_type == SRC_REGEX)
3147             fprintf (mdebug__output, "\"%s\"", rule->src.re.pattern);
3148           else if (rule->src_type == SRC_INDEX)
3149             fprintf (mdebug__output, "%d", rule->src.match_idx);
3150           else if (rule->src_type == SRC_SEQ)
3151             fprintf (mdebug__output, "(seq)");
3152           else if (rule->src_type == SRC_RANGE)
3153             fprintf (mdebug__output, "(range)");
3154           else
3155             fprintf (mdebug__output, "(invalid src)");
3156
3157           for (i = 0; i < rule->n_cmds; i++)
3158             {
3159               fprintf (mdebug__output, "\n%s  ", prefix);
3160               dump_flt_cmd (stage, rule->cmd_ids[i], indent + 2);
3161             }
3162           fprintf (mdebug__output, ")");
3163         }
3164       else if (cmd->type == FontLayoutCmdTypeCond)
3165         {
3166           FontLayoutCmdCond *cond = &cmd->body.cond;
3167           int i;
3168
3169           fprintf (mdebug__output, "(cond");
3170           for (i = 0; i < cond->n_cmds; i++)
3171             {
3172               fprintf (mdebug__output, "\n%s  ", prefix);
3173               dump_flt_cmd (stage, cond->cmd_ids[i], indent + 2);
3174             }
3175           fprintf (mdebug__output, ")");
3176         }
3177       else if (cmd->type == FontLayoutCmdTypeOTF)
3178         {
3179           fprintf (mdebug__output, "(otf)");
3180         }
3181       else
3182         fprintf (mdebug__output, "(error-command)");
3183     }
3184   else if (id <= CMD_ID_OFFSET_COMBINING)
3185     fprintf (mdebug__output, "cominging-code");
3186   else
3187     fprintf (mdebug__output, "(predefiend %d)", id);
3188 }
3189
3190 /***en
3191     @brief Dump a Font Layout Table.
3192
3193     The mdebug_dump_flt () function prints the Font Layout Table $FLT
3194     in a human readable way to the stderr or to what specified by the
3195     environment variable MDEBUG_OUTPUT_FILE.  $INDENT specifies how
3196     many columns to indent the lines but the first one.
3197
3198     @return
3199     This function returns $FLT.  */
3200
3201 MFLT *
3202 mdebug_dump_flt (MFLT *flt, int indent)
3203 {
3204   char *prefix = (char *) alloca (indent + 1);
3205   MPlist *plist;
3206   int stage_idx = 0;
3207
3208   memset (prefix, 32, indent);
3209   prefix[indent] = 0;
3210   fprintf (mdebug__output, "(flt");
3211   MPLIST_DO (plist, flt->stages)
3212     {
3213       FontLayoutStage *stage = (FontLayoutStage *) MPLIST_VAL (plist);
3214       int i;
3215
3216       fprintf (mdebug__output, "\n%s  (stage %d", prefix, stage_idx);
3217       for (i = 0; i < stage->used; i++)
3218         {
3219           fprintf (mdebug__output, "\n%s    ", prefix);
3220           dump_flt_cmd (stage, INDEX_TO_CMD_ID (i), indent + 4);
3221         }
3222       fprintf (mdebug__output, ")");
3223       stage_idx++;
3224     }
3225   fprintf (mdebug__output, ")");
3226   return flt;
3227 }
3228
3229 void
3230 mflt_dump_gstring (MFLTGlyphString *gstring)
3231 {
3232   int i;
3233
3234   fprintf (mdebug__output, "(flt-gstring");
3235   for (i = 0; i < gstring->used; i++)
3236     {
3237       MFLTGlyph *g = GREF (gstring, i);
3238       fprintf (mdebug__output, "\n  (%02d pos:%d-%d c:%04X code:%04X cat:%c)",
3239                i, g->from, g->to, g->c, g->code, GET_CATEGORY_CODE (g));
3240     }
3241   fprintf (mdebug__output, ")\n");
3242 }
3243
3244 /*** @} */
3245
3246 /*
3247  Local Variables:
3248  coding: euc-japan
3249  End:
3250 */