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