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