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