1 /* m17n-flt.c -- Font Layout Table sub-module.
2 Copyright (C) 2003, 2004, 2007
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,
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 CombiningCodeMask = 0xFFFFFFF,
259 LeftPaddingMask = 1 << 28,
260 RightPaddingMask = 1 << 29
263 #define SET_GLYPH_INFO(g, mask, ctx, info) \
264 ((g)->internal = (((g)->internal & ~(mask)) | (info)), \
265 (ctx)->check_mask |= (mask))
267 #define GET_COMBINING_CODE(g) ((g)->internal & CombiningCodeMask)
268 #define SET_COMBINING_CODE(g, ctx, code) \
269 SET_GLYPH_INFO (g, CombiningCodeMask, ctx, code)
270 #define GET_LEFT_PADDING(g) ((g)->internal & LeftPaddingMask)
271 #define SET_LEFT_PADDING(g, ctx, flag) \
272 SET_GLYPH_INFO (g, LeftPaddingMask, ctx, flag)
273 #define GET_RIGHT_PADDING(g) ((g)->internal & RightPaddingMask)
274 #define SET_RIGHT_PADDING(g, ctx, flag) \
275 SET_GLYPH_INFO (g, RightPaddingMask, ctx, flag)
276 #define GET_ENCODED(g) ((g)->encoded)
277 #define SET_ENCODED(g, flag) ((g)->encoded = (flag))
278 #define GET_MEASURED(g) ((g)->measured)
279 #define SET_MEASURED(g, flag) ((g)->measured = (flag))
281 #define GINIT(gstring, n) \
283 if (! (gstring)->glyph_size) \
284 (gstring)->glyph_size = sizeof (MFLTGlyph); \
285 (gstring)->glyphs = alloca ((gstring)->glyph_size * (n)); \
286 (gstring)->allocated = (n); \
287 (gstring)->used = 0; \
290 #define GALLOCA (gstring) \
291 ((MFLTGlyph *) alloca ((gstring)->glyph_size))
293 #define GREF(gstring, idx) \
294 ((MFLTGlyph *) ((char *) ((gstring)->glyphs) + (gstring)->glyph_size * (idx)))
296 #define PREV(gstring, g) \
297 ((MFLTGlyph *) ((char *) (g) - (gstring)->glyph_size))
299 #define NEXT(gstring, g) \
300 ((MFLTGlyph *) ((char *) (g) + (gstring)->glyph_size))
302 #define GCPY(src, src_idx, n, tgt, tgt_idx) \
304 memcpy ((char *) ((tgt)->glyphs) + (tgt)->glyph_size * (tgt_idx), \
305 (char *) ((src)->glyphs) + (src)->glyph_size * (src_idx), \
306 (src)->glyph_size * (n)); \
309 #define GDUP(ctx, idx) \
311 MFLTGlyphString *src = (ctx)->in; \
312 MFLTGlyphString *tgt = (ctx)->out; \
313 if (tgt->allocated <= tgt->used) \
315 GCPY (src, (idx), 1, tgt, tgt->used); \
320 GREPLACE (MFLTGlyphString *src, int src_from, int src_to,
321 MFLTGlyphString *tgt, int tgt_from, int tgt_to)
323 int src_len = src_to - src_from;
324 int tgt_len = tgt_to - tgt_from;
325 int inc = src_len - tgt_len;
327 if (tgt->allocated < tgt->used + inc)
329 if (inc != 0 && tgt_to < tgt->used)
330 memmove ((char *) tgt->glyphs + tgt->glyph_size * (tgt_from + src_len),
331 (char *) tgt->glyphs + tgt->glyph_size * tgt_to,
332 tgt->glyph_size * (tgt->used - tgt_to));
334 memcpy ((char *) tgt->glyphs + tgt->glyph_size * tgt_from,
335 (char *) src->glyphs + src->glyph_size * src_from,
336 src->glyph_size * src_len);
345 -0x0F .. -2 : builtin commands
346 -0x100000F .. -0x10 : combining code
347 ... -0x1000010: index to FontLayoutStage->cmds
350 #define INVALID_CMD_ID -1
351 #define CMD_ID_OFFSET_BUILTIN -3
352 #define CMD_ID_OFFSET_COMBINING -0x10
353 #define CMD_ID_OFFSET_INDEX -0x1000010
355 /* Builtin commands. */
356 #define CMD_ID_COPY -3 /* '=' */
357 #define CMD_ID_REPEAT -4 /* '*' */
358 #define CMD_ID_CLUSTER_BEGIN -5 /* '<' */
359 #define CMD_ID_CLUSTER_END -6 /* '>' */
360 #define CMD_ID_SEPARATOR -7 /* '|' */
361 #define CMD_ID_LEFT_PADDING -8 /* '[' */
362 #define CMD_ID_RIGHT_PADDING -9 /* ']' */
364 #define CMD_ID_TO_COMBINING_CODE(id) (CMD_ID_OFFSET_COMBINING - (id))
365 #define COMBINING_CODE_TO_CMD_ID(code) (CMD_ID_OFFSET_COMBINING - (code))
367 #define CMD_ID_TO_INDEX(id) (CMD_ID_OFFSET_INDEX - (id))
368 #define INDEX_TO_CMD_ID(idx) (CMD_ID_OFFSET_INDEX - (idx))
370 static MSymbol Mcond, Mrange, Mfont_facility, Mequal;
372 #define GLYPH_CODE_P(code) \
373 ((code) >= GLYPH_CODE_MIN && (code) <= GLYPH_CODE_MAX)
375 #define GLYPH_CODE_INDEX(code) ((code) - GLYPH_CODE_MIN)
377 #define UPDATE_CLUSTER_RANGE(ctx, g) \
379 if (ctx->cluster_begin_pos > (g)->from) \
380 ctx->cluster_begin_pos = (g)->from; \
381 if (ctx->cluster_end_pos < (g)->to) \
382 ctx->cluster_end_pos = (g)->to; \
385 enum FontLayoutCmdRuleSrcType
397 enum FontLayoutCmdRuleSrcType src_type;
414 MFLTOtfSpec otf_spec;
424 /* Beginning and end indices of series of SEQ commands. */
425 int seq_beg, seq_end;
426 /* Range of the first character appears in the above series. */
427 int seq_from, seq_to;
433 enum FontLayoutCmdType
435 FontLayoutCmdTypeRule,
436 FontLayoutCmdTypeCond,
437 FontLayoutCmdTypeOTF,
443 enum FontLayoutCmdType type;
445 FontLayoutCmdRule rule;
446 FontLayoutCmdCond cond;
454 /* Non-null if the table must be re-configured by OTF specs included
455 in the definition. */
457 } FontLayoutCategory;
461 FontLayoutCategory *category;
473 FontLayoutCategory *coverage;
476 /* Font for which coverage or some of categories are configured. */
480 /* Font layout table loader */
482 static int parse_otf_command (MSymbol symbol, MFLTOtfSpec *spec);
485 apply_otf_feature (MFLTFont *font, MFLTOtfSpec *spec,
486 int from, int to, MCharTable *table, int category)
491 if (! mflt_iterate_otf_feature)
493 buf = alloca (to + 1 - from);
494 memset (buf, 0, to + 1 - from);
495 if (mflt_iterate_otf_feature (font, spec, from, to, buf) < 0)
497 for (i = to - from; i >= 0; i--)
499 mchartable_set (table, from + i, (void *) category);
502 /* Load a category table from PLIST. PLIST has this form:
503 PLIST ::= ( FROM-CODE TO-CODE ? CATEGORY-CHAR ) *
506 static FontLayoutCategory *
507 load_category_table (MPlist *plist, MFLTFont *font)
509 FontLayoutCategory *category;
514 table = mchartable (Minteger, (void *) 0);
518 int from, to, category_code;
520 if (! MPLIST_PLIST (p))
521 MERROR_GOTO (MERROR_FONT, end);
522 elt = MPLIST_PLIST (p);
523 if (! MPLIST_INTEGER_P (elt))
524 MERROR_GOTO (MERROR_FONT, end);
525 from = MPLIST_INTEGER (elt);
526 elt = MPLIST_NEXT (elt);
527 if (! MPLIST_INTEGER_P (elt))
528 MERROR_GOTO (MERROR_FONT, end);
529 to = MPLIST_INTEGER (elt);
530 elt = MPLIST_NEXT (elt);
531 if (MPLIST_TAIL_P (elt))
536 else if (MPLIST_SYMBOL_P (elt))
541 if (parse_otf_command (MPLIST_SYMBOL (elt), &spec) < 0)
542 MERROR_GOTO (MERROR_FONT, end);
543 elt = MPLIST_NEXT (elt);
544 if (! MPLIST_INTEGER_P (elt))
545 MERROR_GOTO (MERROR_FONT, end);
546 category_code = MPLIST_INTEGER (elt);
547 if (! isalnum (category_code))
548 MERROR_GOTO (MERROR_FONT, end);
549 apply_otf_feature (font, &spec, from, to, table, category_code);
557 if (! MPLIST_INTEGER_P (elt))
558 MERROR_GOTO (MERROR_FONT, end);
559 category_code = MPLIST_INTEGER (elt);
561 if (! isalnum (category_code))
562 MERROR_GOTO (MERROR_FONT, end);
565 mchartable_set (table, from, (void *) category_code);
567 mchartable_set_range (table, from, to, (void *) category_code);
571 category = malloc (sizeof (FontLayoutCategory));
572 category->table = table;
575 category->definition = plist;
576 M17N_OBJECT_REF (plist);
579 category->definition = NULL;
583 #define ref_category_table(CATEGORY) M17N_OBJECT_REF ((CATEGORY)->table)
586 unref_category_table (FontLayoutCategory *category)
588 M17N_OBJECT_UNREF (category->table);
589 if (! category->table)
591 if (category->definition)
592 M17N_OBJECT_UNREF (category->definition);
598 gen_otf_tag (char *p)
600 unsigned int tag = 0;
603 for (i = 0; i < 4 && *p; i++, p++)
604 tag = (tag << 8) | *p;
606 tag = (tag << 8) | 0x20;
611 otf_count_features (char *p, char *end, char stopper, int *count)
616 if (*p != stopper && *p != '\0')
623 if (*p == stopper || *p == '\0')
637 if (*p == stopper || *p == '\0')
649 otf_store_features (char *p, char *end, unsigned *buf)
654 for (i = 0; p < end;)
657 buf[i++] = 0xFFFFFFFF, p += 2, negative = 1;
661 buf[i++] = 0xFFFFFFFF;
662 buf[i++] = gen_otf_tag (p + 1), p += 6;
665 buf[i++] = gen_otf_tag (p), p += 5;
671 parse_otf_command (MSymbol symbol, MFLTOtfSpec *spec)
673 char *str = MSYMBOL_NAME (symbol);
674 char *end = str + MSYMBOL_NAMELEN (symbol);
675 unsigned int script, langsys;
677 int gsub_count = 0, gpos_count = 0;
680 memset (spec, 0, sizeof (MFLTOtfSpec));
683 str += 5; /* skip the heading ":otf=" */
684 script = gen_otf_tag (str);
688 langsys = gen_otf_tag (str);
695 /* Apply all GSUB features. */
700 str = otf_count_features (p, end, '+', &gsub_count);
702 MERROR (MERROR_FLT, -1);
706 /* Apply all GPOS features. */
711 str = otf_count_features (p, end, '\0', &gpos_count);
713 MERROR (MERROR_FLT, -1);
716 spec->script = script;
717 spec->langsys = langsys;
720 spec->features[0] = malloc (sizeof (int) * (gsub_count + 1));
721 if (! spec->features[0])
724 otf_store_features (gsub + 1, gpos, spec->features[0]);
726 spec->features[0][0] = 0xFFFFFFFF, spec->features[0][1] = 0;
730 spec->features[1] = malloc (sizeof (int) * (gpos_count + 1));
731 if (! spec->features[1])
733 if (spec->features[0])
734 free (spec->features[0]);
738 otf_store_features (gpos + 1, str, spec->features[1]);
740 spec->features[1][0] = 0xFFFFFFFF, spec->features[1][1] = 0;
746 /* Parse OTF command name NAME and store the result in CMD.
748 :SCRIPT[/[LANGSYS][=[GSUB-FEATURES][+GPOS-FEATURES]]]
749 where GSUB-FEATURES and GPOS-FEATURES have this form:
750 [FEATURE[,FEATURE]*] | ' ' */
753 load_otf_command (FontLayoutCmd *cmd, MSymbol sym)
755 char *name = MSYMBOL_NAME (sym);
760 /* This is old format of "otf:...". Change it to ":otf=...". */
761 char *str = alloca (MSYMBOL_NAMELEN (sym) + 2);
763 sprintf (str, ":otf=");
764 strcat (str, name + 4);
768 result = parse_otf_command (sym, &cmd->body.otf);
771 cmd->type = FontLayoutCmdTypeOTF;
776 /* Read a decimal number from STR preceded by one of "+-><". '+' and
777 '>' means a plus sign, '-' and '<' means a minus sign. If the
778 number is greater than 127, limit it to 127. */
781 read_decimal_number (char **str)
784 int sign = (*p == '-' || *p == '<') ? -1 : 1;
788 while (*p >= '0' && *p <= '9')
789 n = n * 10 + *p++ - '0';
793 return (n < 127 ? n * sign : 127 * sign);
797 /* Read a horizontal and vertical combining positions from STR, and
798 store them in the place pointed by X and Y. The horizontal
799 position left, center, and right are represented by 0, 1, and 2
800 respectively. The vertical position top, center, bottom, and base
801 are represented by 0, 1, 2, and 3 respectively. If successfully
802 read, return 0, else return -1. */
805 read_combining_position (char *str, int *x, int *y)
810 /* Vertical position comes first. */
811 for (i = 0; i < 4; i++)
820 /* Then comse horizontal position. */
821 for (i = 0; i < 3; i++)
831 /* Return a combining code corresponding to SYM. */
834 get_combining_command (MSymbol sym)
836 char *str = msymbol_name (sym);
837 int base_x, base_y, add_x, add_y, off_x, off_y;
840 if (read_combining_position (str, &base_x, &base_y) < 0)
851 if (c == '+' || c == '-')
853 off_y = read_decimal_number (&str) + 128;
858 if (c == '<' || c == '>')
859 off_x = read_decimal_number (&str) + 128;
863 if (read_combining_position (str, &add_x, &add_y) < 0)
866 c = MAKE_COMBINING_CODE (base_y, base_x, add_y, add_x, off_y, off_x);
867 return (COMBINING_CODE_TO_CMD_ID (c));
871 /* Load a command from PLIST into STAGE, and return that
872 identification number. If ID is not INVALID_CMD_ID, that means we
873 are loading a top level command or a macro. In that case, use ID
874 as the identification number of the command. Otherwise, generate a
875 new id number for the command. MACROS is a list of raw macros. */
878 load_command (FontLayoutStage *stage, MPlist *plist,
879 MPlist *macros, int id)
884 if (MPLIST_INTEGER_P (plist))
886 int code = MPLIST_INTEGER (plist);
889 MERROR (MERROR_DRAW, INVALID_CMD_ID);
892 else if (MPLIST_PLIST_P (plist))
894 /* PLIST ::= ( cond ... ) | ( STRING ... ) | ( INTEGER ... )
895 | ( ( INTEGER INTEGER ) ... )
896 | ( ( range INTEGER INTEGER ) ... )
897 | ( ( font-facilty [ INTEGER ] ) ... )
898 | ( ( font-facilty OTF-SPEC ) ... ) */
899 MPlist *elt = MPLIST_PLIST (plist);
900 int len = MPLIST_LENGTH (elt) - 1;
903 if (id == INVALID_CMD_ID)
906 id = INDEX_TO_CMD_ID (stage->used);
907 MLIST_APPEND1 (stage, cmds, dummy, MERROR_DRAW);
909 cmd = stage->cmds + CMD_ID_TO_INDEX (id);
911 if (MPLIST_SYMBOL_P (elt))
913 FontLayoutCmdCond *cond;
915 if (MPLIST_SYMBOL (elt) != Mcond)
916 MERROR (MERROR_DRAW, INVALID_CMD_ID);
917 elt = MPLIST_NEXT (elt);
918 cmd->type = FontLayoutCmdTypeCond;
919 cond = &cmd->body.cond;
920 cond->seq_beg = cond->seq_end = -1;
921 cond->seq_from = cond->seq_to = 0;
923 MTABLE_CALLOC (cond->cmd_ids, len, MERROR_DRAW);
924 for (i = 0; i < len; i++, elt = MPLIST_NEXT (elt))
926 int this_id = load_command (stage, elt, macros, INVALID_CMD_ID);
928 if (this_id == INVALID_CMD_ID || this_id == -2)
929 MERROR (MERROR_DRAW, this_id);
930 /* The above load_command may relocate stage->cmds. */
931 cmd = stage->cmds + CMD_ID_TO_INDEX (id);
932 cond = &cmd->body.cond;
933 cond->cmd_ids[i] = this_id;
934 if (this_id <= CMD_ID_OFFSET_INDEX)
936 FontLayoutCmd *this_cmd
937 = stage->cmds + CMD_ID_TO_INDEX (this_id);
939 if (this_cmd->type == FontLayoutCmdTypeRule
940 && this_cmd->body.rule.src_type == SRC_SEQ)
942 int first_char = this_cmd->body.rule.src.seq.codes[0];
944 if (cond->seq_beg < 0)
946 /* The first SEQ command. */
948 cond->seq_from = cond->seq_to = first_char;
950 else if (cond->seq_end < 0)
952 /* The following SEQ command. */
953 if (cond->seq_from > first_char)
954 cond->seq_from = first_char;
955 else if (cond->seq_to < first_char)
956 cond->seq_to = first_char;
961 if (cond->seq_beg >= 0 && cond->seq_end < 0)
962 /* The previous one is the last SEQ command. */
968 if (cond->seq_beg >= 0 && cond->seq_end < 0)
969 /* The previous one is the last SEQ command. */
973 if (cond->seq_beg >= 0 && cond->seq_end < 0)
974 /* The previous one is the last SEQ command. */
979 cmd->type = FontLayoutCmdTypeRule;
980 if (MPLIST_MTEXT_P (elt))
982 MText *mt = MPLIST_MTEXT (elt);
983 char *str = (char *) MTEXT_DATA (mt);
987 mtext_ins_char (mt, 0, '^', 1);
988 str = (char *) MTEXT_DATA (mt);
990 if (regcomp (&cmd->body.rule.src.re.preg, str, REG_EXTENDED))
991 MERROR (MERROR_FONT, INVALID_CMD_ID);
992 cmd->body.rule.src_type = SRC_REGEX;
993 cmd->body.rule.src.re.pattern = strdup (str);
995 else if (MPLIST_INTEGER_P (elt))
997 cmd->body.rule.src_type = SRC_INDEX;
998 cmd->body.rule.src.match_idx = MPLIST_INTEGER (elt);
1000 else if (MPLIST_PLIST_P (elt))
1002 MPlist *pl = MPLIST_PLIST (elt), *p;
1003 int size = MPLIST_LENGTH (pl);
1005 if (MPLIST_INTEGER_P (pl))
1009 cmd->body.rule.src_type = SRC_SEQ;
1010 cmd->body.rule.src.seq.n_codes = size;
1011 MTABLE_CALLOC (cmd->body.rule.src.seq.codes, size,
1013 for (i = 0; i < size; i++, pl = MPLIST_NEXT (pl))
1015 if (! MPLIST_INTEGER_P (pl))
1016 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1017 cmd->body.rule.src.seq.codes[i]
1018 = (unsigned) MPLIST_INTEGER (pl);
1021 else if (MPLIST_SYMBOL_P (pl))
1023 if (MPLIST_SYMBOL (pl) == Mrange)
1026 MERROR (MERROR_FLT, INVALID_CMD_ID);
1027 cmd->body.rule.src_type = SRC_RANGE;
1028 pl = MPLIST_NEXT (pl);
1029 if (! MPLIST_INTEGER_P (pl))
1030 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1031 cmd->body.rule.src.range.from
1032 = (unsigned) MPLIST_INTEGER (pl);
1033 pl = MPLIST_NEXT (pl);
1034 if (! MPLIST_INTEGER_P (pl))
1035 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1036 cmd->body.rule.src.range.to
1037 = (unsigned) MPLIST_INTEGER (pl);
1039 else if (MPLIST_SYMBOL (pl) == Mfont_facility)
1041 FontLayoutCmdRule *rule = &cmd->body.rule;
1043 pl = MPLIST_NEXT (pl);
1044 if (MPLIST_SYMBOL_P (pl))
1046 MSymbol sym = MPLIST_SYMBOL (pl);
1047 char *otf_spec = MSYMBOL_NAME (sym);
1049 if (otf_spec[0] == ':' && otf_spec[1] == 'o'
1050 && otf_spec[2] == 't' && otf_spec[3] == 'f')
1051 parse_otf_command (sym, &rule->src.facility.otf_spec);
1053 MERROR (MERROR_FLT, INVALID_CMD_ID);
1054 rule->src_type = SRC_OTF_SPEC;
1055 pl = MPLIST_NEXT (pl);
1057 else if (MPLIST_TAIL_P (pl))
1058 MERROR (MERROR_FLT, INVALID_CMD_ID);
1060 rule->src_type = SRC_HAS_GLYPH;
1061 rule->src.facility.len = 0;
1064 if (! MPLIST_INTEGER_P (p)
1065 && (MPLIST_SYMBOL_P (p)
1066 ? MPLIST_SYMBOL (p) != Mequal
1068 MERROR (MERROR_FLT, INVALID_CMD_ID);
1069 rule->src.facility.len++;
1071 rule->src.facility.codes = pl;
1072 M17N_OBJECT_REF (pl);
1076 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1079 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1081 elt = MPLIST_NEXT (elt);
1082 cmd->body.rule.n_cmds = len;
1083 MTABLE_CALLOC (cmd->body.rule.cmd_ids, len, MERROR_DRAW);
1084 for (i = 0; i < len; i++, elt = MPLIST_NEXT (elt))
1086 int this_id = load_command (stage, elt, macros, INVALID_CMD_ID);
1088 if (this_id == INVALID_CMD_ID || this_id == -2)
1089 MERROR (MERROR_DRAW, this_id);
1090 /* The above load_command may relocate stage->cmds. */
1091 cmd = stage->cmds + CMD_ID_TO_INDEX (id);
1092 cmd->body.rule.cmd_ids[i] = this_id;
1096 else if (MPLIST_SYMBOL_P (plist))
1099 MSymbol sym = MPLIST_SYMBOL (plist);
1100 char *name = msymbol_name (sym);
1101 int len = strlen (name);
1105 && ((name[0] == 'o' && name[1] == 't'
1106 && name[2] == 'f' && name[3] == ':')
1107 || (name[0] == ':' && name[1] == 'o' && name[2] == 't'
1108 && name[3] == 'f' && name[4] == '=')))
1110 result = load_otf_command (&cmd, sym);
1113 if (id == INVALID_CMD_ID)
1115 id = INDEX_TO_CMD_ID (stage->used);
1116 MLIST_APPEND1 (stage, cmds, cmd, MERROR_DRAW);
1119 stage->cmds[CMD_ID_TO_INDEX (id)] = cmd;
1127 else if (*name == '*')
1128 return CMD_ID_REPEAT;
1129 else if (*name == '<')
1130 return CMD_ID_CLUSTER_BEGIN;
1131 else if (*name == '>')
1132 return CMD_ID_CLUSTER_END;
1133 else if (*name == '|')
1134 return CMD_ID_SEPARATOR;
1135 else if (*name == '[')
1136 return CMD_ID_LEFT_PADDING;
1137 else if (*name == ']')
1138 return CMD_ID_RIGHT_PADDING;
1144 id = get_combining_command (sym);
1150 MPLIST_DO (elt, macros)
1152 if (sym == MPLIST_SYMBOL (MPLIST_PLIST (elt)))
1154 id = INDEX_TO_CMD_ID (i);
1155 if (stage->cmds[i].type == FontLayoutCmdTypeMAX)
1156 id = load_command (stage, MPLIST_NEXT (MPLIST_PLIST (elt)),
1162 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1165 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1171 free_flt_command (FontLayoutCmd *cmd)
1173 if (cmd->type == FontLayoutCmdTypeRule)
1175 FontLayoutCmdRule *rule = &cmd->body.rule;
1177 if (rule->src_type == SRC_REGEX)
1179 free (rule->src.re.pattern);
1180 regfree (&rule->src.re.preg);
1182 else if (rule->src_type == SRC_SEQ)
1183 free (rule->src.seq.codes);
1184 free (rule->cmd_ids);
1186 else if (cmd->type == FontLayoutCmdTypeCond)
1187 free (cmd->body.cond.cmd_ids);
1188 else if (cmd->type == FontLayoutCmdTypeOTF)
1190 if (cmd->body.otf.features[0])
1191 free (cmd->body.otf.features[0]);
1192 if (cmd->body.otf.features[1])
1193 free (cmd->body.otf.features[1]);
1197 /* Load a generator from PLIST into a newly allocated FontLayoutStage,
1198 and return it. PLIST has this form:
1199 PLIST ::= ( COMMAND ( CMD-NAME COMMAND ) * )
1202 static FontLayoutStage *
1203 load_generator (MPlist *plist)
1205 FontLayoutStage *stage;
1207 FontLayoutCmd dummy;
1210 MSTRUCT_CALLOC (stage, MERROR_DRAW);
1211 MLIST_INIT1 (stage, cmds, 32);
1212 dummy.type = FontLayoutCmdTypeMAX;
1213 MLIST_APPEND1 (stage, cmds, dummy, MERROR_FONT);
1214 MPLIST_DO (elt, MPLIST_NEXT (plist))
1216 if (! MPLIST_PLIST_P (elt))
1217 MERROR (MERROR_FONT, NULL);
1218 pl = MPLIST_PLIST (elt);
1219 if (! MPLIST_SYMBOL_P (pl))
1220 MERROR (MERROR_FONT, NULL);
1221 MLIST_APPEND1 (stage, cmds, dummy, MERROR_FONT);
1224 /* Load the first command from PLIST into STAGE->cmds[0]. Macros
1225 called in the first command are also loaded from MPLIST_NEXT
1226 (PLIST) into STAGE->cmds[n]. */
1227 result = load_command (stage, plist, MPLIST_NEXT (plist),
1228 INDEX_TO_CMD_ID (0));
1229 if (result == INVALID_CMD_ID || result == -2)
1231 MLIST_FREE1 (stage, cmds);
1240 /* Load stages of the font layout table FLT. */
1243 load_flt (MFLT *flt, MPlist *key_list)
1245 MPlist *top, *plist, *pl, *p;
1246 FontLayoutCategory *category = NULL;
1250 top = (MPlist *) mdatabase__load_for_keys (flt->mdb, key_list);
1252 top = (MPlist *) mdatabase_load (flt->mdb);
1255 if (! MPLIST_PLIST_P (top))
1257 M17N_OBJECT_UNREF (top);
1258 MERROR (MERROR_FLT, -1);
1263 plist = mdatabase__props (flt->mdb);
1265 MERROR (MERROR_FLT, -1);
1266 MPLIST_DO (plist, plist)
1267 if (MPLIST_PLIST_P (plist))
1269 pl = MPLIST_PLIST (plist);
1270 if (! MPLIST_SYMBOL_P (pl)
1271 || MPLIST_SYMBOL (pl) != Mfont)
1273 pl = MPLIST_NEXT (pl);
1274 if (! MPLIST_PLIST_P (pl))
1276 p = MPLIST_PLIST (pl);
1277 if (! MPLIST_SYMBOL_P (p))
1279 p = MPLIST_NEXT (p);
1280 if (! MPLIST_SYMBOL_P (p))
1282 flt->family = MPLIST_SYMBOL (p);
1283 MPLIST_DO (p, MPLIST_NEXT (p))
1284 if (MPLIST_SYMBOL_P (p))
1286 sym = MPLIST_SYMBOL (p);
1287 if (MSYMBOL_NAME (sym)[0] != ':')
1288 flt->registry = sym, sym = Mnil;
1294 char *otf_spec = MSYMBOL_NAME (sym);
1296 if (otf_spec[0] == ':' && otf_spec[1] == 'o'
1297 && otf_spec[2] == 't' && otf_spec[3] == 'f')
1298 parse_otf_command (sym, &flt->otf);
1303 MPLIST_DO (plist, top)
1305 if (MPLIST_SYMBOL_P (plist)
1306 && MPLIST_SYMBOL (plist) == Mend)
1308 mplist_set (plist, Mnil, NULL);
1311 if (! MPLIST_PLIST (plist))
1313 pl = MPLIST_PLIST (plist);
1314 if (! MPLIST_SYMBOL_P (pl))
1316 sym = MPLIST_SYMBOL (pl);
1317 pl = MPLIST_NEXT (pl);
1320 if (sym == Mcategory)
1323 unref_category_table (category);
1324 else if (flt->coverage)
1326 category = flt->coverage;
1327 ref_category_table (category);
1330 category = load_category_table (pl, NULL);
1331 if (! flt->coverage)
1333 flt->coverage = category;
1334 ref_category_table (category);
1336 if (category->definition)
1337 flt->need_config = 1;
1339 else if (sym == Mgenerator)
1341 FontLayoutStage *stage;
1345 stage = load_generator (pl);
1348 stage->category = category;
1349 M17N_OBJECT_REF (category->table);
1351 flt->stages = mplist ();
1352 mplist_add (flt->stages, Mt, stage);
1356 unref_category_table (category);
1358 if (! MPLIST_TAIL_P (plist))
1360 M17N_OBJECT_UNREF (top);
1361 M17N_OBJECT_UNREF (flt->stages);
1362 MERROR (MERROR_FLT, -1);
1364 M17N_OBJECT_UNREF (top);
1370 free_flt_stage (MFLT *flt, FontLayoutStage *stage)
1374 unref_category_table (stage->category);
1377 for (i = 0; i < stage->used; i++)
1378 free_flt_command (stage->cmds + i);
1379 MLIST_FREE1 (stage, cmds);
1391 MPLIST_DO (plist, flt_list)
1393 MFLT *flt = MPLIST_VAL (plist);
1396 unref_category_table (flt->coverage);
1399 MPLIST_DO (pl, MPLIST_NEXT (flt->stages))
1400 free_flt_stage (flt, MPLIST_VAL (pl));
1401 M17N_OBJECT_UNREF (flt->stages);
1404 MPLIST_VAL (plist) = NULL;
1406 M17N_OBJECT_UNREF (flt_list);
1413 MPlist *plist, *key_list = NULL;
1417 if (! (plist = mdatabase_list (Mfont, Mlayouter, Mnil, Mnil)))
1419 if (! (flt_list = mplist ()))
1421 if (! (key_list = mplist ()))
1423 if (! mplist_add (key_list, Mcategory, Mt))
1426 MPLIST_DO (pl, plist)
1428 MDatabase *mdb = MPLIST_VAL (pl);
1429 MSymbol *tags = mdatabase_tag (mdb);
1432 if (! MSTRUCT_CALLOC_SAFE (flt))
1434 flt->name = tags[2];
1436 if (load_flt (flt, key_list) < 0)
1440 if (MPLIST_TAIL_P (flt_list))
1442 flt_min_coverage = mchartable_min_char (flt->coverage->table);
1443 flt_max_coverage = mchartable_max_char (flt->coverage->table);
1449 c = mchartable_min_char (flt->coverage->table);
1450 if (flt_min_coverage > c)
1451 flt_min_coverage = c;
1452 c = mchartable_max_char (flt->coverage->table);
1453 if (flt_max_coverage < c)
1454 flt_max_coverage = c;
1456 if (! mplist_push (flt_list, flt->name, flt))
1466 M17N_OBJECT_UNREF (plist);
1467 M17N_OBJECT_UNREF (key_list);
1471 /* FLS (Font Layout Service) */
1473 /* Structure to hold information about a context of FLS. */
1477 /* Pointer to the current stage. */
1478 FontLayoutStage *stage;
1480 /* Pointer to the font. */
1483 /* Input and output glyph string. */
1484 MFLTGlyphString *in, *out;
1486 /* Encode each character or code of a glyph by the current category
1487 table into this array. An element is a category letter used for
1488 a regular expression matching. */
1493 int cluster_begin_idx;
1494 int cluster_begin_pos;
1495 int cluster_end_pos;
1499 } FontLayoutContext;
1501 static int run_command (int, int, int, int, FontLayoutContext *);
1506 run_rule (int depth,
1507 FontLayoutCmdRule *rule, int from, int to, FontLayoutContext *ctx)
1509 int *saved_match_indices = ctx->match_indices;
1510 int match_indices[NMATCH * 2];
1513 int orig_from = from;
1514 int need_cluster_update = 0;
1516 if (rule->src_type == SRC_REGEX)
1518 regmatch_t pmatch[NMATCH];
1524 saved_code = ctx->encoded[to - ctx->encoded_offset];
1525 ctx->encoded[to - ctx->encoded_offset] = '\0';
1526 result = regexec (&(rule->src.re.preg),
1527 ctx->encoded + (from - ctx->encoded_offset),
1529 if (result == 0 && pmatch[0].rm_so == 0)
1531 if (MDEBUG_FLAG () > 2)
1532 MDEBUG_PRINT5 ("\n [FLT] %*s(REGEX \"%s\" \"%s\" %d", depth, "",
1533 rule->src.re.pattern,
1534 ctx->encoded + (from - ctx->encoded_offset),
1536 ctx->encoded[to - ctx->encoded_offset] = saved_code;
1537 for (i = 0; i < NMATCH; i++)
1539 if (pmatch[i].rm_so < 0)
1540 match_indices[i * 2] = match_indices[i * 2 + 1] = -1;
1543 match_indices[i * 2] = from + pmatch[i].rm_so;
1544 match_indices[i * 2 + 1] = from + pmatch[i].rm_eo;
1547 ctx->match_indices = match_indices;
1548 to = match_indices[1];
1552 ctx->encoded[to - ctx->encoded_offset] = saved_code;
1555 need_cluster_update = 1;
1557 else if (rule->src_type == SRC_SEQ)
1561 len = rule->src.seq.n_codes;
1562 if (len > (to - from))
1564 for (i = 0; i < len; i++)
1565 if (rule->src.seq.codes[i] != GREF (ctx->in, from + i)->code)
1570 if (MDEBUG_FLAG () > 2)
1571 MDEBUG_PRINT3 ("\n [FLT] %*s(SEQ 0x%X", depth, "",
1572 rule->src.seq.codes[0]);
1573 need_cluster_update = 1;
1575 else if (rule->src_type == SRC_RANGE)
1581 head = GREF (ctx->in, from)->code;
1582 if (head < rule->src.range.from || head > rule->src.range.to)
1584 ctx->code_offset = head - rule->src.range.from;
1586 if (MDEBUG_FLAG () > 2)
1587 MDEBUG_PRINT4 ("\n [FLT] %*s(RANGE 0x%X-0x%X", depth, "",
1588 rule->src.range.from, rule->src.range.to);
1589 need_cluster_update = 1;
1591 else if (rule->src_type == SRC_INDEX)
1593 if (rule->src.match_idx >= NMATCH)
1595 from = ctx->match_indices[rule->src.match_idx * 2];
1598 to = ctx->match_indices[rule->src.match_idx * 2 + 1];
1599 if (MDEBUG_FLAG () > 2)
1600 MDEBUG_PRINT3 ("\n [FLT] %*s(SUBPART %d", depth, "",
1601 rule->src.match_idx);
1602 need_cluster_update = 1;
1604 else if (rule->src_type == SRC_HAS_GLYPH
1605 || rule->src_type == SRC_OTF_SPEC)
1607 static MFLTGlyphString gstring;
1611 if (rule->src.facility.len > 0)
1613 if (! gstring.glyph_size)
1615 gstring.glyph_size = ctx->in->glyph_size;
1616 gstring.glyphs = calloc (rule->src.facility.len,
1617 gstring.glyph_size);
1618 gstring.allocated = rule->src.facility.len;
1619 gstring.used = rule->src.facility.len;
1621 else if (rule->src.facility.len < gstring.allocated)
1623 gstring.glyphs = realloc (gstring.glyphs,
1625 * rule->src.facility.len);
1626 gstring.allocated = rule->src.facility.len;
1627 gstring.used = rule->src.facility.len;
1630 for (i = 0, p = rule->src.facility.codes, idx = from;
1631 i < rule->src.facility.len; i++, p = MPLIST_NEXT (p))
1633 if (MPLIST_INTEGER_P (p))
1635 GREF (&gstring, i)->code = MPLIST_INTEGER (p);
1636 GREF (&gstring, i)->encoded = 0;
1640 GREF (&gstring, i)->code = GREF (ctx->in, idx)->code;
1641 GREF (&gstring, i)->encoded = GREF (ctx->in, idx)->encoded;
1647 if (MDEBUG_FLAG () > 2)
1649 if (rule->src_type == SRC_HAS_GLYPH)
1650 MDEBUG_PRINT2 ("\n [FLT] %*s(HAS-GLYPH", depth, "");
1652 MDEBUG_PRINT2 ("\n [FLT] %*s(OTF-SPEC", depth, "");
1653 for (i = 0; i < rule->src.facility.len; i++)
1654 MDEBUG_PRINT1 (" %04X", GREF (&gstring, i)->code);
1656 if (ctx->font->get_glyph_id (ctx->font, &gstring, 0,
1657 rule->src.facility.len) < 0)
1659 MDEBUG_PRINT (") FAIL!");
1662 if (rule->src_type == SRC_OTF_SPEC)
1664 MFLTOtfSpec *spec = &rule->src.facility.otf_spec;
1666 if (! ctx->font->check_otf)
1668 if ((spec->features[0] && spec->features[0][0] != 0xFFFFFFFF)
1669 || (spec->features[1] && spec->features[1][0] != 0xFFFFFFFF))
1674 if (rule->src.facility.len == 0)
1676 if (! ctx->font->check_otf (ctx->font, spec))
1681 int prev_out_used = ctx->out->used, out_used;
1682 MFLTGlyphAdjustment *adjustment;
1684 adjustment = alloca ((sizeof *adjustment)
1685 * (ctx->out->allocated - ctx->out->used));
1687 MERROR (MERROR_FLT, -1);
1688 memset (adjustment, 0,
1689 (sizeof *adjustment)
1690 * (ctx->out->allocated - ctx->out->used));
1691 ctx->font->drive_otf (ctx->font, &rule->src.facility.otf_spec,
1692 &gstring, 0, rule->src.facility.len,
1695 out_used = ctx->out->used;
1696 ctx->out->used = prev_out_used;
1697 if (rule->src.facility.len == out_used - prev_out_used)
1699 for (i = prev_out_used; i < out_used; i++)
1701 if (GREF (&gstring, i - prev_out_used)->code
1702 != GREF (ctx->out, i)->code)
1704 if (adjustment[i - prev_out_used].set)
1715 if (need_cluster_update && ctx->cluster_begin_idx >= 0)
1717 for (i = from; i < to; i++)
1719 MFLTGlyph *g = GREF (ctx->in, i);
1720 UPDATE_CLUSTER_RANGE (ctx, g);
1726 for (i = 0; i < rule->n_cmds; i++)
1730 if (rule->cmd_ids[i] == CMD_ID_REPEAT)
1736 pos = run_command (depth, rule->cmd_ids[i], from, to, ctx);
1739 consumed = pos > from;
1744 ctx->match_indices = saved_match_indices;
1745 if (MDEBUG_FLAG () > 2)
1747 return (rule->src_type == SRC_INDEX ? orig_from : to);
1751 run_cond (int depth,
1752 FontLayoutCmdCond *cond, int from, int to, FontLayoutContext *ctx)
1756 if (MDEBUG_FLAG () > 2)
1757 MDEBUG_PRINT2 ("\n [FLT] %*s(COND", depth, "");
1759 for (i = 0; i < cond->n_cmds; i++)
1761 /* TODO: Write a code for optimization utilizaing the info
1763 if ((pos = run_command (depth, cond->cmd_ids[i], from, to, ctx))
1769 if (MDEBUG_FLAG () > 2)
1776 MFLTOtfSpec *otf_spec, int from, int to, FontLayoutContext *ctx)
1778 MFLTFont *font = ctx->font;
1779 int from_idx = ctx->out->used;
1781 if (MDEBUG_FLAG () > 2)
1782 MDEBUG_PRINT3 ("\n [FLT] %*s%s", depth, "", MSYMBOL_NAME (otf_spec->sym));
1784 font->get_glyph_id (font, ctx->in, from, to);
1785 if (! font->drive_otf)
1787 if (ctx->out->used + (to - from) > ctx->out->allocated)
1789 font->get_metrics (font, ctx->in, from, to);
1790 GCPY (ctx->in, from, to - from, ctx->out, ctx->out->used);
1791 ctx->out->used += to - from;
1795 MFLTGlyphAdjustment *adjustment;
1799 adjustment = alloca ((sizeof *adjustment)
1800 * (ctx->out->allocated - ctx->out->used));
1802 MERROR (MERROR_FLT, -1);
1803 memset (adjustment, 0,
1804 (sizeof *adjustment) * (ctx->out->allocated - ctx->out->used));
1805 to = font->drive_otf (font, otf_spec, ctx->in, from, to, ctx->out,
1809 out_len = ctx->out->used - from_idx;
1810 if (otf_spec->features[1])
1812 MFLTGlyphAdjustment *a;
1815 for (i = 0, a = adjustment; i < out_len; i++, a++)
1820 font->get_metrics (font, ctx->out, from_idx, ctx->out->used);
1821 for (g = GREF (ctx->out, from_idx + i);
1822 i < out_len; i++, a++, g = NEXT (ctx->out, g))
1825 if (a->advance_is_absolute)
1830 else if (a->xadv || a->yadv)
1835 if (a->xoff || a->yoff || a->back)
1838 MFLTGlyph *gg = PREV (ctx->out, g);
1839 MFLTGlyphAdjustment *aa = a;
1843 while (aa->back > 0)
1845 for (j = 0; j < aa->back;
1846 j++, gg = PREV (ctx->out, gg))
1848 g->xoff -= gg->xadv;
1849 g->lbearing -= gg->xadv;
1850 g->rbearing -= gg->xadv;
1853 g->xoff += aa->xoff;
1854 g->yoff += aa->yoff;
1855 g->lbearing += aa->xoff;
1856 g->rbearing += aa->xoff;
1857 g->ascent -= aa->yoff;
1858 g->descent -= aa->yoff;
1861 SET_COMBINING_CODE (g, ctx, 0);
1868 if (ctx->cluster_begin_idx >= 0)
1869 for (; from_idx < ctx->out->used; from_idx++)
1871 MFLTGlyph *g = GREF (ctx->out, from_idx);
1872 UPDATE_CLUSTER_RANGE (ctx, g);
1877 static char work[16];
1880 dump_combining_code (int code)
1882 char *vallign = "tcbB";
1883 char *hallign = "lcr";
1889 work[0] = vallign[COMBINING_CODE_BASE_Y (code)];
1890 work[1] = hallign[COMBINING_CODE_BASE_X (code)];
1891 off_y = COMBINING_CODE_OFF_Y (code);
1892 off_x = COMBINING_CODE_OFF_X (code);
1894 sprintf (work + 2, "+%d", off_y);
1896 sprintf (work + 2, "%d", off_y);
1897 else if (off_x == 0)
1898 sprintf (work + 2, ".");
1899 p = work + strlen (work);
1901 sprintf (p, ">%d", off_x);
1903 sprintf (p, "<%d", -off_x);
1905 p[0] = vallign[COMBINING_CODE_ADD_Y (code)];
1906 p[1] = hallign[COMBINING_CODE_ADD_X (code)];
1912 run_command (int depth, int id, int from, int to, FontLayoutContext *ctx)
1920 /* Direct code (== ctx->code_offset + id) output.
1921 The source is not consumed. */
1922 if (MDEBUG_FLAG () > 2)
1923 MDEBUG_PRINT3 ("\n [FLT] %*s(DIRECT 0x%X", depth, "",
1924 ctx->code_offset + id);
1925 i = (from < to || from == 0) ? from : from - 1;
1927 g = GREF (ctx->out, ctx->out->used - 1);
1928 g->c = g->code = ctx->code_offset + id;
1930 SET_MEASURED (g, 0);
1931 if (ctx->combining_code)
1932 SET_COMBINING_CODE (g, ctx, ctx->combining_code);
1933 if (ctx->left_padding)
1934 SET_LEFT_PADDING (g, ctx, LeftPaddingMask);
1935 for (i = from; i < to; i++)
1937 MFLTGlyph *tmp = GREF (ctx->in, i);
1939 if (g->from > tmp->from)
1940 g->from = tmp->from;
1941 else if (g->to < tmp->to)
1944 if (ctx->cluster_begin_idx >= 0)
1945 UPDATE_CLUSTER_RANGE (ctx, g);
1946 ctx->code_offset = ctx->combining_code = ctx->left_padding = 0;
1947 if (MDEBUG_FLAG () > 2)
1952 if (id <= CMD_ID_OFFSET_INDEX)
1954 int idx = CMD_ID_TO_INDEX (id);
1957 if (idx >= ctx->stage->used)
1958 MERROR (MERROR_DRAW, -1);
1959 cmd = ctx->stage->cmds + idx;
1960 if (cmd->type == FontLayoutCmdTypeRule)
1961 to = run_rule (depth, &cmd->body.rule, from, to, ctx);
1962 else if (cmd->type == FontLayoutCmdTypeCond)
1963 to = run_cond (depth, &cmd->body.cond, from, to, ctx);
1964 else if (cmd->type == FontLayoutCmdTypeOTF)
1965 to = run_otf (depth, &cmd->body.otf, from, to, ctx);
1969 if (id <= CMD_ID_OFFSET_COMBINING)
1971 ctx->combining_code = CMD_ID_TO_COMBINING_CODE (id);
1972 if (MDEBUG_FLAG () > 2)
1973 MDEBUG_PRINT3 ("\n [FLT] %*s(CMB %s)", depth, "",
1974 dump_combining_code (ctx->combining_code));
1985 g = GREF (ctx->out, ctx->out->used - 1);
1986 if (ctx->combining_code)
1987 SET_COMBINING_CODE (g, ctx, ctx->combining_code);
1988 if (ctx->left_padding)
1989 SET_LEFT_PADDING (g, ctx, LeftPaddingMask);
1990 if (ctx->cluster_begin_idx >= 0)
1991 UPDATE_CLUSTER_RANGE (ctx, g);
1992 if (MDEBUG_FLAG () > 2)
1995 MDEBUG_PRINT2 ("\n [FLT] %*s(COPY |)", depth, "");
1997 MDEBUG_PRINT3 ("\n [FLT] %*s(COPY 0x%X)", depth, "", g->code);
1999 ctx->code_offset = ctx->combining_code = ctx->left_padding = 0;
2003 case CMD_ID_CLUSTER_BEGIN:
2004 if (ctx->cluster_begin_idx < 0)
2006 if (MDEBUG_FLAG () > 2)
2007 MDEBUG_PRINT3 ("\n [FLT] %*s<%d", depth, "",
2008 GREF (ctx->in, from)->from);
2009 ctx->cluster_begin_idx = ctx->out->used;
2010 ctx->cluster_begin_pos = GREF (ctx->in, from)->from;
2011 ctx->cluster_end_pos = GREF (ctx->in, from)->to;
2015 case CMD_ID_CLUSTER_END:
2016 if (ctx->cluster_begin_idx >= 0
2017 && ctx->cluster_begin_idx < ctx->out->used)
2021 if (MDEBUG_FLAG () > 2)
2022 MDEBUG_PRINT1 (" %d>", ctx->cluster_end_pos + 1);
2023 for (i = ctx->cluster_begin_idx; i < ctx->out->used; i++)
2025 GREF (ctx->out, i)->from = ctx->cluster_begin_pos;
2026 GREF (ctx->out, i)->to = ctx->cluster_end_pos;
2028 ctx->cluster_begin_idx = -1;
2032 case CMD_ID_SEPARATOR:
2036 i = from < to ? from : from - 1;
2038 g = GREF (ctx->out, ctx->out->used - 1);
2039 g->c = -1, g->code = 0;
2040 g->xadv = g->yadv = 0;
2042 SET_MEASURED (g, 0);
2046 case CMD_ID_LEFT_PADDING:
2047 if (MDEBUG_FLAG () > 2)
2048 MDEBUG_PRINT2 ("\n [FLT] %*s[", depth, "");
2049 ctx->left_padding = 1;
2052 case CMD_ID_RIGHT_PADDING:
2053 if (ctx->out->used > 0)
2055 if (MDEBUG_FLAG () > 2)
2056 MDEBUG_PRINT2 ("\n [FLT] %*s]", depth, "");
2057 g = GREF (ctx->out, ctx->out->used - 1);
2058 SET_RIGHT_PADDING (g, ctx, RightPaddingMask);
2063 MERROR (MERROR_DRAW, -1);
2067 run_stages (MFLTGlyphString *gstring, int from, int to,
2068 MFLT *flt, FontLayoutContext *ctx)
2070 MFLTGlyphString buf, *temp;
2072 int orig_from = from, orig_to = to;
2073 int from_pos, to_pos, len;
2076 MPlist *stages = flt->stages;
2078 from_pos = GREF (ctx->in, from)->from;
2079 to_pos = GREF (ctx->in, to - 1)->to;
2080 len = to_pos - from_pos;
2084 GINIT (ctx->out, ctx->out->allocated);
2085 ctx->encoded = alloca (ctx->out->allocated);
2086 if (! ctx->out->glyphs || ! ctx->encoded)
2089 for (stage_idx = 0; 1; stage_idx++)
2094 ctx->stage = (FontLayoutStage *) MPLIST_VAL (stages);
2095 table = ctx->stage->category->table;
2096 ctx->code_offset = ctx->combining_code = ctx->left_padding = 0;
2097 ctx->encoded_offset = from;
2098 for (i = from; i < to; i++)
2100 MFLTGlyph *g = GREF (ctx->in, i);
2101 char enc = (GET_ENCODED (g)
2102 ? (g->c > 0 ? (int) mchartable_lookup (table, g->c) : 1)
2104 ? (int) mchartable_lookup (table, g->code)
2107 ctx->encoded[i - from] = enc;
2108 if (! enc && stage_idx == 0)
2114 ctx->encoded[i - from] = '\0';
2115 ctx->match_indices[0] = from;
2116 ctx->match_indices[1] = to;
2117 for (i = 2; i < NMATCH; i++)
2118 ctx->match_indices[i] = -1;
2120 if (MDEBUG_FLAG () > 2)
2122 MDEBUG_PRINT2 ("\n [FLT] (STAGE %d \"%s\"", stage_idx,
2124 MDEBUG_PRINT (" (");
2125 for (i = from; i < to; i++)
2127 g = GREF (ctx->in, i);
2129 MDEBUG_PRINT2 ("%*s|", (i > 0), "");
2131 MDEBUG_PRINT3 ("%*s%04X", (i > 0), "", GREF (ctx->in, i)->code);
2135 result = run_command (4, INDEX_TO_CMD_ID (0), from, to, ctx);
2136 if (MDEBUG_FLAG () > 2)
2141 stages = MPLIST_NEXT (stages);
2142 /* If this is the last stage, break the loop. */
2143 if (MPLIST_TAIL_P (stages))
2146 /* Otherwise, prepare for the next stage. */
2153 GINIT (&buf, ctx->out->allocated);
2162 if (ctx->out->used > 0)
2165 int x_ppem = ctx->font->x_ppem << 6, y_ppem = ctx->font->y_ppem << 6;
2167 /* Remove separator glyphs. */
2168 for (i = 0; i < ctx->out->used;)
2170 g = GREF (ctx->out, i);
2172 GREPLACE (NULL, 0, 0, ctx->out, i, i + 1);
2177 /* Get actual glyph IDs of glyphs. */
2178 ctx->font->get_glyph_id (ctx->font, ctx->out, 0, ctx->out->used);
2180 /* Check if all characters in the range are covered by some
2181 glyph(s). If not, change <from> and <to> of glyphs to cover
2182 uncovered characters. */
2183 g_indices = alloca (sizeof (int) * len);
2186 for (i = 0; i < len; i++) g_indices[i] = -1;
2187 for (i = 0; i < ctx->out->used; i++)
2191 g = GREF (ctx->out, i);
2192 for (pos = g->from; pos <= g->to; pos++)
2193 if (g_indices[pos - from_pos] < 0)
2194 g_indices[pos - from_pos] = i;
2196 for (i = 0; i < len; i++)
2197 if (g_indices[i] < 0)
2203 for (i++; i < len && g_indices[i] < 0; i++);
2205 g = GREF (ctx->out, j);
2206 this_from = g->from;
2208 g->from = orig_from + i;
2209 } while (++j < ctx->out->used
2210 && (g = GREF (ctx->out, j))
2211 && g->from == this_from);
2217 j = g_indices[i - 1];
2218 g = GREF (ctx->out, j);
2221 g->to = orig_from + i + 1;
2223 && (g = GREF (ctx->out, j))
2224 && g->to == this_to);
2228 ctx->font->get_metrics (ctx->font, ctx->out, 0, ctx->out->used);
2230 /* Handle combining. */
2231 if (ctx->check_mask & CombiningCodeMask)
2233 MFLTGlyph *base = GREF (ctx->out, 0);
2234 int base_height = base->ascent + base->descent;
2235 int base_width = base->rbearing - base->lbearing;
2238 for (i = 1; i < ctx->out->used; i++)
2240 if ((g = GREF (ctx->out, i))
2241 && (combining_code = GET_COMBINING_CODE (g)))
2243 int height = g->ascent + g->descent;
2244 int width = g->rbearing - g->lbearing;
2245 int base_x, base_y, add_x, add_y, off_x, off_y;
2247 if (base->from > g->from)
2248 base->from = g->from;
2249 else if (base->to < g->to)
2252 base_x = COMBINING_CODE_BASE_X (combining_code);
2253 base_y = COMBINING_CODE_BASE_Y (combining_code);
2254 add_x = COMBINING_CODE_ADD_X (combining_code);
2255 add_y = COMBINING_CODE_ADD_Y (combining_code);
2256 off_x = COMBINING_CODE_OFF_X (combining_code);
2257 off_y = COMBINING_CODE_OFF_Y (combining_code);
2259 g->xoff = ((base_width * base_x - width * add_x) / 2
2260 + x_ppem * off_x / 100
2261 - (base->xadv - base->lbearing) - g->lbearing);
2263 g->yoff = base_height * base_y / 2 - base->ascent;
2267 g->yoff -= height * add_y / 2 - g->ascent;
2268 g->yoff -= y_ppem * off_y / 100;
2269 if (base->lbearing > base->xadv + g->lbearing + g->xoff)
2270 base->lbearing = base->xadv + g->lbearing + g->xoff;
2271 if (base->rbearing < base->xadv + g->rbearing + g->xoff)
2272 base->rbearing = base->xadv + g->rbearing + g->xoff;
2273 if (base->ascent < g->ascent - g->yoff)
2274 base->ascent = g->ascent - g->yoff;
2275 if (base->descent < g->descent - g->yoff)
2276 base->descent = g->descent - g->yoff;
2277 g->xadv = g->yadv = 0;
2278 if (GET_RIGHT_PADDING (g))
2279 SET_RIGHT_PADDING (base, ctx, RightPaddingMask);
2285 base_height = g->ascent + g->descent;
2286 base_width = g->rbearing - g->lbearing;
2291 /* Handle padding */
2292 if (ctx->check_mask & (LeftPaddingMask | RightPaddingMask))
2293 for (i = 0; i < ctx->out->used; i++)
2295 g = GREF (ctx->out, i);
2296 if (! GET_COMBINING_CODE (g))
2298 if (GET_RIGHT_PADDING (g) && g->rbearing > g->xadv)
2300 g->xadv = g->rbearing;
2303 if (GET_LEFT_PADDING (g) && g->lbearing < 0)
2305 g->xoff += - g->lbearing;
2306 g->xadv += - g->lbearing;
2307 g->rbearing += - g->lbearing;
2315 GREPLACE (ctx->out, 0, ctx->out->used, gstring, orig_from, orig_to);
2316 to = orig_from + ctx->out->used;
2321 setup_combining_coverage (int from, int to, void *val, void *arg)
2323 int combining_class = (int) val;
2326 if (combining_class < 200)
2328 else if (combining_class <= 204)
2330 if ((combining_class % 2) == 0)
2331 category = "bcd"[(combining_class - 200) / 2];
2333 else if (combining_class <= 232)
2335 if ((combining_class % 2) == 0)
2336 category = "efghijklmnopq"[(combining_class - 208) / 2];
2338 else if (combining_class == 233)
2340 else if (combining_class == 234)
2342 else if (combining_class == 240)
2344 mchartable_set_range ((MCharTable *) arg, from, to, (void *) category);
2348 setup_combining_flt (MFLT *flt)
2351 MCharTable *combininig_class_table
2352 = mchar_get_prop_table (Mcombining_class, &type);
2354 mchartable_set_range (flt->coverage->table, 0, 0x10FFFF, (void *) 'u');
2355 if (combininig_class_table)
2356 mchartable_map (combininig_class_table, (void *) 0,
2357 setup_combining_coverage, flt->coverage->table);
2360 #define CHECK_FLT_STAGES(flt) ((flt)->stages || load_flt (flt, NULL) == 0)
2362 static FontLayoutCategory *
2363 configure_category (FontLayoutCategory *category, MFLTFont *font)
2365 if (! mflt_font_id || ! mflt_iterate_otf_feature)
2367 FontLayoutCategory *new = malloc (sizeof (FontLayoutCategory));
2368 new->definition = NULL;
2369 new->table = category->table;
2370 M17N_OBJECT_REF (new->table);
2373 return load_category_table (category->definition, font);
2377 configure_flt (MFLT *flt, MFLTFont *font, MSymbol font_id)
2382 if (! mflt_font_id || ! mflt_iterate_otf_feature)
2384 MPLIST_DO (plist, flt_list)
2386 configured = MPLIST_VAL (plist);
2387 if (! configured->font_id)
2389 if (configured->name == flt->name
2390 && configured->font_id == font_id)
2393 if (! MSTRUCT_CALLOC_SAFE (configured))
2396 configured->stages = mplist_copy (flt->stages);
2397 MPLIST_DO (plist, configured->stages)
2399 FontLayoutStage *stage = MPLIST_VAL (plist);
2400 if (stage->category->definition)
2402 MSTRUCT_CALLOC (stage, MERROR_FLT);
2403 *stage = *((FontLayoutStage *) MPLIST_VAL (plist));
2404 stage->category = configure_category (stage->category, font);
2405 MPLIST_VAL (plist) = stage;
2408 M17N_OBJECT_REF (stage->category->table);
2410 configured->need_config = 0;
2411 configured->font_id = font_id;
2412 mplist_push (flt_list, flt->name, configured);
2418 int m17n__flt_initialized;
2423 /* The following two are actually not exposed to a user but concealed
2424 by the macro M17N_INIT (). */
2427 m17n_init_flt (void)
2429 int mdebug_flag = MDEBUG_INIT;
2431 merror_code = MERROR_NONE;
2432 if (m17n__flt_initialized++)
2435 if (merror_code != MERROR_NONE)
2437 m17n__flt_initialized--;
2441 MDEBUG_PUSH_TIME ();
2443 Mcond = msymbol ("cond");
2444 Mrange = msymbol ("range");
2445 Mfont = msymbol ("font");
2446 Mlayouter = msymbol ("layouter");
2447 Mcombining = msymbol ("combining");
2448 Mfont_facility = msymbol ("font-facility");
2449 Mequal = msymbol ("=");
2450 Mgenerator = msymbol ("generator");
2451 Mend = msymbol ("end");
2453 mflt_iterate_otf_feature = NULL;
2454 mflt_font_id = NULL;
2456 MDEBUG_PRINT_TIME ("INIT", (stderr, " to initialize the flt modules."));
2461 m17n_fini_flt (void)
2463 int mdebug_flag = MDEBUG_FINI;
2465 if (m17n__flt_initialized == 0
2466 || --m17n__flt_initialized > 0)
2469 MDEBUG_PUSH_TIME ();
2471 MDEBUG_PRINT_TIME ("FINI", (stderr, " to finalize the flt modules."));
2477 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
2479 /*** @addtogroup m17nFLT */
2485 @brief Return an FLT object that has a specified name.
2487 The mflt_get () function returns an FLT object whose name is $NAME.
2490 If the operation was successful, mflt_get () returns a pointer
2491 to the found FLT object. Otherwise, it returns @c NULL. */
2494 @brief »ØÄꤵ¤ì¤¿Ì¾Á°¤ò»ý¤Ä FLT ¥ª¥Ö¥¸¥§¥¯¥È¤òÊÖ¤¹.
2496 ´Ø¿ô mflt_get () ¤Ï¡¢$NAME ¤È¤¤¤¦Ì¾Á°¤ò»ý¤Ä FLT ¥ª¥Ö¥¸¥§¥¯¥È¤òÊÖ¤¹¡£
2499 ¤â¤·À®¸ù¤¹¤ì¤Ð¡¢mflt_get () ¤Ï¸«¤Ä¤«¤Ã¤¿ FLT
2500 ¥ª¥Ö¥¸¥§¥¯¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¼ºÇÔ¤·¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤¹¡£ */
2503 mflt_get (MSymbol name)
2508 if (! flt_list && list_flt () < 0)
2510 for (plist = flt_list; plist; plist = plist->next)
2511 if (((MFLT *) MPLIST_VAL (plist))->font_id == Mnil)
2513 flt = mplist_get (plist, name);
2514 if (! flt || ! CHECK_FLT_STAGES (flt))
2516 if (flt->name == Mcombining
2517 && ! mchartable_lookup (flt->coverage->table, 0))
2518 setup_combining_flt (flt);
2525 @brief Find an FLT suitable for the specified character and font.
2527 The mflt_find () function returns the most appropriate FLT for
2528 layouting character $C with font $FONT.
2531 If the operation was successful, mflt_find () returns a pointer
2532 to the found FLT object. Otherwise, it returns @c NULL. */
2535 @brief »ØÄꤵ¤ì¤¿Ê¸»ú¤È¥Õ¥©¥ó¥È¤Ë¹ç¤Ã¤¿ FLT ¤òõ¤¹.
2537 ´Ø¿ô mflt_find () ¤Ï¡¢Ê¸»ú $C ¤ò¥Õ¥©¥ó¥È $FONT
2538 ¤Ç¥ì¥¤¥¢¥¦¥È¤¹¤ë¤¿¤á¤ËºÇ¤âŬÀÚ¤Ê FLT ¤òÊÖ¤¹¡£
2541 ¤â¤·À®¸ù¤¹¤ì¤Ð¡¢mflt_find () ¤Ï¸«¤Ä¤«¤Ã¤¿ FLT
2542 ¥ª¥Ö¥¸¥§¥¯¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¼ºÇÔ¤·¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤¹¡£ */
2545 mflt_find (int c, MFLTFont *font)
2549 static MSymbol unicode_bmp = NULL, unicode_full = NULL;
2553 unicode_bmp = msymbol ("unicode-bmp");
2554 unicode_full = msymbol ("unicode-full");
2557 if (! flt_list && list_flt () < 0)
2559 /* Skip configured FLTs. */
2560 MPLIST_DO (plist, flt_list)
2561 if (((MFLT *) MPLIST_VAL (plist))->font_id == Mnil)
2567 MPLIST_DO (pl, plist)
2569 flt = MPLIST_VAL (pl);
2570 if (flt->registry != unicode_bmp
2571 && flt->registry != unicode_full)
2573 if (flt->family && flt->family != font->family)
2575 if (flt->name == Mcombining
2576 && ! mchartable_lookup (flt->coverage->table, 0))
2577 setup_combining_flt (flt);
2579 && ! mchartable_lookup (flt->coverage->table, c))
2583 MFLTOtfSpec *spec = &flt->otf;
2585 if (! font->check_otf)
2587 if ((spec->features[0] && spec->features[0][0] != 0xFFFFFFFF)
2588 || (spec->features[1] && spec->features[1][0] != 0xFFFFFFFF))
2591 else if (! font->check_otf (font, spec))
2602 MPLIST_DO (pl, plist)
2604 flt = MPLIST_VAL (pl);
2605 if (mchartable_lookup (flt->coverage->table, c))
2612 if (! CHECK_FLT_STAGES (flt))
2614 if (font && flt->need_config)
2615 flt = configure_flt (flt, font, mflt_font_id (font));
2621 @brief Return the name of an FLT.
2623 The mflt_name () function returns the name of $FLT. */
2626 @brief FLT ¤Î̾Á°¤òÊÖ¤¹.
2628 ´Ø¿ô mflt_name () ¤Ï $FLT ¤Î̾Á°¤òÊÖ¤¹¡£ */
2631 mflt_name (MFLT *flt)
2633 return MSYMBOL_NAME (flt->name);
2638 @brief Return a coverage of a FLT.
2640 The mflt_coverage () function returns a char-table that contains
2641 nonzero values for characters supported by $FLT. */
2644 @brief FLT ¤ÎÈϰϤòÊÖ¤¹.
2646 ´Ø¿ô mflt_coverage () ¤Ï¡¢$FLT ¤¬¥µ¥Ý¡¼¥È¤¹¤ëʸ»ú¤ËÂФ·¤Æ
2647 0 ¤Ç¤Ê¤¤Ãͤò´Þ¤àʸ»ú¥Æ¡¼¥Ö¥ë¤òÊÖ¤¹¡£ */
2650 mflt_coverage (MFLT *flt)
2652 return flt->coverage->table;
2657 @brief Layout characters with an FLT.
2659 The mflt_run () function layouts characters in $GSTRING between
2660 $FROM (inclusive) and $TO (exclusive) with $FONT. If $FLT is
2661 nonzero, it is used for all the charaters. Otherwise, appropriate
2662 FLTs are automatically chosen.
2665 The operation was successful. The value is the index to the
2666 glyph, which was previously indexed by $TO, in $GSTRING->glyphs.
2669 $GSTRING->glyphs is too short to store the result. The caller can
2670 call this fucntion again with a longer $GSTRING->glyphs.
2673 Some other error occurred. */
2676 @brief FLT ¤ò»È¤Ã¤Æʸ»ú¤ò¥ì¥¤¥¢¥¦¥È¤¹¤ë.
2678 ´Ø¿ô mflt_run () ¤Ï¡¢$GSTRING Ãæ¤Î $FROM ¤«¤é $TO ľÁ°¤Þ¤Ç¤Îʸ»ú¤ò
2679 $FONT ¤òÍѤ¤¤Æ¥ì¥¤¥¢¥¦¥È¤¹¤ë¡£¤â¤· $FLT
2680 ¤¬¥¼¥í¤Ç¤Ê¤±¤ì¤Ð¡¢¤½¤ÎÃͤò¤¹¤Ù¤Æ¤Îʸ»ú¤ËÂФ·¤ÆÍѤ¤¤ë¡£
2681 ¤½¤¦¤Ç¤Ê¤±¤ì¤ÐŬÀÚ¤Ê FLT ¤ò¼«Æ°Åª¤ËÁªÂò¤¹¤ë¡£
2684 ¼Â¹ÔÀ®¸ù¤ò¼¨¤¹¡£ÊÖ¤µ¤ì¤ëÃͤϡ¢$GSTRING->glyphs Ãæ¤Ç°ÊÁ° $TO
2685 ¤Ë¤è¤Ã¤Æ¼¨¤µ¤ì¤Æ¤¤¤¿¥°¥ê¥Õ¤Ø¤Î¥¤¥ó¥Ç¥¯¥¹¤Ç¤¢¤ë¡£
2688 ·ë²Ì¤ò³ÊǼ¤¹¤ë¤Ë¤Ï $GSTRING->glyphs ¤¬Ã»¤¹¤®¤ë¤³¤È¤ò¼¨¤¹¡£
2689 ¸Æ¤Ó½Ð¤·Â¦¤Ï¡¢¤è¤êŤ¤ $GSTRING->glyphs
2690 ¤òÍѤ¤¤ÆºÆÅÙ¤³¤Î´Ø¿ô¤ò¸Æ¤Ö¤³¤È¤¬¤Ç¤¤ë¡£
2693 ¤½¤Î¾¤Î¥¨¥é¡¼¤¬µ¯¤¤¿¤³¤È¤ò¼¨¤¹¡£ */
2696 mflt_run (MFLTGlyphString *gstring, int from, int to,
2697 MFLTFont *font, MFLT *flt)
2699 FontLayoutContext ctx;
2700 int match_indices[NMATCH];
2702 MFLTGlyphString out;
2703 int auto_flt = ! flt;
2705 int this_from, this_to;
2706 MSymbol font_id = mflt_font_id ? mflt_font_id (font) : Mnil;
2710 /* This is usually sufficient, but if not, we retry with the larger
2711 values at most 3 times. This value is also used for the
2712 allocating size of ctx.encoded. */
2713 out.allocated = (to - from) * 4;
2715 for (i = from; i < to; i++)
2717 g = GREF (gstring, i);
2721 memset (g, 0, sizeof (MFLTGlyph));
2724 g->from = g->to = i;
2727 for (this_from = from; this_from < to;)
2731 for (this_to = this_from; this_to < to; this_to++)
2732 if (mchartable_lookup (flt->coverage->table,
2733 GREF (gstring, this_to)->c))
2738 if (! flt_list && list_flt () < 0)
2740 font->get_glyph_id (font, gstring, this_from, to);
2741 font->get_metrics (font, gstring, this_from, to);
2745 for (this_to = this_from; this_to < to; this_to++)
2747 c = GREF (gstring, this_to)->c;
2748 if (c >= flt_min_coverage && c <= flt_max_coverage)
2751 for (; this_to < to; this_to++)
2753 c = GREF (gstring, this_to)->c;
2755 && mchartable_lookup (((MFLT *) font->internal)->coverage->table, c))
2757 flt = font->internal;
2760 flt = mflt_find (c, font);
2763 if (CHECK_FLT_STAGES (flt))
2765 font->internal = flt;
2772 if (this_from < this_to)
2774 font->get_glyph_id (font, gstring, this_from, this_to);
2775 font->get_metrics (font, gstring, this_from, this_to);
2776 this_from = this_to;
2781 MDEBUG_PRINT1 (" [FLT] (%s", MSYMBOL_NAME (flt->name));
2783 if (flt->need_config)
2784 flt = configure_flt (flt, font, font_id);
2786 for (; this_to < to; this_to++)
2787 if (! mchartable_lookup (flt->coverage->table,
2788 GREF (gstring, this_to)->c))
2794 MDEBUG_PRINT1 (" (%s)", MSYMBOL_NAME (font->family));
2795 MDEBUG_PRINT ("\n [FLT] (SOURCE");
2796 for (i = this_from, j = 0; i < this_to; i++, j++)
2798 if (j > 0 && j % 8 == 0)
2799 MDEBUG_PRINT ("\n [FLT] ");
2800 MDEBUG_PRINT1 (" %04X", GREF (gstring, i)->c);
2805 for (i = 0; i < 3; i++)
2808 memset (&ctx, 0, sizeof ctx);
2809 ctx.match_indices = match_indices;
2811 ctx.cluster_begin_idx = -1;
2814 j = run_stages (gstring, this_from, this_to, flt, &ctx);
2828 MDEBUG_PRINT ("\n [FLT] (RESULT");
2829 if (MDEBUG_FLAG () > 1)
2830 for (i = 0; this_from < this_to; this_from++, i++)
2832 if (i > 0 && i % 4 == 0)
2833 MDEBUG_PRINT ("\n [FLT] ");
2834 g = GREF (gstring, this_from);
2835 MDEBUG_PRINT4 (" (%04X %d %d %d)",
2836 g->code, g->xadv, g->xoff, g->yoff);
2839 for (; this_from < this_to; this_from++)
2840 MDEBUG_PRINT1 (" %04X", GREF (gstring, this_from)->code);
2841 MDEBUG_PRINT ("))\n");
2843 this_from = this_to;
2848 int len = to - from;
2851 memcpy (((char *) out.glyphs),
2852 ((char *) gstring->glyphs) + gstring->glyph_size * from,
2853 gstring->glyph_size * len);
2854 for (i = from, j = to; i < to;)
2856 for (k = i + 1, j--; k < to && GREF (&out, k)->xadv == 0;
2858 GCPY (&out, i, (k - i), gstring, j);
2866 int (*mflt_iterate_otf_feature) (struct _MFLTFont *font,
2869 unsigned char *table);
2871 MSymbol (*mflt_font_id) (struct _MFLTFont *font);
2874 /* for debugging... */
2877 dump_flt_cmd (FontLayoutStage *stage, int id, int indent)
2879 char *prefix = (char *) alloca (indent + 1);
2881 memset (prefix, 32, indent);
2885 fprintf (stderr, "0x%02X", id);
2886 else if (id <= CMD_ID_OFFSET_INDEX)
2888 int idx = CMD_ID_TO_INDEX (id);
2889 FontLayoutCmd *cmd = stage->cmds + idx;
2891 if (cmd->type == FontLayoutCmdTypeRule)
2893 FontLayoutCmdRule *rule = &cmd->body.rule;
2896 fprintf (stderr, "(rule ");
2897 if (rule->src_type == SRC_REGEX)
2898 fprintf (stderr, "\"%s\"", rule->src.re.pattern);
2899 else if (rule->src_type == SRC_INDEX)
2900 fprintf (stderr, "%d", rule->src.match_idx);
2901 else if (rule->src_type == SRC_SEQ)
2902 fprintf (stderr, "(seq)");
2903 else if (rule->src_type == SRC_RANGE)
2904 fprintf (stderr, "(range)");
2906 fprintf (stderr, "(invalid src)");
2908 for (i = 0; i < rule->n_cmds; i++)
2910 fprintf (stderr, "\n%s ", prefix);
2911 dump_flt_cmd (stage, rule->cmd_ids[i], indent + 2);
2913 fprintf (stderr, ")");
2915 else if (cmd->type == FontLayoutCmdTypeCond)
2917 FontLayoutCmdCond *cond = &cmd->body.cond;
2920 fprintf (stderr, "(cond");
2921 for (i = 0; i < cond->n_cmds; i++)
2923 fprintf (stderr, "\n%s ", prefix);
2924 dump_flt_cmd (stage, cond->cmd_ids[i], indent + 2);
2926 fprintf (stderr, ")");
2928 else if (cmd->type == FontLayoutCmdTypeOTF)
2930 fprintf (stderr, "(otf)");
2933 fprintf (stderr, "(error-command)");
2935 else if (id <= CMD_ID_OFFSET_COMBINING)
2936 fprintf (stderr, "cominging-code");
2938 fprintf (stderr, "(predefiend %d)", id);
2942 @brief Dump a Font Layout Table.
2944 The mdebug_dump_flt () function prints the Font Layout Table $FLT
2945 in a human readable way to the stderr. $INDENT specifies how many
2946 columns to indent the lines but the first one.
2949 This function returns $FLT. */
2952 mdebug_dump_flt (MFLT *flt, int indent)
2954 char *prefix = (char *) alloca (indent + 1);
2958 memset (prefix, 32, indent);
2960 fprintf (stderr, "(flt");
2961 MPLIST_DO (plist, flt->stages)
2963 FontLayoutStage *stage = (FontLayoutStage *) MPLIST_VAL (plist);
2966 fprintf (stderr, "\n%s (stage %d", prefix, stage_idx);
2967 for (i = 0; i < stage->used; i++)
2969 fprintf (stderr, "\n%s ", prefix);
2970 dump_flt_cmd (stage, INDEX_TO_CMD_ID (i), indent + 4);
2972 fprintf (stderr, ")");
2975 fprintf (stderr, ")");