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 [-1,0] [-1,0] any|any all all
748 SCRIPT= NULL [-1,0] none&1 none all
749 SCRIPT+ [-1,0] NULL 1&none all none
750 SCRIPT=F1 [F1,0] [-1,0] F1&1 F1 all
751 SCRIPT+F1 [-1][0] [F1,0] none&F1 none F1
752 SCRIPT=F1+ [F1,0] NULL F1&none F1 none
753 SCRIPT=~F2 [-1,F2,0] [-1,0] ~F2&1 all~F2 all
754 SCRIPT=F1,~F2 [F1,-1,A2,0][-1,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)
819 * (feature_count[i] < 0 ? 2
820 : feature_count[i] + 1));
821 if (! spec->features[i])
823 if (feature_count[i] > 0)
824 otf_store_features (features[i] + 1, features[i + 1],
827 spec->features[i][0] = 0xFFFFFFFF, spec->features[i][1] = 0;
834 /* Parse OTF command name NAME and store the result in CMD.
836 :SCRIPT[/[LANGSYS][=[GSUB-FEATURES][+GPOS-FEATURES]]]
837 where GSUB-FEATURES and GPOS-FEATURES have this form:
838 [FEATURE[,FEATURE]*] | ' ' */
841 load_otf_command (FontLayoutCmd *cmd, MSymbol sym)
843 char *name = MSYMBOL_NAME (sym);
848 /* This is old format of "otf:...". Change it to ":otf=...". */
849 char *str = alloca (MSYMBOL_NAMELEN (sym) + 2);
851 sprintf (str, ":otf=");
852 strcat (str, name + 4);
856 result = parse_otf_command (sym, &cmd->body.otf);
859 cmd->type = (name[4] == '?' ? FontLayoutCmdTypeOTFCategory
860 : FontLayoutCmdTypeOTF);
865 /* Read a decimal number from STR preceded by one of "+-><". '+' and
866 '>' means a plus sign, '-' and '<' means a minus sign. If the
867 number is greater than 127, limit it to 127. */
870 read_decimal_number (char **str)
873 int sign = (*p == '-' || *p == '<') ? -1 : 1;
877 while (*p >= '0' && *p <= '9')
878 n = n * 10 + *p++ - '0';
882 return (n < 127 ? n * sign : 127 * sign);
886 /* Read a horizontal and vertical combining positions from STR, and
887 store them in the place pointed by X and Y. The horizontal
888 position left, center, and right are represented by 0, 1, and 2
889 respectively. The vertical position top, center, bottom, and base
890 are represented by 0, 1, 2, and 3 respectively. If successfully
891 read, return 0, else return -1. */
894 read_combining_position (char *str, int *x, int *y)
899 /* Vertical position comes first. */
900 for (i = 0; i < 4; i++)
909 /* Then comse horizontal position. */
910 for (i = 0; i < 3; i++)
920 /* Return a combining code corresponding to SYM. */
923 get_combining_command (MSymbol sym)
925 char *str = msymbol_name (sym);
926 int base_x, base_y, add_x, add_y, off_x, off_y;
929 if (read_combining_position (str, &base_x, &base_y) < 0)
940 if (c == '+' || c == '-')
942 off_y = read_decimal_number (&str) + 128;
947 if (c == '<' || c == '>')
948 off_x = read_decimal_number (&str) + 128;
952 if (read_combining_position (str, &add_x, &add_y) < 0)
955 c = MAKE_COMBINING_CODE (base_y, base_x, add_y, add_x, off_y, off_x);
956 return (COMBINING_CODE_TO_CMD_ID (c));
960 /* Load a command from PLIST into STAGE, and return that
961 identification number. If ID is not INVALID_CMD_ID, that means we
962 are loading a top level command or a macro. In that case, use ID
963 as the identification number of the command. Otherwise, generate a
964 new id number for the command. MACROS is a list of raw macros. */
967 load_command (FontLayoutStage *stage, MPlist *plist,
968 MPlist *macros, int id)
973 if (MPLIST_INTEGER_P (plist))
975 int code = MPLIST_INTEGER (plist);
978 MERROR (MERROR_DRAW, INVALID_CMD_ID);
981 else if (MPLIST_PLIST_P (plist))
983 /* PLIST ::= ( cond ... ) | ( STRING ... ) | ( INTEGER ... )
984 | ( ( INTEGER INTEGER ) ... )
985 | ( ( range INTEGER INTEGER ) ... )
986 | ( ( SYMBOL STRING ) ... )
987 | ( ( font-facilty [ INTEGER ] ) ... )
988 | ( ( font-facilty OTF-SPEC ) ... ) */
989 MPlist *elt = MPLIST_PLIST (plist);
990 int len = MPLIST_LENGTH (elt) - 1;
993 if (id == INVALID_CMD_ID)
996 id = INDEX_TO_CMD_ID (stage->used);
997 MLIST_APPEND1 (stage, cmds, dummy, MERROR_DRAW);
999 cmd = stage->cmds + CMD_ID_TO_INDEX (id);
1001 if (MPLIST_SYMBOL_P (elt))
1003 FontLayoutCmdCond *cond;
1005 if (MPLIST_SYMBOL (elt) != Mcond)
1006 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1007 elt = MPLIST_NEXT (elt);
1008 cmd->type = FontLayoutCmdTypeCond;
1009 cond = &cmd->body.cond;
1010 cond->seq_beg = cond->seq_end = -1;
1011 cond->seq_from = cond->seq_to = 0;
1013 MTABLE_CALLOC (cond->cmd_ids, len, MERROR_DRAW);
1014 for (i = 0; i < len; i++, elt = MPLIST_NEXT (elt))
1016 int this_id = load_command (stage, elt, macros, INVALID_CMD_ID);
1018 if (this_id == INVALID_CMD_ID || this_id == -2)
1019 MERROR (MERROR_DRAW, this_id);
1020 /* The above load_command may relocate stage->cmds. */
1021 cmd = stage->cmds + CMD_ID_TO_INDEX (id);
1022 cond = &cmd->body.cond;
1023 cond->cmd_ids[i] = this_id;
1024 if (this_id <= CMD_ID_OFFSET_INDEX)
1026 FontLayoutCmd *this_cmd
1027 = stage->cmds + CMD_ID_TO_INDEX (this_id);
1029 if (this_cmd->type == FontLayoutCmdTypeRule
1030 && this_cmd->body.rule.src_type == SRC_SEQ)
1032 int first_char = this_cmd->body.rule.src.seq.codes[0];
1034 if (cond->seq_beg < 0)
1036 /* The first SEQ command. */
1038 cond->seq_from = cond->seq_to = first_char;
1040 else if (cond->seq_end < 0)
1042 /* The following SEQ command. */
1043 if (cond->seq_from > first_char)
1044 cond->seq_from = first_char;
1045 else if (cond->seq_to < first_char)
1046 cond->seq_to = first_char;
1051 if (cond->seq_beg >= 0 && cond->seq_end < 0)
1052 /* The previous one is the last SEQ command. */
1058 if (cond->seq_beg >= 0 && cond->seq_end < 0)
1059 /* The previous one is the last SEQ command. */
1063 if (cond->seq_beg >= 0 && cond->seq_end < 0)
1064 /* The previous one is the last SEQ command. */
1069 cmd->type = FontLayoutCmdTypeRule;
1070 if (MPLIST_MTEXT_P (elt))
1072 MText *mt = MPLIST_MTEXT (elt);
1073 char *str = (char *) MTEXT_DATA (mt);
1077 mtext_ins_char (mt, 0, '^', 1);
1078 str = (char *) MTEXT_DATA (mt);
1080 if (regcomp (&cmd->body.rule.src.re.preg, str, REG_EXTENDED))
1081 MERROR (MERROR_FONT, INVALID_CMD_ID);
1082 cmd->body.rule.src_type = SRC_REGEX;
1083 cmd->body.rule.src.re.pattern = strdup (str);
1085 else if (MPLIST_INTEGER_P (elt))
1087 cmd->body.rule.src_type = SRC_INDEX;
1088 cmd->body.rule.src.match_idx = MPLIST_INTEGER (elt);
1090 else if (MPLIST_PLIST_P (elt))
1092 MPlist *pl = MPLIST_PLIST (elt), *p;
1093 int size = MPLIST_LENGTH (pl);
1095 if (MPLIST_INTEGER_P (pl))
1099 cmd->body.rule.src_type = SRC_SEQ;
1100 cmd->body.rule.src.seq.n_codes = size;
1101 MTABLE_CALLOC (cmd->body.rule.src.seq.codes, size,
1103 for (i = 0; i < size; i++, pl = MPLIST_NEXT (pl))
1105 if (! MPLIST_INTEGER_P (pl))
1106 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1107 cmd->body.rule.src.seq.codes[i]
1108 = (unsigned) MPLIST_INTEGER (pl);
1111 else if (MPLIST_SYMBOL_P (pl))
1113 if (MPLIST_SYMBOL (pl) == Mrange)
1116 MERROR (MERROR_FLT, INVALID_CMD_ID);
1117 cmd->body.rule.src_type = SRC_RANGE;
1118 pl = MPLIST_NEXT (pl);
1119 if (! MPLIST_INTEGER_P (pl))
1120 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1121 cmd->body.rule.src.range.from
1122 = (unsigned) MPLIST_INTEGER (pl);
1123 pl = MPLIST_NEXT (pl);
1124 if (! MPLIST_INTEGER_P (pl))
1125 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1126 cmd->body.rule.src.range.to
1127 = (unsigned) MPLIST_INTEGER (pl);
1129 else if (MPLIST_SYMBOL (pl) == Mfont_facility)
1131 FontLayoutCmdRule *rule = &cmd->body.rule;
1133 pl = MPLIST_NEXT (pl);
1134 if (MPLIST_SYMBOL_P (pl))
1136 MSymbol sym = MPLIST_SYMBOL (pl);
1137 char *otf_spec = MSYMBOL_NAME (sym);
1139 if (otf_spec[0] == ':' && otf_spec[1] == 'o'
1140 && otf_spec[2] == 't' && otf_spec[3] == 'f')
1141 parse_otf_command (sym, &rule->src.facility.otf_spec);
1143 MERROR (MERROR_FLT, INVALID_CMD_ID);
1144 rule->src_type = SRC_OTF_SPEC;
1145 pl = MPLIST_NEXT (pl);
1147 else if (MPLIST_TAIL_P (pl))
1148 MERROR (MERROR_FLT, INVALID_CMD_ID);
1150 rule->src_type = SRC_HAS_GLYPH;
1151 rule->src.facility.len = 0;
1154 if (! MPLIST_INTEGER_P (p)
1155 && (MPLIST_SYMBOL_P (p)
1156 ? MPLIST_SYMBOL (p) != Mequal
1158 MERROR (MERROR_FLT, INVALID_CMD_ID);
1159 rule->src.facility.len++;
1161 rule->src.facility.codes = pl;
1162 M17N_OBJECT_REF (pl);
1166 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1169 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1171 elt = MPLIST_NEXT (elt);
1172 cmd->body.rule.n_cmds = len;
1173 MTABLE_CALLOC (cmd->body.rule.cmd_ids, len, MERROR_DRAW);
1174 for (i = 0; i < len; i++, elt = MPLIST_NEXT (elt))
1176 int this_id = load_command (stage, elt, macros, INVALID_CMD_ID);
1178 if (this_id == INVALID_CMD_ID || this_id == -2)
1179 MERROR (MERROR_DRAW, this_id);
1180 /* The above load_command may relocate stage->cmds. */
1181 cmd = stage->cmds + CMD_ID_TO_INDEX (id);
1182 cmd->body.rule.cmd_ids[i] = this_id;
1186 else if (MPLIST_SYMBOL_P (plist))
1189 MSymbol sym = MPLIST_SYMBOL (plist);
1190 char *name = msymbol_name (sym);
1191 int len = strlen (name);
1195 && ((name[0] == 'o' && name[1] == 't'
1196 && name[2] == 'f' && name[3] == ':')
1197 || (name[0] == ':' && name[1] == 'o' && name[2] == 't'
1198 && name[3] == 'f' && (name[4] == '=' || name[4] == '?'))))
1200 result = load_otf_command (&cmd, sym);
1203 if (id == INVALID_CMD_ID)
1205 id = INDEX_TO_CMD_ID (stage->used);
1206 MLIST_APPEND1 (stage, cmds, cmd, MERROR_DRAW);
1209 stage->cmds[CMD_ID_TO_INDEX (id)] = cmd;
1217 else if (*name == '*')
1218 return CMD_ID_REPEAT;
1219 else if (*name == '<')
1220 return CMD_ID_CLUSTER_BEGIN;
1221 else if (*name == '>')
1222 return CMD_ID_CLUSTER_END;
1223 else if (*name == '|')
1224 return CMD_ID_SEPARATOR;
1225 else if (*name == '[')
1226 return CMD_ID_LEFT_PADDING;
1227 else if (*name == ']')
1228 return CMD_ID_RIGHT_PADDING;
1234 id = get_combining_command (sym);
1240 MPLIST_DO (elt, macros)
1242 if (sym == MPLIST_SYMBOL (MPLIST_PLIST (elt)))
1244 id = INDEX_TO_CMD_ID (i);
1245 if (stage->cmds[i].type == FontLayoutCmdTypeMAX)
1246 id = load_command (stage, MPLIST_NEXT (MPLIST_PLIST (elt)),
1252 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1255 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1261 free_flt_command (FontLayoutCmd *cmd)
1263 if (cmd->type == FontLayoutCmdTypeRule)
1265 FontLayoutCmdRule *rule = &cmd->body.rule;
1267 if (rule->src_type == SRC_REGEX)
1269 free (rule->src.re.pattern);
1270 regfree (&rule->src.re.preg);
1272 else if (rule->src_type == SRC_SEQ)
1273 free (rule->src.seq.codes);
1274 free (rule->cmd_ids);
1276 else if (cmd->type == FontLayoutCmdTypeCond)
1277 free (cmd->body.cond.cmd_ids);
1278 else if (cmd->type == FontLayoutCmdTypeOTF
1279 || cmd->type == FontLayoutCmdTypeOTFCategory)
1281 if (cmd->body.otf.features[0])
1282 free (cmd->body.otf.features[0]);
1283 if (cmd->body.otf.features[1])
1284 free (cmd->body.otf.features[1]);
1288 /* Load a generator from PLIST into a newly allocated FontLayoutStage,
1289 and return it. PLIST has this form:
1290 PLIST ::= ( COMMAND ( CMD-NAME COMMAND ) * )
1293 static FontLayoutStage *
1294 load_generator (MPlist *plist)
1296 FontLayoutStage *stage;
1298 FontLayoutCmd dummy;
1301 MSTRUCT_CALLOC (stage, MERROR_DRAW);
1302 MLIST_INIT1 (stage, cmds, 32);
1303 dummy.type = FontLayoutCmdTypeMAX;
1304 MLIST_APPEND1 (stage, cmds, dummy, MERROR_FONT);
1305 MPLIST_DO (elt, MPLIST_NEXT (plist))
1307 if (! MPLIST_PLIST_P (elt))
1308 MERROR (MERROR_FONT, NULL);
1309 pl = MPLIST_PLIST (elt);
1310 if (! MPLIST_SYMBOL_P (pl))
1311 MERROR (MERROR_FONT, NULL);
1312 MLIST_APPEND1 (stage, cmds, dummy, MERROR_FONT);
1315 /* Load the first command from PLIST into STAGE->cmds[0]. Macros
1316 called in the first command are also loaded from MPLIST_NEXT
1317 (PLIST) into STAGE->cmds[n]. */
1318 result = load_command (stage, plist, MPLIST_NEXT (plist),
1319 INDEX_TO_CMD_ID (0));
1320 if (result == INVALID_CMD_ID || result == -2)
1322 MLIST_FREE1 (stage, cmds);
1331 /* Load stages of the font layout table FLT. */
1334 load_flt (MFLT *flt, MPlist *key_list)
1336 MPlist *top, *plist, *pl, *p;
1337 FontLayoutCategory *category = NULL;
1341 top = (MPlist *) mdatabase__load_for_keys (flt->mdb, key_list);
1343 top = (MPlist *) mdatabase_load (flt->mdb);
1346 if (! MPLIST_PLIST_P (top))
1348 M17N_OBJECT_UNREF (top);
1349 MERROR (MERROR_FLT, -1);
1354 plist = mdatabase__props (flt->mdb);
1356 MERROR (MERROR_FLT, -1);
1357 MPLIST_DO (plist, plist)
1358 if (MPLIST_PLIST_P (plist))
1360 pl = MPLIST_PLIST (plist);
1361 if (! MPLIST_SYMBOL_P (pl)
1362 || MPLIST_SYMBOL (pl) != Mfont)
1364 pl = MPLIST_NEXT (pl);
1365 if (! MPLIST_PLIST_P (pl))
1367 p = MPLIST_PLIST (pl);
1368 if (! MPLIST_SYMBOL_P (p))
1370 p = MPLIST_NEXT (p);
1371 if (! MPLIST_SYMBOL_P (p))
1373 flt->family = MPLIST_SYMBOL (p);
1374 MPLIST_DO (p, MPLIST_NEXT (p))
1375 if (MPLIST_SYMBOL_P (p))
1377 sym = MPLIST_SYMBOL (p);
1378 if (MSYMBOL_NAME (sym)[0] != ':')
1379 flt->registry = sym, sym = Mnil;
1385 char *otf_spec = MSYMBOL_NAME (sym);
1387 if (otf_spec[0] == ':' && otf_spec[1] == 'o'
1388 && otf_spec[2] == 't' && otf_spec[3] == 'f')
1389 parse_otf_command (sym, &flt->otf);
1394 MPLIST_DO (plist, top)
1396 if (MPLIST_SYMBOL_P (plist)
1397 && MPLIST_SYMBOL (plist) == Mend)
1399 mplist_set (plist, Mnil, NULL);
1402 if (! MPLIST_PLIST (plist))
1404 pl = MPLIST_PLIST (plist);
1405 if (! MPLIST_SYMBOL_P (pl))
1407 sym = MPLIST_SYMBOL (pl);
1408 pl = MPLIST_NEXT (pl);
1411 if (sym == Mcategory)
1414 unref_category_table (category);
1415 else if (flt->coverage)
1417 category = flt->coverage;
1418 ref_category_table (category);
1421 category = load_category_table (pl, NULL);
1424 if (! flt->coverage)
1426 flt->coverage = category;
1427 ref_category_table (category);
1429 if (category->definition)
1430 flt->need_config = 1;
1432 else if (sym == Mgenerator)
1434 FontLayoutStage *stage;
1438 stage = load_generator (pl);
1441 stage->category = category;
1442 M17N_OBJECT_REF (category->table);
1444 flt->stages = mplist ();
1445 mplist_add (flt->stages, Mt, stage);
1449 unref_category_table (category);
1451 if (! MPLIST_TAIL_P (plist))
1453 M17N_OBJECT_UNREF (top);
1454 M17N_OBJECT_UNREF (flt->stages);
1455 MERROR (MERROR_FLT, -1);
1457 M17N_OBJECT_UNREF (top);
1463 free_flt_stage (MFLT *flt, FontLayoutStage *stage)
1467 unref_category_table (stage->category);
1470 for (i = 0; i < stage->used; i++)
1471 free_flt_command (stage->cmds + i);
1472 MLIST_FREE1 (stage, cmds);
1484 MPLIST_DO (plist, flt_list)
1486 MFLT *flt = MPLIST_VAL (plist);
1489 unref_category_table (flt->coverage);
1492 MPLIST_DO (pl, MPLIST_NEXT (flt->stages))
1493 free_flt_stage (flt, MPLIST_VAL (pl));
1494 M17N_OBJECT_UNREF (flt->stages);
1497 MPLIST_VAL (plist) = NULL;
1499 M17N_OBJECT_UNREF (flt_list);
1506 MPlist *plist, *key_list = NULL;
1510 if (! (plist = mdatabase_list (Mfont, Mlayouter, Mnil, Mnil)))
1512 if (! (flt_list = mplist ()))
1514 if (! (key_list = mplist ()))
1516 if (! mplist_add (key_list, Mcategory, Mt))
1519 MPLIST_DO (pl, plist)
1521 MDatabase *mdb = MPLIST_VAL (pl);
1522 MSymbol *tags = mdatabase_tag (mdb);
1525 if (! MSTRUCT_CALLOC_SAFE (flt))
1527 flt->name = tags[2];
1529 if (load_flt (flt, key_list) < 0)
1533 if (MPLIST_TAIL_P (flt_list))
1535 flt_min_coverage = mchartable_min_char (flt->coverage->table);
1536 flt_max_coverage = mchartable_max_char (flt->coverage->table);
1542 c = mchartable_min_char (flt->coverage->table);
1543 if (flt_min_coverage > c)
1544 flt_min_coverage = c;
1545 c = mchartable_max_char (flt->coverage->table);
1546 if (flt_max_coverage < c)
1547 flt_max_coverage = c;
1549 if (! mplist_push (flt_list, flt->name, flt))
1559 M17N_OBJECT_UNREF (plist);
1560 M17N_OBJECT_UNREF (key_list);
1564 /* FLS (Font Layout Service) */
1566 /* Structure to hold information about a context of FLS. */
1570 /* Pointer to the current stage. */
1571 FontLayoutStage *stage;
1573 /* Pointer to the category table of the next stage or NULL if none. */
1574 FontLayoutCategory *category;
1576 /* Pointer to the font. */
1579 /* Input and output glyph string. */
1580 MFLTGlyphString *in, *out;
1582 /* Encode each character or code of a glyph by the current category
1583 table into this array. An element is a category letter used for
1584 a regular expression matching. */
1589 int cluster_begin_idx;
1590 int cluster_begin_pos;
1591 int cluster_end_pos;
1595 } FontLayoutContext;
1597 static int run_command (int, int, int, int, FontLayoutContext *);
1598 static int run_otf (int, MFLTOtfSpec *, int, int, FontLayoutContext *);
1599 static int try_otf (int, MFLTOtfSpec *, int, int, FontLayoutContext *);
1604 run_rule (int depth,
1605 FontLayoutCmdRule *rule, int from, int to, FontLayoutContext *ctx)
1607 int *saved_match_indices = ctx->match_indices;
1608 int match_indices[NMATCH * 2];
1611 int orig_from = from;
1612 int need_cluster_update = 0;
1614 if (rule->src_type == SRC_REGEX)
1616 regmatch_t pmatch[NMATCH];
1622 saved_code = ctx->encoded[to - ctx->encoded_offset];
1623 ctx->encoded[to - ctx->encoded_offset] = '\0';
1624 result = regexec (&(rule->src.re.preg),
1625 ctx->encoded + (from - ctx->encoded_offset),
1627 if (result == 0 && pmatch[0].rm_so == 0)
1629 if (MDEBUG_FLAG () > 2)
1630 MDEBUG_PRINT5 ("\n [FLT] %*s(REGEX \"%s\" \"%s\" %d", depth, "",
1631 rule->src.re.pattern,
1632 ctx->encoded + (from - ctx->encoded_offset),
1634 ctx->encoded[to - ctx->encoded_offset] = saved_code;
1635 for (i = 0; i < NMATCH; i++)
1637 if (pmatch[i].rm_so < 0)
1638 match_indices[i * 2] = match_indices[i * 2 + 1] = -1;
1641 match_indices[i * 2] = from + pmatch[i].rm_so;
1642 match_indices[i * 2 + 1] = from + pmatch[i].rm_eo;
1645 ctx->match_indices = match_indices;
1646 to = match_indices[1];
1650 ctx->encoded[to - ctx->encoded_offset] = saved_code;
1653 need_cluster_update = 1;
1655 else if (rule->src_type == SRC_SEQ)
1659 len = rule->src.seq.n_codes;
1660 if (len > (to - from))
1662 for (i = 0; i < len; i++)
1663 if (rule->src.seq.codes[i] != GREF (ctx->in, from + i)->c)
1668 if (MDEBUG_FLAG () > 2)
1669 MDEBUG_PRINT3 ("\n [FLT] %*s(SEQ 0x%X", depth, "",
1670 rule->src.seq.codes[0]);
1671 need_cluster_update = 1;
1673 else if (rule->src_type == SRC_RANGE)
1679 head = GREF (ctx->in, from)->c;
1680 if (head < rule->src.range.from || head > rule->src.range.to)
1682 ctx->code_offset = head - rule->src.range.from;
1684 if (MDEBUG_FLAG () > 2)
1685 MDEBUG_PRINT4 ("\n [FLT] %*s(RANGE 0x%X-0x%X", depth, "",
1686 rule->src.range.from, rule->src.range.to);
1687 need_cluster_update = 1;
1689 else if (rule->src_type == SRC_INDEX)
1691 if (rule->src.match_idx >= NMATCH)
1693 from = ctx->match_indices[rule->src.match_idx * 2];
1696 to = ctx->match_indices[rule->src.match_idx * 2 + 1];
1697 if (MDEBUG_FLAG () > 2)
1698 MDEBUG_PRINT3 ("\n [FLT] %*s(SUBPART %d", depth, "",
1699 rule->src.match_idx);
1700 need_cluster_update = 1;
1702 else if (rule->src_type == SRC_HAS_GLYPH
1703 || rule->src_type == SRC_OTF_SPEC)
1705 static MFLTGlyphString gstring;
1709 if (rule->src.facility.len > 0)
1711 if (! gstring.glyph_size)
1713 gstring.glyph_size = ctx->in->glyph_size;
1714 gstring.glyphs = calloc (rule->src.facility.len,
1715 gstring.glyph_size);
1716 gstring.allocated = rule->src.facility.len;
1717 gstring.used = rule->src.facility.len;
1719 else if (rule->src.facility.len < gstring.allocated)
1721 gstring.glyphs = realloc (gstring.glyphs,
1723 * rule->src.facility.len);
1724 gstring.allocated = rule->src.facility.len;
1725 gstring.used = rule->src.facility.len;
1728 for (i = 0, p = rule->src.facility.codes, idx = from;
1729 i < rule->src.facility.len; i++, p = MPLIST_NEXT (p))
1731 if (MPLIST_INTEGER_P (p))
1733 GREF (&gstring, i)->c = MPLIST_INTEGER (p);
1734 GREF (&gstring, i)->encoded = 0;
1738 GREF (&gstring, i)->c = GREF (ctx->in, idx)->code;
1739 GREF (&gstring, i)->encoded = GREF (ctx->in, idx)->encoded;
1745 if (MDEBUG_FLAG () > 2)
1747 if (rule->src_type == SRC_HAS_GLYPH)
1748 MDEBUG_PRINT2 ("\n [FLT] %*s(HAS-GLYPH", depth, "");
1750 MDEBUG_PRINT2 ("\n [FLT] %*s(OTF-SPEC", depth, "");
1751 for (i = 0; i < rule->src.facility.len; i++)
1752 MDEBUG_PRINT1 (" %04X", GREF (&gstring, i)->code);
1754 if (ctx->font->get_glyph_id (ctx->font, &gstring, 0,
1755 rule->src.facility.len) < 0)
1757 MDEBUG_PRINT (") FAIL!");
1760 if (rule->src_type == SRC_OTF_SPEC)
1762 MFLTOtfSpec *spec = &rule->src.facility.otf_spec;
1764 if (! ctx->font->check_otf)
1766 if ((spec->features[0] && spec->features[0][0] != 0xFFFFFFFF)
1767 || (spec->features[1] && spec->features[1][0] != 0xFFFFFFFF))
1772 if (rule->src.facility.len == 0)
1774 if (! ctx->font->check_otf (ctx->font, spec))
1779 int prev_out_used = ctx->out->used, out_used;
1780 MFLTGlyphAdjustment *adjustment;
1782 adjustment = alloca ((sizeof *adjustment)
1783 * (ctx->out->allocated - ctx->out->used));
1785 MERROR (MERROR_FLT, -1);
1786 memset (adjustment, 0,
1787 (sizeof *adjustment)
1788 * (ctx->out->allocated - ctx->out->used));
1789 ctx->font->drive_otf (ctx->font, &rule->src.facility.otf_spec,
1790 &gstring, 0, rule->src.facility.len,
1793 out_used = ctx->out->used;
1794 ctx->out->used = prev_out_used;
1795 if (rule->src.facility.len == out_used - prev_out_used)
1797 for (i = prev_out_used; i < out_used; i++)
1799 if (GREF (&gstring, i - prev_out_used)->code
1800 != GREF (ctx->out, i)->code)
1802 if (adjustment[i - prev_out_used].set)
1813 if (need_cluster_update && ctx->cluster_begin_idx >= 0)
1815 for (i = from; i < to; i++)
1817 MFLTGlyph *g = GREF (ctx->in, i);
1818 UPDATE_CLUSTER_RANGE (ctx, g);
1824 for (i = 0; i < rule->n_cmds; i++)
1828 if (rule->cmd_ids[i] == CMD_ID_REPEAT)
1834 pos = run_command (depth, rule->cmd_ids[i], from, to, ctx);
1837 consumed = pos > from;
1842 ctx->match_indices = saved_match_indices;
1843 if (MDEBUG_FLAG () > 2)
1845 return (rule->src_type == SRC_INDEX ? orig_from : to);
1849 run_cond (int depth,
1850 FontLayoutCmdCond *cond, int from, int to, FontLayoutContext *ctx)
1854 if (MDEBUG_FLAG () > 2)
1855 MDEBUG_PRINT2 ("\n [FLT] %*s(COND", depth, "");
1857 for (i = 0; i < cond->n_cmds; i++)
1859 /* TODO: Write a code for optimization utilizaing the info
1861 if ((pos = run_command (depth, cond->cmd_ids[i], from, to, ctx))
1867 if (MDEBUG_FLAG () > 2)
1873 decode_packed_otf_tag (FontLayoutContext *ctx, MFLTGlyphString *gstring,
1874 int from, int to, FontLayoutCategory *category)
1876 for (; from < to; from++)
1878 MFLTGlyph *g = GREF (gstring, from);
1879 unsigned int tag = g->internal & 0xFFFFFFF;
1882 if (GET_COMBINED (g))
1886 SET_CATEGORY_CODE (g, 0);
1890 if (tag & 0xFFFFF80)
1894 /* Clear the feature tag code. */
1895 g->internal &= ~0xFFFFFFF;
1896 for (i = 0; i < category->feature_table.size; i++)
1897 if (category->feature_table.tag[i] == tag)
1899 enc = category->feature_table.code[i];
1900 if (ctx->in == gstring)
1901 ctx->encoded[from - ctx->encoded_offset] = enc;
1906 enc = (g->c > 0 ? (int) mchartable_lookup (category->table, g->c)
1907 : g->c == 0 ? 1 : ' ');
1908 SET_CATEGORY_CODE (g, enc);
1914 MFLTOtfSpec *otf_spec, int from, int to, FontLayoutContext *ctx)
1916 MFLTFont *font = ctx->font;
1917 int from_idx = ctx->out->used;
1919 if (MDEBUG_FLAG () > 2)
1920 MDEBUG_PRINT3 ("\n [FLT] %*s%s", depth, "", MSYMBOL_NAME (otf_spec->sym));
1922 font->get_glyph_id (font, ctx->in, from, to);
1923 if (! font->drive_otf)
1925 if (ctx->out->used + (to - from) > ctx->out->allocated)
1927 font->get_metrics (font, ctx->in, from, to);
1928 GCPY (ctx->in, from, to - from, ctx->out, ctx->out->used);
1929 ctx->out->used += to - from;
1933 MFLTGlyphAdjustment *adjustment;
1937 adjustment = alloca ((sizeof *adjustment)
1938 * (ctx->out->allocated - ctx->out->used));
1940 MERROR (MERROR_FLT, -1);
1941 memset (adjustment, 0,
1942 (sizeof *adjustment) * (ctx->out->allocated - ctx->out->used));
1943 to = font->drive_otf (font, otf_spec, ctx->in, from, to, ctx->out,
1947 decode_packed_otf_tag (ctx, ctx->out, from_idx, ctx->out->used,
1949 out_len = ctx->out->used - from_idx;
1950 if (otf_spec->features[1])
1952 MFLTGlyphAdjustment *a;
1955 for (i = 0, a = adjustment; i < out_len; i++, a++)
1960 font->get_metrics (font, ctx->out, from_idx, ctx->out->used);
1961 for (g = GREF (ctx->out, from_idx + i);
1962 i < out_len; i++, a++, g = NEXT (ctx->out, g))
1965 if (a->advance_is_absolute)
1970 else if (a->xadv || a->yadv)
1975 if (a->xoff || a->yoff || a->back)
1978 MFLTGlyph *gg = PREV (ctx->out, g);
1979 MFLTGlyphAdjustment *aa = a;
1983 g->lbearing += a->xoff;
1984 g->rbearing += a->xoff;
1985 g->ascent -= a->yoff;
1986 g->descent -= a->yoff;
1987 while (aa->back > 0)
1989 for (j = 0; j < aa->back;
1990 j++, gg = PREV (ctx->out, gg))
1992 g->xoff -= gg->xadv;
1993 g->lbearing -= gg->xadv;
1994 g->rbearing -= gg->xadv;
1997 g->xoff += aa->xoff;
1998 g->yoff += aa->yoff;
1999 g->lbearing += aa->xoff;
2000 g->rbearing += aa->xoff;
2001 g->ascent -= aa->yoff;
2002 g->descent -= aa->yoff;
2011 if (ctx->cluster_begin_idx >= 0)
2012 for (; from_idx < ctx->out->used; from_idx++)
2014 MFLTGlyph *g = GREF (ctx->out, from_idx);
2015 UPDATE_CLUSTER_RANGE (ctx, g);
2021 try_otf (int depth, MFLTOtfSpec *otf_spec, int from, int to,
2022 FontLayoutContext *ctx)
2024 MFLTFont *font = ctx->font;
2026 if (MDEBUG_FLAG () > 2)
2027 MDEBUG_PRINT3 ("\n [FLT] %*s%s", depth, "", MSYMBOL_NAME (otf_spec->sym));
2029 if (! otf_spec->features[0] && ! otf_spec->features[1])
2031 /* Reset categories. */
2032 MCharTable *table = ctx->category->table;
2035 for (i = from; i < to; i++)
2037 MFLTGlyph *g = GREF (ctx->in, i);
2039 if (! GET_COMBINED (g))
2041 char enc = (GET_ENCODED (g)
2042 ? (g->c > 0 ? (int) mchartable_lookup (table, g->c)
2045 ? (int) mchartable_lookup (table, g->code)
2047 SET_CATEGORY_CODE (g, enc);
2048 ctx->encoded[i - ctx->encoded_offset] = enc;
2054 if (ctx->stage->category->feature_table.size == 0)
2057 font->get_glyph_id (font, ctx->in, from, to);
2060 to = mflt_try_otf (font, otf_spec, ctx->in, from, to);
2063 decode_packed_otf_tag (ctx, ctx->in, from, to, ctx->stage->category);
2068 static char work[16];
2071 dump_combining_code (int code)
2073 char *vallign = "tcbB";
2074 char *hallign = "lcr";
2080 work[0] = vallign[COMBINING_CODE_BASE_Y (code)];
2081 work[1] = hallign[COMBINING_CODE_BASE_X (code)];
2082 off_y = COMBINING_CODE_OFF_Y (code);
2083 off_x = COMBINING_CODE_OFF_X (code);
2085 sprintf (work + 2, "+%d", off_y);
2087 sprintf (work + 2, "%d", off_y);
2088 else if (off_x == 0)
2089 sprintf (work + 2, ".");
2090 p = work + strlen (work);
2092 sprintf (p, ">%d", off_x);
2094 sprintf (p, "<%d", -off_x);
2096 p[0] = vallign[COMBINING_CODE_ADD_Y (code)];
2097 p[1] = hallign[COMBINING_CODE_ADD_X (code)];
2103 run_command (int depth, int id, int from, int to, FontLayoutContext *ctx)
2110 MCharTable *table = ctx->category ? ctx->category->table : NULL;
2113 /* Direct code (== ctx->code_offset + id) output.
2114 The source is not consumed. */
2115 if (MDEBUG_FLAG () > 2)
2116 MDEBUG_PRINT3 ("\n [FLT] %*s(DIRECT 0x%X", depth, "",
2117 ctx->code_offset + id);
2118 i = (from < to || from == 0) ? from : from - 1;
2120 g = GREF (ctx->out, ctx->out->used - 1);
2121 g->c = g->code = ctx->code_offset + id;
2122 if (ctx->combining_code)
2123 SET_COMBINING_CODE (g, ctx, ctx->combining_code);
2126 enc = (GET_ENCODED (g)
2127 ? (g->c > 0 ? (int) mchartable_lookup (table, g->c) : 1)
2129 ? (int) mchartable_lookup (table, g->code)
2131 SET_CATEGORY_CODE (g, enc);
2134 SET_MEASURED (g, 0);
2135 if (ctx->left_padding)
2136 SET_LEFT_PADDING (g, ctx, LeftPaddingMask);
2137 for (i = from; i < to; i++)
2139 MFLTGlyph *tmp = GREF (ctx->in, i);
2141 if (g->from > tmp->from)
2142 g->from = tmp->from;
2143 else if (g->to < tmp->to)
2146 if (ctx->cluster_begin_idx >= 0)
2147 UPDATE_CLUSTER_RANGE (ctx, g);
2148 ctx->code_offset = ctx->combining_code = ctx->left_padding = 0;
2149 if (MDEBUG_FLAG () > 2)
2154 if (id <= CMD_ID_OFFSET_INDEX)
2156 int idx = CMD_ID_TO_INDEX (id);
2159 if (idx >= ctx->stage->used)
2160 MERROR (MERROR_DRAW, -1);
2161 cmd = ctx->stage->cmds + idx;
2162 if (cmd->type == FontLayoutCmdTypeRule)
2163 to = run_rule (depth, &cmd->body.rule, from, to, ctx);
2164 else if (cmd->type == FontLayoutCmdTypeCond)
2165 to = run_cond (depth, &cmd->body.cond, from, to, ctx);
2166 else if (cmd->type == FontLayoutCmdTypeOTF)
2167 to = run_otf (depth, &cmd->body.otf, from, to, ctx);
2168 else if (cmd->type == FontLayoutCmdTypeOTFCategory)
2169 to = try_otf (depth, &cmd->body.otf, from, to, ctx);
2173 if (id <= CMD_ID_OFFSET_COMBINING)
2175 ctx->combining_code = CMD_ID_TO_COMBINING_CODE (id);
2176 if (MDEBUG_FLAG () > 2)
2177 MDEBUG_PRINT3 ("\n [FLT] %*s(CMB %s)", depth, "",
2178 dump_combining_code (ctx->combining_code));
2189 g = GREF (ctx->out, ctx->out->used - 1);
2190 if (ctx->combining_code)
2191 SET_COMBINING_CODE (g, ctx, ctx->combining_code);
2192 if (ctx->left_padding)
2193 SET_LEFT_PADDING (g, ctx, LeftPaddingMask);
2194 if (ctx->cluster_begin_idx >= 0)
2195 UPDATE_CLUSTER_RANGE (ctx, g);
2196 if (MDEBUG_FLAG () > 2)
2199 MDEBUG_PRINT2 ("\n [FLT] %*s(COPY |)", depth, "");
2201 MDEBUG_PRINT3 ("\n [FLT] %*s(COPY 0x%X)", depth, "", g->c);
2203 ctx->code_offset = ctx->combining_code = ctx->left_padding = 0;
2207 case CMD_ID_CLUSTER_BEGIN:
2208 if (ctx->cluster_begin_idx < 0)
2210 if (MDEBUG_FLAG () > 2)
2211 MDEBUG_PRINT3 ("\n [FLT] %*s<%d", depth, "",
2212 GREF (ctx->in, from)->from);
2213 ctx->cluster_begin_idx = ctx->out->used;
2214 ctx->cluster_begin_pos = GREF (ctx->in, from)->from;
2215 ctx->cluster_end_pos = GREF (ctx->in, from)->to;
2219 case CMD_ID_CLUSTER_END:
2220 if (ctx->cluster_begin_idx >= 0
2221 && ctx->cluster_begin_idx < ctx->out->used)
2225 if (MDEBUG_FLAG () > 2)
2226 MDEBUG_PRINT1 (" %d>", ctx->cluster_end_pos + 1);
2227 for (i = ctx->cluster_begin_idx; i < ctx->out->used; i++)
2229 GREF (ctx->out, i)->from = ctx->cluster_begin_pos;
2230 GREF (ctx->out, i)->to = ctx->cluster_end_pos;
2232 ctx->cluster_begin_idx = -1;
2236 case CMD_ID_SEPARATOR:
2240 if (MDEBUG_FLAG () > 2)
2241 MDEBUG_PRINT2 ("\n [FLT] %*s|", depth, "");
2242 i = from < to ? from : from - 1;
2244 g = GREF (ctx->out, ctx->out->used - 1);
2245 g->c = -1, g->code = 0;
2246 g->xadv = g->yadv = 0;
2248 SET_MEASURED (g, 0);
2249 SET_CATEGORY_CODE (g, ' ');
2253 case CMD_ID_LEFT_PADDING:
2254 if (MDEBUG_FLAG () > 2)
2255 MDEBUG_PRINT2 ("\n [FLT] %*s[", depth, "");
2256 ctx->left_padding = 1;
2259 case CMD_ID_RIGHT_PADDING:
2260 if (ctx->out->used > 0)
2262 if (MDEBUG_FLAG () > 2)
2263 MDEBUG_PRINT2 ("\n [FLT] %*s]", depth, "");
2264 g = GREF (ctx->out, ctx->out->used - 1);
2265 SET_RIGHT_PADDING (g, ctx, RightPaddingMask);
2270 MERROR (MERROR_DRAW, -1);
2274 run_stages (MFLTGlyphString *gstring, int from, int to,
2275 MFLT *flt, FontLayoutContext *ctx)
2277 MFLTGlyphString buf, *temp;
2279 int orig_from = from, orig_to = to;
2280 int from_pos, to_pos, len;
2283 MPlist *stages = flt->stages;
2284 FontLayoutCategory *prev_category = NULL;
2286 from_pos = GREF (ctx->in, from)->from;
2287 to_pos = GREF (ctx->in, to - 1)->to;
2288 len = to_pos - from_pos;
2292 GINIT (ctx->out, ctx->out->allocated);
2293 ctx->encoded = alloca (ctx->out->allocated);
2294 if (! ctx->out->glyphs || ! ctx->encoded)
2297 for (stage_idx = 0; 1; stage_idx++)
2302 ctx->stage = (FontLayoutStage *) MPLIST_VAL (stages);
2303 table = ctx->stage->category->table;
2304 stages = MPLIST_NEXT (stages);
2305 if (MPLIST_TAIL_P (stages))
2306 ctx->category = NULL;
2308 ctx->category = ((FontLayoutStage *) MPLIST_VAL (stages))->category;
2309 ctx->code_offset = ctx->combining_code = ctx->left_padding = 0;
2310 ctx->encoded_offset = from;
2311 for (i = from; i < to; i++)
2313 MFLTGlyph *g = GREF (ctx->in, i);
2316 if (GET_COMBINED (g)
2317 || (prev_category && prev_category != ctx->stage->category))
2319 enc = (GET_ENCODED (g)
2320 ? (g->c > 0 ? (int) mchartable_lookup (table, g->c) : 1)
2322 ? (int) mchartable_lookup (table, g->code)
2324 if (! GET_COMBINED (g))
2325 SET_CATEGORY_CODE (g, enc);
2328 enc = GET_CATEGORY_CODE (g);
2329 ctx->encoded[i - from] = enc;
2330 if (! enc && stage_idx == 0)
2336 ctx->encoded[i - from] = '\0';
2337 ctx->match_indices[0] = from;
2338 ctx->match_indices[1] = to;
2339 for (i = 2; i < NMATCH; i++)
2340 ctx->match_indices[i] = -1;
2342 if (MDEBUG_FLAG () > 2)
2344 MDEBUG_PRINT2 ("\n [FLT] (STAGE %d \"%s\"", stage_idx,
2346 MDEBUG_PRINT (" (");
2347 for (i = from; i < to; i++)
2349 g = GREF (ctx->in, i);
2351 MDEBUG_PRINT2 ("%*s|", (i > 0), "");
2353 MDEBUG_PRINT3 ("%*s%04X", (i > 0), "", GREF (ctx->in, i)->code);
2357 result = run_command (4, INDEX_TO_CMD_ID (0), from, to, ctx);
2358 if (MDEBUG_FLAG () > 2)
2363 /* If this is the last stage, break the loop. */
2364 if (MPLIST_TAIL_P (stages))
2367 /* Otherwise, prepare for the next stage. */
2368 prev_category = ctx->stage->category;
2375 GINIT (&buf, ctx->out->allocated);
2384 if (ctx->out->used > 0)
2387 int x_ppem = ctx->font->x_ppem << 6, y_ppem = ctx->font->y_ppem << 6;
2389 /* Remove separator glyphs. */
2390 for (i = 0; i < ctx->out->used;)
2392 g = GREF (ctx->out, i);
2394 GREPLACE (NULL, 0, 0, ctx->out, i, i + 1);
2399 /* Get actual glyph IDs of glyphs. */
2400 ctx->font->get_glyph_id (ctx->font, ctx->out, 0, ctx->out->used);
2402 /* Check if all characters in the range are covered by some
2403 glyph(s). If not, change <from> and <to> of glyphs to cover
2404 uncovered characters. */
2405 g_indices = alloca (sizeof (int) * len);
2408 for (i = 0; i < len; i++) g_indices[i] = -1;
2409 for (i = 0; i < ctx->out->used; i++)
2413 g = GREF (ctx->out, i);
2414 for (pos = g->from; pos <= g->to; pos++)
2415 if (g_indices[pos - from_pos] < 0)
2416 g_indices[pos - from_pos] = i;
2418 for (i = 0; i < len; i++)
2419 if (g_indices[i] < 0)
2425 for (i++; i < len && g_indices[i] < 0; i++);
2427 g = GREF (ctx->out, j);
2428 this_from = g->from;
2430 g->from = orig_from + i;
2431 } while (++j < ctx->out->used
2432 && (g = GREF (ctx->out, j))
2433 && g->from == this_from);
2439 j = g_indices[i - 1];
2440 g = GREF (ctx->out, j);
2443 g->to = orig_from + i + 1;
2445 && (g = GREF (ctx->out, j))
2446 && g->to == this_to);
2450 ctx->font->get_metrics (ctx->font, ctx->out, 0, ctx->out->used);
2452 /* Handle combining. */
2453 if (ctx->check_mask & CombinedMask)
2455 MFLTGlyph *base = GREF (ctx->out, 0);
2456 int base_height = base->ascent + base->descent;
2457 int base_width = base->rbearing - base->lbearing;
2460 for (i = 1; i < ctx->out->used; i++)
2462 if ((g = GREF (ctx->out, i))
2464 && (combining_code = GET_COMBINING_CODE (g)))
2466 int height = g->ascent + g->descent;
2467 int width = g->rbearing - g->lbearing;
2468 int base_x, base_y, add_x, add_y, off_x, off_y;
2470 if (base->from > g->from)
2471 base->from = g->from;
2472 else if (base->to < g->to)
2475 base_x = COMBINING_CODE_BASE_X (combining_code);
2476 base_y = COMBINING_CODE_BASE_Y (combining_code);
2477 add_x = COMBINING_CODE_ADD_X (combining_code);
2478 add_y = COMBINING_CODE_ADD_Y (combining_code);
2479 off_x = COMBINING_CODE_OFF_X (combining_code);
2480 off_y = COMBINING_CODE_OFF_Y (combining_code);
2482 g->xoff = ((base_width * base_x - width * add_x) / 2
2483 + x_ppem * off_x / 100
2484 - (base->xadv - base->lbearing) - g->lbearing);
2486 g->yoff = base_height * base_y / 2 - base->ascent;
2490 g->yoff -= height * add_y / 2 - g->ascent;
2491 g->yoff -= y_ppem * off_y / 100;
2492 if (base->lbearing > base->xadv + g->lbearing + g->xoff)
2493 base->lbearing = base->xadv + g->lbearing + g->xoff;
2494 if (base->rbearing < base->xadv + g->rbearing + g->xoff)
2495 base->rbearing = base->xadv + g->rbearing + g->xoff;
2496 if (base->ascent < g->ascent - g->yoff)
2497 base->ascent = g->ascent - g->yoff;
2498 if (base->descent < g->descent - g->yoff)
2499 base->descent = g->descent - g->yoff;
2500 g->xadv = g->yadv = 0;
2501 if (GET_RIGHT_PADDING (g))
2502 SET_RIGHT_PADDING (base, ctx, RightPaddingMask);
2508 base_height = g->ascent + g->descent;
2509 base_width = g->rbearing - g->lbearing;
2514 /* Handle padding */
2515 if (ctx->check_mask & (LeftPaddingMask | RightPaddingMask))
2516 for (i = 0; i < ctx->out->used; i++)
2518 g = GREF (ctx->out, i);
2519 if (! GET_COMBINED (g))
2521 if (GET_RIGHT_PADDING (g) && g->rbearing > g->xadv)
2523 g->xadv = g->rbearing;
2526 if (GET_LEFT_PADDING (g) && g->lbearing < 0)
2528 g->xoff += - g->lbearing;
2529 g->xadv += - g->lbearing;
2530 g->rbearing += - g->lbearing;
2538 GREPLACE (ctx->out, 0, ctx->out->used, gstring, orig_from, orig_to);
2539 to = orig_from + ctx->out->used;
2544 setup_combining_coverage (int from, int to, void *val, void *arg)
2546 int combining_class = (int) val;
2549 if (combining_class < 200)
2551 else if (combining_class <= 204)
2553 if ((combining_class % 2) == 0)
2554 category = "bcd"[(combining_class - 200) / 2];
2556 else if (combining_class <= 232)
2558 if ((combining_class % 2) == 0)
2559 category = "efghijklmnopq"[(combining_class - 208) / 2];
2561 else if (combining_class == 233)
2563 else if (combining_class == 234)
2565 else if (combining_class == 240)
2567 mchartable_set_range ((MCharTable *) arg, from, to, (void *) category);
2571 setup_combining_flt (MFLT *flt)
2574 MCharTable *combininig_class_table
2575 = mchar_get_prop_table (Mcombining_class, &type);
2577 mchartable_set_range (flt->coverage->table, 0, 0x10FFFF, (void *) 'u');
2578 if (combininig_class_table)
2579 mchartable_map (combininig_class_table, (void *) 0,
2580 setup_combining_coverage, flt->coverage->table);
2583 #define CHECK_FLT_STAGES(flt) ((flt)->stages || load_flt (flt, NULL) == 0)
2585 static FontLayoutCategory *
2586 configure_category (FontLayoutCategory *category, MFLTFont *font)
2588 if (! mflt_font_id || ! mflt_iterate_otf_feature)
2590 FontLayoutCategory *new = malloc (sizeof (FontLayoutCategory));
2591 new->definition = NULL;
2592 new->table = category->table;
2593 M17N_OBJECT_REF (new->table);
2596 return load_category_table (category->definition, font);
2600 configure_flt (MFLT *flt, MFLTFont *font, MSymbol font_id)
2605 if (! mflt_font_id || ! mflt_iterate_otf_feature)
2607 MPLIST_DO (plist, flt_list)
2609 configured = MPLIST_VAL (plist);
2610 if (! configured->font_id)
2612 if (configured->name == flt->name
2613 && configured->font_id == font_id)
2616 if (! MSTRUCT_CALLOC_SAFE (configured))
2619 configured->stages = mplist_copy (flt->stages);
2620 MPLIST_DO (plist, configured->stages)
2622 FontLayoutStage *stage = MPLIST_VAL (plist);
2623 if (stage->category->definition)
2625 MSTRUCT_CALLOC (stage, MERROR_FLT);
2626 *stage = *((FontLayoutStage *) MPLIST_VAL (plist));
2627 stage->category = configure_category (stage->category, font);
2628 MPLIST_VAL (plist) = stage;
2631 M17N_OBJECT_REF (stage->category->table);
2633 configured->need_config = 0;
2634 configured->font_id = font_id;
2635 mplist_push (flt_list, flt->name, configured);
2641 int m17n__flt_initialized;
2646 /* The following two are actually not exposed to a user but concealed
2647 by the macro M17N_INIT (). */
2650 m17n_init_flt (void)
2652 int mdebug_flag = MDEBUG_INIT;
2654 merror_code = MERROR_NONE;
2655 if (m17n__flt_initialized++)
2658 if (merror_code != MERROR_NONE)
2660 m17n__flt_initialized--;
2664 MDEBUG_PUSH_TIME ();
2666 Mcond = msymbol ("cond");
2667 Mrange = msymbol ("range");
2668 Mfont = msymbol ("font");
2669 Mlayouter = msymbol ("layouter");
2670 Mcombining = msymbol ("combining");
2671 Mfont_facility = msymbol ("font-facility");
2672 Mequal = msymbol ("=");
2673 Mgenerator = msymbol ("generator");
2674 Mend = msymbol ("end");
2676 mflt_enable_new_feature = 0;
2677 mflt_iterate_otf_feature = NULL;
2678 mflt_font_id = NULL;
2679 mflt_try_otf = NULL;
2681 MDEBUG_PRINT_TIME ("INIT", (mdebug__output, " to initialize the flt modules."));
2686 m17n_fini_flt (void)
2688 int mdebug_flag = MDEBUG_FINI;
2690 if (m17n__flt_initialized == 0
2691 || --m17n__flt_initialized > 0)
2694 MDEBUG_PUSH_TIME ();
2696 MDEBUG_PRINT_TIME ("FINI", (mdebug__output, " to finalize the flt modules."));
2702 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
2704 /*** @addtogroup m17nFLT */
2710 @brief Return an FLT object that has a specified name.
2712 The mflt_get () function returns an FLT object whose name is $NAME.
2715 If the operation was successful, mflt_get () returns a pointer
2716 to the found FLT object. Otherwise, it returns @c NULL. */
2719 @brief »ØÄꤵ¤ì¤¿Ì¾Á°¤ò»ý¤Ä FLT ¥ª¥Ö¥¸¥§¥¯¥È¤òÊÖ¤¹.
2721 ´Ø¿ô mflt_get () ¤Ï¡¢$NAME ¤È¤¤¤¦Ì¾Á°¤ò»ý¤Ä FLT ¥ª¥Ö¥¸¥§¥¯¥È¤òÊÖ¤¹¡£
2724 ¤â¤·À®¸ù¤¹¤ì¤Ð¡¢mflt_get () ¤Ï¸«¤Ä¤«¤Ã¤¿ FLT
2725 ¥ª¥Ö¥¸¥§¥¯¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¼ºÇÔ¤·¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤¹¡£ */
2728 mflt_get (MSymbol name)
2733 if (! flt_list && list_flt () < 0)
2735 for (plist = flt_list; plist; plist = plist->next)
2736 if (((MFLT *) MPLIST_VAL (plist))->font_id == Mnil)
2738 flt = mplist_get (plist, name);
2739 if (! flt || ! CHECK_FLT_STAGES (flt))
2741 if (flt->name == Mcombining
2742 && ! mchartable_lookup (flt->coverage->table, 0))
2743 setup_combining_flt (flt);
2750 @brief Find an FLT suitable for the specified character and font.
2752 The mflt_find () function returns the most appropriate FLT for
2753 layouting character $C with font $FONT.
2756 If the operation was successful, mflt_find () returns a pointer
2757 to the found FLT object. Otherwise, it returns @c NULL. */
2760 @brief »ØÄꤵ¤ì¤¿Ê¸»ú¤È¥Õ¥©¥ó¥È¤Ë¹ç¤Ã¤¿ FLT ¤òõ¤¹.
2762 ´Ø¿ô mflt_find () ¤Ï¡¢Ê¸»ú $C ¤ò¥Õ¥©¥ó¥È $FONT
2763 ¤Ç¥ì¥¤¥¢¥¦¥È¤¹¤ë¤¿¤á¤ËºÇ¤âŬÀÚ¤Ê FLT ¤òÊÖ¤¹¡£
2766 ¤â¤·À®¸ù¤¹¤ì¤Ð¡¢mflt_find () ¤Ï¸«¤Ä¤«¤Ã¤¿ FLT
2767 ¥ª¥Ö¥¸¥§¥¯¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¼ºÇÔ¤·¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤¹¡£ */
2770 mflt_find (int c, MFLTFont *font)
2774 static MSymbol unicode_bmp = NULL, unicode_full = NULL;
2778 unicode_bmp = msymbol ("unicode-bmp");
2779 unicode_full = msymbol ("unicode-full");
2782 if (! flt_list && list_flt () < 0)
2784 /* Skip configured FLTs. */
2785 MPLIST_DO (plist, flt_list)
2786 if (((MFLT *) MPLIST_VAL (plist))->font_id == Mnil)
2792 MPLIST_DO (pl, plist)
2794 flt = MPLIST_VAL (pl);
2795 if (flt->registry != unicode_bmp
2796 && flt->registry != unicode_full)
2798 if (flt->family && flt->family != font->family)
2800 if (flt->name == Mcombining
2801 && ! mchartable_lookup (flt->coverage->table, 0))
2802 setup_combining_flt (flt);
2804 && ! mchartable_lookup (flt->coverage->table, c))
2808 MFLTOtfSpec *spec = &flt->otf;
2810 if (! font->check_otf)
2812 if ((spec->features[0] && spec->features[0][0] != 0xFFFFFFFF)
2813 || (spec->features[1] && spec->features[1][0] != 0xFFFFFFFF))
2816 else if (! font->check_otf (font, spec))
2829 MPLIST_DO (pl, plist)
2831 flt = MPLIST_VAL (pl);
2832 if (mchartable_lookup (flt->coverage->table, c))
2839 if (! CHECK_FLT_STAGES (flt))
2841 if (font && flt->need_config && mflt_font_id)
2842 flt = configure_flt (flt, font, mflt_font_id (font));
2848 @brief Return the name of an FLT.
2850 The mflt_name () function returns the name of $FLT. */
2853 @brief FLT ¤Î̾Á°¤òÊÖ¤¹.
2855 ´Ø¿ô mflt_name () ¤Ï $FLT ¤Î̾Á°¤òÊÖ¤¹¡£ */
2858 mflt_name (MFLT *flt)
2860 return MSYMBOL_NAME (flt->name);
2865 @brief Return a coverage of a FLT.
2867 The mflt_coverage () function returns a char-table that contains
2868 nonzero values for characters supported by $FLT. */
2871 @brief FLT ¤ÎÈϰϤòÊÖ¤¹.
2873 ´Ø¿ô mflt_coverage () ¤Ï¡¢$FLT ¤¬¥µ¥Ý¡¼¥È¤¹¤ëʸ»ú¤ËÂФ·¤Æ
2874 0 ¤Ç¤Ê¤¤Ãͤò´Þ¤àʸ»ú¥Æ¡¼¥Ö¥ë¤òÊÖ¤¹¡£ */
2877 mflt_coverage (MFLT *flt)
2879 return flt->coverage->table;
2884 @brief Layout characters with an FLT.
2886 The mflt_run () function layouts characters in $GSTRING between
2887 $FROM (inclusive) and $TO (exclusive) with $FONT. If $FLT is
2888 nonzero, it is used for all the charaters. Otherwise, appropriate
2889 FLTs are automatically chosen.
2892 The operation was successful. The value is the index to the
2893 glyph, which was previously indexed by $TO, in $GSTRING->glyphs.
2896 $GSTRING->glyphs is too short to store the result. The caller can
2897 call this fucntion again with a longer $GSTRING->glyphs.
2900 Some other error occurred. */
2903 @brief FLT ¤ò»È¤Ã¤Æʸ»ú¤ò¥ì¥¤¥¢¥¦¥È¤¹¤ë.
2905 ´Ø¿ô mflt_run () ¤Ï¡¢$GSTRING Ãæ¤Î $FROM ¤«¤é $TO ľÁ°¤Þ¤Ç¤Îʸ»ú¤ò
2906 $FONT ¤òÍѤ¤¤Æ¥ì¥¤¥¢¥¦¥È¤¹¤ë¡£¤â¤· $FLT
2907 ¤¬¥¼¥í¤Ç¤Ê¤±¤ì¤Ð¡¢¤½¤ÎÃͤò¤¹¤Ù¤Æ¤Îʸ»ú¤ËÂФ·¤ÆÍѤ¤¤ë¡£
2908 ¤½¤¦¤Ç¤Ê¤±¤ì¤ÐŬÀÚ¤Ê FLT ¤ò¼«Æ°Åª¤ËÁªÂò¤¹¤ë¡£
2911 ¼Â¹ÔÀ®¸ù¤ò¼¨¤¹¡£ÊÖ¤µ¤ì¤ëÃͤϡ¢$GSTRING->glyphs Ãæ¤Ç°ÊÁ° $TO
2912 ¤Ë¤è¤Ã¤Æ¼¨¤µ¤ì¤Æ¤¤¤¿¥°¥ê¥Õ¤Ø¤Î¥¤¥ó¥Ç¥¯¥¹¤Ç¤¢¤ë¡£
2915 ·ë²Ì¤ò³ÊǼ¤¹¤ë¤Ë¤Ï $GSTRING->glyphs ¤¬Ã»¤¹¤®¤ë¤³¤È¤ò¼¨¤¹¡£
2916 ¸Æ¤Ó½Ð¤·Â¦¤Ï¡¢¤è¤êŤ¤ $GSTRING->glyphs
2917 ¤òÍѤ¤¤ÆºÆÅÙ¤³¤Î´Ø¿ô¤ò¸Æ¤Ö¤³¤È¤¬¤Ç¤¤ë¡£
2920 ¤½¤Î¾¤Î¥¨¥é¡¼¤¬µ¯¤¤¿¤³¤È¤ò¼¨¤¹¡£ */
2923 mflt_run (MFLTGlyphString *gstring, int from, int to,
2924 MFLTFont *font, MFLT *flt)
2926 FontLayoutContext ctx;
2927 int match_indices[NMATCH];
2929 MFLTGlyphString out;
2930 int auto_flt = ! flt;
2932 int this_from, this_to;
2933 MSymbol font_id = mflt_font_id ? mflt_font_id (font) : Mnil;
2937 /* This is usually sufficient, but if not, we retry with the larger
2938 values at most 3 times. This value is also used for the
2939 allocating size of ctx.encoded. */
2940 out.allocated = (to - from) * 4;
2942 for (i = from; i < to; i++)
2944 g = GREF (gstring, i);
2948 memset (g, 0, sizeof (MFLTGlyph));
2951 g->from = g->to = i;
2954 for (this_from = from; this_from < to;)
2958 for (this_to = this_from; this_to < to; this_to++)
2959 if (mchartable_lookup (flt->coverage->table,
2960 GREF (gstring, this_to)->c))
2965 if (! flt_list && list_flt () < 0)
2967 font->get_glyph_id (font, gstring, this_from, to);
2968 font->get_metrics (font, gstring, this_from, to);
2972 for (this_to = this_from; this_to < to; this_to++)
2974 c = GREF (gstring, this_to)->c;
2975 if (c >= flt_min_coverage && c <= flt_max_coverage)
2978 for (; this_to < to; this_to++)
2980 c = GREF (gstring, this_to)->c;
2982 && mchartable_lookup (((MFLT *) font->internal)->coverage->table, c))
2984 flt = font->internal;
2987 flt = mflt_find (c, font);
2990 if (CHECK_FLT_STAGES (flt))
2992 font->internal = flt;
2999 if (this_from < this_to)
3001 font->get_glyph_id (font, gstring, this_from, this_to);
3002 font->get_metrics (font, gstring, this_from, this_to);
3003 this_from = this_to;
3008 MDEBUG_PRINT1 (" [FLT] (%s", MSYMBOL_NAME (flt->name));
3010 if (flt->need_config && font_id != Mnil)
3011 flt = configure_flt (flt, font, font_id);
3013 for (; this_to < to; this_to++)
3016 g = GREF (gstring, this_to);
3017 enc = (int) mchartable_lookup (flt->coverage->table, g->c);
3020 SET_CATEGORY_CODE (g, enc);
3026 MDEBUG_PRINT1 (" (%s)", MSYMBOL_NAME (font->family));
3027 MDEBUG_PRINT ("\n [FLT] (SOURCE");
3028 for (i = this_from, j = 0; i < this_to; i++, j++)
3030 if (j > 0 && j % 8 == 0)
3031 MDEBUG_PRINT ("\n [FLT] ");
3032 MDEBUG_PRINT1 (" %04X", GREF (gstring, i)->c);
3037 for (i = 0; i < 3; i++)
3040 memset (&ctx, 0, sizeof ctx);
3041 ctx.match_indices = match_indices;
3043 ctx.cluster_begin_idx = -1;
3046 j = run_stages (gstring, this_from, this_to, flt, &ctx);
3060 MDEBUG_PRINT ("\n [FLT] (RESULT");
3061 if (MDEBUG_FLAG () > 1)
3064 for (i = 0; this_from < this_to; i++, this_from++)
3066 g = GREF (gstring, this_from);
3070 MDEBUG_PRINT2 ("\n [FLT] %02d-%02d",
3073 MDEBUG_PRINT2 (" %02d-%02d", g->from, g->to);
3076 MDEBUG_PRINT4 (" (%04X %d %d %d)",
3077 g->code, g->xadv, g->xoff, g->yoff);
3081 for (; this_from < this_to; this_from++)
3082 MDEBUG_PRINT1 (" %04X", GREF (gstring, this_from)->code);
3083 MDEBUG_PRINT ("))\n");
3085 this_from = this_to;
3090 int len = to - from;
3093 memcpy (((char *) out.glyphs),
3094 ((char *) gstring->glyphs) + gstring->glyph_size * from,
3095 gstring->glyph_size * len);
3096 for (i = from, j = to; i < to;)
3098 for (k = i + 1, j--; k < to && GREF (&out, k)->xadv == 0;
3100 GCPY (&out, i, (k - i), gstring, j);
3108 int mflt_enable_new_feature;
3110 int (*mflt_iterate_otf_feature) (struct _MFLTFont *font,
3113 unsigned char *table);
3115 MSymbol (*mflt_font_id) (struct _MFLTFont *font);
3117 int (*mflt_try_otf) (struct _MFLTFont *font, MFLTOtfSpec *spec,
3118 MFLTGlyphString *gstring, int from, int to);
3121 /* for debugging... */
3124 dump_flt_cmd (FontLayoutStage *stage, int id, int indent)
3126 char *prefix = (char *) alloca (indent + 1);
3128 memset (prefix, 32, indent);
3132 fprintf (mdebug__output, "0x%02X", id);
3133 else if (id <= CMD_ID_OFFSET_INDEX)
3135 int idx = CMD_ID_TO_INDEX (id);
3136 FontLayoutCmd *cmd = stage->cmds + idx;
3138 if (cmd->type == FontLayoutCmdTypeRule)
3140 FontLayoutCmdRule *rule = &cmd->body.rule;
3143 fprintf (mdebug__output, "(rule ");
3144 if (rule->src_type == SRC_REGEX)
3145 fprintf (mdebug__output, "\"%s\"", rule->src.re.pattern);
3146 else if (rule->src_type == SRC_INDEX)
3147 fprintf (mdebug__output, "%d", rule->src.match_idx);
3148 else if (rule->src_type == SRC_SEQ)
3149 fprintf (mdebug__output, "(seq)");
3150 else if (rule->src_type == SRC_RANGE)
3151 fprintf (mdebug__output, "(range)");
3153 fprintf (mdebug__output, "(invalid src)");
3155 for (i = 0; i < rule->n_cmds; i++)
3157 fprintf (mdebug__output, "\n%s ", prefix);
3158 dump_flt_cmd (stage, rule->cmd_ids[i], indent + 2);
3160 fprintf (mdebug__output, ")");
3162 else if (cmd->type == FontLayoutCmdTypeCond)
3164 FontLayoutCmdCond *cond = &cmd->body.cond;
3167 fprintf (mdebug__output, "(cond");
3168 for (i = 0; i < cond->n_cmds; i++)
3170 fprintf (mdebug__output, "\n%s ", prefix);
3171 dump_flt_cmd (stage, cond->cmd_ids[i], indent + 2);
3173 fprintf (mdebug__output, ")");
3175 else if (cmd->type == FontLayoutCmdTypeOTF)
3177 fprintf (mdebug__output, "(otf)");
3180 fprintf (mdebug__output, "(error-command)");
3182 else if (id <= CMD_ID_OFFSET_COMBINING)
3183 fprintf (mdebug__output, "cominging-code");
3185 fprintf (mdebug__output, "(predefiend %d)", id);
3189 @brief Dump a Font Layout Table.
3191 The mdebug_dump_flt () function prints the Font Layout Table $FLT
3192 in a human readable way to the stderr or to what specified by the
3193 environment variable MDEBUG_OUTPUT_FILE. $INDENT specifies how
3194 many columns to indent the lines but the first one.
3197 This function returns $FLT. */
3200 mdebug_dump_flt (MFLT *flt, int indent)
3202 char *prefix = (char *) alloca (indent + 1);
3206 memset (prefix, 32, indent);
3208 fprintf (mdebug__output, "(flt");
3209 MPLIST_DO (plist, flt->stages)
3211 FontLayoutStage *stage = (FontLayoutStage *) MPLIST_VAL (plist);
3214 fprintf (mdebug__output, "\n%s (stage %d", prefix, stage_idx);
3215 for (i = 0; i < stage->used; i++)
3217 fprintf (mdebug__output, "\n%s ", prefix);
3218 dump_flt_cmd (stage, INDEX_TO_CMD_ID (i), indent + 4);
3220 fprintf (mdebug__output, ")");
3223 fprintf (mdebug__output, ")");
3228 mflt_dump_gstring (MFLTGlyphString *gstring)
3232 fprintf (mdebug__output, "(flt-gstring");
3233 for (i = 0; i < gstring->used; i++)
3235 MFLTGlyph *g = GREF (gstring, i);
3236 fprintf (mdebug__output, "\n (%02d pos:%d-%d c:%04X code:%04X cat:%c)",
3237 i, g->from, g->to, g->c, g->code, GET_CATEGORY_CODE (g));
3239 fprintf (mdebug__output, ")\n");