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;
453 MCharTable *category;
465 MCharTable *coverage;
469 /* Font layout table loader */
471 static int parse_otf_command (MSymbol symbol, MFLTOtfSpec *spec);
473 /* Load a category table from PLIST. PLIST has this form:
474 PLIST ::= ( FROM-CODE TO-CODE ? CATEGORY-CHAR ) *
478 load_category_table (MPlist *plist)
482 table = mchartable (Minteger, (void *) 0);
484 MPLIST_DO (plist, plist)
487 int from, to, category_code;
489 if (! MPLIST_PLIST (plist))
490 MERROR (MERROR_FONT, NULL);
491 elt = MPLIST_PLIST (plist);
492 if (! MPLIST_INTEGER_P (elt))
493 MERROR (MERROR_FONT, NULL);
494 from = MPLIST_INTEGER (elt);
495 elt = MPLIST_NEXT (elt);
496 if (! MPLIST_INTEGER_P (elt))
497 MERROR (MERROR_FONT, NULL);
498 to = MPLIST_INTEGER (elt);
499 elt = MPLIST_NEXT (elt);
500 if (MPLIST_TAIL_P (elt))
507 if (! MPLIST_INTEGER_P (elt))
508 MERROR (MERROR_FONT, NULL);
509 category_code = MPLIST_INTEGER (elt);
511 if (! isalnum (category_code))
512 MERROR (MERROR_FONT, NULL);
515 mchartable_set (table, from, (void *) category_code);
517 mchartable_set_range (table, from, to, (void *) category_code);
524 gen_otf_tag (char *p)
526 unsigned int tag = 0;
529 for (i = 0; i < 4 && *p; i++, p++)
530 tag = (tag << 8) | *p;
532 tag = (tag << 8) | 0x20;
537 otf_count_features (char *p, char *end, char stopper, int *count)
542 if (*p != stopper && *p != '\0')
549 if (*p == stopper || *p == '\0')
563 if (*p == stopper || *p == '\0')
575 otf_store_features (char *p, char *end, unsigned *buf)
580 for (i = 0; p < end;)
583 buf[i++] = 0xFFFFFFFF, p += 2, negative = 1;
587 buf[i++] = 0xFFFFFFFF;
588 buf[i++] = gen_otf_tag (p + 1), p += 6;
591 buf[i++] = gen_otf_tag (p), p += 5;
597 parse_otf_command (MSymbol symbol, MFLTOtfSpec *spec)
599 char *str = MSYMBOL_NAME (symbol);
600 char *end = str + MSYMBOL_NAMELEN (symbol);
601 unsigned int script, langsys;
603 int gsub_count = 0, gpos_count = 0;
606 memset (spec, 0, sizeof (MFLTOtfSpec));
609 str += 5; /* skip the heading ":otf=" */
610 script = gen_otf_tag (str);
614 langsys = gen_otf_tag (str);
621 /* Apply all GSUB features. */
626 str = otf_count_features (p, end, '+', &gsub_count);
628 MERROR (MERROR_FLT, -1);
632 /* Apply all GPOS features. */
637 str = otf_count_features (p, end, '\0', &gpos_count);
639 MERROR (MERROR_FLT, -1);
642 spec->script = script;
643 spec->langsys = langsys;
646 spec->features[0] = malloc (sizeof (int) * (gsub_count + 1));
647 if (! spec->features[0])
650 otf_store_features (gsub + 1, gpos, spec->features[0]);
652 spec->features[0][0] = 0xFFFFFFFF, spec->features[0][1] = 0;
656 spec->features[1] = malloc (sizeof (int) * (gpos_count + 1));
657 if (! spec->features[1])
659 if (spec->features[0])
660 free (spec->features[0]);
664 otf_store_features (gpos + 1, str, spec->features[1]);
666 spec->features[1][0] = 0xFFFFFFFF, spec->features[1][1] = 0;
672 /* Parse OTF command name NAME and store the result in CMD.
674 :SCRIPT[/[LANGSYS][=[GSUB-FEATURES][+GPOS-FEATURES]]]
675 where GSUB-FEATURES and GPOS-FEATURES have this form:
676 [FEATURE[,FEATURE]*] | ' ' */
679 load_otf_command (FontLayoutCmd *cmd, MSymbol sym)
681 char *name = MSYMBOL_NAME (sym);
686 /* This is old format of "otf:...". Change it to ":otf=...". */
687 char *str = alloca (MSYMBOL_NAMELEN (sym) + 2);
689 sprintf (str, ":otf=");
690 strcat (str, name + 4);
694 result = parse_otf_command (sym, &cmd->body.otf);
697 cmd->type = FontLayoutCmdTypeOTF;
702 /* Read a decimal number from STR preceded by one of "+-><". '+' and
703 '>' means a plus sign, '-' and '<' means a minus sign. If the
704 number is greater than 127, limit it to 127. */
707 read_decimal_number (char **str)
710 int sign = (*p == '-' || *p == '<') ? -1 : 1;
714 while (*p >= '0' && *p <= '9')
715 n = n * 10 + *p++ - '0';
719 return (n < 127 ? n * sign : 127 * sign);
723 /* Read a horizontal and vertical combining positions from STR, and
724 store them in the place pointed by X and Y. The horizontal
725 position left, center, and right are represented by 0, 1, and 2
726 respectively. The vertical position top, center, bottom, and base
727 are represented by 0, 1, 2, and 3 respectively. If successfully
728 read, return 0, else return -1. */
731 read_combining_position (char *str, int *x, int *y)
736 /* Vertical position comes first. */
737 for (i = 0; i < 4; i++)
746 /* Then comse horizontal position. */
747 for (i = 0; i < 3; i++)
757 /* Return a combining code corresponding to SYM. */
760 get_combining_command (MSymbol sym)
762 char *str = msymbol_name (sym);
763 int base_x, base_y, add_x, add_y, off_x, off_y;
766 if (read_combining_position (str, &base_x, &base_y) < 0)
777 if (c == '+' || c == '-')
779 off_y = read_decimal_number (&str) + 128;
784 if (c == '<' || c == '>')
785 off_x = read_decimal_number (&str) + 128;
789 if (read_combining_position (str, &add_x, &add_y) < 0)
792 c = MAKE_COMBINING_CODE (base_y, base_x, add_y, add_x, off_y, off_x);
793 return (COMBINING_CODE_TO_CMD_ID (c));
797 /* Load a command from PLIST into STAGE, and return that
798 identification number. If ID is not INVALID_CMD_ID, that means we
799 are loading a top level command or a macro. In that case, use ID
800 as the identification number of the command. Otherwise, generate a
801 new id number for the command. MACROS is a list of raw macros. */
804 load_command (FontLayoutStage *stage, MPlist *plist,
805 MPlist *macros, int id)
810 if (MPLIST_INTEGER_P (plist))
812 int code = MPLIST_INTEGER (plist);
815 MERROR (MERROR_DRAW, INVALID_CMD_ID);
818 else if (MPLIST_PLIST_P (plist))
820 /* PLIST ::= ( cond ... ) | ( STRING ... ) | ( INTEGER ... )
821 | ( ( INTEGER INTEGER ) ... )
822 | ( ( range INTEGER INTEGER ) ... )
823 | ( ( font-facilty [ INTEGER ] ) ... )
824 | ( ( font-facilty OTF-SPEC ) ... ) */
825 MPlist *elt = MPLIST_PLIST (plist);
826 int len = MPLIST_LENGTH (elt) - 1;
829 if (id == INVALID_CMD_ID)
832 id = INDEX_TO_CMD_ID (stage->used);
833 MLIST_APPEND1 (stage, cmds, dummy, MERROR_DRAW);
835 cmd = stage->cmds + CMD_ID_TO_INDEX (id);
837 if (MPLIST_SYMBOL_P (elt))
839 FontLayoutCmdCond *cond;
841 if (MPLIST_SYMBOL (elt) != Mcond)
842 MERROR (MERROR_DRAW, INVALID_CMD_ID);
843 elt = MPLIST_NEXT (elt);
844 cmd->type = FontLayoutCmdTypeCond;
845 cond = &cmd->body.cond;
846 cond->seq_beg = cond->seq_end = -1;
847 cond->seq_from = cond->seq_to = 0;
849 MTABLE_CALLOC (cond->cmd_ids, len, MERROR_DRAW);
850 for (i = 0; i < len; i++, elt = MPLIST_NEXT (elt))
852 int this_id = load_command (stage, elt, macros, INVALID_CMD_ID);
854 if (this_id == INVALID_CMD_ID || this_id == -2)
855 MERROR (MERROR_DRAW, this_id);
856 /* The above load_command may relocate stage->cmds. */
857 cmd = stage->cmds + CMD_ID_TO_INDEX (id);
858 cond = &cmd->body.cond;
859 cond->cmd_ids[i] = this_id;
860 if (this_id <= CMD_ID_OFFSET_INDEX)
862 FontLayoutCmd *this_cmd
863 = stage->cmds + CMD_ID_TO_INDEX (this_id);
865 if (this_cmd->type == FontLayoutCmdTypeRule
866 && this_cmd->body.rule.src_type == SRC_SEQ)
868 int first_char = this_cmd->body.rule.src.seq.codes[0];
870 if (cond->seq_beg < 0)
872 /* The first SEQ command. */
874 cond->seq_from = cond->seq_to = first_char;
876 else if (cond->seq_end < 0)
878 /* The following SEQ command. */
879 if (cond->seq_from > first_char)
880 cond->seq_from = first_char;
881 else if (cond->seq_to < first_char)
882 cond->seq_to = first_char;
887 if (cond->seq_beg >= 0 && cond->seq_end < 0)
888 /* The previous one is the last SEQ command. */
894 if (cond->seq_beg >= 0 && cond->seq_end < 0)
895 /* The previous one is the last SEQ command. */
899 if (cond->seq_beg >= 0 && cond->seq_end < 0)
900 /* The previous one is the last SEQ command. */
905 cmd->type = FontLayoutCmdTypeRule;
906 if (MPLIST_MTEXT_P (elt))
908 MText *mt = MPLIST_MTEXT (elt);
909 char *str = (char *) MTEXT_DATA (mt);
913 mtext_ins_char (mt, 0, '^', 1);
914 str = (char *) MTEXT_DATA (mt);
916 if (regcomp (&cmd->body.rule.src.re.preg, str, REG_EXTENDED))
917 MERROR (MERROR_FONT, INVALID_CMD_ID);
918 cmd->body.rule.src_type = SRC_REGEX;
919 cmd->body.rule.src.re.pattern = strdup (str);
921 else if (MPLIST_INTEGER_P (elt))
923 cmd->body.rule.src_type = SRC_INDEX;
924 cmd->body.rule.src.match_idx = MPLIST_INTEGER (elt);
926 else if (MPLIST_PLIST_P (elt))
928 MPlist *pl = MPLIST_PLIST (elt), *p;
929 int size = MPLIST_LENGTH (pl);
931 if (MPLIST_INTEGER_P (pl))
935 cmd->body.rule.src_type = SRC_SEQ;
936 cmd->body.rule.src.seq.n_codes = size;
937 MTABLE_CALLOC (cmd->body.rule.src.seq.codes, size,
939 for (i = 0; i < size; i++, pl = MPLIST_NEXT (pl))
941 if (! MPLIST_INTEGER_P (pl))
942 MERROR (MERROR_DRAW, INVALID_CMD_ID);
943 cmd->body.rule.src.seq.codes[i]
944 = (unsigned) MPLIST_INTEGER (pl);
947 else if (MPLIST_SYMBOL_P (pl))
949 if (MPLIST_SYMBOL (pl) == Mrange)
952 MERROR (MERROR_FLT, INVALID_CMD_ID);
953 cmd->body.rule.src_type = SRC_RANGE;
954 pl = MPLIST_NEXT (pl);
955 if (! MPLIST_INTEGER_P (pl))
956 MERROR (MERROR_DRAW, INVALID_CMD_ID);
957 cmd->body.rule.src.range.from
958 = (unsigned) MPLIST_INTEGER (pl);
959 pl = MPLIST_NEXT (pl);
960 if (! MPLIST_INTEGER_P (pl))
961 MERROR (MERROR_DRAW, INVALID_CMD_ID);
962 cmd->body.rule.src.range.to
963 = (unsigned) MPLIST_INTEGER (pl);
965 else if (MPLIST_SYMBOL (pl) == Mfont_facility)
967 FontLayoutCmdRule *rule = &cmd->body.rule;
969 pl = MPLIST_NEXT (pl);
970 if (MPLIST_SYMBOL_P (pl))
972 MSymbol sym = MPLIST_SYMBOL (pl);
973 char *otf_spec = MSYMBOL_NAME (sym);
975 if (otf_spec[0] == ':' && otf_spec[1] == 'o'
976 && otf_spec[2] == 't' && otf_spec[3] == 'f')
977 parse_otf_command (sym, &rule->src.facility.otf_spec);
979 MERROR (MERROR_FLT, INVALID_CMD_ID);
980 rule->src_type = SRC_OTF_SPEC;
981 pl = MPLIST_NEXT (pl);
983 else if (MPLIST_TAIL_P (pl))
984 MERROR (MERROR_FLT, INVALID_CMD_ID);
986 rule->src_type = SRC_HAS_GLYPH;
987 rule->src.facility.len = 0;
990 if (! MPLIST_INTEGER_P (p)
991 && (MPLIST_SYMBOL_P (p)
992 ? MPLIST_SYMBOL (p) != Mequal
994 MERROR (MERROR_FLT, INVALID_CMD_ID);
995 rule->src.facility.len++;
997 rule->src.facility.codes = pl;
998 M17N_OBJECT_REF (pl);
1002 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1005 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1007 elt = MPLIST_NEXT (elt);
1008 cmd->body.rule.n_cmds = len;
1009 MTABLE_CALLOC (cmd->body.rule.cmd_ids, len, MERROR_DRAW);
1010 for (i = 0; i < len; i++, elt = MPLIST_NEXT (elt))
1012 int this_id = load_command (stage, elt, macros, INVALID_CMD_ID);
1014 if (this_id == INVALID_CMD_ID || this_id == -2)
1015 MERROR (MERROR_DRAW, this_id);
1016 /* The above load_command may relocate stage->cmds. */
1017 cmd = stage->cmds + CMD_ID_TO_INDEX (id);
1018 cmd->body.rule.cmd_ids[i] = this_id;
1022 else if (MPLIST_SYMBOL_P (plist))
1025 MSymbol sym = MPLIST_SYMBOL (plist);
1026 char *name = msymbol_name (sym);
1027 int len = strlen (name);
1031 && ((name[0] == 'o' && name[1] == 't'
1032 && name[2] == 'f' && name[3] == ':')
1033 || (name[0] == ':' && name[1] == 'o' && name[2] == 't'
1034 && name[3] == 'f' && name[4] == '=')))
1036 result = load_otf_command (&cmd, sym);
1039 if (id == INVALID_CMD_ID)
1041 id = INDEX_TO_CMD_ID (stage->used);
1042 MLIST_APPEND1 (stage, cmds, cmd, MERROR_DRAW);
1045 stage->cmds[CMD_ID_TO_INDEX (id)] = cmd;
1053 else if (*name == '*')
1054 return CMD_ID_REPEAT;
1055 else if (*name == '<')
1056 return CMD_ID_CLUSTER_BEGIN;
1057 else if (*name == '>')
1058 return CMD_ID_CLUSTER_END;
1059 else if (*name == '|')
1060 return CMD_ID_SEPARATOR;
1061 else if (*name == '[')
1062 return CMD_ID_LEFT_PADDING;
1063 else if (*name == ']')
1064 return CMD_ID_RIGHT_PADDING;
1070 id = get_combining_command (sym);
1076 MPLIST_DO (elt, macros)
1078 if (sym == MPLIST_SYMBOL (MPLIST_PLIST (elt)))
1080 id = INDEX_TO_CMD_ID (i);
1081 if (stage->cmds[i].type == FontLayoutCmdTypeMAX)
1082 id = load_command (stage, MPLIST_NEXT (MPLIST_PLIST (elt)),
1088 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1091 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1097 free_flt_command (FontLayoutCmd *cmd)
1099 if (cmd->type == FontLayoutCmdTypeRule)
1101 FontLayoutCmdRule *rule = &cmd->body.rule;
1103 if (rule->src_type == SRC_REGEX)
1105 free (rule->src.re.pattern);
1106 regfree (&rule->src.re.preg);
1108 else if (rule->src_type == SRC_SEQ)
1109 free (rule->src.seq.codes);
1110 free (rule->cmd_ids);
1112 else if (cmd->type == FontLayoutCmdTypeCond)
1113 free (cmd->body.cond.cmd_ids);
1114 else if (cmd->type == FontLayoutCmdTypeOTF)
1116 if (cmd->body.otf.features[0])
1117 free (cmd->body.otf.features[0]);
1118 if (cmd->body.otf.features[1])
1119 free (cmd->body.otf.features[1]);
1123 /* Load a generator from PLIST into a newly allocated FontLayoutStage,
1124 and return it. PLIST has this form:
1125 PLIST ::= ( COMMAND ( CMD-NAME COMMAND ) * )
1128 static FontLayoutStage *
1129 load_generator (MPlist *plist)
1131 FontLayoutStage *stage;
1133 FontLayoutCmd dummy;
1136 MSTRUCT_CALLOC (stage, MERROR_DRAW);
1137 MLIST_INIT1 (stage, cmds, 32);
1138 dummy.type = FontLayoutCmdTypeMAX;
1139 MLIST_APPEND1 (stage, cmds, dummy, MERROR_FONT);
1140 MPLIST_DO (elt, MPLIST_NEXT (plist))
1142 if (! MPLIST_PLIST_P (elt))
1143 MERROR (MERROR_FONT, NULL);
1144 pl = MPLIST_PLIST (elt);
1145 if (! MPLIST_SYMBOL_P (pl))
1146 MERROR (MERROR_FONT, NULL);
1147 MLIST_APPEND1 (stage, cmds, dummy, MERROR_FONT);
1150 /* Load the first command from PLIST into STAGE->cmds[0]. Macros
1151 called in the first command are also loaded from MPLIST_NEXT
1152 (PLIST) into STAGE->cmds[n]. */
1153 result = load_command (stage, plist, MPLIST_NEXT (plist),
1154 INDEX_TO_CMD_ID (0));
1155 if (result == INVALID_CMD_ID || result == -2)
1157 MLIST_FREE1 (stage, cmds);
1166 /* Load stages of the font layout table FLT. */
1169 load_flt (MFLT *flt, MPlist *key_list)
1171 MPlist *top, *plist, *pl, *p;
1172 MCharTable *category = NULL;
1176 top = (MPlist *) mdatabase__load_for_keys (flt->mdb, key_list);
1178 top = (MPlist *) mdatabase_load (flt->mdb);
1181 if (! MPLIST_PLIST_P (top))
1183 M17N_OBJECT_UNREF (top);
1184 MERROR (MERROR_FLT, -1);
1189 plist = mdatabase__props (flt->mdb);
1191 MERROR (MERROR_FLT, -1);
1192 MPLIST_DO (plist, plist)
1193 if (MPLIST_PLIST_P (plist))
1195 pl = MPLIST_PLIST (plist);
1196 if (! MPLIST_SYMBOL_P (pl)
1197 || MPLIST_SYMBOL (pl) != Mfont)
1199 pl = MPLIST_NEXT (pl);
1200 if (! MPLIST_PLIST_P (pl))
1202 p = MPLIST_PLIST (pl);
1203 if (! MPLIST_SYMBOL_P (p))
1205 p = MPLIST_NEXT (p);
1206 if (! MPLIST_SYMBOL_P (p))
1208 flt->family = MPLIST_SYMBOL (p);
1209 MPLIST_DO (p, MPLIST_NEXT (p))
1210 if (MPLIST_SYMBOL_P (p))
1212 sym = MPLIST_SYMBOL (p);
1213 if (MSYMBOL_NAME (sym)[0] != ':')
1214 flt->registry = sym, sym = Mnil;
1220 char *otf_spec = MSYMBOL_NAME (sym);
1222 if (otf_spec[0] == ':' && otf_spec[1] == 'o'
1223 && otf_spec[2] == 't' && otf_spec[3] == 'f')
1224 parse_otf_command (sym, &flt->otf);
1229 MPLIST_DO (plist, top)
1231 if (MPLIST_SYMBOL_P (plist)
1232 && MPLIST_SYMBOL (plist) == Mend)
1234 mplist_set (plist, Mnil, NULL);
1237 if (! MPLIST_PLIST (plist))
1239 pl = MPLIST_PLIST (plist);
1240 if (! MPLIST_SYMBOL_P (pl))
1242 sym = MPLIST_SYMBOL (pl);
1243 pl = MPLIST_NEXT (pl);
1246 if (sym == Mcategory)
1249 M17N_OBJECT_UNREF (category);
1250 else if (flt->coverage)
1252 category = flt->coverage;
1255 category = load_category_table (pl);
1256 if (! flt->coverage)
1258 flt->coverage = category;
1259 M17N_OBJECT_REF (category);
1262 else if (sym == Mgenerator)
1264 FontLayoutStage *stage;
1268 stage = load_generator (pl);
1271 stage->category = category;
1272 M17N_OBJECT_REF (category);
1274 flt->stages = mplist ();
1275 mplist_add (flt->stages, Mt, stage);
1279 M17N_OBJECT_UNREF (category);
1280 if (! MPLIST_TAIL_P (plist))
1282 M17N_OBJECT_UNREF (top);
1283 M17N_OBJECT_UNREF (flt->stages);
1284 MERROR (MERROR_FLT, -1);
1286 M17N_OBJECT_UNREF (top);
1292 free_flt_stage (FontLayoutStage *stage)
1296 M17N_OBJECT_UNREF (stage->category);
1297 for (i = 0; i < stage->used; i++)
1298 free_flt_command (stage->cmds + i);
1299 MLIST_FREE1 (stage, cmds);
1310 MPLIST_DO (plist, flt_list)
1312 MFLT *flt = MPLIST_VAL (plist);
1315 M17N_OBJECT_UNREF (flt->coverage);
1318 MPLIST_DO (pl, MPLIST_NEXT (flt->stages))
1319 free_flt_stage (MPLIST_VAL (pl));
1320 M17N_OBJECT_UNREF (flt->stages);
1323 M17N_OBJECT_UNREF (flt_list);
1330 MPlist *plist, *key_list = NULL;
1334 if (! (plist = mdatabase_list (Mfont, Mlayouter, Mnil, Mnil)))
1336 if (! (flt_list = mplist ()))
1338 if (! (key_list = mplist ()))
1340 if (! mplist_add (key_list, Mcategory, Mt))
1343 MPLIST_DO (pl, plist)
1345 MDatabase *mdb = MPLIST_VAL (pl);
1346 MSymbol *tags = mdatabase_tag (mdb);
1349 if (! MSTRUCT_CALLOC_SAFE (flt))
1351 flt->name = tags[2];
1353 if (load_flt (flt, key_list) < 0)
1357 if (MPLIST_TAIL_P (flt_list))
1359 flt_min_coverage = mchartable_min_char (flt->coverage);
1360 flt_max_coverage = mchartable_max_char (flt->coverage);
1366 c = mchartable_min_char (flt->coverage);
1367 if (flt_min_coverage > c)
1368 flt_min_coverage = c;
1369 c = mchartable_max_char (flt->coverage);
1370 if (flt_max_coverage < c)
1371 flt_max_coverage = c;
1373 if (! mplist_push (flt_list, flt->name, flt))
1383 M17N_OBJECT_UNREF (plist);
1384 M17N_OBJECT_UNREF (key_list);
1388 /* FLS (Font Layout Service) */
1390 /* Structure to hold information about a context of FLS. */
1394 /* Pointer to the current stage. */
1395 FontLayoutStage *stage;
1397 /* Pointer to the font. */
1400 /* Input and output glyph string. */
1401 MFLTGlyphString *in, *out;
1403 /* Encode each character or code of a glyph by the current category
1404 table into this array. An element is a category letter used for
1405 a regular expression matching. */
1410 int cluster_begin_idx;
1411 int cluster_begin_pos;
1412 int cluster_end_pos;
1416 } FontLayoutContext;
1418 static int run_command (int, int, int, int, FontLayoutContext *);
1423 run_rule (int depth,
1424 FontLayoutCmdRule *rule, int from, int to, FontLayoutContext *ctx)
1426 int *saved_match_indices = ctx->match_indices;
1427 int match_indices[NMATCH * 2];
1430 int orig_from = from;
1431 int need_cluster_update = 0;
1433 if (rule->src_type == SRC_REGEX)
1435 regmatch_t pmatch[NMATCH];
1441 saved_code = ctx->encoded[to - ctx->encoded_offset];
1442 ctx->encoded[to - ctx->encoded_offset] = '\0';
1443 result = regexec (&(rule->src.re.preg),
1444 ctx->encoded + (from - ctx->encoded_offset),
1446 if (result == 0 && pmatch[0].rm_so == 0)
1448 if (MDEBUG_FLAG () > 2)
1449 MDEBUG_PRINT5 ("\n [FLT] %*s(REGEX \"%s\" \"%s\" %d", depth, "",
1450 rule->src.re.pattern,
1451 ctx->encoded + (from - ctx->encoded_offset),
1453 ctx->encoded[to - ctx->encoded_offset] = saved_code;
1454 for (i = 0; i < NMATCH; i++)
1456 if (pmatch[i].rm_so < 0)
1457 match_indices[i * 2] = match_indices[i * 2 + 1] = -1;
1460 match_indices[i * 2] = from + pmatch[i].rm_so;
1461 match_indices[i * 2 + 1] = from + pmatch[i].rm_eo;
1464 ctx->match_indices = match_indices;
1465 to = match_indices[1];
1469 ctx->encoded[to - ctx->encoded_offset] = saved_code;
1472 need_cluster_update = 1;
1474 else if (rule->src_type == SRC_SEQ)
1478 len = rule->src.seq.n_codes;
1479 if (len > (to - from))
1481 for (i = 0; i < len; i++)
1482 if (rule->src.seq.codes[i] != GREF (ctx->in, from + i)->code)
1487 if (MDEBUG_FLAG () > 2)
1488 MDEBUG_PRINT3 ("\n [FLT] %*s(SEQ 0x%X", depth, "",
1489 rule->src.seq.codes[0]);
1490 need_cluster_update = 1;
1492 else if (rule->src_type == SRC_RANGE)
1498 head = GREF (ctx->in, from)->code;
1499 if (head < rule->src.range.from || head > rule->src.range.to)
1501 ctx->code_offset = head - rule->src.range.from;
1503 if (MDEBUG_FLAG () > 2)
1504 MDEBUG_PRINT4 ("\n [FLT] %*s(RANGE 0x%X-0x%X", depth, "",
1505 rule->src.range.from, rule->src.range.to);
1506 need_cluster_update = 1;
1508 else if (rule->src_type == SRC_INDEX)
1510 if (rule->src.match_idx >= NMATCH)
1512 from = ctx->match_indices[rule->src.match_idx * 2];
1515 to = ctx->match_indices[rule->src.match_idx * 2 + 1];
1516 if (MDEBUG_FLAG () > 2)
1517 MDEBUG_PRINT3 ("\n [FLT] %*s(SUBPART %d", depth, "",
1518 rule->src.match_idx);
1519 need_cluster_update = 1;
1521 else if (rule->src_type == SRC_HAS_GLYPH
1522 || rule->src_type == SRC_OTF_SPEC)
1524 static MFLTGlyphString gstring;
1528 if (rule->src.facility.len > 0)
1530 if (! gstring.glyph_size)
1532 gstring.glyph_size = ctx->in->glyph_size;
1533 gstring.glyphs = calloc (rule->src.facility.len,
1534 gstring.glyph_size);
1535 gstring.allocated = rule->src.facility.len;
1536 gstring.used = rule->src.facility.len;
1538 else if (rule->src.facility.len < gstring.allocated)
1540 gstring.glyphs = realloc (gstring.glyphs,
1542 * rule->src.facility.len);
1543 gstring.allocated = rule->src.facility.len;
1544 gstring.used = rule->src.facility.len;
1547 for (i = 0, p = rule->src.facility.codes, idx = from;
1548 i < rule->src.facility.len; i++, p = MPLIST_NEXT (p))
1550 if (MPLIST_INTEGER_P (p))
1552 GREF (&gstring, i)->code = MPLIST_INTEGER (p);
1553 GREF (&gstring, i)->encoded = 0;
1557 GREF (&gstring, i)->code = GREF (ctx->in, idx)->code;
1558 GREF (&gstring, i)->encoded = GREF (ctx->in, idx)->encoded;
1564 if (MDEBUG_FLAG () > 2)
1566 if (rule->src_type == SRC_HAS_GLYPH)
1567 MDEBUG_PRINT2 ("\n [FLT] %*s(HAS-GLYPH", depth, "");
1569 MDEBUG_PRINT2 ("\n [FLT] %*s(OTF-SPEC", depth, "");
1570 for (i = 0; i < rule->src.facility.len; i++)
1571 MDEBUG_PRINT1 (" %04X", GREF (&gstring, i)->code);
1573 if (ctx->font->get_glyph_id (ctx->font, &gstring, 0,
1574 rule->src.facility.len) < 0)
1576 MDEBUG_PRINT (") FAIL!");
1579 if (rule->src_type == SRC_OTF_SPEC)
1581 MFLTOtfSpec *spec = &rule->src.facility.otf_spec;
1583 if (! ctx->font->check_otf)
1585 if ((spec->features[0] && spec->features[0][0] != 0xFFFFFFFF)
1586 || (spec->features[1] && spec->features[1][0] != 0xFFFFFFFF))
1591 if (rule->src.facility.len == 0)
1593 if (! ctx->font->check_otf (ctx->font, spec))
1598 int prev_out_used = ctx->out->used, out_used;
1599 MFLTGlyphAdjustment *adjustment;
1601 adjustment = alloca ((sizeof *adjustment)
1602 * (ctx->out->allocated - ctx->out->used));
1604 MERROR (MERROR_FLT, -1);
1605 memset (adjustment, 0,
1606 (sizeof *adjustment)
1607 * (ctx->out->allocated - ctx->out->used));
1608 ctx->font->drive_otf (ctx->font, &rule->src.facility.otf_spec,
1609 &gstring, 0, rule->src.facility.len,
1612 out_used = ctx->out->used;
1613 ctx->out->used = prev_out_used;
1614 if (rule->src.facility.len == out_used - prev_out_used)
1616 for (i = prev_out_used; i < out_used; i++)
1618 if (GREF (&gstring, i - prev_out_used)->code
1619 != GREF (ctx->out, i)->code)
1621 if (adjustment[i - prev_out_used].set)
1632 if (need_cluster_update && ctx->cluster_begin_idx >= 0)
1634 for (i = from; i < to; i++)
1636 MFLTGlyph *g = GREF (ctx->in, i);
1637 UPDATE_CLUSTER_RANGE (ctx, g);
1643 for (i = 0; i < rule->n_cmds; i++)
1647 if (rule->cmd_ids[i] == CMD_ID_REPEAT)
1653 pos = run_command (depth, rule->cmd_ids[i], from, to, ctx);
1656 consumed = pos > from;
1661 ctx->match_indices = saved_match_indices;
1662 if (MDEBUG_FLAG () > 2)
1664 return (rule->src_type == SRC_INDEX ? orig_from : to);
1668 run_cond (int depth,
1669 FontLayoutCmdCond *cond, int from, int to, FontLayoutContext *ctx)
1673 if (MDEBUG_FLAG () > 2)
1674 MDEBUG_PRINT2 ("\n [FLT] %*s(COND", depth, "");
1676 for (i = 0; i < cond->n_cmds; i++)
1678 /* TODO: Write a code for optimization utilizaing the info
1680 if ((pos = run_command (depth, cond->cmd_ids[i], from, to, ctx))
1686 if (MDEBUG_FLAG () > 2)
1693 MFLTOtfSpec *otf_spec, int from, int to, FontLayoutContext *ctx)
1695 MFLTFont *font = ctx->font;
1696 int from_idx = ctx->out->used;
1698 if (MDEBUG_FLAG () > 2)
1699 MDEBUG_PRINT3 ("\n [FLT] %*s%s", depth, "", MSYMBOL_NAME (otf_spec->sym));
1701 font->get_glyph_id (font, ctx->in, from, to);
1702 if (! font->drive_otf)
1704 if (ctx->out->used + (to - from) > ctx->out->allocated)
1706 font->get_metrics (font, ctx->in, from, to);
1707 GCPY (ctx->in, from, to - from, ctx->out, ctx->out->used);
1708 ctx->out->used += to - from;
1712 MFLTGlyphAdjustment *adjustment;
1716 adjustment = alloca ((sizeof *adjustment)
1717 * (ctx->out->allocated - ctx->out->used));
1719 MERROR (MERROR_FLT, -1);
1720 memset (adjustment, 0,
1721 (sizeof *adjustment) * (ctx->out->allocated - ctx->out->used));
1722 to = font->drive_otf (font, otf_spec, ctx->in, from, to, ctx->out,
1726 out_len = ctx->out->used - from_idx;
1727 if (otf_spec->features[1])
1729 MFLTGlyphAdjustment *a;
1732 for (i = 0, a = adjustment; i < out_len; i++, a++)
1737 font->get_metrics (font, ctx->out, from_idx, ctx->out->used);
1738 for (g = GREF (ctx->out, from_idx + i);
1739 i < out_len; i++, a++, g = NEXT (ctx->out, g))
1742 if (a->advance_is_absolute)
1747 else if (a->xadv || a->yadv)
1752 if (a->xoff || a->yoff || a->back)
1755 MFLTGlyph *gg = PREV (ctx->out, g);
1756 MFLTGlyphAdjustment *aa = a;
1760 while (aa->back > 0)
1762 for (j = 0; j < aa->back;
1763 j++, gg = PREV (ctx->out, gg))
1765 g->xoff -= gg->xadv;
1766 g->lbearing -= gg->xadv;
1767 g->rbearing -= gg->xadv;
1770 g->xoff += aa->xoff;
1771 g->yoff += aa->yoff;
1772 g->lbearing += aa->xoff;
1773 g->rbearing += aa->xoff;
1774 g->ascent -= aa->yoff;
1775 g->descent -= aa->yoff;
1784 if (ctx->cluster_begin_idx >= 0)
1785 for (; from_idx < ctx->out->used; from_idx++)
1787 MFLTGlyph *g = GREF (ctx->out, from_idx);
1788 UPDATE_CLUSTER_RANGE (ctx, g);
1793 static char work[16];
1796 dump_combining_code (int code)
1798 char *vallign = "tcbB";
1799 char *hallign = "lcr";
1805 work[0] = vallign[COMBINING_CODE_BASE_Y (code)];
1806 work[1] = hallign[COMBINING_CODE_BASE_X (code)];
1807 off_y = COMBINING_CODE_OFF_Y (code);
1808 off_x = COMBINING_CODE_OFF_X (code);
1810 sprintf (work + 2, "+%d", off_y);
1812 sprintf (work + 2, "%d", off_y);
1813 else if (off_x == 0)
1814 sprintf (work + 2, ".");
1815 p = work + strlen (work);
1817 sprintf (p, ">%d", off_x);
1819 sprintf (p, "<%d", -off_x);
1821 p[0] = vallign[COMBINING_CODE_ADD_Y (code)];
1822 p[1] = hallign[COMBINING_CODE_ADD_X (code)];
1828 run_command (int depth, int id, int from, int to, FontLayoutContext *ctx)
1836 /* Direct code (== ctx->code_offset + id) output.
1837 The source is not consumed. */
1838 if (MDEBUG_FLAG () > 2)
1839 MDEBUG_PRINT3 ("\n [FLT] %*s(DIRECT 0x%X", depth, "",
1840 ctx->code_offset + id);
1841 i = (from < to || from == 0) ? from : from - 1;
1843 g = GREF (ctx->out, ctx->out->used - 1);
1844 g->c = g->code = ctx->code_offset + id;
1846 SET_MEASURED (g, 0);
1847 if (ctx->combining_code)
1848 SET_COMBINING_CODE (g, ctx, ctx->combining_code);
1849 if (ctx->left_padding)
1850 SET_LEFT_PADDING (g, ctx, LeftPaddingMask);
1851 for (i = from; i < to; i++)
1853 MFLTGlyph *tmp = GREF (ctx->in, i);
1855 if (g->from > tmp->from)
1856 g->from = tmp->from;
1857 else if (g->to < tmp->to)
1860 if (ctx->cluster_begin_idx >= 0)
1861 UPDATE_CLUSTER_RANGE (ctx, g);
1862 ctx->code_offset = ctx->combining_code = ctx->left_padding = 0;
1863 if (MDEBUG_FLAG () > 2)
1868 if (id <= CMD_ID_OFFSET_INDEX)
1870 int idx = CMD_ID_TO_INDEX (id);
1873 if (idx >= ctx->stage->used)
1874 MERROR (MERROR_DRAW, -1);
1875 cmd = ctx->stage->cmds + idx;
1876 if (cmd->type == FontLayoutCmdTypeRule)
1877 to = run_rule (depth, &cmd->body.rule, from, to, ctx);
1878 else if (cmd->type == FontLayoutCmdTypeCond)
1879 to = run_cond (depth, &cmd->body.cond, from, to, ctx);
1880 else if (cmd->type == FontLayoutCmdTypeOTF)
1881 to = run_otf (depth, &cmd->body.otf, from, to, ctx);
1885 if (id <= CMD_ID_OFFSET_COMBINING)
1887 ctx->combining_code = CMD_ID_TO_COMBINING_CODE (id);
1888 if (MDEBUG_FLAG () > 2)
1889 MDEBUG_PRINT3 ("\n [FLT] %*s(CMB %s)", depth, "",
1890 dump_combining_code (ctx->combining_code));
1901 g = GREF (ctx->out, ctx->out->used - 1);
1902 if (ctx->combining_code)
1903 SET_COMBINING_CODE (g, ctx, ctx->combining_code);
1904 if (ctx->left_padding)
1905 SET_LEFT_PADDING (g, ctx, LeftPaddingMask);
1906 if (ctx->cluster_begin_idx >= 0)
1907 UPDATE_CLUSTER_RANGE (ctx, g);
1908 if (MDEBUG_FLAG () > 2)
1911 MDEBUG_PRINT2 ("\n [FLT] %*s(COPY |)", depth, "");
1913 MDEBUG_PRINT3 ("\n [FLT] %*s(COPY 0x%X)", depth, "", g->code);
1915 ctx->code_offset = ctx->combining_code = ctx->left_padding = 0;
1919 case CMD_ID_CLUSTER_BEGIN:
1920 if (ctx->cluster_begin_idx < 0)
1922 if (MDEBUG_FLAG () > 2)
1923 MDEBUG_PRINT3 ("\n [FLT] %*s<%d", depth, "",
1924 GREF (ctx->in, from)->from);
1925 ctx->cluster_begin_idx = ctx->out->used;
1926 ctx->cluster_begin_pos = GREF (ctx->in, from)->from;
1927 ctx->cluster_end_pos = GREF (ctx->in, from)->to;
1931 case CMD_ID_CLUSTER_END:
1932 if (ctx->cluster_begin_idx >= 0
1933 && ctx->cluster_begin_idx < ctx->out->used)
1937 if (MDEBUG_FLAG () > 2)
1938 MDEBUG_PRINT1 (" %d>", ctx->cluster_end_pos + 1);
1939 for (i = ctx->cluster_begin_idx; i < ctx->out->used; i++)
1941 GREF (ctx->out, i)->from = ctx->cluster_begin_pos;
1942 GREF (ctx->out, i)->to = ctx->cluster_end_pos;
1944 ctx->cluster_begin_idx = -1;
1948 case CMD_ID_SEPARATOR:
1952 i = from < to ? from : from - 1;
1954 g = GREF (ctx->out, ctx->out->used - 1);
1955 g->c = -1, g->code = 0;
1956 g->xadv = g->yadv = 0;
1958 SET_MEASURED (g, 0);
1962 case CMD_ID_LEFT_PADDING:
1963 if (MDEBUG_FLAG () > 2)
1964 MDEBUG_PRINT2 ("\n [FLT] %*s[", depth, "");
1965 ctx->left_padding = 1;
1968 case CMD_ID_RIGHT_PADDING:
1969 if (ctx->out->used > 0)
1971 if (MDEBUG_FLAG () > 2)
1972 MDEBUG_PRINT2 ("\n [FLT] %*s]", depth, "");
1973 g = GREF (ctx->out, ctx->out->used - 1);
1974 SET_RIGHT_PADDING (g, ctx, RightPaddingMask);
1979 MERROR (MERROR_DRAW, -1);
1983 run_stages (MFLTGlyphString *gstring, int from, int to,
1984 MFLT *flt, FontLayoutContext *ctx)
1986 MFLTGlyphString buf, *temp;
1988 int orig_from = from, orig_to = to;
1989 int from_pos, to_pos, len;
1992 MPlist *stages = flt->stages;
1994 from_pos = GREF (ctx->in, from)->from;
1995 to_pos = GREF (ctx->in, to - 1)->to;
1996 len = to_pos - from_pos;
2000 GINIT (ctx->out, ctx->out->allocated);
2001 ctx->encoded = alloca (ctx->out->allocated);
2002 if (! ctx->out->glyphs || ! ctx->encoded)
2005 for (stage_idx = 0; 1; stage_idx++)
2010 ctx->stage = (FontLayoutStage *) MPLIST_VAL (stages);
2011 table = ctx->stage->category;
2012 ctx->code_offset = ctx->combining_code = ctx->left_padding = 0;
2013 ctx->encoded_offset = from;
2014 for (i = from; i < to; i++)
2016 MFLTGlyph *g = GREF (ctx->in, i);
2017 char enc = (GET_ENCODED (g)
2018 ? (g->c > 0 ? (int) mchartable_lookup (table, g->c) : 1)
2020 ? (int) mchartable_lookup (table, g->code)
2023 ctx->encoded[i - from] = enc;
2024 if (! enc && stage_idx == 0)
2030 ctx->encoded[i - from] = '\0';
2031 ctx->match_indices[0] = from;
2032 ctx->match_indices[1] = to;
2033 for (i = 2; i < NMATCH; i++)
2034 ctx->match_indices[i] = -1;
2036 if (MDEBUG_FLAG () > 2)
2038 MDEBUG_PRINT2 ("\n [FLT] (STAGE %d \"%s\"", stage_idx,
2040 MDEBUG_PRINT (" (");
2041 for (i = from; i < to; i++)
2043 g = GREF (ctx->in, i);
2045 MDEBUG_PRINT2 ("%*s|", (i > 0), "");
2047 MDEBUG_PRINT3 ("%*s%04X", (i > 0), "", GREF (ctx->in, i)->code);
2051 result = run_command (4, INDEX_TO_CMD_ID (0), from, to, ctx);
2052 if (MDEBUG_FLAG () > 2)
2057 stages = MPLIST_NEXT (stages);
2058 /* If this is the last stage, break the loop. */
2059 if (MPLIST_TAIL_P (stages))
2062 /* Otherwise, prepare for the next stage. */
2069 GINIT (&buf, ctx->out->allocated);
2078 if (ctx->out->used > 0)
2081 int x_ppem = ctx->font->x_ppem << 6, y_ppem = ctx->font->y_ppem << 6;
2083 /* Remove separator glyphs. */
2084 for (i = 0; i < ctx->out->used;)
2086 g = GREF (ctx->out, i);
2088 GREPLACE (NULL, 0, 0, ctx->out, i, i + 1);
2093 /* Get actual glyph IDs of glyphs. */
2094 ctx->font->get_glyph_id (ctx->font, ctx->out, 0, ctx->out->used);
2096 /* Check if all characters in the range are covered by some
2097 glyph(s). If not, change <from> and <to> of glyphs to cover
2098 uncovered characters. */
2099 g_indices = alloca (sizeof (int) * len);
2102 for (i = 0; i < len; i++) g_indices[i] = -1;
2103 for (i = 0; i < ctx->out->used; i++)
2107 g = GREF (ctx->out, i);
2108 for (pos = g->from; pos <= g->to; pos++)
2109 if (g_indices[pos - from_pos] < 0)
2110 g_indices[pos - from_pos] = i;
2112 for (i = 0; i < len; i++)
2113 if (g_indices[i] < 0)
2119 for (i++; i < len && g_indices[i] < 0; i++);
2121 g = GREF (ctx->out, j);
2122 this_from = g->from;
2124 g->from = orig_from + i;
2125 } while (++j < ctx->out->used
2126 && (g = GREF (ctx->out, j))
2127 && g->from == this_from);
2133 j = g_indices[i - 1];
2134 g = GREF (ctx->out, j);
2137 g->to = orig_from + i + 1;
2139 && (g = GREF (ctx->out, j))
2140 && g->to == this_to);
2144 ctx->font->get_metrics (ctx->font, ctx->out, 0, ctx->out->used);
2146 /* Handle combining. */
2147 if (ctx->check_mask & CombiningCodeMask)
2149 MFLTGlyph *base = GREF (ctx->out, 0);
2150 int base_height = base->ascent + base->descent;
2153 for (i = 1; i < ctx->out->used; i++)
2155 if ((g = GREF (ctx->out, i))
2156 && (combining_code = GET_COMBINING_CODE (g)))
2158 int height = g->ascent + g->descent;
2159 int base_x, base_y, add_x, add_y, off_x, off_y;
2161 if (base->from > g->from)
2162 base->from = g->from;
2163 else if (base->to < g->to)
2166 base_x = COMBINING_CODE_BASE_X (combining_code);
2167 base_y = COMBINING_CODE_BASE_Y (combining_code);
2168 add_x = COMBINING_CODE_ADD_X (combining_code);
2169 add_y = COMBINING_CODE_ADD_Y (combining_code);
2170 off_x = COMBINING_CODE_OFF_X (combining_code);
2171 off_y = COMBINING_CODE_OFF_Y (combining_code);
2173 g->xoff = ((base->xadv * base_x - g->xadv * add_x) / 2
2174 + x_ppem * off_x / 100 - base->xadv);
2176 g->yoff = base_height * base_y / 2 - base->ascent;
2180 g->yoff -= height * add_y / 2 - g->ascent;
2181 g->yoff -= y_ppem * off_y / 100;
2182 if (base->lbearing > base->xadv + g->lbearing + g->xoff)
2183 base->lbearing = base->xadv + g->lbearing + g->xoff;
2184 if (base->rbearing < base->xadv + g->xadv + g->xoff)
2185 base->rbearing = base->xadv + g->xadv + g->xoff;
2186 if (base->ascent < g->ascent - g->yoff)
2187 base->ascent = g->ascent - g->yoff;
2188 if (base->descent < g->descent - g->yoff)
2189 base->descent = g->descent - g->yoff;
2190 g->xadv = g->yadv = 0;
2191 if (GET_RIGHT_PADDING (g))
2192 SET_RIGHT_PADDING (base, ctx, RightPaddingMask);
2198 base_height = g->ascent + g->descent;
2203 /* Handle padding */
2204 if (ctx->check_mask & (LeftPaddingMask | RightPaddingMask))
2205 for (i = 0; i < ctx->out->used; i++)
2207 g = GREF (ctx->out, i);
2208 if (! GET_COMBINING_CODE (g))
2210 if (GET_RIGHT_PADDING (g) && g->rbearing > g->xadv)
2212 g->xadv = g->rbearing;
2215 if (GET_LEFT_PADDING (g) && g->lbearing < 0)
2217 g->xoff += - g->lbearing;
2218 g->xadv += - g->lbearing;
2219 g->rbearing += - g->lbearing;
2227 GREPLACE (ctx->out, 0, ctx->out->used, gstring, orig_from, orig_to);
2228 to = orig_from + ctx->out->used;
2233 setup_combining_coverage (int from, int to, void *val, void *arg)
2235 int combining_class = (int) val;
2238 if (combining_class < 200)
2240 else if (combining_class <= 204)
2242 if ((combining_class % 2) == 0)
2243 category = "bcd"[(combining_class - 200) / 2];
2245 else if (combining_class <= 232)
2247 if ((combining_class % 2) == 0)
2248 category = "efghijklmnopq"[(combining_class - 208) / 2];
2250 else if (combining_class == 233)
2252 else if (combining_class == 234)
2254 else if (combining_class == 240)
2256 mchartable_set_range ((MCharTable *) arg, from, to, (void *) category);
2260 setup_combining_flt (MFLT *flt)
2263 MCharTable *combininig_class_table
2264 = mchar_get_prop_table (Mcombining_class, &type);
2266 mchartable_set_range (flt->coverage, 0, 0x10FFFF, (void *) 'u');
2267 if (combininig_class_table)
2268 mchartable_map (combininig_class_table, (void *) 0,
2269 setup_combining_coverage, flt->coverage);
2272 #define CHECK_FLT_STAGES(flt) ((flt)->stages || load_flt (flt, NULL) == 0)
2277 int m17n__flt_initialized;
2282 /* The following two are actually not exposed to a user but concealed
2283 by the macro M17N_INIT (). */
2286 m17n_init_flt (void)
2288 int mdebug_flag = MDEBUG_INIT;
2290 merror_code = MERROR_NONE;
2291 if (m17n__flt_initialized++)
2294 if (merror_code != MERROR_NONE)
2296 m17n__flt_initialized--;
2300 MDEBUG_PUSH_TIME ();
2302 Mcond = msymbol ("cond");
2303 Mrange = msymbol ("range");
2304 Mfont = msymbol ("font");
2305 Mlayouter = msymbol ("layouter");
2306 Mcombining = msymbol ("combining");
2307 Mfont_facility = msymbol ("font-facility");
2308 Mequal = msymbol ("=");
2309 Mgenerator = msymbol ("generator");
2310 Mend = msymbol ("end");
2312 MDEBUG_PRINT_TIME ("INIT", (stderr, " to initialize the flt modules."));
2317 m17n_fini_flt (void)
2319 int mdebug_flag = MDEBUG_FINI;
2321 if (m17n__flt_initialized == 0
2322 || --m17n__flt_initialized > 0)
2325 MDEBUG_PUSH_TIME ();
2327 MDEBUG_PRINT_TIME ("FINI", (stderr, " to finalize the flt modules."));
2333 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
2335 /*** @addtogroup m17nFLT */
2341 @brief Return an FLT object that has a specified name.
2343 The mflt_get () function returns an FLT object whose name is $NAME.
2346 If the operation was successful, mflt_get () returns a pointer
2347 to the found FLT object. Otherwise, it returns @c NULL. */
2350 @brief »ØÄꤵ¤ì¤¿Ì¾Á°¤ò»ý¤Ä FLT ¥ª¥Ö¥¸¥§¥¯¥È¤òÊÖ¤¹.
2352 ´Ø¿ô mflt_get () ¤Ï¡¢$NAME ¤È¤¤¤¦Ì¾Á°¤ò»ý¤Ä FLT ¥ª¥Ö¥¸¥§¥¯¥È¤òÊÖ¤¹¡£
2355 ¤â¤·À®¸ù¤¹¤ì¤Ð¡¢mflt_get () ¤Ï¸«¤Ä¤«¤Ã¤¿ FLT
2356 ¥ª¥Ö¥¸¥§¥¯¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¼ºÇÔ¤·¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤¹¡£ */
2359 mflt_get (MSymbol name)
2363 if (! flt_list && list_flt () < 0)
2365 flt = mplist_get (flt_list, name);
2366 if (! flt || ! CHECK_FLT_STAGES (flt))
2368 if (flt->name == Mcombining
2369 && ! mchartable_lookup (flt->coverage, 0))
2370 setup_combining_flt (flt);
2377 @brief Find an FLT suitable for the specified character and font.
2379 The mflt_find () function returns the most appropriate FLT for
2380 layouting character $C with font $FONT.
2383 If the operation was successful, mflt_find () returns a pointer
2384 to the found FLT object. Otherwise, it returns @c NULL. */
2387 @brief »ØÄꤵ¤ì¤¿Ê¸»ú¤È¥Õ¥©¥ó¥È¤Ë¹ç¤Ã¤¿ FLT ¤òõ¤¹.
2389 ´Ø¿ô mflt_find () ¤Ï¡¢Ê¸»ú $C ¤ò¥Õ¥©¥ó¥È $FONT
2390 ¤Ç¥ì¥¤¥¢¥¦¥È¤¹¤ë¤¿¤á¤ËºÇ¤âŬÀÚ¤Ê FLT ¤òÊÖ¤¹¡£
2393 ¤â¤·À®¸ù¤¹¤ì¤Ð¡¢mflt_find () ¤Ï¸«¤Ä¤«¤Ã¤¿ FLT
2394 ¥ª¥Ö¥¸¥§¥¯¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¼ºÇÔ¤·¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤¹¡£ */
2397 mflt_find (int c, MFLTFont *font)
2401 static MSymbol unicode_bmp = NULL, unicode_full = NULL;
2405 unicode_bmp = msymbol ("unicode-bmp");
2406 unicode_full = msymbol ("unicode-full");
2409 if (! flt_list && list_flt () < 0)
2415 MPLIST_DO (plist, flt_list)
2417 flt = MPLIST_VAL (plist);
2418 if (flt->registry != unicode_bmp
2419 && flt->registry != unicode_full)
2421 if (flt->family && flt->family != font->family)
2424 && ! mchartable_lookup (flt->coverage, c))
2428 MFLTOtfSpec *spec = &flt->otf;
2430 if (! font->check_otf)
2432 if ((spec->features[0] && spec->features[0][0] != 0xFFFFFFFF)
2433 || (spec->features[1] && spec->features[1][0] != 0xFFFFFFFF))
2436 else if (! font->check_otf (font, spec))
2446 MPLIST_DO (plist, flt_list)
2448 flt = MPLIST_VAL (plist);
2449 if (mchartable_lookup (flt->coverage, c))
2458 @brief Return the name of an FLT.
2460 The mflt_name () function returns the name of $FLT. */
2463 @brief FLT ¤Î̾Á°¤òÊÖ¤¹.
2465 ´Ø¿ô mflt_name () ¤Ï $FLT ¤Î̾Á°¤òÊÖ¤¹¡£ */
2468 mflt_name (MFLT *flt)
2470 return MSYMBOL_NAME (flt->name);
2475 @brief Return a coverage of a FLT.
2477 The mflt_coverage () function returns a char-table that contains
2478 nonzero values for characters supported by $FLT. */
2481 @brief FLT ¤ÎÈϰϤòÊÖ¤¹.
2483 ´Ø¿ô mflt_coverage () ¤Ï¡¢$FLT ¤¬¥µ¥Ý¡¼¥È¤¹¤ëʸ»ú¤ËÂФ·¤Æ
2484 0 ¤Ç¤Ê¤¤Ãͤò´Þ¤àʸ»ú¥Æ¡¼¥Ö¥ë¤òÊÖ¤¹¡£ */
2487 mflt_coverage (MFLT *flt)
2489 return flt->coverage;
2494 @brief Layout characters with an FLT.
2496 The mflt_run () function layouts characters in $GSTRING between
2497 $FROM (inclusive) and $TO (exclusive) with $FONT. If $FLT is
2498 nonzero, it is used for all the charaters. Otherwise, appropriate
2499 FLTs are automatically chosen.
2502 The operation was successful. The value is the index to the
2503 glyph, which was previously indexed by $TO, in $GSTRING->glyphs.
2506 $GSTRING->glyphs is too short to store the result. The caller can
2507 call this fucntion again with a longer $GSTRING->glyphs.
2510 Some other error occurred. */
2513 @brief FLT ¤ò»È¤Ã¤Æʸ»ú¤ò¥ì¥¤¥¢¥¦¥È¤¹¤ë.
2515 ´Ø¿ô mflt_run () ¤Ï¡¢$GSTRING Ãæ¤Î $FROM ¤«¤é $TO ľÁ°¤Þ¤Ç¤Îʸ»ú¤ò
2516 $FONT ¤òÍѤ¤¤Æ¥ì¥¤¥¢¥¦¥È¤¹¤ë¡£¤â¤· $FLT
2517 ¤¬¥¼¥í¤Ç¤Ê¤±¤ì¤Ð¡¢¤½¤ÎÃͤò¤¹¤Ù¤Æ¤Îʸ»ú¤ËÂФ·¤ÆÍѤ¤¤ë¡£
2518 ¤½¤¦¤Ç¤Ê¤±¤ì¤ÐŬÀÚ¤Ê FLT ¤ò¼«Æ°Åª¤ËÁªÂò¤¹¤ë¡£
2521 ¼Â¹ÔÀ®¸ù¤ò¼¨¤¹¡£ÊÖ¤µ¤ì¤ëÃͤϡ¢$GSTRING->glyphs Ãæ¤Ç°ÊÁ° $TO
2522 ¤Ë¤è¤Ã¤Æ¼¨¤µ¤ì¤Æ¤¤¤¿¥°¥ê¥Õ¤Ø¤Î¥¤¥ó¥Ç¥¯¥¹¤Ç¤¢¤ë¡£
2525 ·ë²Ì¤ò³ÊǼ¤¹¤ë¤Ë¤Ï $GSTRING->glyphs ¤¬Ã»¤¹¤®¤ë¤³¤È¤ò¼¨¤¹¡£
2526 ¸Æ¤Ó½Ð¤·Â¦¤Ï¡¢¤è¤êŤ¤ $GSTRING->glyphs
2527 ¤òÍѤ¤¤ÆºÆÅÙ¤³¤Î´Ø¿ô¤ò¸Æ¤Ö¤³¤È¤¬¤Ç¤¤ë¡£
2530 ¤½¤Î¾¤Î¥¨¥é¡¼¤¬µ¯¤¤¿¤³¤È¤ò¼¨¤¹¡£ */
2533 mflt_run (MFLTGlyphString *gstring, int from, int to,
2534 MFLTFont *font, MFLT *flt)
2536 FontLayoutContext ctx;
2537 int match_indices[NMATCH];
2539 MFLTGlyphString out;
2540 int auto_flt = ! flt;
2542 int this_from, this_to;
2546 /* This is usually sufficient, but if not, we retry with the larger
2547 values at most 3 times. This value is also used for the
2548 allocating size of ctx.encoded. */
2549 out.allocated = (to - from) * 4;
2551 for (i = from; i < to; i++)
2553 g = GREF (gstring, i);
2555 memset (g, 0, sizeof (MFLTGlyph));
2557 g->from = g->to = i;
2560 for (this_from = from; this_from < to;)
2564 for (this_to = this_from; this_to < to; this_to++)
2565 if (mchartable_lookup (flt->coverage, GREF (gstring, this_to)->c))
2570 if (! flt_list && list_flt () < 0)
2572 font->get_glyph_id (font, gstring, this_from, to);
2573 font->get_metrics (font, gstring, this_from, to);
2577 for (this_to = this_from; this_to < to; this_to++)
2579 c = GREF (gstring, this_to)->c;
2580 if (c >= flt_min_coverage && c <= flt_max_coverage)
2583 for (; this_to < to; this_to++)
2585 c = GREF (gstring, this_to)->c;
2587 && mchartable_lookup (((MFLT *) font->internal)->coverage, c))
2589 flt = font->internal;
2592 flt = mflt_find (c, font);
2595 if (CHECK_FLT_STAGES (flt))
2597 font->internal = flt;
2604 if (this_from < this_to)
2606 font->get_glyph_id (font, gstring, this_from, this_to);
2607 font->get_metrics (font, gstring, this_from, this_to);
2608 this_from = this_to;
2613 MDEBUG_PRINT1 (" [FLT] (%s", MSYMBOL_NAME (flt->name));
2615 for (; this_to < to; this_to++)
2616 if (! mchartable_lookup (flt->coverage, GREF (gstring, this_to)->c))
2622 MDEBUG_PRINT1 (" (%s)", MSYMBOL_NAME (font->family));
2623 MDEBUG_PRINT ("\n [FLT] (SOURCE");
2624 for (i = this_from, j = 0; i < this_to; i++, j++)
2626 if (j > 0 && j % 8 == 0)
2627 MDEBUG_PRINT ("\n [FLT] ");
2628 MDEBUG_PRINT1 (" %04X", GREF (gstring, i)->c);
2633 for (i = 0; i < 3; i++)
2636 memset (&ctx, 0, sizeof ctx);
2637 ctx.match_indices = match_indices;
2639 ctx.cluster_begin_idx = -1;
2642 j = run_stages (gstring, this_from, this_to, flt, &ctx);
2656 MDEBUG_PRINT ("\n [FLT] (RESULT");
2657 if (MDEBUG_FLAG () > 1)
2658 for (i = 0; this_from < this_to; this_from++, i++)
2660 if (i > 0 && i % 4 == 0)
2661 MDEBUG_PRINT ("\n [FLT] ");
2662 g = GREF (gstring, this_from);
2663 MDEBUG_PRINT4 (" (%04X %d %d %d)",
2664 g->code, g->xadv, g->xoff, g->yoff);
2667 for (; this_from < this_to; this_from++)
2668 MDEBUG_PRINT1 (" %04X", GREF (gstring, this_from)->code);
2669 MDEBUG_PRINT ("))\n");
2671 this_from = this_to;
2676 int len = to - from;
2679 memcpy (((char *) out.glyphs),
2680 ((char *) gstring->glyphs) + gstring->glyph_size * from,
2681 gstring->glyph_size * len);
2682 for (i = from, j = to; i < to;)
2684 for (k = i + 1, j--; k < to && GREF (&out, k)->xadv == 0;
2686 GCPY (&out, i, (k - i), gstring, j);
2695 /* for debugging... */
2698 dump_flt_cmd (FontLayoutStage *stage, int id, int indent)
2700 char *prefix = (char *) alloca (indent + 1);
2702 memset (prefix, 32, indent);
2706 fprintf (stderr, "0x%02X", id);
2707 else if (id <= CMD_ID_OFFSET_INDEX)
2709 int idx = CMD_ID_TO_INDEX (id);
2710 FontLayoutCmd *cmd = stage->cmds + idx;
2712 if (cmd->type == FontLayoutCmdTypeRule)
2714 FontLayoutCmdRule *rule = &cmd->body.rule;
2717 fprintf (stderr, "(rule ");
2718 if (rule->src_type == SRC_REGEX)
2719 fprintf (stderr, "\"%s\"", rule->src.re.pattern);
2720 else if (rule->src_type == SRC_INDEX)
2721 fprintf (stderr, "%d", rule->src.match_idx);
2722 else if (rule->src_type == SRC_SEQ)
2723 fprintf (stderr, "(seq)");
2724 else if (rule->src_type == SRC_RANGE)
2725 fprintf (stderr, "(range)");
2727 fprintf (stderr, "(invalid src)");
2729 for (i = 0; i < rule->n_cmds; i++)
2731 fprintf (stderr, "\n%s ", prefix);
2732 dump_flt_cmd (stage, rule->cmd_ids[i], indent + 2);
2734 fprintf (stderr, ")");
2736 else if (cmd->type == FontLayoutCmdTypeCond)
2738 FontLayoutCmdCond *cond = &cmd->body.cond;
2741 fprintf (stderr, "(cond");
2742 for (i = 0; i < cond->n_cmds; i++)
2744 fprintf (stderr, "\n%s ", prefix);
2745 dump_flt_cmd (stage, cond->cmd_ids[i], indent + 2);
2747 fprintf (stderr, ")");
2749 else if (cmd->type == FontLayoutCmdTypeOTF)
2751 fprintf (stderr, "(otf)");
2754 fprintf (stderr, "(error-command)");
2756 else if (id <= CMD_ID_OFFSET_COMBINING)
2757 fprintf (stderr, "cominging-code");
2759 fprintf (stderr, "(predefiend %d)", id);
2763 @brief Dump a Font Layout Table.
2765 The mdebug_dump_flt () function prints the Font Layout Table $FLT
2766 in a human readable way to the stderr. $INDENT specifies how many
2767 columns to indent the lines but the first one.
2770 This function returns $FLT. */
2773 mdebug_dump_flt (MFLT *flt, int indent)
2775 char *prefix = (char *) alloca (indent + 1);
2779 memset (prefix, 32, indent);
2781 fprintf (stderr, "(flt");
2782 MPLIST_DO (plist, flt->stages)
2784 FontLayoutStage *stage = (FontLayoutStage *) MPLIST_VAL (plist);
2787 fprintf (stderr, "\n%s (stage %d", prefix, stage_idx);
2788 for (i = 0; i < stage->used; i++)
2790 fprintf (stderr, "\n%s ", prefix);
2791 dump_flt_cmd (stage, INDEX_TO_CMD_ID (i), indent + 4);
2793 fprintf (stderr, ")");
2796 fprintf (stderr, ")");