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;
745 /* SYMBOL's name features[0] [1] for checking for applying
746 ------------- --------------- ------------ ------------
747 SCRIPT [0] [0] any|any all all
748 SCRIPT= NULL [0] none&1 none all
749 SCRIPT+ [0] NULL 1&none all none
750 SCRIPT=F1 [F1,0] [0] F1&1 F1 all
751 SCRIPT+F1 [0] [F1,0] none&F1 none F1
752 SCRIPT=F1+ [F1,0] NULL F1&none F1 none
753 SCRIPT=~F2 [-1,F2,0] [0] ~F2&1 all~F2 all
754 SCRIPT=F1,~F2 [F1,-1,A2,0][0] F1&~F2&1 F1 (*1) all
756 (*1) Invalid specification
760 parse_otf_command (MSymbol symbol, MFLTOtfSpec *spec)
762 char *str = MSYMBOL_NAME (symbol);
763 char *end = str + MSYMBOL_NAMELEN (symbol);
764 unsigned int script, langsys;
766 int feature_count[2]; /* [0]:GSUB, [1]:GPOS */
770 memset (spec, 0, sizeof (MFLTOtfSpec));
773 str += 5; /* skip the heading ":otf=" or ":otf?" */
776 if (! mflt_enable_new_feature)
777 /* The client can't use this command. */
780 /* This is a spec to reset category codes. */
783 spec->script = gen_otf_tag (str, 8);
787 spec->langsys = gen_otf_tag (str, 8);
794 /* Apply all GSUB features. */
795 feature_count[0] = -1;
799 str = otf_count_features (p, end, '+', feature_count);
801 MERROR (MERROR_FLT, -1);
805 /* Apply all GPOS features. */
806 feature_count[1] = -1;
810 str = otf_count_features (p, end, '\0', feature_count + 1);
812 MERROR (MERROR_FLT, -1);
815 for (i = 0; i < 2; i++)
816 if (feature_count[i])
818 spec->features[i] = malloc (sizeof (int) * (feature_count[i] + 1));
819 if (! spec->features[i])
821 if (feature_count[i] > 0)
822 otf_store_features (features[i] + 1, features[i + 1],
825 spec->features[i][1] = 0;
832 /* Parse OTF command name NAME and store the result in CMD.
834 :SCRIPT[/[LANGSYS][=[GSUB-FEATURES][+GPOS-FEATURES]]]
835 where GSUB-FEATURES and GPOS-FEATURES have this form:
836 [FEATURE[,FEATURE]*] | ' ' */
839 load_otf_command (FontLayoutCmd *cmd, MSymbol sym)
841 char *name = MSYMBOL_NAME (sym);
846 /* This is old format of "otf:...". Change it to ":otf=...". */
847 char *str = alloca (MSYMBOL_NAMELEN (sym) + 2);
849 sprintf (str, ":otf=");
850 strcat (str, name + 4);
854 result = parse_otf_command (sym, &cmd->body.otf);
857 cmd->type = (name[4] == '?' ? FontLayoutCmdTypeOTFCategory
858 : FontLayoutCmdTypeOTF);
863 /* Read a decimal number from STR preceded by one of "+-><". '+' and
864 '>' means a plus sign, '-' and '<' means a minus sign. If the
865 number is greater than 127, limit it to 127. */
868 read_decimal_number (char **str)
871 int sign = (*p == '-' || *p == '<') ? -1 : 1;
875 while (*p >= '0' && *p <= '9')
876 n = n * 10 + *p++ - '0';
880 return (n < 127 ? n * sign : 127 * sign);
884 /* Read a horizontal and vertical combining positions from STR, and
885 store them in the place pointed by X and Y. The horizontal
886 position left, center, and right are represented by 0, 1, and 2
887 respectively. The vertical position top, center, bottom, and base
888 are represented by 0, 1, 2, and 3 respectively. If successfully
889 read, return 0, else return -1. */
892 read_combining_position (char *str, int *x, int *y)
897 /* Vertical position comes first. */
898 for (i = 0; i < 4; i++)
907 /* Then comse horizontal position. */
908 for (i = 0; i < 3; i++)
918 /* Return a combining code corresponding to SYM. */
921 get_combining_command (MSymbol sym)
923 char *str = msymbol_name (sym);
924 int base_x, base_y, add_x, add_y, off_x, off_y;
927 if (read_combining_position (str, &base_x, &base_y) < 0)
938 if (c == '+' || c == '-')
940 off_y = read_decimal_number (&str) + 128;
945 if (c == '<' || c == '>')
946 off_x = read_decimal_number (&str) + 128;
950 if (read_combining_position (str, &add_x, &add_y) < 0)
953 c = MAKE_COMBINING_CODE (base_y, base_x, add_y, add_x, off_y, off_x);
954 return (COMBINING_CODE_TO_CMD_ID (c));
958 /* Load a command from PLIST into STAGE, and return that
959 identification number. If ID is not INVALID_CMD_ID, that means we
960 are loading a top level command or a macro. In that case, use ID
961 as the identification number of the command. Otherwise, generate a
962 new id number for the command. MACROS is a list of raw macros. */
965 load_command (FontLayoutStage *stage, MPlist *plist,
966 MPlist *macros, int id)
971 if (MPLIST_INTEGER_P (plist))
973 int code = MPLIST_INTEGER (plist);
976 MERROR (MERROR_DRAW, INVALID_CMD_ID);
979 else if (MPLIST_PLIST_P (plist))
981 /* PLIST ::= ( cond ... ) | ( STRING ... ) | ( INTEGER ... )
982 | ( ( INTEGER INTEGER ) ... )
983 | ( ( range INTEGER INTEGER ) ... )
984 | ( ( SYMBOL STRING ) ... )
985 | ( ( font-facilty [ INTEGER ] ) ... )
986 | ( ( font-facilty OTF-SPEC ) ... ) */
987 MPlist *elt = MPLIST_PLIST (plist);
988 int len = MPLIST_LENGTH (elt) - 1;
991 if (id == INVALID_CMD_ID)
994 id = INDEX_TO_CMD_ID (stage->used);
995 MLIST_APPEND1 (stage, cmds, dummy, MERROR_DRAW);
997 cmd = stage->cmds + CMD_ID_TO_INDEX (id);
999 if (MPLIST_SYMBOL_P (elt))
1001 FontLayoutCmdCond *cond;
1003 if (MPLIST_SYMBOL (elt) != Mcond)
1004 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1005 elt = MPLIST_NEXT (elt);
1006 cmd->type = FontLayoutCmdTypeCond;
1007 cond = &cmd->body.cond;
1008 cond->seq_beg = cond->seq_end = -1;
1009 cond->seq_from = cond->seq_to = 0;
1011 MTABLE_CALLOC (cond->cmd_ids, len, MERROR_DRAW);
1012 for (i = 0; i < len; i++, elt = MPLIST_NEXT (elt))
1014 int this_id = load_command (stage, elt, macros, INVALID_CMD_ID);
1016 if (this_id == INVALID_CMD_ID || this_id == -2)
1017 MERROR (MERROR_DRAW, this_id);
1018 /* The above load_command may relocate stage->cmds. */
1019 cmd = stage->cmds + CMD_ID_TO_INDEX (id);
1020 cond = &cmd->body.cond;
1021 cond->cmd_ids[i] = this_id;
1022 if (this_id <= CMD_ID_OFFSET_INDEX)
1024 FontLayoutCmd *this_cmd
1025 = stage->cmds + CMD_ID_TO_INDEX (this_id);
1027 if (this_cmd->type == FontLayoutCmdTypeRule
1028 && this_cmd->body.rule.src_type == SRC_SEQ)
1030 int first_char = this_cmd->body.rule.src.seq.codes[0];
1032 if (cond->seq_beg < 0)
1034 /* The first SEQ command. */
1036 cond->seq_from = cond->seq_to = first_char;
1038 else if (cond->seq_end < 0)
1040 /* The following SEQ command. */
1041 if (cond->seq_from > first_char)
1042 cond->seq_from = first_char;
1043 else if (cond->seq_to < first_char)
1044 cond->seq_to = first_char;
1049 if (cond->seq_beg >= 0 && cond->seq_end < 0)
1050 /* The previous one is the last SEQ command. */
1056 if (cond->seq_beg >= 0 && cond->seq_end < 0)
1057 /* The previous one is the last SEQ command. */
1061 if (cond->seq_beg >= 0 && cond->seq_end < 0)
1062 /* The previous one is the last SEQ command. */
1067 cmd->type = FontLayoutCmdTypeRule;
1068 if (MPLIST_MTEXT_P (elt))
1070 MText *mt = MPLIST_MTEXT (elt);
1071 char *str = (char *) MTEXT_DATA (mt);
1075 mtext_ins_char (mt, 0, '^', 1);
1076 str = (char *) MTEXT_DATA (mt);
1078 if (regcomp (&cmd->body.rule.src.re.preg, str, REG_EXTENDED))
1079 MERROR (MERROR_FONT, INVALID_CMD_ID);
1080 cmd->body.rule.src_type = SRC_REGEX;
1081 cmd->body.rule.src.re.pattern = strdup (str);
1083 else if (MPLIST_INTEGER_P (elt))
1085 cmd->body.rule.src_type = SRC_INDEX;
1086 cmd->body.rule.src.match_idx = MPLIST_INTEGER (elt);
1088 else if (MPLIST_PLIST_P (elt))
1090 MPlist *pl = MPLIST_PLIST (elt), *p;
1091 int size = MPLIST_LENGTH (pl);
1093 if (MPLIST_INTEGER_P (pl))
1097 cmd->body.rule.src_type = SRC_SEQ;
1098 cmd->body.rule.src.seq.n_codes = size;
1099 MTABLE_CALLOC (cmd->body.rule.src.seq.codes, size,
1101 for (i = 0; i < size; i++, pl = MPLIST_NEXT (pl))
1103 if (! MPLIST_INTEGER_P (pl))
1104 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1105 cmd->body.rule.src.seq.codes[i]
1106 = (unsigned) MPLIST_INTEGER (pl);
1109 else if (MPLIST_SYMBOL_P (pl))
1111 if (MPLIST_SYMBOL (pl) == Mrange)
1114 MERROR (MERROR_FLT, INVALID_CMD_ID);
1115 cmd->body.rule.src_type = SRC_RANGE;
1116 pl = MPLIST_NEXT (pl);
1117 if (! MPLIST_INTEGER_P (pl))
1118 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1119 cmd->body.rule.src.range.from
1120 = (unsigned) MPLIST_INTEGER (pl);
1121 pl = MPLIST_NEXT (pl);
1122 if (! MPLIST_INTEGER_P (pl))
1123 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1124 cmd->body.rule.src.range.to
1125 = (unsigned) MPLIST_INTEGER (pl);
1127 else if (MPLIST_SYMBOL (pl) == Mfont_facility)
1129 FontLayoutCmdRule *rule = &cmd->body.rule;
1131 pl = MPLIST_NEXT (pl);
1132 if (MPLIST_SYMBOL_P (pl))
1134 MSymbol sym = MPLIST_SYMBOL (pl);
1135 char *otf_spec = MSYMBOL_NAME (sym);
1137 if (otf_spec[0] == ':' && otf_spec[1] == 'o'
1138 && otf_spec[2] == 't' && otf_spec[3] == 'f')
1139 parse_otf_command (sym, &rule->src.facility.otf_spec);
1141 MERROR (MERROR_FLT, INVALID_CMD_ID);
1142 rule->src_type = SRC_OTF_SPEC;
1143 pl = MPLIST_NEXT (pl);
1145 else if (MPLIST_TAIL_P (pl))
1146 MERROR (MERROR_FLT, INVALID_CMD_ID);
1148 rule->src_type = SRC_HAS_GLYPH;
1149 rule->src.facility.len = 0;
1152 if (! MPLIST_INTEGER_P (p)
1153 && (MPLIST_SYMBOL_P (p)
1154 ? MPLIST_SYMBOL (p) != Mequal
1156 MERROR (MERROR_FLT, INVALID_CMD_ID);
1157 rule->src.facility.len++;
1159 rule->src.facility.codes = pl;
1160 M17N_OBJECT_REF (pl);
1164 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1167 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1169 elt = MPLIST_NEXT (elt);
1170 cmd->body.rule.n_cmds = len;
1171 MTABLE_CALLOC (cmd->body.rule.cmd_ids, len, MERROR_DRAW);
1172 for (i = 0; i < len; i++, elt = MPLIST_NEXT (elt))
1174 int this_id = load_command (stage, elt, macros, INVALID_CMD_ID);
1176 if (this_id == INVALID_CMD_ID || this_id == -2)
1177 MERROR (MERROR_DRAW, this_id);
1178 /* The above load_command may relocate stage->cmds. */
1179 cmd = stage->cmds + CMD_ID_TO_INDEX (id);
1180 cmd->body.rule.cmd_ids[i] = this_id;
1184 else if (MPLIST_SYMBOL_P (plist))
1187 MSymbol sym = MPLIST_SYMBOL (plist);
1188 char *name = msymbol_name (sym);
1189 int len = strlen (name);
1193 && ((name[0] == 'o' && name[1] == 't'
1194 && name[2] == 'f' && name[3] == ':')
1195 || (name[0] == ':' && name[1] == 'o' && name[2] == 't'
1196 && name[3] == 'f' && (name[4] == '=' || name[4] == '?'))))
1198 result = load_otf_command (&cmd, sym);
1201 if (id == INVALID_CMD_ID)
1203 id = INDEX_TO_CMD_ID (stage->used);
1204 MLIST_APPEND1 (stage, cmds, cmd, MERROR_DRAW);
1207 stage->cmds[CMD_ID_TO_INDEX (id)] = cmd;
1215 else if (*name == '*')
1216 return CMD_ID_REPEAT;
1217 else if (*name == '<')
1218 return CMD_ID_CLUSTER_BEGIN;
1219 else if (*name == '>')
1220 return CMD_ID_CLUSTER_END;
1221 else if (*name == '|')
1222 return CMD_ID_SEPARATOR;
1223 else if (*name == '[')
1224 return CMD_ID_LEFT_PADDING;
1225 else if (*name == ']')
1226 return CMD_ID_RIGHT_PADDING;
1232 id = get_combining_command (sym);
1238 MPLIST_DO (elt, macros)
1240 if (sym == MPLIST_SYMBOL (MPLIST_PLIST (elt)))
1242 id = INDEX_TO_CMD_ID (i);
1243 if (stage->cmds[i].type == FontLayoutCmdTypeMAX)
1244 id = load_command (stage, MPLIST_NEXT (MPLIST_PLIST (elt)),
1250 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1253 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1259 free_flt_command (FontLayoutCmd *cmd)
1261 if (cmd->type == FontLayoutCmdTypeRule)
1263 FontLayoutCmdRule *rule = &cmd->body.rule;
1265 if (rule->src_type == SRC_REGEX)
1267 free (rule->src.re.pattern);
1268 regfree (&rule->src.re.preg);
1270 else if (rule->src_type == SRC_SEQ)
1271 free (rule->src.seq.codes);
1272 free (rule->cmd_ids);
1274 else if (cmd->type == FontLayoutCmdTypeCond)
1275 free (cmd->body.cond.cmd_ids);
1276 else if (cmd->type == FontLayoutCmdTypeOTF
1277 || cmd->type == FontLayoutCmdTypeOTFCategory)
1279 if (cmd->body.otf.features[0])
1280 free (cmd->body.otf.features[0]);
1281 if (cmd->body.otf.features[1])
1282 free (cmd->body.otf.features[1]);
1286 /* Load a generator from PLIST into a newly allocated FontLayoutStage,
1287 and return it. PLIST has this form:
1288 PLIST ::= ( COMMAND ( CMD-NAME COMMAND ) * )
1291 static FontLayoutStage *
1292 load_generator (MPlist *plist)
1294 FontLayoutStage *stage;
1296 FontLayoutCmd dummy;
1299 MSTRUCT_CALLOC (stage, MERROR_DRAW);
1300 MLIST_INIT1 (stage, cmds, 32);
1301 dummy.type = FontLayoutCmdTypeMAX;
1302 MLIST_APPEND1 (stage, cmds, dummy, MERROR_FONT);
1303 MPLIST_DO (elt, MPLIST_NEXT (plist))
1305 if (! MPLIST_PLIST_P (elt))
1306 MERROR (MERROR_FONT, NULL);
1307 pl = MPLIST_PLIST (elt);
1308 if (! MPLIST_SYMBOL_P (pl))
1309 MERROR (MERROR_FONT, NULL);
1310 MLIST_APPEND1 (stage, cmds, dummy, MERROR_FONT);
1313 /* Load the first command from PLIST into STAGE->cmds[0]. Macros
1314 called in the first command are also loaded from MPLIST_NEXT
1315 (PLIST) into STAGE->cmds[n]. */
1316 result = load_command (stage, plist, MPLIST_NEXT (plist),
1317 INDEX_TO_CMD_ID (0));
1318 if (result == INVALID_CMD_ID || result == -2)
1320 MLIST_FREE1 (stage, cmds);
1329 /* Load stages of the font layout table FLT. */
1332 load_flt (MFLT *flt, MPlist *key_list)
1334 MPlist *top, *plist, *pl, *p;
1335 FontLayoutCategory *category = NULL;
1339 top = (MPlist *) mdatabase__load_for_keys (flt->mdb, key_list);
1341 top = (MPlist *) mdatabase_load (flt->mdb);
1344 if (! MPLIST_PLIST_P (top))
1346 M17N_OBJECT_UNREF (top);
1347 MERROR (MERROR_FLT, -1);
1352 plist = mdatabase__props (flt->mdb);
1354 MERROR (MERROR_FLT, -1);
1355 MPLIST_DO (plist, plist)
1356 if (MPLIST_PLIST_P (plist))
1358 pl = MPLIST_PLIST (plist);
1359 if (! MPLIST_SYMBOL_P (pl)
1360 || MPLIST_SYMBOL (pl) != Mfont)
1362 pl = MPLIST_NEXT (pl);
1363 if (! MPLIST_PLIST_P (pl))
1365 p = MPLIST_PLIST (pl);
1366 if (! MPLIST_SYMBOL_P (p))
1368 p = MPLIST_NEXT (p);
1369 if (! MPLIST_SYMBOL_P (p))
1371 flt->family = MPLIST_SYMBOL (p);
1372 MPLIST_DO (p, MPLIST_NEXT (p))
1373 if (MPLIST_SYMBOL_P (p))
1375 sym = MPLIST_SYMBOL (p);
1376 if (MSYMBOL_NAME (sym)[0] != ':')
1377 flt->registry = sym, sym = Mnil;
1383 char *otf_spec = MSYMBOL_NAME (sym);
1385 if (otf_spec[0] == ':' && otf_spec[1] == 'o'
1386 && otf_spec[2] == 't' && otf_spec[3] == 'f')
1387 parse_otf_command (sym, &flt->otf);
1392 MPLIST_DO (plist, top)
1394 if (MPLIST_SYMBOL_P (plist)
1395 && MPLIST_SYMBOL (plist) == Mend)
1397 mplist_set (plist, Mnil, NULL);
1400 if (! MPLIST_PLIST (plist))
1402 pl = MPLIST_PLIST (plist);
1403 if (! MPLIST_SYMBOL_P (pl))
1405 sym = MPLIST_SYMBOL (pl);
1406 pl = MPLIST_NEXT (pl);
1409 if (sym == Mcategory)
1412 unref_category_table (category);
1413 else if (flt->coverage)
1415 category = flt->coverage;
1416 ref_category_table (category);
1419 category = load_category_table (pl, NULL);
1422 if (! flt->coverage)
1424 flt->coverage = category;
1425 ref_category_table (category);
1427 if (category->definition)
1428 flt->need_config = 1;
1430 else if (sym == Mgenerator)
1432 FontLayoutStage *stage;
1436 stage = load_generator (pl);
1439 stage->category = category;
1440 M17N_OBJECT_REF (category->table);
1442 flt->stages = mplist ();
1443 mplist_add (flt->stages, Mt, stage);
1447 unref_category_table (category);
1449 if (! MPLIST_TAIL_P (plist))
1451 M17N_OBJECT_UNREF (top);
1452 M17N_OBJECT_UNREF (flt->stages);
1453 MERROR (MERROR_FLT, -1);
1455 M17N_OBJECT_UNREF (top);
1461 free_flt_stage (MFLT *flt, FontLayoutStage *stage)
1465 unref_category_table (stage->category);
1468 for (i = 0; i < stage->used; i++)
1469 free_flt_command (stage->cmds + i);
1470 MLIST_FREE1 (stage, cmds);
1482 MPLIST_DO (plist, flt_list)
1484 MFLT *flt = MPLIST_VAL (plist);
1487 unref_category_table (flt->coverage);
1490 MPLIST_DO (pl, MPLIST_NEXT (flt->stages))
1491 free_flt_stage (flt, MPLIST_VAL (pl));
1492 M17N_OBJECT_UNREF (flt->stages);
1495 MPLIST_VAL (plist) = NULL;
1497 M17N_OBJECT_UNREF (flt_list);
1504 MPlist *plist, *key_list = NULL;
1508 if (! (plist = mdatabase_list (Mfont, Mlayouter, Mnil, Mnil)))
1510 if (! (flt_list = mplist ()))
1512 if (! (key_list = mplist ()))
1514 if (! mplist_add (key_list, Mcategory, Mt))
1517 MPLIST_DO (pl, plist)
1519 MDatabase *mdb = MPLIST_VAL (pl);
1520 MSymbol *tags = mdatabase_tag (mdb);
1523 if (! MSTRUCT_CALLOC_SAFE (flt))
1525 flt->name = tags[2];
1527 if (load_flt (flt, key_list) < 0)
1531 if (MPLIST_TAIL_P (flt_list))
1533 flt_min_coverage = mchartable_min_char (flt->coverage->table);
1534 flt_max_coverage = mchartable_max_char (flt->coverage->table);
1540 c = mchartable_min_char (flt->coverage->table);
1541 if (flt_min_coverage > c)
1542 flt_min_coverage = c;
1543 c = mchartable_max_char (flt->coverage->table);
1544 if (flt_max_coverage < c)
1545 flt_max_coverage = c;
1547 if (! mplist_push (flt_list, flt->name, flt))
1557 M17N_OBJECT_UNREF (plist);
1558 M17N_OBJECT_UNREF (key_list);
1562 /* FLS (Font Layout Service) */
1564 /* Structure to hold information about a context of FLS. */
1568 /* Pointer to the current stage. */
1569 FontLayoutStage *stage;
1571 /* Pointer to the category table of the next stage or NULL if none. */
1572 FontLayoutCategory *category;
1574 /* Pointer to the font. */
1577 /* Input and output glyph string. */
1578 MFLTGlyphString *in, *out;
1580 /* Encode each character or code of a glyph by the current category
1581 table into this array. An element is a category letter used for
1582 a regular expression matching. */
1587 int cluster_begin_idx;
1588 int cluster_begin_pos;
1589 int cluster_end_pos;
1593 } FontLayoutContext;
1595 static int run_command (int, int, int, int, FontLayoutContext *);
1596 static int run_otf (int, MFLTOtfSpec *, int, int, FontLayoutContext *);
1597 static int try_otf (int, MFLTOtfSpec *, int, int, FontLayoutContext *);
1602 run_rule (int depth,
1603 FontLayoutCmdRule *rule, int from, int to, FontLayoutContext *ctx)
1605 int *saved_match_indices = ctx->match_indices;
1606 int match_indices[NMATCH * 2];
1609 int orig_from = from;
1610 int need_cluster_update = 0;
1612 if (rule->src_type == SRC_REGEX)
1614 regmatch_t pmatch[NMATCH];
1620 saved_code = ctx->encoded[to - ctx->encoded_offset];
1621 ctx->encoded[to - ctx->encoded_offset] = '\0';
1622 result = regexec (&(rule->src.re.preg),
1623 ctx->encoded + (from - ctx->encoded_offset),
1625 if (result == 0 && pmatch[0].rm_so == 0)
1627 if (MDEBUG_FLAG () > 2)
1628 MDEBUG_PRINT5 ("\n [FLT] %*s(REGEX \"%s\" \"%s\" %d", depth, "",
1629 rule->src.re.pattern,
1630 ctx->encoded + (from - ctx->encoded_offset),
1632 ctx->encoded[to - ctx->encoded_offset] = saved_code;
1633 for (i = 0; i < NMATCH; i++)
1635 if (pmatch[i].rm_so < 0)
1636 match_indices[i * 2] = match_indices[i * 2 + 1] = -1;
1639 match_indices[i * 2] = from + pmatch[i].rm_so;
1640 match_indices[i * 2 + 1] = from + pmatch[i].rm_eo;
1643 ctx->match_indices = match_indices;
1644 to = match_indices[1];
1648 ctx->encoded[to - ctx->encoded_offset] = saved_code;
1651 need_cluster_update = 1;
1653 else if (rule->src_type == SRC_SEQ)
1657 len = rule->src.seq.n_codes;
1658 if (len > (to - from))
1660 for (i = 0; i < len; i++)
1661 if (rule->src.seq.codes[i] != GREF (ctx->in, from + i)->c)
1666 if (MDEBUG_FLAG () > 2)
1667 MDEBUG_PRINT3 ("\n [FLT] %*s(SEQ 0x%X", depth, "",
1668 rule->src.seq.codes[0]);
1669 need_cluster_update = 1;
1671 else if (rule->src_type == SRC_RANGE)
1677 head = GREF (ctx->in, from)->c;
1678 if (head < rule->src.range.from || head > rule->src.range.to)
1680 ctx->code_offset = head - rule->src.range.from;
1682 if (MDEBUG_FLAG () > 2)
1683 MDEBUG_PRINT4 ("\n [FLT] %*s(RANGE 0x%X-0x%X", depth, "",
1684 rule->src.range.from, rule->src.range.to);
1685 need_cluster_update = 1;
1687 else if (rule->src_type == SRC_INDEX)
1689 if (rule->src.match_idx >= NMATCH)
1691 from = ctx->match_indices[rule->src.match_idx * 2];
1694 to = ctx->match_indices[rule->src.match_idx * 2 + 1];
1695 if (MDEBUG_FLAG () > 2)
1696 MDEBUG_PRINT3 ("\n [FLT] %*s(SUBPART %d", depth, "",
1697 rule->src.match_idx);
1698 need_cluster_update = 1;
1700 else if (rule->src_type == SRC_HAS_GLYPH
1701 || rule->src_type == SRC_OTF_SPEC)
1703 static MFLTGlyphString gstring;
1707 if (rule->src.facility.len > 0)
1709 if (! gstring.glyph_size)
1711 gstring.glyph_size = ctx->in->glyph_size;
1712 gstring.glyphs = calloc (rule->src.facility.len,
1713 gstring.glyph_size);
1714 gstring.allocated = rule->src.facility.len;
1715 gstring.used = rule->src.facility.len;
1717 else if (rule->src.facility.len < gstring.allocated)
1719 gstring.glyphs = realloc (gstring.glyphs,
1721 * rule->src.facility.len);
1722 gstring.allocated = rule->src.facility.len;
1723 gstring.used = rule->src.facility.len;
1726 for (i = 0, p = rule->src.facility.codes, idx = from;
1727 i < rule->src.facility.len; i++, p = MPLIST_NEXT (p))
1729 if (MPLIST_INTEGER_P (p))
1731 GREF (&gstring, i)->c = MPLIST_INTEGER (p);
1732 GREF (&gstring, i)->encoded = 0;
1736 GREF (&gstring, i)->c = GREF (ctx->in, idx)->code;
1737 GREF (&gstring, i)->encoded = GREF (ctx->in, idx)->encoded;
1743 if (MDEBUG_FLAG () > 2)
1745 if (rule->src_type == SRC_HAS_GLYPH)
1746 MDEBUG_PRINT2 ("\n [FLT] %*s(HAS-GLYPH", depth, "");
1748 MDEBUG_PRINT2 ("\n [FLT] %*s(OTF-SPEC", depth, "");
1749 for (i = 0; i < rule->src.facility.len; i++)
1750 MDEBUG_PRINT1 (" %04X", GREF (&gstring, i)->code);
1752 if (ctx->font->get_glyph_id (ctx->font, &gstring, 0,
1753 rule->src.facility.len) < 0)
1755 MDEBUG_PRINT (") FAIL!");
1758 if (rule->src_type == SRC_OTF_SPEC)
1760 MFLTOtfSpec *spec = &rule->src.facility.otf_spec;
1762 if (! ctx->font->check_otf)
1764 if ((spec->features[0] && spec->features[0][0] != 0xFFFFFFFF)
1765 || (spec->features[1] && spec->features[1][0] != 0xFFFFFFFF))
1770 if (rule->src.facility.len == 0)
1772 if (! ctx->font->check_otf (ctx->font, spec))
1777 int prev_out_used = ctx->out->used, out_used;
1778 MFLTGlyphAdjustment *adjustment;
1780 adjustment = alloca ((sizeof *adjustment)
1781 * (ctx->out->allocated - ctx->out->used));
1783 MERROR (MERROR_FLT, -1);
1784 memset (adjustment, 0,
1785 (sizeof *adjustment)
1786 * (ctx->out->allocated - ctx->out->used));
1787 ctx->font->drive_otf (ctx->font, &rule->src.facility.otf_spec,
1788 &gstring, 0, rule->src.facility.len,
1791 out_used = ctx->out->used;
1792 ctx->out->used = prev_out_used;
1793 if (rule->src.facility.len == out_used - prev_out_used)
1795 for (i = prev_out_used; i < out_used; i++)
1797 if (GREF (&gstring, i - prev_out_used)->code
1798 != GREF (ctx->out, i)->code)
1800 if (adjustment[i - prev_out_used].set)
1811 if (need_cluster_update && ctx->cluster_begin_idx >= 0)
1813 for (i = from; i < to; i++)
1815 MFLTGlyph *g = GREF (ctx->in, i);
1816 UPDATE_CLUSTER_RANGE (ctx, g);
1822 for (i = 0; i < rule->n_cmds; i++)
1826 if (rule->cmd_ids[i] == CMD_ID_REPEAT)
1832 pos = run_command (depth, rule->cmd_ids[i], from, to, ctx);
1835 consumed = pos > from;
1840 ctx->match_indices = saved_match_indices;
1841 if (MDEBUG_FLAG () > 2)
1843 return (rule->src_type == SRC_INDEX ? orig_from : to);
1847 run_cond (int depth,
1848 FontLayoutCmdCond *cond, int from, int to, FontLayoutContext *ctx)
1852 if (MDEBUG_FLAG () > 2)
1853 MDEBUG_PRINT2 ("\n [FLT] %*s(COND", depth, "");
1855 for (i = 0; i < cond->n_cmds; i++)
1857 /* TODO: Write a code for optimization utilizaing the info
1859 if ((pos = run_command (depth, cond->cmd_ids[i], from, to, ctx))
1865 if (MDEBUG_FLAG () > 2)
1871 decode_packed_otf_tag (FontLayoutContext *ctx, MFLTGlyphString *gstring,
1872 int from, int to, FontLayoutCategory *category)
1874 for (; from < to; from++)
1876 MFLTGlyph *g = GREF (gstring, from);
1877 unsigned int tag = g->internal & 0xFFFFFFF;
1880 if (GET_COMBINED (g))
1884 SET_CATEGORY_CODE (g, 0);
1888 if (tag & 0xFFFFF80)
1892 /* Clear the feature tag code. */
1893 g->internal &= ~0xFFFFFFF;
1894 for (i = 0; i < category->feature_table.size; i++)
1895 if (category->feature_table.tag[i] == tag)
1897 enc = category->feature_table.code[i];
1898 if (ctx->in == gstring)
1899 ctx->encoded[from - ctx->encoded_offset] = enc;
1904 enc = (g->c > 0 ? (int) mchartable_lookup (category->table, g->c)
1905 : g->c == 0 ? 1 : ' ');
1906 SET_CATEGORY_CODE (g, enc);
1912 MFLTOtfSpec *otf_spec, int from, int to, FontLayoutContext *ctx)
1914 MFLTFont *font = ctx->font;
1915 int from_idx = ctx->out->used;
1917 if (MDEBUG_FLAG () > 2)
1918 MDEBUG_PRINT3 ("\n [FLT] %*s%s", depth, "", MSYMBOL_NAME (otf_spec->sym));
1920 font->get_glyph_id (font, ctx->in, from, to);
1921 if (! font->drive_otf)
1923 if (ctx->out->used + (to - from) > ctx->out->allocated)
1925 font->get_metrics (font, ctx->in, from, to);
1926 GCPY (ctx->in, from, to - from, ctx->out, ctx->out->used);
1927 ctx->out->used += to - from;
1931 MFLTGlyphAdjustment *adjustment;
1935 adjustment = alloca ((sizeof *adjustment)
1936 * (ctx->out->allocated - ctx->out->used));
1938 MERROR (MERROR_FLT, -1);
1939 memset (adjustment, 0,
1940 (sizeof *adjustment) * (ctx->out->allocated - ctx->out->used));
1941 to = font->drive_otf (font, otf_spec, ctx->in, from, to, ctx->out,
1945 decode_packed_otf_tag (ctx, ctx->out, from_idx, ctx->out->used,
1947 out_len = ctx->out->used - from_idx;
1948 if (otf_spec->features[1])
1950 MFLTGlyphAdjustment *a;
1953 for (i = 0, a = adjustment; i < out_len; i++, a++)
1958 font->get_metrics (font, ctx->out, from_idx, ctx->out->used);
1959 for (g = GREF (ctx->out, from_idx + i);
1960 i < out_len; i++, a++, g = NEXT (ctx->out, g))
1963 if (a->advance_is_absolute)
1968 else if (a->xadv || a->yadv)
1973 if (a->xoff || a->yoff || a->back)
1976 MFLTGlyph *gg = PREV (ctx->out, g);
1977 MFLTGlyphAdjustment *aa = a;
1981 g->lbearing += a->xoff;
1982 g->rbearing += a->xoff;
1983 g->ascent -= a->yoff;
1984 g->descent -= a->yoff;
1985 while (aa->back > 0)
1987 for (j = 0; j < aa->back;
1988 j++, gg = PREV (ctx->out, gg))
1990 g->xoff -= gg->xadv;
1991 g->lbearing -= gg->xadv;
1992 g->rbearing -= gg->xadv;
1995 g->xoff += aa->xoff;
1996 g->yoff += aa->yoff;
1997 g->lbearing += aa->xoff;
1998 g->rbearing += aa->xoff;
1999 g->ascent -= aa->yoff;
2000 g->descent -= aa->yoff;
2009 if (ctx->cluster_begin_idx >= 0)
2010 for (; from_idx < ctx->out->used; from_idx++)
2012 MFLTGlyph *g = GREF (ctx->out, from_idx);
2013 UPDATE_CLUSTER_RANGE (ctx, g);
2019 try_otf (int depth, MFLTOtfSpec *otf_spec, int from, int to,
2020 FontLayoutContext *ctx)
2022 MFLTFont *font = ctx->font;
2024 if (MDEBUG_FLAG () > 2)
2025 MDEBUG_PRINT3 ("\n [FLT] %*s%s", depth, "", MSYMBOL_NAME (otf_spec->sym));
2027 if (! otf_spec->features[0] && ! otf_spec->features[1])
2029 /* Reset categories. */
2030 MCharTable *table = ctx->category->table;
2033 for (i = from; i < to; i++)
2035 MFLTGlyph *g = GREF (ctx->in, i);
2037 if (! GET_COMBINED (g))
2039 char enc = (GET_ENCODED (g)
2040 ? (g->c > 0 ? (int) mchartable_lookup (table, g->c)
2043 ? (int) mchartable_lookup (table, g->code)
2045 SET_CATEGORY_CODE (g, enc);
2046 ctx->encoded[i - ctx->encoded_offset] = enc;
2052 if (ctx->stage->category->feature_table.size == 0)
2055 font->get_glyph_id (font, ctx->in, from, to);
2058 to = mflt_try_otf (font, otf_spec, ctx->in, from, to);
2061 decode_packed_otf_tag (ctx, ctx->in, from, to, ctx->stage->category);
2066 static char work[16];
2069 dump_combining_code (int code)
2071 char *vallign = "tcbB";
2072 char *hallign = "lcr";
2078 work[0] = vallign[COMBINING_CODE_BASE_Y (code)];
2079 work[1] = hallign[COMBINING_CODE_BASE_X (code)];
2080 off_y = COMBINING_CODE_OFF_Y (code);
2081 off_x = COMBINING_CODE_OFF_X (code);
2083 sprintf (work + 2, "+%d", off_y);
2085 sprintf (work + 2, "%d", off_y);
2086 else if (off_x == 0)
2087 sprintf (work + 2, ".");
2088 p = work + strlen (work);
2090 sprintf (p, ">%d", off_x);
2092 sprintf (p, "<%d", -off_x);
2094 p[0] = vallign[COMBINING_CODE_ADD_Y (code)];
2095 p[1] = hallign[COMBINING_CODE_ADD_X (code)];
2101 run_command (int depth, int id, int from, int to, FontLayoutContext *ctx)
2108 MCharTable *table = ctx->category ? ctx->category->table : NULL;
2111 /* Direct code (== ctx->code_offset + id) output.
2112 The source is not consumed. */
2113 if (MDEBUG_FLAG () > 2)
2114 MDEBUG_PRINT3 ("\n [FLT] %*s(DIRECT 0x%X", depth, "",
2115 ctx->code_offset + id);
2116 i = (from < to || from == 0) ? from : from - 1;
2118 g = GREF (ctx->out, ctx->out->used - 1);
2119 g->c = g->code = ctx->code_offset + id;
2120 if (ctx->combining_code)
2121 SET_COMBINING_CODE (g, ctx, ctx->combining_code);
2124 enc = (GET_ENCODED (g)
2125 ? (g->c > 0 ? (int) mchartable_lookup (table, g->c) : 1)
2127 ? (int) mchartable_lookup (table, g->code)
2129 SET_CATEGORY_CODE (g, enc);
2132 SET_MEASURED (g, 0);
2133 if (ctx->left_padding)
2134 SET_LEFT_PADDING (g, ctx, LeftPaddingMask);
2135 for (i = from; i < to; i++)
2137 MFLTGlyph *tmp = GREF (ctx->in, i);
2139 if (g->from > tmp->from)
2140 g->from = tmp->from;
2141 else if (g->to < tmp->to)
2144 if (ctx->cluster_begin_idx >= 0)
2145 UPDATE_CLUSTER_RANGE (ctx, g);
2146 ctx->code_offset = ctx->combining_code = ctx->left_padding = 0;
2147 if (MDEBUG_FLAG () > 2)
2152 if (id <= CMD_ID_OFFSET_INDEX)
2154 int idx = CMD_ID_TO_INDEX (id);
2157 if (idx >= ctx->stage->used)
2158 MERROR (MERROR_DRAW, -1);
2159 cmd = ctx->stage->cmds + idx;
2160 if (cmd->type == FontLayoutCmdTypeRule)
2161 to = run_rule (depth, &cmd->body.rule, from, to, ctx);
2162 else if (cmd->type == FontLayoutCmdTypeCond)
2163 to = run_cond (depth, &cmd->body.cond, from, to, ctx);
2164 else if (cmd->type == FontLayoutCmdTypeOTF)
2165 to = run_otf (depth, &cmd->body.otf, from, to, ctx);
2166 else if (cmd->type == FontLayoutCmdTypeOTFCategory)
2167 to = try_otf (depth, &cmd->body.otf, from, to, ctx);
2171 if (id <= CMD_ID_OFFSET_COMBINING)
2173 ctx->combining_code = CMD_ID_TO_COMBINING_CODE (id);
2174 if (MDEBUG_FLAG () > 2)
2175 MDEBUG_PRINT3 ("\n [FLT] %*s(CMB %s)", depth, "",
2176 dump_combining_code (ctx->combining_code));
2187 g = GREF (ctx->out, ctx->out->used - 1);
2188 if (ctx->combining_code)
2189 SET_COMBINING_CODE (g, ctx, ctx->combining_code);
2190 if (ctx->left_padding)
2191 SET_LEFT_PADDING (g, ctx, LeftPaddingMask);
2192 if (ctx->cluster_begin_idx >= 0)
2193 UPDATE_CLUSTER_RANGE (ctx, g);
2194 if (MDEBUG_FLAG () > 2)
2197 MDEBUG_PRINT2 ("\n [FLT] %*s(COPY |)", depth, "");
2199 MDEBUG_PRINT3 ("\n [FLT] %*s(COPY 0x%X)", depth, "", g->c);
2201 ctx->code_offset = ctx->combining_code = ctx->left_padding = 0;
2205 case CMD_ID_CLUSTER_BEGIN:
2206 if (ctx->cluster_begin_idx < 0)
2208 if (MDEBUG_FLAG () > 2)
2209 MDEBUG_PRINT3 ("\n [FLT] %*s<%d", depth, "",
2210 GREF (ctx->in, from)->from);
2211 ctx->cluster_begin_idx = ctx->out->used;
2212 ctx->cluster_begin_pos = GREF (ctx->in, from)->from;
2213 ctx->cluster_end_pos = GREF (ctx->in, from)->to;
2217 case CMD_ID_CLUSTER_END:
2218 if (ctx->cluster_begin_idx >= 0
2219 && ctx->cluster_begin_idx < ctx->out->used)
2223 if (MDEBUG_FLAG () > 2)
2224 MDEBUG_PRINT1 (" %d>", ctx->cluster_end_pos + 1);
2225 for (i = ctx->cluster_begin_idx; i < ctx->out->used; i++)
2227 GREF (ctx->out, i)->from = ctx->cluster_begin_pos;
2228 GREF (ctx->out, i)->to = ctx->cluster_end_pos;
2230 ctx->cluster_begin_idx = -1;
2234 case CMD_ID_SEPARATOR:
2238 if (MDEBUG_FLAG () > 2)
2239 MDEBUG_PRINT2 ("\n [FLT] %*s|", depth, "");
2240 i = from < to ? from : from - 1;
2242 g = GREF (ctx->out, ctx->out->used - 1);
2243 g->c = -1, g->code = 0;
2244 g->xadv = g->yadv = 0;
2246 SET_MEASURED (g, 0);
2247 SET_CATEGORY_CODE (g, ' ');
2251 case CMD_ID_LEFT_PADDING:
2252 if (MDEBUG_FLAG () > 2)
2253 MDEBUG_PRINT2 ("\n [FLT] %*s[", depth, "");
2254 ctx->left_padding = 1;
2257 case CMD_ID_RIGHT_PADDING:
2258 if (ctx->out->used > 0)
2260 if (MDEBUG_FLAG () > 2)
2261 MDEBUG_PRINT2 ("\n [FLT] %*s]", depth, "");
2262 g = GREF (ctx->out, ctx->out->used - 1);
2263 SET_RIGHT_PADDING (g, ctx, RightPaddingMask);
2268 MERROR (MERROR_DRAW, -1);
2272 run_stages (MFLTGlyphString *gstring, int from, int to,
2273 MFLT *flt, FontLayoutContext *ctx)
2275 MFLTGlyphString buf, *temp;
2277 int orig_from = from, orig_to = to;
2278 int from_pos, to_pos, len;
2281 MPlist *stages = flt->stages;
2282 FontLayoutCategory *prev_category = NULL;
2284 from_pos = GREF (ctx->in, from)->from;
2285 to_pos = GREF (ctx->in, to - 1)->to;
2286 len = to_pos - from_pos;
2290 GINIT (ctx->out, ctx->out->allocated);
2291 ctx->encoded = alloca (ctx->out->allocated);
2292 if (! ctx->out->glyphs || ! ctx->encoded)
2295 for (stage_idx = 0; 1; stage_idx++)
2300 ctx->stage = (FontLayoutStage *) MPLIST_VAL (stages);
2301 table = ctx->stage->category->table;
2302 stages = MPLIST_NEXT (stages);
2303 if (MPLIST_TAIL_P (stages))
2304 ctx->category = NULL;
2306 ctx->category = ((FontLayoutStage *) MPLIST_VAL (stages))->category;
2307 ctx->code_offset = ctx->combining_code = ctx->left_padding = 0;
2308 ctx->encoded_offset = from;
2309 for (i = from; i < to; i++)
2311 MFLTGlyph *g = GREF (ctx->in, i);
2314 if (GET_COMBINED (g)
2315 || (prev_category && prev_category != ctx->stage->category))
2317 enc = (GET_ENCODED (g)
2318 ? (g->c > 0 ? (int) mchartable_lookup (table, g->c) : 1)
2320 ? (int) mchartable_lookup (table, g->code)
2322 if (! GET_COMBINED (g))
2323 SET_CATEGORY_CODE (g, enc);
2326 enc = GET_CATEGORY_CODE (g);
2327 ctx->encoded[i - from] = enc;
2328 if (! enc && stage_idx == 0)
2334 ctx->encoded[i - from] = '\0';
2335 ctx->match_indices[0] = from;
2336 ctx->match_indices[1] = to;
2337 for (i = 2; i < NMATCH; i++)
2338 ctx->match_indices[i] = -1;
2340 if (MDEBUG_FLAG () > 2)
2342 MDEBUG_PRINT2 ("\n [FLT] (STAGE %d \"%s\"", stage_idx,
2344 MDEBUG_PRINT (" (");
2345 for (i = from; i < to; i++)
2347 g = GREF (ctx->in, i);
2349 MDEBUG_PRINT2 ("%*s|", (i > 0), "");
2351 MDEBUG_PRINT3 ("%*s%04X", (i > 0), "", GREF (ctx->in, i)->code);
2355 result = run_command (4, INDEX_TO_CMD_ID (0), from, to, ctx);
2356 if (MDEBUG_FLAG () > 2)
2361 /* If this is the last stage, break the loop. */
2362 if (MPLIST_TAIL_P (stages))
2365 /* Otherwise, prepare for the next stage. */
2366 prev_category = ctx->stage->category;
2373 GINIT (&buf, ctx->out->allocated);
2382 if (ctx->out->used > 0)
2385 int x_ppem = ctx->font->x_ppem << 6, y_ppem = ctx->font->y_ppem << 6;
2387 /* Remove separator glyphs. */
2388 for (i = 0; i < ctx->out->used;)
2390 g = GREF (ctx->out, i);
2392 GREPLACE (NULL, 0, 0, ctx->out, i, i + 1);
2397 /* Get actual glyph IDs of glyphs. */
2398 ctx->font->get_glyph_id (ctx->font, ctx->out, 0, ctx->out->used);
2400 /* Check if all characters in the range are covered by some
2401 glyph(s). If not, change <from> and <to> of glyphs to cover
2402 uncovered characters. */
2403 g_indices = alloca (sizeof (int) * len);
2406 for (i = 0; i < len; i++) g_indices[i] = -1;
2407 for (i = 0; i < ctx->out->used; i++)
2411 g = GREF (ctx->out, i);
2412 for (pos = g->from; pos <= g->to; pos++)
2413 if (g_indices[pos - from_pos] < 0)
2414 g_indices[pos - from_pos] = i;
2416 for (i = 0; i < len; i++)
2417 if (g_indices[i] < 0)
2423 for (i++; i < len && g_indices[i] < 0; i++);
2425 g = GREF (ctx->out, j);
2426 this_from = g->from;
2428 g->from = orig_from + i;
2429 } while (++j < ctx->out->used
2430 && (g = GREF (ctx->out, j))
2431 && g->from == this_from);
2437 j = g_indices[i - 1];
2438 g = GREF (ctx->out, j);
2441 g->to = orig_from + i + 1;
2443 && (g = GREF (ctx->out, j))
2444 && g->to == this_to);
2448 ctx->font->get_metrics (ctx->font, ctx->out, 0, ctx->out->used);
2450 /* Handle combining. */
2451 if (ctx->check_mask & CombinedMask)
2453 MFLTGlyph *base = GREF (ctx->out, 0);
2454 int base_height = base->ascent + base->descent;
2455 int base_width = base->rbearing - base->lbearing;
2458 for (i = 1; i < ctx->out->used; i++)
2460 if ((g = GREF (ctx->out, i))
2462 && (combining_code = GET_COMBINING_CODE (g)))
2464 int height = g->ascent + g->descent;
2465 int width = g->rbearing - g->lbearing;
2466 int base_x, base_y, add_x, add_y, off_x, off_y;
2468 if (base->from > g->from)
2469 base->from = g->from;
2470 else if (base->to < g->to)
2473 base_x = COMBINING_CODE_BASE_X (combining_code);
2474 base_y = COMBINING_CODE_BASE_Y (combining_code);
2475 add_x = COMBINING_CODE_ADD_X (combining_code);
2476 add_y = COMBINING_CODE_ADD_Y (combining_code);
2477 off_x = COMBINING_CODE_OFF_X (combining_code);
2478 off_y = COMBINING_CODE_OFF_Y (combining_code);
2480 g->xoff = ((base_width * base_x - width * add_x) / 2
2481 + x_ppem * off_x / 100
2482 - (base->xadv - base->lbearing) - g->lbearing);
2484 g->yoff = base_height * base_y / 2 - base->ascent;
2488 g->yoff -= height * add_y / 2 - g->ascent;
2489 g->yoff -= y_ppem * off_y / 100;
2490 if (base->lbearing > base->xadv + g->lbearing + g->xoff)
2491 base->lbearing = base->xadv + g->lbearing + g->xoff;
2492 if (base->rbearing < base->xadv + g->rbearing + g->xoff)
2493 base->rbearing = base->xadv + g->rbearing + g->xoff;
2494 if (base->ascent < g->ascent - g->yoff)
2495 base->ascent = g->ascent - g->yoff;
2496 if (base->descent < g->descent - g->yoff)
2497 base->descent = g->descent - g->yoff;
2498 g->xadv = g->yadv = 0;
2499 if (GET_RIGHT_PADDING (g))
2500 SET_RIGHT_PADDING (base, ctx, RightPaddingMask);
2506 base_height = g->ascent + g->descent;
2507 base_width = g->rbearing - g->lbearing;
2512 /* Handle padding */
2513 if (ctx->check_mask & (LeftPaddingMask | RightPaddingMask))
2514 for (i = 0; i < ctx->out->used; i++)
2516 g = GREF (ctx->out, i);
2517 if (! GET_COMBINED (g))
2519 if (GET_RIGHT_PADDING (g) && g->rbearing > g->xadv)
2521 g->xadv = g->rbearing;
2524 if (GET_LEFT_PADDING (g) && g->lbearing < 0)
2526 g->xoff += - g->lbearing;
2527 g->xadv += - g->lbearing;
2528 g->rbearing += - g->lbearing;
2536 GREPLACE (ctx->out, 0, ctx->out->used, gstring, orig_from, orig_to);
2537 to = orig_from + ctx->out->used;
2542 setup_combining_coverage (int from, int to, void *val, void *arg)
2544 int combining_class = (int) val;
2547 if (combining_class < 200)
2549 else if (combining_class <= 204)
2551 if ((combining_class % 2) == 0)
2552 category = "bcd"[(combining_class - 200) / 2];
2554 else if (combining_class <= 232)
2556 if ((combining_class % 2) == 0)
2557 category = "efghijklmnopq"[(combining_class - 208) / 2];
2559 else if (combining_class == 233)
2561 else if (combining_class == 234)
2563 else if (combining_class == 240)
2565 mchartable_set_range ((MCharTable *) arg, from, to, (void *) category);
2569 setup_combining_flt (MFLT *flt)
2572 MCharTable *combininig_class_table
2573 = mchar_get_prop_table (Mcombining_class, &type);
2575 mchartable_set_range (flt->coverage->table, 0, 0x10FFFF, (void *) 'u');
2576 if (combininig_class_table)
2577 mchartable_map (combininig_class_table, (void *) 0,
2578 setup_combining_coverage, flt->coverage->table);
2581 #define CHECK_FLT_STAGES(flt) ((flt)->stages || load_flt (flt, NULL) == 0)
2583 static FontLayoutCategory *
2584 configure_category (FontLayoutCategory *category, MFLTFont *font)
2586 if (! mflt_font_id || ! mflt_iterate_otf_feature)
2588 FontLayoutCategory *new = malloc (sizeof (FontLayoutCategory));
2589 new->definition = NULL;
2590 new->table = category->table;
2591 M17N_OBJECT_REF (new->table);
2594 return load_category_table (category->definition, font);
2598 configure_flt (MFLT *flt, MFLTFont *font, MSymbol font_id)
2603 if (! mflt_font_id || ! mflt_iterate_otf_feature)
2605 MPLIST_DO (plist, flt_list)
2607 configured = MPLIST_VAL (plist);
2608 if (! configured->font_id)
2610 if (configured->name == flt->name
2611 && configured->font_id == font_id)
2614 if (! MSTRUCT_CALLOC_SAFE (configured))
2617 configured->stages = mplist_copy (flt->stages);
2618 MPLIST_DO (plist, configured->stages)
2620 FontLayoutStage *stage = MPLIST_VAL (plist);
2621 if (stage->category->definition)
2623 MSTRUCT_CALLOC (stage, MERROR_FLT);
2624 *stage = *((FontLayoutStage *) MPLIST_VAL (plist));
2625 stage->category = configure_category (stage->category, font);
2626 MPLIST_VAL (plist) = stage;
2629 M17N_OBJECT_REF (stage->category->table);
2631 configured->need_config = 0;
2632 configured->font_id = font_id;
2633 mplist_push (flt_list, flt->name, configured);
2639 int m17n__flt_initialized;
2644 /* The following two are actually not exposed to a user but concealed
2645 by the macro M17N_INIT (). */
2648 m17n_init_flt (void)
2650 int mdebug_flag = MDEBUG_INIT;
2652 merror_code = MERROR_NONE;
2653 if (m17n__flt_initialized++)
2656 if (merror_code != MERROR_NONE)
2658 m17n__flt_initialized--;
2662 MDEBUG_PUSH_TIME ();
2664 Mcond = msymbol ("cond");
2665 Mrange = msymbol ("range");
2666 Mfont = msymbol ("font");
2667 Mlayouter = msymbol ("layouter");
2668 Mcombining = msymbol ("combining");
2669 Mfont_facility = msymbol ("font-facility");
2670 Mequal = msymbol ("=");
2671 Mgenerator = msymbol ("generator");
2672 Mend = msymbol ("end");
2674 mflt_enable_new_feature = 0;
2675 mflt_iterate_otf_feature = NULL;
2676 mflt_font_id = NULL;
2677 mflt_try_otf = NULL;
2679 MDEBUG_PRINT_TIME ("INIT", (mdebug__output, " to initialize the flt modules."));
2684 m17n_fini_flt (void)
2686 int mdebug_flag = MDEBUG_FINI;
2688 if (m17n__flt_initialized == 0
2689 || --m17n__flt_initialized > 0)
2692 MDEBUG_PUSH_TIME ();
2694 MDEBUG_PRINT_TIME ("FINI", (mdebug__output, " to finalize the flt modules."));
2700 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
2702 /*** @addtogroup m17nFLT */
2708 @brief Return an FLT object that has a specified name.
2710 The mflt_get () function returns an FLT object whose name is $NAME.
2713 If the operation was successful, mflt_get () returns a pointer
2714 to the found FLT object. Otherwise, it returns @c NULL. */
2717 @brief »ØÄꤵ¤ì¤¿Ì¾Á°¤ò»ý¤Ä FLT ¥ª¥Ö¥¸¥§¥¯¥È¤òÊÖ¤¹.
2719 ´Ø¿ô mflt_get () ¤Ï¡¢$NAME ¤È¤¤¤¦Ì¾Á°¤ò»ý¤Ä FLT ¥ª¥Ö¥¸¥§¥¯¥È¤òÊÖ¤¹¡£
2722 ¤â¤·À®¸ù¤¹¤ì¤Ð¡¢mflt_get () ¤Ï¸«¤Ä¤«¤Ã¤¿ FLT
2723 ¥ª¥Ö¥¸¥§¥¯¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¼ºÇÔ¤·¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤¹¡£ */
2726 mflt_get (MSymbol name)
2731 if (! flt_list && list_flt () < 0)
2733 for (plist = flt_list; plist; plist = plist->next)
2734 if (((MFLT *) MPLIST_VAL (plist))->font_id == Mnil)
2736 flt = mplist_get (plist, name);
2737 if (! flt || ! CHECK_FLT_STAGES (flt))
2739 if (flt->name == Mcombining
2740 && ! mchartable_lookup (flt->coverage->table, 0))
2741 setup_combining_flt (flt);
2748 @brief Find an FLT suitable for the specified character and font.
2750 The mflt_find () function returns the most appropriate FLT for
2751 layouting character $C with font $FONT.
2754 If the operation was successful, mflt_find () returns a pointer
2755 to the found FLT object. Otherwise, it returns @c NULL. */
2758 @brief »ØÄꤵ¤ì¤¿Ê¸»ú¤È¥Õ¥©¥ó¥È¤Ë¹ç¤Ã¤¿ FLT ¤òõ¤¹.
2760 ´Ø¿ô mflt_find () ¤Ï¡¢Ê¸»ú $C ¤ò¥Õ¥©¥ó¥È $FONT
2761 ¤Ç¥ì¥¤¥¢¥¦¥È¤¹¤ë¤¿¤á¤ËºÇ¤âŬÀÚ¤Ê FLT ¤òÊÖ¤¹¡£
2764 ¤â¤·À®¸ù¤¹¤ì¤Ð¡¢mflt_find () ¤Ï¸«¤Ä¤«¤Ã¤¿ FLT
2765 ¥ª¥Ö¥¸¥§¥¯¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¼ºÇÔ¤·¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤¹¡£ */
2768 mflt_find (int c, MFLTFont *font)
2772 static MSymbol unicode_bmp = NULL, unicode_full = NULL;
2776 unicode_bmp = msymbol ("unicode-bmp");
2777 unicode_full = msymbol ("unicode-full");
2780 if (! flt_list && list_flt () < 0)
2782 /* Skip configured FLTs. */
2783 MPLIST_DO (plist, flt_list)
2784 if (((MFLT *) MPLIST_VAL (plist))->font_id == Mnil)
2790 MPLIST_DO (pl, plist)
2792 flt = MPLIST_VAL (pl);
2793 if (flt->registry != unicode_bmp
2794 && flt->registry != unicode_full)
2796 if (flt->family && flt->family != font->family)
2798 if (flt->name == Mcombining
2799 && ! mchartable_lookup (flt->coverage->table, 0))
2800 setup_combining_flt (flt);
2802 && ! mchartable_lookup (flt->coverage->table, c))
2806 MFLTOtfSpec *spec = &flt->otf;
2808 if (! font->check_otf)
2810 if ((spec->features[0] && spec->features[0][0] != 0xFFFFFFFF)
2811 || (spec->features[1] && spec->features[1][0] != 0xFFFFFFFF))
2814 else if (! font->check_otf (font, spec))
2827 MPLIST_DO (pl, plist)
2829 flt = MPLIST_VAL (pl);
2830 if (mchartable_lookup (flt->coverage->table, c))
2837 if (! CHECK_FLT_STAGES (flt))
2839 if (font && flt->need_config && mflt_font_id)
2840 flt = configure_flt (flt, font, mflt_font_id (font));
2846 @brief Return the name of an FLT.
2848 The mflt_name () function returns the name of $FLT. */
2851 @brief FLT ¤Î̾Á°¤òÊÖ¤¹.
2853 ´Ø¿ô mflt_name () ¤Ï $FLT ¤Î̾Á°¤òÊÖ¤¹¡£ */
2856 mflt_name (MFLT *flt)
2858 return MSYMBOL_NAME (flt->name);
2863 @brief Return a coverage of a FLT.
2865 The mflt_coverage () function returns a char-table that contains
2866 nonzero values for characters supported by $FLT. */
2869 @brief FLT ¤ÎÈϰϤòÊÖ¤¹.
2871 ´Ø¿ô mflt_coverage () ¤Ï¡¢$FLT ¤¬¥µ¥Ý¡¼¥È¤¹¤ëʸ»ú¤ËÂФ·¤Æ
2872 0 ¤Ç¤Ê¤¤Ãͤò´Þ¤àʸ»ú¥Æ¡¼¥Ö¥ë¤òÊÖ¤¹¡£ */
2875 mflt_coverage (MFLT *flt)
2877 return flt->coverage->table;
2882 @brief Layout characters with an FLT.
2884 The mflt_run () function layouts characters in $GSTRING between
2885 $FROM (inclusive) and $TO (exclusive) with $FONT. If $FLT is
2886 nonzero, it is used for all the charaters. Otherwise, appropriate
2887 FLTs are automatically chosen.
2890 The operation was successful. The value is the index to the
2891 glyph, which was previously indexed by $TO, in $GSTRING->glyphs.
2894 $GSTRING->glyphs is too short to store the result. The caller can
2895 call this fucntion again with a longer $GSTRING->glyphs.
2898 Some other error occurred. */
2901 @brief FLT ¤ò»È¤Ã¤Æʸ»ú¤ò¥ì¥¤¥¢¥¦¥È¤¹¤ë.
2903 ´Ø¿ô mflt_run () ¤Ï¡¢$GSTRING Ãæ¤Î $FROM ¤«¤é $TO ľÁ°¤Þ¤Ç¤Îʸ»ú¤ò
2904 $FONT ¤òÍѤ¤¤Æ¥ì¥¤¥¢¥¦¥È¤¹¤ë¡£¤â¤· $FLT
2905 ¤¬¥¼¥í¤Ç¤Ê¤±¤ì¤Ð¡¢¤½¤ÎÃͤò¤¹¤Ù¤Æ¤Îʸ»ú¤ËÂФ·¤ÆÍѤ¤¤ë¡£
2906 ¤½¤¦¤Ç¤Ê¤±¤ì¤ÐŬÀÚ¤Ê FLT ¤ò¼«Æ°Åª¤ËÁªÂò¤¹¤ë¡£
2909 ¼Â¹ÔÀ®¸ù¤ò¼¨¤¹¡£ÊÖ¤µ¤ì¤ëÃͤϡ¢$GSTRING->glyphs Ãæ¤Ç°ÊÁ° $TO
2910 ¤Ë¤è¤Ã¤Æ¼¨¤µ¤ì¤Æ¤¤¤¿¥°¥ê¥Õ¤Ø¤Î¥¤¥ó¥Ç¥¯¥¹¤Ç¤¢¤ë¡£
2913 ·ë²Ì¤ò³ÊǼ¤¹¤ë¤Ë¤Ï $GSTRING->glyphs ¤¬Ã»¤¹¤®¤ë¤³¤È¤ò¼¨¤¹¡£
2914 ¸Æ¤Ó½Ð¤·Â¦¤Ï¡¢¤è¤êŤ¤ $GSTRING->glyphs
2915 ¤òÍѤ¤¤ÆºÆÅÙ¤³¤Î´Ø¿ô¤ò¸Æ¤Ö¤³¤È¤¬¤Ç¤¤ë¡£
2918 ¤½¤Î¾¤Î¥¨¥é¡¼¤¬µ¯¤¤¿¤³¤È¤ò¼¨¤¹¡£ */
2921 mflt_run (MFLTGlyphString *gstring, int from, int to,
2922 MFLTFont *font, MFLT *flt)
2924 FontLayoutContext ctx;
2925 int match_indices[NMATCH];
2927 MFLTGlyphString out;
2928 int auto_flt = ! flt;
2930 int this_from, this_to;
2931 MSymbol font_id = mflt_font_id ? mflt_font_id (font) : Mnil;
2935 /* This is usually sufficient, but if not, we retry with the larger
2936 values at most 3 times. This value is also used for the
2937 allocating size of ctx.encoded. */
2938 out.allocated = (to - from) * 4;
2940 for (i = from; i < to; i++)
2942 g = GREF (gstring, i);
2946 memset (g, 0, sizeof (MFLTGlyph));
2949 g->from = g->to = i;
2952 for (this_from = from; this_from < to;)
2956 for (this_to = this_from; this_to < to; this_to++)
2957 if (mchartable_lookup (flt->coverage->table,
2958 GREF (gstring, this_to)->c))
2963 if (! flt_list && list_flt () < 0)
2965 font->get_glyph_id (font, gstring, this_from, to);
2966 font->get_metrics (font, gstring, this_from, to);
2970 for (this_to = this_from; this_to < to; this_to++)
2972 c = GREF (gstring, this_to)->c;
2973 if (c >= flt_min_coverage && c <= flt_max_coverage)
2976 for (; this_to < to; this_to++)
2978 c = GREF (gstring, this_to)->c;
2980 && mchartable_lookup (((MFLT *) font->internal)->coverage->table, c))
2982 flt = font->internal;
2985 flt = mflt_find (c, font);
2988 if (CHECK_FLT_STAGES (flt))
2990 font->internal = flt;
2997 if (this_from < this_to)
2999 font->get_glyph_id (font, gstring, this_from, this_to);
3000 font->get_metrics (font, gstring, this_from, this_to);
3001 this_from = this_to;
3006 MDEBUG_PRINT1 (" [FLT] (%s", MSYMBOL_NAME (flt->name));
3008 if (flt->need_config && font_id != Mnil)
3009 flt = configure_flt (flt, font, font_id);
3011 for (; this_to < to; this_to++)
3014 g = GREF (gstring, this_to);
3015 enc = (int) mchartable_lookup (flt->coverage->table, g->c);
3018 SET_CATEGORY_CODE (g, enc);
3024 MDEBUG_PRINT1 (" (%s)", MSYMBOL_NAME (font->family));
3025 MDEBUG_PRINT ("\n [FLT] (SOURCE");
3026 for (i = this_from, j = 0; i < this_to; i++, j++)
3028 if (j > 0 && j % 8 == 0)
3029 MDEBUG_PRINT ("\n [FLT] ");
3030 MDEBUG_PRINT1 (" %04X", GREF (gstring, i)->c);
3035 for (i = 0; i < 3; i++)
3038 memset (&ctx, 0, sizeof ctx);
3039 ctx.match_indices = match_indices;
3041 ctx.cluster_begin_idx = -1;
3044 j = run_stages (gstring, this_from, this_to, flt, &ctx);
3058 MDEBUG_PRINT ("\n [FLT] (RESULT");
3059 if (MDEBUG_FLAG () > 1)
3062 for (i = 0; this_from < this_to; i++, this_from++)
3064 g = GREF (gstring, this_from);
3068 MDEBUG_PRINT2 ("\n [FLT] %02d-%02d",
3071 MDEBUG_PRINT2 (" %02d-%02d", g->from, g->to);
3074 MDEBUG_PRINT4 (" (%04X %d %d %d)",
3075 g->code, g->xadv, g->xoff, g->yoff);
3079 for (; this_from < this_to; this_from++)
3080 MDEBUG_PRINT1 (" %04X", GREF (gstring, this_from)->code);
3081 MDEBUG_PRINT ("))\n");
3083 this_from = this_to;
3088 int len = to - from;
3091 memcpy (((char *) out.glyphs),
3092 ((char *) gstring->glyphs) + gstring->glyph_size * from,
3093 gstring->glyph_size * len);
3094 for (i = from, j = to; i < to;)
3096 for (k = i + 1, j--; k < to && GREF (&out, k)->xadv == 0;
3098 GCPY (&out, i, (k - i), gstring, j);
3106 int mflt_enable_new_feature;
3108 int (*mflt_iterate_otf_feature) (struct _MFLTFont *font,
3111 unsigned char *table);
3113 MSymbol (*mflt_font_id) (struct _MFLTFont *font);
3115 int (*mflt_try_otf) (struct _MFLTFont *font, MFLTOtfSpec *spec,
3116 MFLTGlyphString *gstring, int from, int to);
3119 /* for debugging... */
3122 dump_flt_cmd (FontLayoutStage *stage, int id, int indent)
3124 char *prefix = (char *) alloca (indent + 1);
3126 memset (prefix, 32, indent);
3130 fprintf (mdebug__output, "0x%02X", id);
3131 else if (id <= CMD_ID_OFFSET_INDEX)
3133 int idx = CMD_ID_TO_INDEX (id);
3134 FontLayoutCmd *cmd = stage->cmds + idx;
3136 if (cmd->type == FontLayoutCmdTypeRule)
3138 FontLayoutCmdRule *rule = &cmd->body.rule;
3141 fprintf (mdebug__output, "(rule ");
3142 if (rule->src_type == SRC_REGEX)
3143 fprintf (mdebug__output, "\"%s\"", rule->src.re.pattern);
3144 else if (rule->src_type == SRC_INDEX)
3145 fprintf (mdebug__output, "%d", rule->src.match_idx);
3146 else if (rule->src_type == SRC_SEQ)
3147 fprintf (mdebug__output, "(seq)");
3148 else if (rule->src_type == SRC_RANGE)
3149 fprintf (mdebug__output, "(range)");
3151 fprintf (mdebug__output, "(invalid src)");
3153 for (i = 0; i < rule->n_cmds; i++)
3155 fprintf (mdebug__output, "\n%s ", prefix);
3156 dump_flt_cmd (stage, rule->cmd_ids[i], indent + 2);
3158 fprintf (mdebug__output, ")");
3160 else if (cmd->type == FontLayoutCmdTypeCond)
3162 FontLayoutCmdCond *cond = &cmd->body.cond;
3165 fprintf (mdebug__output, "(cond");
3166 for (i = 0; i < cond->n_cmds; i++)
3168 fprintf (mdebug__output, "\n%s ", prefix);
3169 dump_flt_cmd (stage, cond->cmd_ids[i], indent + 2);
3171 fprintf (mdebug__output, ")");
3173 else if (cmd->type == FontLayoutCmdTypeOTF)
3175 fprintf (mdebug__output, "(otf)");
3178 fprintf (mdebug__output, "(error-command)");
3180 else if (id <= CMD_ID_OFFSET_COMBINING)
3181 fprintf (mdebug__output, "cominging-code");
3183 fprintf (mdebug__output, "(predefiend %d)", id);
3187 @brief Dump a Font Layout Table.
3189 The mdebug_dump_flt () function prints the Font Layout Table $FLT
3190 in a human readable way to the stderr or to what specified by the
3191 environment variable MDEBUG_OUTPUT_FILE. $INDENT specifies how
3192 many columns to indent the lines but the first one.
3195 This function returns $FLT. */
3198 mdebug_dump_flt (MFLT *flt, int indent)
3200 char *prefix = (char *) alloca (indent + 1);
3204 memset (prefix, 32, indent);
3206 fprintf (mdebug__output, "(flt");
3207 MPLIST_DO (plist, flt->stages)
3209 FontLayoutStage *stage = (FontLayoutStage *) MPLIST_VAL (plist);
3212 fprintf (mdebug__output, "\n%s (stage %d", prefix, stage_idx);
3213 for (i = 0; i < stage->used; i++)
3215 fprintf (mdebug__output, "\n%s ", prefix);
3216 dump_flt_cmd (stage, INDEX_TO_CMD_ID (i), indent + 4);
3218 fprintf (mdebug__output, ")");
3221 fprintf (mdebug__output, ")");
3226 mflt_dump_gstring (MFLTGlyphString *gstring)
3230 fprintf (mdebug__output, "(flt-gstring");
3231 for (i = 0; i < gstring->used; i++)
3233 MFLTGlyph *g = GREF (gstring, i);
3234 fprintf (mdebug__output, "\n (%02d pos:%d-%d c:%04X code:%04X cat:%c)",
3235 i, g->from, g->to, g->c, g->code, GET_CATEGORY_CODE (g));
3237 fprintf (mdebug__output, ")\n");