1 /* m17n-flt.c -- Font Layout Table sub-module.
2 Copyright (C) 2003, 2004, 2007, 2008, 2009, 2010
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 << 28,
261 LeftPaddingMask = 1 << 29,
262 RightPaddingMask = 1 << 30
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))
548 if (! mflt_enable_new_feature)
550 M17N_OBJECT_UNREF (table);
553 next = MPLIST_NEXT (elt);
554 if (! MPLIST_INTEGER_P (next))
555 MERROR_GOTO (MERROR_FLT, end);
556 if (! feature_table_head)
557 feature_table_head = p;
558 feature_table_size++;
561 if (! MPLIST_INTEGER_P (elt))
562 MERROR_GOTO (MERROR_FLT, end);
563 from = MPLIST_INTEGER (elt);
564 elt = MPLIST_NEXT (elt);
565 if (! MPLIST_INTEGER_P (elt))
566 MERROR_GOTO (MERROR_FLT, end);
567 to = MPLIST_INTEGER (elt);
568 elt = MPLIST_NEXT (elt);
569 if (MPLIST_TAIL_P (elt))
574 else if (MPLIST_SYMBOL_P (elt))
576 if (! mflt_enable_new_feature)
578 M17N_OBJECT_UNREF (table);
584 if (parse_otf_command (MPLIST_SYMBOL (elt), &spec) < 0)
585 MERROR_GOTO (MERROR_FLT, end);
586 elt = MPLIST_NEXT (elt);
587 if (! MPLIST_INTEGER_P (elt))
588 MERROR_GOTO (MERROR_FLT, end);
589 category_code = MPLIST_INTEGER (elt);
590 if (! isalnum (category_code))
591 MERROR_GOTO (MERROR_FLT, end);
592 apply_otf_feature (font, &spec, from, to, table, category_code);
600 if (! MPLIST_INTEGER_P (elt))
601 MERROR_GOTO (MERROR_FLT, end);
602 category_code = MPLIST_INTEGER (elt);
604 if (! isalnum (category_code))
605 MERROR_GOTO (MERROR_FLT, end);
608 mchartable_set (table, from, (void *) category_code);
610 mchartable_set_range (table, from, to, (void *) category_code);
614 category = calloc (1, sizeof (FontLayoutCategory));
615 category->table = table;
618 category->definition = plist;
619 M17N_OBJECT_REF (plist);
622 category->definition = NULL;
623 if (feature_table_head)
626 category->feature_table.size = feature_table_size;
627 category->feature_table.tag = malloc (sizeof (unsigned int)
628 * feature_table_size);
629 category->feature_table.code = malloc (feature_table_size);
631 MPLIST_DO (p, feature_table_head)
635 if (! MPLIST_PLIST_P (p))
637 elt = MPLIST_PLIST (p);
638 if (! MPLIST_SYMBOL_P (elt))
640 feature = MPLIST_SYMBOL (elt);
641 elt = MPLIST_NEXT (elt);
642 if (! MPLIST_INTEGER_P (elt))
644 category->feature_table.tag[i]
645 = gen_otf_tag (MSYMBOL_NAME (feature), 7);
646 category->feature_table.code[i] = MPLIST_INTEGER (elt);
653 #define ref_category_table(CATEGORY) M17N_OBJECT_REF ((CATEGORY)->table)
656 unref_category_table (FontLayoutCategory *category)
658 M17N_OBJECT_UNREF (category->table);
659 if (! category->table)
661 if (category->definition)
662 M17N_OBJECT_UNREF (category->definition);
663 if (category->feature_table.size > 0)
665 free (category->feature_table.tag);
666 free (category->feature_table.code);
673 gen_otf_tag (char *p, int shift)
675 unsigned int tag = 0;
678 for (i = 0; i < 4 && *p; i++, p++)
679 tag = (tag << shift) | *p;
681 tag = (tag << shift) | 0x20;
686 otf_count_features (char *p, char *end, char stopper, int *count)
691 if (*p != stopper && *p != '\0')
698 if (*p == stopper || *p == '\0')
712 if (*p == stopper || *p == '\0')
724 otf_store_features (char *p, char *end, unsigned *buf)
729 for (i = 0; p < end;)
732 buf[i++] = 0xFFFFFFFF, p += 2, negative = 1;
736 buf[i++] = 0xFFFFFFFF;
737 buf[i++] = gen_otf_tag (p + 1, 8), p += 6;
740 buf[i++] = gen_otf_tag (p, 8), p += 5;
746 parse_otf_command (MSymbol symbol, MFLTOtfSpec *spec)
748 char *str = MSYMBOL_NAME (symbol);
749 char *end = str + MSYMBOL_NAMELEN (symbol);
750 unsigned int script, langsys;
752 int gsub_count = 0, gpos_count = 0;
755 memset (spec, 0, sizeof (MFLTOtfSpec));
758 str += 5; /* skip the heading ":otf=" or ":otf?" */
761 if (! mflt_enable_new_feature)
762 /* The client can't use this command. */
765 /* This is a spec to reset category codes. */
768 script = gen_otf_tag (str, 8);
772 langsys = gen_otf_tag (str, 8);
779 /* Apply all GSUB features. */
784 str = otf_count_features (p, end, '+', &gsub_count);
786 MERROR (MERROR_FLT, -1);
790 /* Apply all GPOS features. */
795 str = otf_count_features (p, end, '\0', &gpos_count);
797 MERROR (MERROR_FLT, -1);
800 spec->script = script;
801 spec->langsys = langsys;
804 spec->features[0] = malloc (sizeof (int) * (gsub_count + 1));
805 if (! spec->features[0])
808 otf_store_features (gsub + 1, gpos, spec->features[0]);
810 spec->features[0][0] = 0xFFFFFFFF, spec->features[0][1] = 0;
814 spec->features[1] = malloc (sizeof (int) * (gpos_count + 1));
815 if (! spec->features[1])
817 if (spec->features[0])
818 free (spec->features[0]);
822 otf_store_features (gpos + 1, str, spec->features[1]);
824 spec->features[1][0] = 0xFFFFFFFF, spec->features[1][1] = 0;
830 /* Parse OTF command name NAME and store the result in CMD.
832 :SCRIPT[/[LANGSYS][=[GSUB-FEATURES][+GPOS-FEATURES]]]
833 where GSUB-FEATURES and GPOS-FEATURES have this form:
834 [FEATURE[,FEATURE]*] | ' ' */
837 load_otf_command (FontLayoutCmd *cmd, MSymbol sym)
839 char *name = MSYMBOL_NAME (sym);
844 /* This is old format of "otf:...". Change it to ":otf=...". */
845 char *str = alloca (MSYMBOL_NAMELEN (sym) + 2);
847 sprintf (str, ":otf=");
848 strcat (str, name + 4);
852 result = parse_otf_command (sym, &cmd->body.otf);
855 cmd->type = (name[4] == '?' ? FontLayoutCmdTypeOTFCategory
856 : FontLayoutCmdTypeOTF);
861 /* Read a decimal number from STR preceded by one of "+-><". '+' and
862 '>' means a plus sign, '-' and '<' means a minus sign. If the
863 number is greater than 127, limit it to 127. */
866 read_decimal_number (char **str)
869 int sign = (*p == '-' || *p == '<') ? -1 : 1;
873 while (*p >= '0' && *p <= '9')
874 n = n * 10 + *p++ - '0';
878 return (n < 127 ? n * sign : 127 * sign);
882 /* Read a horizontal and vertical combining positions from STR, and
883 store them in the place pointed by X and Y. The horizontal
884 position left, center, and right are represented by 0, 1, and 2
885 respectively. The vertical position top, center, bottom, and base
886 are represented by 0, 1, 2, and 3 respectively. If successfully
887 read, return 0, else return -1. */
890 read_combining_position (char *str, int *x, int *y)
895 /* Vertical position comes first. */
896 for (i = 0; i < 4; i++)
905 /* Then comse horizontal position. */
906 for (i = 0; i < 3; i++)
916 /* Return a combining code corresponding to SYM. */
919 get_combining_command (MSymbol sym)
921 char *str = msymbol_name (sym);
922 int base_x, base_y, add_x, add_y, off_x, off_y;
925 if (read_combining_position (str, &base_x, &base_y) < 0)
936 if (c == '+' || c == '-')
938 off_y = read_decimal_number (&str) + 128;
943 if (c == '<' || c == '>')
944 off_x = read_decimal_number (&str) + 128;
948 if (read_combining_position (str, &add_x, &add_y) < 0)
951 c = MAKE_COMBINING_CODE (base_y, base_x, add_y, add_x, off_y, off_x);
952 return (COMBINING_CODE_TO_CMD_ID (c));
956 /* Load a command from PLIST into STAGE, and return that
957 identification number. If ID is not INVALID_CMD_ID, that means we
958 are loading a top level command or a macro. In that case, use ID
959 as the identification number of the command. Otherwise, generate a
960 new id number for the command. MACROS is a list of raw macros. */
963 load_command (FontLayoutStage *stage, MPlist *plist,
964 MPlist *macros, int id)
969 if (MPLIST_INTEGER_P (plist))
971 int code = MPLIST_INTEGER (plist);
974 MERROR (MERROR_DRAW, INVALID_CMD_ID);
977 else if (MPLIST_PLIST_P (plist))
979 /* PLIST ::= ( cond ... ) | ( STRING ... ) | ( INTEGER ... )
980 | ( ( INTEGER INTEGER ) ... )
981 | ( ( range INTEGER INTEGER ) ... )
982 | ( ( SYMBOL STRING ) ... )
983 | ( ( font-facilty [ INTEGER ] ) ... )
984 | ( ( font-facilty OTF-SPEC ) ... ) */
985 MPlist *elt = MPLIST_PLIST (plist);
986 int len = MPLIST_LENGTH (elt) - 1;
989 if (id == INVALID_CMD_ID)
992 id = INDEX_TO_CMD_ID (stage->used);
993 MLIST_APPEND1 (stage, cmds, dummy, MERROR_DRAW);
995 cmd = stage->cmds + CMD_ID_TO_INDEX (id);
997 if (MPLIST_SYMBOL_P (elt))
999 FontLayoutCmdCond *cond;
1001 if (MPLIST_SYMBOL (elt) != Mcond)
1002 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1003 elt = MPLIST_NEXT (elt);
1004 cmd->type = FontLayoutCmdTypeCond;
1005 cond = &cmd->body.cond;
1006 cond->seq_beg = cond->seq_end = -1;
1007 cond->seq_from = cond->seq_to = 0;
1009 MTABLE_CALLOC (cond->cmd_ids, len, MERROR_DRAW);
1010 for (i = 0; i < len; i++, elt = MPLIST_NEXT (elt))
1012 int this_id = load_command (stage, elt, macros, INVALID_CMD_ID);
1014 if (this_id == INVALID_CMD_ID || this_id == -2)
1015 MERROR (MERROR_DRAW, this_id);
1016 /* The above load_command may relocate stage->cmds. */
1017 cmd = stage->cmds + CMD_ID_TO_INDEX (id);
1018 cond = &cmd->body.cond;
1019 cond->cmd_ids[i] = this_id;
1020 if (this_id <= CMD_ID_OFFSET_INDEX)
1022 FontLayoutCmd *this_cmd
1023 = stage->cmds + CMD_ID_TO_INDEX (this_id);
1025 if (this_cmd->type == FontLayoutCmdTypeRule
1026 && this_cmd->body.rule.src_type == SRC_SEQ)
1028 int first_char = this_cmd->body.rule.src.seq.codes[0];
1030 if (cond->seq_beg < 0)
1032 /* The first SEQ command. */
1034 cond->seq_from = cond->seq_to = first_char;
1036 else if (cond->seq_end < 0)
1038 /* The following SEQ command. */
1039 if (cond->seq_from > first_char)
1040 cond->seq_from = first_char;
1041 else if (cond->seq_to < first_char)
1042 cond->seq_to = first_char;
1047 if (cond->seq_beg >= 0 && cond->seq_end < 0)
1048 /* The previous one is the last SEQ command. */
1054 if (cond->seq_beg >= 0 && cond->seq_end < 0)
1055 /* The previous one is the last SEQ command. */
1059 if (cond->seq_beg >= 0 && cond->seq_end < 0)
1060 /* The previous one is the last SEQ command. */
1065 cmd->type = FontLayoutCmdTypeRule;
1066 if (MPLIST_MTEXT_P (elt))
1068 MText *mt = MPLIST_MTEXT (elt);
1069 char *str = (char *) MTEXT_DATA (mt);
1073 mtext_ins_char (mt, 0, '^', 1);
1074 str = (char *) MTEXT_DATA (mt);
1076 if (regcomp (&cmd->body.rule.src.re.preg, str, REG_EXTENDED))
1077 MERROR (MERROR_FONT, INVALID_CMD_ID);
1078 cmd->body.rule.src_type = SRC_REGEX;
1079 cmd->body.rule.src.re.pattern = strdup (str);
1081 else if (MPLIST_INTEGER_P (elt))
1083 cmd->body.rule.src_type = SRC_INDEX;
1084 cmd->body.rule.src.match_idx = MPLIST_INTEGER (elt);
1086 else if (MPLIST_PLIST_P (elt))
1088 MPlist *pl = MPLIST_PLIST (elt), *p;
1089 int size = MPLIST_LENGTH (pl);
1091 if (MPLIST_INTEGER_P (pl))
1095 cmd->body.rule.src_type = SRC_SEQ;
1096 cmd->body.rule.src.seq.n_codes = size;
1097 MTABLE_CALLOC (cmd->body.rule.src.seq.codes, size,
1099 for (i = 0; i < size; i++, pl = MPLIST_NEXT (pl))
1101 if (! MPLIST_INTEGER_P (pl))
1102 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1103 cmd->body.rule.src.seq.codes[i]
1104 = (unsigned) MPLIST_INTEGER (pl);
1107 else if (MPLIST_SYMBOL_P (pl))
1109 if (MPLIST_SYMBOL (pl) == Mrange)
1112 MERROR (MERROR_FLT, INVALID_CMD_ID);
1113 cmd->body.rule.src_type = SRC_RANGE;
1114 pl = MPLIST_NEXT (pl);
1115 if (! MPLIST_INTEGER_P (pl))
1116 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1117 cmd->body.rule.src.range.from
1118 = (unsigned) MPLIST_INTEGER (pl);
1119 pl = MPLIST_NEXT (pl);
1120 if (! MPLIST_INTEGER_P (pl))
1121 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1122 cmd->body.rule.src.range.to
1123 = (unsigned) MPLIST_INTEGER (pl);
1125 else if (MPLIST_SYMBOL (pl) == Mfont_facility)
1127 FontLayoutCmdRule *rule = &cmd->body.rule;
1129 pl = MPLIST_NEXT (pl);
1130 if (MPLIST_SYMBOL_P (pl))
1132 MSymbol sym = MPLIST_SYMBOL (pl);
1133 char *otf_spec = MSYMBOL_NAME (sym);
1135 if (otf_spec[0] == ':' && otf_spec[1] == 'o'
1136 && otf_spec[2] == 't' && otf_spec[3] == 'f')
1137 parse_otf_command (sym, &rule->src.facility.otf_spec);
1139 MERROR (MERROR_FLT, INVALID_CMD_ID);
1140 rule->src_type = SRC_OTF_SPEC;
1141 pl = MPLIST_NEXT (pl);
1143 else if (MPLIST_TAIL_P (pl))
1144 MERROR (MERROR_FLT, INVALID_CMD_ID);
1146 rule->src_type = SRC_HAS_GLYPH;
1147 rule->src.facility.len = 0;
1150 if (! MPLIST_INTEGER_P (p)
1151 && (MPLIST_SYMBOL_P (p)
1152 ? MPLIST_SYMBOL (p) != Mequal
1154 MERROR (MERROR_FLT, INVALID_CMD_ID);
1155 rule->src.facility.len++;
1157 rule->src.facility.codes = pl;
1158 M17N_OBJECT_REF (pl);
1162 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1165 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1167 elt = MPLIST_NEXT (elt);
1168 cmd->body.rule.n_cmds = len;
1169 MTABLE_CALLOC (cmd->body.rule.cmd_ids, len, MERROR_DRAW);
1170 for (i = 0; i < len; i++, elt = MPLIST_NEXT (elt))
1172 int this_id = load_command (stage, elt, macros, INVALID_CMD_ID);
1174 if (this_id == INVALID_CMD_ID || this_id == -2)
1175 MERROR (MERROR_DRAW, this_id);
1176 /* The above load_command may relocate stage->cmds. */
1177 cmd = stage->cmds + CMD_ID_TO_INDEX (id);
1178 cmd->body.rule.cmd_ids[i] = this_id;
1182 else if (MPLIST_SYMBOL_P (plist))
1185 MSymbol sym = MPLIST_SYMBOL (plist);
1186 char *name = msymbol_name (sym);
1187 int len = strlen (name);
1191 && ((name[0] == 'o' && name[1] == 't'
1192 && name[2] == 'f' && name[3] == ':')
1193 || (name[0] == ':' && name[1] == 'o' && name[2] == 't'
1194 && name[3] == 'f' && (name[4] == '=' || name[4] == '?'))))
1196 result = load_otf_command (&cmd, sym);
1199 if (id == INVALID_CMD_ID)
1201 id = INDEX_TO_CMD_ID (stage->used);
1202 MLIST_APPEND1 (stage, cmds, cmd, MERROR_DRAW);
1205 stage->cmds[CMD_ID_TO_INDEX (id)] = cmd;
1213 else if (*name == '*')
1214 return CMD_ID_REPEAT;
1215 else if (*name == '<')
1216 return CMD_ID_CLUSTER_BEGIN;
1217 else if (*name == '>')
1218 return CMD_ID_CLUSTER_END;
1219 else if (*name == '|')
1220 return CMD_ID_SEPARATOR;
1221 else if (*name == '[')
1222 return CMD_ID_LEFT_PADDING;
1223 else if (*name == ']')
1224 return CMD_ID_RIGHT_PADDING;
1230 id = get_combining_command (sym);
1236 MPLIST_DO (elt, macros)
1238 if (sym == MPLIST_SYMBOL (MPLIST_PLIST (elt)))
1240 id = INDEX_TO_CMD_ID (i);
1241 if (stage->cmds[i].type == FontLayoutCmdTypeMAX)
1242 id = load_command (stage, MPLIST_NEXT (MPLIST_PLIST (elt)),
1248 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1251 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1257 free_flt_command (FontLayoutCmd *cmd)
1259 if (cmd->type == FontLayoutCmdTypeRule)
1261 FontLayoutCmdRule *rule = &cmd->body.rule;
1263 if (rule->src_type == SRC_REGEX)
1265 free (rule->src.re.pattern);
1266 regfree (&rule->src.re.preg);
1268 else if (rule->src_type == SRC_SEQ)
1269 free (rule->src.seq.codes);
1270 free (rule->cmd_ids);
1272 else if (cmd->type == FontLayoutCmdTypeCond)
1273 free (cmd->body.cond.cmd_ids);
1274 else if (cmd->type == FontLayoutCmdTypeOTF
1275 || cmd->type == FontLayoutCmdTypeOTFCategory)
1277 if (cmd->body.otf.features[0])
1278 free (cmd->body.otf.features[0]);
1279 if (cmd->body.otf.features[1])
1280 free (cmd->body.otf.features[1]);
1284 /* Load a generator from PLIST into a newly allocated FontLayoutStage,
1285 and return it. PLIST has this form:
1286 PLIST ::= ( COMMAND ( CMD-NAME COMMAND ) * )
1289 static FontLayoutStage *
1290 load_generator (MPlist *plist)
1292 FontLayoutStage *stage;
1294 FontLayoutCmd dummy;
1297 MSTRUCT_CALLOC (stage, MERROR_DRAW);
1298 MLIST_INIT1 (stage, cmds, 32);
1299 dummy.type = FontLayoutCmdTypeMAX;
1300 MLIST_APPEND1 (stage, cmds, dummy, MERROR_FONT);
1301 MPLIST_DO (elt, MPLIST_NEXT (plist))
1303 if (! MPLIST_PLIST_P (elt))
1304 MERROR (MERROR_FONT, NULL);
1305 pl = MPLIST_PLIST (elt);
1306 if (! MPLIST_SYMBOL_P (pl))
1307 MERROR (MERROR_FONT, NULL);
1308 MLIST_APPEND1 (stage, cmds, dummy, MERROR_FONT);
1311 /* Load the first command from PLIST into STAGE->cmds[0]. Macros
1312 called in the first command are also loaded from MPLIST_NEXT
1313 (PLIST) into STAGE->cmds[n]. */
1314 result = load_command (stage, plist, MPLIST_NEXT (plist),
1315 INDEX_TO_CMD_ID (0));
1316 if (result == INVALID_CMD_ID || result == -2)
1318 MLIST_FREE1 (stage, cmds);
1327 /* Load stages of the font layout table FLT. */
1330 load_flt (MFLT *flt, MPlist *key_list)
1332 MPlist *top, *plist, *pl, *p;
1333 FontLayoutCategory *category = NULL;
1337 top = (MPlist *) mdatabase__load_for_keys (flt->mdb, key_list);
1339 top = (MPlist *) mdatabase_load (flt->mdb);
1342 if (! MPLIST_PLIST_P (top))
1344 M17N_OBJECT_UNREF (top);
1345 MERROR (MERROR_FLT, -1);
1350 plist = mdatabase__props (flt->mdb);
1352 MERROR (MERROR_FLT, -1);
1353 MPLIST_DO (plist, plist)
1354 if (MPLIST_PLIST_P (plist))
1356 pl = MPLIST_PLIST (plist);
1357 if (! MPLIST_SYMBOL_P (pl)
1358 || MPLIST_SYMBOL (pl) != Mfont)
1360 pl = MPLIST_NEXT (pl);
1361 if (! MPLIST_PLIST_P (pl))
1363 p = MPLIST_PLIST (pl);
1364 if (! MPLIST_SYMBOL_P (p))
1366 p = MPLIST_NEXT (p);
1367 if (! MPLIST_SYMBOL_P (p))
1369 flt->family = MPLIST_SYMBOL (p);
1370 MPLIST_DO (p, MPLIST_NEXT (p))
1371 if (MPLIST_SYMBOL_P (p))
1373 sym = MPLIST_SYMBOL (p);
1374 if (MSYMBOL_NAME (sym)[0] != ':')
1375 flt->registry = sym, sym = Mnil;
1381 char *otf_spec = MSYMBOL_NAME (sym);
1383 if (otf_spec[0] == ':' && otf_spec[1] == 'o'
1384 && otf_spec[2] == 't' && otf_spec[3] == 'f')
1385 parse_otf_command (sym, &flt->otf);
1390 MPLIST_DO (plist, top)
1392 if (MPLIST_SYMBOL_P (plist)
1393 && MPLIST_SYMBOL (plist) == Mend)
1395 mplist_set (plist, Mnil, NULL);
1398 if (! MPLIST_PLIST (plist))
1400 pl = MPLIST_PLIST (plist);
1401 if (! MPLIST_SYMBOL_P (pl))
1403 sym = MPLIST_SYMBOL (pl);
1404 pl = MPLIST_NEXT (pl);
1407 if (sym == Mcategory)
1410 unref_category_table (category);
1411 else if (flt->coverage)
1413 category = flt->coverage;
1414 ref_category_table (category);
1417 category = load_category_table (pl, NULL);
1420 if (! flt->coverage)
1422 flt->coverage = category;
1423 ref_category_table (category);
1425 if (category->definition)
1426 flt->need_config = 1;
1428 else if (sym == Mgenerator)
1430 FontLayoutStage *stage;
1434 stage = load_generator (pl);
1437 stage->category = category;
1438 M17N_OBJECT_REF (category->table);
1440 flt->stages = mplist ();
1441 mplist_add (flt->stages, Mt, stage);
1445 unref_category_table (category);
1447 if (! MPLIST_TAIL_P (plist))
1449 M17N_OBJECT_UNREF (top);
1450 M17N_OBJECT_UNREF (flt->stages);
1451 MERROR (MERROR_FLT, -1);
1453 M17N_OBJECT_UNREF (top);
1459 free_flt_stage (MFLT *flt, FontLayoutStage *stage)
1463 unref_category_table (stage->category);
1466 for (i = 0; i < stage->used; i++)
1467 free_flt_command (stage->cmds + i);
1468 MLIST_FREE1 (stage, cmds);
1480 MPLIST_DO (plist, flt_list)
1482 MFLT *flt = MPLIST_VAL (plist);
1485 unref_category_table (flt->coverage);
1488 MPLIST_DO (pl, MPLIST_NEXT (flt->stages))
1489 free_flt_stage (flt, MPLIST_VAL (pl));
1490 M17N_OBJECT_UNREF (flt->stages);
1493 MPLIST_VAL (plist) = NULL;
1495 M17N_OBJECT_UNREF (flt_list);
1502 MPlist *plist, *key_list = NULL;
1506 if (! (plist = mdatabase_list (Mfont, Mlayouter, Mnil, Mnil)))
1508 if (! (flt_list = mplist ()))
1510 if (! (key_list = mplist ()))
1512 if (! mplist_add (key_list, Mcategory, Mt))
1515 MPLIST_DO (pl, plist)
1517 MDatabase *mdb = MPLIST_VAL (pl);
1518 MSymbol *tags = mdatabase_tag (mdb);
1521 if (! MSTRUCT_CALLOC_SAFE (flt))
1523 flt->name = tags[2];
1525 if (load_flt (flt, key_list) < 0)
1529 if (MPLIST_TAIL_P (flt_list))
1531 flt_min_coverage = mchartable_min_char (flt->coverage->table);
1532 flt_max_coverage = mchartable_max_char (flt->coverage->table);
1538 c = mchartable_min_char (flt->coverage->table);
1539 if (flt_min_coverage > c)
1540 flt_min_coverage = c;
1541 c = mchartable_max_char (flt->coverage->table);
1542 if (flt_max_coverage < c)
1543 flt_max_coverage = c;
1545 if (! mplist_push (flt_list, flt->name, flt))
1555 M17N_OBJECT_UNREF (plist);
1556 M17N_OBJECT_UNREF (key_list);
1560 /* FLS (Font Layout Service) */
1562 /* Structure to hold information about a context of FLS. */
1566 /* Pointer to the current stage. */
1567 FontLayoutStage *stage;
1569 /* Pointer to the category table of the next stage or NULL if none. */
1570 FontLayoutCategory *category;
1572 /* Pointer to the font. */
1575 /* Input and output glyph string. */
1576 MFLTGlyphString *in, *out;
1578 /* Encode each character or code of a glyph by the current category
1579 table into this array. An element is a category letter used for
1580 a regular expression matching. */
1585 int cluster_begin_idx;
1586 int cluster_begin_pos;
1587 int cluster_end_pos;
1591 } FontLayoutContext;
1593 static int run_command (int, int, int, int, FontLayoutContext *);
1594 static int run_otf (int, MFLTOtfSpec *, int, int, FontLayoutContext *);
1595 static int try_otf (int, MFLTOtfSpec *, int, int, FontLayoutContext *);
1600 run_rule (int depth,
1601 FontLayoutCmdRule *rule, int from, int to, FontLayoutContext *ctx)
1603 int *saved_match_indices = ctx->match_indices;
1604 int match_indices[NMATCH * 2];
1607 int orig_from = from;
1608 int need_cluster_update = 0;
1610 if (rule->src_type == SRC_REGEX)
1612 regmatch_t pmatch[NMATCH];
1618 saved_code = ctx->encoded[to - ctx->encoded_offset];
1619 ctx->encoded[to - ctx->encoded_offset] = '\0';
1620 result = regexec (&(rule->src.re.preg),
1621 ctx->encoded + (from - ctx->encoded_offset),
1623 if (result == 0 && pmatch[0].rm_so == 0)
1625 if (MDEBUG_FLAG () > 2)
1626 MDEBUG_PRINT5 ("\n [FLT] %*s(REGEX \"%s\" \"%s\" %d", depth, "",
1627 rule->src.re.pattern,
1628 ctx->encoded + (from - ctx->encoded_offset),
1630 ctx->encoded[to - ctx->encoded_offset] = saved_code;
1631 for (i = 0; i < NMATCH; i++)
1633 if (pmatch[i].rm_so < 0)
1634 match_indices[i * 2] = match_indices[i * 2 + 1] = -1;
1637 match_indices[i * 2] = from + pmatch[i].rm_so;
1638 match_indices[i * 2 + 1] = from + pmatch[i].rm_eo;
1641 ctx->match_indices = match_indices;
1642 to = match_indices[1];
1646 ctx->encoded[to - ctx->encoded_offset] = saved_code;
1649 need_cluster_update = 1;
1651 else if (rule->src_type == SRC_SEQ)
1655 len = rule->src.seq.n_codes;
1656 if (len > (to - from))
1658 for (i = 0; i < len; i++)
1659 if (rule->src.seq.codes[i] != GREF (ctx->in, from + i)->c)
1664 if (MDEBUG_FLAG () > 2)
1665 MDEBUG_PRINT3 ("\n [FLT] %*s(SEQ 0x%X", depth, "",
1666 rule->src.seq.codes[0]);
1667 need_cluster_update = 1;
1669 else if (rule->src_type == SRC_RANGE)
1675 head = GREF (ctx->in, from)->c;
1676 if (head < rule->src.range.from || head > rule->src.range.to)
1678 ctx->code_offset = head - rule->src.range.from;
1680 if (MDEBUG_FLAG () > 2)
1681 MDEBUG_PRINT4 ("\n [FLT] %*s(RANGE 0x%X-0x%X", depth, "",
1682 rule->src.range.from, rule->src.range.to);
1683 need_cluster_update = 1;
1685 else if (rule->src_type == SRC_INDEX)
1687 if (rule->src.match_idx >= NMATCH)
1689 from = ctx->match_indices[rule->src.match_idx * 2];
1692 to = ctx->match_indices[rule->src.match_idx * 2 + 1];
1693 if (MDEBUG_FLAG () > 2)
1694 MDEBUG_PRINT3 ("\n [FLT] %*s(SUBPART %d", depth, "",
1695 rule->src.match_idx);
1696 need_cluster_update = 1;
1698 else if (rule->src_type == SRC_HAS_GLYPH
1699 || rule->src_type == SRC_OTF_SPEC)
1701 static MFLTGlyphString gstring;
1705 if (rule->src.facility.len > 0)
1707 if (! gstring.glyph_size)
1709 gstring.glyph_size = ctx->in->glyph_size;
1710 gstring.glyphs = calloc (rule->src.facility.len,
1711 gstring.glyph_size);
1712 gstring.allocated = rule->src.facility.len;
1713 gstring.used = rule->src.facility.len;
1715 else if (rule->src.facility.len < gstring.allocated)
1717 gstring.glyphs = realloc (gstring.glyphs,
1719 * rule->src.facility.len);
1720 gstring.allocated = rule->src.facility.len;
1721 gstring.used = rule->src.facility.len;
1724 for (i = 0, p = rule->src.facility.codes, idx = from;
1725 i < rule->src.facility.len; i++, p = MPLIST_NEXT (p))
1727 if (MPLIST_INTEGER_P (p))
1729 GREF (&gstring, i)->c = MPLIST_INTEGER (p);
1730 GREF (&gstring, i)->encoded = 0;
1734 GREF (&gstring, i)->c = GREF (ctx->in, idx)->code;
1735 GREF (&gstring, i)->encoded = GREF (ctx->in, idx)->encoded;
1741 if (MDEBUG_FLAG () > 2)
1743 if (rule->src_type == SRC_HAS_GLYPH)
1744 MDEBUG_PRINT2 ("\n [FLT] %*s(HAS-GLYPH", depth, "");
1746 MDEBUG_PRINT2 ("\n [FLT] %*s(OTF-SPEC", depth, "");
1747 for (i = 0; i < rule->src.facility.len; i++)
1748 MDEBUG_PRINT1 (" %04X", GREF (&gstring, i)->code);
1750 if (ctx->font->get_glyph_id (ctx->font, &gstring, 0,
1751 rule->src.facility.len) < 0)
1753 MDEBUG_PRINT (") FAIL!");
1756 if (rule->src_type == SRC_OTF_SPEC)
1758 MFLTOtfSpec *spec = &rule->src.facility.otf_spec;
1760 if (! ctx->font->check_otf)
1762 if ((spec->features[0] && spec->features[0][0] != 0xFFFFFFFF)
1763 || (spec->features[1] && spec->features[1][0] != 0xFFFFFFFF))
1768 if (rule->src.facility.len == 0)
1770 if (! ctx->font->check_otf (ctx->font, spec))
1775 int prev_out_used = ctx->out->used, out_used;
1776 MFLTGlyphAdjustment *adjustment;
1778 adjustment = alloca ((sizeof *adjustment)
1779 * (ctx->out->allocated - ctx->out->used));
1781 MERROR (MERROR_FLT, -1);
1782 memset (adjustment, 0,
1783 (sizeof *adjustment)
1784 * (ctx->out->allocated - ctx->out->used));
1785 ctx->font->drive_otf (ctx->font, &rule->src.facility.otf_spec,
1786 &gstring, 0, rule->src.facility.len,
1789 out_used = ctx->out->used;
1790 ctx->out->used = prev_out_used;
1791 if (rule->src.facility.len == out_used - prev_out_used)
1793 for (i = prev_out_used; i < out_used; i++)
1795 if (GREF (&gstring, i - prev_out_used)->code
1796 != GREF (ctx->out, i)->code)
1798 if (adjustment[i - prev_out_used].set)
1809 if (need_cluster_update && ctx->cluster_begin_idx >= 0)
1811 for (i = from; i < to; i++)
1813 MFLTGlyph *g = GREF (ctx->in, i);
1814 UPDATE_CLUSTER_RANGE (ctx, g);
1820 for (i = 0; i < rule->n_cmds; i++)
1824 if (rule->cmd_ids[i] == CMD_ID_REPEAT)
1830 pos = run_command (depth, rule->cmd_ids[i], from, to, ctx);
1833 consumed = pos > from;
1838 ctx->match_indices = saved_match_indices;
1839 if (MDEBUG_FLAG () > 2)
1841 return (rule->src_type == SRC_INDEX ? orig_from : to);
1845 run_cond (int depth,
1846 FontLayoutCmdCond *cond, int from, int to, FontLayoutContext *ctx)
1850 if (MDEBUG_FLAG () > 2)
1851 MDEBUG_PRINT2 ("\n [FLT] %*s(COND", depth, "");
1853 for (i = 0; i < cond->n_cmds; i++)
1855 /* TODO: Write a code for optimization utilizaing the info
1857 if ((pos = run_command (depth, cond->cmd_ids[i], from, to, ctx))
1863 if (MDEBUG_FLAG () > 2)
1869 decode_packed_otf_tag (FontLayoutContext *ctx, MFLTGlyphString *gstring,
1870 int from, int to, FontLayoutCategory *category)
1872 for (; from < to; from++)
1874 MFLTGlyph *g = GREF (gstring, from);
1875 unsigned int tag = g->internal & 0xFFFFFFF;
1878 if (GET_COMBINED (g))
1882 SET_CATEGORY_CODE (g, 0);
1885 if (tag & 0xFFFFF80)
1889 /* Clear the feature tag code. */
1890 g->internal &= ~0xFFFFFFF;
1891 for (i = 0, enc = '\0'; i < category->feature_table.size; i++)
1892 if (category->feature_table.tag[i] == tag)
1894 enc = category->feature_table.code[i];
1895 if (ctx->in == gstring)
1896 ctx->encoded[from - ctx->encoded_offset] = enc;
1903 enc = g->c > 0 ? (int) mchartable_lookup (category->table, g->c) : 1;
1904 SET_CATEGORY_CODE (g, enc);
1910 MFLTOtfSpec *otf_spec, int from, int to, FontLayoutContext *ctx)
1912 MFLTFont *font = ctx->font;
1913 int from_idx = ctx->out->used;
1915 if (MDEBUG_FLAG () > 2)
1916 MDEBUG_PRINT3 ("\n [FLT] %*s%s", depth, "", MSYMBOL_NAME (otf_spec->sym));
1918 font->get_glyph_id (font, ctx->in, from, to);
1919 if (! font->drive_otf)
1921 if (ctx->out->used + (to - from) > ctx->out->allocated)
1923 font->get_metrics (font, ctx->in, from, to);
1924 GCPY (ctx->in, from, to - from, ctx->out, ctx->out->used);
1925 ctx->out->used += to - from;
1929 MFLTGlyphAdjustment *adjustment;
1933 adjustment = alloca ((sizeof *adjustment)
1934 * (ctx->out->allocated - ctx->out->used));
1936 MERROR (MERROR_FLT, -1);
1937 memset (adjustment, 0,
1938 (sizeof *adjustment) * (ctx->out->allocated - ctx->out->used));
1939 to = font->drive_otf (font, otf_spec, ctx->in, from, to, ctx->out,
1943 decode_packed_otf_tag (ctx, ctx->out, from_idx, ctx->out->used,
1945 out_len = ctx->out->used - from_idx;
1946 if (otf_spec->features[1])
1948 MFLTGlyphAdjustment *a;
1951 for (i = 0, a = adjustment; i < out_len; i++, a++)
1956 font->get_metrics (font, ctx->out, from_idx, ctx->out->used);
1957 for (g = GREF (ctx->out, from_idx + i);
1958 i < out_len; i++, a++, g = NEXT (ctx->out, g))
1961 if (a->advance_is_absolute)
1966 else if (a->xadv || a->yadv)
1971 if (a->xoff || a->yoff || a->back)
1974 MFLTGlyph *gg = PREV (ctx->out, g);
1975 MFLTGlyphAdjustment *aa = a;
1979 g->lbearing += a->xoff;
1980 g->rbearing += a->xoff;
1981 g->ascent -= a->yoff;
1982 g->descent -= a->yoff;
1983 while (aa->back > 0)
1985 for (j = 0; j < aa->back;
1986 j++, gg = PREV (ctx->out, gg))
1988 g->xoff -= gg->xadv;
1989 g->lbearing -= gg->xadv;
1990 g->rbearing -= gg->xadv;
1993 g->xoff += aa->xoff;
1994 g->yoff += aa->yoff;
1995 g->lbearing += aa->xoff;
1996 g->rbearing += aa->xoff;
1997 g->ascent -= aa->yoff;
1998 g->descent -= aa->yoff;
2007 if (ctx->cluster_begin_idx >= 0)
2008 for (; from_idx < ctx->out->used; from_idx++)
2010 MFLTGlyph *g = GREF (ctx->out, from_idx);
2011 UPDATE_CLUSTER_RANGE (ctx, g);
2017 try_otf (int depth, MFLTOtfSpec *otf_spec, int from, int to,
2018 FontLayoutContext *ctx)
2020 MFLTFont *font = ctx->font;
2022 if (MDEBUG_FLAG () > 2)
2023 MDEBUG_PRINT3 ("\n [FLT] %*s%s", depth, "", MSYMBOL_NAME (otf_spec->sym));
2025 if (! otf_spec->features[0] && ! otf_spec->features[1])
2027 /* Reset categories. */
2028 MCharTable *table = ctx->category->table;
2031 for (i = from; i < to; i++)
2033 MFLTGlyph *g = GREF (ctx->in, i);
2035 if (! GET_COMBINED (g))
2037 char enc = (GET_ENCODED (g)
2038 ? (g->c > 0 ? (int) mchartable_lookup (table, g->c)
2041 ? (int) mchartable_lookup (table, g->code)
2043 SET_CATEGORY_CODE (g, enc);
2044 ctx->encoded[i - ctx->encoded_offset] = enc;
2050 if (ctx->stage->category->feature_table.size == 0)
2053 font->get_glyph_id (font, ctx->in, from, to);
2056 to = mflt_try_otf (font, otf_spec, ctx->in, from, to);
2059 decode_packed_otf_tag (ctx, ctx->in, from, to, ctx->stage->category);
2064 static char work[16];
2067 dump_combining_code (int code)
2069 char *vallign = "tcbB";
2070 char *hallign = "lcr";
2076 work[0] = vallign[COMBINING_CODE_BASE_Y (code)];
2077 work[1] = hallign[COMBINING_CODE_BASE_X (code)];
2078 off_y = COMBINING_CODE_OFF_Y (code);
2079 off_x = COMBINING_CODE_OFF_X (code);
2081 sprintf (work + 2, "+%d", off_y);
2083 sprintf (work + 2, "%d", off_y);
2084 else if (off_x == 0)
2085 sprintf (work + 2, ".");
2086 p = work + strlen (work);
2088 sprintf (p, ">%d", off_x);
2090 sprintf (p, "<%d", -off_x);
2092 p[0] = vallign[COMBINING_CODE_ADD_Y (code)];
2093 p[1] = hallign[COMBINING_CODE_ADD_X (code)];
2099 run_command (int depth, int id, int from, int to, FontLayoutContext *ctx)
2106 MCharTable *table = ctx->category ? ctx->category->table : NULL;
2109 /* Direct code (== ctx->code_offset + id) output.
2110 The source is not consumed. */
2111 if (MDEBUG_FLAG () > 2)
2112 MDEBUG_PRINT3 ("\n [FLT] %*s(DIRECT 0x%X", depth, "",
2113 ctx->code_offset + id);
2114 i = (from < to || from == 0) ? from : from - 1;
2116 g = GREF (ctx->out, ctx->out->used - 1);
2117 g->c = g->code = ctx->code_offset + id;
2118 if (ctx->combining_code)
2119 SET_COMBINING_CODE (g, ctx, ctx->combining_code);
2122 enc = (GET_ENCODED (g)
2123 ? (g->c > 0 ? (int) mchartable_lookup (table, g->c) : 1)
2125 ? (int) mchartable_lookup (table, g->code)
2127 SET_CATEGORY_CODE (g, enc);
2130 SET_MEASURED (g, 0);
2131 if (ctx->left_padding)
2132 SET_LEFT_PADDING (g, ctx, LeftPaddingMask);
2133 for (i = from; i < to; i++)
2135 MFLTGlyph *tmp = GREF (ctx->in, i);
2137 if (g->from > tmp->from)
2138 g->from = tmp->from;
2139 else if (g->to < tmp->to)
2142 if (ctx->cluster_begin_idx >= 0)
2143 UPDATE_CLUSTER_RANGE (ctx, g);
2144 ctx->code_offset = ctx->combining_code = ctx->left_padding = 0;
2145 if (MDEBUG_FLAG () > 2)
2150 if (id <= CMD_ID_OFFSET_INDEX)
2152 int idx = CMD_ID_TO_INDEX (id);
2155 if (idx >= ctx->stage->used)
2156 MERROR (MERROR_DRAW, -1);
2157 cmd = ctx->stage->cmds + idx;
2158 if (cmd->type == FontLayoutCmdTypeRule)
2159 to = run_rule (depth, &cmd->body.rule, from, to, ctx);
2160 else if (cmd->type == FontLayoutCmdTypeCond)
2161 to = run_cond (depth, &cmd->body.cond, from, to, ctx);
2162 else if (cmd->type == FontLayoutCmdTypeOTF)
2163 to = run_otf (depth, &cmd->body.otf, from, to, ctx);
2164 else if (cmd->type == FontLayoutCmdTypeOTFCategory)
2165 to = try_otf (depth, &cmd->body.otf, from, to, ctx);
2169 if (id <= CMD_ID_OFFSET_COMBINING)
2171 ctx->combining_code = CMD_ID_TO_COMBINING_CODE (id);
2172 if (MDEBUG_FLAG () > 2)
2173 MDEBUG_PRINT3 ("\n [FLT] %*s(CMB %s)", depth, "",
2174 dump_combining_code (ctx->combining_code));
2185 g = GREF (ctx->out, ctx->out->used - 1);
2186 if (ctx->combining_code)
2187 SET_COMBINING_CODE (g, ctx, ctx->combining_code);
2188 if (ctx->left_padding)
2189 SET_LEFT_PADDING (g, ctx, LeftPaddingMask);
2190 if (ctx->cluster_begin_idx >= 0)
2191 UPDATE_CLUSTER_RANGE (ctx, g);
2192 if (MDEBUG_FLAG () > 2)
2195 MDEBUG_PRINT2 ("\n [FLT] %*s(COPY |)", depth, "");
2197 MDEBUG_PRINT3 ("\n [FLT] %*s(COPY 0x%X)", depth, "", g->c);
2199 ctx->code_offset = ctx->combining_code = ctx->left_padding = 0;
2203 case CMD_ID_CLUSTER_BEGIN:
2204 if (ctx->cluster_begin_idx < 0)
2206 if (MDEBUG_FLAG () > 2)
2207 MDEBUG_PRINT3 ("\n [FLT] %*s<%d", depth, "",
2208 GREF (ctx->in, from)->from);
2209 ctx->cluster_begin_idx = ctx->out->used;
2210 ctx->cluster_begin_pos = GREF (ctx->in, from)->from;
2211 ctx->cluster_end_pos = GREF (ctx->in, from)->to;
2215 case CMD_ID_CLUSTER_END:
2216 if (ctx->cluster_begin_idx >= 0
2217 && ctx->cluster_begin_idx < ctx->out->used)
2221 if (MDEBUG_FLAG () > 2)
2222 MDEBUG_PRINT1 (" %d>", ctx->cluster_end_pos + 1);
2223 for (i = ctx->cluster_begin_idx; i < ctx->out->used; i++)
2225 GREF (ctx->out, i)->from = ctx->cluster_begin_pos;
2226 GREF (ctx->out, i)->to = ctx->cluster_end_pos;
2228 ctx->cluster_begin_idx = -1;
2232 case CMD_ID_SEPARATOR:
2236 i = from < to ? from : from - 1;
2238 g = GREF (ctx->out, ctx->out->used - 1);
2239 g->c = -1, g->code = 0;
2240 g->xadv = g->yadv = 0;
2242 SET_MEASURED (g, 0);
2243 SET_CATEGORY_CODE (g, ' ');
2247 case CMD_ID_LEFT_PADDING:
2248 if (MDEBUG_FLAG () > 2)
2249 MDEBUG_PRINT2 ("\n [FLT] %*s[", depth, "");
2250 ctx->left_padding = 1;
2253 case CMD_ID_RIGHT_PADDING:
2254 if (ctx->out->used > 0)
2256 if (MDEBUG_FLAG () > 2)
2257 MDEBUG_PRINT2 ("\n [FLT] %*s]", depth, "");
2258 g = GREF (ctx->out, ctx->out->used - 1);
2259 SET_RIGHT_PADDING (g, ctx, RightPaddingMask);
2264 MERROR (MERROR_DRAW, -1);
2268 run_stages (MFLTGlyphString *gstring, int from, int to,
2269 MFLT *flt, FontLayoutContext *ctx)
2271 MFLTGlyphString buf, *temp;
2273 int orig_from = from, orig_to = to;
2274 int from_pos, to_pos, len;
2277 MPlist *stages = flt->stages;
2278 FontLayoutCategory *prev_category = NULL;
2280 from_pos = GREF (ctx->in, from)->from;
2281 to_pos = GREF (ctx->in, to - 1)->to;
2282 len = to_pos - from_pos;
2286 GINIT (ctx->out, ctx->out->allocated);
2287 ctx->encoded = alloca (ctx->out->allocated);
2288 if (! ctx->out->glyphs || ! ctx->encoded)
2291 for (stage_idx = 0; 1; stage_idx++)
2296 ctx->stage = (FontLayoutStage *) MPLIST_VAL (stages);
2297 table = ctx->stage->category->table;
2298 stages = MPLIST_NEXT (stages);
2299 if (MPLIST_TAIL_P (stages))
2300 ctx->category = NULL;
2302 ctx->category = ((FontLayoutStage *) MPLIST_VAL (stages))->category;
2303 ctx->code_offset = ctx->combining_code = ctx->left_padding = 0;
2304 ctx->encoded_offset = from;
2305 for (i = from; i < to; i++)
2307 MFLTGlyph *g = GREF (ctx->in, i);
2310 if (GET_COMBINED (g)
2311 || (prev_category && prev_category != ctx->stage->category))
2313 enc = (GET_ENCODED (g)
2314 ? (g->c > 0 ? (int) mchartable_lookup (table, g->c) : 1)
2316 ? (int) mchartable_lookup (table, g->code)
2318 if (! GET_COMBINED (g))
2319 SET_CATEGORY_CODE (g, enc);
2322 enc = GET_CATEGORY_CODE (g);
2323 ctx->encoded[i - from] = enc;
2324 if (! enc && stage_idx == 0)
2330 ctx->encoded[i - from] = '\0';
2331 ctx->match_indices[0] = from;
2332 ctx->match_indices[1] = to;
2333 for (i = 2; i < NMATCH; i++)
2334 ctx->match_indices[i] = -1;
2336 if (MDEBUG_FLAG () > 2)
2338 MDEBUG_PRINT2 ("\n [FLT] (STAGE %d \"%s\"", stage_idx,
2340 MDEBUG_PRINT (" (");
2341 for (i = from; i < to; i++)
2343 g = GREF (ctx->in, i);
2345 MDEBUG_PRINT2 ("%*s|", (i > 0), "");
2347 MDEBUG_PRINT3 ("%*s%04X", (i > 0), "", GREF (ctx->in, i)->code);
2351 result = run_command (4, INDEX_TO_CMD_ID (0), from, to, ctx);
2352 if (MDEBUG_FLAG () > 2)
2357 /* If this is the last stage, break the loop. */
2358 if (MPLIST_TAIL_P (stages))
2361 /* Otherwise, prepare for the next stage. */
2362 prev_category = ctx->stage->category;
2369 GINIT (&buf, ctx->out->allocated);
2378 if (ctx->out->used > 0)
2381 int x_ppem = ctx->font->x_ppem << 6, y_ppem = ctx->font->y_ppem << 6;
2383 /* Remove separator glyphs. */
2384 for (i = 0; i < ctx->out->used;)
2386 g = GREF (ctx->out, i);
2388 GREPLACE (NULL, 0, 0, ctx->out, i, i + 1);
2393 /* Get actual glyph IDs of glyphs. */
2394 ctx->font->get_glyph_id (ctx->font, ctx->out, 0, ctx->out->used);
2396 /* Check if all characters in the range are covered by some
2397 glyph(s). If not, change <from> and <to> of glyphs to cover
2398 uncovered characters. */
2399 g_indices = alloca (sizeof (int) * len);
2402 for (i = 0; i < len; i++) g_indices[i] = -1;
2403 for (i = 0; i < ctx->out->used; i++)
2407 g = GREF (ctx->out, i);
2408 for (pos = g->from; pos <= g->to; pos++)
2409 if (g_indices[pos - from_pos] < 0)
2410 g_indices[pos - from_pos] = i;
2412 for (i = 0; i < len; i++)
2413 if (g_indices[i] < 0)
2419 for (i++; i < len && g_indices[i] < 0; i++);
2421 g = GREF (ctx->out, j);
2422 this_from = g->from;
2424 g->from = orig_from + i;
2425 } while (++j < ctx->out->used
2426 && (g = GREF (ctx->out, j))
2427 && g->from == this_from);
2433 j = g_indices[i - 1];
2434 g = GREF (ctx->out, j);
2437 g->to = orig_from + i + 1;
2439 && (g = GREF (ctx->out, j))
2440 && g->to == this_to);
2444 ctx->font->get_metrics (ctx->font, ctx->out, 0, ctx->out->used);
2446 /* Handle combining. */
2447 if (ctx->check_mask & CombinedMask)
2449 MFLTGlyph *base = GREF (ctx->out, 0);
2450 int base_height = base->ascent + base->descent;
2451 int base_width = base->rbearing - base->lbearing;
2454 for (i = 1; i < ctx->out->used; i++)
2456 if ((g = GREF (ctx->out, i))
2458 && (combining_code = GET_COMBINING_CODE (g)))
2460 int height = g->ascent + g->descent;
2461 int width = g->rbearing - g->lbearing;
2462 int base_x, base_y, add_x, add_y, off_x, off_y;
2464 if (base->from > g->from)
2465 base->from = g->from;
2466 else if (base->to < g->to)
2469 base_x = COMBINING_CODE_BASE_X (combining_code);
2470 base_y = COMBINING_CODE_BASE_Y (combining_code);
2471 add_x = COMBINING_CODE_ADD_X (combining_code);
2472 add_y = COMBINING_CODE_ADD_Y (combining_code);
2473 off_x = COMBINING_CODE_OFF_X (combining_code);
2474 off_y = COMBINING_CODE_OFF_Y (combining_code);
2476 g->xoff = ((base_width * base_x - width * add_x) / 2
2477 + x_ppem * off_x / 100
2478 - (base->xadv - base->lbearing) - g->lbearing);
2480 g->yoff = base_height * base_y / 2 - base->ascent;
2484 g->yoff -= height * add_y / 2 - g->ascent;
2485 g->yoff -= y_ppem * off_y / 100;
2486 if (base->lbearing > base->xadv + g->lbearing + g->xoff)
2487 base->lbearing = base->xadv + g->lbearing + g->xoff;
2488 if (base->rbearing < base->xadv + g->rbearing + g->xoff)
2489 base->rbearing = base->xadv + g->rbearing + g->xoff;
2490 if (base->ascent < g->ascent - g->yoff)
2491 base->ascent = g->ascent - g->yoff;
2492 if (base->descent < g->descent - g->yoff)
2493 base->descent = g->descent - g->yoff;
2494 g->xadv = g->yadv = 0;
2495 if (GET_RIGHT_PADDING (g))
2496 SET_RIGHT_PADDING (base, ctx, RightPaddingMask);
2502 base_height = g->ascent + g->descent;
2503 base_width = g->rbearing - g->lbearing;
2508 /* Handle padding */
2509 if (ctx->check_mask & (LeftPaddingMask | RightPaddingMask))
2510 for (i = 0; i < ctx->out->used; i++)
2512 g = GREF (ctx->out, i);
2513 if (! GET_COMBINED (g))
2515 if (GET_RIGHT_PADDING (g) && g->rbearing > g->xadv)
2517 g->xadv = g->rbearing;
2520 if (GET_LEFT_PADDING (g) && g->lbearing < 0)
2522 g->xoff += - g->lbearing;
2523 g->xadv += - g->lbearing;
2524 g->rbearing += - g->lbearing;
2532 GREPLACE (ctx->out, 0, ctx->out->used, gstring, orig_from, orig_to);
2533 to = orig_from + ctx->out->used;
2538 setup_combining_coverage (int from, int to, void *val, void *arg)
2540 int combining_class = (int) val;
2543 if (combining_class < 200)
2545 else if (combining_class <= 204)
2547 if ((combining_class % 2) == 0)
2548 category = "bcd"[(combining_class - 200) / 2];
2550 else if (combining_class <= 232)
2552 if ((combining_class % 2) == 0)
2553 category = "efghijklmnopq"[(combining_class - 208) / 2];
2555 else if (combining_class == 233)
2557 else if (combining_class == 234)
2559 else if (combining_class == 240)
2561 mchartable_set_range ((MCharTable *) arg, from, to, (void *) category);
2565 setup_combining_flt (MFLT *flt)
2568 MCharTable *combininig_class_table
2569 = mchar_get_prop_table (Mcombining_class, &type);
2571 mchartable_set_range (flt->coverage->table, 0, 0x10FFFF, (void *) 'u');
2572 if (combininig_class_table)
2573 mchartable_map (combininig_class_table, (void *) 0,
2574 setup_combining_coverage, flt->coverage->table);
2577 #define CHECK_FLT_STAGES(flt) ((flt)->stages || load_flt (flt, NULL) == 0)
2579 static FontLayoutCategory *
2580 configure_category (FontLayoutCategory *category, MFLTFont *font)
2582 if (! mflt_font_id || ! mflt_iterate_otf_feature)
2584 FontLayoutCategory *new = malloc (sizeof (FontLayoutCategory));
2585 new->definition = NULL;
2586 new->table = category->table;
2587 M17N_OBJECT_REF (new->table);
2590 return load_category_table (category->definition, font);
2594 configure_flt (MFLT *flt, MFLTFont *font, MSymbol font_id)
2599 if (! mflt_font_id || ! mflt_iterate_otf_feature)
2601 MPLIST_DO (plist, flt_list)
2603 configured = MPLIST_VAL (plist);
2604 if (! configured->font_id)
2606 if (configured->name == flt->name
2607 && configured->font_id == font_id)
2610 if (! MSTRUCT_CALLOC_SAFE (configured))
2613 configured->stages = mplist_copy (flt->stages);
2614 MPLIST_DO (plist, configured->stages)
2616 FontLayoutStage *stage = MPLIST_VAL (plist);
2617 if (stage->category->definition)
2619 MSTRUCT_CALLOC (stage, MERROR_FLT);
2620 *stage = *((FontLayoutStage *) MPLIST_VAL (plist));
2621 stage->category = configure_category (stage->category, font);
2622 MPLIST_VAL (plist) = stage;
2625 M17N_OBJECT_REF (stage->category->table);
2627 configured->need_config = 0;
2628 configured->font_id = font_id;
2629 mplist_push (flt_list, flt->name, configured);
2635 int m17n__flt_initialized;
2640 /* The following two are actually not exposed to a user but concealed
2641 by the macro M17N_INIT (). */
2644 m17n_init_flt (void)
2646 int mdebug_flag = MDEBUG_INIT;
2648 merror_code = MERROR_NONE;
2649 if (m17n__flt_initialized++)
2652 if (merror_code != MERROR_NONE)
2654 m17n__flt_initialized--;
2658 MDEBUG_PUSH_TIME ();
2660 Mcond = msymbol ("cond");
2661 Mrange = msymbol ("range");
2662 Mfont = msymbol ("font");
2663 Mlayouter = msymbol ("layouter");
2664 Mcombining = msymbol ("combining");
2665 Mfont_facility = msymbol ("font-facility");
2666 Mequal = msymbol ("=");
2667 Mgenerator = msymbol ("generator");
2668 Mend = msymbol ("end");
2670 mflt_enable_new_feature = 0;
2671 mflt_iterate_otf_feature = NULL;
2672 mflt_font_id = NULL;
2673 mflt_try_otf = NULL;
2675 MDEBUG_PRINT_TIME ("INIT", (mdebug__output, " to initialize the flt modules."));
2680 m17n_fini_flt (void)
2682 int mdebug_flag = MDEBUG_FINI;
2684 if (m17n__flt_initialized == 0
2685 || --m17n__flt_initialized > 0)
2688 MDEBUG_PUSH_TIME ();
2690 MDEBUG_PRINT_TIME ("FINI", (mdebug__output, " to finalize the flt modules."));
2696 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
2698 /*** @addtogroup m17nFLT */
2704 @brief Return an FLT object that has a specified name.
2706 The mflt_get () function returns an FLT object whose name is $NAME.
2709 If the operation was successful, mflt_get () returns a pointer
2710 to the found FLT object. Otherwise, it returns @c NULL. */
2713 @brief »ØÄꤵ¤ì¤¿Ì¾Á°¤ò»ý¤Ä FLT ¥ª¥Ö¥¸¥§¥¯¥È¤òÊÖ¤¹.
2715 ´Ø¿ô mflt_get () ¤Ï¡¢$NAME ¤È¤¤¤¦Ì¾Á°¤ò»ý¤Ä FLT ¥ª¥Ö¥¸¥§¥¯¥È¤òÊÖ¤¹¡£
2718 ¤â¤·À®¸ù¤¹¤ì¤Ð¡¢mflt_get () ¤Ï¸«¤Ä¤«¤Ã¤¿ FLT
2719 ¥ª¥Ö¥¸¥§¥¯¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¼ºÇÔ¤·¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤¹¡£ */
2722 mflt_get (MSymbol name)
2727 if (! flt_list && list_flt () < 0)
2729 for (plist = flt_list; plist; plist = plist->next)
2730 if (((MFLT *) MPLIST_VAL (plist))->font_id == Mnil)
2732 flt = mplist_get (plist, name);
2733 if (! flt || ! CHECK_FLT_STAGES (flt))
2735 if (flt->name == Mcombining
2736 && ! mchartable_lookup (flt->coverage->table, 0))
2737 setup_combining_flt (flt);
2744 @brief Find an FLT suitable for the specified character and font.
2746 The mflt_find () function returns the most appropriate FLT for
2747 layouting character $C with font $FONT.
2750 If the operation was successful, mflt_find () returns a pointer
2751 to the found FLT object. Otherwise, it returns @c NULL. */
2754 @brief »ØÄꤵ¤ì¤¿Ê¸»ú¤È¥Õ¥©¥ó¥È¤Ë¹ç¤Ã¤¿ FLT ¤òõ¤¹.
2756 ´Ø¿ô mflt_find () ¤Ï¡¢Ê¸»ú $C ¤ò¥Õ¥©¥ó¥È $FONT
2757 ¤Ç¥ì¥¤¥¢¥¦¥È¤¹¤ë¤¿¤á¤ËºÇ¤âŬÀÚ¤Ê FLT ¤òÊÖ¤¹¡£
2760 ¤â¤·À®¸ù¤¹¤ì¤Ð¡¢mflt_find () ¤Ï¸«¤Ä¤«¤Ã¤¿ FLT
2761 ¥ª¥Ö¥¸¥§¥¯¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¼ºÇÔ¤·¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤¹¡£ */
2764 mflt_find (int c, MFLTFont *font)
2768 static MSymbol unicode_bmp = NULL, unicode_full = NULL;
2772 unicode_bmp = msymbol ("unicode-bmp");
2773 unicode_full = msymbol ("unicode-full");
2776 if (! flt_list && list_flt () < 0)
2778 /* Skip configured FLTs. */
2779 MPLIST_DO (plist, flt_list)
2780 if (((MFLT *) MPLIST_VAL (plist))->font_id == Mnil)
2786 MPLIST_DO (pl, plist)
2788 flt = MPLIST_VAL (pl);
2789 if (flt->registry != unicode_bmp
2790 && flt->registry != unicode_full)
2792 if (flt->family && flt->family != font->family)
2794 if (flt->name == Mcombining
2795 && ! mchartable_lookup (flt->coverage->table, 0))
2796 setup_combining_flt (flt);
2798 && ! mchartable_lookup (flt->coverage->table, c))
2802 MFLTOtfSpec *spec = &flt->otf;
2804 if (! font->check_otf)
2806 if ((spec->features[0] && spec->features[0][0] != 0xFFFFFFFF)
2807 || (spec->features[1] && spec->features[1][0] != 0xFFFFFFFF))
2810 else if (! font->check_otf (font, spec))
2823 MPLIST_DO (pl, plist)
2825 flt = MPLIST_VAL (pl);
2826 if (mchartable_lookup (flt->coverage->table, c))
2833 if (! CHECK_FLT_STAGES (flt))
2835 if (font && flt->need_config && mflt_font_id)
2836 flt = configure_flt (flt, font, mflt_font_id (font));
2842 @brief Return the name of an FLT.
2844 The mflt_name () function returns the name of $FLT. */
2847 @brief FLT ¤Î̾Á°¤òÊÖ¤¹.
2849 ´Ø¿ô mflt_name () ¤Ï $FLT ¤Î̾Á°¤òÊÖ¤¹¡£ */
2852 mflt_name (MFLT *flt)
2854 return MSYMBOL_NAME (flt->name);
2859 @brief Return a coverage of a FLT.
2861 The mflt_coverage () function returns a char-table that contains
2862 nonzero values for characters supported by $FLT. */
2865 @brief FLT ¤ÎÈϰϤòÊÖ¤¹.
2867 ´Ø¿ô mflt_coverage () ¤Ï¡¢$FLT ¤¬¥µ¥Ý¡¼¥È¤¹¤ëʸ»ú¤ËÂФ·¤Æ
2868 0 ¤Ç¤Ê¤¤Ãͤò´Þ¤àʸ»ú¥Æ¡¼¥Ö¥ë¤òÊÖ¤¹¡£ */
2871 mflt_coverage (MFLT *flt)
2873 return flt->coverage->table;
2878 @brief Layout characters with an FLT.
2880 The mflt_run () function layouts characters in $GSTRING between
2881 $FROM (inclusive) and $TO (exclusive) with $FONT. If $FLT is
2882 nonzero, it is used for all the charaters. Otherwise, appropriate
2883 FLTs are automatically chosen.
2886 The operation was successful. The value is the index to the
2887 glyph, which was previously indexed by $TO, in $GSTRING->glyphs.
2890 $GSTRING->glyphs is too short to store the result. The caller can
2891 call this fucntion again with a longer $GSTRING->glyphs.
2894 Some other error occurred. */
2897 @brief FLT ¤ò»È¤Ã¤Æʸ»ú¤ò¥ì¥¤¥¢¥¦¥È¤¹¤ë.
2899 ´Ø¿ô mflt_run () ¤Ï¡¢$GSTRING Ãæ¤Î $FROM ¤«¤é $TO ľÁ°¤Þ¤Ç¤Îʸ»ú¤ò
2900 $FONT ¤òÍѤ¤¤Æ¥ì¥¤¥¢¥¦¥È¤¹¤ë¡£¤â¤· $FLT
2901 ¤¬¥¼¥í¤Ç¤Ê¤±¤ì¤Ð¡¢¤½¤ÎÃͤò¤¹¤Ù¤Æ¤Îʸ»ú¤ËÂФ·¤ÆÍѤ¤¤ë¡£
2902 ¤½¤¦¤Ç¤Ê¤±¤ì¤ÐŬÀÚ¤Ê FLT ¤ò¼«Æ°Åª¤ËÁªÂò¤¹¤ë¡£
2905 ¼Â¹ÔÀ®¸ù¤ò¼¨¤¹¡£ÊÖ¤µ¤ì¤ëÃͤϡ¢$GSTRING->glyphs Ãæ¤Ç°ÊÁ° $TO
2906 ¤Ë¤è¤Ã¤Æ¼¨¤µ¤ì¤Æ¤¤¤¿¥°¥ê¥Õ¤Ø¤Î¥¤¥ó¥Ç¥¯¥¹¤Ç¤¢¤ë¡£
2909 ·ë²Ì¤ò³ÊǼ¤¹¤ë¤Ë¤Ï $GSTRING->glyphs ¤¬Ã»¤¹¤®¤ë¤³¤È¤ò¼¨¤¹¡£
2910 ¸Æ¤Ó½Ð¤·Â¦¤Ï¡¢¤è¤êŤ¤ $GSTRING->glyphs
2911 ¤òÍѤ¤¤ÆºÆÅÙ¤³¤Î´Ø¿ô¤ò¸Æ¤Ö¤³¤È¤¬¤Ç¤¤ë¡£
2914 ¤½¤Î¾¤Î¥¨¥é¡¼¤¬µ¯¤¤¿¤³¤È¤ò¼¨¤¹¡£ */
2917 mflt_run (MFLTGlyphString *gstring, int from, int to,
2918 MFLTFont *font, MFLT *flt)
2920 FontLayoutContext ctx;
2921 int match_indices[NMATCH];
2923 MFLTGlyphString out;
2924 int auto_flt = ! flt;
2926 int this_from, this_to;
2927 MSymbol font_id = mflt_font_id ? mflt_font_id (font) : Mnil;
2931 /* This is usually sufficient, but if not, we retry with the larger
2932 values at most 3 times. This value is also used for the
2933 allocating size of ctx.encoded. */
2934 out.allocated = (to - from) * 4;
2936 for (i = from; i < to; i++)
2938 g = GREF (gstring, i);
2942 memset (g, 0, sizeof (MFLTGlyph));
2945 g->from = g->to = i;
2948 for (this_from = from; this_from < to;)
2952 for (this_to = this_from; this_to < to; this_to++)
2953 if (mchartable_lookup (flt->coverage->table,
2954 GREF (gstring, this_to)->c))
2959 if (! flt_list && list_flt () < 0)
2961 font->get_glyph_id (font, gstring, this_from, to);
2962 font->get_metrics (font, gstring, this_from, to);
2966 for (this_to = this_from; this_to < to; this_to++)
2968 c = GREF (gstring, this_to)->c;
2969 if (c >= flt_min_coverage && c <= flt_max_coverage)
2972 for (; this_to < to; this_to++)
2974 c = GREF (gstring, this_to)->c;
2976 && mchartable_lookup (((MFLT *) font->internal)->coverage->table, c))
2978 flt = font->internal;
2981 flt = mflt_find (c, font);
2984 if (CHECK_FLT_STAGES (flt))
2986 font->internal = flt;
2993 if (this_from < this_to)
2995 font->get_glyph_id (font, gstring, this_from, this_to);
2996 font->get_metrics (font, gstring, this_from, this_to);
2997 this_from = this_to;
3002 MDEBUG_PRINT1 (" [FLT] (%s", MSYMBOL_NAME (flt->name));
3004 if (flt->need_config && font_id != Mnil)
3005 flt = configure_flt (flt, font, font_id);
3007 for (; this_to < to; this_to++)
3010 g = GREF (gstring, this_to);
3011 enc = (int) mchartable_lookup (flt->coverage->table, g->c);
3014 SET_CATEGORY_CODE (g, enc);
3020 MDEBUG_PRINT1 (" (%s)", MSYMBOL_NAME (font->family));
3021 MDEBUG_PRINT ("\n [FLT] (SOURCE");
3022 for (i = this_from, j = 0; i < this_to; i++, j++)
3024 if (j > 0 && j % 8 == 0)
3025 MDEBUG_PRINT ("\n [FLT] ");
3026 MDEBUG_PRINT1 (" %04X", GREF (gstring, i)->c);
3031 for (i = 0; i < 3; i++)
3034 memset (&ctx, 0, sizeof ctx);
3035 ctx.match_indices = match_indices;
3037 ctx.cluster_begin_idx = -1;
3040 j = run_stages (gstring, this_from, this_to, flt, &ctx);
3054 MDEBUG_PRINT ("\n [FLT] (RESULT");
3055 if (MDEBUG_FLAG () > 1)
3056 for (i = 0; this_from < this_to; this_from++, i++)
3058 if (i > 0 && i % 4 == 0)
3059 MDEBUG_PRINT ("\n [FLT] ");
3060 g = GREF (gstring, this_from);
3061 MDEBUG_PRINT4 (" (%04X %d %d %d)",
3062 g->code, g->xadv, g->xoff, g->yoff);
3065 for (; this_from < this_to; this_from++)
3066 MDEBUG_PRINT1 (" %04X", GREF (gstring, this_from)->code);
3067 MDEBUG_PRINT ("))\n");
3069 this_from = this_to;
3074 int len = to - from;
3077 memcpy (((char *) out.glyphs),
3078 ((char *) gstring->glyphs) + gstring->glyph_size * from,
3079 gstring->glyph_size * len);
3080 for (i = from, j = to; i < to;)
3082 for (k = i + 1, j--; k < to && GREF (&out, k)->xadv == 0;
3084 GCPY (&out, i, (k - i), gstring, j);
3092 int mflt_enable_new_feature;
3094 int (*mflt_iterate_otf_feature) (struct _MFLTFont *font,
3097 unsigned char *table);
3099 MSymbol (*mflt_font_id) (struct _MFLTFont *font);
3101 int (*mflt_try_otf) (struct _MFLTFont *font, MFLTOtfSpec *spec,
3102 MFLTGlyphString *gstring, int from, int to);
3105 /* for debugging... */
3108 dump_flt_cmd (FontLayoutStage *stage, int id, int indent)
3110 char *prefix = (char *) alloca (indent + 1);
3112 memset (prefix, 32, indent);
3116 fprintf (mdebug__output, "0x%02X", id);
3117 else if (id <= CMD_ID_OFFSET_INDEX)
3119 int idx = CMD_ID_TO_INDEX (id);
3120 FontLayoutCmd *cmd = stage->cmds + idx;
3122 if (cmd->type == FontLayoutCmdTypeRule)
3124 FontLayoutCmdRule *rule = &cmd->body.rule;
3127 fprintf (mdebug__output, "(rule ");
3128 if (rule->src_type == SRC_REGEX)
3129 fprintf (mdebug__output, "\"%s\"", rule->src.re.pattern);
3130 else if (rule->src_type == SRC_INDEX)
3131 fprintf (mdebug__output, "%d", rule->src.match_idx);
3132 else if (rule->src_type == SRC_SEQ)
3133 fprintf (mdebug__output, "(seq)");
3134 else if (rule->src_type == SRC_RANGE)
3135 fprintf (mdebug__output, "(range)");
3137 fprintf (mdebug__output, "(invalid src)");
3139 for (i = 0; i < rule->n_cmds; i++)
3141 fprintf (mdebug__output, "\n%s ", prefix);
3142 dump_flt_cmd (stage, rule->cmd_ids[i], indent + 2);
3144 fprintf (mdebug__output, ")");
3146 else if (cmd->type == FontLayoutCmdTypeCond)
3148 FontLayoutCmdCond *cond = &cmd->body.cond;
3151 fprintf (mdebug__output, "(cond");
3152 for (i = 0; i < cond->n_cmds; i++)
3154 fprintf (mdebug__output, "\n%s ", prefix);
3155 dump_flt_cmd (stage, cond->cmd_ids[i], indent + 2);
3157 fprintf (mdebug__output, ")");
3159 else if (cmd->type == FontLayoutCmdTypeOTF)
3161 fprintf (mdebug__output, "(otf)");
3164 fprintf (mdebug__output, "(error-command)");
3166 else if (id <= CMD_ID_OFFSET_COMBINING)
3167 fprintf (mdebug__output, "cominging-code");
3169 fprintf (mdebug__output, "(predefiend %d)", id);
3173 @brief Dump a Font Layout Table.
3175 The mdebug_dump_flt () function prints the Font Layout Table $FLT
3176 in a human readable way to the stderr or to what specified by the
3177 environment variable MDEBUG_OUTPUT_FILE. $INDENT specifies how
3178 many columns to indent the lines but the first one.
3181 This function returns $FLT. */
3184 mdebug_dump_flt (MFLT *flt, int indent)
3186 char *prefix = (char *) alloca (indent + 1);
3190 memset (prefix, 32, indent);
3192 fprintf (mdebug__output, "(flt");
3193 MPLIST_DO (plist, flt->stages)
3195 FontLayoutStage *stage = (FontLayoutStage *) MPLIST_VAL (plist);
3198 fprintf (mdebug__output, "\n%s (stage %d", prefix, stage_idx);
3199 for (i = 0; i < stage->used; i++)
3201 fprintf (mdebug__output, "\n%s ", prefix);
3202 dump_flt_cmd (stage, INDEX_TO_CMD_ID (i), indent + 4);
3204 fprintf (mdebug__output, ")");
3207 fprintf (mdebug__output, ")");
3212 mflt_dump_gstring (MFLTGlyphString *gstring)
3216 fprintf (mdebug__output, "(flt-gstring");
3217 for (i = 0; i < gstring->used; i++)
3219 MFLTGlyph *g = GREF (gstring, i);
3220 fprintf (mdebug__output, "\n (%02d pos:%d-%d c:%04X code:%04X cat:%c)",
3221 i, g->from, g->to, g->c, g->code, GET_CATEGORY_CODE (g));
3223 fprintf (mdebug__output, ")\n");