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_idx >= 0) \
381 if (ctx->cluster_begin_pos > (g)->from) \
382 ctx->cluster_begin_pos = (g)->from; \
383 if (ctx->cluster_end_pos < (g)->to) \
384 ctx->cluster_end_pos = (g)->to; \
388 enum FontLayoutCmdRuleSrcType
400 enum FontLayoutCmdRuleSrcType src_type;
417 MFLTOtfSpec otf_spec;
427 /* Beginning and end indices of series of SEQ commands. */
428 int seq_beg, seq_end;
429 /* Range of the first character appears in the above series. */
430 int seq_from, seq_to;
436 enum FontLayoutCmdType
438 FontLayoutCmdTypeRule,
439 FontLayoutCmdTypeCond,
440 FontLayoutCmdTypeOTF,
446 enum FontLayoutCmdType type;
448 FontLayoutCmdRule rule;
449 FontLayoutCmdCond cond;
456 MCharTable *category;
468 MCharTable *coverage;
472 /* Font layout table loader */
474 static int parse_otf_command (MSymbol symbol, MFLTOtfSpec *spec);
476 /* Load a category table from PLIST. PLIST has this form:
477 PLIST ::= ( FROM-CODE TO-CODE ? CATEGORY-CHAR ) *
481 load_category_table (MPlist *plist)
485 table = mchartable (Minteger, (void *) 0);
487 MPLIST_DO (plist, plist)
490 int from, to, category_code;
492 if (! MPLIST_PLIST (plist))
493 MERROR (MERROR_FONT, NULL);
494 elt = MPLIST_PLIST (plist);
495 if (! MPLIST_INTEGER_P (elt))
496 MERROR (MERROR_FONT, NULL);
497 from = MPLIST_INTEGER (elt);
498 elt = MPLIST_NEXT (elt);
499 if (! MPLIST_INTEGER_P (elt))
500 MERROR (MERROR_FONT, NULL);
501 to = MPLIST_INTEGER (elt);
502 elt = MPLIST_NEXT (elt);
503 if (MPLIST_TAIL_P (elt))
510 if (! MPLIST_INTEGER_P (elt))
511 MERROR (MERROR_FONT, NULL);
512 category_code = MPLIST_INTEGER (elt);
514 if (! isalnum (category_code))
515 MERROR (MERROR_FONT, NULL);
518 mchartable_set (table, from, (void *) category_code);
520 mchartable_set_range (table, from, to, (void *) category_code);
527 gen_otf_tag (char *p)
529 unsigned int tag = 0;
532 for (i = 0; i < 4 && *p; i++, p++)
533 tag = (tag << 8) | *p;
535 tag = (tag << 8) | 0x20;
540 otf_count_features (char *p, char *end, char stopper, int *count)
545 if (*p != stopper && *p != '\0')
552 if (*p == stopper || *p == '\0')
566 if (*p == stopper || *p == '\0')
578 otf_store_features (char *p, char *end, unsigned *buf)
583 for (i = 0; p < end;)
586 buf[i++] = 0xFFFFFFFF, p += 2, negative = 1;
590 buf[i++] = 0xFFFFFFFF;
591 buf[i++] = gen_otf_tag (p + 1), p += 6;
594 buf[i++] = gen_otf_tag (p), p += 5;
600 parse_otf_command (MSymbol symbol, MFLTOtfSpec *spec)
602 char *str = MSYMBOL_NAME (symbol);
603 char *end = str + MSYMBOL_NAMELEN (symbol);
604 unsigned int script, langsys;
606 int gsub_count = 0, gpos_count = 0;
609 memset (spec, 0, sizeof (MFLTOtfSpec));
612 str += 5; /* skip the heading ":otf=" */
613 script = gen_otf_tag (str);
617 langsys = gen_otf_tag (str);
624 /* Apply all GSUB features. */
629 str = otf_count_features (p, end, '+', &gsub_count);
631 MERROR (MERROR_FLT, -1);
635 /* Apply all GPOS features. */
640 str = otf_count_features (p, end, '\0', &gpos_count);
642 MERROR (MERROR_FLT, -1);
645 spec->script = script;
646 spec->langsys = langsys;
649 spec->features[0] = malloc (sizeof (int) * (gsub_count + 1));
650 if (! spec->features[0])
653 otf_store_features (gsub + 1, gpos, spec->features[0]);
655 spec->features[0][0] = 0xFFFFFFFF, spec->features[0][1] = 0;
659 spec->features[1] = malloc (sizeof (int) * (gpos_count + 1));
660 if (! spec->features[1])
662 if (spec->features[0])
663 free (spec->features[0]);
667 otf_store_features (gpos + 1, str, spec->features[1]);
669 spec->features[1][0] = 0xFFFFFFFF, spec->features[1][1] = 0;
675 /* Parse OTF command name NAME and store the result in CMD.
677 :SCRIPT[/[LANGSYS][=[GSUB-FEATURES][+GPOS-FEATURES]]]
678 where GSUB-FEATURES and GPOS-FEATURES have this form:
679 [FEATURE[,FEATURE]*] | ' ' */
682 load_otf_command (FontLayoutCmd *cmd, MSymbol sym)
684 char *name = MSYMBOL_NAME (sym);
689 /* This is old format of "otf:...". Change it to ":otf=...". */
690 char *str = alloca (MSYMBOL_NAMELEN (sym) + 2);
692 sprintf (str, ":otf=");
693 strcat (str, name + 4);
697 result = parse_otf_command (sym, &cmd->body.otf);
700 cmd->type = FontLayoutCmdTypeOTF;
705 /* Read a decimal number from STR preceded by one of "+-><". '+' and
706 '>' means a plus sign, '-' and '<' means a minus sign. If the
707 number is greater than 127, limit it to 127. */
710 read_decimal_number (char **str)
713 int sign = (*p == '-' || *p == '<') ? -1 : 1;
717 while (*p >= '0' && *p <= '9')
718 n = n * 10 + *p++ - '0';
722 return (n < 127 ? n * sign : 127 * sign);
726 /* Read a horizontal and vertical combining positions from STR, and
727 store them in the place pointed by X and Y. The horizontal
728 position left, center, and right are represented by 0, 1, and 2
729 respectively. The vertical position top, center, bottom, and base
730 are represented by 0, 1, 2, and 3 respectively. If successfully
731 read, return 0, else return -1. */
734 read_combining_position (char *str, int *x, int *y)
739 /* Vertical position comes first. */
740 for (i = 0; i < 4; i++)
749 /* Then comse horizontal position. */
750 for (i = 0; i < 3; i++)
760 /* Return a combining code corresponding to SYM. */
763 get_combining_command (MSymbol sym)
765 char *str = msymbol_name (sym);
766 int base_x, base_y, add_x, add_y, off_x, off_y;
769 if (read_combining_position (str, &base_x, &base_y) < 0)
780 if (c == '+' || c == '-')
782 off_y = read_decimal_number (&str) + 128;
787 if (c == '<' || c == '>')
788 off_x = read_decimal_number (&str) + 128;
792 if (read_combining_position (str, &add_x, &add_y) < 0)
795 c = MAKE_COMBINING_CODE (base_y, base_x, add_y, add_x, off_y, off_x);
796 return (COMBINING_CODE_TO_CMD_ID (c));
800 /* Load a command from PLIST into STAGE, and return that
801 identification number. If ID is not INVALID_CMD_ID, that means we
802 are loading a top level command or a macro. In that case, use ID
803 as the identification number of the command. Otherwise, generate a
804 new id number for the command. MACROS is a list of raw macros. */
807 load_command (FontLayoutStage *stage, MPlist *plist,
808 MPlist *macros, int id)
813 if (MPLIST_INTEGER_P (plist))
815 int code = MPLIST_INTEGER (plist);
818 MERROR (MERROR_DRAW, INVALID_CMD_ID);
821 else if (MPLIST_PLIST_P (plist))
823 /* PLIST ::= ( cond ... ) | ( STRING ... ) | ( INTEGER ... )
824 | ( ( INTEGER INTEGER ) ... )
825 | ( ( range INTEGER INTEGER ) ... )
826 | ( ( font-facilty [ INTEGER ] ) ... )
827 | ( ( font-facilty OTF-SPEC ) ... ) */
828 MPlist *elt = MPLIST_PLIST (plist);
829 int len = MPLIST_LENGTH (elt) - 1;
832 if (id == INVALID_CMD_ID)
835 id = INDEX_TO_CMD_ID (stage->used);
836 MLIST_APPEND1 (stage, cmds, dummy, MERROR_DRAW);
838 cmd = stage->cmds + CMD_ID_TO_INDEX (id);
840 if (MPLIST_SYMBOL_P (elt))
842 FontLayoutCmdCond *cond;
844 if (MPLIST_SYMBOL (elt) != Mcond)
845 MERROR (MERROR_DRAW, INVALID_CMD_ID);
846 elt = MPLIST_NEXT (elt);
847 cmd->type = FontLayoutCmdTypeCond;
848 cond = &cmd->body.cond;
849 cond->seq_beg = cond->seq_end = -1;
850 cond->seq_from = cond->seq_to = 0;
852 MTABLE_CALLOC (cond->cmd_ids, len, MERROR_DRAW);
853 for (i = 0; i < len; i++, elt = MPLIST_NEXT (elt))
855 int this_id = load_command (stage, elt, macros, INVALID_CMD_ID);
857 if (this_id == INVALID_CMD_ID || this_id == -2)
858 MERROR (MERROR_DRAW, this_id);
859 /* The above load_command may relocate stage->cmds. */
860 cmd = stage->cmds + CMD_ID_TO_INDEX (id);
861 cond = &cmd->body.cond;
862 cond->cmd_ids[i] = this_id;
863 if (this_id <= CMD_ID_OFFSET_INDEX)
865 FontLayoutCmd *this_cmd
866 = stage->cmds + CMD_ID_TO_INDEX (this_id);
868 if (this_cmd->type == FontLayoutCmdTypeRule
869 && this_cmd->body.rule.src_type == SRC_SEQ)
871 int first_char = this_cmd->body.rule.src.seq.codes[0];
873 if (cond->seq_beg < 0)
875 /* The first SEQ command. */
877 cond->seq_from = cond->seq_to = first_char;
879 else if (cond->seq_end < 0)
881 /* The following SEQ command. */
882 if (cond->seq_from > first_char)
883 cond->seq_from = first_char;
884 else if (cond->seq_to < first_char)
885 cond->seq_to = first_char;
890 if (cond->seq_beg >= 0 && cond->seq_end < 0)
891 /* The previous one is the last SEQ command. */
897 if (cond->seq_beg >= 0 && cond->seq_end < 0)
898 /* The previous one is the last SEQ command. */
902 if (cond->seq_beg >= 0 && cond->seq_end < 0)
903 /* The previous one is the last SEQ command. */
908 cmd->type = FontLayoutCmdTypeRule;
909 if (MPLIST_MTEXT_P (elt))
911 MText *mt = MPLIST_MTEXT (elt);
912 char *str = (char *) MTEXT_DATA (mt);
916 mtext_ins_char (mt, 0, '^', 1);
917 str = (char *) MTEXT_DATA (mt);
919 if (regcomp (&cmd->body.rule.src.re.preg, str, REG_EXTENDED))
920 MERROR (MERROR_FONT, INVALID_CMD_ID);
921 cmd->body.rule.src_type = SRC_REGEX;
922 cmd->body.rule.src.re.pattern = strdup (str);
924 else if (MPLIST_INTEGER_P (elt))
926 cmd->body.rule.src_type = SRC_INDEX;
927 cmd->body.rule.src.match_idx = MPLIST_INTEGER (elt);
929 else if (MPLIST_PLIST_P (elt))
931 MPlist *pl = MPLIST_PLIST (elt), *p;
932 int size = MPLIST_LENGTH (pl);
934 if (MPLIST_INTEGER_P (pl))
938 cmd->body.rule.src_type = SRC_SEQ;
939 cmd->body.rule.src.seq.n_codes = size;
940 MTABLE_CALLOC (cmd->body.rule.src.seq.codes, size,
942 for (i = 0; i < size; i++, pl = MPLIST_NEXT (pl))
944 if (! MPLIST_INTEGER_P (pl))
945 MERROR (MERROR_DRAW, INVALID_CMD_ID);
946 cmd->body.rule.src.seq.codes[i]
947 = (unsigned) MPLIST_INTEGER (pl);
950 else if (MPLIST_SYMBOL_P (pl))
952 if (MPLIST_SYMBOL (pl) == Mrange)
955 MERROR (MERROR_FLT, INVALID_CMD_ID);
956 cmd->body.rule.src_type = SRC_RANGE;
957 pl = MPLIST_NEXT (pl);
958 if (! MPLIST_INTEGER_P (pl))
959 MERROR (MERROR_DRAW, INVALID_CMD_ID);
960 cmd->body.rule.src.range.from
961 = (unsigned) MPLIST_INTEGER (pl);
962 pl = MPLIST_NEXT (pl);
963 if (! MPLIST_INTEGER_P (pl))
964 MERROR (MERROR_DRAW, INVALID_CMD_ID);
965 cmd->body.rule.src.range.to
966 = (unsigned) MPLIST_INTEGER (pl);
968 else if (MPLIST_SYMBOL (pl) == Mfont_facility)
970 FontLayoutCmdRule *rule = &cmd->body.rule;
972 pl = MPLIST_NEXT (pl);
973 if (MPLIST_SYMBOL_P (pl))
975 MSymbol sym = MPLIST_SYMBOL (pl);
976 char *otf_spec = MSYMBOL_NAME (sym);
978 if (otf_spec[0] == ':' && otf_spec[1] == 'o'
979 && otf_spec[2] == 't' && otf_spec[3] == 'f')
980 parse_otf_command (sym, &rule->src.facility.otf_spec);
982 MERROR (MERROR_FLT, INVALID_CMD_ID);
983 rule->src_type = SRC_OTF_SPEC;
984 pl = MPLIST_NEXT (pl);
986 else if (MPLIST_TAIL_P (pl))
987 MERROR (MERROR_FLT, INVALID_CMD_ID);
989 rule->src_type = SRC_HAS_GLYPH;
990 rule->src.facility.len = 0;
993 if (! MPLIST_INTEGER_P (p)
994 && (MPLIST_SYMBOL_P (p)
995 ? MPLIST_SYMBOL (p) != Mequal
997 MERROR (MERROR_FLT, INVALID_CMD_ID);
998 rule->src.facility.len++;
1000 rule->src.facility.codes = pl;
1001 M17N_OBJECT_REF (pl);
1005 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1008 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1010 elt = MPLIST_NEXT (elt);
1011 cmd->body.rule.n_cmds = len;
1012 MTABLE_CALLOC (cmd->body.rule.cmd_ids, len, MERROR_DRAW);
1013 for (i = 0; i < len; i++, elt = MPLIST_NEXT (elt))
1015 int this_id = load_command (stage, elt, macros, INVALID_CMD_ID);
1017 if (this_id == INVALID_CMD_ID || this_id == -2)
1018 MERROR (MERROR_DRAW, this_id);
1019 /* The above load_command may relocate stage->cmds. */
1020 cmd = stage->cmds + CMD_ID_TO_INDEX (id);
1021 cmd->body.rule.cmd_ids[i] = this_id;
1025 else if (MPLIST_SYMBOL_P (plist))
1028 MSymbol sym = MPLIST_SYMBOL (plist);
1029 char *name = msymbol_name (sym);
1030 int len = strlen (name);
1034 && ((name[0] == 'o' && name[1] == 't'
1035 && name[2] == 'f' && name[3] == ':')
1036 || (name[0] == ':' && name[1] == 'o' && name[2] == 't'
1037 && name[3] == 'f' && name[4] == '=')))
1039 result = load_otf_command (&cmd, sym);
1042 if (id == INVALID_CMD_ID)
1044 id = INDEX_TO_CMD_ID (stage->used);
1045 MLIST_APPEND1 (stage, cmds, cmd, MERROR_DRAW);
1048 stage->cmds[CMD_ID_TO_INDEX (id)] = cmd;
1056 else if (*name == '*')
1057 return CMD_ID_REPEAT;
1058 else if (*name == '<')
1059 return CMD_ID_CLUSTER_BEGIN;
1060 else if (*name == '>')
1061 return CMD_ID_CLUSTER_END;
1062 else if (*name == '|')
1063 return CMD_ID_SEPARATOR;
1064 else if (*name == '[')
1065 return CMD_ID_LEFT_PADDING;
1066 else if (*name == ']')
1067 return CMD_ID_RIGHT_PADDING;
1073 id = get_combining_command (sym);
1079 MPLIST_DO (elt, macros)
1081 if (sym == MPLIST_SYMBOL (MPLIST_PLIST (elt)))
1083 id = INDEX_TO_CMD_ID (i);
1084 if (stage->cmds[i].type == FontLayoutCmdTypeMAX)
1085 id = load_command (stage, MPLIST_NEXT (MPLIST_PLIST (elt)),
1091 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1094 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1100 free_flt_command (FontLayoutCmd *cmd)
1102 if (cmd->type == FontLayoutCmdTypeRule)
1104 FontLayoutCmdRule *rule = &cmd->body.rule;
1106 if (rule->src_type == SRC_REGEX)
1108 free (rule->src.re.pattern);
1109 regfree (&rule->src.re.preg);
1111 else if (rule->src_type == SRC_SEQ)
1112 free (rule->src.seq.codes);
1113 free (rule->cmd_ids);
1115 else if (cmd->type == FontLayoutCmdTypeCond)
1116 free (cmd->body.cond.cmd_ids);
1117 else if (cmd->type == FontLayoutCmdTypeOTF)
1119 if (cmd->body.otf.features[0])
1120 free (cmd->body.otf.features[0]);
1121 if (cmd->body.otf.features[1])
1122 free (cmd->body.otf.features[1]);
1126 /* Load a generator from PLIST into a newly allocated FontLayoutStage,
1127 and return it. PLIST has this form:
1128 PLIST ::= ( COMMAND ( CMD-NAME COMMAND ) * )
1131 static FontLayoutStage *
1132 load_generator (MPlist *plist)
1134 FontLayoutStage *stage;
1136 FontLayoutCmd dummy;
1139 MSTRUCT_CALLOC (stage, MERROR_DRAW);
1140 MLIST_INIT1 (stage, cmds, 32);
1141 dummy.type = FontLayoutCmdTypeMAX;
1142 MLIST_APPEND1 (stage, cmds, dummy, MERROR_FONT);
1143 MPLIST_DO (elt, MPLIST_NEXT (plist))
1145 if (! MPLIST_PLIST_P (elt))
1146 MERROR (MERROR_FONT, NULL);
1147 pl = MPLIST_PLIST (elt);
1148 if (! MPLIST_SYMBOL_P (pl))
1149 MERROR (MERROR_FONT, NULL);
1150 MLIST_APPEND1 (stage, cmds, dummy, MERROR_FONT);
1153 /* Load the first command from PLIST into STAGE->cmds[0]. Macros
1154 called in the first command are also loaded from MPLIST_NEXT
1155 (PLIST) into STAGE->cmds[n]. */
1156 result = load_command (stage, plist, MPLIST_NEXT (plist),
1157 INDEX_TO_CMD_ID (0));
1158 if (result == INVALID_CMD_ID || result == -2)
1160 MLIST_FREE1 (stage, cmds);
1169 /* Load stages of the font layout table FLT. */
1172 load_flt (MFLT *flt, MPlist *key_list)
1174 MPlist *top, *plist, *pl, *p;
1175 MCharTable *category = NULL;
1179 top = (MPlist *) mdatabase__load_for_keys (flt->mdb, key_list);
1181 top = (MPlist *) mdatabase_load (flt->mdb);
1184 if (! MPLIST_PLIST_P (top))
1186 M17N_OBJECT_UNREF (top);
1187 MERROR (MERROR_FLT, -1);
1192 plist = mdatabase__props (flt->mdb);
1194 MERROR (MERROR_FLT, -1);
1195 MPLIST_DO (plist, plist)
1196 if (MPLIST_PLIST_P (plist))
1198 pl = MPLIST_PLIST (plist);
1199 if (! MPLIST_SYMBOL_P (pl)
1200 || MPLIST_SYMBOL (pl) != Mfont)
1202 pl = MPLIST_NEXT (pl);
1203 if (! MPLIST_PLIST_P (pl))
1205 p = MPLIST_PLIST (pl);
1206 if (! MPLIST_SYMBOL_P (p))
1208 p = MPLIST_NEXT (p);
1209 if (! MPLIST_SYMBOL_P (p))
1211 flt->family = MPLIST_SYMBOL (p);
1212 MPLIST_DO (p, MPLIST_NEXT (p))
1213 if (MPLIST_SYMBOL_P (p))
1215 sym = MPLIST_SYMBOL (p);
1216 if (MSYMBOL_NAME (sym)[0] != ':')
1217 flt->registry = sym, sym = Mnil;
1223 char *otf_spec = MSYMBOL_NAME (sym);
1225 if (otf_spec[0] == ':' && otf_spec[1] == 'o'
1226 && otf_spec[2] == 't' && otf_spec[3] == 'f')
1227 parse_otf_command (sym, &flt->otf);
1232 MPLIST_DO (plist, top)
1234 if (MPLIST_SYMBOL_P (plist)
1235 && MPLIST_SYMBOL (plist) == Mend)
1237 mplist_set (plist, Mnil, NULL);
1240 if (! MPLIST_PLIST (plist))
1242 pl = MPLIST_PLIST (plist);
1243 if (! MPLIST_SYMBOL_P (pl))
1245 sym = MPLIST_SYMBOL (pl);
1246 pl = MPLIST_NEXT (pl);
1249 if (sym == Mcategory)
1252 M17N_OBJECT_UNREF (category);
1253 else if (flt->coverage)
1255 category = flt->coverage;
1258 category = load_category_table (pl);
1259 if (! flt->coverage)
1261 flt->coverage = category;
1262 M17N_OBJECT_REF (category);
1265 else if (sym == Mgenerator)
1267 FontLayoutStage *stage;
1271 stage = load_generator (pl);
1274 stage->category = category;
1275 M17N_OBJECT_REF (category);
1277 flt->stages = mplist ();
1278 mplist_add (flt->stages, Mt, stage);
1282 M17N_OBJECT_UNREF (category);
1283 if (! MPLIST_TAIL_P (plist))
1285 M17N_OBJECT_UNREF (top);
1286 M17N_OBJECT_UNREF (flt->stages);
1287 MERROR (MERROR_FLT, -1);
1289 M17N_OBJECT_UNREF (top);
1295 free_flt_stage (FontLayoutStage *stage)
1299 M17N_OBJECT_UNREF (stage->category);
1300 for (i = 0; i < stage->used; i++)
1301 free_flt_command (stage->cmds + i);
1302 MLIST_FREE1 (stage, cmds);
1313 MPLIST_DO (plist, flt_list)
1315 MFLT *flt = MPLIST_VAL (plist);
1318 M17N_OBJECT_UNREF (flt->coverage);
1321 MPLIST_DO (pl, MPLIST_NEXT (flt->stages))
1322 free_flt_stage (MPLIST_VAL (pl));
1323 M17N_OBJECT_UNREF (flt->stages);
1326 M17N_OBJECT_UNREF (flt_list);
1333 MPlist *plist, *key_list = NULL;
1337 if (! (plist = mdatabase_list (Mfont, Mlayouter, Mnil, Mnil)))
1339 if (! (flt_list = mplist ()))
1341 if (! (key_list = mplist ()))
1343 if (! mplist_add (key_list, Mcategory, Mt))
1346 MPLIST_DO (pl, plist)
1348 MDatabase *mdb = MPLIST_VAL (pl);
1349 MSymbol *tags = mdatabase_tag (mdb);
1352 if (! MSTRUCT_CALLOC_SAFE (flt))
1354 flt->name = tags[2];
1356 if (load_flt (flt, key_list) < 0)
1360 if (MPLIST_TAIL_P (flt_list))
1362 flt_min_coverage = mchartable_min_char (flt->coverage);
1363 flt_max_coverage = mchartable_max_char (flt->coverage);
1369 c = mchartable_min_char (flt->coverage);
1370 if (flt_min_coverage > c)
1371 flt_min_coverage = c;
1372 c = mchartable_max_char (flt->coverage);
1373 if (flt_max_coverage < c)
1374 flt_max_coverage = c;
1376 if (! mplist_push (flt_list, flt->name, flt))
1386 M17N_OBJECT_UNREF (plist);
1387 M17N_OBJECT_UNREF (key_list);
1391 /* FLS (Font Layout Service) */
1393 /* Structure to hold information about a context of FLS. */
1397 /* Pointer to the current stage. */
1398 FontLayoutStage *stage;
1400 /* Pointer to the font. */
1403 /* Input and output glyph string. */
1404 MFLTGlyphString *in, *out;
1406 /* Encode each character or code of a glyph by the current category
1407 table into this array. An element is a category letter used for
1408 a regular expression matching. */
1413 int cluster_begin_idx;
1414 int cluster_begin_pos;
1415 int cluster_end_pos;
1419 } FontLayoutContext;
1421 static int run_command (int, int, int, int, FontLayoutContext *);
1426 run_rule (int depth,
1427 FontLayoutCmdRule *rule, int from, int to, FontLayoutContext *ctx)
1429 int *saved_match_indices = ctx->match_indices;
1430 int match_indices[NMATCH * 2];
1433 int orig_from = from;
1435 if (rule->src_type == SRC_SEQ)
1439 len = rule->src.seq.n_codes;
1440 if (len > (to - from))
1442 for (i = 0; i < len; i++)
1443 if (rule->src.seq.codes[i] != GREF (ctx->in, from + i)->code)
1448 if (MDEBUG_FLAG () > 2)
1449 MDEBUG_PRINT3 ("\n [FLT] %*s(SEQ 0x%X", depth, "",
1450 rule->src.seq.codes[0]);
1452 else if (rule->src_type == SRC_RANGE)
1458 head = GREF (ctx->in, from)->code;
1459 if (head < rule->src.range.from || head > rule->src.range.to)
1461 ctx->code_offset = head - rule->src.range.from;
1463 if (MDEBUG_FLAG () > 2)
1464 MDEBUG_PRINT4 ("\n [FLT] %*s(RANGE 0x%X-0x%X", depth, "",
1465 rule->src.range.from, rule->src.range.to);
1467 else if (rule->src_type == SRC_REGEX)
1469 regmatch_t pmatch[NMATCH];
1475 saved_code = ctx->encoded[to - ctx->encoded_offset];
1476 ctx->encoded[to - ctx->encoded_offset] = '\0';
1477 result = regexec (&(rule->src.re.preg),
1478 ctx->encoded + (from - ctx->encoded_offset),
1480 if (result == 0 && pmatch[0].rm_so == 0)
1482 if (MDEBUG_FLAG () > 2)
1483 MDEBUG_PRINT5 ("\n [FLT] %*s(REGEX \"%s\" \"%s\" %d", depth, "",
1484 rule->src.re.pattern,
1485 ctx->encoded + (from - ctx->encoded_offset),
1487 ctx->encoded[to - ctx->encoded_offset] = saved_code;
1488 for (i = 0; i < NMATCH; i++)
1490 if (pmatch[i].rm_so < 0)
1491 match_indices[i * 2] = match_indices[i * 2 + 1] = -1;
1494 match_indices[i * 2] = from + pmatch[i].rm_so;
1495 match_indices[i * 2 + 1] = from + pmatch[i].rm_eo;
1498 ctx->match_indices = match_indices;
1499 to = match_indices[1];
1503 ctx->encoded[to - ctx->encoded_offset] = saved_code;
1507 else if (rule->src_type == SRC_INDEX)
1509 if (rule->src.match_idx >= NMATCH)
1511 from = ctx->match_indices[rule->src.match_idx * 2];
1514 to = ctx->match_indices[rule->src.match_idx * 2 + 1];
1515 if (MDEBUG_FLAG () > 2)
1516 MDEBUG_PRINT3 ("\n [FLT] %*s(SUBPART %d", depth, "",
1517 rule->src.match_idx);
1519 else if (rule->src_type == SRC_HAS_GLYPH
1520 || rule->src_type == SRC_OTF_SPEC)
1522 static MFLTGlyphString gstring;
1526 if (rule->src.facility.len > 0)
1528 if (! gstring.glyph_size)
1530 gstring.glyph_size = ctx->in->glyph_size;
1531 gstring.glyphs = calloc (rule->src.facility.len,
1532 gstring.glyph_size);
1533 gstring.allocated = rule->src.facility.len;
1534 gstring.used = rule->src.facility.len;
1536 else if (rule->src.facility.len < gstring.allocated)
1538 gstring.glyphs = realloc (gstring.glyphs,
1540 * rule->src.facility.len);
1541 gstring.allocated = rule->src.facility.len;
1542 gstring.used = rule->src.facility.len;
1545 for (i = 0, p = rule->src.facility.codes, idx = from;
1546 i < rule->src.facility.len; i++, p = MPLIST_NEXT (p))
1548 if (MPLIST_INTEGER_P (p))
1550 GREF (&gstring, i)->code = MPLIST_INTEGER (p);
1551 GREF (&gstring, i)->encoded = 0;
1555 GREF (&gstring, i)->code = GREF (ctx->in, idx)->code;
1556 GREF (&gstring, i)->encoded = GREF (ctx->in, idx)->encoded;
1562 if (MDEBUG_FLAG () > 2)
1564 if (rule->src_type == SRC_HAS_GLYPH)
1565 MDEBUG_PRINT2 ("\n [FLT] %*s(HAS-GLYPH", depth, "");
1567 MDEBUG_PRINT2 ("\n [FLT] %*s(OTF-SPEC", depth, "");
1568 for (i = 0; i < rule->src.facility.len; i++)
1569 MDEBUG_PRINT1 (" %04X", GREF (&gstring, i)->code);
1571 if (ctx->font->get_glyph_id (ctx->font, &gstring, 0,
1572 rule->src.facility.len) < 0)
1574 MDEBUG_PRINT (") FAIL!");
1577 if (rule->src_type == SRC_OTF_SPEC)
1579 MFLTOtfSpec *spec = &rule->src.facility.otf_spec;
1581 if (! ctx->font->check_otf)
1583 if ((spec->features[0] && spec->features[0][0] != 0xFFFFFFFF)
1584 || (spec->features[1] && spec->features[1][0] != 0xFFFFFFFF))
1589 if (rule->src.facility.len == 0)
1591 if (! ctx->font->check_otf (ctx->font, spec))
1596 int prev_out_used = ctx->out->used, out_used;
1597 MFLTGlyphAdjustment *adjustment;
1599 adjustment = alloca ((sizeof *adjustment)
1600 * (ctx->out->allocated - ctx->out->used));
1602 MERROR (MERROR_FLT, -1);
1603 memset (adjustment, 0,
1604 (sizeof *adjustment)
1605 * (ctx->out->allocated - ctx->out->used));
1606 ctx->font->drive_otf (ctx->font, &rule->src.facility.otf_spec,
1607 &gstring, 0, rule->src.facility.len,
1610 out_used = ctx->out->used;
1611 ctx->out->used = prev_out_used;
1612 if (rule->src.facility.len == out_used - prev_out_used)
1614 for (i = prev_out_used; i < out_used; i++)
1616 if (GREF (&gstring, i - prev_out_used)->code
1617 != GREF (ctx->out, i)->code)
1619 if (adjustment[i - prev_out_used].set)
1632 for (i = 0; i < rule->n_cmds; i++)
1636 if (rule->cmd_ids[i] == CMD_ID_REPEAT)
1642 pos = run_command (depth, rule->cmd_ids[i], from, to, ctx);
1645 consumed = pos > from;
1650 ctx->match_indices = saved_match_indices;
1651 if (MDEBUG_FLAG () > 2)
1653 return (rule->src_type == SRC_INDEX ? orig_from : to);
1657 run_cond (int depth,
1658 FontLayoutCmdCond *cond, int from, int to, FontLayoutContext *ctx)
1662 if (MDEBUG_FLAG () > 2)
1663 MDEBUG_PRINT2 ("\n [FLT] %*s(COND", depth, "");
1665 for (i = 0; i < cond->n_cmds; i++)
1667 /* TODO: Write a code for optimization utilizaing the info
1669 if ((pos = run_command (depth, cond->cmd_ids[i], from, to, ctx))
1675 if (MDEBUG_FLAG () > 2)
1682 MFLTOtfSpec *otf_spec, int from, int to, FontLayoutContext *ctx)
1684 MFLTFont *font = ctx->font;
1685 int from_idx = ctx->out->used;
1687 if (MDEBUG_FLAG () > 2)
1688 MDEBUG_PRINT3 ("\n [FLT] %*s%s", depth, "", MSYMBOL_NAME (otf_spec->sym));
1690 font->get_glyph_id (font, ctx->in, from, to);
1691 if (! font->drive_otf)
1693 if (ctx->out->used + (to - from) > ctx->out->allocated)
1695 font->get_metrics (font, ctx->in, from, to);
1696 GCPY (ctx->in, from, to - from, ctx->out, ctx->out->used);
1697 ctx->out->used += to - from;
1701 MFLTGlyphAdjustment *adjustment;
1705 adjustment = alloca ((sizeof *adjustment)
1706 * (ctx->out->allocated - ctx->out->used));
1708 MERROR (MERROR_FLT, -1);
1709 memset (adjustment, 0,
1710 (sizeof *adjustment) * (ctx->out->allocated - ctx->out->used));
1711 to = font->drive_otf (font, otf_spec, ctx->in, from, to, ctx->out,
1715 out_len = ctx->out->used - from_idx;
1716 if (otf_spec->features[1])
1718 MFLTGlyphAdjustment *a;
1721 for (i = 0, a = adjustment; i < out_len; i++, a++)
1726 font->get_metrics (font, ctx->out, from_idx, ctx->out->used);
1727 for (g = GREF (ctx->out, from_idx + i);
1728 i < out_len; i++, a++, g = NEXT (ctx->out, g))
1731 if (a->advance_is_absolute)
1736 else if (a->xadv || a->yadv)
1741 if (a->xoff || a->yoff || a->back)
1744 MFLTGlyph *gg = PREV (ctx->out, g);
1745 MFLTGlyphAdjustment *aa = a;
1749 while (aa->back > 0)
1751 for (j = 0; j < aa->back;
1752 j++, gg = PREV (ctx->out, gg))
1754 g->xoff -= gg->xadv;
1755 g->lbearing -= gg->xadv;
1756 g->rbearing -= gg->xadv;
1759 g->xoff += aa->xoff;
1760 g->yoff += aa->yoff;
1761 g->lbearing += aa->xoff;
1762 g->rbearing += aa->xoff;
1763 g->ascent -= aa->yoff;
1764 g->descent -= aa->yoff;
1773 if (ctx->cluster_begin_idx >= 0)
1774 for (; from_idx < ctx->out->used; from_idx++)
1776 MFLTGlyph *g = GREF (ctx->out, from_idx);
1777 UPDATE_CLUSTER_RANGE (ctx, g);
1782 static char work[16];
1785 dump_combining_code (int code)
1787 char *vallign = "tcbB";
1788 char *hallign = "lcr";
1794 work[0] = vallign[COMBINING_CODE_BASE_Y (code)];
1795 work[1] = hallign[COMBINING_CODE_BASE_X (code)];
1796 off_y = COMBINING_CODE_OFF_Y (code);
1797 off_x = COMBINING_CODE_OFF_X (code);
1799 sprintf (work + 2, "+%d", off_y);
1801 sprintf (work + 2, "%d", off_y);
1802 else if (off_x == 0)
1803 sprintf (work + 2, ".");
1804 p = work + strlen (work);
1806 sprintf (p, ">%d", off_x);
1808 sprintf (p, "<%d", -off_x);
1810 p[0] = vallign[COMBINING_CODE_ADD_Y (code)];
1811 p[1] = hallign[COMBINING_CODE_ADD_X (code)];
1817 run_command (int depth, int id, int from, int to, FontLayoutContext *ctx)
1825 /* Direct code (== ctx->code_offset + id) output.
1826 The source is not consumed. */
1827 if (MDEBUG_FLAG () > 2)
1828 MDEBUG_PRINT3 ("\n [FLT] %*s(DIRECT 0x%X", depth, "",
1829 ctx->code_offset + id);
1830 i = (from < to || from == 0) ? from : from - 1;
1832 g = GREF (ctx->out, ctx->out->used - 1);
1833 g->c = g->code = ctx->code_offset + id;
1835 SET_MEASURED (g, 0);
1836 if (ctx->combining_code)
1837 SET_COMBINING_CODE (g, ctx, ctx->combining_code);
1838 if (ctx->left_padding)
1839 SET_LEFT_PADDING (g, ctx, LeftPaddingMask);
1840 for (i = from; i < to; i++)
1842 MFLTGlyph *tmp = GREF (ctx->in, i);
1844 if (g->from > tmp->from)
1845 g->from = tmp->from;
1846 else if (g->to < tmp->to)
1849 UPDATE_CLUSTER_RANGE (ctx, g);
1850 ctx->code_offset = ctx->combining_code = ctx->left_padding = 0;
1851 if (MDEBUG_FLAG () > 2)
1856 if (id <= CMD_ID_OFFSET_INDEX)
1858 int idx = CMD_ID_TO_INDEX (id);
1861 if (idx >= ctx->stage->used)
1862 MERROR (MERROR_DRAW, -1);
1863 cmd = ctx->stage->cmds + idx;
1864 if (cmd->type == FontLayoutCmdTypeRule)
1865 to = run_rule (depth, &cmd->body.rule, from, to, ctx);
1866 else if (cmd->type == FontLayoutCmdTypeCond)
1867 to = run_cond (depth, &cmd->body.cond, from, to, ctx);
1868 else if (cmd->type == FontLayoutCmdTypeOTF)
1869 to = run_otf (depth, &cmd->body.otf, from, to, ctx);
1873 if (id <= CMD_ID_OFFSET_COMBINING)
1875 ctx->combining_code = CMD_ID_TO_COMBINING_CODE (id);
1876 if (MDEBUG_FLAG () > 2)
1877 MDEBUG_PRINT3 ("\n [FLT] %*s(CMB %s)", depth, "",
1878 dump_combining_code (ctx->combining_code));
1889 g = GREF (ctx->out, ctx->out->used - 1);
1890 if (ctx->combining_code)
1891 SET_COMBINING_CODE (g, ctx, ctx->combining_code);
1892 if (ctx->left_padding)
1893 SET_LEFT_PADDING (g, ctx, LeftPaddingMask);
1894 UPDATE_CLUSTER_RANGE (ctx, g);
1895 if (MDEBUG_FLAG () > 2)
1898 MDEBUG_PRINT2 ("\n [FLT] %*s(COPY |)", depth, "");
1900 MDEBUG_PRINT3 ("\n [FLT] %*s(COPY 0x%X)", depth, "", g->code);
1902 ctx->code_offset = ctx->combining_code = ctx->left_padding = 0;
1906 case CMD_ID_CLUSTER_BEGIN:
1907 if (ctx->cluster_begin_idx < 0)
1909 if (MDEBUG_FLAG () > 2)
1910 MDEBUG_PRINT3 ("\n [FLT] %*s<%d", depth, "",
1911 GREF (ctx->in, from)->from);
1912 ctx->cluster_begin_idx = ctx->out->used;
1913 ctx->cluster_begin_pos = GREF (ctx->in, from)->from;
1914 ctx->cluster_end_pos = GREF (ctx->in, from)->to;
1918 case CMD_ID_CLUSTER_END:
1919 if (ctx->cluster_begin_idx >= 0
1920 && ctx->cluster_begin_idx < ctx->out->used)
1924 if (MDEBUG_FLAG () > 2)
1925 MDEBUG_PRINT1 (" %d>", ctx->cluster_end_pos + 1);
1926 for (i = ctx->cluster_begin_idx; i < ctx->out->used; i++)
1928 GREF (ctx->out, i)->from = ctx->cluster_begin_pos;
1929 GREF (ctx->out, i)->to = ctx->cluster_end_pos;
1931 ctx->cluster_begin_idx = -1;
1935 case CMD_ID_SEPARATOR:
1939 i = from < to ? from : from - 1;
1941 g = GREF (ctx->out, ctx->out->used - 1);
1942 g->c = -1, g->code = 0;
1943 g->xadv = g->yadv = 0;
1945 SET_MEASURED (g, 0);
1949 case CMD_ID_LEFT_PADDING:
1950 if (MDEBUG_FLAG () > 2)
1951 MDEBUG_PRINT2 ("\n [FLT] %*s[", depth, "");
1952 ctx->left_padding = 1;
1955 case CMD_ID_RIGHT_PADDING:
1956 if (ctx->out->used > 0)
1958 if (MDEBUG_FLAG () > 2)
1959 MDEBUG_PRINT2 ("\n [FLT] %*s]", depth, "");
1960 g = GREF (ctx->out, ctx->out->used - 1);
1961 SET_RIGHT_PADDING (g, ctx, RightPaddingMask);
1966 MERROR (MERROR_DRAW, -1);
1970 run_stages (MFLTGlyphString *gstring, int from, int to,
1971 MFLT *flt, FontLayoutContext *ctx)
1973 MFLTGlyphString buf, *temp;
1975 int orig_from = from, orig_to = to;
1976 int from_pos, to_pos, len;
1979 MPlist *stages = flt->stages;
1981 from_pos = GREF (ctx->in, from)->from;
1982 to_pos = GREF (ctx->in, to - 1)->to;
1983 len = to_pos - from_pos;
1987 GINIT (ctx->out, ctx->out->allocated);
1988 ctx->encoded = alloca (ctx->out->allocated);
1989 if (! ctx->out->glyphs || ! ctx->encoded)
1992 for (stage_idx = 0; 1; stage_idx++)
1997 ctx->stage = (FontLayoutStage *) MPLIST_VAL (stages);
1998 table = ctx->stage->category;
1999 ctx->code_offset = ctx->combining_code = ctx->left_padding = 0;
2000 ctx->encoded_offset = from;
2001 for (i = from; i < to; i++)
2003 MFLTGlyph *g = GREF (ctx->in, i);
2004 char enc = (GET_ENCODED (g)
2005 ? (g->c > 0 ? (int) mchartable_lookup (table, g->c) : 1)
2007 ? (int) mchartable_lookup (table, g->code)
2010 ctx->encoded[i - from] = enc;
2011 if (! enc && stage_idx == 0)
2017 ctx->encoded[i - from] = '\0';
2018 ctx->match_indices[0] = from;
2019 ctx->match_indices[1] = to;
2020 for (i = 2; i < NMATCH; i++)
2021 ctx->match_indices[i] = -1;
2023 if (MDEBUG_FLAG () > 2)
2025 MDEBUG_PRINT2 ("\n [FLT] (STAGE %d \"%s\"", stage_idx,
2027 MDEBUG_PRINT (" (");
2028 for (i = from; i < to; i++)
2030 g = GREF (ctx->in, i);
2032 MDEBUG_PRINT2 ("%*s|", (i > 0), "");
2034 MDEBUG_PRINT3 ("%*s%04X", (i > 0), "", GREF (ctx->in, i)->code);
2038 result = run_command (4, INDEX_TO_CMD_ID (0), from, to, ctx);
2039 if (MDEBUG_FLAG () > 2)
2044 stages = MPLIST_NEXT (stages);
2045 /* If this is the last stage, break the loop. */
2046 if (MPLIST_TAIL_P (stages))
2049 /* Otherwise, prepare for the next stage. */
2056 GINIT (&buf, ctx->out->allocated);
2065 if (ctx->out->used > 0)
2068 int x_ppem = ctx->font->x_ppem << 6, y_ppem = ctx->font->y_ppem << 6;
2070 /* Remove separator glyphs. */
2071 for (i = 0; i < ctx->out->used;)
2073 g = GREF (ctx->out, i);
2075 GREPLACE (NULL, 0, 0, ctx->out, i, i + 1);
2080 /* Get actual glyph IDs of glyphs. */
2081 ctx->font->get_glyph_id (ctx->font, ctx->out, 0, ctx->out->used);
2083 /* Check if all characters in the range are covered by some
2084 glyph(s). If not, change <from> and <to> of glyphs to cover
2085 uncovered characters. */
2086 g_indices = alloca (sizeof (int) * len);
2089 for (i = 0; i < len; i++) g_indices[i] = -1;
2090 for (i = 0; i < ctx->out->used; i++)
2094 g = GREF (ctx->out, i);
2095 for (pos = g->from; pos <= g->to; pos++)
2096 if (g_indices[pos - orig_from] < 0)
2097 g_indices[pos - orig_from] = i;
2099 for (i = 0; i < len; i++)
2100 if (g_indices[i] < 0)
2106 for (i++; i < len && g_indices[i] < 0; i++);
2108 g = GREF (ctx->out, j);
2109 this_from = g->from;
2111 g->from = orig_from + i;
2112 } while (++j < ctx->out->used
2113 && (g = GREF (ctx->out, j))
2114 && g->from == this_from);
2120 j = g_indices[i - 1];
2121 g = GREF (ctx->out, j);
2124 g->to = orig_from + i + 1;
2126 && (g = GREF (ctx->out, j))
2127 && g->to == this_to);
2131 ctx->font->get_metrics (ctx->font, ctx->out, 0, ctx->out->used);
2133 /* Handle combining. */
2134 if (ctx->check_mask & CombiningCodeMask)
2136 MFLTGlyph *base = GREF (ctx->out, 0);
2137 int base_height = base->ascent + base->descent;
2140 for (i = 1; i < ctx->out->used; i++)
2142 if ((g = GREF (ctx->out, i))
2143 && (combining_code = GET_COMBINING_CODE (g)))
2145 int height = g->ascent + g->descent;
2146 int base_x, base_y, add_x, add_y, off_x, off_y;
2148 if (base->from > g->from)
2149 base->from = g->from;
2150 else if (base->to < g->to)
2153 base_x = COMBINING_CODE_BASE_X (combining_code);
2154 base_y = COMBINING_CODE_BASE_Y (combining_code);
2155 add_x = COMBINING_CODE_ADD_X (combining_code);
2156 add_y = COMBINING_CODE_ADD_Y (combining_code);
2157 off_x = COMBINING_CODE_OFF_X (combining_code);
2158 off_y = COMBINING_CODE_OFF_Y (combining_code);
2160 g->xoff = ((base->xadv * base_x - g->xadv * add_x) / 2
2161 + x_ppem * off_x / 100 - base->xadv);
2163 g->yoff = base_height * base_y / 2 - base->ascent;
2167 g->yoff -= height * add_y / 2 - g->ascent;
2168 g->yoff -= y_ppem * off_y / 100;
2169 if (base->lbearing > base->xadv + g->lbearing + g->xoff)
2170 base->lbearing = base->xadv + g->lbearing + g->xoff;
2171 if (base->rbearing < base->xadv + g->xadv + g->xoff)
2172 base->rbearing = base->xadv + g->xadv + g->xoff;
2173 if (base->ascent < g->ascent - g->yoff)
2174 base->ascent = g->ascent - g->yoff;
2175 if (base->descent < g->descent - g->yoff)
2176 base->descent = g->descent - g->yoff;
2177 g->xadv = g->yadv = 0;
2178 if (GET_RIGHT_PADDING (g))
2179 SET_RIGHT_PADDING (base, ctx, RightPaddingMask);
2185 base_height = g->ascent + g->descent;
2190 /* Handle padding */
2191 if (ctx->check_mask & (LeftPaddingMask | RightPaddingMask))
2192 for (i = 0; i < ctx->out->used; i++)
2194 g = GREF (ctx->out, i);
2195 if (! GET_COMBINING_CODE (g))
2197 if (GET_RIGHT_PADDING (g) && g->rbearing > g->xadv)
2199 g->xadv = g->rbearing;
2202 if (GET_LEFT_PADDING (g) && g->lbearing < 0)
2204 g->xoff += - g->lbearing;
2205 g->xadv += - g->lbearing;
2206 g->rbearing += - g->lbearing;
2214 GREPLACE (ctx->out, 0, ctx->out->used, gstring, orig_from, orig_to);
2215 to = orig_from + ctx->out->used;
2220 setup_combining_coverage (int from, int to, void *val, void *arg)
2222 int combining_class = (int) val;
2225 if (combining_class < 200)
2227 else if (combining_class <= 204)
2229 if ((combining_class % 2) == 0)
2230 category = "bcd"[(combining_class - 200) / 2];
2232 else if (combining_class <= 232)
2234 if ((combining_class % 2) == 0)
2235 category = "efghijklmnopq"[(combining_class - 208) / 2];
2237 else if (combining_class == 233)
2239 else if (combining_class == 234)
2241 else if (combining_class == 240)
2243 mchartable_set_range ((MCharTable *) arg, from, to, (void *) category);
2247 setup_combining_flt (MFLT *flt)
2250 MCharTable *combininig_class_table
2251 = mchar_get_prop_table (Mcombining_class, &type);
2253 mchartable_set_range (flt->coverage, 0, 0x10FFFF, (void *) 'u');
2254 if (combininig_class_table)
2255 mchartable_map (combininig_class_table, (void *) 0,
2256 setup_combining_coverage, flt->coverage);
2259 #define CHECK_FLT_STAGES(flt) ((flt)->stages || load_flt (flt, NULL) == 0)
2264 int m17n__flt_initialized;
2269 /* The following two are actually not exposed to a user but concealed
2270 by the macro M17N_INIT (). */
2273 m17n_init_flt (void)
2275 int mdebug_flag = MDEBUG_INIT;
2277 merror_code = MERROR_NONE;
2278 if (m17n__flt_initialized++)
2281 if (merror_code != MERROR_NONE)
2283 m17n__flt_initialized--;
2287 MDEBUG_PUSH_TIME ();
2289 Mcond = msymbol ("cond");
2290 Mrange = msymbol ("range");
2291 Mfont = msymbol ("font");
2292 Mlayouter = msymbol ("layouter");
2293 Mcombining = msymbol ("combining");
2294 Mfont_facility = msymbol ("font-facility");
2295 Mequal = msymbol ("=");
2296 Mgenerator = msymbol ("generator");
2297 Mend = msymbol ("end");
2299 MDEBUG_PRINT_TIME ("INIT", (stderr, " to initialize the flt modules."));
2304 m17n_fini_flt (void)
2306 int mdebug_flag = MDEBUG_FINI;
2308 if (m17n__flt_initialized == 0
2309 || --m17n__flt_initialized > 0)
2312 MDEBUG_PUSH_TIME ();
2314 MDEBUG_PRINT_TIME ("FINI", (stderr, " to finalize the flt modules."));
2320 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
2322 /*** @addtogroup m17nFLT */
2328 @brief Return an FLT object that has a specified name.
2330 The mflt_get () function returns an FLT object whose name is $NAME.
2333 If the operation was successful, mflt_get () returns a pointer
2334 to the found FLT object. Otherwise, it returns @c NULL. */
2337 @brief »ØÄꤵ¤ì¤¿Ì¾Á°¤ò»ý¤Ä FLT ¥ª¥Ö¥¸¥§¥¯¥È¤òÊÖ¤¹.
2339 ´Ø¿ô mflt_get () ¤Ï¡¢$NAME ¤È¤¤¤¦Ì¾Á°¤ò»ý¤Ä FLT ¥ª¥Ö¥¸¥§¥¯¥È¤òÊÖ¤¹¡£
2342 ¤â¤·À®¸ù¤¹¤ì¤Ð¡¢mflt_get () ¤Ï¸«¤Ä¤«¤Ã¤¿ FLT
2343 ¥ª¥Ö¥¸¥§¥¯¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¼ºÇÔ¤·¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤¹¡£ */
2346 mflt_get (MSymbol name)
2350 if (! flt_list && list_flt () < 0)
2352 flt = mplist_get (flt_list, name);
2353 if (! flt || ! CHECK_FLT_STAGES (flt))
2355 if (flt->name == Mcombining
2356 && ! mchartable_lookup (flt->coverage, 0))
2357 setup_combining_flt (flt);
2364 @brief Find an FLT suitable for the specified character and font.
2366 The mflt_find () function returns the most appropriate FLT for
2367 layouting character $C with font $FONT.
2370 If the operation was successful, mflt_find () returns a pointer
2371 to the found FLT object. Otherwise, it returns @c NULL. */
2374 @brief »ØÄꤵ¤ì¤¿Ê¸»ú¤È¥Õ¥©¥ó¥È¤Ë¹ç¤Ã¤¿ FLT ¤òõ¤¹.
2376 ´Ø¿ô mflt_find () ¤Ï¡¢Ê¸»ú $C ¤ò¥Õ¥©¥ó¥È $FONT
2377 ¤Ç¥ì¥¤¥¢¥¦¥È¤¹¤ë¤¿¤á¤ËºÇ¤âŬÀÚ¤Ê FLT ¤òÊÖ¤¹¡£
2380 ¤â¤·À®¸ù¤¹¤ì¤Ð¡¢mflt_find () ¤Ï¸«¤Ä¤«¤Ã¤¿ FLT
2381 ¥ª¥Ö¥¸¥§¥¯¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¼ºÇÔ¤·¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤¹¡£ */
2384 mflt_find (int c, MFLTFont *font)
2388 static MSymbol unicode_bmp = NULL, unicode_full = NULL;
2392 unicode_bmp = msymbol ("unicode-bmp");
2393 unicode_full = msymbol ("unicode-full");
2396 if (! flt_list && list_flt () < 0)
2402 MPLIST_DO (plist, flt_list)
2404 flt = MPLIST_VAL (plist);
2405 if (flt->registry != unicode_bmp
2406 && flt->registry != unicode_full)
2408 if (flt->family && flt->family != font->family)
2411 && ! mchartable_lookup (flt->coverage, c))
2415 MFLTOtfSpec *spec = &flt->otf;
2417 if (! font->check_otf)
2419 if ((spec->features[0] && spec->features[0][0] != 0xFFFFFFFF)
2420 || (spec->features[1] && spec->features[1][0] != 0xFFFFFFFF))
2423 else if (! font->check_otf (font, spec))
2433 MPLIST_DO (plist, flt_list)
2435 flt = MPLIST_VAL (plist);
2436 if (mchartable_lookup (flt->coverage, c))
2445 @brief Return the name of an FLT.
2447 The mflt_name () function returns the name of $FLT. */
2450 @brief FLT ¤Î̾Á°¤òÊÖ¤¹.
2452 ´Ø¿ô mflt_name () ¤Ï $FLT ¤Î̾Á°¤òÊÖ¤¹¡£ */
2455 mflt_name (MFLT *flt)
2457 return MSYMBOL_NAME (flt->name);
2462 @brief Return a coverage of a FLT.
2464 The mflt_coverage () function returns a char-table that contains
2465 nonzero values for characters supported by $FLT. */
2468 @brief FLT ¤ÎÈϰϤòÊÖ¤¹.
2470 ´Ø¿ô mflt_coverage () ¤Ï¡¢$FLT ¤¬¥µ¥Ý¡¼¥È¤¹¤ëʸ»ú¤ËÂФ·¤Æ
2471 0 ¤Ç¤Ê¤¤Ãͤò´Þ¤àʸ»ú¥Æ¡¼¥Ö¥ë¤òÊÖ¤¹¡£ */
2474 mflt_coverage (MFLT *flt)
2476 return flt->coverage;
2481 @brief Layout characters with an FLT.
2483 The mflt_run () function layouts characters in $GSTRING between
2484 $FROM (inclusive) and $TO (exclusive) with $FONT. If $FLT is
2485 nonzero, it is used for all the charaters. Otherwise, appropriate
2486 FLTs are automatically chosen.
2489 The operation was successful. The value is the index to the
2490 glyph, which was previously indexed by $TO, in $GSTRING->glyphs.
2493 $GSTRING->glyphs is too short to store the result. The caller can
2494 call this fucntion again with a longer $GSTRING->glyphs.
2497 Some other error occurred. */
2500 @brief FLT ¤ò»È¤Ã¤Æʸ»ú¤ò¥ì¥¤¥¢¥¦¥È¤¹¤ë.
2502 ´Ø¿ô mflt_run () ¤Ï¡¢$GSTRING Ãæ¤Î $FROM ¤«¤é $TO ľÁ°¤Þ¤Ç¤Îʸ»ú¤ò
2503 $FONT ¤òÍѤ¤¤Æ¥ì¥¤¥¢¥¦¥È¤¹¤ë¡£¤â¤· $FLT
2504 ¤¬¥¼¥í¤Ç¤Ê¤±¤ì¤Ð¡¢¤½¤ÎÃͤò¤¹¤Ù¤Æ¤Îʸ»ú¤ËÂФ·¤ÆÍѤ¤¤ë¡£
2505 ¤½¤¦¤Ç¤Ê¤±¤ì¤ÐŬÀÚ¤Ê FLT ¤ò¼«Æ°Åª¤ËÁªÂò¤¹¤ë¡£
2508 ¼Â¹ÔÀ®¸ù¤ò¼¨¤¹¡£ÊÖ¤µ¤ì¤ëÃͤϡ¢$GSTRING->glyphs Ãæ¤Ç°ÊÁ° $TO
2509 ¤Ë¤è¤Ã¤Æ¼¨¤µ¤ì¤Æ¤¤¤¿¥°¥ê¥Õ¤Ø¤Î¥¤¥ó¥Ç¥¯¥¹¤Ç¤¢¤ë¡£
2512 ·ë²Ì¤ò³ÊǼ¤¹¤ë¤Ë¤Ï $GSTRING->glyphs ¤¬Ã»¤¹¤®¤ë¤³¤È¤ò¼¨¤¹¡£
2513 ¸Æ¤Ó½Ð¤·Â¦¤Ï¡¢¤è¤êŤ¤ $GSTRING->glyphs
2514 ¤òÍѤ¤¤ÆºÆÅÙ¤³¤Î´Ø¿ô¤ò¸Æ¤Ö¤³¤È¤¬¤Ç¤¤ë¡£
2517 ¤½¤Î¾¤Î¥¨¥é¡¼¤¬µ¯¤¤¿¤³¤È¤ò¼¨¤¹¡£ */
2520 mflt_run (MFLTGlyphString *gstring, int from, int to,
2521 MFLTFont *font, MFLT *flt)
2523 FontLayoutContext ctx;
2524 int match_indices[NMATCH];
2526 MFLTGlyphString out;
2527 int auto_flt = ! flt;
2529 int this_from, this_to;
2533 /* This is usually sufficient, but if not, we retry with the larger
2534 values at most 3 times. This value is also used for the
2535 allocating size of ctx.encoded. */
2536 out.allocated = (to - from) * 4;
2538 for (i = from; i < to; i++)
2540 g = GREF (gstring, i);
2542 memset (g, 0, sizeof (MFLTGlyph));
2544 g->from = g->to = i;
2547 for (this_from = from; this_from < to;)
2551 for (this_to = this_from; this_to < to; this_to++)
2552 if (mchartable_lookup (flt->coverage, GREF (gstring, this_to)->c))
2557 if (! flt_list && list_flt () < 0)
2559 font->get_glyph_id (font, gstring, this_from, to);
2560 font->get_metrics (font, gstring, this_from, to);
2564 for (this_to = this_from; this_to < to; this_to++)
2566 c = GREF (gstring, this_to)->c;
2567 if (c >= flt_min_coverage && c <= flt_max_coverage)
2570 for (; this_to < to; this_to++)
2572 c = GREF (gstring, this_to)->c;
2574 && mchartable_lookup (((MFLT *) font->internal)->coverage, c))
2576 flt = font->internal;
2579 flt = mflt_find (c, font);
2582 if (CHECK_FLT_STAGES (flt))
2584 font->internal = flt;
2591 if (this_from < this_to)
2593 font->get_glyph_id (font, gstring, this_from, this_to);
2594 font->get_metrics (font, gstring, this_from, this_to);
2595 this_from = this_to;
2600 MDEBUG_PRINT1 (" [FLT] (%s", MSYMBOL_NAME (flt->name));
2602 for (; this_to < to; this_to++)
2603 if (! mchartable_lookup (flt->coverage, GREF (gstring, this_to)->c))
2609 MDEBUG_PRINT1 (" (%s)", MSYMBOL_NAME (font->family));
2610 MDEBUG_PRINT ("\n [FLT] (SOURCE");
2611 for (i = this_from, j = 0; i < this_to; i++, j++)
2613 if (j > 0 && j % 8 == 0)
2614 MDEBUG_PRINT ("\n [FLT] ");
2615 MDEBUG_PRINT1 (" %04X", GREF (gstring, i)->c);
2620 for (i = 0; i < 3; i++)
2623 memset (&ctx, 0, sizeof ctx);
2624 ctx.match_indices = match_indices;
2626 ctx.cluster_begin_idx = -1;
2629 j = run_stages (gstring, this_from, this_to, flt, &ctx);
2643 MDEBUG_PRINT ("\n [FLT] (RESULT");
2644 if (MDEBUG_FLAG () > 1)
2645 for (i = 0; this_from < this_to; this_from++, i++)
2647 if (i > 0 && i % 4 == 0)
2648 MDEBUG_PRINT ("\n [FLT] ");
2649 g = GREF (gstring, this_from);
2650 MDEBUG_PRINT4 (" (%04X %d %d %d)",
2651 g->code, g->xadv, g->xoff, g->yoff);
2654 for (; this_from < this_to; this_from++)
2655 MDEBUG_PRINT1 (" %04X", GREF (gstring, this_from)->code);
2656 MDEBUG_PRINT ("))\n");
2658 this_from = this_to;
2663 int len = to - from;
2666 memcpy (((char *) out.glyphs),
2667 ((char *) gstring->glyphs) + gstring->glyph_size * from,
2668 gstring->glyph_size * len);
2669 for (i = from, j = to; i < to;)
2671 for (k = i + 1, j--; k < to && GREF (&out, k)->xadv == 0;
2673 GCPY (&out, i, (k - i), gstring, j);
2682 /* for debugging... */
2685 dump_flt_cmd (FontLayoutStage *stage, int id, int indent)
2687 char *prefix = (char *) alloca (indent + 1);
2689 memset (prefix, 32, indent);
2693 fprintf (stderr, "0x%02X", id);
2694 else if (id <= CMD_ID_OFFSET_INDEX)
2696 int idx = CMD_ID_TO_INDEX (id);
2697 FontLayoutCmd *cmd = stage->cmds + idx;
2699 if (cmd->type == FontLayoutCmdTypeRule)
2701 FontLayoutCmdRule *rule = &cmd->body.rule;
2704 fprintf (stderr, "(rule ");
2705 if (rule->src_type == SRC_REGEX)
2706 fprintf (stderr, "\"%s\"", rule->src.re.pattern);
2707 else if (rule->src_type == SRC_INDEX)
2708 fprintf (stderr, "%d", rule->src.match_idx);
2709 else if (rule->src_type == SRC_SEQ)
2710 fprintf (stderr, "(seq)");
2711 else if (rule->src_type == SRC_RANGE)
2712 fprintf (stderr, "(range)");
2714 fprintf (stderr, "(invalid src)");
2716 for (i = 0; i < rule->n_cmds; i++)
2718 fprintf (stderr, "\n%s ", prefix);
2719 dump_flt_cmd (stage, rule->cmd_ids[i], indent + 2);
2721 fprintf (stderr, ")");
2723 else if (cmd->type == FontLayoutCmdTypeCond)
2725 FontLayoutCmdCond *cond = &cmd->body.cond;
2728 fprintf (stderr, "(cond");
2729 for (i = 0; i < cond->n_cmds; i++)
2731 fprintf (stderr, "\n%s ", prefix);
2732 dump_flt_cmd (stage, cond->cmd_ids[i], indent + 2);
2734 fprintf (stderr, ")");
2736 else if (cmd->type == FontLayoutCmdTypeOTF)
2738 fprintf (stderr, "(otf)");
2741 fprintf (stderr, "(error-command)");
2743 else if (id <= CMD_ID_OFFSET_COMBINING)
2744 fprintf (stderr, "cominging-code");
2746 fprintf (stderr, "(predefiend %d)", id);
2750 mdebug_dump_flt (MFLT *flt, int indent)
2752 char *prefix = (char *) alloca (indent + 1);
2756 memset (prefix, 32, indent);
2758 fprintf (stderr, "(flt");
2759 MPLIST_DO (plist, flt->stages)
2761 FontLayoutStage *stage = (FontLayoutStage *) MPLIST_VAL (plist);
2764 fprintf (stderr, "\n%s (stage %d", prefix, stage_idx);
2765 for (i = 0; i < stage->used; i++)
2767 fprintf (stderr, "\n%s ", prefix);
2768 dump_flt_cmd (stage, INDEX_TO_CMD_ID (i), indent + 4);
2770 fprintf (stderr, ")");
2773 fprintf (stderr, ")");