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=" or ":otf?" */
747 if (str[-1] == '?' && ! *str)
748 /* This is a spec to reset category codes. */
750 script = gen_otf_tag (str, 8);
754 langsys = gen_otf_tag (str, 8);
761 /* Apply all GSUB features. */
766 str = otf_count_features (p, end, '+', &gsub_count);
768 MERROR (MERROR_FLT, -1);
772 /* Apply all GPOS features. */
777 str = otf_count_features (p, end, '\0', &gpos_count);
779 MERROR (MERROR_FLT, -1);
782 spec->script = script;
783 spec->langsys = langsys;
786 spec->features[0] = malloc (sizeof (int) * (gsub_count + 1));
787 if (! spec->features[0])
790 otf_store_features (gsub + 1, gpos, spec->features[0]);
792 spec->features[0][0] = 0xFFFFFFFF, spec->features[0][1] = 0;
796 spec->features[1] = malloc (sizeof (int) * (gpos_count + 1));
797 if (! spec->features[1])
799 if (spec->features[0])
800 free (spec->features[0]);
804 otf_store_features (gpos + 1, str, spec->features[1]);
806 spec->features[1][0] = 0xFFFFFFFF, spec->features[1][1] = 0;
812 /* Parse OTF command name NAME and store the result in CMD.
814 :SCRIPT[/[LANGSYS][=[GSUB-FEATURES][+GPOS-FEATURES]]]
815 where GSUB-FEATURES and GPOS-FEATURES have this form:
816 [FEATURE[,FEATURE]*] | ' ' */
819 load_otf_command (FontLayoutCmd *cmd, MSymbol sym)
821 char *name = MSYMBOL_NAME (sym);
824 if (name[0] != ':' && name[0] != '?')
826 /* This is old format of "otf:...". Change it to ":otf=...". */
827 char *str = alloca (MSYMBOL_NAMELEN (sym) + 2);
829 sprintf (str, ":otf=");
830 strcat (str, name + 4);
834 result = parse_otf_command (sym, &cmd->body.otf);
837 cmd->type = (name[4] == '?' ? FontLayoutCmdTypeOTFCategory
838 : FontLayoutCmdTypeOTF);
843 /* Read a decimal number from STR preceded by one of "+-><". '+' and
844 '>' means a plus sign, '-' and '<' means a minus sign. If the
845 number is greater than 127, limit it to 127. */
848 read_decimal_number (char **str)
851 int sign = (*p == '-' || *p == '<') ? -1 : 1;
855 while (*p >= '0' && *p <= '9')
856 n = n * 10 + *p++ - '0';
860 return (n < 127 ? n * sign : 127 * sign);
864 /* Read a horizontal and vertical combining positions from STR, and
865 store them in the place pointed by X and Y. The horizontal
866 position left, center, and right are represented by 0, 1, and 2
867 respectively. The vertical position top, center, bottom, and base
868 are represented by 0, 1, 2, and 3 respectively. If successfully
869 read, return 0, else return -1. */
872 read_combining_position (char *str, int *x, int *y)
877 /* Vertical position comes first. */
878 for (i = 0; i < 4; i++)
887 /* Then comse horizontal position. */
888 for (i = 0; i < 3; i++)
898 /* Return a combining code corresponding to SYM. */
901 get_combining_command (MSymbol sym)
903 char *str = msymbol_name (sym);
904 int base_x, base_y, add_x, add_y, off_x, off_y;
907 if (read_combining_position (str, &base_x, &base_y) < 0)
918 if (c == '+' || c == '-')
920 off_y = read_decimal_number (&str) + 128;
925 if (c == '<' || c == '>')
926 off_x = read_decimal_number (&str) + 128;
930 if (read_combining_position (str, &add_x, &add_y) < 0)
933 c = MAKE_COMBINING_CODE (base_y, base_x, add_y, add_x, off_y, off_x);
934 return (COMBINING_CODE_TO_CMD_ID (c));
938 /* Load a command from PLIST into STAGE, and return that
939 identification number. If ID is not INVALID_CMD_ID, that means we
940 are loading a top level command or a macro. In that case, use ID
941 as the identification number of the command. Otherwise, generate a
942 new id number for the command. MACROS is a list of raw macros. */
945 load_command (FontLayoutStage *stage, MPlist *plist,
946 MPlist *macros, int id)
951 if (MPLIST_INTEGER_P (plist))
953 int code = MPLIST_INTEGER (plist);
956 MERROR (MERROR_DRAW, INVALID_CMD_ID);
959 else if (MPLIST_PLIST_P (plist))
961 /* PLIST ::= ( cond ... ) | ( STRING ... ) | ( INTEGER ... )
962 | ( ( INTEGER INTEGER ) ... )
963 | ( ( range INTEGER INTEGER ) ... )
964 | ( ( SYMBOL STRING ) ... )
965 | ( ( font-facilty [ INTEGER ] ) ... )
966 | ( ( font-facilty OTF-SPEC ) ... ) */
967 MPlist *elt = MPLIST_PLIST (plist);
968 int len = MPLIST_LENGTH (elt) - 1;
971 if (id == INVALID_CMD_ID)
974 id = INDEX_TO_CMD_ID (stage->used);
975 MLIST_APPEND1 (stage, cmds, dummy, MERROR_DRAW);
977 cmd = stage->cmds + CMD_ID_TO_INDEX (id);
979 if (MPLIST_SYMBOL_P (elt))
981 FontLayoutCmdCond *cond;
983 if (MPLIST_SYMBOL (elt) != Mcond)
984 MERROR (MERROR_DRAW, INVALID_CMD_ID);
985 elt = MPLIST_NEXT (elt);
986 cmd->type = FontLayoutCmdTypeCond;
987 cond = &cmd->body.cond;
988 cond->seq_beg = cond->seq_end = -1;
989 cond->seq_from = cond->seq_to = 0;
991 MTABLE_CALLOC (cond->cmd_ids, len, MERROR_DRAW);
992 for (i = 0; i < len; i++, elt = MPLIST_NEXT (elt))
994 int this_id = load_command (stage, elt, macros, INVALID_CMD_ID);
996 if (this_id == INVALID_CMD_ID || this_id == -2)
997 MERROR (MERROR_DRAW, this_id);
998 /* The above load_command may relocate stage->cmds. */
999 cmd = stage->cmds + CMD_ID_TO_INDEX (id);
1000 cond = &cmd->body.cond;
1001 cond->cmd_ids[i] = this_id;
1002 if (this_id <= CMD_ID_OFFSET_INDEX)
1004 FontLayoutCmd *this_cmd
1005 = stage->cmds + CMD_ID_TO_INDEX (this_id);
1007 if (this_cmd->type == FontLayoutCmdTypeRule
1008 && this_cmd->body.rule.src_type == SRC_SEQ)
1010 int first_char = this_cmd->body.rule.src.seq.codes[0];
1012 if (cond->seq_beg < 0)
1014 /* The first SEQ command. */
1016 cond->seq_from = cond->seq_to = first_char;
1018 else if (cond->seq_end < 0)
1020 /* The following SEQ command. */
1021 if (cond->seq_from > first_char)
1022 cond->seq_from = first_char;
1023 else if (cond->seq_to < first_char)
1024 cond->seq_to = first_char;
1029 if (cond->seq_beg >= 0 && cond->seq_end < 0)
1030 /* The previous one is the last SEQ command. */
1036 if (cond->seq_beg >= 0 && cond->seq_end < 0)
1037 /* The previous one is the last SEQ command. */
1041 if (cond->seq_beg >= 0 && cond->seq_end < 0)
1042 /* The previous one is the last SEQ command. */
1047 cmd->type = FontLayoutCmdTypeRule;
1048 if (MPLIST_MTEXT_P (elt))
1050 MText *mt = MPLIST_MTEXT (elt);
1051 char *str = (char *) MTEXT_DATA (mt);
1055 mtext_ins_char (mt, 0, '^', 1);
1056 str = (char *) MTEXT_DATA (mt);
1058 if (regcomp (&cmd->body.rule.src.re.preg, str, REG_EXTENDED))
1059 MERROR (MERROR_FONT, INVALID_CMD_ID);
1060 cmd->body.rule.src_type = SRC_REGEX;
1061 cmd->body.rule.src.re.pattern = strdup (str);
1063 else if (MPLIST_INTEGER_P (elt))
1065 cmd->body.rule.src_type = SRC_INDEX;
1066 cmd->body.rule.src.match_idx = MPLIST_INTEGER (elt);
1068 else if (MPLIST_PLIST_P (elt))
1070 MPlist *pl = MPLIST_PLIST (elt), *p;
1071 int size = MPLIST_LENGTH (pl);
1073 if (MPLIST_INTEGER_P (pl))
1077 cmd->body.rule.src_type = SRC_SEQ;
1078 cmd->body.rule.src.seq.n_codes = size;
1079 MTABLE_CALLOC (cmd->body.rule.src.seq.codes, size,
1081 for (i = 0; i < size; i++, pl = MPLIST_NEXT (pl))
1083 if (! MPLIST_INTEGER_P (pl))
1084 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1085 cmd->body.rule.src.seq.codes[i]
1086 = (unsigned) MPLIST_INTEGER (pl);
1089 else if (MPLIST_SYMBOL_P (pl))
1091 if (MPLIST_SYMBOL (pl) == Mrange)
1094 MERROR (MERROR_FLT, INVALID_CMD_ID);
1095 cmd->body.rule.src_type = SRC_RANGE;
1096 pl = MPLIST_NEXT (pl);
1097 if (! MPLIST_INTEGER_P (pl))
1098 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1099 cmd->body.rule.src.range.from
1100 = (unsigned) MPLIST_INTEGER (pl);
1101 pl = MPLIST_NEXT (pl);
1102 if (! MPLIST_INTEGER_P (pl))
1103 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1104 cmd->body.rule.src.range.to
1105 = (unsigned) MPLIST_INTEGER (pl);
1107 else if (MPLIST_SYMBOL (pl) == Mfont_facility)
1109 FontLayoutCmdRule *rule = &cmd->body.rule;
1111 pl = MPLIST_NEXT (pl);
1112 if (MPLIST_SYMBOL_P (pl))
1114 MSymbol sym = MPLIST_SYMBOL (pl);
1115 char *otf_spec = MSYMBOL_NAME (sym);
1117 if (otf_spec[0] == ':' && otf_spec[1] == 'o'
1118 && otf_spec[2] == 't' && otf_spec[3] == 'f')
1119 parse_otf_command (sym, &rule->src.facility.otf_spec);
1121 MERROR (MERROR_FLT, INVALID_CMD_ID);
1122 rule->src_type = SRC_OTF_SPEC;
1123 pl = MPLIST_NEXT (pl);
1125 else if (MPLIST_TAIL_P (pl))
1126 MERROR (MERROR_FLT, INVALID_CMD_ID);
1128 rule->src_type = SRC_HAS_GLYPH;
1129 rule->src.facility.len = 0;
1132 if (! MPLIST_INTEGER_P (p)
1133 && (MPLIST_SYMBOL_P (p)
1134 ? MPLIST_SYMBOL (p) != Mequal
1136 MERROR (MERROR_FLT, INVALID_CMD_ID);
1137 rule->src.facility.len++;
1139 rule->src.facility.codes = pl;
1140 M17N_OBJECT_REF (pl);
1144 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1147 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1149 elt = MPLIST_NEXT (elt);
1150 cmd->body.rule.n_cmds = len;
1151 MTABLE_CALLOC (cmd->body.rule.cmd_ids, len, MERROR_DRAW);
1152 for (i = 0; i < len; i++, elt = MPLIST_NEXT (elt))
1154 int this_id = load_command (stage, elt, macros, INVALID_CMD_ID);
1156 if (this_id == INVALID_CMD_ID || this_id == -2)
1157 MERROR (MERROR_DRAW, this_id);
1158 /* The above load_command may relocate stage->cmds. */
1159 cmd = stage->cmds + CMD_ID_TO_INDEX (id);
1160 cmd->body.rule.cmd_ids[i] = this_id;
1164 else if (MPLIST_SYMBOL_P (plist))
1167 MSymbol sym = MPLIST_SYMBOL (plist);
1168 char *name = msymbol_name (sym);
1169 int len = strlen (name);
1173 && ((name[0] == 'o' && name[1] == 't'
1174 && name[2] == 'f' && name[3] == ':')
1175 || (name[0] == ':' && name[1] == 'o' && name[2] == 't'
1176 && name[3] == 'f' && (name[4] == '=' || name[4] == '?'))))
1178 result = load_otf_command (&cmd, sym);
1181 if (id == INVALID_CMD_ID)
1183 id = INDEX_TO_CMD_ID (stage->used);
1184 MLIST_APPEND1 (stage, cmds, cmd, MERROR_DRAW);
1187 stage->cmds[CMD_ID_TO_INDEX (id)] = cmd;
1195 else if (*name == '*')
1196 return CMD_ID_REPEAT;
1197 else if (*name == '<')
1198 return CMD_ID_CLUSTER_BEGIN;
1199 else if (*name == '>')
1200 return CMD_ID_CLUSTER_END;
1201 else if (*name == '|')
1202 return CMD_ID_SEPARATOR;
1203 else if (*name == '[')
1204 return CMD_ID_LEFT_PADDING;
1205 else if (*name == ']')
1206 return CMD_ID_RIGHT_PADDING;
1212 id = get_combining_command (sym);
1218 MPLIST_DO (elt, macros)
1220 if (sym == MPLIST_SYMBOL (MPLIST_PLIST (elt)))
1222 id = INDEX_TO_CMD_ID (i);
1223 if (stage->cmds[i].type == FontLayoutCmdTypeMAX)
1224 id = load_command (stage, MPLIST_NEXT (MPLIST_PLIST (elt)),
1230 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1233 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1239 free_flt_command (FontLayoutCmd *cmd)
1241 if (cmd->type == FontLayoutCmdTypeRule)
1243 FontLayoutCmdRule *rule = &cmd->body.rule;
1245 if (rule->src_type == SRC_REGEX)
1247 free (rule->src.re.pattern);
1248 regfree (&rule->src.re.preg);
1250 else if (rule->src_type == SRC_SEQ)
1251 free (rule->src.seq.codes);
1252 free (rule->cmd_ids);
1254 else if (cmd->type == FontLayoutCmdTypeCond)
1255 free (cmd->body.cond.cmd_ids);
1256 else if (cmd->type == FontLayoutCmdTypeOTF
1257 || cmd->type == FontLayoutCmdTypeOTFCategory)
1259 if (cmd->body.otf.features[0])
1260 free (cmd->body.otf.features[0]);
1261 if (cmd->body.otf.features[1])
1262 free (cmd->body.otf.features[1]);
1266 /* Load a generator from PLIST into a newly allocated FontLayoutStage,
1267 and return it. PLIST has this form:
1268 PLIST ::= ( COMMAND ( CMD-NAME COMMAND ) * )
1271 static FontLayoutStage *
1272 load_generator (MPlist *plist)
1274 FontLayoutStage *stage;
1276 FontLayoutCmd dummy;
1279 MSTRUCT_CALLOC (stage, MERROR_DRAW);
1280 MLIST_INIT1 (stage, cmds, 32);
1281 dummy.type = FontLayoutCmdTypeMAX;
1282 MLIST_APPEND1 (stage, cmds, dummy, MERROR_FONT);
1283 MPLIST_DO (elt, MPLIST_NEXT (plist))
1285 if (! MPLIST_PLIST_P (elt))
1286 MERROR (MERROR_FONT, NULL);
1287 pl = MPLIST_PLIST (elt);
1288 if (! MPLIST_SYMBOL_P (pl))
1289 MERROR (MERROR_FONT, NULL);
1290 MLIST_APPEND1 (stage, cmds, dummy, MERROR_FONT);
1293 /* Load the first command from PLIST into STAGE->cmds[0]. Macros
1294 called in the first command are also loaded from MPLIST_NEXT
1295 (PLIST) into STAGE->cmds[n]. */
1296 result = load_command (stage, plist, MPLIST_NEXT (plist),
1297 INDEX_TO_CMD_ID (0));
1298 if (result == INVALID_CMD_ID || result == -2)
1300 MLIST_FREE1 (stage, cmds);
1309 /* Load stages of the font layout table FLT. */
1312 load_flt (MFLT *flt, MPlist *key_list)
1314 MPlist *top, *plist, *pl, *p;
1315 FontLayoutCategory *category = NULL;
1319 top = (MPlist *) mdatabase__load_for_keys (flt->mdb, key_list);
1321 top = (MPlist *) mdatabase_load (flt->mdb);
1324 if (! MPLIST_PLIST_P (top))
1326 M17N_OBJECT_UNREF (top);
1327 MERROR (MERROR_FLT, -1);
1332 plist = mdatabase__props (flt->mdb);
1334 MERROR (MERROR_FLT, -1);
1335 MPLIST_DO (plist, plist)
1336 if (MPLIST_PLIST_P (plist))
1338 pl = MPLIST_PLIST (plist);
1339 if (! MPLIST_SYMBOL_P (pl)
1340 || MPLIST_SYMBOL (pl) != Mfont)
1342 pl = MPLIST_NEXT (pl);
1343 if (! MPLIST_PLIST_P (pl))
1345 p = MPLIST_PLIST (pl);
1346 if (! MPLIST_SYMBOL_P (p))
1348 p = MPLIST_NEXT (p);
1349 if (! MPLIST_SYMBOL_P (p))
1351 flt->family = MPLIST_SYMBOL (p);
1352 MPLIST_DO (p, MPLIST_NEXT (p))
1353 if (MPLIST_SYMBOL_P (p))
1355 sym = MPLIST_SYMBOL (p);
1356 if (MSYMBOL_NAME (sym)[0] != ':')
1357 flt->registry = sym, sym = Mnil;
1363 char *otf_spec = MSYMBOL_NAME (sym);
1365 if (otf_spec[0] == ':' && otf_spec[1] == 'o'
1366 && otf_spec[2] == 't' && otf_spec[3] == 'f')
1367 parse_otf_command (sym, &flt->otf);
1372 MPLIST_DO (plist, top)
1374 if (MPLIST_SYMBOL_P (plist)
1375 && MPLIST_SYMBOL (plist) == Mend)
1377 mplist_set (plist, Mnil, NULL);
1380 if (! MPLIST_PLIST (plist))
1382 pl = MPLIST_PLIST (plist);
1383 if (! MPLIST_SYMBOL_P (pl))
1385 sym = MPLIST_SYMBOL (pl);
1386 pl = MPLIST_NEXT (pl);
1389 if (sym == Mcategory)
1392 unref_category_table (category);
1393 else if (flt->coverage)
1395 category = flt->coverage;
1396 ref_category_table (category);
1399 category = load_category_table (pl, NULL);
1400 if (! flt->coverage)
1402 flt->coverage = category;
1403 ref_category_table (category);
1405 if (category->definition)
1406 flt->need_config = 1;
1408 else if (sym == Mgenerator)
1410 FontLayoutStage *stage;
1414 stage = load_generator (pl);
1417 stage->category = category;
1418 M17N_OBJECT_REF (category->table);
1420 flt->stages = mplist ();
1421 mplist_add (flt->stages, Mt, stage);
1425 unref_category_table (category);
1427 if (! MPLIST_TAIL_P (plist))
1429 M17N_OBJECT_UNREF (top);
1430 M17N_OBJECT_UNREF (flt->stages);
1431 MERROR (MERROR_FLT, -1);
1433 M17N_OBJECT_UNREF (top);
1439 free_flt_stage (MFLT *flt, FontLayoutStage *stage)
1443 unref_category_table (stage->category);
1446 for (i = 0; i < stage->used; i++)
1447 free_flt_command (stage->cmds + i);
1448 MLIST_FREE1 (stage, cmds);
1460 MPLIST_DO (plist, flt_list)
1462 MFLT *flt = MPLIST_VAL (plist);
1465 unref_category_table (flt->coverage);
1468 MPLIST_DO (pl, MPLIST_NEXT (flt->stages))
1469 free_flt_stage (flt, MPLIST_VAL (pl));
1470 M17N_OBJECT_UNREF (flt->stages);
1473 MPLIST_VAL (plist) = NULL;
1475 M17N_OBJECT_UNREF (flt_list);
1482 MPlist *plist, *key_list = NULL;
1486 if (! (plist = mdatabase_list (Mfont, Mlayouter, Mnil, Mnil)))
1488 if (! (flt_list = mplist ()))
1490 if (! (key_list = mplist ()))
1492 if (! mplist_add (key_list, Mcategory, Mt))
1495 MPLIST_DO (pl, plist)
1497 MDatabase *mdb = MPLIST_VAL (pl);
1498 MSymbol *tags = mdatabase_tag (mdb);
1501 if (! MSTRUCT_CALLOC_SAFE (flt))
1503 flt->name = tags[2];
1505 if (load_flt (flt, key_list) < 0)
1509 if (MPLIST_TAIL_P (flt_list))
1511 flt_min_coverage = mchartable_min_char (flt->coverage->table);
1512 flt_max_coverage = mchartable_max_char (flt->coverage->table);
1518 c = mchartable_min_char (flt->coverage->table);
1519 if (flt_min_coverage > c)
1520 flt_min_coverage = c;
1521 c = mchartable_max_char (flt->coverage->table);
1522 if (flt_max_coverage < c)
1523 flt_max_coverage = c;
1525 if (! mplist_push (flt_list, flt->name, flt))
1535 M17N_OBJECT_UNREF (plist);
1536 M17N_OBJECT_UNREF (key_list);
1540 /* FLS (Font Layout Service) */
1542 /* Structure to hold information about a context of FLS. */
1546 /* Pointer to the current stage. */
1547 FontLayoutStage *stage;
1549 /* Pointer to the category table of the next stage or NULL if none. */
1550 FontLayoutCategory *category;
1552 /* Pointer to the font. */
1555 /* Input and output glyph string. */
1556 MFLTGlyphString *in, *out;
1558 /* Encode each character or code of a glyph by the current category
1559 table into this array. An element is a category letter used for
1560 a regular expression matching. */
1565 int cluster_begin_idx;
1566 int cluster_begin_pos;
1567 int cluster_end_pos;
1571 } FontLayoutContext;
1573 static int run_command (int, int, int, int, FontLayoutContext *);
1574 static int run_otf (int, MFLTOtfSpec *, int, int, FontLayoutContext *);
1575 static int run_otf_category (int, MFLTOtfSpec *, int, int, FontLayoutContext *);
1580 run_rule (int depth,
1581 FontLayoutCmdRule *rule, int from, int to, FontLayoutContext *ctx)
1583 int *saved_match_indices = ctx->match_indices;
1584 int match_indices[NMATCH * 2];
1587 int orig_from = from;
1588 int need_cluster_update = 0;
1590 if (rule->src_type == SRC_REGEX)
1592 regmatch_t pmatch[NMATCH];
1598 saved_code = ctx->encoded[to - ctx->encoded_offset];
1599 ctx->encoded[to - ctx->encoded_offset] = '\0';
1600 result = regexec (&(rule->src.re.preg),
1601 ctx->encoded + (from - ctx->encoded_offset),
1603 if (result == 0 && pmatch[0].rm_so == 0)
1605 if (MDEBUG_FLAG () > 2)
1606 MDEBUG_PRINT5 ("\n [FLT] %*s(REGEX \"%s\" \"%s\" %d", depth, "",
1607 rule->src.re.pattern,
1608 ctx->encoded + (from - ctx->encoded_offset),
1610 ctx->encoded[to - ctx->encoded_offset] = saved_code;
1611 for (i = 0; i < NMATCH; i++)
1613 if (pmatch[i].rm_so < 0)
1614 match_indices[i * 2] = match_indices[i * 2 + 1] = -1;
1617 match_indices[i * 2] = from + pmatch[i].rm_so;
1618 match_indices[i * 2 + 1] = from + pmatch[i].rm_eo;
1621 ctx->match_indices = match_indices;
1622 to = match_indices[1];
1626 ctx->encoded[to - ctx->encoded_offset] = saved_code;
1629 need_cluster_update = 1;
1631 else if (rule->src_type == SRC_SEQ)
1635 len = rule->src.seq.n_codes;
1636 if (len > (to - from))
1638 for (i = 0; i < len; i++)
1639 if (rule->src.seq.codes[i] != GREF (ctx->in, from + i)->c)
1644 if (MDEBUG_FLAG () > 2)
1645 MDEBUG_PRINT3 ("\n [FLT] %*s(SEQ 0x%X", depth, "",
1646 rule->src.seq.codes[0]);
1647 need_cluster_update = 1;
1649 else if (rule->src_type == SRC_RANGE)
1655 head = GREF (ctx->in, from)->c;
1656 if (head < rule->src.range.from || head > rule->src.range.to)
1658 ctx->code_offset = head - rule->src.range.from;
1660 if (MDEBUG_FLAG () > 2)
1661 MDEBUG_PRINT4 ("\n [FLT] %*s(RANGE 0x%X-0x%X", depth, "",
1662 rule->src.range.from, rule->src.range.to);
1663 need_cluster_update = 1;
1665 else if (rule->src_type == SRC_INDEX)
1667 if (rule->src.match_idx >= NMATCH)
1669 from = ctx->match_indices[rule->src.match_idx * 2];
1672 to = ctx->match_indices[rule->src.match_idx * 2 + 1];
1673 if (MDEBUG_FLAG () > 2)
1674 MDEBUG_PRINT3 ("\n [FLT] %*s(SUBPART %d", depth, "",
1675 rule->src.match_idx);
1676 need_cluster_update = 1;
1678 else if (rule->src_type == SRC_HAS_GLYPH
1679 || rule->src_type == SRC_OTF_SPEC)
1681 static MFLTGlyphString gstring;
1685 if (rule->src.facility.len > 0)
1687 if (! gstring.glyph_size)
1689 gstring.glyph_size = ctx->in->glyph_size;
1690 gstring.glyphs = calloc (rule->src.facility.len,
1691 gstring.glyph_size);
1692 gstring.allocated = rule->src.facility.len;
1693 gstring.used = rule->src.facility.len;
1695 else if (rule->src.facility.len < gstring.allocated)
1697 gstring.glyphs = realloc (gstring.glyphs,
1699 * rule->src.facility.len);
1700 gstring.allocated = rule->src.facility.len;
1701 gstring.used = rule->src.facility.len;
1704 for (i = 0, p = rule->src.facility.codes, idx = from;
1705 i < rule->src.facility.len; i++, p = MPLIST_NEXT (p))
1707 if (MPLIST_INTEGER_P (p))
1709 GREF (&gstring, i)->code = MPLIST_INTEGER (p);
1710 GREF (&gstring, i)->encoded = 0;
1714 GREF (&gstring, i)->code = GREF (ctx->in, idx)->code;
1715 GREF (&gstring, i)->encoded = GREF (ctx->in, idx)->encoded;
1721 if (MDEBUG_FLAG () > 2)
1723 if (rule->src_type == SRC_HAS_GLYPH)
1724 MDEBUG_PRINT2 ("\n [FLT] %*s(HAS-GLYPH", depth, "");
1726 MDEBUG_PRINT2 ("\n [FLT] %*s(OTF-SPEC", depth, "");
1727 for (i = 0; i < rule->src.facility.len; i++)
1728 MDEBUG_PRINT1 (" %04X", GREF (&gstring, i)->code);
1730 if (ctx->font->get_glyph_id (ctx->font, &gstring, 0,
1731 rule->src.facility.len) < 0)
1733 MDEBUG_PRINT (") FAIL!");
1736 if (rule->src_type == SRC_OTF_SPEC)
1738 MFLTOtfSpec *spec = &rule->src.facility.otf_spec;
1740 if (! ctx->font->check_otf)
1742 if ((spec->features[0] && spec->features[0][0] != 0xFFFFFFFF)
1743 || (spec->features[1] && spec->features[1][0] != 0xFFFFFFFF))
1748 if (rule->src.facility.len == 0)
1750 if (! ctx->font->check_otf (ctx->font, spec))
1755 int prev_out_used = ctx->out->used, out_used;
1756 MFLTGlyphAdjustment *adjustment;
1758 adjustment = alloca ((sizeof *adjustment)
1759 * (ctx->out->allocated - ctx->out->used));
1761 MERROR (MERROR_FLT, -1);
1762 memset (adjustment, 0,
1763 (sizeof *adjustment)
1764 * (ctx->out->allocated - ctx->out->used));
1765 ctx->font->drive_otf (ctx->font, &rule->src.facility.otf_spec,
1766 &gstring, 0, rule->src.facility.len,
1769 out_used = ctx->out->used;
1770 ctx->out->used = prev_out_used;
1771 if (rule->src.facility.len == out_used - prev_out_used)
1773 for (i = prev_out_used; i < out_used; i++)
1775 if (GREF (&gstring, i - prev_out_used)->code
1776 != GREF (ctx->out, i)->code)
1778 if (adjustment[i - prev_out_used].set)
1789 if (need_cluster_update && ctx->cluster_begin_idx >= 0)
1791 for (i = from; i < to; i++)
1793 MFLTGlyph *g = GREF (ctx->in, i);
1794 UPDATE_CLUSTER_RANGE (ctx, g);
1800 for (i = 0; i < rule->n_cmds; i++)
1804 if (rule->cmd_ids[i] == CMD_ID_REPEAT)
1810 pos = run_command (depth, rule->cmd_ids[i], from, to, ctx);
1813 consumed = pos > from;
1818 ctx->match_indices = saved_match_indices;
1819 if (MDEBUG_FLAG () > 2)
1821 return (rule->src_type == SRC_INDEX ? orig_from : to);
1825 run_cond (int depth,
1826 FontLayoutCmdCond *cond, int from, int to, FontLayoutContext *ctx)
1830 if (MDEBUG_FLAG () > 2)
1831 MDEBUG_PRINT2 ("\n [FLT] %*s(COND", depth, "");
1833 for (i = 0; i < cond->n_cmds; i++)
1835 /* TODO: Write a code for optimization utilizaing the info
1837 if ((pos = run_command (depth, cond->cmd_ids[i], from, to, ctx))
1843 if (MDEBUG_FLAG () > 2)
1849 decode_packed_otf_tag (FontLayoutContext *ctx, MFLTGlyphString *gstring,
1850 int from, int to, FontLayoutCategory *category)
1852 for (; from < to; from++)
1854 MFLTGlyph *g = GREF (gstring, from);
1855 unsigned int tag = g->internal & 0xFFFFFFF;
1860 SET_CATEGORY_CODE (g, 0);
1863 if (tag & 0xFFFFF80)
1867 /* Clear the feature tag code. */
1868 g->internal &= ~0xFFFFFFF;
1869 for (i = 0, enc = '\0'; i < category->feature_table.size; i++)
1870 if (category->feature_table.tag[i] == tag)
1872 enc = category->feature_table.code[i];
1873 if (ctx->in == gstring)
1874 ctx->encoded[from - ctx->encoded_offset] = enc;
1881 enc = g->c > 0 ? (int) mchartable_lookup (category->table, g->c) : 1;
1882 SET_CATEGORY_CODE (g, enc);
1888 MFLTOtfSpec *otf_spec, int from, int to, FontLayoutContext *ctx)
1890 MFLTFont *font = ctx->font;
1891 int from_idx = ctx->out->used;
1893 if (MDEBUG_FLAG () > 2)
1894 MDEBUG_PRINT3 ("\n [FLT] %*s%s", depth, "", MSYMBOL_NAME (otf_spec->sym));
1896 font->get_glyph_id (font, ctx->in, from, to);
1897 if (! font->drive_otf)
1899 if (ctx->out->used + (to - from) > ctx->out->allocated)
1901 font->get_metrics (font, ctx->in, from, to);
1902 GCPY (ctx->in, from, to - from, ctx->out, ctx->out->used);
1903 ctx->out->used += to - from;
1907 MFLTGlyphAdjustment *adjustment;
1911 adjustment = alloca ((sizeof *adjustment)
1912 * (ctx->out->allocated - ctx->out->used));
1914 MERROR (MERROR_FLT, -1);
1915 memset (adjustment, 0,
1916 (sizeof *adjustment) * (ctx->out->allocated - ctx->out->used));
1917 to = font->drive_otf (font, otf_spec, ctx->in, from, to, ctx->out,
1921 decode_packed_otf_tag (ctx, ctx->out, from_idx, ctx->out->used,
1923 out_len = ctx->out->used - from_idx;
1924 if (otf_spec->features[1])
1926 MFLTGlyphAdjustment *a;
1929 for (i = 0, a = adjustment; i < out_len; i++, a++)
1934 font->get_metrics (font, ctx->out, from_idx, ctx->out->used);
1935 for (g = GREF (ctx->out, from_idx + i);
1936 i < out_len; i++, a++, g = NEXT (ctx->out, g))
1939 if (a->advance_is_absolute)
1944 else if (a->xadv || a->yadv)
1949 if (a->xoff || a->yoff || a->back)
1952 MFLTGlyph *gg = PREV (ctx->out, g);
1953 MFLTGlyphAdjustment *aa = a;
1957 g->lbearing += a->xoff;
1958 g->rbearing += a->xoff;
1959 g->ascent -= a->yoff;
1960 g->descent -= a->yoff;
1961 while (aa->back > 0)
1963 for (j = 0; j < aa->back;
1964 j++, gg = PREV (ctx->out, gg))
1966 g->xoff -= gg->xadv;
1967 g->lbearing -= gg->xadv;
1968 g->rbearing -= gg->xadv;
1971 g->xoff += aa->xoff;
1972 g->yoff += aa->yoff;
1973 g->lbearing += aa->xoff;
1974 g->rbearing += aa->xoff;
1975 g->ascent -= aa->yoff;
1976 g->descent -= aa->yoff;
1985 if (ctx->cluster_begin_idx >= 0)
1986 for (; from_idx < ctx->out->used; from_idx++)
1988 MFLTGlyph *g = GREF (ctx->out, from_idx);
1989 UPDATE_CLUSTER_RANGE (ctx, g);
1995 run_otf_category (int depth, MFLTOtfSpec *otf_spec, int from, int to,
1996 FontLayoutContext *ctx)
1998 MFLTFont *font = ctx->font;
1999 int from_idx = ctx->out->used;
2001 if (MDEBUG_FLAG () > 2)
2002 MDEBUG_PRINT3 ("\n [FLT] %*s%s", depth, "", MSYMBOL_NAME (otf_spec->sym));
2004 if (! otf_spec->features[0] && ! otf_spec->features[1])
2006 /* Reset categories. */
2007 MCharTable *table = ctx->category->table;
2010 for (i = from; i < to; i++)
2012 MFLTGlyph *g = GREF (ctx->in, i);
2014 if (! GET_COMBINED (g))
2016 char enc = (GET_ENCODED (g)
2017 ? (g->c > 0 ? (int) mchartable_lookup (table, g->c)
2020 ? (int) mchartable_lookup (table, g->code)
2022 SET_CATEGORY_CODE (g, enc);
2023 ctx->encoded[i - ctx->encoded_offset] = enc;
2029 if (ctx->stage->category->feature_table.size == 0)
2032 font->get_glyph_id (font, ctx->in, from, to);
2033 if (font->drive_otf)
2038 to = font->drive_otf (font, otf_spec, ctx->in, from, to, NULL, NULL);
2041 decode_packed_otf_tag (ctx, ctx->in, from, to, ctx->stage->category);
2046 static char work[16];
2049 dump_combining_code (int code)
2051 char *vallign = "tcbB";
2052 char *hallign = "lcr";
2058 work[0] = vallign[COMBINING_CODE_BASE_Y (code)];
2059 work[1] = hallign[COMBINING_CODE_BASE_X (code)];
2060 off_y = COMBINING_CODE_OFF_Y (code);
2061 off_x = COMBINING_CODE_OFF_X (code);
2063 sprintf (work + 2, "+%d", off_y);
2065 sprintf (work + 2, "%d", off_y);
2066 else if (off_x == 0)
2067 sprintf (work + 2, ".");
2068 p = work + strlen (work);
2070 sprintf (p, ">%d", off_x);
2072 sprintf (p, "<%d", -off_x);
2074 p[0] = vallign[COMBINING_CODE_ADD_Y (code)];
2075 p[1] = hallign[COMBINING_CODE_ADD_X (code)];
2081 run_command (int depth, int id, int from, int to, FontLayoutContext *ctx)
2088 MCharTable *table = ctx->category ? ctx->category->table : NULL;
2091 /* Direct code (== ctx->code_offset + id) output.
2092 The source is not consumed. */
2093 if (MDEBUG_FLAG () > 2)
2094 MDEBUG_PRINT3 ("\n [FLT] %*s(DIRECT 0x%X", depth, "",
2095 ctx->code_offset + id);
2096 i = (from < to || from == 0) ? from : from - 1;
2098 g = GREF (ctx->out, ctx->out->used - 1);
2099 g->c = g->code = ctx->code_offset + id;
2100 if (ctx->combining_code)
2101 SET_COMBINING_CODE (g, ctx, ctx->combining_code);
2104 enc = (GET_ENCODED (g)
2105 ? (g->c > 0 ? (int) mchartable_lookup (table, g->c) : 1)
2107 ? (int) mchartable_lookup (table, g->code)
2109 SET_CATEGORY_CODE (g, enc);
2112 SET_MEASURED (g, 0);
2113 if (ctx->left_padding)
2114 SET_LEFT_PADDING (g, ctx, LeftPaddingMask);
2115 for (i = from; i < to; i++)
2117 MFLTGlyph *tmp = GREF (ctx->in, i);
2119 if (g->from > tmp->from)
2120 g->from = tmp->from;
2121 else if (g->to < tmp->to)
2124 if (ctx->cluster_begin_idx >= 0)
2125 UPDATE_CLUSTER_RANGE (ctx, g);
2126 ctx->code_offset = ctx->combining_code = ctx->left_padding = 0;
2127 if (MDEBUG_FLAG () > 2)
2132 if (id <= CMD_ID_OFFSET_INDEX)
2134 int idx = CMD_ID_TO_INDEX (id);
2137 if (idx >= ctx->stage->used)
2138 MERROR (MERROR_DRAW, -1);
2139 cmd = ctx->stage->cmds + idx;
2140 if (cmd->type == FontLayoutCmdTypeRule)
2141 to = run_rule (depth, &cmd->body.rule, from, to, ctx);
2142 else if (cmd->type == FontLayoutCmdTypeCond)
2143 to = run_cond (depth, &cmd->body.cond, from, to, ctx);
2144 else if (cmd->type == FontLayoutCmdTypeOTF)
2145 to = run_otf (depth, &cmd->body.otf, from, to, ctx);
2146 else if (cmd->type == FontLayoutCmdTypeOTFCategory)
2147 to = run_otf_category (depth, &cmd->body.otf, from, to, ctx);
2151 if (id <= CMD_ID_OFFSET_COMBINING)
2153 ctx->combining_code = CMD_ID_TO_COMBINING_CODE (id);
2154 if (MDEBUG_FLAG () > 2)
2155 MDEBUG_PRINT3 ("\n [FLT] %*s(CMB %s)", depth, "",
2156 dump_combining_code (ctx->combining_code));
2167 g = GREF (ctx->out, ctx->out->used - 1);
2168 if (ctx->combining_code)
2169 SET_COMBINING_CODE (g, ctx, ctx->combining_code);
2170 if (ctx->left_padding)
2171 SET_LEFT_PADDING (g, ctx, LeftPaddingMask);
2172 if (ctx->cluster_begin_idx >= 0)
2173 UPDATE_CLUSTER_RANGE (ctx, g);
2174 if (MDEBUG_FLAG () > 2)
2177 MDEBUG_PRINT2 ("\n [FLT] %*s(COPY |)", depth, "");
2179 MDEBUG_PRINT3 ("\n [FLT] %*s(COPY 0x%X)", depth, "", g->c);
2181 ctx->code_offset = ctx->combining_code = ctx->left_padding = 0;
2185 case CMD_ID_CLUSTER_BEGIN:
2186 if (ctx->cluster_begin_idx < 0)
2188 if (MDEBUG_FLAG () > 2)
2189 MDEBUG_PRINT3 ("\n [FLT] %*s<%d", depth, "",
2190 GREF (ctx->in, from)->from);
2191 ctx->cluster_begin_idx = ctx->out->used;
2192 ctx->cluster_begin_pos = GREF (ctx->in, from)->from;
2193 ctx->cluster_end_pos = GREF (ctx->in, from)->to;
2197 case CMD_ID_CLUSTER_END:
2198 if (ctx->cluster_begin_idx >= 0
2199 && ctx->cluster_begin_idx < ctx->out->used)
2203 if (MDEBUG_FLAG () > 2)
2204 MDEBUG_PRINT1 (" %d>", ctx->cluster_end_pos + 1);
2205 for (i = ctx->cluster_begin_idx; i < ctx->out->used; i++)
2207 GREF (ctx->out, i)->from = ctx->cluster_begin_pos;
2208 GREF (ctx->out, i)->to = ctx->cluster_end_pos;
2210 ctx->cluster_begin_idx = -1;
2214 case CMD_ID_SEPARATOR:
2218 i = from < to ? from : from - 1;
2220 g = GREF (ctx->out, ctx->out->used - 1);
2221 g->c = -1, g->code = 0;
2222 g->xadv = g->yadv = 0;
2224 SET_MEASURED (g, 0);
2225 SET_CATEGORY_CODE (g, ' ');
2229 case CMD_ID_LEFT_PADDING:
2230 if (MDEBUG_FLAG () > 2)
2231 MDEBUG_PRINT2 ("\n [FLT] %*s[", depth, "");
2232 ctx->left_padding = 1;
2235 case CMD_ID_RIGHT_PADDING:
2236 if (ctx->out->used > 0)
2238 if (MDEBUG_FLAG () > 2)
2239 MDEBUG_PRINT2 ("\n [FLT] %*s]", depth, "");
2240 g = GREF (ctx->out, ctx->out->used - 1);
2241 SET_RIGHT_PADDING (g, ctx, RightPaddingMask);
2246 MERROR (MERROR_DRAW, -1);
2250 run_stages (MFLTGlyphString *gstring, int from, int to,
2251 MFLT *flt, FontLayoutContext *ctx)
2253 MFLTGlyphString buf, *temp;
2255 int orig_from = from, orig_to = to;
2256 int from_pos, to_pos, len;
2259 MPlist *stages = flt->stages;
2260 FontLayoutCategory *prev_category = NULL;
2262 from_pos = GREF (ctx->in, from)->from;
2263 to_pos = GREF (ctx->in, to - 1)->to;
2264 len = to_pos - from_pos;
2268 GINIT (ctx->out, ctx->out->allocated);
2269 ctx->encoded = alloca (ctx->out->allocated);
2270 if (! ctx->out->glyphs || ! ctx->encoded)
2273 for (stage_idx = 0; 1; stage_idx++)
2278 ctx->stage = (FontLayoutStage *) MPLIST_VAL (stages);
2279 table = ctx->stage->category->table;
2280 stages = MPLIST_NEXT (stages);
2281 if (MPLIST_TAIL_P (stages))
2282 ctx->category = NULL;
2284 ctx->category = ((FontLayoutStage *) MPLIST_VAL (stages))->category;
2285 ctx->code_offset = ctx->combining_code = ctx->left_padding = 0;
2286 ctx->encoded_offset = from;
2287 for (i = from; i < to; i++)
2289 MFLTGlyph *g = GREF (ctx->in, i);
2292 if (GET_COMBINED (g)
2293 || (prev_category && prev_category != ctx->stage->category))
2294 enc = (GET_ENCODED (g)
2295 ? (g->c > 0 ? (int) mchartable_lookup (table, g->c) : 1)
2297 ? (int) mchartable_lookup (table, g->code)
2300 enc = GET_CATEGORY_CODE (g);
2301 ctx->encoded[i - from] = enc;
2302 if (! enc && stage_idx == 0)
2308 ctx->encoded[i - from] = '\0';
2309 ctx->match_indices[0] = from;
2310 ctx->match_indices[1] = to;
2311 for (i = 2; i < NMATCH; i++)
2312 ctx->match_indices[i] = -1;
2314 if (MDEBUG_FLAG () > 2)
2316 MDEBUG_PRINT2 ("\n [FLT] (STAGE %d \"%s\"", stage_idx,
2318 MDEBUG_PRINT (" (");
2319 for (i = from; i < to; i++)
2321 g = GREF (ctx->in, i);
2323 MDEBUG_PRINT2 ("%*s|", (i > 0), "");
2325 MDEBUG_PRINT3 ("%*s%04X", (i > 0), "", GREF (ctx->in, i)->code);
2329 result = run_command (4, INDEX_TO_CMD_ID (0), from, to, ctx);
2330 if (MDEBUG_FLAG () > 2)
2335 /* If this is the last stage, break the loop. */
2336 if (MPLIST_TAIL_P (stages))
2339 /* Otherwise, prepare for the next stage. */
2340 prev_category = ctx->stage->category;
2347 GINIT (&buf, ctx->out->allocated);
2356 if (ctx->out->used > 0)
2359 int x_ppem = ctx->font->x_ppem << 6, y_ppem = ctx->font->y_ppem << 6;
2361 /* Remove separator glyphs. */
2362 for (i = 0; i < ctx->out->used;)
2364 g = GREF (ctx->out, i);
2366 GREPLACE (NULL, 0, 0, ctx->out, i, i + 1);
2371 /* Get actual glyph IDs of glyphs. */
2372 ctx->font->get_glyph_id (ctx->font, ctx->out, 0, ctx->out->used);
2374 /* Check if all characters in the range are covered by some
2375 glyph(s). If not, change <from> and <to> of glyphs to cover
2376 uncovered characters. */
2377 g_indices = alloca (sizeof (int) * len);
2380 for (i = 0; i < len; i++) g_indices[i] = -1;
2381 for (i = 0; i < ctx->out->used; i++)
2385 g = GREF (ctx->out, i);
2386 for (pos = g->from; pos <= g->to; pos++)
2387 if (g_indices[pos - from_pos] < 0)
2388 g_indices[pos - from_pos] = i;
2390 for (i = 0; i < len; i++)
2391 if (g_indices[i] < 0)
2397 for (i++; i < len && g_indices[i] < 0; i++);
2399 g = GREF (ctx->out, j);
2400 this_from = g->from;
2402 g->from = orig_from + i;
2403 } while (++j < ctx->out->used
2404 && (g = GREF (ctx->out, j))
2405 && g->from == this_from);
2411 j = g_indices[i - 1];
2412 g = GREF (ctx->out, j);
2415 g->to = orig_from + i + 1;
2417 && (g = GREF (ctx->out, j))
2418 && g->to == this_to);
2422 ctx->font->get_metrics (ctx->font, ctx->out, 0, ctx->out->used);
2424 /* Handle combining. */
2425 if (ctx->check_mask & CombinedMask)
2427 MFLTGlyph *base = GREF (ctx->out, 0);
2428 int base_height = base->ascent + base->descent;
2429 int base_width = base->rbearing - base->lbearing;
2432 for (i = 1; i < ctx->out->used; i++)
2434 if ((g = GREF (ctx->out, i))
2436 && (combining_code = GET_COMBINING_CODE (g)))
2438 int height = g->ascent + g->descent;
2439 int width = g->rbearing - g->lbearing;
2440 int base_x, base_y, add_x, add_y, off_x, off_y;
2442 if (base->from > g->from)
2443 base->from = g->from;
2444 else if (base->to < g->to)
2447 base_x = COMBINING_CODE_BASE_X (combining_code);
2448 base_y = COMBINING_CODE_BASE_Y (combining_code);
2449 add_x = COMBINING_CODE_ADD_X (combining_code);
2450 add_y = COMBINING_CODE_ADD_Y (combining_code);
2451 off_x = COMBINING_CODE_OFF_X (combining_code);
2452 off_y = COMBINING_CODE_OFF_Y (combining_code);
2454 g->xoff = ((base_width * base_x - width * add_x) / 2
2455 + x_ppem * off_x / 100
2456 - (base->xadv - base->lbearing) - g->lbearing);
2458 g->yoff = base_height * base_y / 2 - base->ascent;
2462 g->yoff -= height * add_y / 2 - g->ascent;
2463 g->yoff -= y_ppem * off_y / 100;
2464 if (base->lbearing > base->xadv + g->lbearing + g->xoff)
2465 base->lbearing = base->xadv + g->lbearing + g->xoff;
2466 if (base->rbearing < base->xadv + g->rbearing + g->xoff)
2467 base->rbearing = base->xadv + g->rbearing + g->xoff;
2468 if (base->ascent < g->ascent - g->yoff)
2469 base->ascent = g->ascent - g->yoff;
2470 if (base->descent < g->descent - g->yoff)
2471 base->descent = g->descent - g->yoff;
2472 g->xadv = g->yadv = 0;
2473 if (GET_RIGHT_PADDING (g))
2474 SET_RIGHT_PADDING (base, ctx, RightPaddingMask);
2480 base_height = g->ascent + g->descent;
2481 base_width = g->rbearing - g->lbearing;
2486 /* Handle padding */
2487 if (ctx->check_mask & (LeftPaddingMask | RightPaddingMask))
2488 for (i = 0; i < ctx->out->used; i++)
2490 g = GREF (ctx->out, i);
2491 if (! GET_COMBINED (g))
2493 if (GET_RIGHT_PADDING (g) && g->rbearing > g->xadv)
2495 g->xadv = g->rbearing;
2498 if (GET_LEFT_PADDING (g) && g->lbearing < 0)
2500 g->xoff += - g->lbearing;
2501 g->xadv += - g->lbearing;
2502 g->rbearing += - g->lbearing;
2510 GREPLACE (ctx->out, 0, ctx->out->used, gstring, orig_from, orig_to);
2511 to = orig_from + ctx->out->used;
2516 setup_combining_coverage (int from, int to, void *val, void *arg)
2518 int combining_class = (int) val;
2521 if (combining_class < 200)
2523 else if (combining_class <= 204)
2525 if ((combining_class % 2) == 0)
2526 category = "bcd"[(combining_class - 200) / 2];
2528 else if (combining_class <= 232)
2530 if ((combining_class % 2) == 0)
2531 category = "efghijklmnopq"[(combining_class - 208) / 2];
2533 else if (combining_class == 233)
2535 else if (combining_class == 234)
2537 else if (combining_class == 240)
2539 mchartable_set_range ((MCharTable *) arg, from, to, (void *) category);
2543 setup_combining_flt (MFLT *flt)
2546 MCharTable *combininig_class_table
2547 = mchar_get_prop_table (Mcombining_class, &type);
2549 mchartable_set_range (flt->coverage->table, 0, 0x10FFFF, (void *) 'u');
2550 if (combininig_class_table)
2551 mchartable_map (combininig_class_table, (void *) 0,
2552 setup_combining_coverage, flt->coverage->table);
2555 #define CHECK_FLT_STAGES(flt) ((flt)->stages || load_flt (flt, NULL) == 0)
2557 static FontLayoutCategory *
2558 configure_category (FontLayoutCategory *category, MFLTFont *font)
2560 if (! mflt_font_id || ! mflt_iterate_otf_feature)
2562 FontLayoutCategory *new = malloc (sizeof (FontLayoutCategory));
2563 new->definition = NULL;
2564 new->table = category->table;
2565 M17N_OBJECT_REF (new->table);
2568 return load_category_table (category->definition, font);
2572 configure_flt (MFLT *flt, MFLTFont *font, MSymbol font_id)
2577 if (! mflt_font_id || ! mflt_iterate_otf_feature)
2579 MPLIST_DO (plist, flt_list)
2581 configured = MPLIST_VAL (plist);
2582 if (! configured->font_id)
2584 if (configured->name == flt->name
2585 && configured->font_id == font_id)
2588 if (! MSTRUCT_CALLOC_SAFE (configured))
2591 configured->stages = mplist_copy (flt->stages);
2592 MPLIST_DO (plist, configured->stages)
2594 FontLayoutStage *stage = MPLIST_VAL (plist);
2595 if (stage->category->definition)
2597 MSTRUCT_CALLOC (stage, MERROR_FLT);
2598 *stage = *((FontLayoutStage *) MPLIST_VAL (plist));
2599 stage->category = configure_category (stage->category, font);
2600 MPLIST_VAL (plist) = stage;
2603 M17N_OBJECT_REF (stage->category->table);
2605 configured->need_config = 0;
2606 configured->font_id = font_id;
2607 mplist_push (flt_list, flt->name, configured);
2613 int m17n__flt_initialized;
2618 /* The following two are actually not exposed to a user but concealed
2619 by the macro M17N_INIT (). */
2622 m17n_init_flt (void)
2624 int mdebug_flag = MDEBUG_INIT;
2626 merror_code = MERROR_NONE;
2627 if (m17n__flt_initialized++)
2630 if (merror_code != MERROR_NONE)
2632 m17n__flt_initialized--;
2636 MDEBUG_PUSH_TIME ();
2638 Mcond = msymbol ("cond");
2639 Mrange = msymbol ("range");
2640 Mfont = msymbol ("font");
2641 Mlayouter = msymbol ("layouter");
2642 Mcombining = msymbol ("combining");
2643 Mfont_facility = msymbol ("font-facility");
2644 Mequal = msymbol ("=");
2645 Mgenerator = msymbol ("generator");
2646 Mend = msymbol ("end");
2648 mflt_iterate_otf_feature = NULL;
2649 mflt_font_id = NULL;
2651 MDEBUG_PRINT_TIME ("INIT", (stderr, " to initialize the flt modules."));
2656 m17n_fini_flt (void)
2658 int mdebug_flag = MDEBUG_FINI;
2660 if (m17n__flt_initialized == 0
2661 || --m17n__flt_initialized > 0)
2664 MDEBUG_PUSH_TIME ();
2666 MDEBUG_PRINT_TIME ("FINI", (stderr, " to finalize the flt modules."));
2672 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
2674 /*** @addtogroup m17nFLT */
2680 @brief Return an FLT object that has a specified name.
2682 The mflt_get () function returns an FLT object whose name is $NAME.
2685 If the operation was successful, mflt_get () returns a pointer
2686 to the found FLT object. Otherwise, it returns @c NULL. */
2689 @brief »ØÄꤵ¤ì¤¿Ì¾Á°¤ò»ý¤Ä FLT ¥ª¥Ö¥¸¥§¥¯¥È¤òÊÖ¤¹.
2691 ´Ø¿ô mflt_get () ¤Ï¡¢$NAME ¤È¤¤¤¦Ì¾Á°¤ò»ý¤Ä FLT ¥ª¥Ö¥¸¥§¥¯¥È¤òÊÖ¤¹¡£
2694 ¤â¤·À®¸ù¤¹¤ì¤Ð¡¢mflt_get () ¤Ï¸«¤Ä¤«¤Ã¤¿ FLT
2695 ¥ª¥Ö¥¸¥§¥¯¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¼ºÇÔ¤·¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤¹¡£ */
2698 mflt_get (MSymbol name)
2703 if (! flt_list && list_flt () < 0)
2705 for (plist = flt_list; plist; plist = plist->next)
2706 if (((MFLT *) MPLIST_VAL (plist))->font_id == Mnil)
2708 flt = mplist_get (plist, name);
2709 if (! flt || ! CHECK_FLT_STAGES (flt))
2711 if (flt->name == Mcombining
2712 && ! mchartable_lookup (flt->coverage->table, 0))
2713 setup_combining_flt (flt);
2720 @brief Find an FLT suitable for the specified character and font.
2722 The mflt_find () function returns the most appropriate FLT for
2723 layouting character $C with font $FONT.
2726 If the operation was successful, mflt_find () returns a pointer
2727 to the found FLT object. Otherwise, it returns @c NULL. */
2730 @brief »ØÄꤵ¤ì¤¿Ê¸»ú¤È¥Õ¥©¥ó¥È¤Ë¹ç¤Ã¤¿ FLT ¤òõ¤¹.
2732 ´Ø¿ô mflt_find () ¤Ï¡¢Ê¸»ú $C ¤ò¥Õ¥©¥ó¥È $FONT
2733 ¤Ç¥ì¥¤¥¢¥¦¥È¤¹¤ë¤¿¤á¤ËºÇ¤âŬÀÚ¤Ê FLT ¤òÊÖ¤¹¡£
2736 ¤â¤·À®¸ù¤¹¤ì¤Ð¡¢mflt_find () ¤Ï¸«¤Ä¤«¤Ã¤¿ FLT
2737 ¥ª¥Ö¥¸¥§¥¯¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¼ºÇÔ¤·¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤¹¡£ */
2740 mflt_find (int c, MFLTFont *font)
2744 static MSymbol unicode_bmp = NULL, unicode_full = NULL;
2748 unicode_bmp = msymbol ("unicode-bmp");
2749 unicode_full = msymbol ("unicode-full");
2752 if (! flt_list && list_flt () < 0)
2754 /* Skip configured FLTs. */
2755 MPLIST_DO (plist, flt_list)
2756 if (((MFLT *) MPLIST_VAL (plist))->font_id == Mnil)
2762 MPLIST_DO (pl, plist)
2764 flt = MPLIST_VAL (pl);
2765 if (flt->registry != unicode_bmp
2766 && flt->registry != unicode_full)
2768 if (flt->family && flt->family != font->family)
2770 if (flt->name == Mcombining
2771 && ! mchartable_lookup (flt->coverage->table, 0))
2772 setup_combining_flt (flt);
2774 && ! mchartable_lookup (flt->coverage->table, c))
2778 MFLTOtfSpec *spec = &flt->otf;
2780 if (! font->check_otf)
2782 if ((spec->features[0] && spec->features[0][0] != 0xFFFFFFFF)
2783 || (spec->features[1] && spec->features[1][0] != 0xFFFFFFFF))
2786 else if (! font->check_otf (font, spec))
2799 MPLIST_DO (pl, plist)
2801 flt = MPLIST_VAL (pl);
2802 if (mchartable_lookup (flt->coverage->table, c))
2809 if (! CHECK_FLT_STAGES (flt))
2811 if (font && flt->need_config && mflt_font_id)
2812 flt = configure_flt (flt, font, mflt_font_id (font));
2818 @brief Return the name of an FLT.
2820 The mflt_name () function returns the name of $FLT. */
2823 @brief FLT ¤Î̾Á°¤òÊÖ¤¹.
2825 ´Ø¿ô mflt_name () ¤Ï $FLT ¤Î̾Á°¤òÊÖ¤¹¡£ */
2828 mflt_name (MFLT *flt)
2830 return MSYMBOL_NAME (flt->name);
2835 @brief Return a coverage of a FLT.
2837 The mflt_coverage () function returns a char-table that contains
2838 nonzero values for characters supported by $FLT. */
2841 @brief FLT ¤ÎÈϰϤòÊÖ¤¹.
2843 ´Ø¿ô mflt_coverage () ¤Ï¡¢$FLT ¤¬¥µ¥Ý¡¼¥È¤¹¤ëʸ»ú¤ËÂФ·¤Æ
2844 0 ¤Ç¤Ê¤¤Ãͤò´Þ¤àʸ»ú¥Æ¡¼¥Ö¥ë¤òÊÖ¤¹¡£ */
2847 mflt_coverage (MFLT *flt)
2849 return flt->coverage->table;
2854 @brief Layout characters with an FLT.
2856 The mflt_run () function layouts characters in $GSTRING between
2857 $FROM (inclusive) and $TO (exclusive) with $FONT. If $FLT is
2858 nonzero, it is used for all the charaters. Otherwise, appropriate
2859 FLTs are automatically chosen.
2862 The operation was successful. The value is the index to the
2863 glyph, which was previously indexed by $TO, in $GSTRING->glyphs.
2866 $GSTRING->glyphs is too short to store the result. The caller can
2867 call this fucntion again with a longer $GSTRING->glyphs.
2870 Some other error occurred. */
2873 @brief FLT ¤ò»È¤Ã¤Æʸ»ú¤ò¥ì¥¤¥¢¥¦¥È¤¹¤ë.
2875 ´Ø¿ô mflt_run () ¤Ï¡¢$GSTRING Ãæ¤Î $FROM ¤«¤é $TO ľÁ°¤Þ¤Ç¤Îʸ»ú¤ò
2876 $FONT ¤òÍѤ¤¤Æ¥ì¥¤¥¢¥¦¥È¤¹¤ë¡£¤â¤· $FLT
2877 ¤¬¥¼¥í¤Ç¤Ê¤±¤ì¤Ð¡¢¤½¤ÎÃͤò¤¹¤Ù¤Æ¤Îʸ»ú¤ËÂФ·¤ÆÍѤ¤¤ë¡£
2878 ¤½¤¦¤Ç¤Ê¤±¤ì¤ÐŬÀÚ¤Ê FLT ¤ò¼«Æ°Åª¤ËÁªÂò¤¹¤ë¡£
2881 ¼Â¹ÔÀ®¸ù¤ò¼¨¤¹¡£ÊÖ¤µ¤ì¤ëÃͤϡ¢$GSTRING->glyphs Ãæ¤Ç°ÊÁ° $TO
2882 ¤Ë¤è¤Ã¤Æ¼¨¤µ¤ì¤Æ¤¤¤¿¥°¥ê¥Õ¤Ø¤Î¥¤¥ó¥Ç¥¯¥¹¤Ç¤¢¤ë¡£
2885 ·ë²Ì¤ò³ÊǼ¤¹¤ë¤Ë¤Ï $GSTRING->glyphs ¤¬Ã»¤¹¤®¤ë¤³¤È¤ò¼¨¤¹¡£
2886 ¸Æ¤Ó½Ð¤·Â¦¤Ï¡¢¤è¤êŤ¤ $GSTRING->glyphs
2887 ¤òÍѤ¤¤ÆºÆÅÙ¤³¤Î´Ø¿ô¤ò¸Æ¤Ö¤³¤È¤¬¤Ç¤¤ë¡£
2890 ¤½¤Î¾¤Î¥¨¥é¡¼¤¬µ¯¤¤¿¤³¤È¤ò¼¨¤¹¡£ */
2893 mflt_run (MFLTGlyphString *gstring, int from, int to,
2894 MFLTFont *font, MFLT *flt)
2896 FontLayoutContext ctx;
2897 int match_indices[NMATCH];
2899 MFLTGlyphString out;
2900 int auto_flt = ! flt;
2902 int this_from, this_to;
2903 MSymbol font_id = mflt_font_id ? mflt_font_id (font) : Mnil;
2907 /* This is usually sufficient, but if not, we retry with the larger
2908 values at most 3 times. This value is also used for the
2909 allocating size of ctx.encoded. */
2910 out.allocated = (to - from) * 4;
2912 for (i = from; i < to; i++)
2914 g = GREF (gstring, i);
2918 memset (g, 0, sizeof (MFLTGlyph));
2921 g->from = g->to = i;
2924 for (this_from = from; this_from < to;)
2928 for (this_to = this_from; this_to < to; this_to++)
2929 if (mchartable_lookup (flt->coverage->table,
2930 GREF (gstring, this_to)->c))
2935 if (! flt_list && list_flt () < 0)
2937 font->get_glyph_id (font, gstring, this_from, to);
2938 font->get_metrics (font, gstring, this_from, to);
2942 for (this_to = this_from; this_to < to; this_to++)
2944 c = GREF (gstring, this_to)->c;
2945 if (c >= flt_min_coverage && c <= flt_max_coverage)
2948 for (; this_to < to; this_to++)
2950 c = GREF (gstring, this_to)->c;
2952 && mchartable_lookup (((MFLT *) font->internal)->coverage->table, c))
2954 flt = font->internal;
2957 flt = mflt_find (c, font);
2960 if (CHECK_FLT_STAGES (flt))
2962 font->internal = flt;
2969 if (this_from < this_to)
2971 font->get_glyph_id (font, gstring, this_from, this_to);
2972 font->get_metrics (font, gstring, this_from, this_to);
2973 this_from = this_to;
2978 MDEBUG_PRINT1 (" [FLT] (%s", MSYMBOL_NAME (flt->name));
2980 if (flt->need_config && font_id != Mnil)
2981 flt = configure_flt (flt, font, font_id);
2983 for (; this_to < to; this_to++)
2986 g = GREF (gstring, this_to);
2987 enc = (int) mchartable_lookup (flt->coverage->table, g->c);
2990 SET_CATEGORY_CODE (g, enc);
2996 MDEBUG_PRINT1 (" (%s)", MSYMBOL_NAME (font->family));
2997 MDEBUG_PRINT ("\n [FLT] (SOURCE");
2998 for (i = this_from, j = 0; i < this_to; i++, j++)
3000 if (j > 0 && j % 8 == 0)
3001 MDEBUG_PRINT ("\n [FLT] ");
3002 MDEBUG_PRINT1 (" %04X", GREF (gstring, i)->c);
3007 for (i = 0; i < 3; i++)
3010 memset (&ctx, 0, sizeof ctx);
3011 ctx.match_indices = match_indices;
3013 ctx.cluster_begin_idx = -1;
3016 j = run_stages (gstring, this_from, this_to, flt, &ctx);
3030 MDEBUG_PRINT ("\n [FLT] (RESULT");
3031 if (MDEBUG_FLAG () > 1)
3032 for (i = 0; this_from < this_to; this_from++, i++)
3034 if (i > 0 && i % 4 == 0)
3035 MDEBUG_PRINT ("\n [FLT] ");
3036 g = GREF (gstring, this_from);
3037 MDEBUG_PRINT4 (" (%04X %d %d %d)",
3038 g->code, g->xadv, g->xoff, g->yoff);
3041 for (; this_from < this_to; this_from++)
3042 MDEBUG_PRINT1 (" %04X", GREF (gstring, this_from)->code);
3043 MDEBUG_PRINT ("))\n");
3045 this_from = this_to;
3050 int len = to - from;
3053 memcpy (((char *) out.glyphs),
3054 ((char *) gstring->glyphs) + gstring->glyph_size * from,
3055 gstring->glyph_size * len);
3056 for (i = from, j = to; i < to;)
3058 for (k = i + 1, j--; k < to && GREF (&out, k)->xadv == 0;
3060 GCPY (&out, i, (k - i), gstring, j);
3068 int (*mflt_iterate_otf_feature) (struct _MFLTFont *font,
3071 unsigned char *table);
3073 MSymbol (*mflt_font_id) (struct _MFLTFont *font);
3076 /* for debugging... */
3079 dump_flt_cmd (FontLayoutStage *stage, int id, int indent)
3081 char *prefix = (char *) alloca (indent + 1);
3083 memset (prefix, 32, indent);
3087 fprintf (stderr, "0x%02X", id);
3088 else if (id <= CMD_ID_OFFSET_INDEX)
3090 int idx = CMD_ID_TO_INDEX (id);
3091 FontLayoutCmd *cmd = stage->cmds + idx;
3093 if (cmd->type == FontLayoutCmdTypeRule)
3095 FontLayoutCmdRule *rule = &cmd->body.rule;
3098 fprintf (stderr, "(rule ");
3099 if (rule->src_type == SRC_REGEX)
3100 fprintf (stderr, "\"%s\"", rule->src.re.pattern);
3101 else if (rule->src_type == SRC_INDEX)
3102 fprintf (stderr, "%d", rule->src.match_idx);
3103 else if (rule->src_type == SRC_SEQ)
3104 fprintf (stderr, "(seq)");
3105 else if (rule->src_type == SRC_RANGE)
3106 fprintf (stderr, "(range)");
3108 fprintf (stderr, "(invalid src)");
3110 for (i = 0; i < rule->n_cmds; i++)
3112 fprintf (stderr, "\n%s ", prefix);
3113 dump_flt_cmd (stage, rule->cmd_ids[i], indent + 2);
3115 fprintf (stderr, ")");
3117 else if (cmd->type == FontLayoutCmdTypeCond)
3119 FontLayoutCmdCond *cond = &cmd->body.cond;
3122 fprintf (stderr, "(cond");
3123 for (i = 0; i < cond->n_cmds; i++)
3125 fprintf (stderr, "\n%s ", prefix);
3126 dump_flt_cmd (stage, cond->cmd_ids[i], indent + 2);
3128 fprintf (stderr, ")");
3130 else if (cmd->type == FontLayoutCmdTypeOTF)
3132 fprintf (stderr, "(otf)");
3135 fprintf (stderr, "(error-command)");
3137 else if (id <= CMD_ID_OFFSET_COMBINING)
3138 fprintf (stderr, "cominging-code");
3140 fprintf (stderr, "(predefiend %d)", id);
3144 @brief Dump a Font Layout Table.
3146 The mdebug_dump_flt () function prints the Font Layout Table $FLT
3147 in a human readable way to the stderr. $INDENT specifies how many
3148 columns to indent the lines but the first one.
3151 This function returns $FLT. */
3154 mdebug_dump_flt (MFLT *flt, int indent)
3156 char *prefix = (char *) alloca (indent + 1);
3160 memset (prefix, 32, indent);
3162 fprintf (stderr, "(flt");
3163 MPLIST_DO (plist, flt->stages)
3165 FontLayoutStage *stage = (FontLayoutStage *) MPLIST_VAL (plist);
3168 fprintf (stderr, "\n%s (stage %d", prefix, stage_idx);
3169 for (i = 0; i < stage->used; i++)
3171 fprintf (stderr, "\n%s ", prefix);
3172 dump_flt_cmd (stage, INDEX_TO_CMD_ID (i), indent + 4);
3174 fprintf (stderr, ")");
3177 fprintf (stderr, ")");
3182 mflt_dump_gstring (MFLTGlyphString *gstring)
3186 fprintf (stderr, "(flt-gstring");
3187 for (i = 0; i < gstring->used; i++)
3189 MFLTGlyph *g = GREF (gstring, i);
3190 fprintf (stderr, "\n (%02d pos:%d-%d c:%04X code:%04X cat:%c)",
3191 i, g->from, g->to, g->c, g->code, GET_CATEGORY_CODE (g));
3193 fprintf (stderr, ")\n");