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] for checking for applying
746 features[1] GSUB GPOS GSUB GPOS
747 ------------- ------------------ ------------- ------------
748 SCRIPT [-1,0] [-1,0] any | any all all
749 SCRIPT= NULL [-1,0] none & 1 none all
750 SCRIPT+ [-1,0] NULL 1 & none all none
751 SCRIPT=+ NULL NULL none & none none none
752 SCRIPT=F1 [F1,0] [-1,0] F1 & 1 F1 all
753 SCRIPT+F1 [-1][0] [F1,0] 1 & F1 none F1
754 SCRIPT=F1+ [F1,0] NULL F1 & none F1 none
755 SCRIPT=~F2 [-1,F2,0] [-1,0] ~F2 & 1 all~F2 all
756 SCRIPT=F1,~F2 [F1,-1,F2,0][-1,0] F1&~F2 & 1 F1 (*1) all
758 (*1) Invalid specification
762 parse_otf_command (MSymbol symbol, MFLTOtfSpec *spec)
764 char *str = MSYMBOL_NAME (symbol);
765 char *end = str + MSYMBOL_NAMELEN (symbol);
766 unsigned int script, langsys;
768 int feature_count[2]; /* [0]:GSUB, [1]:GPOS */
772 memset (spec, 0, sizeof (MFLTOtfSpec));
775 str += 5; /* skip the heading ":otf=" or ":otf?" */
778 if (! mflt_enable_new_feature)
779 /* The client can't use this command. */
782 /* This is a spec to reset category codes. */
785 spec->script = gen_otf_tag (str, 8);
789 spec->langsys = gen_otf_tag (str, 8);
796 /* Apply all GSUB features. */
797 feature_count[0] = -1;
801 str = otf_count_features (p, end, '+', feature_count);
803 MERROR (MERROR_FLT, -1);
807 /* Apply all GPOS features. */
808 feature_count[1] = -1;
812 str = otf_count_features (p, end, '\0', feature_count + 1);
814 MERROR (MERROR_FLT, -1);
817 for (i = 0; i < 2; i++)
818 if (feature_count[i])
820 spec->features[i] = malloc (sizeof (int)
821 * (feature_count[i] < 0 ? 2
822 : feature_count[i] + 1));
823 if (! spec->features[i])
825 if (feature_count[i] > 0)
826 otf_store_features (features[i] + 1, features[i + 1],
829 spec->features[i][0] = 0xFFFFFFFF, spec->features[i][1] = 0;
836 /* Parse OTF command name NAME and store the result in CMD.
838 :SCRIPT[/[LANGSYS][=[GSUB-FEATURES][+GPOS-FEATURES]]]
839 where GSUB-FEATURES and GPOS-FEATURES have this form:
840 [FEATURE[,FEATURE]*] | ' ' */
843 load_otf_command (FontLayoutCmd *cmd, MSymbol sym)
845 char *name = MSYMBOL_NAME (sym);
850 /* This is old format of "otf:...". Change it to ":otf=...". */
851 char *str = alloca (MSYMBOL_NAMELEN (sym) + 2);
853 sprintf (str, ":otf=");
854 strcat (str, name + 4);
858 result = parse_otf_command (sym, &cmd->body.otf);
861 cmd->type = (name[4] == '?' ? FontLayoutCmdTypeOTFCategory
862 : FontLayoutCmdTypeOTF);
867 /* Read a decimal number from STR preceded by one of "+-><". '+' and
868 '>' means a plus sign, '-' and '<' means a minus sign. If the
869 number is greater than 127, limit it to 127. */
872 read_decimal_number (char **str)
875 int sign = (*p == '-' || *p == '<') ? -1 : 1;
879 while (*p >= '0' && *p <= '9')
880 n = n * 10 + *p++ - '0';
884 return (n < 127 ? n * sign : 127 * sign);
888 /* Read a horizontal and vertical combining positions from STR, and
889 store them in the place pointed by X and Y. The horizontal
890 position left, center, and right are represented by 0, 1, and 2
891 respectively. The vertical position top, center, bottom, and base
892 are represented by 0, 1, 2, and 3 respectively. If successfully
893 read, return 0, else return -1. */
896 read_combining_position (char *str, int *x, int *y)
901 /* Vertical position comes first. */
902 for (i = 0; i < 4; i++)
911 /* Then comse horizontal position. */
912 for (i = 0; i < 3; i++)
922 /* Return a combining code corresponding to SYM. */
925 get_combining_command (MSymbol sym)
927 char *str = msymbol_name (sym);
928 int base_x, base_y, add_x, add_y, off_x, off_y;
931 if (read_combining_position (str, &base_x, &base_y) < 0)
942 if (c == '+' || c == '-')
944 off_y = read_decimal_number (&str) + 128;
949 if (c == '<' || c == '>')
950 off_x = read_decimal_number (&str) + 128;
954 if (read_combining_position (str, &add_x, &add_y) < 0)
957 c = MAKE_COMBINING_CODE (base_y, base_x, add_y, add_x, off_y, off_x);
958 return (COMBINING_CODE_TO_CMD_ID (c));
962 /* Load a command from PLIST into STAGE, and return that
963 identification number. If ID is not INVALID_CMD_ID, that means we
964 are loading a top level command or a macro. In that case, use ID
965 as the identification number of the command. Otherwise, generate a
966 new id number for the command. MACROS is a list of raw macros. */
969 load_command (FontLayoutStage *stage, MPlist *plist,
970 MPlist *macros, int id)
975 if (MPLIST_INTEGER_P (plist))
977 int code = MPLIST_INTEGER (plist);
980 MERROR (MERROR_DRAW, INVALID_CMD_ID);
983 else if (MPLIST_PLIST_P (plist))
985 /* PLIST ::= ( cond ... ) | ( STRING ... ) | ( INTEGER ... )
986 | ( ( INTEGER INTEGER ) ... )
987 | ( ( range INTEGER INTEGER ) ... )
988 | ( ( SYMBOL STRING ) ... )
989 | ( ( font-facilty [ INTEGER ] ) ... )
990 | ( ( font-facilty OTF-SPEC ) ... ) */
991 MPlist *elt = MPLIST_PLIST (plist);
992 int len = MPLIST_LENGTH (elt) - 1;
995 if (id == INVALID_CMD_ID)
998 id = INDEX_TO_CMD_ID (stage->used);
999 MLIST_APPEND1 (stage, cmds, dummy, MERROR_DRAW);
1001 cmd = stage->cmds + CMD_ID_TO_INDEX (id);
1003 if (MPLIST_SYMBOL_P (elt))
1005 FontLayoutCmdCond *cond;
1007 if (MPLIST_SYMBOL (elt) != Mcond)
1008 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1009 elt = MPLIST_NEXT (elt);
1010 cmd->type = FontLayoutCmdTypeCond;
1011 cond = &cmd->body.cond;
1012 cond->seq_beg = cond->seq_end = -1;
1013 cond->seq_from = cond->seq_to = 0;
1015 MTABLE_CALLOC (cond->cmd_ids, len, MERROR_DRAW);
1016 for (i = 0; i < len; i++, elt = MPLIST_NEXT (elt))
1018 int this_id = load_command (stage, elt, macros, INVALID_CMD_ID);
1020 if (this_id == INVALID_CMD_ID || this_id == -2)
1021 MERROR (MERROR_DRAW, this_id);
1022 /* The above load_command may relocate stage->cmds. */
1023 cmd = stage->cmds + CMD_ID_TO_INDEX (id);
1024 cond = &cmd->body.cond;
1025 cond->cmd_ids[i] = this_id;
1026 if (this_id <= CMD_ID_OFFSET_INDEX)
1028 FontLayoutCmd *this_cmd
1029 = stage->cmds + CMD_ID_TO_INDEX (this_id);
1031 if (this_cmd->type == FontLayoutCmdTypeRule
1032 && this_cmd->body.rule.src_type == SRC_SEQ)
1034 int first_char = this_cmd->body.rule.src.seq.codes[0];
1036 if (cond->seq_beg < 0)
1038 /* The first SEQ command. */
1040 cond->seq_from = cond->seq_to = first_char;
1042 else if (cond->seq_end < 0)
1044 /* The following SEQ command. */
1045 if (cond->seq_from > first_char)
1046 cond->seq_from = first_char;
1047 else if (cond->seq_to < first_char)
1048 cond->seq_to = first_char;
1053 if (cond->seq_beg >= 0 && cond->seq_end < 0)
1054 /* The previous one is the last SEQ command. */
1060 if (cond->seq_beg >= 0 && cond->seq_end < 0)
1061 /* The previous one is the last SEQ command. */
1065 if (cond->seq_beg >= 0 && cond->seq_end < 0)
1066 /* The previous one is the last SEQ command. */
1071 cmd->type = FontLayoutCmdTypeRule;
1072 if (MPLIST_MTEXT_P (elt))
1074 MText *mt = MPLIST_MTEXT (elt);
1075 char *str = (char *) MTEXT_DATA (mt);
1079 mtext_ins_char (mt, 0, '^', 1);
1080 str = (char *) MTEXT_DATA (mt);
1082 if (regcomp (&cmd->body.rule.src.re.preg, str, REG_EXTENDED))
1083 MERROR (MERROR_FONT, INVALID_CMD_ID);
1084 cmd->body.rule.src_type = SRC_REGEX;
1085 cmd->body.rule.src.re.pattern = strdup (str);
1087 else if (MPLIST_INTEGER_P (elt))
1089 cmd->body.rule.src_type = SRC_INDEX;
1090 cmd->body.rule.src.match_idx = MPLIST_INTEGER (elt);
1092 else if (MPLIST_PLIST_P (elt))
1094 MPlist *pl = MPLIST_PLIST (elt), *p;
1095 int size = MPLIST_LENGTH (pl);
1097 if (MPLIST_INTEGER_P (pl))
1101 cmd->body.rule.src_type = SRC_SEQ;
1102 cmd->body.rule.src.seq.n_codes = size;
1103 MTABLE_CALLOC (cmd->body.rule.src.seq.codes, size,
1105 for (i = 0; i < size; i++, pl = MPLIST_NEXT (pl))
1107 if (! MPLIST_INTEGER_P (pl))
1108 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1109 cmd->body.rule.src.seq.codes[i]
1110 = (unsigned) MPLIST_INTEGER (pl);
1113 else if (MPLIST_SYMBOL_P (pl))
1115 if (MPLIST_SYMBOL (pl) == Mrange)
1118 MERROR (MERROR_FLT, INVALID_CMD_ID);
1119 cmd->body.rule.src_type = SRC_RANGE;
1120 pl = MPLIST_NEXT (pl);
1121 if (! MPLIST_INTEGER_P (pl))
1122 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1123 cmd->body.rule.src.range.from
1124 = (unsigned) MPLIST_INTEGER (pl);
1125 pl = MPLIST_NEXT (pl);
1126 if (! MPLIST_INTEGER_P (pl))
1127 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1128 cmd->body.rule.src.range.to
1129 = (unsigned) MPLIST_INTEGER (pl);
1131 else if (MPLIST_SYMBOL (pl) == Mfont_facility)
1133 FontLayoutCmdRule *rule = &cmd->body.rule;
1135 pl = MPLIST_NEXT (pl);
1136 if (MPLIST_SYMBOL_P (pl))
1138 MSymbol sym = MPLIST_SYMBOL (pl);
1139 char *otf_spec = MSYMBOL_NAME (sym);
1141 if (otf_spec[0] == ':' && otf_spec[1] == 'o'
1142 && otf_spec[2] == 't' && otf_spec[3] == 'f')
1143 parse_otf_command (sym, &rule->src.facility.otf_spec);
1145 MERROR (MERROR_FLT, INVALID_CMD_ID);
1146 rule->src_type = SRC_OTF_SPEC;
1147 pl = MPLIST_NEXT (pl);
1149 else if (MPLIST_TAIL_P (pl))
1150 MERROR (MERROR_FLT, INVALID_CMD_ID);
1152 rule->src_type = SRC_HAS_GLYPH;
1153 rule->src.facility.len = 0;
1156 if (! MPLIST_INTEGER_P (p)
1157 && (MPLIST_SYMBOL_P (p)
1158 ? MPLIST_SYMBOL (p) != Mequal
1160 MERROR (MERROR_FLT, INVALID_CMD_ID);
1161 rule->src.facility.len++;
1163 rule->src.facility.codes = pl;
1164 M17N_OBJECT_REF (pl);
1168 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1171 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1173 elt = MPLIST_NEXT (elt);
1174 cmd->body.rule.n_cmds = len;
1175 MTABLE_CALLOC (cmd->body.rule.cmd_ids, len, MERROR_DRAW);
1176 for (i = 0; i < len; i++, elt = MPLIST_NEXT (elt))
1178 int this_id = load_command (stage, elt, macros, INVALID_CMD_ID);
1180 if (this_id == INVALID_CMD_ID || this_id == -2)
1181 MERROR (MERROR_DRAW, this_id);
1182 /* The above load_command may relocate stage->cmds. */
1183 cmd = stage->cmds + CMD_ID_TO_INDEX (id);
1184 cmd->body.rule.cmd_ids[i] = this_id;
1188 else if (MPLIST_SYMBOL_P (plist))
1191 MSymbol sym = MPLIST_SYMBOL (plist);
1192 char *name = msymbol_name (sym);
1193 int len = strlen (name);
1197 && ((name[0] == 'o' && name[1] == 't'
1198 && name[2] == 'f' && name[3] == ':')
1199 || (name[0] == ':' && name[1] == 'o' && name[2] == 't'
1200 && name[3] == 'f' && (name[4] == '=' || name[4] == '?'))))
1202 result = load_otf_command (&cmd, sym);
1205 if (id == INVALID_CMD_ID)
1207 id = INDEX_TO_CMD_ID (stage->used);
1208 MLIST_APPEND1 (stage, cmds, cmd, MERROR_DRAW);
1211 stage->cmds[CMD_ID_TO_INDEX (id)] = cmd;
1219 else if (*name == '*')
1220 return CMD_ID_REPEAT;
1221 else if (*name == '<')
1222 return CMD_ID_CLUSTER_BEGIN;
1223 else if (*name == '>')
1224 return CMD_ID_CLUSTER_END;
1225 else if (*name == '|')
1226 return CMD_ID_SEPARATOR;
1227 else if (*name == '[')
1228 return CMD_ID_LEFT_PADDING;
1229 else if (*name == ']')
1230 return CMD_ID_RIGHT_PADDING;
1236 id = get_combining_command (sym);
1242 MPLIST_DO (elt, macros)
1244 if (sym == MPLIST_SYMBOL (MPLIST_PLIST (elt)))
1246 id = INDEX_TO_CMD_ID (i);
1247 if (stage->cmds[i].type == FontLayoutCmdTypeMAX)
1248 id = load_command (stage, MPLIST_NEXT (MPLIST_PLIST (elt)),
1254 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1257 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1263 free_flt_command (FontLayoutCmd *cmd)
1265 if (cmd->type == FontLayoutCmdTypeRule)
1267 FontLayoutCmdRule *rule = &cmd->body.rule;
1269 if (rule->src_type == SRC_REGEX)
1271 free (rule->src.re.pattern);
1272 regfree (&rule->src.re.preg);
1274 else if (rule->src_type == SRC_SEQ)
1275 free (rule->src.seq.codes);
1276 free (rule->cmd_ids);
1278 else if (cmd->type == FontLayoutCmdTypeCond)
1279 free (cmd->body.cond.cmd_ids);
1280 else if (cmd->type == FontLayoutCmdTypeOTF
1281 || cmd->type == FontLayoutCmdTypeOTFCategory)
1283 if (cmd->body.otf.features[0])
1284 free (cmd->body.otf.features[0]);
1285 if (cmd->body.otf.features[1])
1286 free (cmd->body.otf.features[1]);
1290 /* Load a generator from PLIST into a newly allocated FontLayoutStage,
1291 and return it. PLIST has this form:
1292 PLIST ::= ( COMMAND ( CMD-NAME COMMAND ) * )
1295 static FontLayoutStage *
1296 load_generator (MPlist *plist)
1298 FontLayoutStage *stage;
1300 FontLayoutCmd dummy;
1303 MSTRUCT_CALLOC (stage, MERROR_DRAW);
1304 MLIST_INIT1 (stage, cmds, 32);
1305 dummy.type = FontLayoutCmdTypeMAX;
1306 MLIST_APPEND1 (stage, cmds, dummy, MERROR_FONT);
1307 MPLIST_DO (elt, MPLIST_NEXT (plist))
1309 if (! MPLIST_PLIST_P (elt))
1310 MERROR (MERROR_FONT, NULL);
1311 pl = MPLIST_PLIST (elt);
1312 if (! MPLIST_SYMBOL_P (pl))
1313 MERROR (MERROR_FONT, NULL);
1314 MLIST_APPEND1 (stage, cmds, dummy, MERROR_FONT);
1317 /* Load the first command from PLIST into STAGE->cmds[0]. Macros
1318 called in the first command are also loaded from MPLIST_NEXT
1319 (PLIST) into STAGE->cmds[n]. */
1320 result = load_command (stage, plist, MPLIST_NEXT (plist),
1321 INDEX_TO_CMD_ID (0));
1322 if (result == INVALID_CMD_ID || result == -2)
1324 MLIST_FREE1 (stage, cmds);
1333 /* Load stages of the font layout table FLT. */
1336 load_flt (MFLT *flt, MPlist *key_list)
1338 MPlist *top, *plist, *pl, *p;
1339 FontLayoutCategory *category = NULL;
1343 top = (MPlist *) mdatabase__load_for_keys (flt->mdb, key_list);
1345 top = (MPlist *) mdatabase_load (flt->mdb);
1348 if (! MPLIST_PLIST_P (top))
1350 M17N_OBJECT_UNREF (top);
1351 MERROR (MERROR_FLT, -1);
1356 plist = mdatabase__props (flt->mdb);
1358 MERROR (MERROR_FLT, -1);
1359 MPLIST_DO (plist, plist)
1360 if (MPLIST_PLIST_P (plist))
1362 pl = MPLIST_PLIST (plist);
1363 if (! MPLIST_SYMBOL_P (pl)
1364 || MPLIST_SYMBOL (pl) != Mfont)
1366 pl = MPLIST_NEXT (pl);
1367 if (! MPLIST_PLIST_P (pl))
1369 p = MPLIST_PLIST (pl);
1370 if (! MPLIST_SYMBOL_P (p))
1372 p = MPLIST_NEXT (p);
1373 if (! MPLIST_SYMBOL_P (p))
1375 flt->family = MPLIST_SYMBOL (p);
1376 MPLIST_DO (p, MPLIST_NEXT (p))
1377 if (MPLIST_SYMBOL_P (p))
1379 sym = MPLIST_SYMBOL (p);
1380 if (MSYMBOL_NAME (sym)[0] != ':')
1381 flt->registry = sym, sym = Mnil;
1387 char *otf_spec = MSYMBOL_NAME (sym);
1389 if (otf_spec[0] == ':' && otf_spec[1] == 'o'
1390 && otf_spec[2] == 't' && otf_spec[3] == 'f')
1391 parse_otf_command (sym, &flt->otf);
1396 MPLIST_DO (plist, top)
1398 if (MPLIST_SYMBOL_P (plist)
1399 && MPLIST_SYMBOL (plist) == Mend)
1401 mplist_set (plist, Mnil, NULL);
1404 if (! MPLIST_PLIST (plist))
1406 pl = MPLIST_PLIST (plist);
1407 if (! MPLIST_SYMBOL_P (pl))
1409 sym = MPLIST_SYMBOL (pl);
1410 pl = MPLIST_NEXT (pl);
1413 if (sym == Mcategory)
1416 unref_category_table (category);
1417 else if (flt->coverage)
1419 category = flt->coverage;
1420 ref_category_table (category);
1423 category = load_category_table (pl, NULL);
1426 if (! flt->coverage)
1428 flt->coverage = category;
1429 ref_category_table (category);
1431 if (category->definition)
1432 flt->need_config = 1;
1434 else if (sym == Mgenerator)
1436 FontLayoutStage *stage;
1440 stage = load_generator (pl);
1443 stage->category = category;
1444 M17N_OBJECT_REF (category->table);
1446 flt->stages = mplist ();
1447 mplist_add (flt->stages, Mt, stage);
1451 unref_category_table (category);
1453 if (! MPLIST_TAIL_P (plist))
1455 M17N_OBJECT_UNREF (top);
1456 M17N_OBJECT_UNREF (flt->stages);
1457 MERROR (MERROR_FLT, -1);
1459 M17N_OBJECT_UNREF (top);
1465 free_flt_stage (MFLT *flt, FontLayoutStage *stage)
1469 unref_category_table (stage->category);
1472 for (i = 0; i < stage->used; i++)
1473 free_flt_command (stage->cmds + i);
1474 MLIST_FREE1 (stage, cmds);
1486 MPLIST_DO (plist, flt_list)
1488 MFLT *flt = MPLIST_VAL (plist);
1491 unref_category_table (flt->coverage);
1494 MPLIST_DO (pl, MPLIST_NEXT (flt->stages))
1495 free_flt_stage (flt, MPLIST_VAL (pl));
1496 M17N_OBJECT_UNREF (flt->stages);
1499 MPLIST_VAL (plist) = NULL;
1501 M17N_OBJECT_UNREF (flt_list);
1508 MPlist *plist, *key_list = NULL;
1512 if (! (plist = mdatabase_list (Mfont, Mlayouter, Mnil, Mnil)))
1514 if (! (flt_list = mplist ()))
1516 if (! (key_list = mplist ()))
1518 if (! mplist_add (key_list, Mcategory, Mt))
1521 MPLIST_DO (pl, plist)
1523 MDatabase *mdb = MPLIST_VAL (pl);
1524 MSymbol *tags = mdatabase_tag (mdb);
1527 if (! MSTRUCT_CALLOC_SAFE (flt))
1529 flt->name = tags[2];
1531 if (load_flt (flt, key_list) < 0)
1535 if (MPLIST_TAIL_P (flt_list))
1537 flt_min_coverage = mchartable_min_char (flt->coverage->table);
1538 flt_max_coverage = mchartable_max_char (flt->coverage->table);
1544 c = mchartable_min_char (flt->coverage->table);
1545 if (flt_min_coverage > c)
1546 flt_min_coverage = c;
1547 c = mchartable_max_char (flt->coverage->table);
1548 if (flt_max_coverage < c)
1549 flt_max_coverage = c;
1551 if (! mplist_push (flt_list, flt->name, flt))
1561 M17N_OBJECT_UNREF (plist);
1562 M17N_OBJECT_UNREF (key_list);
1566 /* FLS (Font Layout Service) */
1568 /* Structure to hold information about a context of FLS. */
1572 /* Pointer to the current stage. */
1573 FontLayoutStage *stage;
1575 /* Pointer to the category table of the next stage or NULL if none. */
1576 FontLayoutCategory *category;
1578 /* Pointer to the font. */
1581 /* Input and output glyph string. */
1582 MFLTGlyphString *in, *out;
1584 /* Encode each character or code of a glyph by the current category
1585 table into this array. An element is a category letter used for
1586 a regular expression matching. */
1591 int cluster_begin_idx;
1592 int cluster_begin_pos;
1593 int cluster_end_pos;
1597 } FontLayoutContext;
1599 static int run_command (int, int, int, int, FontLayoutContext *);
1600 static int run_otf (int, MFLTOtfSpec *, int, int, FontLayoutContext *);
1601 static int try_otf (int, MFLTOtfSpec *, int, int, FontLayoutContext *);
1606 run_rule (int depth,
1607 FontLayoutCmdRule *rule, int from, int to, FontLayoutContext *ctx)
1609 int *saved_match_indices = ctx->match_indices;
1610 int match_indices[NMATCH * 2];
1613 int orig_from = from;
1614 int need_cluster_update = 0;
1616 if (rule->src_type == SRC_REGEX)
1618 regmatch_t pmatch[NMATCH];
1624 saved_code = ctx->encoded[to - ctx->encoded_offset];
1625 ctx->encoded[to - ctx->encoded_offset] = '\0';
1626 result = regexec (&(rule->src.re.preg),
1627 ctx->encoded + (from - ctx->encoded_offset),
1629 if (result == 0 && pmatch[0].rm_so == 0)
1631 if (MDEBUG_FLAG () > 2)
1632 MDEBUG_PRINT5 ("\n [FLT] %*s(REGEX \"%s\" \"%s\" %d", depth, "",
1633 rule->src.re.pattern,
1634 ctx->encoded + (from - ctx->encoded_offset),
1636 ctx->encoded[to - ctx->encoded_offset] = saved_code;
1637 for (i = 0; i < NMATCH; i++)
1639 if (pmatch[i].rm_so < 0)
1640 match_indices[i * 2] = match_indices[i * 2 + 1] = -1;
1643 match_indices[i * 2] = from + pmatch[i].rm_so;
1644 match_indices[i * 2 + 1] = from + pmatch[i].rm_eo;
1647 ctx->match_indices = match_indices;
1648 to = match_indices[1];
1652 ctx->encoded[to - ctx->encoded_offset] = saved_code;
1655 need_cluster_update = 1;
1657 else if (rule->src_type == SRC_SEQ)
1661 len = rule->src.seq.n_codes;
1662 if (len > (to - from))
1664 for (i = 0; i < len; i++)
1665 if (rule->src.seq.codes[i] != GREF (ctx->in, from + i)->c)
1670 if (MDEBUG_FLAG () > 2)
1671 MDEBUG_PRINT3 ("\n [FLT] %*s(SEQ 0x%X", depth, "",
1672 rule->src.seq.codes[0]);
1673 need_cluster_update = 1;
1675 else if (rule->src_type == SRC_RANGE)
1681 head = GREF (ctx->in, from)->c;
1682 if (head < rule->src.range.from || head > rule->src.range.to)
1684 ctx->code_offset = head - rule->src.range.from;
1686 if (MDEBUG_FLAG () > 2)
1687 MDEBUG_PRINT4 ("\n [FLT] %*s(RANGE 0x%X-0x%X", depth, "",
1688 rule->src.range.from, rule->src.range.to);
1689 need_cluster_update = 1;
1691 else if (rule->src_type == SRC_INDEX)
1693 if (rule->src.match_idx >= NMATCH)
1695 from = ctx->match_indices[rule->src.match_idx * 2];
1698 to = ctx->match_indices[rule->src.match_idx * 2 + 1];
1699 if (MDEBUG_FLAG () > 2)
1700 MDEBUG_PRINT3 ("\n [FLT] %*s(SUBPART %d", depth, "",
1701 rule->src.match_idx);
1702 need_cluster_update = 1;
1704 else if (rule->src_type == SRC_HAS_GLYPH
1705 || rule->src_type == SRC_OTF_SPEC)
1707 static MFLTGlyphString gstring;
1711 if (rule->src.facility.len > 0)
1713 if (! gstring.glyph_size)
1715 gstring.glyph_size = ctx->in->glyph_size;
1716 gstring.glyphs = calloc (rule->src.facility.len,
1717 gstring.glyph_size);
1718 gstring.allocated = rule->src.facility.len;
1719 gstring.used = rule->src.facility.len;
1721 else if (rule->src.facility.len < gstring.allocated)
1723 gstring.glyphs = realloc (gstring.glyphs,
1725 * rule->src.facility.len);
1726 gstring.allocated = rule->src.facility.len;
1727 gstring.used = rule->src.facility.len;
1730 for (i = 0, p = rule->src.facility.codes, idx = from;
1731 i < rule->src.facility.len; i++, p = MPLIST_NEXT (p))
1733 if (MPLIST_INTEGER_P (p))
1735 GREF (&gstring, i)->c = MPLIST_INTEGER (p);
1736 GREF (&gstring, i)->encoded = 0;
1740 GREF (&gstring, i)->c = GREF (ctx->in, idx)->code;
1741 GREF (&gstring, i)->encoded = GREF (ctx->in, idx)->encoded;
1747 if (MDEBUG_FLAG () > 2)
1749 if (rule->src_type == SRC_HAS_GLYPH)
1750 MDEBUG_PRINT2 ("\n [FLT] %*s(HAS-GLYPH", depth, "");
1752 MDEBUG_PRINT2 ("\n [FLT] %*s(OTF-SPEC", depth, "");
1753 for (i = 0; i < rule->src.facility.len; i++)
1754 MDEBUG_PRINT1 (" %04X", GREF (&gstring, i)->code);
1756 if (ctx->font->get_glyph_id (ctx->font, &gstring, 0,
1757 rule->src.facility.len) < 0)
1759 MDEBUG_PRINT (") FAIL!");
1762 if (rule->src_type == SRC_OTF_SPEC)
1764 MFLTOtfSpec *spec = &rule->src.facility.otf_spec;
1766 if (! ctx->font->check_otf)
1768 if ((spec->features[0] && spec->features[0][0] != 0xFFFFFFFF)
1769 || (spec->features[1] && spec->features[1][0] != 0xFFFFFFFF))
1774 if (rule->src.facility.len == 0)
1776 if (! ctx->font->check_otf (ctx->font, spec))
1781 int prev_out_used = ctx->out->used, out_used;
1782 MFLTGlyphAdjustment *adjustment;
1784 adjustment = alloca ((sizeof *adjustment)
1785 * (ctx->out->allocated - ctx->out->used));
1787 MERROR (MERROR_FLT, -1);
1788 memset (adjustment, 0,
1789 (sizeof *adjustment)
1790 * (ctx->out->allocated - ctx->out->used));
1791 ctx->font->drive_otf (ctx->font, &rule->src.facility.otf_spec,
1792 &gstring, 0, rule->src.facility.len,
1795 out_used = ctx->out->used;
1796 ctx->out->used = prev_out_used;
1797 if (rule->src.facility.len == out_used - prev_out_used)
1799 for (i = prev_out_used; i < out_used; i++)
1801 if (GREF (&gstring, i - prev_out_used)->code
1802 != GREF (ctx->out, i)->code)
1804 if (adjustment[i - prev_out_used].set)
1815 if (need_cluster_update && ctx->cluster_begin_idx >= 0)
1817 for (i = from; i < to; i++)
1819 MFLTGlyph *g = GREF (ctx->in, i);
1820 UPDATE_CLUSTER_RANGE (ctx, g);
1826 for (i = 0; i < rule->n_cmds; i++)
1830 if (rule->cmd_ids[i] == CMD_ID_REPEAT)
1836 pos = run_command (depth, rule->cmd_ids[i], from, to, ctx);
1839 consumed = pos > from;
1844 ctx->match_indices = saved_match_indices;
1845 if (MDEBUG_FLAG () > 2)
1847 return (rule->src_type == SRC_INDEX ? orig_from : to);
1851 run_cond (int depth,
1852 FontLayoutCmdCond *cond, int from, int to, FontLayoutContext *ctx)
1856 if (MDEBUG_FLAG () > 2)
1857 MDEBUG_PRINT2 ("\n [FLT] %*s(COND", depth, "");
1859 for (i = 0; i < cond->n_cmds; i++)
1861 /* TODO: Write a code for optimization utilizaing the info
1863 if ((pos = run_command (depth, cond->cmd_ids[i], from, to, ctx))
1869 if (MDEBUG_FLAG () > 2)
1875 decode_packed_otf_tag (FontLayoutContext *ctx, MFLTGlyphString *gstring,
1876 int from, int to, FontLayoutCategory *category)
1878 for (; from < to; from++)
1880 MFLTGlyph *g = GREF (gstring, from);
1881 unsigned int tag = g->internal & 0xFFFFFFF;
1884 if (GET_COMBINED (g))
1888 SET_CATEGORY_CODE (g, 0);
1892 if (tag & 0xFFFFF80)
1896 /* Clear the feature tag code. */
1897 g->internal &= ~0xFFFFFFF;
1898 for (i = 0; i < category->feature_table.size; i++)
1899 if (category->feature_table.tag[i] == tag)
1901 enc = category->feature_table.code[i];
1902 if (ctx->in == gstring)
1903 ctx->encoded[from - ctx->encoded_offset] = enc;
1908 enc = (g->c > 0 ? (int) mchartable_lookup (category->table, g->c)
1909 : g->c == 0 ? 1 : ' ');
1910 SET_CATEGORY_CODE (g, enc);
1916 MFLTOtfSpec *otf_spec, int from, int to, FontLayoutContext *ctx)
1918 MFLTFont *font = ctx->font;
1919 int from_idx = ctx->out->used;
1921 if (MDEBUG_FLAG () > 2)
1922 MDEBUG_PRINT3 ("\n [FLT] %*s%s", depth, "", MSYMBOL_NAME (otf_spec->sym));
1924 font->get_glyph_id (font, ctx->in, from, to);
1925 if (! font->drive_otf)
1927 if (ctx->out->used + (to - from) > ctx->out->allocated)
1929 font->get_metrics (font, ctx->in, from, to);
1930 GCPY (ctx->in, from, to - from, ctx->out, ctx->out->used);
1931 ctx->out->used += to - from;
1935 MFLTGlyphAdjustment *adjustment;
1939 adjustment = alloca ((sizeof *adjustment)
1940 * (ctx->out->allocated - ctx->out->used));
1942 MERROR (MERROR_FLT, -1);
1943 memset (adjustment, 0,
1944 (sizeof *adjustment) * (ctx->out->allocated - ctx->out->used));
1945 to = font->drive_otf (font, otf_spec, ctx->in, from, to, ctx->out,
1949 decode_packed_otf_tag (ctx, ctx->out, from_idx, ctx->out->used,
1951 out_len = ctx->out->used - from_idx;
1952 if (otf_spec->features[1])
1954 MFLTGlyphAdjustment *a;
1957 for (i = 0, a = adjustment; i < out_len; i++, a++)
1962 font->get_metrics (font, ctx->out, from_idx, ctx->out->used);
1963 for (g = GREF (ctx->out, from_idx + i);
1964 i < out_len; i++, a++, g = NEXT (ctx->out, g))
1967 if (a->advance_is_absolute)
1972 else if (a->xadv || a->yadv)
1977 if (a->xoff || a->yoff || a->back)
1980 MFLTGlyph *gg = PREV (ctx->out, g);
1981 MFLTGlyphAdjustment *aa = a;
1985 g->lbearing += a->xoff;
1986 g->rbearing += a->xoff;
1987 g->ascent -= a->yoff;
1988 g->descent -= a->yoff;
1989 while (aa->back > 0)
1991 for (j = 0; j < aa->back;
1992 j++, gg = PREV (ctx->out, gg))
1994 g->xoff -= gg->xadv;
1995 g->lbearing -= gg->xadv;
1996 g->rbearing -= gg->xadv;
1999 g->xoff += aa->xoff;
2000 g->yoff += aa->yoff;
2001 g->lbearing += aa->xoff;
2002 g->rbearing += aa->xoff;
2003 g->ascent -= aa->yoff;
2004 g->descent -= aa->yoff;
2013 if (ctx->cluster_begin_idx >= 0)
2014 for (; from_idx < ctx->out->used; from_idx++)
2016 MFLTGlyph *g = GREF (ctx->out, from_idx);
2017 UPDATE_CLUSTER_RANGE (ctx, g);
2023 try_otf (int depth, MFLTOtfSpec *otf_spec, int from, int to,
2024 FontLayoutContext *ctx)
2026 MFLTFont *font = ctx->font;
2028 if (MDEBUG_FLAG () > 2)
2029 MDEBUG_PRINT3 ("\n [FLT] %*s%s", depth, "", MSYMBOL_NAME (otf_spec->sym));
2031 if (! otf_spec->features[0] && ! otf_spec->features[1])
2033 /* Reset categories. */
2034 MCharTable *table = ctx->category->table;
2037 for (i = from; i < to; i++)
2039 MFLTGlyph *g = GREF (ctx->in, i);
2041 if (! GET_COMBINED (g))
2043 char enc = (GET_ENCODED (g)
2044 ? (g->c > 0 ? (int) mchartable_lookup (table, g->c)
2047 ? (int) mchartable_lookup (table, g->code)
2049 SET_CATEGORY_CODE (g, enc);
2050 ctx->encoded[i - ctx->encoded_offset] = enc;
2056 if (ctx->stage->category->feature_table.size == 0)
2059 font->get_glyph_id (font, ctx->in, from, to);
2062 to = mflt_try_otf (font, otf_spec, ctx->in, from, to);
2065 decode_packed_otf_tag (ctx, ctx->in, from, to, ctx->stage->category);
2070 static char work[16];
2073 dump_combining_code (int code)
2075 char *vallign = "tcbB";
2076 char *hallign = "lcr";
2082 work[0] = vallign[COMBINING_CODE_BASE_Y (code)];
2083 work[1] = hallign[COMBINING_CODE_BASE_X (code)];
2084 off_y = COMBINING_CODE_OFF_Y (code);
2085 off_x = COMBINING_CODE_OFF_X (code);
2087 sprintf (work + 2, "+%d", off_y);
2089 sprintf (work + 2, "%d", off_y);
2090 else if (off_x == 0)
2091 sprintf (work + 2, ".");
2092 p = work + strlen (work);
2094 sprintf (p, ">%d", off_x);
2096 sprintf (p, "<%d", -off_x);
2098 p[0] = vallign[COMBINING_CODE_ADD_Y (code)];
2099 p[1] = hallign[COMBINING_CODE_ADD_X (code)];
2105 run_command (int depth, int id, int from, int to, FontLayoutContext *ctx)
2112 MCharTable *table = ctx->category ? ctx->category->table : NULL;
2115 /* Direct code (== ctx->code_offset + id) output.
2116 The source is not consumed. */
2117 if (MDEBUG_FLAG () > 2)
2118 MDEBUG_PRINT3 ("\n [FLT] %*s(DIRECT 0x%X", depth, "",
2119 ctx->code_offset + id);
2120 i = (from < to || from == 0) ? from : from - 1;
2122 g = GREF (ctx->out, ctx->out->used - 1);
2123 g->c = g->code = ctx->code_offset + id;
2124 if (ctx->combining_code)
2125 SET_COMBINING_CODE (g, ctx, ctx->combining_code);
2128 enc = (GET_ENCODED (g)
2129 ? (g->c > 0 ? (int) mchartable_lookup (table, g->c) : 1)
2131 ? (int) mchartable_lookup (table, g->code)
2133 SET_CATEGORY_CODE (g, enc);
2136 SET_MEASURED (g, 0);
2137 if (ctx->left_padding)
2138 SET_LEFT_PADDING (g, ctx, LeftPaddingMask);
2139 for (i = from; i < to; i++)
2141 MFLTGlyph *tmp = GREF (ctx->in, i);
2143 if (g->from > tmp->from)
2144 g->from = tmp->from;
2145 else if (g->to < tmp->to)
2148 if (ctx->cluster_begin_idx >= 0)
2149 UPDATE_CLUSTER_RANGE (ctx, g);
2150 ctx->code_offset = ctx->combining_code = ctx->left_padding = 0;
2151 if (MDEBUG_FLAG () > 2)
2156 if (id <= CMD_ID_OFFSET_INDEX)
2158 int idx = CMD_ID_TO_INDEX (id);
2161 if (idx >= ctx->stage->used)
2162 MERROR (MERROR_DRAW, -1);
2163 cmd = ctx->stage->cmds + idx;
2164 if (cmd->type == FontLayoutCmdTypeRule)
2165 to = run_rule (depth, &cmd->body.rule, from, to, ctx);
2166 else if (cmd->type == FontLayoutCmdTypeCond)
2167 to = run_cond (depth, &cmd->body.cond, from, to, ctx);
2168 else if (cmd->type == FontLayoutCmdTypeOTF)
2169 to = run_otf (depth, &cmd->body.otf, from, to, ctx);
2170 else if (cmd->type == FontLayoutCmdTypeOTFCategory)
2171 to = try_otf (depth, &cmd->body.otf, from, to, ctx);
2175 if (id <= CMD_ID_OFFSET_COMBINING)
2177 ctx->combining_code = CMD_ID_TO_COMBINING_CODE (id);
2178 if (MDEBUG_FLAG () > 2)
2179 MDEBUG_PRINT3 ("\n [FLT] %*s(CMB %s)", depth, "",
2180 dump_combining_code (ctx->combining_code));
2191 g = GREF (ctx->out, ctx->out->used - 1);
2192 if (ctx->combining_code)
2193 SET_COMBINING_CODE (g, ctx, ctx->combining_code);
2194 if (ctx->left_padding)
2195 SET_LEFT_PADDING (g, ctx, LeftPaddingMask);
2196 if (ctx->cluster_begin_idx >= 0)
2197 UPDATE_CLUSTER_RANGE (ctx, g);
2198 if (MDEBUG_FLAG () > 2)
2201 MDEBUG_PRINT2 ("\n [FLT] %*s(COPY |)", depth, "");
2203 MDEBUG_PRINT3 ("\n [FLT] %*s(COPY 0x%X)", depth, "", g->c);
2205 ctx->code_offset = ctx->combining_code = ctx->left_padding = 0;
2209 case CMD_ID_CLUSTER_BEGIN:
2210 if (ctx->cluster_begin_idx < 0)
2212 if (MDEBUG_FLAG () > 2)
2213 MDEBUG_PRINT3 ("\n [FLT] %*s<%d", depth, "",
2214 GREF (ctx->in, from)->from);
2215 ctx->cluster_begin_idx = ctx->out->used;
2216 ctx->cluster_begin_pos = GREF (ctx->in, from)->from;
2217 ctx->cluster_end_pos = GREF (ctx->in, from)->to;
2221 case CMD_ID_CLUSTER_END:
2222 if (ctx->cluster_begin_idx >= 0
2223 && ctx->cluster_begin_idx < ctx->out->used)
2227 if (MDEBUG_FLAG () > 2)
2228 MDEBUG_PRINT1 (" %d>", ctx->cluster_end_pos + 1);
2229 for (i = ctx->cluster_begin_idx; i < ctx->out->used; i++)
2231 GREF (ctx->out, i)->from = ctx->cluster_begin_pos;
2232 GREF (ctx->out, i)->to = ctx->cluster_end_pos;
2234 ctx->cluster_begin_idx = -1;
2238 case CMD_ID_SEPARATOR:
2242 if (MDEBUG_FLAG () > 2)
2243 MDEBUG_PRINT2 ("\n [FLT] %*s|", depth, "");
2244 i = from < to ? from : from - 1;
2246 g = GREF (ctx->out, ctx->out->used - 1);
2247 g->c = -1, g->code = 0;
2248 g->xadv = g->yadv = 0;
2250 SET_MEASURED (g, 0);
2251 SET_CATEGORY_CODE (g, ' ');
2255 case CMD_ID_LEFT_PADDING:
2256 if (MDEBUG_FLAG () > 2)
2257 MDEBUG_PRINT2 ("\n [FLT] %*s[", depth, "");
2258 ctx->left_padding = 1;
2261 case CMD_ID_RIGHT_PADDING:
2262 if (ctx->out->used > 0)
2264 if (MDEBUG_FLAG () > 2)
2265 MDEBUG_PRINT2 ("\n [FLT] %*s]", depth, "");
2266 g = GREF (ctx->out, ctx->out->used - 1);
2267 SET_RIGHT_PADDING (g, ctx, RightPaddingMask);
2272 MERROR (MERROR_DRAW, -1);
2276 run_stages (MFLTGlyphString *gstring, int from, int to,
2277 MFLT *flt, FontLayoutContext *ctx)
2279 MFLTGlyphString buf, *temp;
2281 int orig_from = from, orig_to = to;
2282 int from_pos, to_pos, len;
2285 MPlist *stages = flt->stages;
2286 FontLayoutCategory *prev_category = NULL;
2288 from_pos = GREF (ctx->in, from)->from;
2289 to_pos = GREF (ctx->in, to - 1)->to;
2290 len = to_pos - from_pos;
2294 GINIT (ctx->out, ctx->out->allocated);
2295 ctx->encoded = alloca (ctx->out->allocated);
2296 if (! ctx->out->glyphs || ! ctx->encoded)
2299 for (stage_idx = 0; 1; stage_idx++)
2304 ctx->stage = (FontLayoutStage *) MPLIST_VAL (stages);
2305 table = ctx->stage->category->table;
2306 stages = MPLIST_NEXT (stages);
2307 if (MPLIST_TAIL_P (stages))
2308 ctx->category = NULL;
2310 ctx->category = ((FontLayoutStage *) MPLIST_VAL (stages))->category;
2311 ctx->code_offset = ctx->combining_code = ctx->left_padding = 0;
2312 ctx->encoded_offset = from;
2313 for (i = from; i < to; i++)
2315 MFLTGlyph *g = GREF (ctx->in, i);
2318 if (GET_COMBINED (g)
2319 || (prev_category && prev_category != ctx->stage->category))
2321 enc = (GET_ENCODED (g)
2322 ? (g->c > 0 ? (int) mchartable_lookup (table, g->c) : 1)
2324 ? (int) mchartable_lookup (table, g->code)
2326 if (! GET_COMBINED (g))
2327 SET_CATEGORY_CODE (g, enc);
2330 enc = GET_CATEGORY_CODE (g);
2331 ctx->encoded[i - from] = enc;
2332 if (! enc && stage_idx == 0)
2338 ctx->encoded[i - from] = '\0';
2339 ctx->match_indices[0] = from;
2340 ctx->match_indices[1] = to;
2341 for (i = 2; i < NMATCH; i++)
2342 ctx->match_indices[i] = -1;
2344 if (MDEBUG_FLAG () > 2)
2346 MDEBUG_PRINT2 ("\n [FLT] (STAGE %d \"%s\"", stage_idx,
2348 MDEBUG_PRINT (" (");
2349 for (i = from; i < to; i++)
2351 g = GREF (ctx->in, i);
2353 MDEBUG_PRINT2 ("%*s|", (i > 0), "");
2355 MDEBUG_PRINT3 ("%*s%04X", (i > 0), "", GREF (ctx->in, i)->code);
2359 result = run_command (4, INDEX_TO_CMD_ID (0), from, to, ctx);
2360 if (MDEBUG_FLAG () > 2)
2365 /* If this is the last stage, break the loop. */
2366 if (MPLIST_TAIL_P (stages))
2369 /* Otherwise, prepare for the next stage. */
2370 prev_category = ctx->stage->category;
2377 GINIT (&buf, ctx->out->allocated);
2386 if (ctx->out->used > 0)
2389 int x_ppem = ctx->font->x_ppem << 6, y_ppem = ctx->font->y_ppem << 6;
2391 /* Remove separator glyphs. */
2392 for (i = 0; i < ctx->out->used;)
2394 g = GREF (ctx->out, i);
2396 GREPLACE (NULL, 0, 0, ctx->out, i, i + 1);
2401 /* Get actual glyph IDs of glyphs. */
2402 ctx->font->get_glyph_id (ctx->font, ctx->out, 0, ctx->out->used);
2404 /* Check if all characters in the range are covered by some
2405 glyph(s). If not, change <from> and <to> of glyphs to cover
2406 uncovered characters. */
2407 g_indices = alloca (sizeof (int) * len);
2410 for (i = 0; i < len; i++) g_indices[i] = -1;
2411 for (i = 0; i < ctx->out->used; i++)
2415 g = GREF (ctx->out, i);
2416 for (pos = g->from; pos <= g->to; pos++)
2417 if (g_indices[pos - from_pos] < 0)
2418 g_indices[pos - from_pos] = i;
2420 for (i = 0; i < len; i++)
2421 if (g_indices[i] < 0)
2427 for (i++; i < len && g_indices[i] < 0; i++);
2429 g = GREF (ctx->out, j);
2430 this_from = g->from;
2432 g->from = orig_from + i;
2433 } while (++j < ctx->out->used
2434 && (g = GREF (ctx->out, j))
2435 && g->from == this_from);
2441 j = g_indices[i - 1];
2442 g = GREF (ctx->out, j);
2445 g->to = orig_from + i + 1;
2447 && (g = GREF (ctx->out, j))
2448 && g->to == this_to);
2452 ctx->font->get_metrics (ctx->font, ctx->out, 0, ctx->out->used);
2454 /* Handle combining. */
2455 if (ctx->check_mask & CombinedMask)
2457 MFLTGlyph *base = GREF (ctx->out, 0);
2458 int base_height = base->ascent + base->descent;
2459 int base_width = base->rbearing - base->lbearing;
2462 for (i = 1; i < ctx->out->used; i++)
2464 if ((g = GREF (ctx->out, i))
2466 && (combining_code = GET_COMBINING_CODE (g)))
2468 int height = g->ascent + g->descent;
2469 int width = g->rbearing - g->lbearing;
2470 int base_x, base_y, add_x, add_y, off_x, off_y;
2472 if (base->from > g->from)
2473 base->from = g->from;
2474 else if (base->to < g->to)
2477 base_x = COMBINING_CODE_BASE_X (combining_code);
2478 base_y = COMBINING_CODE_BASE_Y (combining_code);
2479 add_x = COMBINING_CODE_ADD_X (combining_code);
2480 add_y = COMBINING_CODE_ADD_Y (combining_code);
2481 off_x = COMBINING_CODE_OFF_X (combining_code);
2482 off_y = COMBINING_CODE_OFF_Y (combining_code);
2484 g->xoff = ((base_width * base_x - width * add_x) / 2
2485 + x_ppem * off_x / 100
2486 - (base->xadv - base->lbearing) - g->lbearing);
2488 g->yoff = base_height * base_y / 2 - base->ascent;
2492 g->yoff -= height * add_y / 2 - g->ascent;
2493 g->yoff -= y_ppem * off_y / 100;
2494 if (base->lbearing > base->xadv + g->lbearing + g->xoff)
2495 base->lbearing = base->xadv + g->lbearing + g->xoff;
2496 if (base->rbearing < base->xadv + g->rbearing + g->xoff)
2497 base->rbearing = base->xadv + g->rbearing + g->xoff;
2498 if (base->ascent < g->ascent - g->yoff)
2499 base->ascent = g->ascent - g->yoff;
2500 if (base->descent < g->descent - g->yoff)
2501 base->descent = g->descent - g->yoff;
2502 g->xadv = g->yadv = 0;
2503 if (GET_RIGHT_PADDING (g))
2504 SET_RIGHT_PADDING (base, ctx, RightPaddingMask);
2510 base_height = g->ascent + g->descent;
2511 base_width = g->rbearing - g->lbearing;
2516 /* Handle padding */
2517 if (ctx->check_mask & (LeftPaddingMask | RightPaddingMask))
2518 for (i = 0; i < ctx->out->used; i++)
2520 g = GREF (ctx->out, i);
2521 if (! GET_COMBINED (g))
2523 if (GET_RIGHT_PADDING (g) && g->rbearing > g->xadv)
2525 g->xadv = g->rbearing;
2528 if (GET_LEFT_PADDING (g) && g->lbearing < 0)
2530 g->xoff += - g->lbearing;
2531 g->xadv += - g->lbearing;
2532 g->rbearing += - g->lbearing;
2540 GREPLACE (ctx->out, 0, ctx->out->used, gstring, orig_from, orig_to);
2541 to = orig_from + ctx->out->used;
2546 setup_combining_coverage (int from, int to, void *val, void *arg)
2548 int combining_class = (int) val;
2551 if (combining_class < 200)
2553 else if (combining_class <= 204)
2555 if ((combining_class % 2) == 0)
2556 category = "bcd"[(combining_class - 200) / 2];
2558 else if (combining_class <= 232)
2560 if ((combining_class % 2) == 0)
2561 category = "efghijklmnopq"[(combining_class - 208) / 2];
2563 else if (combining_class == 233)
2565 else if (combining_class == 234)
2567 else if (combining_class == 240)
2569 mchartable_set_range ((MCharTable *) arg, from, to, (void *) category);
2573 setup_combining_flt (MFLT *flt)
2576 MCharTable *combininig_class_table
2577 = mchar_get_prop_table (Mcombining_class, &type);
2579 mchartable_set_range (flt->coverage->table, 0, 0x10FFFF, (void *) 'u');
2580 if (combininig_class_table)
2581 mchartable_map (combininig_class_table, (void *) 0,
2582 setup_combining_coverage, flt->coverage->table);
2585 #define CHECK_FLT_STAGES(flt) ((flt)->stages || load_flt (flt, NULL) == 0)
2587 static FontLayoutCategory *
2588 configure_category (FontLayoutCategory *category, MFLTFont *font)
2590 if (! mflt_font_id || ! mflt_iterate_otf_feature)
2592 FontLayoutCategory *new = malloc (sizeof (FontLayoutCategory));
2593 new->definition = NULL;
2594 new->table = category->table;
2595 M17N_OBJECT_REF (new->table);
2598 return load_category_table (category->definition, font);
2602 configure_flt (MFLT *flt, MFLTFont *font, MSymbol font_id)
2607 if (! mflt_font_id || ! mflt_iterate_otf_feature)
2609 MPLIST_DO (plist, flt_list)
2611 configured = MPLIST_VAL (plist);
2612 if (! configured->font_id)
2614 if (configured->name == flt->name
2615 && configured->font_id == font_id)
2618 if (! MSTRUCT_CALLOC_SAFE (configured))
2621 configured->stages = mplist_copy (flt->stages);
2622 MPLIST_DO (plist, configured->stages)
2624 FontLayoutStage *stage = MPLIST_VAL (plist);
2625 if (stage->category->definition)
2627 MSTRUCT_CALLOC (stage, MERROR_FLT);
2628 *stage = *((FontLayoutStage *) MPLIST_VAL (plist));
2629 stage->category = configure_category (stage->category, font);
2630 MPLIST_VAL (plist) = stage;
2633 M17N_OBJECT_REF (stage->category->table);
2635 configured->need_config = 0;
2636 configured->font_id = font_id;
2637 mplist_push (flt_list, flt->name, configured);
2643 int m17n__flt_initialized;
2648 /* The following two are actually not exposed to a user but concealed
2649 by the macro M17N_INIT (). */
2652 m17n_init_flt (void)
2654 int mdebug_flag = MDEBUG_INIT;
2656 merror_code = MERROR_NONE;
2657 if (m17n__flt_initialized++)
2660 if (merror_code != MERROR_NONE)
2662 m17n__flt_initialized--;
2666 MDEBUG_PUSH_TIME ();
2668 Mcond = msymbol ("cond");
2669 Mrange = msymbol ("range");
2670 Mfont = msymbol ("font");
2671 Mlayouter = msymbol ("layouter");
2672 Mcombining = msymbol ("combining");
2673 Mfont_facility = msymbol ("font-facility");
2674 Mequal = msymbol ("=");
2675 Mgenerator = msymbol ("generator");
2676 Mend = msymbol ("end");
2678 mflt_enable_new_feature = 0;
2679 mflt_iterate_otf_feature = NULL;
2680 mflt_font_id = NULL;
2681 mflt_try_otf = NULL;
2683 MDEBUG_PRINT_TIME ("INIT", (mdebug__output, " to initialize the flt modules."));
2688 m17n_fini_flt (void)
2690 int mdebug_flag = MDEBUG_FINI;
2692 if (m17n__flt_initialized == 0
2693 || --m17n__flt_initialized > 0)
2696 MDEBUG_PUSH_TIME ();
2698 MDEBUG_PRINT_TIME ("FINI", (mdebug__output, " to finalize the flt modules."));
2704 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
2706 /*** @addtogroup m17nFLT */
2712 @brief Return an FLT object that has a specified name.
2714 The mflt_get () function returns an FLT object whose name is $NAME.
2717 If the operation was successful, mflt_get () returns a pointer
2718 to the found FLT object. Otherwise, it returns @c NULL. */
2721 @brief »ØÄꤵ¤ì¤¿Ì¾Á°¤ò»ý¤Ä FLT ¥ª¥Ö¥¸¥§¥¯¥È¤òÊÖ¤¹.
2723 ´Ø¿ô mflt_get () ¤Ï¡¢$NAME ¤È¤¤¤¦Ì¾Á°¤ò»ý¤Ä FLT ¥ª¥Ö¥¸¥§¥¯¥È¤òÊÖ¤¹¡£
2726 ¤â¤·À®¸ù¤¹¤ì¤Ð¡¢mflt_get () ¤Ï¸«¤Ä¤«¤Ã¤¿ FLT
2727 ¥ª¥Ö¥¸¥§¥¯¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¼ºÇÔ¤·¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤¹¡£ */
2730 mflt_get (MSymbol name)
2735 if (! flt_list && list_flt () < 0)
2737 for (plist = flt_list; plist; plist = plist->next)
2738 if (((MFLT *) MPLIST_VAL (plist))->font_id == Mnil)
2740 flt = mplist_get (plist, name);
2741 if (! flt || ! CHECK_FLT_STAGES (flt))
2743 if (flt->name == Mcombining
2744 && ! mchartable_lookup (flt->coverage->table, 0))
2745 setup_combining_flt (flt);
2752 @brief Find an FLT suitable for the specified character and font.
2754 The mflt_find () function returns the most appropriate FLT for
2755 layouting character $C with font $FONT.
2758 If the operation was successful, mflt_find () returns a pointer
2759 to the found FLT object. Otherwise, it returns @c NULL. */
2762 @brief »ØÄꤵ¤ì¤¿Ê¸»ú¤È¥Õ¥©¥ó¥È¤Ë¹ç¤Ã¤¿ FLT ¤òõ¤¹.
2764 ´Ø¿ô mflt_find () ¤Ï¡¢Ê¸»ú $C ¤ò¥Õ¥©¥ó¥È $FONT
2765 ¤Ç¥ì¥¤¥¢¥¦¥È¤¹¤ë¤¿¤á¤ËºÇ¤âŬÀÚ¤Ê FLT ¤òÊÖ¤¹¡£
2768 ¤â¤·À®¸ù¤¹¤ì¤Ð¡¢mflt_find () ¤Ï¸«¤Ä¤«¤Ã¤¿ FLT
2769 ¥ª¥Ö¥¸¥§¥¯¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¼ºÇÔ¤·¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤¹¡£ */
2772 mflt_find (int c, MFLTFont *font)
2776 static MSymbol unicode_bmp = NULL, unicode_full = NULL;
2780 unicode_bmp = msymbol ("unicode-bmp");
2781 unicode_full = msymbol ("unicode-full");
2784 if (! flt_list && list_flt () < 0)
2786 /* Skip configured FLTs. */
2787 MPLIST_DO (plist, flt_list)
2788 if (((MFLT *) MPLIST_VAL (plist))->font_id == Mnil)
2794 MPLIST_DO (pl, plist)
2796 flt = MPLIST_VAL (pl);
2797 if (flt->registry != unicode_bmp
2798 && flt->registry != unicode_full)
2800 if (flt->family && flt->family != font->family)
2802 if (flt->name == Mcombining
2803 && ! mchartable_lookup (flt->coverage->table, 0))
2804 setup_combining_flt (flt);
2806 && ! mchartable_lookup (flt->coverage->table, c))
2810 MFLTOtfSpec *spec = &flt->otf;
2812 if (! font->check_otf)
2814 if ((spec->features[0] && spec->features[0][0] != 0xFFFFFFFF)
2815 || (spec->features[1] && spec->features[1][0] != 0xFFFFFFFF))
2818 else if (! font->check_otf (font, spec))
2831 MPLIST_DO (pl, plist)
2833 flt = MPLIST_VAL (pl);
2834 if (mchartable_lookup (flt->coverage->table, c))
2841 if (! CHECK_FLT_STAGES (flt))
2843 if (font && flt->need_config && mflt_font_id)
2844 flt = configure_flt (flt, font, mflt_font_id (font));
2850 @brief Return the name of an FLT.
2852 The mflt_name () function returns the name of $FLT. */
2855 @brief FLT ¤Î̾Á°¤òÊÖ¤¹.
2857 ´Ø¿ô mflt_name () ¤Ï $FLT ¤Î̾Á°¤òÊÖ¤¹¡£ */
2860 mflt_name (MFLT *flt)
2862 return MSYMBOL_NAME (flt->name);
2867 @brief Return a coverage of a FLT.
2869 The mflt_coverage () function returns a char-table that contains
2870 nonzero values for characters supported by $FLT. */
2873 @brief FLT ¤ÎÈϰϤòÊÖ¤¹.
2875 ´Ø¿ô mflt_coverage () ¤Ï¡¢$FLT ¤¬¥µ¥Ý¡¼¥È¤¹¤ëʸ»ú¤ËÂФ·¤Æ
2876 0 ¤Ç¤Ê¤¤Ãͤò´Þ¤àʸ»ú¥Æ¡¼¥Ö¥ë¤òÊÖ¤¹¡£ */
2879 mflt_coverage (MFLT *flt)
2881 return flt->coverage->table;
2886 @brief Layout characters with an FLT.
2888 The mflt_run () function layouts characters in $GSTRING between
2889 $FROM (inclusive) and $TO (exclusive) with $FONT. If $FLT is
2890 nonzero, it is used for all the charaters. Otherwise, appropriate
2891 FLTs are automatically chosen.
2894 The operation was successful. The value is the index to the
2895 glyph, which was previously indexed by $TO, in $GSTRING->glyphs.
2898 $GSTRING->glyphs is too short to store the result. The caller can
2899 call this fucntion again with a longer $GSTRING->glyphs.
2902 Some other error occurred. */
2905 @brief FLT ¤ò»È¤Ã¤Æʸ»ú¤ò¥ì¥¤¥¢¥¦¥È¤¹¤ë.
2907 ´Ø¿ô mflt_run () ¤Ï¡¢$GSTRING Ãæ¤Î $FROM ¤«¤é $TO ľÁ°¤Þ¤Ç¤Îʸ»ú¤ò
2908 $FONT ¤òÍѤ¤¤Æ¥ì¥¤¥¢¥¦¥È¤¹¤ë¡£¤â¤· $FLT
2909 ¤¬¥¼¥í¤Ç¤Ê¤±¤ì¤Ð¡¢¤½¤ÎÃͤò¤¹¤Ù¤Æ¤Îʸ»ú¤ËÂФ·¤ÆÍѤ¤¤ë¡£
2910 ¤½¤¦¤Ç¤Ê¤±¤ì¤ÐŬÀÚ¤Ê FLT ¤ò¼«Æ°Åª¤ËÁªÂò¤¹¤ë¡£
2913 ¼Â¹ÔÀ®¸ù¤ò¼¨¤¹¡£ÊÖ¤µ¤ì¤ëÃͤϡ¢$GSTRING->glyphs Ãæ¤Ç°ÊÁ° $TO
2914 ¤Ë¤è¤Ã¤Æ¼¨¤µ¤ì¤Æ¤¤¤¿¥°¥ê¥Õ¤Ø¤Î¥¤¥ó¥Ç¥¯¥¹¤Ç¤¢¤ë¡£
2917 ·ë²Ì¤ò³ÊǼ¤¹¤ë¤Ë¤Ï $GSTRING->glyphs ¤¬Ã»¤¹¤®¤ë¤³¤È¤ò¼¨¤¹¡£
2918 ¸Æ¤Ó½Ð¤·Â¦¤Ï¡¢¤è¤êŤ¤ $GSTRING->glyphs
2919 ¤òÍѤ¤¤ÆºÆÅÙ¤³¤Î´Ø¿ô¤ò¸Æ¤Ö¤³¤È¤¬¤Ç¤¤ë¡£
2922 ¤½¤Î¾¤Î¥¨¥é¡¼¤¬µ¯¤¤¿¤³¤È¤ò¼¨¤¹¡£ */
2925 mflt_run (MFLTGlyphString *gstring, int from, int to,
2926 MFLTFont *font, MFLT *flt)
2928 FontLayoutContext ctx;
2929 int match_indices[NMATCH];
2931 MFLTGlyphString out;
2932 int auto_flt = ! flt;
2934 int this_from, this_to;
2935 MSymbol font_id = mflt_font_id ? mflt_font_id (font) : Mnil;
2939 /* This is usually sufficient, but if not, we retry with the larger
2940 values at most 3 times. This value is also used for the
2941 allocating size of ctx.encoded. */
2942 out.allocated = (to - from) * 4;
2944 for (i = from; i < to; i++)
2946 g = GREF (gstring, i);
2950 memset (g, 0, sizeof (MFLTGlyph));
2953 g->from = g->to = i;
2956 for (this_from = from; this_from < to;)
2960 for (this_to = this_from; this_to < to; this_to++)
2961 if (mchartable_lookup (flt->coverage->table,
2962 GREF (gstring, this_to)->c))
2967 if (! flt_list && list_flt () < 0)
2969 font->get_glyph_id (font, gstring, this_from, to);
2970 font->get_metrics (font, gstring, this_from, to);
2974 for (this_to = this_from; this_to < to; this_to++)
2976 c = GREF (gstring, this_to)->c;
2977 if (c >= flt_min_coverage && c <= flt_max_coverage)
2980 for (; this_to < to; this_to++)
2982 c = GREF (gstring, this_to)->c;
2984 && mchartable_lookup (((MFLT *) font->internal)->coverage->table, c))
2986 flt = font->internal;
2989 flt = mflt_find (c, font);
2992 if (CHECK_FLT_STAGES (flt))
2994 font->internal = flt;
3001 if (this_from < this_to)
3003 font->get_glyph_id (font, gstring, this_from, this_to);
3004 font->get_metrics (font, gstring, this_from, this_to);
3005 this_from = this_to;
3010 MDEBUG_PRINT1 (" [FLT] (%s", MSYMBOL_NAME (flt->name));
3012 if (flt->need_config && font_id != Mnil)
3013 flt = configure_flt (flt, font, font_id);
3015 for (; this_to < to; this_to++)
3018 g = GREF (gstring, this_to);
3019 enc = (int) mchartable_lookup (flt->coverage->table, g->c);
3022 SET_CATEGORY_CODE (g, enc);
3028 MDEBUG_PRINT1 (" (%s)", MSYMBOL_NAME (font->family));
3029 MDEBUG_PRINT ("\n [FLT] (SOURCE");
3030 for (i = this_from, j = 0; i < this_to; i++, j++)
3032 if (j > 0 && j % 8 == 0)
3033 MDEBUG_PRINT ("\n [FLT] ");
3034 MDEBUG_PRINT1 (" %04X", GREF (gstring, i)->c);
3039 for (i = 0; i < 3; i++)
3042 memset (&ctx, 0, sizeof ctx);
3043 ctx.match_indices = match_indices;
3045 ctx.cluster_begin_idx = -1;
3048 j = run_stages (gstring, this_from, this_to, flt, &ctx);
3062 MDEBUG_PRINT ("\n [FLT] (RESULT");
3063 if (MDEBUG_FLAG () > 1)
3066 for (i = 0; this_from < this_to; i++, this_from++)
3068 g = GREF (gstring, this_from);
3072 MDEBUG_PRINT2 ("\n [FLT] %02d-%02d",
3075 MDEBUG_PRINT2 (" %02d-%02d", g->from, g->to);
3078 MDEBUG_PRINT4 (" (%04X %d %d %d)",
3079 g->code, g->xadv, g->xoff, g->yoff);
3083 for (; this_from < this_to; this_from++)
3084 MDEBUG_PRINT1 (" %04X", GREF (gstring, this_from)->code);
3085 MDEBUG_PRINT ("))\n");
3087 this_from = this_to;
3092 int len = to - from;
3095 memcpy (((char *) out.glyphs),
3096 ((char *) gstring->glyphs) + gstring->glyph_size * from,
3097 gstring->glyph_size * len);
3098 for (i = from, j = to; i < to;)
3100 for (k = i + 1, j--; k < to && GREF (&out, k)->xadv == 0;
3102 GCPY (&out, i, (k - i), gstring, j);
3110 int mflt_enable_new_feature;
3112 int (*mflt_iterate_otf_feature) (struct _MFLTFont *font,
3115 unsigned char *table);
3117 MSymbol (*mflt_font_id) (struct _MFLTFont *font);
3119 int (*mflt_try_otf) (struct _MFLTFont *font, MFLTOtfSpec *spec,
3120 MFLTGlyphString *gstring, int from, int to);
3123 /* for debugging... */
3126 dump_flt_cmd (FontLayoutStage *stage, int id, int indent)
3128 char *prefix = (char *) alloca (indent + 1);
3130 memset (prefix, 32, indent);
3134 fprintf (mdebug__output, "0x%02X", id);
3135 else if (id <= CMD_ID_OFFSET_INDEX)
3137 int idx = CMD_ID_TO_INDEX (id);
3138 FontLayoutCmd *cmd = stage->cmds + idx;
3140 if (cmd->type == FontLayoutCmdTypeRule)
3142 FontLayoutCmdRule *rule = &cmd->body.rule;
3145 fprintf (mdebug__output, "(rule ");
3146 if (rule->src_type == SRC_REGEX)
3147 fprintf (mdebug__output, "\"%s\"", rule->src.re.pattern);
3148 else if (rule->src_type == SRC_INDEX)
3149 fprintf (mdebug__output, "%d", rule->src.match_idx);
3150 else if (rule->src_type == SRC_SEQ)
3151 fprintf (mdebug__output, "(seq)");
3152 else if (rule->src_type == SRC_RANGE)
3153 fprintf (mdebug__output, "(range)");
3155 fprintf (mdebug__output, "(invalid src)");
3157 for (i = 0; i < rule->n_cmds; i++)
3159 fprintf (mdebug__output, "\n%s ", prefix);
3160 dump_flt_cmd (stage, rule->cmd_ids[i], indent + 2);
3162 fprintf (mdebug__output, ")");
3164 else if (cmd->type == FontLayoutCmdTypeCond)
3166 FontLayoutCmdCond *cond = &cmd->body.cond;
3169 fprintf (mdebug__output, "(cond");
3170 for (i = 0; i < cond->n_cmds; i++)
3172 fprintf (mdebug__output, "\n%s ", prefix);
3173 dump_flt_cmd (stage, cond->cmd_ids[i], indent + 2);
3175 fprintf (mdebug__output, ")");
3177 else if (cmd->type == FontLayoutCmdTypeOTF)
3179 fprintf (mdebug__output, "(otf)");
3182 fprintf (mdebug__output, "(error-command)");
3184 else if (id <= CMD_ID_OFFSET_COMBINING)
3185 fprintf (mdebug__output, "cominging-code");
3187 fprintf (mdebug__output, "(predefiend %d)", id);
3191 @brief Dump a Font Layout Table.
3193 The mdebug_dump_flt () function prints the Font Layout Table $FLT
3194 in a human readable way to the stderr or to what specified by the
3195 environment variable MDEBUG_OUTPUT_FILE. $INDENT specifies how
3196 many columns to indent the lines but the first one.
3199 This function returns $FLT. */
3202 mdebug_dump_flt (MFLT *flt, int indent)
3204 char *prefix = (char *) alloca (indent + 1);
3208 memset (prefix, 32, indent);
3210 fprintf (mdebug__output, "(flt");
3211 MPLIST_DO (plist, flt->stages)
3213 FontLayoutStage *stage = (FontLayoutStage *) MPLIST_VAL (plist);
3216 fprintf (mdebug__output, "\n%s (stage %d", prefix, stage_idx);
3217 for (i = 0; i < stage->used; i++)
3219 fprintf (mdebug__output, "\n%s ", prefix);
3220 dump_flt_cmd (stage, INDEX_TO_CMD_ID (i), indent + 4);
3222 fprintf (mdebug__output, ")");
3225 fprintf (mdebug__output, ")");
3230 mflt_dump_gstring (MFLTGlyphString *gstring)
3234 fprintf (mdebug__output, "(flt-gstring");
3235 for (i = 0; i < gstring->used; i++)
3237 MFLTGlyph *g = GREF (gstring, i);
3238 fprintf (mdebug__output, "\n (%02d pos:%d-%d c:%04X code:%04X cat:%c)",
3239 i, g->from, g->to, g->c, g->code, GET_CATEGORY_CODE (g));
3241 fprintf (mdebug__output, ")\n");