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[4] == '?' ? 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[1] == 'o' && name[2] == 't'
1173 && name[3] == 'f' && (name[4] == '=' || name[4] == '?'))))
1175 result = load_otf_command (&cmd, sym);
1178 if (id == INVALID_CMD_ID)
1180 id = INDEX_TO_CMD_ID (stage->used);
1181 MLIST_APPEND1 (stage, cmds, cmd, MERROR_DRAW);
1184 stage->cmds[CMD_ID_TO_INDEX (id)] = cmd;
1192 else if (*name == '*')
1193 return CMD_ID_REPEAT;
1194 else if (*name == '<')
1195 return CMD_ID_CLUSTER_BEGIN;
1196 else if (*name == '>')
1197 return CMD_ID_CLUSTER_END;
1198 else if (*name == '|')
1199 return CMD_ID_SEPARATOR;
1200 else if (*name == '[')
1201 return CMD_ID_LEFT_PADDING;
1202 else if (*name == ']')
1203 return CMD_ID_RIGHT_PADDING;
1209 id = get_combining_command (sym);
1215 MPLIST_DO (elt, macros)
1217 if (sym == MPLIST_SYMBOL (MPLIST_PLIST (elt)))
1219 id = INDEX_TO_CMD_ID (i);
1220 if (stage->cmds[i].type == FontLayoutCmdTypeMAX)
1221 id = load_command (stage, MPLIST_NEXT (MPLIST_PLIST (elt)),
1227 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1230 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1236 free_flt_command (FontLayoutCmd *cmd)
1238 if (cmd->type == FontLayoutCmdTypeRule)
1240 FontLayoutCmdRule *rule = &cmd->body.rule;
1242 if (rule->src_type == SRC_REGEX)
1244 free (rule->src.re.pattern);
1245 regfree (&rule->src.re.preg);
1247 else if (rule->src_type == SRC_SEQ)
1248 free (rule->src.seq.codes);
1249 free (rule->cmd_ids);
1251 else if (cmd->type == FontLayoutCmdTypeCond)
1252 free (cmd->body.cond.cmd_ids);
1253 else if (cmd->type == FontLayoutCmdTypeOTF
1254 || cmd->type == FontLayoutCmdTypeOTFCategory)
1256 if (cmd->body.otf.features[0])
1257 free (cmd->body.otf.features[0]);
1258 if (cmd->body.otf.features[1])
1259 free (cmd->body.otf.features[1]);
1263 /* Load a generator from PLIST into a newly allocated FontLayoutStage,
1264 and return it. PLIST has this form:
1265 PLIST ::= ( COMMAND ( CMD-NAME COMMAND ) * )
1268 static FontLayoutStage *
1269 load_generator (MPlist *plist)
1271 FontLayoutStage *stage;
1273 FontLayoutCmd dummy;
1276 MSTRUCT_CALLOC (stage, MERROR_DRAW);
1277 MLIST_INIT1 (stage, cmds, 32);
1278 dummy.type = FontLayoutCmdTypeMAX;
1279 MLIST_APPEND1 (stage, cmds, dummy, MERROR_FONT);
1280 MPLIST_DO (elt, MPLIST_NEXT (plist))
1282 if (! MPLIST_PLIST_P (elt))
1283 MERROR (MERROR_FONT, NULL);
1284 pl = MPLIST_PLIST (elt);
1285 if (! MPLIST_SYMBOL_P (pl))
1286 MERROR (MERROR_FONT, NULL);
1287 MLIST_APPEND1 (stage, cmds, dummy, MERROR_FONT);
1290 /* Load the first command from PLIST into STAGE->cmds[0]. Macros
1291 called in the first command are also loaded from MPLIST_NEXT
1292 (PLIST) into STAGE->cmds[n]. */
1293 result = load_command (stage, plist, MPLIST_NEXT (plist),
1294 INDEX_TO_CMD_ID (0));
1295 if (result == INVALID_CMD_ID || result == -2)
1297 MLIST_FREE1 (stage, cmds);
1306 /* Load stages of the font layout table FLT. */
1309 load_flt (MFLT *flt, MPlist *key_list)
1311 MPlist *top, *plist, *pl, *p;
1312 FontLayoutCategory *category = NULL;
1316 top = (MPlist *) mdatabase__load_for_keys (flt->mdb, key_list);
1318 top = (MPlist *) mdatabase_load (flt->mdb);
1321 if (! MPLIST_PLIST_P (top))
1323 M17N_OBJECT_UNREF (top);
1324 MERROR (MERROR_FLT, -1);
1329 plist = mdatabase__props (flt->mdb);
1331 MERROR (MERROR_FLT, -1);
1332 MPLIST_DO (plist, plist)
1333 if (MPLIST_PLIST_P (plist))
1335 pl = MPLIST_PLIST (plist);
1336 if (! MPLIST_SYMBOL_P (pl)
1337 || MPLIST_SYMBOL (pl) != Mfont)
1339 pl = MPLIST_NEXT (pl);
1340 if (! MPLIST_PLIST_P (pl))
1342 p = MPLIST_PLIST (pl);
1343 if (! MPLIST_SYMBOL_P (p))
1345 p = MPLIST_NEXT (p);
1346 if (! MPLIST_SYMBOL_P (p))
1348 flt->family = MPLIST_SYMBOL (p);
1349 MPLIST_DO (p, MPLIST_NEXT (p))
1350 if (MPLIST_SYMBOL_P (p))
1352 sym = MPLIST_SYMBOL (p);
1353 if (MSYMBOL_NAME (sym)[0] != ':')
1354 flt->registry = sym, sym = Mnil;
1360 char *otf_spec = MSYMBOL_NAME (sym);
1362 if (otf_spec[0] == ':' && otf_spec[1] == 'o'
1363 && otf_spec[2] == 't' && otf_spec[3] == 'f')
1364 parse_otf_command (sym, &flt->otf);
1369 MPLIST_DO (plist, top)
1371 if (MPLIST_SYMBOL_P (plist)
1372 && MPLIST_SYMBOL (plist) == Mend)
1374 mplist_set (plist, Mnil, NULL);
1377 if (! MPLIST_PLIST (plist))
1379 pl = MPLIST_PLIST (plist);
1380 if (! MPLIST_SYMBOL_P (pl))
1382 sym = MPLIST_SYMBOL (pl);
1383 pl = MPLIST_NEXT (pl);
1386 if (sym == Mcategory)
1389 unref_category_table (category);
1390 else if (flt->coverage)
1392 category = flt->coverage;
1393 ref_category_table (category);
1396 category = load_category_table (pl, NULL);
1397 if (! flt->coverage)
1399 flt->coverage = category;
1400 ref_category_table (category);
1402 if (category->definition)
1403 flt->need_config = 1;
1405 else if (sym == Mgenerator)
1407 FontLayoutStage *stage;
1411 stage = load_generator (pl);
1414 stage->category = category;
1415 M17N_OBJECT_REF (category->table);
1417 flt->stages = mplist ();
1418 mplist_add (flt->stages, Mt, stage);
1422 unref_category_table (category);
1424 if (! MPLIST_TAIL_P (plist))
1426 M17N_OBJECT_UNREF (top);
1427 M17N_OBJECT_UNREF (flt->stages);
1428 MERROR (MERROR_FLT, -1);
1430 M17N_OBJECT_UNREF (top);
1436 free_flt_stage (MFLT *flt, FontLayoutStage *stage)
1440 unref_category_table (stage->category);
1443 for (i = 0; i < stage->used; i++)
1444 free_flt_command (stage->cmds + i);
1445 MLIST_FREE1 (stage, cmds);
1457 MPLIST_DO (plist, flt_list)
1459 MFLT *flt = MPLIST_VAL (plist);
1462 unref_category_table (flt->coverage);
1465 MPLIST_DO (pl, MPLIST_NEXT (flt->stages))
1466 free_flt_stage (flt, MPLIST_VAL (pl));
1467 M17N_OBJECT_UNREF (flt->stages);
1470 MPLIST_VAL (plist) = NULL;
1472 M17N_OBJECT_UNREF (flt_list);
1479 MPlist *plist, *key_list = NULL;
1483 if (! (plist = mdatabase_list (Mfont, Mlayouter, Mnil, Mnil)))
1485 if (! (flt_list = mplist ()))
1487 if (! (key_list = mplist ()))
1489 if (! mplist_add (key_list, Mcategory, Mt))
1492 MPLIST_DO (pl, plist)
1494 MDatabase *mdb = MPLIST_VAL (pl);
1495 MSymbol *tags = mdatabase_tag (mdb);
1498 if (! MSTRUCT_CALLOC_SAFE (flt))
1500 flt->name = tags[2];
1502 if (load_flt (flt, key_list) < 0)
1506 if (MPLIST_TAIL_P (flt_list))
1508 flt_min_coverage = mchartable_min_char (flt->coverage->table);
1509 flt_max_coverage = mchartable_max_char (flt->coverage->table);
1515 c = mchartable_min_char (flt->coverage->table);
1516 if (flt_min_coverage > c)
1517 flt_min_coverage = c;
1518 c = mchartable_max_char (flt->coverage->table);
1519 if (flt_max_coverage < c)
1520 flt_max_coverage = c;
1522 if (! mplist_push (flt_list, flt->name, flt))
1532 M17N_OBJECT_UNREF (plist);
1533 M17N_OBJECT_UNREF (key_list);
1537 /* FLS (Font Layout Service) */
1539 /* Structure to hold information about a context of FLS. */
1543 /* Pointer to the current stage. */
1544 FontLayoutStage *stage;
1546 /* Pointer to the category table of the next stage or NULL if none. */
1547 FontLayoutCategory *category;
1549 /* Pointer to the font. */
1552 /* Input and output glyph string. */
1553 MFLTGlyphString *in, *out;
1555 /* Encode each character or code of a glyph by the current category
1556 table into this array. An element is a category letter used for
1557 a regular expression matching. */
1562 int cluster_begin_idx;
1563 int cluster_begin_pos;
1564 int cluster_end_pos;
1568 } FontLayoutContext;
1570 static int run_command (int, int, int, int, FontLayoutContext *);
1571 static int run_otf (int, MFLTOtfSpec *, int, int, FontLayoutContext *);
1572 static int run_otf_category (int, MFLTOtfSpec *, int, int, FontLayoutContext *);
1577 run_rule (int depth,
1578 FontLayoutCmdRule *rule, int from, int to, FontLayoutContext *ctx)
1580 int *saved_match_indices = ctx->match_indices;
1581 int match_indices[NMATCH * 2];
1584 int orig_from = from;
1585 int need_cluster_update = 0;
1587 if (rule->src_type == SRC_REGEX)
1589 regmatch_t pmatch[NMATCH];
1595 saved_code = ctx->encoded[to - ctx->encoded_offset];
1596 ctx->encoded[to - ctx->encoded_offset] = '\0';
1597 result = regexec (&(rule->src.re.preg),
1598 ctx->encoded + (from - ctx->encoded_offset),
1600 if (result == 0 && pmatch[0].rm_so == 0)
1602 if (MDEBUG_FLAG () > 2)
1603 MDEBUG_PRINT5 ("\n [FLT] %*s(REGEX \"%s\" \"%s\" %d", depth, "",
1604 rule->src.re.pattern,
1605 ctx->encoded + (from - ctx->encoded_offset),
1607 ctx->encoded[to - ctx->encoded_offset] = saved_code;
1608 for (i = 0; i < NMATCH; i++)
1610 if (pmatch[i].rm_so < 0)
1611 match_indices[i * 2] = match_indices[i * 2 + 1] = -1;
1614 match_indices[i * 2] = from + pmatch[i].rm_so;
1615 match_indices[i * 2 + 1] = from + pmatch[i].rm_eo;
1618 ctx->match_indices = match_indices;
1619 to = match_indices[1];
1623 ctx->encoded[to - ctx->encoded_offset] = saved_code;
1626 need_cluster_update = 1;
1628 else if (rule->src_type == SRC_SEQ)
1632 len = rule->src.seq.n_codes;
1633 if (len > (to - from))
1635 for (i = 0; i < len; i++)
1636 if (rule->src.seq.codes[i] != GREF (ctx->in, from + i)->c)
1641 if (MDEBUG_FLAG () > 2)
1642 MDEBUG_PRINT3 ("\n [FLT] %*s(SEQ 0x%X", depth, "",
1643 rule->src.seq.codes[0]);
1644 need_cluster_update = 1;
1646 else if (rule->src_type == SRC_RANGE)
1652 head = GREF (ctx->in, from)->c;
1653 if (head < rule->src.range.from || head > rule->src.range.to)
1655 ctx->code_offset = head - rule->src.range.from;
1657 if (MDEBUG_FLAG () > 2)
1658 MDEBUG_PRINT4 ("\n [FLT] %*s(RANGE 0x%X-0x%X", depth, "",
1659 rule->src.range.from, rule->src.range.to);
1660 need_cluster_update = 1;
1662 else if (rule->src_type == SRC_INDEX)
1664 if (rule->src.match_idx >= NMATCH)
1666 from = ctx->match_indices[rule->src.match_idx * 2];
1669 to = ctx->match_indices[rule->src.match_idx * 2 + 1];
1670 if (MDEBUG_FLAG () > 2)
1671 MDEBUG_PRINT3 ("\n [FLT] %*s(SUBPART %d", depth, "",
1672 rule->src.match_idx);
1673 need_cluster_update = 1;
1675 else if (rule->src_type == SRC_HAS_GLYPH
1676 || rule->src_type == SRC_OTF_SPEC)
1678 static MFLTGlyphString gstring;
1682 if (rule->src.facility.len > 0)
1684 if (! gstring.glyph_size)
1686 gstring.glyph_size = ctx->in->glyph_size;
1687 gstring.glyphs = calloc (rule->src.facility.len,
1688 gstring.glyph_size);
1689 gstring.allocated = rule->src.facility.len;
1690 gstring.used = rule->src.facility.len;
1692 else if (rule->src.facility.len < gstring.allocated)
1694 gstring.glyphs = realloc (gstring.glyphs,
1696 * rule->src.facility.len);
1697 gstring.allocated = rule->src.facility.len;
1698 gstring.used = rule->src.facility.len;
1701 for (i = 0, p = rule->src.facility.codes, idx = from;
1702 i < rule->src.facility.len; i++, p = MPLIST_NEXT (p))
1704 if (MPLIST_INTEGER_P (p))
1706 GREF (&gstring, i)->code = MPLIST_INTEGER (p);
1707 GREF (&gstring, i)->encoded = 0;
1711 GREF (&gstring, i)->code = GREF (ctx->in, idx)->code;
1712 GREF (&gstring, i)->encoded = GREF (ctx->in, idx)->encoded;
1718 if (MDEBUG_FLAG () > 2)
1720 if (rule->src_type == SRC_HAS_GLYPH)
1721 MDEBUG_PRINT2 ("\n [FLT] %*s(HAS-GLYPH", depth, "");
1723 MDEBUG_PRINT2 ("\n [FLT] %*s(OTF-SPEC", depth, "");
1724 for (i = 0; i < rule->src.facility.len; i++)
1725 MDEBUG_PRINT1 (" %04X", GREF (&gstring, i)->code);
1727 if (ctx->font->get_glyph_id (ctx->font, &gstring, 0,
1728 rule->src.facility.len) < 0)
1730 MDEBUG_PRINT (") FAIL!");
1733 if (rule->src_type == SRC_OTF_SPEC)
1735 MFLTOtfSpec *spec = &rule->src.facility.otf_spec;
1737 if (! ctx->font->check_otf)
1739 if ((spec->features[0] && spec->features[0][0] != 0xFFFFFFFF)
1740 || (spec->features[1] && spec->features[1][0] != 0xFFFFFFFF))
1745 if (rule->src.facility.len == 0)
1747 if (! ctx->font->check_otf (ctx->font, spec))
1752 int prev_out_used = ctx->out->used, out_used;
1753 MFLTGlyphAdjustment *adjustment;
1755 adjustment = alloca ((sizeof *adjustment)
1756 * (ctx->out->allocated - ctx->out->used));
1758 MERROR (MERROR_FLT, -1);
1759 memset (adjustment, 0,
1760 (sizeof *adjustment)
1761 * (ctx->out->allocated - ctx->out->used));
1762 ctx->font->drive_otf (ctx->font, &rule->src.facility.otf_spec,
1763 &gstring, 0, rule->src.facility.len,
1766 out_used = ctx->out->used;
1767 ctx->out->used = prev_out_used;
1768 if (rule->src.facility.len == out_used - prev_out_used)
1770 for (i = prev_out_used; i < out_used; i++)
1772 if (GREF (&gstring, i - prev_out_used)->code
1773 != GREF (ctx->out, i)->code)
1775 if (adjustment[i - prev_out_used].set)
1786 if (need_cluster_update && ctx->cluster_begin_idx >= 0)
1788 for (i = from; i < to; i++)
1790 MFLTGlyph *g = GREF (ctx->in, i);
1791 UPDATE_CLUSTER_RANGE (ctx, g);
1797 for (i = 0; i < rule->n_cmds; i++)
1801 if (rule->cmd_ids[i] == CMD_ID_REPEAT)
1807 pos = run_command (depth, rule->cmd_ids[i], from, to, ctx);
1810 consumed = pos > from;
1815 ctx->match_indices = saved_match_indices;
1816 if (MDEBUG_FLAG () > 2)
1818 return (rule->src_type == SRC_INDEX ? orig_from : to);
1822 run_cond (int depth,
1823 FontLayoutCmdCond *cond, int from, int to, FontLayoutContext *ctx)
1827 if (MDEBUG_FLAG () > 2)
1828 MDEBUG_PRINT2 ("\n [FLT] %*s(COND", depth, "");
1830 for (i = 0; i < cond->n_cmds; i++)
1832 /* TODO: Write a code for optimization utilizaing the info
1834 if ((pos = run_command (depth, cond->cmd_ids[i], from, to, ctx))
1840 if (MDEBUG_FLAG () > 2)
1846 decode_packed_otf_tag (FontLayoutContext *ctx, MFLTGlyphString *gstring,
1847 int from, int to, FontLayoutCategory *category)
1849 for (; from < to; from++)
1851 MFLTGlyph *g = GREF (gstring, from);
1852 unsigned int tag = g->internal & 0xFFFFFFF;
1857 SET_CATEGORY_CODE (g, 0);
1860 if (tag & 0xFFFFF80)
1864 g->internal &= 0x30000000;
1865 for (i = 0, enc = '\0'; i < category->feature_table.size; i++)
1866 if (category->feature_table.tag[i] == tag)
1868 enc = category->feature_table.code[i];
1869 if (ctx->in == gstring)
1870 ctx->encoded[from - ctx->encoded_offset] = enc;
1875 enc = GET_COMBINED (g) ? '\0' : GET_CATEGORY_CODE (g);
1877 enc = g->c > 0 ? (int) mchartable_lookup (category->table, g->c) : 1;
1878 SET_CATEGORY_CODE (g, enc);
1884 MFLTOtfSpec *otf_spec, int from, int to, FontLayoutContext *ctx)
1886 MFLTFont *font = ctx->font;
1887 int from_idx = ctx->out->used;
1889 if (MDEBUG_FLAG () > 2)
1890 MDEBUG_PRINT3 ("\n [FLT] %*s%s", depth, "", MSYMBOL_NAME (otf_spec->sym));
1892 font->get_glyph_id (font, ctx->in, from, to);
1893 if (! font->drive_otf)
1895 if (ctx->out->used + (to - from) > ctx->out->allocated)
1897 font->get_metrics (font, ctx->in, from, to);
1898 GCPY (ctx->in, from, to - from, ctx->out, ctx->out->used);
1899 ctx->out->used += to - from;
1903 MFLTGlyphAdjustment *adjustment;
1907 adjustment = alloca ((sizeof *adjustment)
1908 * (ctx->out->allocated - ctx->out->used));
1910 MERROR (MERROR_FLT, -1);
1911 memset (adjustment, 0,
1912 (sizeof *adjustment) * (ctx->out->allocated - ctx->out->used));
1913 to = font->drive_otf (font, otf_spec, ctx->in, from, to, ctx->out,
1917 decode_packed_otf_tag (ctx, ctx->out, from_idx, ctx->out->used,
1919 out_len = ctx->out->used - from_idx;
1920 if (otf_spec->features[1])
1922 MFLTGlyphAdjustment *a;
1925 for (i = 0, a = adjustment; i < out_len; i++, a++)
1930 font->get_metrics (font, ctx->out, from_idx, ctx->out->used);
1931 for (g = GREF (ctx->out, from_idx + i);
1932 i < out_len; i++, a++, g = NEXT (ctx->out, g))
1935 if (a->advance_is_absolute)
1940 else if (a->xadv || a->yadv)
1945 if (a->xoff || a->yoff || a->back)
1948 MFLTGlyph *gg = PREV (ctx->out, g);
1949 MFLTGlyphAdjustment *aa = a;
1953 g->lbearing += a->xoff;
1954 g->rbearing += a->xoff;
1955 g->ascent -= a->yoff;
1956 g->descent -= a->yoff;
1957 while (aa->back > 0)
1959 for (j = 0; j < aa->back;
1960 j++, gg = PREV (ctx->out, gg))
1962 g->xoff -= gg->xadv;
1963 g->lbearing -= gg->xadv;
1964 g->rbearing -= gg->xadv;
1967 g->xoff += aa->xoff;
1968 g->yoff += aa->yoff;
1969 g->lbearing += aa->xoff;
1970 g->rbearing += aa->xoff;
1971 g->ascent -= aa->yoff;
1972 g->descent -= aa->yoff;
1981 if (ctx->cluster_begin_idx >= 0)
1982 for (; from_idx < ctx->out->used; from_idx++)
1984 MFLTGlyph *g = GREF (ctx->out, from_idx);
1985 UPDATE_CLUSTER_RANGE (ctx, g);
1991 run_otf_category (int depth, MFLTOtfSpec *otf_spec, int from, int to,
1992 FontLayoutContext *ctx)
1994 MFLTFont *font = ctx->font;
1995 int from_idx = ctx->out->used;
1997 if (ctx->stage->category->feature_table.size == 0)
2000 if (MDEBUG_FLAG () > 2)
2001 MDEBUG_PRINT3 ("\n [FLT] %*s%s", depth, "", MSYMBOL_NAME (otf_spec->sym));
2003 font->get_glyph_id (font, ctx->in, from, to);
2004 if (font->drive_otf)
2009 to = font->drive_otf (font, otf_spec, ctx->in, from, to, NULL, NULL);
2012 decode_packed_otf_tag (ctx, ctx->in, from, to, ctx->stage->category);
2017 static char work[16];
2020 dump_combining_code (int code)
2022 char *vallign = "tcbB";
2023 char *hallign = "lcr";
2029 work[0] = vallign[COMBINING_CODE_BASE_Y (code)];
2030 work[1] = hallign[COMBINING_CODE_BASE_X (code)];
2031 off_y = COMBINING_CODE_OFF_Y (code);
2032 off_x = COMBINING_CODE_OFF_X (code);
2034 sprintf (work + 2, "+%d", off_y);
2036 sprintf (work + 2, "%d", off_y);
2037 else if (off_x == 0)
2038 sprintf (work + 2, ".");
2039 p = work + strlen (work);
2041 sprintf (p, ">%d", off_x);
2043 sprintf (p, "<%d", -off_x);
2045 p[0] = vallign[COMBINING_CODE_ADD_Y (code)];
2046 p[1] = hallign[COMBINING_CODE_ADD_X (code)];
2052 run_command (int depth, int id, int from, int to, FontLayoutContext *ctx)
2059 MCharTable *table = ctx->category ? ctx->category->table : NULL;
2062 /* Direct code (== ctx->code_offset + id) output.
2063 The source is not consumed. */
2064 if (MDEBUG_FLAG () > 2)
2065 MDEBUG_PRINT3 ("\n [FLT] %*s(DIRECT 0x%X", depth, "",
2066 ctx->code_offset + id);
2067 i = (from < to || from == 0) ? from : from - 1;
2069 g = GREF (ctx->out, ctx->out->used - 1);
2070 g->c = g->code = ctx->code_offset + id;
2071 if (ctx->combining_code)
2072 SET_COMBINING_CODE (g, ctx, ctx->combining_code);
2075 enc = (GET_ENCODED (g)
2076 ? (g->c > 0 ? (int) mchartable_lookup (table, g->c) : 1)
2078 ? (int) mchartable_lookup (table, g->code)
2080 SET_CATEGORY_CODE (g, enc);
2083 SET_MEASURED (g, 0);
2084 if (ctx->left_padding)
2085 SET_LEFT_PADDING (g, ctx, LeftPaddingMask);
2086 for (i = from; i < to; i++)
2088 MFLTGlyph *tmp = GREF (ctx->in, i);
2090 if (g->from > tmp->from)
2091 g->from = tmp->from;
2092 else if (g->to < tmp->to)
2095 if (ctx->cluster_begin_idx >= 0)
2096 UPDATE_CLUSTER_RANGE (ctx, g);
2097 ctx->code_offset = ctx->combining_code = ctx->left_padding = 0;
2098 if (MDEBUG_FLAG () > 2)
2103 if (id <= CMD_ID_OFFSET_INDEX)
2105 int idx = CMD_ID_TO_INDEX (id);
2108 if (idx >= ctx->stage->used)
2109 MERROR (MERROR_DRAW, -1);
2110 cmd = ctx->stage->cmds + idx;
2111 if (cmd->type == FontLayoutCmdTypeRule)
2112 to = run_rule (depth, &cmd->body.rule, from, to, ctx);
2113 else if (cmd->type == FontLayoutCmdTypeCond)
2114 to = run_cond (depth, &cmd->body.cond, from, to, ctx);
2115 else if (cmd->type == FontLayoutCmdTypeOTF)
2116 to = run_otf (depth, &cmd->body.otf, from, to, ctx);
2117 else if (cmd->type == FontLayoutCmdTypeOTFCategory)
2118 to = run_otf_category (depth, &cmd->body.otf, from, to, ctx);
2122 if (id <= CMD_ID_OFFSET_COMBINING)
2124 ctx->combining_code = CMD_ID_TO_COMBINING_CODE (id);
2125 if (MDEBUG_FLAG () > 2)
2126 MDEBUG_PRINT3 ("\n [FLT] %*s(CMB %s)", depth, "",
2127 dump_combining_code (ctx->combining_code));
2138 g = GREF (ctx->out, ctx->out->used - 1);
2139 if (ctx->combining_code)
2140 SET_COMBINING_CODE (g, ctx, ctx->combining_code);
2141 else if (! GET_COMBINED (g) && ctx->category)
2143 MCharTable *table = ctx->category->table;
2144 char enc = (GET_ENCODED (g)
2145 ? (g->c > 0 ? (int) mchartable_lookup (table, g->c)
2148 ? (int) mchartable_lookup (table, g->code)
2150 SET_CATEGORY_CODE (g, enc);
2152 if (ctx->left_padding)
2153 SET_LEFT_PADDING (g, ctx, LeftPaddingMask);
2154 if (ctx->cluster_begin_idx >= 0)
2155 UPDATE_CLUSTER_RANGE (ctx, g);
2156 if (MDEBUG_FLAG () > 2)
2159 MDEBUG_PRINT2 ("\n [FLT] %*s(COPY |)", depth, "");
2161 MDEBUG_PRINT3 ("\n [FLT] %*s(COPY 0x%X)", depth, "", g->c);
2163 ctx->code_offset = ctx->combining_code = ctx->left_padding = 0;
2167 case CMD_ID_CLUSTER_BEGIN:
2168 if (ctx->cluster_begin_idx < 0)
2170 if (MDEBUG_FLAG () > 2)
2171 MDEBUG_PRINT3 ("\n [FLT] %*s<%d", depth, "",
2172 GREF (ctx->in, from)->from);
2173 ctx->cluster_begin_idx = ctx->out->used;
2174 ctx->cluster_begin_pos = GREF (ctx->in, from)->from;
2175 ctx->cluster_end_pos = GREF (ctx->in, from)->to;
2179 case CMD_ID_CLUSTER_END:
2180 if (ctx->cluster_begin_idx >= 0
2181 && ctx->cluster_begin_idx < ctx->out->used)
2185 if (MDEBUG_FLAG () > 2)
2186 MDEBUG_PRINT1 (" %d>", ctx->cluster_end_pos + 1);
2187 for (i = ctx->cluster_begin_idx; i < ctx->out->used; i++)
2189 GREF (ctx->out, i)->from = ctx->cluster_begin_pos;
2190 GREF (ctx->out, i)->to = ctx->cluster_end_pos;
2192 ctx->cluster_begin_idx = -1;
2196 case CMD_ID_SEPARATOR:
2200 i = from < to ? from : from - 1;
2202 g = GREF (ctx->out, ctx->out->used - 1);
2203 g->c = -1, g->code = 0;
2204 g->xadv = g->yadv = 0;
2206 SET_MEASURED (g, 0);
2207 SET_CATEGORY_CODE (g, ' ');
2211 case CMD_ID_LEFT_PADDING:
2212 if (MDEBUG_FLAG () > 2)
2213 MDEBUG_PRINT2 ("\n [FLT] %*s[", depth, "");
2214 ctx->left_padding = 1;
2217 case CMD_ID_RIGHT_PADDING:
2218 if (ctx->out->used > 0)
2220 if (MDEBUG_FLAG () > 2)
2221 MDEBUG_PRINT2 ("\n [FLT] %*s]", depth, "");
2222 g = GREF (ctx->out, ctx->out->used - 1);
2223 SET_RIGHT_PADDING (g, ctx, RightPaddingMask);
2228 MERROR (MERROR_DRAW, -1);
2232 run_stages (MFLTGlyphString *gstring, int from, int to,
2233 MFLT *flt, FontLayoutContext *ctx)
2235 MFLTGlyphString buf, *temp;
2237 int orig_from = from, orig_to = to;
2238 int from_pos, to_pos, len;
2241 MPlist *stages = flt->stages;
2242 FontLayoutCategory *prev_category = NULL;
2244 from_pos = GREF (ctx->in, from)->from;
2245 to_pos = GREF (ctx->in, to - 1)->to;
2246 len = to_pos - from_pos;
2250 GINIT (ctx->out, ctx->out->allocated);
2251 ctx->encoded = alloca (ctx->out->allocated);
2252 if (! ctx->out->glyphs || ! ctx->encoded)
2255 for (stage_idx = 0; 1; stage_idx++)
2260 ctx->stage = (FontLayoutStage *) MPLIST_VAL (stages);
2261 table = ctx->stage->category->table;
2262 stages = MPLIST_NEXT (stages);
2263 if (MPLIST_TAIL_P (stages))
2264 ctx->category = NULL;
2266 ctx->category = ((FontLayoutStage *) MPLIST_VAL (stages))->category;
2267 ctx->code_offset = ctx->combining_code = ctx->left_padding = 0;
2268 ctx->encoded_offset = from;
2269 for (i = from; i < to; i++)
2271 MFLTGlyph *g = GREF (ctx->in, i);
2274 if (GET_COMBINED (g)
2275 || (prev_category && prev_category != ctx->stage->category))
2276 enc = (GET_ENCODED (g)
2277 ? (g->c > 0 ? (int) mchartable_lookup (table, g->c) : 1)
2279 ? (int) mchartable_lookup (table, g->code)
2282 enc = GET_CATEGORY_CODE (g);
2283 ctx->encoded[i - from] = enc;
2284 if (! enc && stage_idx == 0)
2290 ctx->encoded[i - from] = '\0';
2291 ctx->match_indices[0] = from;
2292 ctx->match_indices[1] = to;
2293 for (i = 2; i < NMATCH; i++)
2294 ctx->match_indices[i] = -1;
2296 if (MDEBUG_FLAG () > 2)
2298 MDEBUG_PRINT2 ("\n [FLT] (STAGE %d \"%s\"", stage_idx,
2300 MDEBUG_PRINT (" (");
2301 for (i = from; i < to; i++)
2303 g = GREF (ctx->in, i);
2305 MDEBUG_PRINT2 ("%*s|", (i > 0), "");
2307 MDEBUG_PRINT3 ("%*s%04X", (i > 0), "", GREF (ctx->in, i)->code);
2311 result = run_command (4, INDEX_TO_CMD_ID (0), from, to, ctx);
2312 if (MDEBUG_FLAG () > 2)
2317 /* If this is the last stage, break the loop. */
2318 if (MPLIST_TAIL_P (stages))
2321 /* Otherwise, prepare for the next stage. */
2322 prev_category = ctx->stage->category;
2329 GINIT (&buf, ctx->out->allocated);
2338 if (ctx->out->used > 0)
2341 int x_ppem = ctx->font->x_ppem << 6, y_ppem = ctx->font->y_ppem << 6;
2343 /* Remove separator glyphs. */
2344 for (i = 0; i < ctx->out->used;)
2346 g = GREF (ctx->out, i);
2348 GREPLACE (NULL, 0, 0, ctx->out, i, i + 1);
2353 /* Get actual glyph IDs of glyphs. */
2354 ctx->font->get_glyph_id (ctx->font, ctx->out, 0, ctx->out->used);
2356 /* Check if all characters in the range are covered by some
2357 glyph(s). If not, change <from> and <to> of glyphs to cover
2358 uncovered characters. */
2359 g_indices = alloca (sizeof (int) * len);
2362 for (i = 0; i < len; i++) g_indices[i] = -1;
2363 for (i = 0; i < ctx->out->used; i++)
2367 g = GREF (ctx->out, i);
2368 for (pos = g->from; pos <= g->to; pos++)
2369 if (g_indices[pos - from_pos] < 0)
2370 g_indices[pos - from_pos] = i;
2372 for (i = 0; i < len; i++)
2373 if (g_indices[i] < 0)
2379 for (i++; i < len && g_indices[i] < 0; i++);
2381 g = GREF (ctx->out, j);
2382 this_from = g->from;
2384 g->from = orig_from + i;
2385 } while (++j < ctx->out->used
2386 && (g = GREF (ctx->out, j))
2387 && g->from == this_from);
2393 j = g_indices[i - 1];
2394 g = GREF (ctx->out, j);
2397 g->to = orig_from + i + 1;
2399 && (g = GREF (ctx->out, j))
2400 && g->to == this_to);
2404 ctx->font->get_metrics (ctx->font, ctx->out, 0, ctx->out->used);
2406 /* Handle combining. */
2407 if (ctx->check_mask & CombinedMask)
2409 MFLTGlyph *base = GREF (ctx->out, 0);
2410 int base_height = base->ascent + base->descent;
2411 int base_width = base->rbearing - base->lbearing;
2414 for (i = 1; i < ctx->out->used; i++)
2416 if ((g = GREF (ctx->out, i))
2418 && (combining_code = GET_COMBINING_CODE (g)))
2420 int height = g->ascent + g->descent;
2421 int width = g->rbearing - g->lbearing;
2422 int base_x, base_y, add_x, add_y, off_x, off_y;
2424 if (base->from > g->from)
2425 base->from = g->from;
2426 else if (base->to < g->to)
2429 base_x = COMBINING_CODE_BASE_X (combining_code);
2430 base_y = COMBINING_CODE_BASE_Y (combining_code);
2431 add_x = COMBINING_CODE_ADD_X (combining_code);
2432 add_y = COMBINING_CODE_ADD_Y (combining_code);
2433 off_x = COMBINING_CODE_OFF_X (combining_code);
2434 off_y = COMBINING_CODE_OFF_Y (combining_code);
2436 g->xoff = ((base_width * base_x - width * add_x) / 2
2437 + x_ppem * off_x / 100
2438 - (base->xadv - base->lbearing) - g->lbearing);
2440 g->yoff = base_height * base_y / 2 - base->ascent;
2444 g->yoff -= height * add_y / 2 - g->ascent;
2445 g->yoff -= y_ppem * off_y / 100;
2446 if (base->lbearing > base->xadv + g->lbearing + g->xoff)
2447 base->lbearing = base->xadv + g->lbearing + g->xoff;
2448 if (base->rbearing < base->xadv + g->rbearing + g->xoff)
2449 base->rbearing = base->xadv + g->rbearing + g->xoff;
2450 if (base->ascent < g->ascent - g->yoff)
2451 base->ascent = g->ascent - g->yoff;
2452 if (base->descent < g->descent - g->yoff)
2453 base->descent = g->descent - g->yoff;
2454 g->xadv = g->yadv = 0;
2455 if (GET_RIGHT_PADDING (g))
2456 SET_RIGHT_PADDING (base, ctx, RightPaddingMask);
2462 base_height = g->ascent + g->descent;
2463 base_width = g->rbearing - g->lbearing;
2468 /* Handle padding */
2469 if (ctx->check_mask & (LeftPaddingMask | RightPaddingMask))
2470 for (i = 0; i < ctx->out->used; i++)
2472 g = GREF (ctx->out, i);
2473 if (! GET_COMBINED (g))
2475 if (GET_RIGHT_PADDING (g) && g->rbearing > g->xadv)
2477 g->xadv = g->rbearing;
2480 if (GET_LEFT_PADDING (g) && g->lbearing < 0)
2482 g->xoff += - g->lbearing;
2483 g->xadv += - g->lbearing;
2484 g->rbearing += - g->lbearing;
2492 GREPLACE (ctx->out, 0, ctx->out->used, gstring, orig_from, orig_to);
2493 to = orig_from + ctx->out->used;
2498 setup_combining_coverage (int from, int to, void *val, void *arg)
2500 int combining_class = (int) val;
2503 if (combining_class < 200)
2505 else if (combining_class <= 204)
2507 if ((combining_class % 2) == 0)
2508 category = "bcd"[(combining_class - 200) / 2];
2510 else if (combining_class <= 232)
2512 if ((combining_class % 2) == 0)
2513 category = "efghijklmnopq"[(combining_class - 208) / 2];
2515 else if (combining_class == 233)
2517 else if (combining_class == 234)
2519 else if (combining_class == 240)
2521 mchartable_set_range ((MCharTable *) arg, from, to, (void *) category);
2525 setup_combining_flt (MFLT *flt)
2528 MCharTable *combininig_class_table
2529 = mchar_get_prop_table (Mcombining_class, &type);
2531 mchartable_set_range (flt->coverage->table, 0, 0x10FFFF, (void *) 'u');
2532 if (combininig_class_table)
2533 mchartable_map (combininig_class_table, (void *) 0,
2534 setup_combining_coverage, flt->coverage->table);
2537 #define CHECK_FLT_STAGES(flt) ((flt)->stages || load_flt (flt, NULL) == 0)
2539 static FontLayoutCategory *
2540 configure_category (FontLayoutCategory *category, MFLTFont *font)
2542 if (! mflt_font_id || ! mflt_iterate_otf_feature)
2544 FontLayoutCategory *new = malloc (sizeof (FontLayoutCategory));
2545 new->definition = NULL;
2546 new->table = category->table;
2547 M17N_OBJECT_REF (new->table);
2550 return load_category_table (category->definition, font);
2554 configure_flt (MFLT *flt, MFLTFont *font, MSymbol font_id)
2559 if (! mflt_font_id || ! mflt_iterate_otf_feature)
2561 MPLIST_DO (plist, flt_list)
2563 configured = MPLIST_VAL (plist);
2564 if (! configured->font_id)
2566 if (configured->name == flt->name
2567 && configured->font_id == font_id)
2570 if (! MSTRUCT_CALLOC_SAFE (configured))
2573 configured->stages = mplist_copy (flt->stages);
2574 MPLIST_DO (plist, configured->stages)
2576 FontLayoutStage *stage = MPLIST_VAL (plist);
2577 if (stage->category->definition)
2579 MSTRUCT_CALLOC (stage, MERROR_FLT);
2580 *stage = *((FontLayoutStage *) MPLIST_VAL (plist));
2581 stage->category = configure_category (stage->category, font);
2582 MPLIST_VAL (plist) = stage;
2585 M17N_OBJECT_REF (stage->category->table);
2587 configured->need_config = 0;
2588 configured->font_id = font_id;
2589 mplist_push (flt_list, flt->name, configured);
2595 int m17n__flt_initialized;
2600 /* The following two are actually not exposed to a user but concealed
2601 by the macro M17N_INIT (). */
2604 m17n_init_flt (void)
2606 int mdebug_flag = MDEBUG_INIT;
2608 merror_code = MERROR_NONE;
2609 if (m17n__flt_initialized++)
2612 if (merror_code != MERROR_NONE)
2614 m17n__flt_initialized--;
2618 MDEBUG_PUSH_TIME ();
2620 Mcond = msymbol ("cond");
2621 Mrange = msymbol ("range");
2622 Mfont = msymbol ("font");
2623 Mlayouter = msymbol ("layouter");
2624 Mcombining = msymbol ("combining");
2625 Mfont_facility = msymbol ("font-facility");
2626 Mequal = msymbol ("=");
2627 Mgenerator = msymbol ("generator");
2628 Mend = msymbol ("end");
2630 mflt_iterate_otf_feature = NULL;
2631 mflt_font_id = NULL;
2633 MDEBUG_PRINT_TIME ("INIT", (stderr, " to initialize the flt modules."));
2638 m17n_fini_flt (void)
2640 int mdebug_flag = MDEBUG_FINI;
2642 if (m17n__flt_initialized == 0
2643 || --m17n__flt_initialized > 0)
2646 MDEBUG_PUSH_TIME ();
2648 MDEBUG_PRINT_TIME ("FINI", (stderr, " to finalize the flt modules."));
2654 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
2656 /*** @addtogroup m17nFLT */
2662 @brief Return an FLT object that has a specified name.
2664 The mflt_get () function returns an FLT object whose name is $NAME.
2667 If the operation was successful, mflt_get () returns a pointer
2668 to the found FLT object. Otherwise, it returns @c NULL. */
2671 @brief »ØÄꤵ¤ì¤¿Ì¾Á°¤ò»ý¤Ä FLT ¥ª¥Ö¥¸¥§¥¯¥È¤òÊÖ¤¹.
2673 ´Ø¿ô mflt_get () ¤Ï¡¢$NAME ¤È¤¤¤¦Ì¾Á°¤ò»ý¤Ä FLT ¥ª¥Ö¥¸¥§¥¯¥È¤òÊÖ¤¹¡£
2676 ¤â¤·À®¸ù¤¹¤ì¤Ð¡¢mflt_get () ¤Ï¸«¤Ä¤«¤Ã¤¿ FLT
2677 ¥ª¥Ö¥¸¥§¥¯¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¼ºÇÔ¤·¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤¹¡£ */
2680 mflt_get (MSymbol name)
2685 if (! flt_list && list_flt () < 0)
2687 for (plist = flt_list; plist; plist = plist->next)
2688 if (((MFLT *) MPLIST_VAL (plist))->font_id == Mnil)
2690 flt = mplist_get (plist, name);
2691 if (! flt || ! CHECK_FLT_STAGES (flt))
2693 if (flt->name == Mcombining
2694 && ! mchartable_lookup (flt->coverage->table, 0))
2695 setup_combining_flt (flt);
2702 @brief Find an FLT suitable for the specified character and font.
2704 The mflt_find () function returns the most appropriate FLT for
2705 layouting character $C with font $FONT.
2708 If the operation was successful, mflt_find () returns a pointer
2709 to the found FLT object. Otherwise, it returns @c NULL. */
2712 @brief »ØÄꤵ¤ì¤¿Ê¸»ú¤È¥Õ¥©¥ó¥È¤Ë¹ç¤Ã¤¿ FLT ¤òõ¤¹.
2714 ´Ø¿ô mflt_find () ¤Ï¡¢Ê¸»ú $C ¤ò¥Õ¥©¥ó¥È $FONT
2715 ¤Ç¥ì¥¤¥¢¥¦¥È¤¹¤ë¤¿¤á¤ËºÇ¤âŬÀÚ¤Ê FLT ¤òÊÖ¤¹¡£
2718 ¤â¤·À®¸ù¤¹¤ì¤Ð¡¢mflt_find () ¤Ï¸«¤Ä¤«¤Ã¤¿ FLT
2719 ¥ª¥Ö¥¸¥§¥¯¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¼ºÇÔ¤·¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤¹¡£ */
2722 mflt_find (int c, MFLTFont *font)
2726 static MSymbol unicode_bmp = NULL, unicode_full = NULL;
2730 unicode_bmp = msymbol ("unicode-bmp");
2731 unicode_full = msymbol ("unicode-full");
2734 if (! flt_list && list_flt () < 0)
2736 /* Skip configured FLTs. */
2737 MPLIST_DO (plist, flt_list)
2738 if (((MFLT *) MPLIST_VAL (plist))->font_id == Mnil)
2744 MPLIST_DO (pl, plist)
2746 flt = MPLIST_VAL (pl);
2747 if (flt->registry != unicode_bmp
2748 && flt->registry != unicode_full)
2750 if (flt->family && flt->family != font->family)
2752 if (flt->name == Mcombining
2753 && ! mchartable_lookup (flt->coverage->table, 0))
2754 setup_combining_flt (flt);
2756 && ! mchartable_lookup (flt->coverage->table, c))
2760 MFLTOtfSpec *spec = &flt->otf;
2762 if (! font->check_otf)
2764 if ((spec->features[0] && spec->features[0][0] != 0xFFFFFFFF)
2765 || (spec->features[1] && spec->features[1][0] != 0xFFFFFFFF))
2768 else if (! font->check_otf (font, spec))
2781 MPLIST_DO (pl, plist)
2783 flt = MPLIST_VAL (pl);
2784 if (mchartable_lookup (flt->coverage->table, c))
2791 if (! CHECK_FLT_STAGES (flt))
2793 if (font && flt->need_config && mflt_font_id)
2794 flt = configure_flt (flt, font, mflt_font_id (font));
2800 @brief Return the name of an FLT.
2802 The mflt_name () function returns the name of $FLT. */
2805 @brief FLT ¤Î̾Á°¤òÊÖ¤¹.
2807 ´Ø¿ô mflt_name () ¤Ï $FLT ¤Î̾Á°¤òÊÖ¤¹¡£ */
2810 mflt_name (MFLT *flt)
2812 return MSYMBOL_NAME (flt->name);
2817 @brief Return a coverage of a FLT.
2819 The mflt_coverage () function returns a char-table that contains
2820 nonzero values for characters supported by $FLT. */
2823 @brief FLT ¤ÎÈϰϤòÊÖ¤¹.
2825 ´Ø¿ô mflt_coverage () ¤Ï¡¢$FLT ¤¬¥µ¥Ý¡¼¥È¤¹¤ëʸ»ú¤ËÂФ·¤Æ
2826 0 ¤Ç¤Ê¤¤Ãͤò´Þ¤àʸ»ú¥Æ¡¼¥Ö¥ë¤òÊÖ¤¹¡£ */
2829 mflt_coverage (MFLT *flt)
2831 return flt->coverage->table;
2836 @brief Layout characters with an FLT.
2838 The mflt_run () function layouts characters in $GSTRING between
2839 $FROM (inclusive) and $TO (exclusive) with $FONT. If $FLT is
2840 nonzero, it is used for all the charaters. Otherwise, appropriate
2841 FLTs are automatically chosen.
2844 The operation was successful. The value is the index to the
2845 glyph, which was previously indexed by $TO, in $GSTRING->glyphs.
2848 $GSTRING->glyphs is too short to store the result. The caller can
2849 call this fucntion again with a longer $GSTRING->glyphs.
2852 Some other error occurred. */
2855 @brief FLT ¤ò»È¤Ã¤Æʸ»ú¤ò¥ì¥¤¥¢¥¦¥È¤¹¤ë.
2857 ´Ø¿ô mflt_run () ¤Ï¡¢$GSTRING Ãæ¤Î $FROM ¤«¤é $TO ľÁ°¤Þ¤Ç¤Îʸ»ú¤ò
2858 $FONT ¤òÍѤ¤¤Æ¥ì¥¤¥¢¥¦¥È¤¹¤ë¡£¤â¤· $FLT
2859 ¤¬¥¼¥í¤Ç¤Ê¤±¤ì¤Ð¡¢¤½¤ÎÃͤò¤¹¤Ù¤Æ¤Îʸ»ú¤ËÂФ·¤ÆÍѤ¤¤ë¡£
2860 ¤½¤¦¤Ç¤Ê¤±¤ì¤ÐŬÀÚ¤Ê FLT ¤ò¼«Æ°Åª¤ËÁªÂò¤¹¤ë¡£
2863 ¼Â¹ÔÀ®¸ù¤ò¼¨¤¹¡£ÊÖ¤µ¤ì¤ëÃͤϡ¢$GSTRING->glyphs Ãæ¤Ç°ÊÁ° $TO
2864 ¤Ë¤è¤Ã¤Æ¼¨¤µ¤ì¤Æ¤¤¤¿¥°¥ê¥Õ¤Ø¤Î¥¤¥ó¥Ç¥¯¥¹¤Ç¤¢¤ë¡£
2867 ·ë²Ì¤ò³ÊǼ¤¹¤ë¤Ë¤Ï $GSTRING->glyphs ¤¬Ã»¤¹¤®¤ë¤³¤È¤ò¼¨¤¹¡£
2868 ¸Æ¤Ó½Ð¤·Â¦¤Ï¡¢¤è¤êŤ¤ $GSTRING->glyphs
2869 ¤òÍѤ¤¤ÆºÆÅÙ¤³¤Î´Ø¿ô¤ò¸Æ¤Ö¤³¤È¤¬¤Ç¤¤ë¡£
2872 ¤½¤Î¾¤Î¥¨¥é¡¼¤¬µ¯¤¤¿¤³¤È¤ò¼¨¤¹¡£ */
2875 mflt_run (MFLTGlyphString *gstring, int from, int to,
2876 MFLTFont *font, MFLT *flt)
2878 FontLayoutContext ctx;
2879 int match_indices[NMATCH];
2881 MFLTGlyphString out;
2882 int auto_flt = ! flt;
2884 int this_from, this_to;
2885 MSymbol font_id = mflt_font_id ? mflt_font_id (font) : Mnil;
2889 /* This is usually sufficient, but if not, we retry with the larger
2890 values at most 3 times. This value is also used for the
2891 allocating size of ctx.encoded. */
2892 out.allocated = (to - from) * 4;
2894 for (i = from; i < to; i++)
2896 g = GREF (gstring, i);
2900 memset (g, 0, sizeof (MFLTGlyph));
2903 g->from = g->to = i;
2906 for (this_from = from; this_from < to;)
2910 for (this_to = this_from; this_to < to; this_to++)
2911 if (mchartable_lookup (flt->coverage->table,
2912 GREF (gstring, this_to)->c))
2917 if (! flt_list && list_flt () < 0)
2919 font->get_glyph_id (font, gstring, this_from, to);
2920 font->get_metrics (font, gstring, this_from, to);
2924 for (this_to = this_from; this_to < to; this_to++)
2926 c = GREF (gstring, this_to)->c;
2927 if (c >= flt_min_coverage && c <= flt_max_coverage)
2930 for (; this_to < to; this_to++)
2932 c = GREF (gstring, this_to)->c;
2934 && mchartable_lookup (((MFLT *) font->internal)->coverage->table, c))
2936 flt = font->internal;
2939 flt = mflt_find (c, font);
2942 if (CHECK_FLT_STAGES (flt))
2944 font->internal = flt;
2951 if (this_from < this_to)
2953 font->get_glyph_id (font, gstring, this_from, this_to);
2954 font->get_metrics (font, gstring, this_from, this_to);
2955 this_from = this_to;
2960 MDEBUG_PRINT1 (" [FLT] (%s", MSYMBOL_NAME (flt->name));
2962 if (flt->need_config && font_id != Mnil)
2963 flt = configure_flt (flt, font, font_id);
2965 for (; this_to < to; this_to++)
2968 g = GREF (gstring, this_to);
2969 enc = (int) mchartable_lookup (flt->coverage->table, g->c);
2972 SET_CATEGORY_CODE (g, enc);
2978 MDEBUG_PRINT1 (" (%s)", MSYMBOL_NAME (font->family));
2979 MDEBUG_PRINT ("\n [FLT] (SOURCE");
2980 for (i = this_from, j = 0; i < this_to; i++, j++)
2982 if (j > 0 && j % 8 == 0)
2983 MDEBUG_PRINT ("\n [FLT] ");
2984 MDEBUG_PRINT1 (" %04X", GREF (gstring, i)->c);
2989 for (i = 0; i < 3; i++)
2992 memset (&ctx, 0, sizeof ctx);
2993 ctx.match_indices = match_indices;
2995 ctx.cluster_begin_idx = -1;
2998 j = run_stages (gstring, this_from, this_to, flt, &ctx);
3012 MDEBUG_PRINT ("\n [FLT] (RESULT");
3013 if (MDEBUG_FLAG () > 1)
3014 for (i = 0; this_from < this_to; this_from++, i++)
3016 if (i > 0 && i % 4 == 0)
3017 MDEBUG_PRINT ("\n [FLT] ");
3018 g = GREF (gstring, this_from);
3019 MDEBUG_PRINT4 (" (%04X %d %d %d)",
3020 g->code, g->xadv, g->xoff, g->yoff);
3023 for (; this_from < this_to; this_from++)
3024 MDEBUG_PRINT1 (" %04X", GREF (gstring, this_from)->code);
3025 MDEBUG_PRINT ("))\n");
3027 this_from = this_to;
3032 int len = to - from;
3035 memcpy (((char *) out.glyphs),
3036 ((char *) gstring->glyphs) + gstring->glyph_size * from,
3037 gstring->glyph_size * len);
3038 for (i = from, j = to; i < to;)
3040 for (k = i + 1, j--; k < to && GREF (&out, k)->xadv == 0;
3042 GCPY (&out, i, (k - i), gstring, j);
3050 int (*mflt_iterate_otf_feature) (struct _MFLTFont *font,
3053 unsigned char *table);
3055 MSymbol (*mflt_font_id) (struct _MFLTFont *font);
3058 /* for debugging... */
3061 dump_flt_cmd (FontLayoutStage *stage, int id, int indent)
3063 char *prefix = (char *) alloca (indent + 1);
3065 memset (prefix, 32, indent);
3069 fprintf (stderr, "0x%02X", id);
3070 else if (id <= CMD_ID_OFFSET_INDEX)
3072 int idx = CMD_ID_TO_INDEX (id);
3073 FontLayoutCmd *cmd = stage->cmds + idx;
3075 if (cmd->type == FontLayoutCmdTypeRule)
3077 FontLayoutCmdRule *rule = &cmd->body.rule;
3080 fprintf (stderr, "(rule ");
3081 if (rule->src_type == SRC_REGEX)
3082 fprintf (stderr, "\"%s\"", rule->src.re.pattern);
3083 else if (rule->src_type == SRC_INDEX)
3084 fprintf (stderr, "%d", rule->src.match_idx);
3085 else if (rule->src_type == SRC_SEQ)
3086 fprintf (stderr, "(seq)");
3087 else if (rule->src_type == SRC_RANGE)
3088 fprintf (stderr, "(range)");
3090 fprintf (stderr, "(invalid src)");
3092 for (i = 0; i < rule->n_cmds; i++)
3094 fprintf (stderr, "\n%s ", prefix);
3095 dump_flt_cmd (stage, rule->cmd_ids[i], indent + 2);
3097 fprintf (stderr, ")");
3099 else if (cmd->type == FontLayoutCmdTypeCond)
3101 FontLayoutCmdCond *cond = &cmd->body.cond;
3104 fprintf (stderr, "(cond");
3105 for (i = 0; i < cond->n_cmds; i++)
3107 fprintf (stderr, "\n%s ", prefix);
3108 dump_flt_cmd (stage, cond->cmd_ids[i], indent + 2);
3110 fprintf (stderr, ")");
3112 else if (cmd->type == FontLayoutCmdTypeOTF)
3114 fprintf (stderr, "(otf)");
3117 fprintf (stderr, "(error-command)");
3119 else if (id <= CMD_ID_OFFSET_COMBINING)
3120 fprintf (stderr, "cominging-code");
3122 fprintf (stderr, "(predefiend %d)", id);
3126 @brief Dump a Font Layout Table.
3128 The mdebug_dump_flt () function prints the Font Layout Table $FLT
3129 in a human readable way to the stderr. $INDENT specifies how many
3130 columns to indent the lines but the first one.
3133 This function returns $FLT. */
3136 mdebug_dump_flt (MFLT *flt, int indent)
3138 char *prefix = (char *) alloca (indent + 1);
3142 memset (prefix, 32, indent);
3144 fprintf (stderr, "(flt");
3145 MPLIST_DO (plist, flt->stages)
3147 FontLayoutStage *stage = (FontLayoutStage *) MPLIST_VAL (plist);
3150 fprintf (stderr, "\n%s (stage %d", prefix, stage_idx);
3151 for (i = 0; i < stage->used; i++)
3153 fprintf (stderr, "\n%s ", prefix);
3154 dump_flt_cmd (stage, INDEX_TO_CMD_ID (i), indent + 4);
3156 fprintf (stderr, ")");
3159 fprintf (stderr, ")");
3164 mflt_dump_gstring (MFLTGlyphString *gstring)
3168 fprintf (stderr, "(flt-gstring");
3169 for (i = 0; i < gstring->used; i++)
3171 MFLTGlyph *g = GREF (gstring, i);
3172 fprintf (stderr, "\n (%02d pos:%d-%d c:%04X code:%04X cat:%c)",
3173 i, g->from, g->to, g->c, g->code, GET_CATEGORY_CODE (g));
3175 fprintf (stderr, ")\n");