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 #if !defined (FOR_DOXYGEN) || defined (DOXYGEN_INTERNAL_MODULE)
34 /*** @addtogroup m17nInternal
43 #include <sys/types.h>
46 #include "m17n-core.h"
48 #include "m17n-misc.h"
54 #include "internal-flt.h"
58 /* Font Layout Table (FLT)
60 Predefined terms: SYMBOL, INTEGER, STRING
62 FLT ::= '(' STAGE + ')'
64 STAGE ::= CATEGORY-TABLE ? FONT-LAYOUT-RULE
66 ;; Each STAGE consumes a source (code sequence) and produces another
67 ;; code sequence that is given to the next STAGE as a source. The
68 ;; source given to the first stage is a sequence of character codes
69 ;; that are assigned category codes by CATEGORY-TABLE. The output of
70 ;; the last stage is a glyph code sequence given to the renderer.
73 '(' 'category' CATEGORY-SPEC + ')'
75 '(' CODE [ CODE ] CATEGORY ')'
78 ;; ASCII character codes of alphabet ('A' .. 'Z' 'a' .. 'z').
81 ;; (0x0900 0x097F ?E) ; All Devanagari characters
82 ;; (0x093C ?N)) ; DEVANAGARI-LETTER NUKTA
83 ;; Assign the category 'E' to all Devanagari characters but 0x093C,
84 ;; assign the category 'N' to 0x093C.
87 '(' 'generator' RULE MACRO-DEF * ')'
89 RULE ::= COMMAND | REGEXP-RULE | MATCH-RULE | MAP-RULE
90 | COND-STRUCT | MACRO-NAME
93 DIRECT-CODE | COMBINING | PREDEFIND-COMMAND | OTF-COMMAND
95 DIRECT-CODE ::= INTEGER
96 ;; Always succeed. Produce the code. Consume no source.
99 '=' | '*' | '<' | '>' | '|'
101 ;; '=': Succeed when the current run contains at least one code.
102 ;; Consume the first code in the current run, and produce it as is.
104 ;; '*': If the the previous command succeeded, repeat it until it
107 ;; '<': Produce a special code that indicates the start of grapheme
108 ;; cluster. Succeed always, consume nothing.
110 ;; '>': Produce a special code that indicates the end of grapheme
111 ;; cluster. Succeed always, consume nothing.
113 ;; '|': Produce a special code whose category is ' '. Succeed always,
117 'otf:''SCRIPT'[':'['LANGSYS'][':'[GSUB-FEATURES][':'GPOS-FEATURES]]]
118 ;; Run the Open Type Layout Table on the current run. Succeed always,
122 ;; OTF's ScriptTag name (four letters) listed at:
123 ;; <http://www.microsoft.om/typograph/otspec/scripttags.htm>
125 ;; OTF's Language System name (four letters) listed at:
126 ;; <http://www.microsoft.om/typograph/otspec/languagetags.htm>
128 GSUB-FEATURES ::= [FEATURE[,FEATURE]*] | ' '
129 GPOS-FEATURES ::= [FEATURE[,FEATURE]*] | ' '
131 ;; OTF's Feature name (four letters) listed at:
132 ;; <http://www.microsoft.om/typograph/otspec/???.htm>
134 OTF-TAG ::= PRINTABLE-CHAR PRINTABLE-CHAR PRINTABLE-CHAR PRINTABLE-CHAR
138 ;; Run all features in the default langsys of 'deva' script.
139 ;; 'otf:deva::nukt:haln'
140 ;; Run all GSUB features, run 'nukt' and 'haln' GPOS features.
142 ;; Run all GSUB features, run no GPOS features.
145 '(' REGEXP RULE * ')'
147 ;; Succeed if REGXP matches the head of source. Run RULEs while
148 ;; limiting the source to the matching part. Consume that part.
151 ;; Must be composed only from ASCII characters. 'A' - 'Z', 'a' - 'z'
152 ;; correspond to CATEGORY.
159 '(' MATCH-IDX RULE * ')'
161 ;; Succeed if the previous REGEXP-RULE found a matching part for
162 ;; MATCH-IDX. Run RULEs while limiting the source to the matching
163 ;; part. If MATCH-IDX is zero, consume the whole part, else consume
166 MATCH-IDX ::= INTEGER
173 '(' ( SOURCE-SEQ | SOURCE-RANGE ) RULE * ')'
175 ;; Succeed if the source matches SOURCE-SEQ or SOURCE-RANGE. Run
176 ;; RULEs while limiting the source to the matching part. Consume that
182 '(' 'range' CODE CODE ')'
184 ;; ((0x0915 0x094D) 0x43)
185 ;; If the source code sequence is 0x0915 0x094D, produce 0x43.
186 ;; ((range 0x0F40 0x0F6A) 0x2221)
187 ;; If the first source code CODE is in the range 0x0F40..0x0F6A,
188 ;; produce (0x2221 + (CODE - 0x0F40)).
191 '(' 'cond' RULE + ')'
193 ;; Try each rule in sequence until one succeeds. Succeed if one
194 ;; succeeds. Consume nothing.
198 ;; ((0x0915 0x094D) 0x43)
199 ;; ((range 0x0F40 0x0F6A) 0x2221)
202 COMBINING ::= 'V''H''O''V''H'
203 V ::= ( 't' | 'c' | 'b' | 'B' )
204 H ::= ( 'l' | 'c' | 'r' )
205 O ::= ( '.' | XOFF | YOFF | XOFF YOFF )
206 XOFF ::= '<'INTEGER | '>'INTEGER
207 YOFF ::= '+'INTEGER | '-'INTEGER
208 ;; INTEGER must be integer 0..127
210 ;; VH pair indicates 12 reference points of a glyph as below:
212 ;; 0----1----2 <---- ascent 0:tl (top-left)
213 ;; | | 1:tc (top-center)
214 ;; | | 2:tr (top-right)
215 ;; | | 3:Bl (base-left)
216 ;; 9 10 11 <---- center 4:Bc (base-center)
217 ;; | | 5:Br (base-right)
218 ;; --3----4----5-- <-- baseline 6:bl (bottom-left)
219 ;; | | 7:bc (bottom-center)
220 ;; 6----7----8 <---- descent 8:br (bottom-right)
221 ;; 9:cl (center-left)
222 ;; | | | 10:cc (center-center)
223 ;; left center right 11:cr (center-right)
227 ;; Align top-left point of the previous glyph and bottom-center
228 ;; point of the current glyph.
230 ;; Align 20% left and 10% below of base-left point of the previous
231 ;; glyph and base-right point of the current glyph.
234 '(' MACRO-NAME RULE + ')'
235 MACRO-NAME ::= SYMBOL
239 static int mdebug_flag = MDEBUG_FONT_FLT;
241 MSymbol Mfont, Mlayouter, Mcombining;
243 static MSymbol Mgenerator, Mend;
245 static MPlist *flt_list;
246 static int flt_min_coverage, flt_max_coverage;
250 CombiningCodeMask = 0xFFFFFFF,
251 LeftPaddingMask = 1 << 28,
252 RightPaddingMask = 1 << 29
255 #define SET_GLYPH_INFO(g, mask, ctx, info) \
256 ((g)->internal = (((g)->internal & ~(mask)) | (info)), \
257 (ctx)->check_mask |= (mask))
259 #define GET_COMBINING_CODE(g) ((g)->internal & CombiningCodeMask)
260 #define SET_COMBINING_CODE(g, ctx, code) \
261 SET_GLYPH_INFO (g, CombiningCodeMask, ctx, code)
262 #define GET_LEFT_PADDING(g) ((g)->internal & LeftPaddingMask)
263 #define SET_LEFT_PADDING(g, ctx, flag) \
264 SET_GLYPH_INFO (g, LeftPaddingMask, ctx, flag)
265 #define GET_RIGHT_PADDING(g) ((g)->internal & RightPaddingMask)
266 #define SET_RIGHT_PADDING(g, ctx, flag) \
267 SET_GLYPH_INFO (g, RightPaddingMask, ctx, flag)
268 #define GET_ENCODED(g) ((g)->encoded)
269 #define SET_ENCODED(g, flag) ((g)->encoded = (flag))
270 #define GET_MEASURED(g) ((g)->measured)
271 #define SET_MEASURED(g, flag) ((g)->measured = (flag))
273 #define GINIT(gstring, n) \
275 if (! (gstring)->glyph_size) \
276 (gstring)->glyph_size = sizeof (MFLTGlyph); \
277 (gstring)->glyphs = alloca ((gstring)->glyph_size * (n)); \
278 (gstring)->allocated = (n); \
279 (gstring)->used = 0; \
282 #define GALLOCA (gstring) \
283 ((MFLTGlyph *) alloca ((gstring)->glyph_size))
285 #define GREF(gstring, idx) \
286 ((MFLTGlyph *) ((char *) ((gstring)->glyphs) + (gstring)->glyph_size * (idx)))
288 #define PREV(gstring, g) \
289 ((MFLTGlyph *) ((char *) (g) - (gstring)->glyph_size))
291 #define NEXT(gstring, g) \
292 ((MFLTGlyph *) ((char *) (g) + (gstring)->glyph_size))
294 #define GCPY(src, src_idx, n, tgt, tgt_idx) \
296 memcpy ((char *) ((tgt)->glyphs) + (tgt)->glyph_size * (tgt_idx), \
297 (char *) ((src)->glyphs) + (src)->glyph_size * (src_idx), \
298 (src)->glyph_size * (n)); \
301 #define GDUP(ctx, idx) \
303 MFLTGlyphString *src = (ctx)->in; \
304 MFLTGlyphString *tgt = (ctx)->out; \
305 if (tgt->allocated <= tgt->used) \
307 GCPY (src, (idx), 1, tgt, tgt->used); \
312 GREPLACE (MFLTGlyphString *src, int src_from, int src_to,
313 MFLTGlyphString *tgt, int tgt_from, int tgt_to)
315 int src_len = src_to - src_from;
316 int tgt_len = tgt_to - tgt_from;
317 int inc = src_len - tgt_len;
319 if (tgt->allocated < tgt->used + inc)
321 if (inc != 0 && tgt_to < tgt->used)
322 memmove ((char *) tgt->glyphs + tgt->glyph_size * (tgt_from + src_len),
323 (char *) tgt->glyphs + tgt->glyph_size * tgt_to,
324 tgt->glyph_size * (tgt->used - tgt_to));
326 memcpy ((char *) tgt->glyphs + tgt->glyph_size * tgt_from,
327 (char *) src->glyphs + src->glyph_size * src_from,
328 src->glyph_size * src_len);
337 -0x0F .. -2 : builtin commands
338 -0x100000F .. -0x10 : combining code
339 ... -0x1000010: index to FontLayoutStage->cmds
342 #define INVALID_CMD_ID -1
343 #define CMD_ID_OFFSET_BUILTIN -3
344 #define CMD_ID_OFFSET_COMBINING -0x10
345 #define CMD_ID_OFFSET_INDEX -0x1000010
347 /* Builtin commands. */
348 #define CMD_ID_COPY -3 /* '=' */
349 #define CMD_ID_REPEAT -4 /* '*' */
350 #define CMD_ID_CLUSTER_BEGIN -5 /* '<' */
351 #define CMD_ID_CLUSTER_END -6 /* '>' */
352 #define CMD_ID_SEPARATOR -7 /* '|' */
353 #define CMD_ID_LEFT_PADDING -8 /* '[' */
354 #define CMD_ID_RIGHT_PADDING -9 /* ']' */
356 #define CMD_ID_TO_COMBINING_CODE(id) (CMD_ID_OFFSET_COMBINING - (id))
357 #define COMBINING_CODE_TO_CMD_ID(code) (CMD_ID_OFFSET_COMBINING - (code))
359 #define CMD_ID_TO_INDEX(id) (CMD_ID_OFFSET_INDEX - (id))
360 #define INDEX_TO_CMD_ID(idx) (CMD_ID_OFFSET_INDEX - (idx))
362 static MSymbol Mcond, Mrange, Mfont_facility;
364 #define GLYPH_CODE_P(code) \
365 ((code) >= GLYPH_CODE_MIN && (code) <= GLYPH_CODE_MAX)
367 #define GLYPH_CODE_INDEX(code) ((code) - GLYPH_CODE_MIN)
369 #define UPDATE_CLUSTER_RANGE(ctx, g) \
371 if ((ctx)->cluster_begin_idx >= 0) \
373 if (ctx->cluster_begin_pos > (g)->from) \
374 ctx->cluster_begin_pos = (g)->from; \
375 if (ctx->cluster_end_pos < (g)->to) \
376 ctx->cluster_end_pos = (g)->to; \
380 enum FontLayoutCmdRuleSrcType
392 enum FontLayoutCmdRuleSrcType src_type;
407 MFLTOtfSpec otf_spec;
416 /* Beginning and end indices of series of SEQ commands. */
417 int seq_beg, seq_end;
418 /* Range of the first character appears in the above series. */
419 int seq_from, seq_to;
425 enum FontLayoutCmdType
427 FontLayoutCmdTypeRule,
428 FontLayoutCmdTypeCond,
429 FontLayoutCmdTypeOTF,
435 enum FontLayoutCmdType type;
437 FontLayoutCmdRule rule;
438 FontLayoutCmdCond cond;
445 MCharTable *category;
457 MCharTable *coverage;
461 /* Font layout table loader */
463 static int parse_otf_command (MSymbol symbol, MFLTOtfSpec *spec);
465 /* Load a category table from PLIST. PLIST has this form:
466 PLIST ::= ( FROM-CODE TO-CODE ? CATEGORY-CHAR ) *
470 load_category_table (MPlist *plist)
474 table = mchartable (Minteger, (void *) 0);
476 MPLIST_DO (plist, plist)
479 int from, to, category_code;
481 if (! MPLIST_PLIST (plist))
482 MERROR (MERROR_FONT, NULL);
483 elt = MPLIST_PLIST (plist);
484 if (! MPLIST_INTEGER_P (elt))
485 MERROR (MERROR_FONT, NULL);
486 from = MPLIST_INTEGER (elt);
487 elt = MPLIST_NEXT (elt);
488 if (! MPLIST_INTEGER_P (elt))
489 MERROR (MERROR_FONT, NULL);
490 to = MPLIST_INTEGER (elt);
491 elt = MPLIST_NEXT (elt);
492 if (MPLIST_TAIL_P (elt))
499 if (! MPLIST_INTEGER_P (elt))
500 MERROR (MERROR_FONT, NULL);
501 category_code = MPLIST_INTEGER (elt);
503 if (! isalnum (category_code))
504 MERROR (MERROR_FONT, NULL);
507 mchartable_set (table, from, (void *) category_code);
509 mchartable_set_range (table, from, to, (void *) category_code);
516 gen_otf_tag (char *p)
518 unsigned int tag = 0;
521 for (i = 0; i < 4 && *p; i++, p++)
522 tag = (tag << 8) | *p;
524 tag = (tag << 8) | 0x20;
529 otf_count_features (char *p, char *end, char stopper, int *count)
534 if (*p != stopper && *p != '\0')
541 if (*p == stopper || *p == '\0')
555 if (*p == stopper || *p == '\0')
567 otf_store_features (char *p, char *end, unsigned *buf)
572 for (i = 0; p < end;)
575 buf[i++] = 0xFFFFFFFF, p += 2, negative = 1;
579 buf[i++] = 0xFFFFFFFF;
580 buf[i++] = gen_otf_tag (p + 1), p += 6;
583 buf[i++] = gen_otf_tag (p), p += 5;
589 parse_otf_command (MSymbol symbol, MFLTOtfSpec *spec)
591 char *str = MSYMBOL_NAME (symbol);
592 char *end = str + MSYMBOL_NAMELEN (symbol);
593 unsigned int script, langsys;
595 int gsub_count = 0, gpos_count = 0;
598 memset (spec, 0, sizeof (MFLTOtfSpec));
601 str += 5; /* skip the heading ":otf=" */
602 script = gen_otf_tag (str);
606 langsys = gen_otf_tag (str);
613 /* Apply all GSUB features. */
618 str = otf_count_features (p, end, '+', &gsub_count);
620 MERROR (MERROR_FLT, -1);
624 /* Apply all GPOS features. */
629 str = otf_count_features (p, end, '\0', &gpos_count);
631 MERROR (MERROR_FLT, -1);
634 spec->script = script;
635 spec->langsys = langsys;
638 spec->features[0] = malloc (sizeof (int) * (gsub_count + 1));
639 if (! spec->features[0])
642 otf_store_features (gsub + 1, gpos, spec->features[0]);
644 spec->features[0][0] = 0xFFFFFFFF, spec->features[0][1] = 0;
648 spec->features[1] = malloc (sizeof (int) * (gpos_count + 1));
649 if (! spec->features[1])
651 if (spec->features[0])
652 free (spec->features[0]);
656 otf_store_features (gpos + 1, str, spec->features[1]);
658 spec->features[1][0] = 0xFFFFFFFF, spec->features[1][1] = 0;
664 /* Parse OTF command name NAME and store the result in CMD.
666 :SCRIPT[/[LANGSYS][=[GSUB-FEATURES][+GPOS-FEATURES]]]
667 where GSUB-FEATURES and GPOS-FEATURES have this form:
668 [FEATURE[,FEATURE]*] | ' ' */
671 load_otf_command (FontLayoutCmd *cmd, MSymbol sym)
673 char *name = MSYMBOL_NAME (sym);
678 /* This is old format of "otf:...". Change it to ":otf=...". */
679 char *str = alloca (MSYMBOL_NAMELEN (sym) + 2);
681 sprintf (str, ":otf=");
682 strcat (str, name + 4);
686 result = parse_otf_command (sym, &cmd->body.otf);
689 cmd->type = FontLayoutCmdTypeOTF;
694 /* Read a decimal number from STR preceded by one of "+-><". '+' and
695 '>' means a plus sign, '-' and '<' means a minus sign. If the
696 number is greater than 127, limit it to 127. */
699 read_decimal_number (char **str)
702 int sign = (*p == '-' || *p == '<') ? -1 : 1;
706 while (*p >= '0' && *p <= '9')
707 n = n * 10 + *p++ - '0';
711 return (n < 127 ? n * sign : 127 * sign);
715 /* Read a horizontal and vertical combining positions from STR, and
716 store them in the place pointed by X and Y. The horizontal
717 position left, center, and right are represented by 0, 1, and 2
718 respectively. The vertical position top, center, bottom, and base
719 are represented by 0, 1, 2, and 3 respectively. If successfully
720 read, return 0, else return -1. */
723 read_combining_position (char *str, int *x, int *y)
728 /* Vertical position comes first. */
729 for (i = 0; i < 4; i++)
738 /* Then comse horizontal position. */
739 for (i = 0; i < 3; i++)
749 /* Return a combining code corresponding to SYM. */
752 get_combining_command (MSymbol sym)
754 char *str = msymbol_name (sym);
755 int base_x, base_y, add_x, add_y, off_x, off_y;
758 if (read_combining_position (str, &base_x, &base_y) < 0)
769 if (c == '+' || c == '-')
771 off_y = read_decimal_number (&str) + 128;
776 if (c == '<' || c == '>')
777 off_x = read_decimal_number (&str) + 128;
781 if (read_combining_position (str, &add_x, &add_y) < 0)
784 c = MAKE_COMBINING_CODE (base_y, base_x, add_y, add_x, off_y, off_x);
785 return (COMBINING_CODE_TO_CMD_ID (c));
789 /* Load a command from PLIST into STAGE, and return that
790 identification number. If ID is not INVALID_CMD_ID, that means we
791 are loading a top level command or a macro. In that case, use ID
792 as the identification number of the command. Otherwise, generate a
793 new id number for the command. MACROS is a list of raw macros. */
796 load_command (FontLayoutStage *stage, MPlist *plist,
797 MPlist *macros, int id)
802 if (MPLIST_INTEGER_P (plist))
804 int code = MPLIST_INTEGER (plist);
807 MERROR (MERROR_DRAW, INVALID_CMD_ID);
810 else if (MPLIST_PLIST_P (plist))
812 /* PLIST ::= ( cond ... ) | ( STRING ... ) | ( INTEGER ... )
813 | ( ( INTEGER INTEGER ) ... )
814 | ( ( range INTEGER INTEGER ) ... )
815 | ( ( font-facilty [ INTEGER ] ) ... )
816 | ( ( font-facilty OTF-SPEC ) ... ) */
817 MPlist *elt = MPLIST_PLIST (plist);
818 int len = MPLIST_LENGTH (elt) - 1;
821 if (id == INVALID_CMD_ID)
824 id = INDEX_TO_CMD_ID (stage->used);
825 MLIST_APPEND1 (stage, cmds, dummy, MERROR_DRAW);
827 cmd = stage->cmds + CMD_ID_TO_INDEX (id);
829 if (MPLIST_SYMBOL_P (elt))
831 FontLayoutCmdCond *cond;
833 if (MPLIST_SYMBOL (elt) != Mcond)
834 MERROR (MERROR_DRAW, INVALID_CMD_ID);
835 elt = MPLIST_NEXT (elt);
836 cmd->type = FontLayoutCmdTypeCond;
837 cond = &cmd->body.cond;
838 cond->seq_beg = cond->seq_end = -1;
839 cond->seq_from = cond->seq_to = 0;
841 MTABLE_CALLOC (cond->cmd_ids, len, MERROR_DRAW);
842 for (i = 0; i < len; i++, elt = MPLIST_NEXT (elt))
844 int this_id = load_command (stage, elt, macros, INVALID_CMD_ID);
846 if (this_id == INVALID_CMD_ID || this_id == -2)
847 MERROR (MERROR_DRAW, this_id);
848 /* The above load_command may relocate stage->cmds. */
849 cmd = stage->cmds + CMD_ID_TO_INDEX (id);
850 cond = &cmd->body.cond;
851 cond->cmd_ids[i] = this_id;
852 if (this_id <= CMD_ID_OFFSET_INDEX)
854 FontLayoutCmd *this_cmd
855 = stage->cmds + CMD_ID_TO_INDEX (this_id);
857 if (this_cmd->type == FontLayoutCmdTypeRule
858 && this_cmd->body.rule.src_type == SRC_SEQ)
860 int first_char = this_cmd->body.rule.src.seq.codes[0];
862 if (cond->seq_beg < 0)
864 /* The first SEQ command. */
866 cond->seq_from = cond->seq_to = first_char;
868 else if (cond->seq_end < 0)
870 /* The following SEQ command. */
871 if (cond->seq_from > first_char)
872 cond->seq_from = first_char;
873 else if (cond->seq_to < first_char)
874 cond->seq_to = first_char;
879 if (cond->seq_beg >= 0 && cond->seq_end < 0)
880 /* The previous one is the last SEQ command. */
886 if (cond->seq_beg >= 0 && cond->seq_end < 0)
887 /* The previous one is the last SEQ command. */
891 if (cond->seq_beg >= 0 && cond->seq_end < 0)
892 /* The previous one is the last SEQ command. */
897 cmd->type = FontLayoutCmdTypeRule;
898 if (MPLIST_MTEXT_P (elt))
900 MText *mt = MPLIST_MTEXT (elt);
901 char *str = (char *) MTEXT_DATA (mt);
905 mtext_ins_char (mt, 0, '^', 1);
906 str = (char *) MTEXT_DATA (mt);
908 if (regcomp (&cmd->body.rule.src.re.preg, str, REG_EXTENDED))
909 MERROR (MERROR_FONT, INVALID_CMD_ID);
910 cmd->body.rule.src_type = SRC_REGEX;
911 cmd->body.rule.src.re.pattern = strdup (str);
913 else if (MPLIST_INTEGER_P (elt))
915 cmd->body.rule.src_type = SRC_INDEX;
916 cmd->body.rule.src.match_idx = MPLIST_INTEGER (elt);
918 else if (MPLIST_PLIST_P (elt))
920 MPlist *pl = MPLIST_PLIST (elt);
921 int size = MPLIST_LENGTH (pl);
923 if (MPLIST_INTEGER_P (pl))
927 cmd->body.rule.src_type = SRC_SEQ;
928 cmd->body.rule.src.seq.n_codes = size;
929 MTABLE_CALLOC (cmd->body.rule.src.seq.codes, size,
931 for (i = 0; i < size; i++, pl = MPLIST_NEXT (pl))
933 if (! MPLIST_INTEGER_P (pl))
934 MERROR (MERROR_DRAW, INVALID_CMD_ID);
935 cmd->body.rule.src.seq.codes[i]
936 = (unsigned) MPLIST_INTEGER (pl);
939 else if (MPLIST_SYMBOL_P (pl) && size == 3)
941 if (MPLIST_SYMBOL (pl) != Mrange)
942 MERROR (MERROR_FLT, INVALID_CMD_ID);
943 cmd->body.rule.src_type = SRC_RANGE;
944 pl = MPLIST_NEXT (pl);
945 if (! MPLIST_INTEGER_P (pl))
946 MERROR (MERROR_DRAW, INVALID_CMD_ID);
947 cmd->body.rule.src.range.from
948 = (unsigned) MPLIST_INTEGER (pl);
949 pl = MPLIST_NEXT (pl);
950 if (! MPLIST_INTEGER_P (pl))
951 MERROR (MERROR_DRAW, INVALID_CMD_ID);
952 cmd->body.rule.src.range.to
953 = (unsigned) MPLIST_INTEGER (pl);
955 else if (MPLIST_SYMBOL_P (pl) && size <= 2)
957 if (MPLIST_SYMBOL (pl) != Mfont_facility)
958 MERROR (MERROR_FLT, INVALID_CMD_ID);
959 pl = MPLIST_NEXT (pl);
960 if (MPLIST_SYMBOL_P (pl))
962 MSymbol sym = MPLIST_SYMBOL (pl);
963 char *otf_spec = MSYMBOL_NAME (sym);
965 if (otf_spec[0] == ':' && otf_spec[1] == 'o'
966 && otf_spec[2] == 't' && otf_spec[3] == 'f')
967 parse_otf_command (sym, &cmd->body.rule.src.otf_spec);
969 MERROR (MERROR_FLT, INVALID_CMD_ID);
970 cmd->body.rule.src_type = SRC_OTF_SPEC;
974 cmd->body.rule.src_type = SRC_HAS_GLYPH;
975 if (MPLIST_INTEGER_P (pl))
976 cmd->body.rule.src.supported_glyph
977 = MPLIST_INTEGER (pl);
979 cmd->body.rule.src.supported_glyph = -1;
983 MERROR (MERROR_DRAW, INVALID_CMD_ID);
986 MERROR (MERROR_DRAW, INVALID_CMD_ID);
988 elt = MPLIST_NEXT (elt);
989 cmd->body.rule.n_cmds = len;
990 MTABLE_CALLOC (cmd->body.rule.cmd_ids, len, MERROR_DRAW);
991 for (i = 0; i < len; i++, elt = MPLIST_NEXT (elt))
993 int this_id = load_command (stage, elt, macros, INVALID_CMD_ID);
995 if (this_id == INVALID_CMD_ID || this_id == -2)
996 MERROR (MERROR_DRAW, this_id);
997 /* The above load_command may relocate stage->cmds. */
998 cmd = stage->cmds + CMD_ID_TO_INDEX (id);
999 cmd->body.rule.cmd_ids[i] = this_id;
1003 else if (MPLIST_SYMBOL_P (plist))
1006 MSymbol sym = MPLIST_SYMBOL (plist);
1007 char *name = msymbol_name (sym);
1008 int len = strlen (name);
1012 && ((name[0] == 'o' && name[1] == 't'
1013 && name[2] == 'f' && name[3] == ':')
1014 || (name[0] == ':' && name[1] == 'o' && name[2] == 't'
1015 && name[3] == 'f' && name[4] == '=')))
1017 result = load_otf_command (&cmd, sym);
1020 if (id == INVALID_CMD_ID)
1022 id = INDEX_TO_CMD_ID (stage->used);
1023 MLIST_APPEND1 (stage, cmds, cmd, MERROR_DRAW);
1026 stage->cmds[CMD_ID_TO_INDEX (id)] = cmd;
1034 else if (*name == '*')
1035 return CMD_ID_REPEAT;
1036 else if (*name == '<')
1037 return CMD_ID_CLUSTER_BEGIN;
1038 else if (*name == '>')
1039 return CMD_ID_CLUSTER_END;
1040 else if (*name == '|')
1041 return CMD_ID_SEPARATOR;
1042 else if (*name == '[')
1043 return CMD_ID_LEFT_PADDING;
1044 else if (*name == ']')
1045 return CMD_ID_RIGHT_PADDING;
1051 id = get_combining_command (sym);
1057 MPLIST_DO (elt, macros)
1059 if (sym == MPLIST_SYMBOL (MPLIST_PLIST (elt)))
1061 id = INDEX_TO_CMD_ID (i);
1062 if (stage->cmds[i].type == FontLayoutCmdTypeMAX)
1063 id = load_command (stage, MPLIST_NEXT (MPLIST_PLIST (elt)),
1069 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1072 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1078 free_flt_command (FontLayoutCmd *cmd)
1080 if (cmd->type == FontLayoutCmdTypeRule)
1082 FontLayoutCmdRule *rule = &cmd->body.rule;
1084 if (rule->src_type == SRC_REGEX)
1086 free (rule->src.re.pattern);
1087 regfree (&rule->src.re.preg);
1089 else if (rule->src_type == SRC_SEQ)
1090 free (rule->src.seq.codes);
1091 free (rule->cmd_ids);
1093 else if (cmd->type == FontLayoutCmdTypeCond)
1094 free (cmd->body.cond.cmd_ids);
1095 else if (cmd->type == FontLayoutCmdTypeOTF)
1097 if (cmd->body.otf.features[0])
1098 free (cmd->body.otf.features[0]);
1099 if (cmd->body.otf.features[1])
1100 free (cmd->body.otf.features[1]);
1104 /* Load a generator from PLIST into a newly allocated FontLayoutStage,
1105 and return it. PLIST has this form:
1106 PLIST ::= ( COMMAND ( CMD-NAME COMMAND ) * )
1109 static FontLayoutStage *
1110 load_generator (MPlist *plist)
1112 FontLayoutStage *stage;
1114 FontLayoutCmd dummy;
1117 MSTRUCT_CALLOC (stage, MERROR_DRAW);
1118 MLIST_INIT1 (stage, cmds, 32);
1119 dummy.type = FontLayoutCmdTypeMAX;
1120 MLIST_APPEND1 (stage, cmds, dummy, MERROR_FONT);
1121 MPLIST_DO (elt, MPLIST_NEXT (plist))
1123 if (! MPLIST_PLIST_P (elt))
1124 MERROR (MERROR_FONT, NULL);
1125 pl = MPLIST_PLIST (elt);
1126 if (! MPLIST_SYMBOL_P (pl))
1127 MERROR (MERROR_FONT, NULL);
1128 MLIST_APPEND1 (stage, cmds, dummy, MERROR_FONT);
1131 /* Load the first command from PLIST into STAGE->cmds[0]. Macros
1132 called in the first command are also loaded from MPLIST_NEXT
1133 (PLIST) into STAGE->cmds[n]. */
1134 result = load_command (stage, plist, MPLIST_NEXT (plist),
1135 INDEX_TO_CMD_ID (0));
1136 if (result == INVALID_CMD_ID || result == -2)
1138 MLIST_FREE1 (stage, cmds);
1147 /* Load stages of the font layout table FLT. */
1150 load_flt (MFLT *flt, MPlist *key_list)
1152 MPlist *top, *plist, *pl, *p;
1153 MCharTable *category = NULL;
1157 top = (MPlist *) mdatabase__load_for_keys (flt->mdb, key_list);
1159 top = (MPlist *) mdatabase_load (flt->mdb);
1162 if (! MPLIST_PLIST_P (top))
1164 M17N_OBJECT_UNREF (top);
1165 MERROR (MERROR_FLT, -1);
1170 plist = mdatabase__props (flt->mdb);
1172 MERROR (MERROR_FLT, -1);
1173 MPLIST_DO (plist, plist)
1174 if (MPLIST_PLIST_P (plist))
1176 pl = MPLIST_PLIST (plist);
1177 if (! MPLIST_SYMBOL_P (pl)
1178 || MPLIST_SYMBOL (pl) != Mfont)
1180 pl = MPLIST_NEXT (pl);
1181 if (! MPLIST_PLIST_P (pl))
1183 p = MPLIST_PLIST (pl);
1184 if (! MPLIST_SYMBOL_P (p))
1186 p = MPLIST_NEXT (p);
1187 if (! MPLIST_SYMBOL_P (p))
1189 flt->family = MPLIST_SYMBOL (p);
1190 MPLIST_DO (p, MPLIST_NEXT (p))
1191 if (MPLIST_SYMBOL_P (p))
1193 sym = MPLIST_SYMBOL (p);
1194 if (MSYMBOL_NAME (sym)[0] != ':')
1195 flt->registry = sym, sym = Mnil;
1201 char *otf_spec = MSYMBOL_NAME (sym);
1203 if (otf_spec[0] == ':' && otf_spec[1] == 'o'
1204 && otf_spec[2] == 't' && otf_spec[3] == 'f')
1205 parse_otf_command (sym, &flt->otf);
1210 MPLIST_DO (plist, top)
1212 if (MPLIST_SYMBOL_P (plist)
1213 && MPLIST_SYMBOL (plist) == Mend)
1215 mplist_set (plist, Mnil, NULL);
1218 if (! MPLIST_PLIST (plist))
1220 pl = MPLIST_PLIST (plist);
1221 if (! MPLIST_SYMBOL_P (pl))
1223 sym = MPLIST_SYMBOL (pl);
1224 pl = MPLIST_NEXT (pl);
1227 if (sym == Mcategory)
1230 M17N_OBJECT_UNREF (category);
1231 else if (flt->coverage)
1233 category = flt->coverage;
1236 category = load_category_table (pl);
1237 if (! flt->coverage)
1239 flt->coverage = category;
1240 M17N_OBJECT_REF (category);
1243 else if (sym == Mgenerator)
1245 FontLayoutStage *stage;
1249 stage = load_generator (pl);
1252 stage->category = category;
1253 M17N_OBJECT_REF (category);
1255 flt->stages = mplist ();
1256 mplist_add (flt->stages, Mt, stage);
1260 M17N_OBJECT_UNREF (category);
1261 if (! MPLIST_TAIL_P (plist))
1263 M17N_OBJECT_UNREF (top);
1264 M17N_OBJECT_UNREF (flt->stages);
1265 MERROR (MERROR_FLT, -1);
1267 M17N_OBJECT_UNREF (top);
1273 free_flt_stage (FontLayoutStage *stage)
1277 M17N_OBJECT_UNREF (stage->category);
1278 for (i = 0; i < stage->used; i++)
1279 free_flt_command (stage->cmds + i);
1280 MLIST_FREE1 (stage, cmds);
1291 MPLIST_DO (plist, flt_list)
1293 MFLT *flt = MPLIST_VAL (plist);
1296 M17N_OBJECT_UNREF (flt->coverage);
1299 MPLIST_DO (pl, MPLIST_NEXT (flt->stages))
1300 free_flt_stage (MPLIST_VAL (pl));
1301 M17N_OBJECT_UNREF (flt->stages);
1304 M17N_OBJECT_UNREF (flt_list);
1311 MPlist *plist, *key_list = NULL;
1315 if (! (plist = mdatabase_list (Mfont, Mlayouter, Mnil, Mnil)))
1317 if (! (flt_list = mplist ()))
1319 if (! (key_list = mplist ()))
1321 if (! mplist_add (key_list, Mcategory, Mt))
1324 MPLIST_DO (pl, plist)
1326 MDatabase *mdb = MPLIST_VAL (pl);
1327 MSymbol *tags = mdatabase_tag (mdb);
1330 if (! MSTRUCT_CALLOC_SAFE (flt))
1332 flt->name = tags[2];
1334 if (load_flt (flt, key_list) < 0)
1338 if (MPLIST_TAIL_P (flt_list))
1340 flt_min_coverage = mchartable_min_char (flt->coverage);
1341 flt_max_coverage = mchartable_max_char (flt->coverage);
1347 c = mchartable_min_char (flt->coverage);
1348 if (flt_min_coverage > c)
1349 flt_min_coverage = c;
1350 c = mchartable_max_char (flt->coverage);
1351 if (flt_max_coverage < c)
1352 flt_max_coverage = c;
1354 if (! mplist_push (flt_list, flt->name, flt))
1364 M17N_OBJECT_UNREF (plist);
1365 M17N_OBJECT_UNREF (key_list);
1369 /* FLS (Font Layout Service) */
1371 /* Structure to hold information about a context of FLS. */
1375 /* Pointer to the current stage. */
1376 FontLayoutStage *stage;
1378 /* Pointer to the font. */
1381 /* Input and output glyph string. */
1382 MFLTGlyphString *in, *out;
1384 /* Encode each character or code of a glyph by the current category
1385 table into this array. An element is a category letter used for
1386 a regular expression matching. */
1391 int cluster_begin_idx;
1392 int cluster_begin_pos;
1393 int cluster_end_pos;
1397 } FontLayoutContext;
1399 static int run_command (int, int, int, int, FontLayoutContext *);
1404 run_rule (int depth,
1405 FontLayoutCmdRule *rule, int from, int to, FontLayoutContext *ctx)
1407 int *saved_match_indices = ctx->match_indices;
1408 int match_indices[NMATCH * 2];
1411 int orig_from = from;
1413 if (rule->src_type == SRC_SEQ)
1417 len = rule->src.seq.n_codes;
1418 if (len > (to - from))
1420 for (i = 0; i < len; i++)
1421 if (rule->src.seq.codes[i] != GREF (ctx->in, from + i)->code)
1426 if (MDEBUG_FLAG () > 2)
1427 MDEBUG_PRINT3 ("\n [FLT] %*s(SEQ 0x%X", depth, "",
1428 rule->src.seq.codes[0]);
1430 else if (rule->src_type == SRC_RANGE)
1436 head = GREF (ctx->in, from)->code;
1437 if (head < rule->src.range.from || head > rule->src.range.to)
1439 ctx->code_offset = head - rule->src.range.from;
1441 if (MDEBUG_FLAG () > 2)
1442 MDEBUG_PRINT4 ("\n [FLT] %*s(RANGE 0x%X-0x%X", depth, "",
1443 rule->src.range.from, rule->src.range.to);
1445 else if (rule->src_type == SRC_REGEX)
1447 regmatch_t pmatch[NMATCH];
1453 saved_code = ctx->encoded[to - ctx->encoded_offset];
1454 ctx->encoded[to - ctx->encoded_offset] = '\0';
1455 result = regexec (&(rule->src.re.preg),
1456 ctx->encoded + (from - ctx->encoded_offset),
1458 if (result == 0 && pmatch[0].rm_so == 0)
1460 if (MDEBUG_FLAG () > 2)
1461 MDEBUG_PRINT5 ("\n [FLT] %*s(REGEX \"%s\" \"%s\" %d", depth, "",
1462 rule->src.re.pattern,
1463 ctx->encoded + (from - ctx->encoded_offset),
1465 ctx->encoded[to - ctx->encoded_offset] = saved_code;
1466 for (i = 0; i < NMATCH; i++)
1468 if (pmatch[i].rm_so < 0)
1469 match_indices[i * 2] = match_indices[i * 2 + 1] = -1;
1472 match_indices[i * 2] = from + pmatch[i].rm_so;
1473 match_indices[i * 2 + 1] = from + pmatch[i].rm_eo;
1476 ctx->match_indices = match_indices;
1477 to = match_indices[1];
1481 ctx->encoded[to - ctx->encoded_offset] = saved_code;
1485 else if (rule->src_type == SRC_INDEX)
1487 if (rule->src.match_idx >= NMATCH)
1489 from = ctx->match_indices[rule->src.match_idx * 2];
1492 to = ctx->match_indices[rule->src.match_idx * 2 + 1];
1493 if (MDEBUG_FLAG () > 2)
1494 MDEBUG_PRINT3 ("\n [FLT] %*s(INDEX %d", depth, "", rule->src.match_idx);
1496 else if (rule->src_type == SRC_HAS_GLYPH)
1501 if (rule->src.supported_glyph < 0)
1505 code = GREF (ctx->in, from)->code;
1507 encoded = GREF (ctx->in, from)->encoded;
1511 code = rule->src.supported_glyph;
1517 static MFLTGlyphString gstring;
1519 if (! gstring.glyph_size)
1521 gstring.glyph_size = ctx->in->glyph_size;
1522 gstring.glyphs = calloc (1, gstring.glyph_size);
1523 gstring.allocated = 1;
1526 gstring.glyphs[0].code = code;
1527 if (ctx->font->get_glyph_id (ctx->font, &gstring, 0, 1) < 0
1528 || ! gstring.glyphs[0].encoded)
1532 else if (rule->src_type == SRC_OTF_SPEC)
1534 MFLTOtfSpec *spec = &rule->src.otf_spec;
1536 if (! ctx->font->check_otf)
1538 if ((spec->features[0] && spec->features[0][0] != 0xFFFFFFFF)
1539 || (spec->features[1] && spec->features[1][0] != 0xFFFFFFFF))
1542 else if (! ctx->font->check_otf (ctx->font, spec))
1548 for (i = 0; i < rule->n_cmds; i++)
1552 if (rule->cmd_ids[i] == CMD_ID_REPEAT)
1558 pos = run_command (depth, rule->cmd_ids[i], from, to, ctx);
1561 consumed = pos > from;
1566 ctx->match_indices = saved_match_indices;
1567 if (MDEBUG_FLAG () > 2)
1569 return (rule->src_type == SRC_INDEX ? orig_from : to);
1573 run_cond (int depth,
1574 FontLayoutCmdCond *cond, int from, int to, FontLayoutContext *ctx)
1578 if (MDEBUG_FLAG () > 2)
1579 MDEBUG_PRINT2 ("\n [FLT] %*s(COND", depth, "");
1581 for (i = 0; i < cond->n_cmds; i++)
1583 /* TODO: Write a code for optimization utilizaing the info
1585 if ((pos = run_command (depth, cond->cmd_ids[i], from, to, ctx))
1591 if (MDEBUG_FLAG () > 2)
1598 MFLTOtfSpec *otf_spec, int from, int to, FontLayoutContext *ctx)
1600 MFLTFont *font = ctx->font;
1601 int from_idx = ctx->out->used;
1603 if (MDEBUG_FLAG () > 2)
1604 MDEBUG_PRINT3 ("\n [FLT] %*s%s", depth, "", MSYMBOL_NAME (otf_spec->sym));
1606 font->get_glyph_id (font, ctx->in, from, to);
1607 if (! font->drive_otf)
1609 if (ctx->out->used + (to - from) > ctx->out->allocated)
1611 font->get_metrics (font, ctx->in, from, to);
1612 GCPY (ctx->in, from, to - from, ctx->out, ctx->out->used);
1613 ctx->out->used += to - from;
1617 MFLTGlyphAdjustment *adjustment;
1621 adjustment = alloca ((sizeof *adjustment)
1622 * (ctx->out->allocated - ctx->out->used));
1624 MERROR (MERROR_FLT, -1);
1625 memset (adjustment, 0,
1626 (sizeof *adjustment) * (ctx->out->allocated - ctx->out->used));
1627 to = font->drive_otf (font, otf_spec, ctx->in, from, to, ctx->out,
1631 out_len = ctx->out->used - from_idx;
1632 if (otf_spec->features[1])
1634 MFLTGlyphAdjustment *a;
1637 for (i = 0, a = adjustment; i < out_len; i++, a++)
1642 font->get_metrics (font, ctx->out, from_idx, ctx->out->used);
1643 for (g = GREF (ctx->out, from_idx + i);
1644 i < out_len; i++, a++, g = NEXT (ctx->out, g))
1647 if (a->advance_is_absolute)
1652 else if (a->xadv || a->yadv)
1657 if (a->xoff || a->yoff)
1660 MFLTGlyph *gg = PREV (ctx->out, g);
1661 MFLTGlyphAdjustment *aa = a;
1665 while (aa->back > 0)
1667 for (j = 0; j < aa->back;
1668 j++, gg = PREV (ctx->out, gg))
1669 g->xoff -= gg->xadv;
1671 g->xoff += aa->xoff;
1672 g->yoff += aa->yoff;
1681 if (ctx->cluster_begin_idx >= 0)
1682 for (; from_idx < ctx->out->used; from_idx++)
1684 MFLTGlyph *g = GREF (ctx->out, from_idx);
1685 UPDATE_CLUSTER_RANGE (ctx, g);
1690 static char work[16];
1693 dump_combining_code (int code)
1695 char *vallign = "tcbB";
1696 char *hallign = "lcr";
1702 work[0] = vallign[COMBINING_CODE_BASE_Y (code)];
1703 work[1] = hallign[COMBINING_CODE_BASE_X (code)];
1704 off_y = COMBINING_CODE_OFF_Y (code);
1705 off_x = COMBINING_CODE_OFF_X (code);
1707 sprintf (work + 2, "+%d", off_y);
1709 sprintf (work + 2, "%d", off_y);
1710 else if (off_x == 0)
1711 sprintf (work + 2, ".");
1712 p = work + strlen (work);
1714 sprintf (p, ">%d", off_x);
1716 sprintf (p, "<%d", -off_x);
1718 p[0] = vallign[COMBINING_CODE_ADD_Y (code)];
1719 p[1] = hallign[COMBINING_CODE_ADD_X (code)];
1725 run_command (int depth, int id, int from, int to, FontLayoutContext *ctx)
1733 /* Direct code (== ctx->code_offset + id) output.
1734 The source is not consumed. */
1735 if (MDEBUG_FLAG () > 2)
1736 MDEBUG_PRINT3 ("\n [FLT] %*s(DIRECT 0x%X", depth, "",
1737 ctx->code_offset + id);
1738 i = (from < to || from == 0) ? from : from - 1;
1740 g = GREF (ctx->out, ctx->out->used - 1);
1741 g->c = g->code = ctx->code_offset + id;
1743 SET_MEASURED (g, 0);
1744 if (ctx->combining_code)
1745 SET_COMBINING_CODE (g, ctx, ctx->combining_code);
1746 if (ctx->left_padding)
1747 SET_LEFT_PADDING (g, ctx, LeftPaddingMask);
1748 for (i = from; i < to; i++)
1750 MFLTGlyph *tmp = GREF (ctx->in, i);
1752 if (g->from > tmp->from)
1753 g->from = tmp->from;
1754 else if (g->to < tmp->to)
1757 UPDATE_CLUSTER_RANGE (ctx, g);
1758 ctx->code_offset = ctx->combining_code = ctx->left_padding = 0;
1759 if (MDEBUG_FLAG () > 2)
1764 if (id <= CMD_ID_OFFSET_INDEX)
1766 int idx = CMD_ID_TO_INDEX (id);
1769 if (idx >= ctx->stage->used)
1770 MERROR (MERROR_DRAW, -1);
1771 cmd = ctx->stage->cmds + idx;
1772 if (cmd->type == FontLayoutCmdTypeRule)
1773 to = run_rule (depth, &cmd->body.rule, from, to, ctx);
1774 else if (cmd->type == FontLayoutCmdTypeCond)
1775 to = run_cond (depth, &cmd->body.cond, from, to, ctx);
1776 else if (cmd->type == FontLayoutCmdTypeOTF)
1777 to = run_otf (depth, &cmd->body.otf, from, to, ctx);
1781 if (id <= CMD_ID_OFFSET_COMBINING)
1783 ctx->combining_code = CMD_ID_TO_COMBINING_CODE (id);
1784 if (MDEBUG_FLAG () > 2)
1785 MDEBUG_PRINT3 ("\n [FLT] %*s(CMB %s)", depth, "",
1786 dump_combining_code (ctx->combining_code));
1797 g = GREF (ctx->out, ctx->out->used - 1);
1798 if (ctx->combining_code)
1799 SET_COMBINING_CODE (g, ctx, ctx->combining_code);
1800 if (ctx->left_padding)
1801 SET_LEFT_PADDING (g, ctx, LeftPaddingMask);
1802 UPDATE_CLUSTER_RANGE (ctx, g);
1803 if (MDEBUG_FLAG () > 2)
1806 MDEBUG_PRINT2 ("\n [FLT] %*s(COPY |)", depth, "");
1808 MDEBUG_PRINT3 ("\n [FLT] %*s(COPY 0x%X)", depth, "", g->code);
1810 ctx->code_offset = ctx->combining_code = ctx->left_padding = 0;
1814 case CMD_ID_CLUSTER_BEGIN:
1815 if (ctx->cluster_begin_idx < 0)
1817 if (MDEBUG_FLAG () > 2)
1818 MDEBUG_PRINT3 ("\n [FLT] %*s<%d", depth, "",
1819 GREF (ctx->in, from)->from);
1820 ctx->cluster_begin_idx = ctx->out->used;
1821 ctx->cluster_begin_pos = GREF (ctx->in, from)->from;
1822 ctx->cluster_end_pos = GREF (ctx->in, from)->to;
1826 case CMD_ID_CLUSTER_END:
1827 if (ctx->cluster_begin_idx >= 0
1828 && ctx->cluster_begin_idx < ctx->out->used)
1832 if (MDEBUG_FLAG () > 2)
1833 MDEBUG_PRINT1 (" %d>", ctx->cluster_end_pos + 1);
1834 for (i = ctx->cluster_begin_idx; i < ctx->out->used; i++)
1836 GREF (ctx->out, i)->from = ctx->cluster_begin_pos;
1837 GREF (ctx->out, i)->to = ctx->cluster_end_pos;
1839 ctx->cluster_begin_idx = -1;
1843 case CMD_ID_SEPARATOR:
1847 i = from < to ? from : from - 1;
1849 g = GREF (ctx->out, ctx->out->used - 1);
1850 g->c = -1, g->code = 0;
1851 g->xadv = g->yadv = 0;
1853 SET_MEASURED (g, 0);
1857 case CMD_ID_LEFT_PADDING:
1858 if (MDEBUG_FLAG () > 2)
1859 MDEBUG_PRINT2 ("\n [FLT] %*s[", depth, "");
1860 ctx->left_padding = 1;
1863 case CMD_ID_RIGHT_PADDING:
1864 if (ctx->out->used > 0)
1866 if (MDEBUG_FLAG () > 2)
1867 MDEBUG_PRINT2 ("\n [FLT] %*s]", depth, "");
1868 g = GREF (ctx->out, ctx->out->used - 1);
1869 SET_RIGHT_PADDING (g, ctx, RightPaddingMask);
1874 MERROR (MERROR_DRAW, -1);
1878 run_stages (MFLTGlyphString *gstring, int from, int to,
1879 MFLT *flt, FontLayoutContext *ctx)
1881 MFLTGlyphString buf, *temp;
1883 int orig_from = from, orig_to = to;
1884 int from_pos, to_pos, len;
1887 MPlist *stages = flt->stages;
1889 from_pos = GREF (ctx->in, from)->from;
1890 to_pos = GREF (ctx->in, to - 1)->to;
1891 len = to_pos - from_pos;
1895 GINIT (ctx->out, ctx->out->allocated);
1896 ctx->encoded = alloca (ctx->out->allocated);
1897 if (! ctx->out->glyphs || ! ctx->encoded)
1900 for (stage_idx = 0; 1; stage_idx++)
1905 ctx->stage = (FontLayoutStage *) MPLIST_VAL (stages);
1906 table = ctx->stage->category;
1907 ctx->code_offset = ctx->combining_code = ctx->left_padding = 0;
1908 ctx->encoded_offset = from;
1909 for (i = from; i < to; i++)
1911 MFLTGlyph *g = GREF (ctx->in, i);
1912 char enc = (GET_ENCODED (g)
1913 ? (g->c > 0 ? (int) mchartable_lookup (table, g->c) : 1)
1915 ? (int) mchartable_lookup (table, g->code)
1918 ctx->encoded[i - from] = enc;
1919 if (! enc && stage_idx == 0)
1925 ctx->encoded[i - from] = '\0';
1926 ctx->match_indices[0] = from;
1927 ctx->match_indices[1] = to;
1928 for (i = 2; i < NMATCH; i++)
1929 ctx->match_indices[i] = -1;
1931 if (MDEBUG_FLAG () > 2)
1933 MDEBUG_PRINT2 ("\n [FLT] (STAGE %d \"%s\"", stage_idx,
1935 MDEBUG_PRINT (" (");
1936 for (i = from; i < to; i++)
1938 g = GREF (ctx->in, i);
1940 MDEBUG_PRINT2 ("%*s|", (i > 0), "");
1942 MDEBUG_PRINT3 ("%*s%04X", (i > 0), "", GREF (ctx->in, i)->code);
1946 result = run_command (4, INDEX_TO_CMD_ID (0), from, to, ctx);
1947 if (MDEBUG_FLAG () > 2)
1952 stages = MPLIST_NEXT (stages);
1953 /* If this is the last stage, break the loop. */
1954 if (MPLIST_TAIL_P (stages))
1957 /* Otherwise, prepare for the next stage. */
1964 GINIT (&buf, ctx->out->allocated);
1973 if (ctx->out->used > 0)
1976 int x_ppem = ctx->font->x_ppem << 6, y_ppem = ctx->font->y_ppem << 6;
1978 /* Remove separator glyphs. */
1979 for (i = 0; i < ctx->out->used;)
1981 g = GREF (ctx->out, i);
1983 GREPLACE (NULL, 0, 0, ctx->out, i, i + 1);
1988 /* Get actual glyph IDs of glyphs. */
1989 ctx->font->get_glyph_id (ctx->font, ctx->out, 0, ctx->out->used);
1991 /* Check if all characters in the range are covered by some
1992 glyph(s). If not, change <from> and <to> of glyphs to cover
1993 uncovered characters. */
1994 g_indices = alloca (sizeof (int) * len);
1997 for (i = 0; i < len; i++) g_indices[i] = -1;
1998 for (i = 0; i < ctx->out->used; i++)
2002 g = GREF (ctx->out, i);
2003 for (pos = g->from; pos <= g->to; pos++)
2004 if (g_indices[pos - orig_from] < 0)
2005 g_indices[pos - orig_from] = i;
2007 for (i = 0; i < len; i++)
2008 if (g_indices[i] < 0)
2014 for (i++; i < len && g_indices[i] < 0; i++);
2016 g = GREF (ctx->out, j);
2017 this_from = g->from;
2019 g->from = orig_from + i;
2020 } while (++j < ctx->out->used
2021 && (g = GREF (ctx->out, j))
2022 && g->from == this_from);
2028 j = g_indices[i - 1];
2029 g = GREF (ctx->out, j);
2032 g->to = orig_from + i + 1;
2034 && (g = GREF (ctx->out, j))
2035 && g->to == this_to);
2039 ctx->font->get_metrics (ctx->font, ctx->out, 0, ctx->out->used);
2041 /* Handle combining. */
2042 if (ctx->check_mask & CombiningCodeMask)
2044 MFLTGlyph *base = GREF (ctx->out, 0);
2045 int base_height = base->ascent + base->descent;
2048 for (i = 1; i < ctx->out->used; i++)
2050 if ((g = GREF (ctx->out, i))
2051 && (combining_code = GET_COMBINING_CODE (g)))
2053 int height = g->ascent + g->descent;
2054 int base_x, base_y, add_x, add_y, off_x, off_y;
2056 if (base->from > g->from)
2057 base->from = g->from;
2058 else if (base->to < g->to)
2061 base_x = COMBINING_CODE_BASE_X (combining_code);
2062 base_y = COMBINING_CODE_BASE_Y (combining_code);
2063 add_x = COMBINING_CODE_ADD_X (combining_code);
2064 add_y = COMBINING_CODE_ADD_Y (combining_code);
2065 off_x = COMBINING_CODE_OFF_X (combining_code);
2066 off_y = COMBINING_CODE_OFF_Y (combining_code);
2068 g->xoff = ((base->xadv * base_x - g->xadv * add_x) / 2
2069 + x_ppem * off_x / 100 - base->xadv);
2071 g->yoff = base_height * base_y / 2 - base->ascent;
2075 g->yoff -= height * add_y / 2 - g->ascent;
2076 g->yoff -= y_ppem * off_y / 100;
2077 if (base->lbearing > base->xadv + g->lbearing + g->xoff)
2078 base->lbearing = base->xadv + g->lbearing + g->xoff;
2079 if (base->rbearing < base->xadv + g->xadv + g->xoff)
2080 base->rbearing = base->xadv + g->xadv + g->xoff;
2081 if (base->ascent < g->ascent - g->yoff)
2082 base->ascent = g->ascent - g->yoff;
2083 if (base->descent < g->descent - g->yoff)
2084 base->descent = g->descent - g->yoff;
2085 g->xadv = g->yadv = 0;
2086 if (GET_RIGHT_PADDING (g))
2087 SET_RIGHT_PADDING (base, ctx, RightPaddingMask);
2093 base_height = g->ascent + g->descent;
2098 /* Handle padding */
2099 if (ctx->check_mask & (LeftPaddingMask | RightPaddingMask))
2100 for (i = 0; i < ctx->out->used; i++)
2102 g = GREF (ctx->out, i);
2103 if (! GET_COMBINING_CODE (g))
2105 if (GET_RIGHT_PADDING (g) && g->rbearing > g->xadv)
2107 g->xadv = g->rbearing;
2110 if (GET_LEFT_PADDING (g) && g->lbearing < 0)
2112 g->xoff += - g->lbearing;
2113 g->xadv += - g->lbearing;
2114 g->rbearing += - g->lbearing;
2122 GREPLACE (ctx->out, 0, ctx->out->used, gstring, orig_from, orig_to);
2123 to = orig_from + ctx->out->used;
2128 setup_combining_coverage (int from, int to, void *val, void *arg)
2130 int combining_class = (int) val;
2133 if (combining_class < 200)
2135 else if (combining_class <= 204)
2137 if ((combining_class % 2) == 0)
2138 category = "bcd"[(combining_class - 200) / 2];
2140 else if (combining_class <= 232)
2142 if ((combining_class % 2) == 0)
2143 category = "efghijklmnopq"[(combining_class - 208) / 2];
2145 else if (combining_class == 233)
2147 else if (combining_class == 234)
2149 else if (combining_class == 240)
2151 mchartable_set_range ((MCharTable *) arg, from, to, (void *) category);
2155 setup_combining_flt (MFLT *flt)
2158 MCharTable *combininig_class_table
2159 = mchar_get_prop_table (Mcombining_class, &type);
2161 mchartable_set_range (flt->coverage, 0, 0x10FFFF, (void *) 'u');
2162 if (combininig_class_table)
2163 mchartable_map (combininig_class_table, (void *) 0,
2164 setup_combining_coverage, flt->coverage);
2167 #define CHECK_FLT_STAGES(flt) ((flt)->stages || load_flt (flt, NULL) == 0)
2172 int m17n__flt_initialized;
2177 extern void m17n_init (void);
2178 extern void m17n_fini (void);
2180 /* The following two are actually not exposed to a user but concealed
2181 by the macro M17N_INIT (). */
2184 m17n_init_flt (int with_shell)
2186 int mdebug_flag = MDEBUG_INIT;
2188 merror_code = MERROR_NONE;
2189 if (m17n__flt_initialized)
2191 m17n__flt_initialized++;
2195 if (merror_code != MERROR_NONE)
2200 if (merror_code != MERROR_NONE)
2203 MDEBUG_PUSH_TIME ();
2205 Mcond = msymbol ("cond");
2206 Mrange = msymbol ("range");
2207 Mfont = msymbol ("font");
2208 Mlayouter = msymbol ("layouter");
2209 Mcombining = msymbol ("combining");
2210 Mfont_facility = msymbol ("font-facility");
2211 Mgenerator = msymbol ("generator");
2212 Mend = msymbol ("end");
2214 MDEBUG_PRINT_TIME ("INIT", (stderr, " to initialize the flt modules."));
2216 m17n__flt_initialized++;
2220 m17n_fini_flt (int with_shell)
2222 int mdebug_flag = MDEBUG_FINI;
2224 if (m17n__flt_initialized == 0
2225 || --m17n__flt_initialized > 0)
2228 MDEBUG_PUSH_TIME ();
2230 MDEBUG_PRINT_TIME ("FINI", (stderr, " to finalize the flt modules."));
2238 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
2240 /*** @addtogroup m17nFLT */
2246 @brief Return a FLT object whose name is NAME.
2248 The mflt_get () function returns a FLT object whose name is $NAME.
2251 If the operation was successfully, mflt_get () returns a pointer
2252 to a FLT object. Otherwise, it returns @c NULL. */
2255 mflt_get (MSymbol name)
2259 if (! flt_list && list_flt () < 0)
2261 flt = mplist_get (flt_list, name);
2262 if (! flt || ! CHECK_FLT_STAGES (flt))
2264 if (flt->name == Mcombining
2265 && ! mchartable_lookup (flt->coverage, 0))
2266 setup_combining_flt (flt);
2273 @brief Find a FLT suitable for a specified character and font.
2275 The mflt_find () function returns the most appropriate FLT for
2276 rendering the character $C by font $FONT.
2279 If the operation was successfully, mflt_find () returns a pointer
2280 to a FLT object. Otherwise, it returns @c NULL. */
2283 mflt_find (int c, MFLTFont *font)
2287 static MSymbol unicode_bmp = NULL, unicode_full = NULL;
2291 unicode_bmp = msymbol ("unicode-bmp");
2292 unicode_full = msymbol ("unicode-full");
2295 if (! flt_list && list_flt () < 0)
2301 MPLIST_DO (plist, flt_list)
2303 flt = MPLIST_VAL (plist);
2304 if (flt->registry != unicode_bmp
2305 && flt->registry != unicode_full)
2307 if (flt->family && flt->family != font->family)
2310 && ! mchartable_lookup (flt->coverage, c))
2314 MFLTOtfSpec *spec = &flt->otf;
2316 if (! font->check_otf)
2318 if ((spec->features[0] && spec->features[0][0] != 0xFFFFFFFF)
2319 || (spec->features[1] && spec->features[1][0] != 0xFFFFFFFF))
2322 else if (! font->check_otf (font, spec))
2332 MPLIST_DO (plist, flt_list)
2334 flt = MPLIST_VAL (plist);
2335 if (mchartable_lookup (flt->coverage, c))
2344 @brief Return a name of a FLT.
2346 The mflt_name () function returns the name of $FLT. */
2349 mflt_name (MFLT *flt)
2351 return MSYMBOL_NAME (flt->name);
2356 @brief Return a coverage of a FLT.
2358 The mflt_coverage () function returns a char-table that contains
2359 nonzero value for characters supported by $FLT. */
2362 mflt_coverage (MFLT *flt)
2364 return flt->coverage;
2369 @brief Layout characters by Font Layout Table.
2371 The mflt_run () function layout characters in $GSTRING between
2372 $FROM (inclusive) and $TO (exclusive) by $FONT. If $FLT is
2373 nonzero, it is used for all the charaters. Otherwise, appropriate
2374 FLTs are automatically chosen.
2377 The operation was successful. The value is an index to the
2378 $GSTRING->glyphs which was previously indexed by $TO.
2381 $GSTRING->glyphs is too short to store the result. A caller can
2382 call this fucntion again with the larger $GSTRING->glyphs.
2385 Some other error occurred. */
2388 mflt_run (MFLTGlyphString *gstring, int from, int to,
2389 MFLTFont *font, MFLT *flt)
2391 FontLayoutContext ctx;
2392 int match_indices[NMATCH];
2394 MFLTGlyphString out;
2395 int auto_flt = ! flt;
2397 int this_from, this_to;
2401 /* This is usually sufficient, but if not, we retry with the larger
2402 values at most 3 times. This value is also used for the
2403 allocating size of ctx.encoded. */
2404 out.allocated = (to - from) * 4;
2406 for (i = from; i < to; i++)
2408 g = GREF (gstring, i);
2410 memset (g, 0, sizeof (MFLTGlyph));
2412 g->from = g->to = i;
2415 for (this_from = from; this_from < to;)
2419 for (this_to = this_from; this_to < to; this_to++)
2420 if (mchartable_lookup (flt->coverage, GREF (gstring, this_to)->c))
2425 if (! flt_list && list_flt () < 0)
2427 font->get_glyph_id (font, gstring, this_from, to);
2428 font->get_metrics (font, gstring, this_from, to);
2432 for (this_to = this_from; this_to < to; this_to++)
2434 c = GREF (gstring, this_to)->c;
2435 if (c >= flt_min_coverage && c <= flt_max_coverage)
2438 for (; this_to < to; this_to++)
2440 c = GREF (gstring, this_to)->c;
2442 && mchartable_lookup (((MFLT *) font->internal)->coverage, c))
2444 flt = font->internal;
2447 flt = mflt_find (c, font);
2450 if (CHECK_FLT_STAGES (flt))
2452 font->internal = flt;
2459 if (this_from < this_to)
2461 font->get_glyph_id (font, gstring, this_from, this_to);
2462 font->get_metrics (font, gstring, this_from, this_to);
2463 this_from = this_to;
2468 MDEBUG_PRINT1 (" [FLT] (%s", MSYMBOL_NAME (flt->name));
2470 for (; this_to < to; this_to++)
2471 if (! mchartable_lookup (flt->coverage, GREF (gstring, this_to)->c))
2477 MDEBUG_PRINT1 (" (%s)", MSYMBOL_NAME (font->family));
2478 MDEBUG_PRINT ("\n [FLT] (SOURCE");
2479 for (i = this_from, j = 0; i < this_to; i++, j++)
2481 if (j > 0 && j % 8 == 0)
2482 MDEBUG_PRINT ("\n [FLT] ");
2483 MDEBUG_PRINT1 (" %04X", GREF (gstring, i)->c);
2488 for (i = 0; i < 3; i++)
2491 memset (&ctx, 0, sizeof ctx);
2492 ctx.match_indices = match_indices;
2494 ctx.cluster_begin_idx = -1;
2497 j = run_stages (gstring, this_from, this_to, flt, &ctx);
2511 MDEBUG_PRINT ("\n [FLT] (RESULT");
2512 if (MDEBUG_FLAG () > 1)
2513 for (i = 0; this_from < this_to; this_from++, i++)
2515 if (i > 0 && i % 4 == 0)
2516 MDEBUG_PRINT ("\n [FLT] ");
2517 g = GREF (gstring, this_from);
2518 MDEBUG_PRINT4 (" (%04X %d %d %d)",
2519 g->code, g->xadv, g->xoff, g->yoff);
2522 for (; this_from < this_to; this_from++)
2523 MDEBUG_PRINT1 (" %04X", GREF (gstring, this_from)->code);
2524 MDEBUG_PRINT ("))\n");
2526 this_from = this_to;
2531 int len = to - from;
2534 memcpy (((char *) out.glyphs),
2535 ((char *) gstring->glyphs) + gstring->glyph_size * from,
2536 gstring->glyph_size * len);
2537 for (i = from, j = to; i < to;)
2539 for (k = i + 1, j--; k < to && GREF (&out, k)->xadv == 0;
2541 GCPY (&out, i, (k - i), gstring, j);
2550 /* for debugging... */
2553 dump_flt_cmd (FontLayoutStage *stage, int id, int indent)
2555 char *prefix = (char *) alloca (indent + 1);
2557 memset (prefix, 32, indent);
2561 fprintf (stderr, "0x%02X", id);
2562 else if (id <= CMD_ID_OFFSET_INDEX)
2564 int idx = CMD_ID_TO_INDEX (id);
2565 FontLayoutCmd *cmd = stage->cmds + idx;
2567 if (cmd->type == FontLayoutCmdTypeRule)
2569 FontLayoutCmdRule *rule = &cmd->body.rule;
2572 fprintf (stderr, "(rule ");
2573 if (rule->src_type == SRC_REGEX)
2574 fprintf (stderr, "\"%s\"", rule->src.re.pattern);
2575 else if (rule->src_type == SRC_INDEX)
2576 fprintf (stderr, "%d", rule->src.match_idx);
2577 else if (rule->src_type == SRC_SEQ)
2578 fprintf (stderr, "(seq)");
2579 else if (rule->src_type == SRC_RANGE)
2580 fprintf (stderr, "(range)");
2582 fprintf (stderr, "(invalid src)");
2584 for (i = 0; i < rule->n_cmds; i++)
2586 fprintf (stderr, "\n%s ", prefix);
2587 dump_flt_cmd (stage, rule->cmd_ids[i], indent + 2);
2589 fprintf (stderr, ")");
2591 else if (cmd->type == FontLayoutCmdTypeCond)
2593 FontLayoutCmdCond *cond = &cmd->body.cond;
2596 fprintf (stderr, "(cond");
2597 for (i = 0; i < cond->n_cmds; i++)
2599 fprintf (stderr, "\n%s ", prefix);
2600 dump_flt_cmd (stage, cond->cmd_ids[i], indent + 2);
2602 fprintf (stderr, ")");
2604 else if (cmd->type == FontLayoutCmdTypeOTF)
2606 fprintf (stderr, "(otf)");
2609 fprintf (stderr, "(error-command)");
2611 else if (id <= CMD_ID_OFFSET_COMBINING)
2612 fprintf (stderr, "cominging-code");
2614 fprintf (stderr, "(predefiend %d)", id);
2618 mdebug_dump_flt (MFLT *flt, int indent)
2620 char *prefix = (char *) alloca (indent + 1);
2624 memset (prefix, 32, indent);
2626 fprintf (stderr, "(flt");
2627 MPLIST_DO (plist, flt->stages)
2629 FontLayoutStage *stage = (FontLayoutStage *) MPLIST_VAL (plist);
2632 fprintf (stderr, "\n%s (stage %d", prefix, stage_idx);
2633 for (i = 0; i < stage->used; i++)
2635 fprintf (stderr, "\n%s ", prefix);
2636 dump_flt_cmd (stage, INDEX_TO_CMD_ID (i), indent + 4);
2638 fprintf (stderr, ")");
2641 fprintf (stderr, ")");