1 /* m17n-flt.c -- Font Layout Table sub-module.
2 Copyright (C) 2003, 2004, 2007, 2008, 2009
3 National Institute of Advanced Industrial Science and Technology (AIST)
4 Registration Number H15PRO112
6 This file is part of the m17n library.
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.
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.
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,
25 @brief FLT support for a window system.
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. */
33 @brief ¥¦¥£¥ó¥É¥¦¥·¥¹¥Æ¥à¤Î¤¿¤á¤Î FLT ¥µ¥Ý¡¼¥È.
35 ¤³¤Î¥»¥¯¥·¥ç¥ó¤Ç¤Ï¡¢FLT (Font Layout Table)
36 ¤òÍѤ¤¤¿Ê¸»ú¥ì¥¤¥¢¥¦¥Èµ¡Ç½¤Ë´Ø¤¹¤ë m17n FLT API ¤òÄêµÁ¤¹¤ë¡£
37 FLT ¤Î·Á¼°¤Ï @ref mdbFLT ¤Ëµ½Ò¤µ¤ì¤Æ¤¤¤ë¡£ */
41 #if !defined (FOR_DOXYGEN) || defined (DOXYGEN_INTERNAL_MODULE)
42 /*** @addtogroup m17nInternal
51 #include <sys/types.h>
54 #include "m17n-core.h"
56 #include "m17n-misc.h"
62 #include "internal-flt.h"
66 /* Font Layout Table (FLT)
68 Predefined terms: SYMBOL, INTEGER, STRING
70 FLT ::= '(' STAGE + ')'
72 STAGE ::= CATEGORY-TABLE ? FONT-LAYOUT-RULE
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.
81 '(' 'category' CATEGORY-SPEC + ')'
83 '(' CODE [ CODE ] CATEGORY ')'
86 ;; ASCII character codes of alphabet ('A' .. 'Z' 'a' .. 'z').
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.
95 '(' 'generator' RULE MACRO-DEF * ')'
97 RULE ::= COMMAND | REGEXP-RULE | MATCH-RULE | MAP-RULE
98 | COND-STRUCT | MACRO-NAME
101 DIRECT-CODE | COMBINING | PREDEFIND-COMMAND | OTF-COMMAND
103 DIRECT-CODE ::= INTEGER
104 ;; Always succeed. Produce the code. Consume no source.
106 PREDEFIND-COMMAND ::=
107 '=' | '*' | '<' | '>' | '|'
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.
112 ;; '*': If the the previous command succeeded, repeat it until it
115 ;; '<': Produce a special code that indicates the start of grapheme
116 ;; cluster. Succeed always, consume nothing.
118 ;; '>': Produce a special code that indicates the end of grapheme
119 ;; cluster. Succeed always, consume nothing.
121 ;; '|': Produce a special code whose category is ' '. Succeed always,
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.
130 ;; OTF's ScriptTag name (four letters) listed at:
131 ;; <http://www.microsoft.om/typograph/otspec/scripttags.htm>
133 ;; OTF's Language System name (four letters) listed at:
134 ;; <http://www.microsoft.om/typograph/otspec/languagetags.htm>
136 GSUB-FEATURES ::= [FEATURE[,FEATURE]*] | ' '
137 GPOS-FEATURES ::= [FEATURE[,FEATURE]*] | ' '
139 ;; OTF's Feature name (four letters) listed at:
140 ;; <http://www.microsoft.om/typograph/otspec/???.htm>
142 OTF-TAG ::= PRINTABLE-CHAR PRINTABLE-CHAR PRINTABLE-CHAR PRINTABLE-CHAR
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.
150 ;; Run all GSUB features, run no GPOS features.
153 '(' REGEXP RULE * ')'
155 ;; Succeed if REGXP matches the head of source. Run RULEs while
156 ;; limiting the source to the matching part. Consume that part.
159 ;; Must be composed only from ASCII characters. 'A' - 'Z', 'a' - 'z'
160 ;; correspond to CATEGORY.
167 '(' MATCH-IDX RULE * ')'
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
174 MATCH-IDX ::= INTEGER
181 '(' ( SOURCE-SEQ | SOURCE-RANGE ) RULE * ')'
183 ;; Succeed if the source matches SOURCE-SEQ or SOURCE-RANGE. Run
184 ;; RULEs while limiting the source to the matching part. Consume that
190 '(' 'range' CODE CODE ')'
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)).
199 '(' 'cond' RULE + ')'
201 ;; Try each rule in sequence until one succeeds. Succeed if one
202 ;; succeeds. Consume nothing.
206 ;; ((0x0915 0x094D) 0x43)
207 ;; ((range 0x0F40 0x0F6A) 0x2221)
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
218 ;; VH pair indicates 12 reference points of a glyph as below:
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)
235 ;; Align top-left point of the previous glyph and bottom-center
236 ;; point of the current glyph.
238 ;; Align 20% left and 10% below of base-left point of the previous
239 ;; glyph and base-right point of the current glyph.
242 '(' MACRO-NAME RULE + ')'
243 MACRO-NAME ::= SYMBOL
247 static int mdebug_flag = MDEBUG_FLT;
249 MSymbol Mfont, Mlayouter, Mcombining;
251 static MSymbol Mgenerator, Mend;
253 static MPlist *flt_list;
254 static int flt_min_coverage, flt_max_coverage;
258 CategoryCodeMask = 0x7F,
259 CombiningCodeMask = 0xFFFFFF,
260 CombinedMask = 1 << 27,
261 LeftPaddingMask = 1 << 28,
262 RightPaddingMask = 1 << 29
265 #define SET_GLYPH_INFO(g, mask, ctx, info) \
266 ((g)->internal = (((g)->internal & ~(mask)) | (info)), \
267 (ctx)->check_mask |= (mask))
269 #define GET_CATEGORY_CODE(g) ((g)->internal & CategoryCodeMask)
270 #define SET_CATEGORY_CODE(g, code) \
271 ((g)->internal = (((g)->internal & ~(CombiningCodeMask | CombinedMask)) \
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))
289 #define GINIT(gstring, n) \
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; \
298 #define GALLOCA (gstring) \
299 ((MFLTGlyph *) alloca ((gstring)->glyph_size))
301 #define GREF(gstring, idx) \
302 ((MFLTGlyph *) ((char *) ((gstring)->glyphs) + (gstring)->glyph_size * (idx)))
304 #define PREV(gstring, g) \
305 ((MFLTGlyph *) ((char *) (g) - (gstring)->glyph_size))
307 #define NEXT(gstring, g) \
308 ((MFLTGlyph *) ((char *) (g) + (gstring)->glyph_size))
310 #define GCPY(src, src_idx, n, tgt, tgt_idx) \
312 memcpy ((char *) ((tgt)->glyphs) + (tgt)->glyph_size * (tgt_idx), \
313 (char *) ((src)->glyphs) + (src)->glyph_size * (src_idx), \
314 (src)->glyph_size * (n)); \
317 #define GDUP(ctx, idx) \
319 MFLTGlyphString *src = (ctx)->in; \
320 MFLTGlyphString *tgt = (ctx)->out; \
321 if (tgt->allocated <= tgt->used) \
323 GCPY (src, (idx), 1, tgt, tgt->used); \
328 GREPLACE (MFLTGlyphString *src, int src_from, int src_to,
329 MFLTGlyphString *tgt, int tgt_from, int tgt_to)
331 int src_len = src_to - src_from;
332 int tgt_len = tgt_to - tgt_from;
333 int inc = src_len - tgt_len;
335 if (tgt->allocated < tgt->used + inc)
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));
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);
353 -0x0F .. -2 : builtin commands
354 -0x100000F .. -0x10 : combining code
355 ... -0x1000010: index to FontLayoutStage->cmds
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
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 /* ']' */
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))
375 #define CMD_ID_TO_INDEX(id) (CMD_ID_OFFSET_INDEX - (id))
376 #define INDEX_TO_CMD_ID(idx) (CMD_ID_OFFSET_INDEX - (idx))
378 static MSymbol Mcond, Mrange, Mfont_facility, Mequal;
380 #define GLYPH_CODE_P(code) \
381 ((code) >= GLYPH_CODE_MIN && (code) <= GLYPH_CODE_MAX)
383 #define GLYPH_CODE_INDEX(code) ((code) - GLYPH_CODE_MIN)
385 #define UPDATE_CLUSTER_RANGE(ctx, g) \
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; \
393 enum FontLayoutCmdRuleSrcType
405 enum FontLayoutCmdRuleSrcType src_type;
422 MFLTOtfSpec otf_spec;
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;
441 enum FontLayoutCmdType
443 FontLayoutCmdTypeRule,
444 FontLayoutCmdTypeCond,
445 FontLayoutCmdTypeOTF,
446 FontLayoutCmdTypeOTFCategory,
452 enum FontLayoutCmdType type;
454 FontLayoutCmdRule rule;
455 FontLayoutCmdCond cond;
470 FeatureCodeTable feature_table;
471 /* Non-null if the table must be re-configured by OTF specs included
472 in the definition. */
474 } FontLayoutCategory;
478 FontLayoutCategory *category;
490 FontLayoutCategory *coverage;
493 /* Font for which coverage or some of categories are configured. */
497 /* Font layout table loader */
499 static int parse_otf_command (MSymbol symbol, MFLTOtfSpec *spec);
502 apply_otf_feature (MFLTFont *font, MFLTOtfSpec *spec,
503 int from, int to, MCharTable *table, int category)
508 if (! mflt_iterate_otf_feature)
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)
514 for (i = to - from; i >= 0; i--)
516 mchartable_set (table, from + i, (void *) category);
519 static unsigned int gen_otf_tag (char *p, int shift);
521 /* Load a category table from PLIST. PLIST has this form:
522 PLIST ::= ( FROM-CODE TO-CODE ? CATEGORY-CHAR ) *
525 static FontLayoutCategory *
526 load_category_table (MPlist *plist, MFLTFont *font)
528 FontLayoutCategory *category;
530 MPlist *feature_table_head = NULL;
531 int feature_table_size = 0;
535 table = mchartable (Minteger, (void *) 0);
539 int from, to, category_code;
541 if (! MPLIST_PLIST_P (p))
542 MERROR_GOTO (MERROR_FLT, end);
543 elt = MPLIST_PLIST (p);
544 if (MPLIST_SYMBOL_P (elt))
546 MPlist *next = MPLIST_NEXT (elt);
547 if (! MPLIST_INTEGER_P (next))
548 MERROR_GOTO (MERROR_FLT, end);
549 if (! feature_table_head)
550 feature_table_head = p;
551 feature_table_size++;
554 if (! MPLIST_INTEGER_P (elt))
555 MERROR_GOTO (MERROR_FLT, end);
556 from = MPLIST_INTEGER (elt);
557 elt = MPLIST_NEXT (elt);
558 if (! MPLIST_INTEGER_P (elt))
559 MERROR_GOTO (MERROR_FLT, end);
560 to = MPLIST_INTEGER (elt);
561 elt = MPLIST_NEXT (elt);
562 if (MPLIST_TAIL_P (elt))
567 else if (MPLIST_SYMBOL_P (elt))
572 if (parse_otf_command (MPLIST_SYMBOL (elt), &spec) < 0)
573 MERROR_GOTO (MERROR_FLT, end);
574 elt = MPLIST_NEXT (elt);
575 if (! MPLIST_INTEGER_P (elt))
576 MERROR_GOTO (MERROR_FLT, end);
577 category_code = MPLIST_INTEGER (elt);
578 if (! isalnum (category_code))
579 MERROR_GOTO (MERROR_FLT, end);
580 apply_otf_feature (font, &spec, from, to, table, category_code);
588 if (! MPLIST_INTEGER_P (elt))
589 MERROR_GOTO (MERROR_FLT, end);
590 category_code = MPLIST_INTEGER (elt);
592 if (! isalnum (category_code))
593 MERROR_GOTO (MERROR_FLT, end);
596 mchartable_set (table, from, (void *) category_code);
598 mchartable_set_range (table, from, to, (void *) category_code);
602 category = calloc (1, sizeof (FontLayoutCategory));
603 category->table = table;
606 category->definition = plist;
607 M17N_OBJECT_REF (plist);
610 category->definition = NULL;
611 if (feature_table_head)
614 category->feature_table.size = feature_table_size;
615 category->feature_table.tag = malloc (sizeof (unsigned int)
616 * feature_table_size);
617 category->feature_table.code = malloc (feature_table_size);
619 MPLIST_DO (p, feature_table_head)
623 if (! MPLIST_PLIST_P (p))
625 elt = MPLIST_PLIST (p);
626 if (! MPLIST_SYMBOL_P (elt))
628 feature = MPLIST_SYMBOL (elt);
629 elt = MPLIST_NEXT (elt);
630 if (! MPLIST_INTEGER_P (elt))
632 category->feature_table.tag[i]
633 = gen_otf_tag (MSYMBOL_NAME (feature), 7);
634 category->feature_table.code[i] = MPLIST_INTEGER (elt);
641 #define ref_category_table(CATEGORY) M17N_OBJECT_REF ((CATEGORY)->table)
644 unref_category_table (FontLayoutCategory *category)
646 M17N_OBJECT_UNREF (category->table);
647 if (! category->table)
649 if (category->definition)
650 M17N_OBJECT_UNREF (category->definition);
651 if (category->feature_table.size > 0)
653 free (category->feature_table.tag);
654 free (category->feature_table.code);
661 gen_otf_tag (char *p, int shift)
663 unsigned int tag = 0;
666 for (i = 0; i < 4 && *p; i++, p++)
667 tag = (tag << shift) | *p;
669 tag = (tag << shift) | 0x20;
674 otf_count_features (char *p, char *end, char stopper, int *count)
679 if (*p != stopper && *p != '\0')
686 if (*p == stopper || *p == '\0')
700 if (*p == stopper || *p == '\0')
712 otf_store_features (char *p, char *end, unsigned *buf)
717 for (i = 0; p < end;)
720 buf[i++] = 0xFFFFFFFF, p += 2, negative = 1;
724 buf[i++] = 0xFFFFFFFF;
725 buf[i++] = gen_otf_tag (p + 1, 8), p += 6;
728 buf[i++] = gen_otf_tag (p, 8), p += 5;
734 parse_otf_command (MSymbol symbol, MFLTOtfSpec *spec)
736 char *str = MSYMBOL_NAME (symbol);
737 char *end = str + MSYMBOL_NAMELEN (symbol);
738 unsigned int script, langsys;
740 int gsub_count = 0, gpos_count = 0;
743 memset (spec, 0, sizeof (MFLTOtfSpec));
746 str += 5; /* skip the heading ":otf=" */
747 script = gen_otf_tag (str, 8);
751 langsys = gen_otf_tag (str, 8);
758 /* Apply all GSUB features. */
763 str = otf_count_features (p, end, '+', &gsub_count);
765 MERROR (MERROR_FLT, -1);
769 /* Apply all GPOS features. */
774 str = otf_count_features (p, end, '\0', &gpos_count);
776 MERROR (MERROR_FLT, -1);
779 spec->script = script;
780 spec->langsys = langsys;
783 spec->features[0] = malloc (sizeof (int) * (gsub_count + 1));
784 if (! spec->features[0])
787 otf_store_features (gsub + 1, gpos, spec->features[0]);
789 spec->features[0][0] = 0xFFFFFFFF, spec->features[0][1] = 0;
793 spec->features[1] = malloc (sizeof (int) * (gpos_count + 1));
794 if (! spec->features[1])
796 if (spec->features[0])
797 free (spec->features[0]);
801 otf_store_features (gpos + 1, str, spec->features[1]);
803 spec->features[1][0] = 0xFFFFFFFF, spec->features[1][1] = 0;
809 /* Parse OTF command name NAME and store the result in CMD.
811 :SCRIPT[/[LANGSYS][=[GSUB-FEATURES][+GPOS-FEATURES]]]
812 where GSUB-FEATURES and GPOS-FEATURES have this form:
813 [FEATURE[,FEATURE]*] | ' ' */
816 load_otf_command (FontLayoutCmd *cmd, MSymbol sym)
818 char *name = MSYMBOL_NAME (sym);
821 if (name[0] != ':' && name[0] != '?')
823 /* This is old format of "otf:...". Change it to ":otf=...". */
824 char *str = alloca (MSYMBOL_NAMELEN (sym) + 2);
826 sprintf (str, ":otf=");
827 strcat (str, name + 4);
831 result = parse_otf_command (sym, &cmd->body.otf);
834 cmd->type = (name[0] == '?' ? FontLayoutCmdTypeOTFCategory
835 : FontLayoutCmdTypeOTF);
840 /* Read a decimal number from STR preceded by one of "+-><". '+' and
841 '>' means a plus sign, '-' and '<' means a minus sign. If the
842 number is greater than 127, limit it to 127. */
845 read_decimal_number (char **str)
848 int sign = (*p == '-' || *p == '<') ? -1 : 1;
852 while (*p >= '0' && *p <= '9')
853 n = n * 10 + *p++ - '0';
857 return (n < 127 ? n * sign : 127 * sign);
861 /* Read a horizontal and vertical combining positions from STR, and
862 store them in the place pointed by X and Y. The horizontal
863 position left, center, and right are represented by 0, 1, and 2
864 respectively. The vertical position top, center, bottom, and base
865 are represented by 0, 1, 2, and 3 respectively. If successfully
866 read, return 0, else return -1. */
869 read_combining_position (char *str, int *x, int *y)
874 /* Vertical position comes first. */
875 for (i = 0; i < 4; i++)
884 /* Then comse horizontal position. */
885 for (i = 0; i < 3; i++)
895 /* Return a combining code corresponding to SYM. */
898 get_combining_command (MSymbol sym)
900 char *str = msymbol_name (sym);
901 int base_x, base_y, add_x, add_y, off_x, off_y;
904 if (read_combining_position (str, &base_x, &base_y) < 0)
915 if (c == '+' || c == '-')
917 off_y = read_decimal_number (&str) + 128;
922 if (c == '<' || c == '>')
923 off_x = read_decimal_number (&str) + 128;
927 if (read_combining_position (str, &add_x, &add_y) < 0)
930 c = MAKE_COMBINING_CODE (base_y, base_x, add_y, add_x, off_y, off_x);
931 return (COMBINING_CODE_TO_CMD_ID (c));
935 /* Load a command from PLIST into STAGE, and return that
936 identification number. If ID is not INVALID_CMD_ID, that means we
937 are loading a top level command or a macro. In that case, use ID
938 as the identification number of the command. Otherwise, generate a
939 new id number for the command. MACROS is a list of raw macros. */
942 load_command (FontLayoutStage *stage, MPlist *plist,
943 MPlist *macros, int id)
948 if (MPLIST_INTEGER_P (plist))
950 int code = MPLIST_INTEGER (plist);
953 MERROR (MERROR_DRAW, INVALID_CMD_ID);
956 else if (MPLIST_PLIST_P (plist))
958 /* PLIST ::= ( cond ... ) | ( STRING ... ) | ( INTEGER ... )
959 | ( ( INTEGER INTEGER ) ... )
960 | ( ( range INTEGER INTEGER ) ... )
961 | ( ( SYMBOL STRING ) ... )
962 | ( ( font-facilty [ INTEGER ] ) ... )
963 | ( ( font-facilty OTF-SPEC ) ... ) */
964 MPlist *elt = MPLIST_PLIST (plist);
965 int len = MPLIST_LENGTH (elt) - 1;
968 if (id == INVALID_CMD_ID)
971 id = INDEX_TO_CMD_ID (stage->used);
972 MLIST_APPEND1 (stage, cmds, dummy, MERROR_DRAW);
974 cmd = stage->cmds + CMD_ID_TO_INDEX (id);
976 if (MPLIST_SYMBOL_P (elt))
978 FontLayoutCmdCond *cond;
980 if (MPLIST_SYMBOL (elt) != Mcond)
981 MERROR (MERROR_DRAW, INVALID_CMD_ID);
982 elt = MPLIST_NEXT (elt);
983 cmd->type = FontLayoutCmdTypeCond;
984 cond = &cmd->body.cond;
985 cond->seq_beg = cond->seq_end = -1;
986 cond->seq_from = cond->seq_to = 0;
988 MTABLE_CALLOC (cond->cmd_ids, len, MERROR_DRAW);
989 for (i = 0; i < len; i++, elt = MPLIST_NEXT (elt))
991 int this_id = load_command (stage, elt, macros, INVALID_CMD_ID);
993 if (this_id == INVALID_CMD_ID || this_id == -2)
994 MERROR (MERROR_DRAW, this_id);
995 /* The above load_command may relocate stage->cmds. */
996 cmd = stage->cmds + CMD_ID_TO_INDEX (id);
997 cond = &cmd->body.cond;
998 cond->cmd_ids[i] = this_id;
999 if (this_id <= CMD_ID_OFFSET_INDEX)
1001 FontLayoutCmd *this_cmd
1002 = stage->cmds + CMD_ID_TO_INDEX (this_id);
1004 if (this_cmd->type == FontLayoutCmdTypeRule
1005 && this_cmd->body.rule.src_type == SRC_SEQ)
1007 int first_char = this_cmd->body.rule.src.seq.codes[0];
1009 if (cond->seq_beg < 0)
1011 /* The first SEQ command. */
1013 cond->seq_from = cond->seq_to = first_char;
1015 else if (cond->seq_end < 0)
1017 /* The following SEQ command. */
1018 if (cond->seq_from > first_char)
1019 cond->seq_from = first_char;
1020 else if (cond->seq_to < first_char)
1021 cond->seq_to = first_char;
1026 if (cond->seq_beg >= 0 && cond->seq_end < 0)
1027 /* The previous one is the last SEQ command. */
1033 if (cond->seq_beg >= 0 && cond->seq_end < 0)
1034 /* The previous one is the last SEQ command. */
1038 if (cond->seq_beg >= 0 && cond->seq_end < 0)
1039 /* The previous one is the last SEQ command. */
1044 cmd->type = FontLayoutCmdTypeRule;
1045 if (MPLIST_MTEXT_P (elt))
1047 MText *mt = MPLIST_MTEXT (elt);
1048 char *str = (char *) MTEXT_DATA (mt);
1052 mtext_ins_char (mt, 0, '^', 1);
1053 str = (char *) MTEXT_DATA (mt);
1055 if (regcomp (&cmd->body.rule.src.re.preg, str, REG_EXTENDED))
1056 MERROR (MERROR_FONT, INVALID_CMD_ID);
1057 cmd->body.rule.src_type = SRC_REGEX;
1058 cmd->body.rule.src.re.pattern = strdup (str);
1060 else if (MPLIST_INTEGER_P (elt))
1062 cmd->body.rule.src_type = SRC_INDEX;
1063 cmd->body.rule.src.match_idx = MPLIST_INTEGER (elt);
1065 else if (MPLIST_PLIST_P (elt))
1067 MPlist *pl = MPLIST_PLIST (elt), *p;
1068 int size = MPLIST_LENGTH (pl);
1070 if (MPLIST_INTEGER_P (pl))
1074 cmd->body.rule.src_type = SRC_SEQ;
1075 cmd->body.rule.src.seq.n_codes = size;
1076 MTABLE_CALLOC (cmd->body.rule.src.seq.codes, size,
1078 for (i = 0; i < size; i++, pl = MPLIST_NEXT (pl))
1080 if (! MPLIST_INTEGER_P (pl))
1081 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1082 cmd->body.rule.src.seq.codes[i]
1083 = (unsigned) MPLIST_INTEGER (pl);
1086 else if (MPLIST_SYMBOL_P (pl))
1088 if (MPLIST_SYMBOL (pl) == Mrange)
1091 MERROR (MERROR_FLT, INVALID_CMD_ID);
1092 cmd->body.rule.src_type = SRC_RANGE;
1093 pl = MPLIST_NEXT (pl);
1094 if (! MPLIST_INTEGER_P (pl))
1095 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1096 cmd->body.rule.src.range.from
1097 = (unsigned) MPLIST_INTEGER (pl);
1098 pl = MPLIST_NEXT (pl);
1099 if (! MPLIST_INTEGER_P (pl))
1100 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1101 cmd->body.rule.src.range.to
1102 = (unsigned) MPLIST_INTEGER (pl);
1104 else if (MPLIST_SYMBOL (pl) == Mfont_facility)
1106 FontLayoutCmdRule *rule = &cmd->body.rule;
1108 pl = MPLIST_NEXT (pl);
1109 if (MPLIST_SYMBOL_P (pl))
1111 MSymbol sym = MPLIST_SYMBOL (pl);
1112 char *otf_spec = MSYMBOL_NAME (sym);
1114 if (otf_spec[0] == ':' && otf_spec[1] == 'o'
1115 && otf_spec[2] == 't' && otf_spec[3] == 'f')
1116 parse_otf_command (sym, &rule->src.facility.otf_spec);
1118 MERROR (MERROR_FLT, INVALID_CMD_ID);
1119 rule->src_type = SRC_OTF_SPEC;
1120 pl = MPLIST_NEXT (pl);
1122 else if (MPLIST_TAIL_P (pl))
1123 MERROR (MERROR_FLT, INVALID_CMD_ID);
1125 rule->src_type = SRC_HAS_GLYPH;
1126 rule->src.facility.len = 0;
1129 if (! MPLIST_INTEGER_P (p)
1130 && (MPLIST_SYMBOL_P (p)
1131 ? MPLIST_SYMBOL (p) != Mequal
1133 MERROR (MERROR_FLT, INVALID_CMD_ID);
1134 rule->src.facility.len++;
1136 rule->src.facility.codes = pl;
1137 M17N_OBJECT_REF (pl);
1141 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1144 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1146 elt = MPLIST_NEXT (elt);
1147 cmd->body.rule.n_cmds = len;
1148 MTABLE_CALLOC (cmd->body.rule.cmd_ids, len, MERROR_DRAW);
1149 for (i = 0; i < len; i++, elt = MPLIST_NEXT (elt))
1151 int this_id = load_command (stage, elt, macros, INVALID_CMD_ID);
1153 if (this_id == INVALID_CMD_ID || this_id == -2)
1154 MERROR (MERROR_DRAW, this_id);
1155 /* The above load_command may relocate stage->cmds. */
1156 cmd = stage->cmds + CMD_ID_TO_INDEX (id);
1157 cmd->body.rule.cmd_ids[i] = this_id;
1161 else if (MPLIST_SYMBOL_P (plist))
1164 MSymbol sym = MPLIST_SYMBOL (plist);
1165 char *name = msymbol_name (sym);
1166 int len = strlen (name);
1170 && ((name[0] == 'o' && name[1] == 't'
1171 && name[2] == 'f' && name[3] == ':')
1172 || ((name[0] == ':' || name[0] == '?')
1173 && name[1] == 'o' && name[2] == 't'
1174 && name[3] == 'f' && name[4] == '=')))
1176 result = load_otf_command (&cmd, sym);
1179 if (id == INVALID_CMD_ID)
1181 id = INDEX_TO_CMD_ID (stage->used);
1182 MLIST_APPEND1 (stage, cmds, cmd, MERROR_DRAW);
1185 stage->cmds[CMD_ID_TO_INDEX (id)] = cmd;
1193 else if (*name == '*')
1194 return CMD_ID_REPEAT;
1195 else if (*name == '<')
1196 return CMD_ID_CLUSTER_BEGIN;
1197 else if (*name == '>')
1198 return CMD_ID_CLUSTER_END;
1199 else if (*name == '|')
1200 return CMD_ID_SEPARATOR;
1201 else if (*name == '[')
1202 return CMD_ID_LEFT_PADDING;
1203 else if (*name == ']')
1204 return CMD_ID_RIGHT_PADDING;
1210 id = get_combining_command (sym);
1216 MPLIST_DO (elt, macros)
1218 if (sym == MPLIST_SYMBOL (MPLIST_PLIST (elt)))
1220 id = INDEX_TO_CMD_ID (i);
1221 if (stage->cmds[i].type == FontLayoutCmdTypeMAX)
1222 id = load_command (stage, MPLIST_NEXT (MPLIST_PLIST (elt)),
1228 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1231 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1237 free_flt_command (FontLayoutCmd *cmd)
1239 if (cmd->type == FontLayoutCmdTypeRule)
1241 FontLayoutCmdRule *rule = &cmd->body.rule;
1243 if (rule->src_type == SRC_REGEX)
1245 free (rule->src.re.pattern);
1246 regfree (&rule->src.re.preg);
1248 else if (rule->src_type == SRC_SEQ)
1249 free (rule->src.seq.codes);
1250 free (rule->cmd_ids);
1252 else if (cmd->type == FontLayoutCmdTypeCond)
1253 free (cmd->body.cond.cmd_ids);
1254 else if (cmd->type == FontLayoutCmdTypeOTF
1255 || cmd->type == FontLayoutCmdTypeOTFCategory)
1257 if (cmd->body.otf.features[0])
1258 free (cmd->body.otf.features[0]);
1259 if (cmd->body.otf.features[1])
1260 free (cmd->body.otf.features[1]);
1264 /* Load a generator from PLIST into a newly allocated FontLayoutStage,
1265 and return it. PLIST has this form:
1266 PLIST ::= ( COMMAND ( CMD-NAME COMMAND ) * )
1269 static FontLayoutStage *
1270 load_generator (MPlist *plist)
1272 FontLayoutStage *stage;
1274 FontLayoutCmd dummy;
1277 MSTRUCT_CALLOC (stage, MERROR_DRAW);
1278 MLIST_INIT1 (stage, cmds, 32);
1279 dummy.type = FontLayoutCmdTypeMAX;
1280 MLIST_APPEND1 (stage, cmds, dummy, MERROR_FONT);
1281 MPLIST_DO (elt, MPLIST_NEXT (plist))
1283 if (! MPLIST_PLIST_P (elt))
1284 MERROR (MERROR_FONT, NULL);
1285 pl = MPLIST_PLIST (elt);
1286 if (! MPLIST_SYMBOL_P (pl))
1287 MERROR (MERROR_FONT, NULL);
1288 MLIST_APPEND1 (stage, cmds, dummy, MERROR_FONT);
1291 /* Load the first command from PLIST into STAGE->cmds[0]. Macros
1292 called in the first command are also loaded from MPLIST_NEXT
1293 (PLIST) into STAGE->cmds[n]. */
1294 result = load_command (stage, plist, MPLIST_NEXT (plist),
1295 INDEX_TO_CMD_ID (0));
1296 if (result == INVALID_CMD_ID || result == -2)
1298 MLIST_FREE1 (stage, cmds);
1307 /* Load stages of the font layout table FLT. */
1310 load_flt (MFLT *flt, MPlist *key_list)
1312 MPlist *top, *plist, *pl, *p;
1313 FontLayoutCategory *category = NULL;
1317 top = (MPlist *) mdatabase__load_for_keys (flt->mdb, key_list);
1319 top = (MPlist *) mdatabase_load (flt->mdb);
1322 if (! MPLIST_PLIST_P (top))
1324 M17N_OBJECT_UNREF (top);
1325 MERROR (MERROR_FLT, -1);
1330 plist = mdatabase__props (flt->mdb);
1332 MERROR (MERROR_FLT, -1);
1333 MPLIST_DO (plist, plist)
1334 if (MPLIST_PLIST_P (plist))
1336 pl = MPLIST_PLIST (plist);
1337 if (! MPLIST_SYMBOL_P (pl)
1338 || MPLIST_SYMBOL (pl) != Mfont)
1340 pl = MPLIST_NEXT (pl);
1341 if (! MPLIST_PLIST_P (pl))
1343 p = MPLIST_PLIST (pl);
1344 if (! MPLIST_SYMBOL_P (p))
1346 p = MPLIST_NEXT (p);
1347 if (! MPLIST_SYMBOL_P (p))
1349 flt->family = MPLIST_SYMBOL (p);
1350 MPLIST_DO (p, MPLIST_NEXT (p))
1351 if (MPLIST_SYMBOL_P (p))
1353 sym = MPLIST_SYMBOL (p);
1354 if (MSYMBOL_NAME (sym)[0] != ':')
1355 flt->registry = sym, sym = Mnil;
1361 char *otf_spec = MSYMBOL_NAME (sym);
1363 if (otf_spec[0] == ':' && otf_spec[1] == 'o'
1364 && otf_spec[2] == 't' && otf_spec[3] == 'f')
1365 parse_otf_command (sym, &flt->otf);
1370 MPLIST_DO (plist, top)
1372 if (MPLIST_SYMBOL_P (plist)
1373 && MPLIST_SYMBOL (plist) == Mend)
1375 mplist_set (plist, Mnil, NULL);
1378 if (! MPLIST_PLIST (plist))
1380 pl = MPLIST_PLIST (plist);
1381 if (! MPLIST_SYMBOL_P (pl))
1383 sym = MPLIST_SYMBOL (pl);
1384 pl = MPLIST_NEXT (pl);
1387 if (sym == Mcategory)
1390 unref_category_table (category);
1391 else if (flt->coverage)
1393 category = flt->coverage;
1394 ref_category_table (category);
1397 category = load_category_table (pl, NULL);
1398 if (! flt->coverage)
1400 flt->coverage = category;
1401 ref_category_table (category);
1403 if (category->definition)
1404 flt->need_config = 1;
1406 else if (sym == Mgenerator)
1408 FontLayoutStage *stage;
1412 stage = load_generator (pl);
1415 stage->category = category;
1416 M17N_OBJECT_REF (category->table);
1418 flt->stages = mplist ();
1419 mplist_add (flt->stages, Mt, stage);
1423 unref_category_table (category);
1425 if (! MPLIST_TAIL_P (plist))
1427 M17N_OBJECT_UNREF (top);
1428 M17N_OBJECT_UNREF (flt->stages);
1429 MERROR (MERROR_FLT, -1);
1431 M17N_OBJECT_UNREF (top);
1437 free_flt_stage (MFLT *flt, FontLayoutStage *stage)
1441 unref_category_table (stage->category);
1444 for (i = 0; i < stage->used; i++)
1445 free_flt_command (stage->cmds + i);
1446 MLIST_FREE1 (stage, cmds);
1458 MPLIST_DO (plist, flt_list)
1460 MFLT *flt = MPLIST_VAL (plist);
1463 unref_category_table (flt->coverage);
1466 MPLIST_DO (pl, MPLIST_NEXT (flt->stages))
1467 free_flt_stage (flt, MPLIST_VAL (pl));
1468 M17N_OBJECT_UNREF (flt->stages);
1471 MPLIST_VAL (plist) = NULL;
1473 M17N_OBJECT_UNREF (flt_list);
1480 MPlist *plist, *key_list = NULL;
1484 if (! (plist = mdatabase_list (Mfont, Mlayouter, Mnil, Mnil)))
1486 if (! (flt_list = mplist ()))
1488 if (! (key_list = mplist ()))
1490 if (! mplist_add (key_list, Mcategory, Mt))
1493 MPLIST_DO (pl, plist)
1495 MDatabase *mdb = MPLIST_VAL (pl);
1496 MSymbol *tags = mdatabase_tag (mdb);
1499 if (! MSTRUCT_CALLOC_SAFE (flt))
1501 flt->name = tags[2];
1503 if (load_flt (flt, key_list) < 0)
1507 if (MPLIST_TAIL_P (flt_list))
1509 flt_min_coverage = mchartable_min_char (flt->coverage->table);
1510 flt_max_coverage = mchartable_max_char (flt->coverage->table);
1516 c = mchartable_min_char (flt->coverage->table);
1517 if (flt_min_coverage > c)
1518 flt_min_coverage = c;
1519 c = mchartable_max_char (flt->coverage->table);
1520 if (flt_max_coverage < c)
1521 flt_max_coverage = c;
1523 if (! mplist_push (flt_list, flt->name, flt))
1533 M17N_OBJECT_UNREF (plist);
1534 M17N_OBJECT_UNREF (key_list);
1538 /* FLS (Font Layout Service) */
1540 /* Structure to hold information about a context of FLS. */
1544 /* Pointer to the current stage. */
1545 FontLayoutStage *stage;
1547 /* Pointer to the category table of the next stage or NULL if none. */
1548 FontLayoutCategory *category;
1550 /* Pointer to the font. */
1553 /* Input and output glyph string. */
1554 MFLTGlyphString *in, *out;
1556 /* Encode each character or code of a glyph by the current category
1557 table into this array. An element is a category letter used for
1558 a regular expression matching. */
1563 int cluster_begin_idx;
1564 int cluster_begin_pos;
1565 int cluster_end_pos;
1569 } FontLayoutContext;
1571 static int run_command (int, int, int, int, FontLayoutContext *);
1572 static int run_otf (int, MFLTOtfSpec *, int, int, FontLayoutContext *);
1573 static int run_otf_category (int, MFLTOtfSpec *, int, int, FontLayoutContext *);
1578 run_rule (int depth,
1579 FontLayoutCmdRule *rule, int from, int to, FontLayoutContext *ctx)
1581 int *saved_match_indices = ctx->match_indices;
1582 int match_indices[NMATCH * 2];
1585 int orig_from = from;
1586 int need_cluster_update = 0;
1588 if (rule->src_type == SRC_REGEX)
1590 regmatch_t pmatch[NMATCH];
1596 saved_code = ctx->encoded[to - ctx->encoded_offset];
1597 ctx->encoded[to - ctx->encoded_offset] = '\0';
1598 result = regexec (&(rule->src.re.preg),
1599 ctx->encoded + (from - ctx->encoded_offset),
1601 if (result == 0 && pmatch[0].rm_so == 0)
1603 if (MDEBUG_FLAG () > 2)
1604 MDEBUG_PRINT5 ("\n [FLT] %*s(REGEX \"%s\" \"%s\" %d", depth, "",
1605 rule->src.re.pattern,
1606 ctx->encoded + (from - ctx->encoded_offset),
1608 ctx->encoded[to - ctx->encoded_offset] = saved_code;
1609 for (i = 0; i < NMATCH; i++)
1611 if (pmatch[i].rm_so < 0)
1612 match_indices[i * 2] = match_indices[i * 2 + 1] = -1;
1615 match_indices[i * 2] = from + pmatch[i].rm_so;
1616 match_indices[i * 2 + 1] = from + pmatch[i].rm_eo;
1619 ctx->match_indices = match_indices;
1620 to = match_indices[1];
1624 ctx->encoded[to - ctx->encoded_offset] = saved_code;
1627 need_cluster_update = 1;
1629 else if (rule->src_type == SRC_SEQ)
1633 len = rule->src.seq.n_codes;
1634 if (len > (to - from))
1636 for (i = 0; i < len; i++)
1637 if (rule->src.seq.codes[i] != GREF (ctx->in, from + i)->c)
1642 if (MDEBUG_FLAG () > 2)
1643 MDEBUG_PRINT3 ("\n [FLT] %*s(SEQ 0x%X", depth, "",
1644 rule->src.seq.codes[0]);
1645 need_cluster_update = 1;
1647 else if (rule->src_type == SRC_RANGE)
1653 head = GREF (ctx->in, from)->c;
1654 if (head < rule->src.range.from || head > rule->src.range.to)
1656 ctx->code_offset = head - rule->src.range.from;
1658 if (MDEBUG_FLAG () > 2)
1659 MDEBUG_PRINT4 ("\n [FLT] %*s(RANGE 0x%X-0x%X", depth, "",
1660 rule->src.range.from, rule->src.range.to);
1661 need_cluster_update = 1;
1663 else if (rule->src_type == SRC_INDEX)
1665 if (rule->src.match_idx >= NMATCH)
1667 from = ctx->match_indices[rule->src.match_idx * 2];
1670 to = ctx->match_indices[rule->src.match_idx * 2 + 1];
1671 if (MDEBUG_FLAG () > 2)
1672 MDEBUG_PRINT3 ("\n [FLT] %*s(SUBPART %d", depth, "",
1673 rule->src.match_idx);
1674 need_cluster_update = 1;
1676 else if (rule->src_type == SRC_HAS_GLYPH
1677 || rule->src_type == SRC_OTF_SPEC)
1679 static MFLTGlyphString gstring;
1683 if (rule->src.facility.len > 0)
1685 if (! gstring.glyph_size)
1687 gstring.glyph_size = ctx->in->glyph_size;
1688 gstring.glyphs = calloc (rule->src.facility.len,
1689 gstring.glyph_size);
1690 gstring.allocated = rule->src.facility.len;
1691 gstring.used = rule->src.facility.len;
1693 else if (rule->src.facility.len < gstring.allocated)
1695 gstring.glyphs = realloc (gstring.glyphs,
1697 * rule->src.facility.len);
1698 gstring.allocated = rule->src.facility.len;
1699 gstring.used = rule->src.facility.len;
1702 for (i = 0, p = rule->src.facility.codes, idx = from;
1703 i < rule->src.facility.len; i++, p = MPLIST_NEXT (p))
1705 if (MPLIST_INTEGER_P (p))
1707 GREF (&gstring, i)->code = MPLIST_INTEGER (p);
1708 GREF (&gstring, i)->encoded = 0;
1712 GREF (&gstring, i)->code = GREF (ctx->in, idx)->code;
1713 GREF (&gstring, i)->encoded = GREF (ctx->in, idx)->encoded;
1719 if (MDEBUG_FLAG () > 2)
1721 if (rule->src_type == SRC_HAS_GLYPH)
1722 MDEBUG_PRINT2 ("\n [FLT] %*s(HAS-GLYPH", depth, "");
1724 MDEBUG_PRINT2 ("\n [FLT] %*s(OTF-SPEC", depth, "");
1725 for (i = 0; i < rule->src.facility.len; i++)
1726 MDEBUG_PRINT1 (" %04X", GREF (&gstring, i)->code);
1728 if (ctx->font->get_glyph_id (ctx->font, &gstring, 0,
1729 rule->src.facility.len) < 0)
1731 MDEBUG_PRINT (") FAIL!");
1734 if (rule->src_type == SRC_OTF_SPEC)
1736 MFLTOtfSpec *spec = &rule->src.facility.otf_spec;
1738 if (! ctx->font->check_otf)
1740 if ((spec->features[0] && spec->features[0][0] != 0xFFFFFFFF)
1741 || (spec->features[1] && spec->features[1][0] != 0xFFFFFFFF))
1746 if (rule->src.facility.len == 0)
1748 if (! ctx->font->check_otf (ctx->font, spec))
1753 int prev_out_used = ctx->out->used, out_used;
1754 MFLTGlyphAdjustment *adjustment;
1756 adjustment = alloca ((sizeof *adjustment)
1757 * (ctx->out->allocated - ctx->out->used));
1759 MERROR (MERROR_FLT, -1);
1760 memset (adjustment, 0,
1761 (sizeof *adjustment)
1762 * (ctx->out->allocated - ctx->out->used));
1763 ctx->font->drive_otf (ctx->font, &rule->src.facility.otf_spec,
1764 &gstring, 0, rule->src.facility.len,
1767 out_used = ctx->out->used;
1768 ctx->out->used = prev_out_used;
1769 if (rule->src.facility.len == out_used - prev_out_used)
1771 for (i = prev_out_used; i < out_used; i++)
1773 if (GREF (&gstring, i - prev_out_used)->code
1774 != GREF (ctx->out, i)->code)
1776 if (adjustment[i - prev_out_used].set)
1787 if (need_cluster_update && ctx->cluster_begin_idx >= 0)
1789 for (i = from; i < to; i++)
1791 MFLTGlyph *g = GREF (ctx->in, i);
1792 UPDATE_CLUSTER_RANGE (ctx, g);
1798 for (i = 0; i < rule->n_cmds; i++)
1802 if (rule->cmd_ids[i] == CMD_ID_REPEAT)
1808 pos = run_command (depth, rule->cmd_ids[i], from, to, ctx);
1811 consumed = pos > from;
1816 ctx->match_indices = saved_match_indices;
1817 if (MDEBUG_FLAG () > 2)
1819 return (rule->src_type == SRC_INDEX ? orig_from : to);
1823 run_cond (int depth,
1824 FontLayoutCmdCond *cond, int from, int to, FontLayoutContext *ctx)
1828 if (MDEBUG_FLAG () > 2)
1829 MDEBUG_PRINT2 ("\n [FLT] %*s(COND", depth, "");
1831 for (i = 0; i < cond->n_cmds; i++)
1833 /* TODO: Write a code for optimization utilizaing the info
1835 if ((pos = run_command (depth, cond->cmd_ids[i], from, to, ctx))
1841 if (MDEBUG_FLAG () > 2)
1847 decode_packed_otf_tag (MFLTGlyphString *gstring, int from, int to,
1848 FontLayoutCategory *category)
1850 for (; from < to; from++)
1852 MFLTGlyph *g = GREF (gstring, from);
1853 unsigned int tag = g->internal & 0xFFFFFFF;
1858 SET_CATEGORY_CODE (g, 0);
1861 if (tag & 0xFFFFF80)
1865 g->internal &= 0x30000000;
1866 for (i = 0, enc = '\0'; i < category->feature_table.size; i++)
1867 if (category->feature_table.tag[i] == tag)
1869 enc = category->feature_table.code[i];
1874 enc = GET_COMBINED (g) ? '\0' : GET_CATEGORY_CODE (g);
1876 enc = g->c > 0 ? (int) mchartable_lookup (category->table, g->c) : 1;
1877 SET_CATEGORY_CODE (g, enc);
1883 MFLTOtfSpec *otf_spec, int from, int to, FontLayoutContext *ctx)
1885 MFLTFont *font = ctx->font;
1886 int from_idx = ctx->out->used;
1888 if (MDEBUG_FLAG () > 2)
1889 MDEBUG_PRINT3 ("\n [FLT] %*s%s", depth, "", MSYMBOL_NAME (otf_spec->sym));
1891 font->get_glyph_id (font, ctx->in, from, to);
1892 if (! font->drive_otf)
1894 if (ctx->out->used + (to - from) > ctx->out->allocated)
1896 font->get_metrics (font, ctx->in, from, to);
1897 GCPY (ctx->in, from, to - from, ctx->out, ctx->out->used);
1898 ctx->out->used += to - from;
1902 MFLTGlyphAdjustment *adjustment;
1906 adjustment = alloca ((sizeof *adjustment)
1907 * (ctx->out->allocated - ctx->out->used));
1909 MERROR (MERROR_FLT, -1);
1910 memset (adjustment, 0,
1911 (sizeof *adjustment) * (ctx->out->allocated - ctx->out->used));
1912 to = font->drive_otf (font, otf_spec, ctx->in, from, to, ctx->out,
1916 decode_packed_otf_tag (ctx->out, from_idx, ctx->out->used, ctx->category);
1917 out_len = ctx->out->used - from_idx;
1918 if (otf_spec->features[1])
1920 MFLTGlyphAdjustment *a;
1923 for (i = 0, a = adjustment; i < out_len; i++, a++)
1928 font->get_metrics (font, ctx->out, from_idx, ctx->out->used);
1929 for (g = GREF (ctx->out, from_idx + i);
1930 i < out_len; i++, a++, g = NEXT (ctx->out, g))
1933 if (a->advance_is_absolute)
1938 else if (a->xadv || a->yadv)
1943 if (a->xoff || a->yoff || a->back)
1946 MFLTGlyph *gg = PREV (ctx->out, g);
1947 MFLTGlyphAdjustment *aa = a;
1951 g->lbearing += a->xoff;
1952 g->rbearing += a->xoff;
1953 g->ascent -= a->yoff;
1954 g->descent -= a->yoff;
1955 while (aa->back > 0)
1957 for (j = 0; j < aa->back;
1958 j++, gg = PREV (ctx->out, gg))
1960 g->xoff -= gg->xadv;
1961 g->lbearing -= gg->xadv;
1962 g->rbearing -= gg->xadv;
1965 g->xoff += aa->xoff;
1966 g->yoff += aa->yoff;
1967 g->lbearing += aa->xoff;
1968 g->rbearing += aa->xoff;
1969 g->ascent -= aa->yoff;
1970 g->descent -= aa->yoff;
1979 if (ctx->cluster_begin_idx >= 0)
1980 for (; from_idx < ctx->out->used; from_idx++)
1982 MFLTGlyph *g = GREF (ctx->out, from_idx);
1983 UPDATE_CLUSTER_RANGE (ctx, g);
1989 run_otf_category (int depth, MFLTOtfSpec *otf_spec, int from, int to,
1990 FontLayoutContext *ctx)
1992 MFLTFont *font = ctx->font;
1993 int from_idx = ctx->out->used;
1995 if (! ctx->category || ctx->category->feature_table.size == 0)
1998 if (MDEBUG_FLAG () > 2)
1999 MDEBUG_PRINT3 ("\n [FLT] %*s%s", depth, "", MSYMBOL_NAME (otf_spec->sym));
2001 font->get_glyph_id (font, ctx->in, from, to);
2002 if (font->drive_otf)
2007 to = font->drive_otf (font, otf_spec, ctx->in, from, to, NULL, NULL);
2010 decode_packed_otf_tag (ctx->in, from, to, ctx->category);
2015 static char work[16];
2018 dump_combining_code (int code)
2020 char *vallign = "tcbB";
2021 char *hallign = "lcr";
2027 work[0] = vallign[COMBINING_CODE_BASE_Y (code)];
2028 work[1] = hallign[COMBINING_CODE_BASE_X (code)];
2029 off_y = COMBINING_CODE_OFF_Y (code);
2030 off_x = COMBINING_CODE_OFF_X (code);
2032 sprintf (work + 2, "+%d", off_y);
2034 sprintf (work + 2, "%d", off_y);
2035 else if (off_x == 0)
2036 sprintf (work + 2, ".");
2037 p = work + strlen (work);
2039 sprintf (p, ">%d", off_x);
2041 sprintf (p, "<%d", -off_x);
2043 p[0] = vallign[COMBINING_CODE_ADD_Y (code)];
2044 p[1] = hallign[COMBINING_CODE_ADD_X (code)];
2050 run_command (int depth, int id, int from, int to, FontLayoutContext *ctx)
2057 MCharTable *table = ctx->category ? ctx->category->table : NULL;
2060 /* Direct code (== ctx->code_offset + id) output.
2061 The source is not consumed. */
2062 if (MDEBUG_FLAG () > 2)
2063 MDEBUG_PRINT3 ("\n [FLT] %*s(DIRECT 0x%X", depth, "",
2064 ctx->code_offset + id);
2065 i = (from < to || from == 0) ? from : from - 1;
2067 g = GREF (ctx->out, ctx->out->used - 1);
2068 g->c = g->code = ctx->code_offset + id;
2069 if (ctx->combining_code)
2070 SET_COMBINING_CODE (g, ctx, ctx->combining_code);
2073 enc = (GET_ENCODED (g)
2074 ? (g->c > 0 ? (int) mchartable_lookup (table, g->c) : 1)
2076 ? (int) mchartable_lookup (table, g->code)
2078 SET_CATEGORY_CODE (g, enc);
2081 SET_MEASURED (g, 0);
2082 if (ctx->left_padding)
2083 SET_LEFT_PADDING (g, ctx, LeftPaddingMask);
2084 for (i = from; i < to; i++)
2086 MFLTGlyph *tmp = GREF (ctx->in, i);
2088 if (g->from > tmp->from)
2089 g->from = tmp->from;
2090 else if (g->to < tmp->to)
2093 if (ctx->cluster_begin_idx >= 0)
2094 UPDATE_CLUSTER_RANGE (ctx, g);
2095 ctx->code_offset = ctx->combining_code = ctx->left_padding = 0;
2096 if (MDEBUG_FLAG () > 2)
2101 if (id <= CMD_ID_OFFSET_INDEX)
2103 int idx = CMD_ID_TO_INDEX (id);
2106 if (idx >= ctx->stage->used)
2107 MERROR (MERROR_DRAW, -1);
2108 cmd = ctx->stage->cmds + idx;
2109 if (cmd->type == FontLayoutCmdTypeRule)
2110 to = run_rule (depth, &cmd->body.rule, from, to, ctx);
2111 else if (cmd->type == FontLayoutCmdTypeCond)
2112 to = run_cond (depth, &cmd->body.cond, from, to, ctx);
2113 else if (cmd->type == FontLayoutCmdTypeOTF)
2114 to = run_otf (depth, &cmd->body.otf, from, to, ctx);
2115 else if (cmd->type == FontLayoutCmdTypeOTFCategory)
2116 to = run_otf_category (depth, &cmd->body.otf, from, to, ctx);
2120 if (id <= CMD_ID_OFFSET_COMBINING)
2122 ctx->combining_code = CMD_ID_TO_COMBINING_CODE (id);
2123 if (MDEBUG_FLAG () > 2)
2124 MDEBUG_PRINT3 ("\n [FLT] %*s(CMB %s)", depth, "",
2125 dump_combining_code (ctx->combining_code));
2136 g = GREF (ctx->out, ctx->out->used - 1);
2137 if (ctx->combining_code)
2138 SET_COMBINING_CODE (g, ctx, ctx->combining_code);
2139 else if (! GET_COMBINED (g) && ctx->category)
2141 MCharTable *table = ctx->category->table;
2142 char enc = (GET_ENCODED (g)
2143 ? (g->c > 0 ? (int) mchartable_lookup (table, g->c)
2146 ? (int) mchartable_lookup (table, g->code)
2148 SET_CATEGORY_CODE (g, enc);
2150 if (ctx->left_padding)
2151 SET_LEFT_PADDING (g, ctx, LeftPaddingMask);
2152 if (ctx->cluster_begin_idx >= 0)
2153 UPDATE_CLUSTER_RANGE (ctx, g);
2154 if (MDEBUG_FLAG () > 2)
2157 MDEBUG_PRINT2 ("\n [FLT] %*s(COPY |)", depth, "");
2159 MDEBUG_PRINT3 ("\n [FLT] %*s(COPY 0x%X)", depth, "", g->c);
2161 ctx->code_offset = ctx->combining_code = ctx->left_padding = 0;
2165 case CMD_ID_CLUSTER_BEGIN:
2166 if (ctx->cluster_begin_idx < 0)
2168 if (MDEBUG_FLAG () > 2)
2169 MDEBUG_PRINT3 ("\n [FLT] %*s<%d", depth, "",
2170 GREF (ctx->in, from)->from);
2171 ctx->cluster_begin_idx = ctx->out->used;
2172 ctx->cluster_begin_pos = GREF (ctx->in, from)->from;
2173 ctx->cluster_end_pos = GREF (ctx->in, from)->to;
2177 case CMD_ID_CLUSTER_END:
2178 if (ctx->cluster_begin_idx >= 0
2179 && ctx->cluster_begin_idx < ctx->out->used)
2183 if (MDEBUG_FLAG () > 2)
2184 MDEBUG_PRINT1 (" %d>", ctx->cluster_end_pos + 1);
2185 for (i = ctx->cluster_begin_idx; i < ctx->out->used; i++)
2187 GREF (ctx->out, i)->from = ctx->cluster_begin_pos;
2188 GREF (ctx->out, i)->to = ctx->cluster_end_pos;
2190 ctx->cluster_begin_idx = -1;
2194 case CMD_ID_SEPARATOR:
2198 i = from < to ? from : from - 1;
2200 g = GREF (ctx->out, ctx->out->used - 1);
2201 g->c = -1, g->code = 0;
2202 g->xadv = g->yadv = 0;
2204 SET_MEASURED (g, 1);
2205 SET_CATEGORY_CODE (g, ' ');
2209 case CMD_ID_LEFT_PADDING:
2210 if (MDEBUG_FLAG () > 2)
2211 MDEBUG_PRINT2 ("\n [FLT] %*s[", depth, "");
2212 ctx->left_padding = 1;
2215 case CMD_ID_RIGHT_PADDING:
2216 if (ctx->out->used > 0)
2218 if (MDEBUG_FLAG () > 2)
2219 MDEBUG_PRINT2 ("\n [FLT] %*s]", depth, "");
2220 g = GREF (ctx->out, ctx->out->used - 1);
2221 SET_RIGHT_PADDING (g, ctx, RightPaddingMask);
2226 MERROR (MERROR_DRAW, -1);
2230 run_stages (MFLTGlyphString *gstring, int from, int to,
2231 MFLT *flt, FontLayoutContext *ctx)
2233 MFLTGlyphString buf, *temp;
2235 int orig_from = from, orig_to = to;
2236 int from_pos, to_pos, len;
2239 MPlist *stages = flt->stages;
2241 from_pos = GREF (ctx->in, from)->from;
2242 to_pos = GREF (ctx->in, to - 1)->to;
2243 len = to_pos - from_pos;
2247 GINIT (ctx->out, ctx->out->allocated);
2248 ctx->encoded = alloca (ctx->out->allocated);
2249 if (! ctx->out->glyphs || ! ctx->encoded)
2252 for (stage_idx = 0; 1; stage_idx++)
2257 ctx->stage = (FontLayoutStage *) MPLIST_VAL (stages);
2258 table = ctx->stage->category->table;
2259 stages = MPLIST_NEXT (stages);
2260 if (MPLIST_TAIL_P (stages))
2261 ctx->category = NULL;
2263 ctx->category = ((FontLayoutStage *) MPLIST_VAL (stages))->category;
2264 ctx->code_offset = ctx->combining_code = ctx->left_padding = 0;
2265 ctx->encoded_offset = from;
2266 for (i = from; i < to; i++)
2268 MFLTGlyph *g = GREF (ctx->in, i);
2271 if (GET_COMBINED (g))
2272 enc = (GET_ENCODED (g)
2273 ? (g->c > 0 ? (int) mchartable_lookup (table, g->c) : 1)
2275 ? (int) mchartable_lookup (table, g->code)
2278 enc = GET_CATEGORY_CODE (g);
2279 ctx->encoded[i - from] = enc;
2280 if (! enc && stage_idx == 0)
2286 ctx->encoded[i - from] = '\0';
2287 ctx->match_indices[0] = from;
2288 ctx->match_indices[1] = to;
2289 for (i = 2; i < NMATCH; i++)
2290 ctx->match_indices[i] = -1;
2292 if (MDEBUG_FLAG () > 2)
2294 MDEBUG_PRINT2 ("\n [FLT] (STAGE %d \"%s\"", stage_idx,
2296 MDEBUG_PRINT (" (");
2297 for (i = from; i < to; i++)
2299 g = GREF (ctx->in, i);
2301 MDEBUG_PRINT2 ("%*s|", (i > 0), "");
2303 MDEBUG_PRINT3 ("%*s%04X", (i > 0), "", GREF (ctx->in, i)->code);
2307 result = run_command (4, INDEX_TO_CMD_ID (0), from, to, ctx);
2308 if (MDEBUG_FLAG () > 2)
2313 /* If this is the last stage, break the loop. */
2314 if (MPLIST_TAIL_P (stages))
2317 /* Otherwise, prepare for the next stage. */
2324 GINIT (&buf, ctx->out->allocated);
2333 if (ctx->out->used > 0)
2336 int x_ppem = ctx->font->x_ppem << 6, y_ppem = ctx->font->y_ppem << 6;
2338 /* Remove separator glyphs. */
2339 for (i = 0; i < ctx->out->used;)
2341 g = GREF (ctx->out, i);
2343 GREPLACE (NULL, 0, 0, ctx->out, i, i + 1);
2348 /* Get actual glyph IDs of glyphs. */
2349 ctx->font->get_glyph_id (ctx->font, ctx->out, 0, ctx->out->used);
2351 /* Check if all characters in the range are covered by some
2352 glyph(s). If not, change <from> and <to> of glyphs to cover
2353 uncovered characters. */
2354 g_indices = alloca (sizeof (int) * len);
2357 for (i = 0; i < len; i++) g_indices[i] = -1;
2358 for (i = 0; i < ctx->out->used; i++)
2362 g = GREF (ctx->out, i);
2363 for (pos = g->from; pos <= g->to; pos++)
2364 if (g_indices[pos - from_pos] < 0)
2365 g_indices[pos - from_pos] = i;
2367 for (i = 0; i < len; i++)
2368 if (g_indices[i] < 0)
2374 for (i++; i < len && g_indices[i] < 0; i++);
2376 g = GREF (ctx->out, j);
2377 this_from = g->from;
2379 g->from = orig_from + i;
2380 } while (++j < ctx->out->used
2381 && (g = GREF (ctx->out, j))
2382 && g->from == this_from);
2388 j = g_indices[i - 1];
2389 g = GREF (ctx->out, j);
2392 g->to = orig_from + i + 1;
2394 && (g = GREF (ctx->out, j))
2395 && g->to == this_to);
2399 ctx->font->get_metrics (ctx->font, ctx->out, 0, ctx->out->used);
2401 /* Handle combining. */
2402 if (ctx->check_mask & CombinedMask)
2404 MFLTGlyph *base = GREF (ctx->out, 0);
2405 int base_height = base->ascent + base->descent;
2406 int base_width = base->rbearing - base->lbearing;
2409 for (i = 1; i < ctx->out->used; i++)
2411 if ((g = GREF (ctx->out, i))
2413 && (combining_code = GET_COMBINING_CODE (g)))
2415 int height = g->ascent + g->descent;
2416 int width = g->rbearing - g->lbearing;
2417 int base_x, base_y, add_x, add_y, off_x, off_y;
2419 if (base->from > g->from)
2420 base->from = g->from;
2421 else if (base->to < g->to)
2424 base_x = COMBINING_CODE_BASE_X (combining_code);
2425 base_y = COMBINING_CODE_BASE_Y (combining_code);
2426 add_x = COMBINING_CODE_ADD_X (combining_code);
2427 add_y = COMBINING_CODE_ADD_Y (combining_code);
2428 off_x = COMBINING_CODE_OFF_X (combining_code);
2429 off_y = COMBINING_CODE_OFF_Y (combining_code);
2431 g->xoff = ((base_width * base_x - width * add_x) / 2
2432 + x_ppem * off_x / 100
2433 - (base->xadv - base->lbearing) - g->lbearing);
2435 g->yoff = base_height * base_y / 2 - base->ascent;
2439 g->yoff -= height * add_y / 2 - g->ascent;
2440 g->yoff -= y_ppem * off_y / 100;
2441 if (base->lbearing > base->xadv + g->lbearing + g->xoff)
2442 base->lbearing = base->xadv + g->lbearing + g->xoff;
2443 if (base->rbearing < base->xadv + g->rbearing + g->xoff)
2444 base->rbearing = base->xadv + g->rbearing + g->xoff;
2445 if (base->ascent < g->ascent - g->yoff)
2446 base->ascent = g->ascent - g->yoff;
2447 if (base->descent < g->descent - g->yoff)
2448 base->descent = g->descent - g->yoff;
2449 g->xadv = g->yadv = 0;
2450 if (GET_RIGHT_PADDING (g))
2451 SET_RIGHT_PADDING (base, ctx, RightPaddingMask);
2457 base_height = g->ascent + g->descent;
2458 base_width = g->rbearing - g->lbearing;
2463 /* Handle padding */
2464 if (ctx->check_mask & (LeftPaddingMask | RightPaddingMask))
2465 for (i = 0; i < ctx->out->used; i++)
2467 g = GREF (ctx->out, i);
2468 if (! GET_COMBINED (g))
2470 if (GET_RIGHT_PADDING (g) && g->rbearing > g->xadv)
2472 g->xadv = g->rbearing;
2475 if (GET_LEFT_PADDING (g) && g->lbearing < 0)
2477 g->xoff += - g->lbearing;
2478 g->xadv += - g->lbearing;
2479 g->rbearing += - g->lbearing;
2487 GREPLACE (ctx->out, 0, ctx->out->used, gstring, orig_from, orig_to);
2488 to = orig_from + ctx->out->used;
2493 setup_combining_coverage (int from, int to, void *val, void *arg)
2495 int combining_class = (int) val;
2498 if (combining_class < 200)
2500 else if (combining_class <= 204)
2502 if ((combining_class % 2) == 0)
2503 category = "bcd"[(combining_class - 200) / 2];
2505 else if (combining_class <= 232)
2507 if ((combining_class % 2) == 0)
2508 category = "efghijklmnopq"[(combining_class - 208) / 2];
2510 else if (combining_class == 233)
2512 else if (combining_class == 234)
2514 else if (combining_class == 240)
2516 mchartable_set_range ((MCharTable *) arg, from, to, (void *) category);
2520 setup_combining_flt (MFLT *flt)
2523 MCharTable *combininig_class_table
2524 = mchar_get_prop_table (Mcombining_class, &type);
2526 mchartable_set_range (flt->coverage->table, 0, 0x10FFFF, (void *) 'u');
2527 if (combininig_class_table)
2528 mchartable_map (combininig_class_table, (void *) 0,
2529 setup_combining_coverage, flt->coverage->table);
2532 #define CHECK_FLT_STAGES(flt) ((flt)->stages || load_flt (flt, NULL) == 0)
2534 static FontLayoutCategory *
2535 configure_category (FontLayoutCategory *category, MFLTFont *font)
2537 if (! mflt_font_id || ! mflt_iterate_otf_feature)
2539 FontLayoutCategory *new = malloc (sizeof (FontLayoutCategory));
2540 new->definition = NULL;
2541 new->table = category->table;
2542 M17N_OBJECT_REF (new->table);
2545 return load_category_table (category->definition, font);
2549 configure_flt (MFLT *flt, MFLTFont *font, MSymbol font_id)
2554 if (! mflt_font_id || ! mflt_iterate_otf_feature)
2556 MPLIST_DO (plist, flt_list)
2558 configured = MPLIST_VAL (plist);
2559 if (! configured->font_id)
2561 if (configured->name == flt->name
2562 && configured->font_id == font_id)
2565 if (! MSTRUCT_CALLOC_SAFE (configured))
2568 configured->stages = mplist_copy (flt->stages);
2569 MPLIST_DO (plist, configured->stages)
2571 FontLayoutStage *stage = MPLIST_VAL (plist);
2572 if (stage->category->definition)
2574 MSTRUCT_CALLOC (stage, MERROR_FLT);
2575 *stage = *((FontLayoutStage *) MPLIST_VAL (plist));
2576 stage->category = configure_category (stage->category, font);
2577 MPLIST_VAL (plist) = stage;
2580 M17N_OBJECT_REF (stage->category->table);
2582 configured->need_config = 0;
2583 configured->font_id = font_id;
2584 mplist_push (flt_list, flt->name, configured);
2590 int m17n__flt_initialized;
2595 /* The following two are actually not exposed to a user but concealed
2596 by the macro M17N_INIT (). */
2599 m17n_init_flt (void)
2601 int mdebug_flag = MDEBUG_INIT;
2603 merror_code = MERROR_NONE;
2604 if (m17n__flt_initialized++)
2607 if (merror_code != MERROR_NONE)
2609 m17n__flt_initialized--;
2613 MDEBUG_PUSH_TIME ();
2615 Mcond = msymbol ("cond");
2616 Mrange = msymbol ("range");
2617 Mfont = msymbol ("font");
2618 Mlayouter = msymbol ("layouter");
2619 Mcombining = msymbol ("combining");
2620 Mfont_facility = msymbol ("font-facility");
2621 Mequal = msymbol ("=");
2622 Mgenerator = msymbol ("generator");
2623 Mend = msymbol ("end");
2625 mflt_iterate_otf_feature = NULL;
2626 mflt_font_id = NULL;
2628 MDEBUG_PRINT_TIME ("INIT", (stderr, " to initialize the flt modules."));
2633 m17n_fini_flt (void)
2635 int mdebug_flag = MDEBUG_FINI;
2637 if (m17n__flt_initialized == 0
2638 || --m17n__flt_initialized > 0)
2641 MDEBUG_PUSH_TIME ();
2643 MDEBUG_PRINT_TIME ("FINI", (stderr, " to finalize the flt modules."));
2649 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
2651 /*** @addtogroup m17nFLT */
2657 @brief Return an FLT object that has a specified name.
2659 The mflt_get () function returns an FLT object whose name is $NAME.
2662 If the operation was successful, mflt_get () returns a pointer
2663 to the found FLT object. Otherwise, it returns @c NULL. */
2666 @brief »ØÄꤵ¤ì¤¿Ì¾Á°¤ò»ý¤Ä FLT ¥ª¥Ö¥¸¥§¥¯¥È¤òÊÖ¤¹.
2668 ´Ø¿ô mflt_get () ¤Ï¡¢$NAME ¤È¤¤¤¦Ì¾Á°¤ò»ý¤Ä FLT ¥ª¥Ö¥¸¥§¥¯¥È¤òÊÖ¤¹¡£
2671 ¤â¤·À®¸ù¤¹¤ì¤Ð¡¢mflt_get () ¤Ï¸«¤Ä¤«¤Ã¤¿ FLT
2672 ¥ª¥Ö¥¸¥§¥¯¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¼ºÇÔ¤·¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤¹¡£ */
2675 mflt_get (MSymbol name)
2680 if (! flt_list && list_flt () < 0)
2682 for (plist = flt_list; plist; plist = plist->next)
2683 if (((MFLT *) MPLIST_VAL (plist))->font_id == Mnil)
2685 flt = mplist_get (plist, name);
2686 if (! flt || ! CHECK_FLT_STAGES (flt))
2688 if (flt->name == Mcombining
2689 && ! mchartable_lookup (flt->coverage->table, 0))
2690 setup_combining_flt (flt);
2697 @brief Find an FLT suitable for the specified character and font.
2699 The mflt_find () function returns the most appropriate FLT for
2700 layouting character $C with font $FONT.
2703 If the operation was successful, mflt_find () returns a pointer
2704 to the found FLT object. Otherwise, it returns @c NULL. */
2707 @brief »ØÄꤵ¤ì¤¿Ê¸»ú¤È¥Õ¥©¥ó¥È¤Ë¹ç¤Ã¤¿ FLT ¤òõ¤¹.
2709 ´Ø¿ô mflt_find () ¤Ï¡¢Ê¸»ú $C ¤ò¥Õ¥©¥ó¥È $FONT
2710 ¤Ç¥ì¥¤¥¢¥¦¥È¤¹¤ë¤¿¤á¤ËºÇ¤âŬÀÚ¤Ê FLT ¤òÊÖ¤¹¡£
2713 ¤â¤·À®¸ù¤¹¤ì¤Ð¡¢mflt_find () ¤Ï¸«¤Ä¤«¤Ã¤¿ FLT
2714 ¥ª¥Ö¥¸¥§¥¯¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¼ºÇÔ¤·¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤¹¡£ */
2717 mflt_find (int c, MFLTFont *font)
2721 static MSymbol unicode_bmp = NULL, unicode_full = NULL;
2725 unicode_bmp = msymbol ("unicode-bmp");
2726 unicode_full = msymbol ("unicode-full");
2729 if (! flt_list && list_flt () < 0)
2731 /* Skip configured FLTs. */
2732 MPLIST_DO (plist, flt_list)
2733 if (((MFLT *) MPLIST_VAL (plist))->font_id == Mnil)
2739 MPLIST_DO (pl, plist)
2741 flt = MPLIST_VAL (pl);
2742 if (flt->registry != unicode_bmp
2743 && flt->registry != unicode_full)
2745 if (flt->family && flt->family != font->family)
2747 if (flt->name == Mcombining
2748 && ! mchartable_lookup (flt->coverage->table, 0))
2749 setup_combining_flt (flt);
2751 && ! mchartable_lookup (flt->coverage->table, c))
2755 MFLTOtfSpec *spec = &flt->otf;
2757 if (! font->check_otf)
2759 if ((spec->features[0] && spec->features[0][0] != 0xFFFFFFFF)
2760 || (spec->features[1] && spec->features[1][0] != 0xFFFFFFFF))
2763 else if (! font->check_otf (font, spec))
2774 MPLIST_DO (pl, plist)
2776 flt = MPLIST_VAL (pl);
2777 if (mchartable_lookup (flt->coverage->table, c))
2784 if (! CHECK_FLT_STAGES (flt))
2786 if (font && flt->need_config && mflt_font_id)
2787 flt = configure_flt (flt, font, mflt_font_id (font));
2793 @brief Return the name of an FLT.
2795 The mflt_name () function returns the name of $FLT. */
2798 @brief FLT ¤Î̾Á°¤òÊÖ¤¹.
2800 ´Ø¿ô mflt_name () ¤Ï $FLT ¤Î̾Á°¤òÊÖ¤¹¡£ */
2803 mflt_name (MFLT *flt)
2805 return MSYMBOL_NAME (flt->name);
2810 @brief Return a coverage of a FLT.
2812 The mflt_coverage () function returns a char-table that contains
2813 nonzero values for characters supported by $FLT. */
2816 @brief FLT ¤ÎÈϰϤòÊÖ¤¹.
2818 ´Ø¿ô mflt_coverage () ¤Ï¡¢$FLT ¤¬¥µ¥Ý¡¼¥È¤¹¤ëʸ»ú¤ËÂФ·¤Æ
2819 0 ¤Ç¤Ê¤¤Ãͤò´Þ¤àʸ»ú¥Æ¡¼¥Ö¥ë¤òÊÖ¤¹¡£ */
2822 mflt_coverage (MFLT *flt)
2824 return flt->coverage->table;
2829 @brief Layout characters with an FLT.
2831 The mflt_run () function layouts characters in $GSTRING between
2832 $FROM (inclusive) and $TO (exclusive) with $FONT. If $FLT is
2833 nonzero, it is used for all the charaters. Otherwise, appropriate
2834 FLTs are automatically chosen.
2837 The operation was successful. The value is the index to the
2838 glyph, which was previously indexed by $TO, in $GSTRING->glyphs.
2841 $GSTRING->glyphs is too short to store the result. The caller can
2842 call this fucntion again with a longer $GSTRING->glyphs.
2845 Some other error occurred. */
2848 @brief FLT ¤ò»È¤Ã¤Æʸ»ú¤ò¥ì¥¤¥¢¥¦¥È¤¹¤ë.
2850 ´Ø¿ô mflt_run () ¤Ï¡¢$GSTRING Ãæ¤Î $FROM ¤«¤é $TO ľÁ°¤Þ¤Ç¤Îʸ»ú¤ò
2851 $FONT ¤òÍѤ¤¤Æ¥ì¥¤¥¢¥¦¥È¤¹¤ë¡£¤â¤· $FLT
2852 ¤¬¥¼¥í¤Ç¤Ê¤±¤ì¤Ð¡¢¤½¤ÎÃͤò¤¹¤Ù¤Æ¤Îʸ»ú¤ËÂФ·¤ÆÍѤ¤¤ë¡£
2853 ¤½¤¦¤Ç¤Ê¤±¤ì¤ÐŬÀÚ¤Ê FLT ¤ò¼«Æ°Åª¤ËÁªÂò¤¹¤ë¡£
2856 ¼Â¹ÔÀ®¸ù¤ò¼¨¤¹¡£ÊÖ¤µ¤ì¤ëÃͤϡ¢$GSTRING->glyphs Ãæ¤Ç°ÊÁ° $TO
2857 ¤Ë¤è¤Ã¤Æ¼¨¤µ¤ì¤Æ¤¤¤¿¥°¥ê¥Õ¤Ø¤Î¥¤¥ó¥Ç¥¯¥¹¤Ç¤¢¤ë¡£
2860 ·ë²Ì¤ò³ÊǼ¤¹¤ë¤Ë¤Ï $GSTRING->glyphs ¤¬Ã»¤¹¤®¤ë¤³¤È¤ò¼¨¤¹¡£
2861 ¸Æ¤Ó½Ð¤·Â¦¤Ï¡¢¤è¤êŤ¤ $GSTRING->glyphs
2862 ¤òÍѤ¤¤ÆºÆÅÙ¤³¤Î´Ø¿ô¤ò¸Æ¤Ö¤³¤È¤¬¤Ç¤¤ë¡£
2865 ¤½¤Î¾¤Î¥¨¥é¡¼¤¬µ¯¤¤¿¤³¤È¤ò¼¨¤¹¡£ */
2868 mflt_run (MFLTGlyphString *gstring, int from, int to,
2869 MFLTFont *font, MFLT *flt)
2871 FontLayoutContext ctx;
2872 int match_indices[NMATCH];
2874 MFLTGlyphString out;
2875 int auto_flt = ! flt;
2877 int this_from, this_to;
2878 MSymbol font_id = mflt_font_id ? mflt_font_id (font) : Mnil;
2882 /* This is usually sufficient, but if not, we retry with the larger
2883 values at most 3 times. This value is also used for the
2884 allocating size of ctx.encoded. */
2885 out.allocated = (to - from) * 4;
2887 for (i = from; i < to; i++)
2889 g = GREF (gstring, i);
2893 memset (g, 0, sizeof (MFLTGlyph));
2896 g->from = g->to = i;
2899 for (this_from = from; this_from < to;)
2903 for (this_to = this_from; this_to < to; this_to++)
2904 if (mchartable_lookup (flt->coverage->table,
2905 GREF (gstring, this_to)->c))
2910 if (! flt_list && list_flt () < 0)
2912 font->get_glyph_id (font, gstring, this_from, to);
2913 font->get_metrics (font, gstring, this_from, to);
2917 for (this_to = this_from; this_to < to; this_to++)
2919 c = GREF (gstring, this_to)->c;
2920 if (c >= flt_min_coverage && c <= flt_max_coverage)
2923 for (; this_to < to; this_to++)
2925 c = GREF (gstring, this_to)->c;
2927 && mchartable_lookup (((MFLT *) font->internal)->coverage->table, c))
2929 flt = font->internal;
2932 flt = mflt_find (c, font);
2935 if (CHECK_FLT_STAGES (flt))
2937 font->internal = flt;
2944 if (this_from < this_to)
2946 font->get_glyph_id (font, gstring, this_from, this_to);
2947 font->get_metrics (font, gstring, this_from, this_to);
2948 this_from = this_to;
2953 MDEBUG_PRINT1 (" [FLT] (%s", MSYMBOL_NAME (flt->name));
2955 if (flt->need_config && font_id != Mnil)
2956 flt = configure_flt (flt, font, font_id);
2958 for (; this_to < to; this_to++)
2961 g = GREF (gstring, this_to);
2962 enc = (int) mchartable_lookup (flt->coverage->table, g->c);
2965 SET_CATEGORY_CODE (g, enc);
2971 MDEBUG_PRINT1 (" (%s)", MSYMBOL_NAME (font->family));
2972 MDEBUG_PRINT ("\n [FLT] (SOURCE");
2973 for (i = this_from, j = 0; i < this_to; i++, j++)
2975 if (j > 0 && j % 8 == 0)
2976 MDEBUG_PRINT ("\n [FLT] ");
2977 MDEBUG_PRINT1 (" %04X", GREF (gstring, i)->c);
2982 for (i = 0; i < 3; i++)
2985 memset (&ctx, 0, sizeof ctx);
2986 ctx.match_indices = match_indices;
2988 ctx.cluster_begin_idx = -1;
2991 j = run_stages (gstring, this_from, this_to, flt, &ctx);
3005 MDEBUG_PRINT ("\n [FLT] (RESULT");
3006 if (MDEBUG_FLAG () > 1)
3007 for (i = 0; this_from < this_to; this_from++, i++)
3009 if (i > 0 && i % 4 == 0)
3010 MDEBUG_PRINT ("\n [FLT] ");
3011 g = GREF (gstring, this_from);
3012 MDEBUG_PRINT4 (" (%04X %d %d %d)",
3013 g->code, g->xadv, g->xoff, g->yoff);
3016 for (; this_from < this_to; this_from++)
3017 MDEBUG_PRINT1 (" %04X", GREF (gstring, this_from)->code);
3018 MDEBUG_PRINT ("))\n");
3020 this_from = this_to;
3025 int len = to - from;
3028 memcpy (((char *) out.glyphs),
3029 ((char *) gstring->glyphs) + gstring->glyph_size * from,
3030 gstring->glyph_size * len);
3031 for (i = from, j = to; i < to;)
3033 for (k = i + 1, j--; k < to && GREF (&out, k)->xadv == 0;
3035 GCPY (&out, i, (k - i), gstring, j);
3043 int (*mflt_iterate_otf_feature) (struct _MFLTFont *font,
3046 unsigned char *table);
3048 MSymbol (*mflt_font_id) (struct _MFLTFont *font);
3051 /* for debugging... */
3054 dump_flt_cmd (FontLayoutStage *stage, int id, int indent)
3056 char *prefix = (char *) alloca (indent + 1);
3058 memset (prefix, 32, indent);
3062 fprintf (stderr, "0x%02X", id);
3063 else if (id <= CMD_ID_OFFSET_INDEX)
3065 int idx = CMD_ID_TO_INDEX (id);
3066 FontLayoutCmd *cmd = stage->cmds + idx;
3068 if (cmd->type == FontLayoutCmdTypeRule)
3070 FontLayoutCmdRule *rule = &cmd->body.rule;
3073 fprintf (stderr, "(rule ");
3074 if (rule->src_type == SRC_REGEX)
3075 fprintf (stderr, "\"%s\"", rule->src.re.pattern);
3076 else if (rule->src_type == SRC_INDEX)
3077 fprintf (stderr, "%d", rule->src.match_idx);
3078 else if (rule->src_type == SRC_SEQ)
3079 fprintf (stderr, "(seq)");
3080 else if (rule->src_type == SRC_RANGE)
3081 fprintf (stderr, "(range)");
3083 fprintf (stderr, "(invalid src)");
3085 for (i = 0; i < rule->n_cmds; i++)
3087 fprintf (stderr, "\n%s ", prefix);
3088 dump_flt_cmd (stage, rule->cmd_ids[i], indent + 2);
3090 fprintf (stderr, ")");
3092 else if (cmd->type == FontLayoutCmdTypeCond)
3094 FontLayoutCmdCond *cond = &cmd->body.cond;
3097 fprintf (stderr, "(cond");
3098 for (i = 0; i < cond->n_cmds; i++)
3100 fprintf (stderr, "\n%s ", prefix);
3101 dump_flt_cmd (stage, cond->cmd_ids[i], indent + 2);
3103 fprintf (stderr, ")");
3105 else if (cmd->type == FontLayoutCmdTypeOTF)
3107 fprintf (stderr, "(otf)");
3110 fprintf (stderr, "(error-command)");
3112 else if (id <= CMD_ID_OFFSET_COMBINING)
3113 fprintf (stderr, "cominging-code");
3115 fprintf (stderr, "(predefiend %d)", id);
3119 @brief Dump a Font Layout Table.
3121 The mdebug_dump_flt () function prints the Font Layout Table $FLT
3122 in a human readable way to the stderr. $INDENT specifies how many
3123 columns to indent the lines but the first one.
3126 This function returns $FLT. */
3129 mdebug_dump_flt (MFLT *flt, int indent)
3131 char *prefix = (char *) alloca (indent + 1);
3135 memset (prefix, 32, indent);
3137 fprintf (stderr, "(flt");
3138 MPLIST_DO (plist, flt->stages)
3140 FontLayoutStage *stage = (FontLayoutStage *) MPLIST_VAL (plist);
3143 fprintf (stderr, "\n%s (stage %d", prefix, stage_idx);
3144 for (i = 0; i < stage->used; i++)
3146 fprintf (stderr, "\n%s ", prefix);
3147 dump_flt_cmd (stage, INDEX_TO_CMD_ID (i), indent + 4);
3149 fprintf (stderr, ")");
3152 fprintf (stderr, ")");
3157 mflt_dump_gstring (MFLTGlyphString *gstring)
3161 fprintf (stderr, "(flt-gstring");
3162 for (i = 0; i < gstring->used; i++)
3164 MFLTGlyph *g = GREF (gstring, i);
3165 fprintf (stderr, "\n (%02d pos:%d-%d c:%04X code:%04X cat:%c)",
3166 i, g->from, g->to, g->c, g->code, GET_CATEGORY_CODE (g));
3168 fprintf (stderr, ")\n");