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