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). */
32 #if !defined (FOR_DOXYGEN) || defined (DOXYGEN_INTERNAL_MODULE)
33 /*** @addtogroup m17nInternal
42 #include <sys/types.h>
45 #include "m17n-core.h"
47 #include "m17n-misc.h"
53 #include "internal-flt.h"
57 /* Font Layout Table (FLT)
59 Predefined terms: SYMBOL, INTEGER, STRING
61 FLT ::= '(' STAGE + ')'
63 STAGE ::= CATEGORY-TABLE ? FONT-LAYOUT-RULE
65 ;; Each STAGE consumes a source (code sequence) and produces another
66 ;; code sequence that is given to the next STAGE as a source. The
67 ;; source given to the first stage is a sequence of character codes
68 ;; that are assigned category codes by CATEGORY-TABLE. The output of
69 ;; the last stage is a glyph code sequence given to the renderer.
72 '(' 'category' CATEGORY-SPEC + ')'
74 '(' CODE [ CODE ] CATEGORY ')'
77 ;; ASCII character codes of alphabet ('A' .. 'Z' 'a' .. 'z').
80 ;; (0x0900 0x097F ?E) ; All Devanagari characters
81 ;; (0x093C ?N)) ; DEVANAGARI-LETTER NUKTA
82 ;; Assign the category 'E' to all Devanagari characters but 0x093C,
83 ;; assign the category 'N' to 0x093C.
86 '(' 'generator' RULE MACRO-DEF * ')'
88 RULE ::= COMMAND | REGEXP-RULE | MATCH-RULE | MAP-RULE
89 | COND-STRUCT | MACRO-NAME
92 DIRECT-CODE | COMBINING | PREDEFIND-COMMAND | OTF-COMMAND
94 DIRECT-CODE ::= INTEGER
95 ;; Always succeed. Produce the code. Consume no source.
98 '=' | '*' | '<' | '>' | '|'
100 ;; '=': Succeed when the current run contains at least one code.
101 ;; Consume the first code in the current run, and produce it as is.
103 ;; '*': If the the previous command succeeded, repeat it until it
106 ;; '<': Produce a special code that indicates the start of grapheme
107 ;; cluster. Succeed always, consume nothing.
109 ;; '>': Produce a special code that indicates the end of grapheme
110 ;; cluster. Succeed always, consume nothing.
112 ;; '|': Produce a special code whose category is ' '. Succeed always,
116 'otf:''SCRIPT'[':'['LANGSYS'][':'[GSUB-FEATURES][':'GPOS-FEATURES]]]
117 ;; Run the Open Type Layout Table on the current run. Succeed always,
121 ;; OTF's ScriptTag name (four letters) listed at:
122 ;; <http://www.microsoft.om/typograph/otspec/scripttags.htm>
124 ;; OTF's Language System name (four letters) listed at:
125 ;; <http://www.microsoft.om/typograph/otspec/languagetags.htm>
127 GSUB-FEATURES ::= [FEATURE[,FEATURE]*] | ' '
128 GPOS-FEATURES ::= [FEATURE[,FEATURE]*] | ' '
130 ;; OTF's Feature name (four letters) listed at:
131 ;; <http://www.microsoft.om/typograph/otspec/???.htm>
133 OTF-TAG ::= PRINTABLE-CHAR PRINTABLE-CHAR PRINTABLE-CHAR PRINTABLE-CHAR
137 ;; Run all features in the default langsys of 'deva' script.
138 ;; 'otf:deva::nukt:haln'
139 ;; Run all GSUB features, run 'nukt' and 'haln' GPOS features.
141 ;; Run all GSUB features, run no GPOS features.
144 '(' REGEXP RULE * ')'
146 ;; Succeed if REGXP matches the head of source. Run RULEs while
147 ;; limiting the source to the matching part. Consume that part.
150 ;; Must be composed only from ASCII characters. 'A' - 'Z', 'a' - 'z'
151 ;; correspond to CATEGORY.
158 '(' MATCH-IDX RULE * ')'
160 ;; Succeed if the previous REGEXP-RULE found a matching part for
161 ;; MATCH-IDX. Run RULEs while limiting the source to the matching
162 ;; part. If MATCH-IDX is zero, consume the whole part, else consume
165 MATCH-IDX ::= INTEGER
172 '(' ( SOURCE-SEQ | SOURCE-RANGE ) RULE * ')'
174 ;; Succeed if the source matches SOURCE-SEQ or SOURCE-RANGE. Run
175 ;; RULEs while limiting the source to the matching part. Consume that
181 '(' 'range' CODE CODE ')'
183 ;; ((0x0915 0x094D) 0x43)
184 ;; If the source code sequence is 0x0915 0x094D, produce 0x43.
185 ;; ((range 0x0F40 0x0F6A) 0x2221)
186 ;; If the first source code CODE is in the range 0x0F40..0x0F6A,
187 ;; produce (0x2221 + (CODE - 0x0F40)).
190 '(' 'cond' RULE + ')'
192 ;; Try each rule in sequence until one succeeds. Succeed if one
193 ;; succeeds. Consume nothing.
197 ;; ((0x0915 0x094D) 0x43)
198 ;; ((range 0x0F40 0x0F6A) 0x2221)
201 COMBINING ::= 'V''H''O''V''H'
202 V ::= ( 't' | 'c' | 'b' | 'B' )
203 H ::= ( 'l' | 'c' | 'r' )
204 O ::= ( '.' | XOFF | YOFF | XOFF YOFF )
205 XOFF ::= '<'INTEGER | '>'INTEGER
206 YOFF ::= '+'INTEGER | '-'INTEGER
207 ;; INTEGER must be integer 0..127
209 ;; VH pair indicates 12 reference points of a glyph as below:
211 ;; 0----1----2 <---- ascent 0:tl (top-left)
212 ;; | | 1:tc (top-center)
213 ;; | | 2:tr (top-right)
214 ;; | | 3:Bl (base-left)
215 ;; 9 10 11 <---- center 4:Bc (base-center)
216 ;; | | 5:Br (base-right)
217 ;; --3----4----5-- <-- baseline 6:bl (bottom-left)
218 ;; | | 7:bc (bottom-center)
219 ;; 6----7----8 <---- descent 8:br (bottom-right)
220 ;; 9:cl (center-left)
221 ;; | | | 10:cc (center-center)
222 ;; left center right 11:cr (center-right)
226 ;; Align top-left point of the previous glyph and bottom-center
227 ;; point of the current glyph.
229 ;; Align 20% left and 10% below of base-left point of the previous
230 ;; glyph and base-right point of the current glyph.
233 '(' MACRO-NAME RULE + ')'
234 MACRO-NAME ::= SYMBOL
238 static int mdebug_flag = MDEBUG_FONT_FLT;
240 MSymbol Mfont, Mlayouter, Mcombining;
242 static MSymbol Mgenerator, Mend;
244 static MPlist *flt_list;
245 static int flt_min_coverage, flt_max_coverage;
249 CombiningCodeMask = 0xFFFFFFF,
250 LeftPaddingMask = 1 << 28,
251 RightPaddingMask = 1 << 29
254 #define SET_GLYPH_INFO(g, mask, ctx, info) \
255 ((g)->internal = (((g)->internal & ~(mask)) | (info)), \
256 (ctx)->check_mask |= (mask))
258 #define GET_COMBINING_CODE(g) ((g)->internal & CombiningCodeMask)
259 #define SET_COMBINING_CODE(g, ctx, code) \
260 SET_GLYPH_INFO (g, CombiningCodeMask, ctx, code)
261 #define GET_LEFT_PADDING(g) ((g)->internal & LeftPaddingMask)
262 #define SET_LEFT_PADDING(g, ctx, flag) \
263 SET_GLYPH_INFO (g, LeftPaddingMask, ctx, flag)
264 #define GET_RIGHT_PADDING(g) ((g)->internal & RightPaddingMask)
265 #define SET_RIGHT_PADDING(g, ctx, flag) \
266 SET_GLYPH_INFO (g, RightPaddingMask, ctx, flag)
267 #define GET_ENCODED(g) ((g)->encoded)
268 #define SET_ENCODED(g, flag) ((g)->encoded = (flag))
269 #define GET_MEASURED(g) ((g)->measured)
270 #define SET_MEASURED(g, flag) ((g)->measured = (flag))
272 #define GINIT(gstring, n) \
274 if (! (gstring)->glyph_size) \
275 (gstring)->glyph_size = sizeof (MFLTGlyph); \
276 (gstring)->glyphs = alloca ((gstring)->glyph_size * (n)); \
277 (gstring)->allocated = (n); \
278 (gstring)->used = 0; \
281 #define GALLOCA (gstring) \
282 ((MFLTGlyph *) alloca ((gstring)->glyph_size))
284 #define GREF(gstring, idx) \
285 ((MFLTGlyph *) ((char *) ((gstring)->glyphs) + (gstring)->glyph_size * (idx)))
287 #define PREV(gstring, g) \
288 ((MFLTGlyph *) ((char *) (g) - (gstring)->glyph_size))
290 #define NEXT(gstring, g) \
291 ((MFLTGlyph *) ((char *) (g) + (gstring)->glyph_size))
293 #define GCPY(src, src_idx, n, tgt, tgt_idx) \
295 memcpy ((char *) ((tgt)->glyphs) + (tgt)->glyph_size * (tgt_idx), \
296 (char *) ((src)->glyphs) + (src)->glyph_size * (src_idx), \
297 (src)->glyph_size * (n)); \
300 #define GDUP(ctx, idx) \
302 MFLTGlyphString *src = (ctx)->in; \
303 MFLTGlyphString *tgt = (ctx)->out; \
304 if (tgt->allocated <= tgt->used) \
306 GCPY (src, (idx), 1, tgt, tgt->used); \
311 GREPLACE (MFLTGlyphString *src, int src_from, int src_to,
312 MFLTGlyphString *tgt, int tgt_from, int tgt_to)
314 int src_len = src_to - src_from;
315 int tgt_len = tgt_to - tgt_from;
316 int inc = src_len - tgt_len;
318 if (tgt->allocated < tgt->used + inc)
320 if (inc != 0 && tgt_to < tgt->used)
321 memmove ((char *) tgt->glyphs + tgt->glyph_size * (tgt_from + src_len),
322 (char *) tgt->glyphs + tgt->glyph_size * tgt_to,
323 tgt->glyph_size * (tgt->used - tgt_to));
325 memcpy ((char *) tgt->glyphs + tgt->glyph_size * tgt_from,
326 (char *) src->glyphs + src->glyph_size * src_from,
327 src->glyph_size * src_len);
336 -0x0F .. -2 : builtin commands
337 -0x100000F .. -0x10 : combining code
338 ... -0x1000010: index to FontLayoutStage->cmds
341 #define INVALID_CMD_ID -1
342 #define CMD_ID_OFFSET_BUILTIN -3
343 #define CMD_ID_OFFSET_COMBINING -0x10
344 #define CMD_ID_OFFSET_INDEX -0x1000010
346 /* Builtin commands. */
347 #define CMD_ID_COPY -3 /* '=' */
348 #define CMD_ID_REPEAT -4 /* '*' */
349 #define CMD_ID_CLUSTER_BEGIN -5 /* '<' */
350 #define CMD_ID_CLUSTER_END -6 /* '>' */
351 #define CMD_ID_SEPARATOR -7 /* '|' */
352 #define CMD_ID_LEFT_PADDING -8 /* '[' */
353 #define CMD_ID_RIGHT_PADDING -9 /* ']' */
355 #define CMD_ID_TO_COMBINING_CODE(id) (CMD_ID_OFFSET_COMBINING - (id))
356 #define COMBINING_CODE_TO_CMD_ID(code) (CMD_ID_OFFSET_COMBINING - (code))
358 #define CMD_ID_TO_INDEX(id) (CMD_ID_OFFSET_INDEX - (id))
359 #define INDEX_TO_CMD_ID(idx) (CMD_ID_OFFSET_INDEX - (idx))
361 static MSymbol Mcond, Mrange, Mfont_facility;
363 #define GLYPH_CODE_P(code) \
364 ((code) >= GLYPH_CODE_MIN && (code) <= GLYPH_CODE_MAX)
366 #define GLYPH_CODE_INDEX(code) ((code) - GLYPH_CODE_MIN)
368 #define UPDATE_CLUSTER_RANGE(ctx, g) \
370 if ((ctx)->cluster_begin_idx >= 0) \
372 if (ctx->cluster_begin_pos > (g)->from) \
373 ctx->cluster_begin_pos = (g)->from; \
374 if (ctx->cluster_end_pos < (g)->to) \
375 ctx->cluster_end_pos = (g)->to; \
379 enum FontLayoutCmdRuleSrcType
391 enum FontLayoutCmdRuleSrcType src_type;
406 MFLTOtfSpec otf_spec;
415 /* Beginning and end indices of series of SEQ commands. */
416 int seq_beg, seq_end;
417 /* Range of the first character appears in the above series. */
418 int seq_from, seq_to;
424 enum FontLayoutCmdType
426 FontLayoutCmdTypeRule,
427 FontLayoutCmdTypeCond,
428 FontLayoutCmdTypeOTF,
434 enum FontLayoutCmdType type;
436 FontLayoutCmdRule rule;
437 FontLayoutCmdCond cond;
444 MCharTable *category;
456 MCharTable *coverage;
460 /* Font layout table loader */
462 static int parse_otf_command (MSymbol symbol, MFLTOtfSpec *spec);
464 /* Load a category table from PLIST. PLIST has this form:
465 PLIST ::= ( FROM-CODE TO-CODE ? CATEGORY-CHAR ) *
469 load_category_table (MPlist *plist)
473 table = mchartable (Minteger, (void *) 0);
475 MPLIST_DO (plist, plist)
478 int from, to, category_code;
480 if (! MPLIST_PLIST (plist))
481 MERROR (MERROR_FONT, NULL);
482 elt = MPLIST_PLIST (plist);
483 if (! MPLIST_INTEGER_P (elt))
484 MERROR (MERROR_FONT, NULL);
485 from = MPLIST_INTEGER (elt);
486 elt = MPLIST_NEXT (elt);
487 if (! MPLIST_INTEGER_P (elt))
488 MERROR (MERROR_FONT, NULL);
489 to = MPLIST_INTEGER (elt);
490 elt = MPLIST_NEXT (elt);
491 if (MPLIST_TAIL_P (elt))
498 if (! MPLIST_INTEGER_P (elt))
499 MERROR (MERROR_FONT, NULL);
500 category_code = MPLIST_INTEGER (elt);
502 if (! isalnum (category_code))
503 MERROR (MERROR_FONT, NULL);
506 mchartable_set (table, from, (void *) category_code);
508 mchartable_set_range (table, from, to, (void *) category_code);
515 gen_otf_tag (char *p)
517 unsigned int tag = 0;
520 for (i = 0; i < 4 && *p; i++, p++)
521 tag = (tag << 8) | *p;
523 tag = (tag << 8) | 0x20;
528 otf_count_features (char *p, char *end, char stopper, int *count)
533 if (*p != stopper && *p != '\0')
540 if (*p == stopper || *p == '\0')
554 if (*p == stopper || *p == '\0')
566 otf_store_features (char *p, char *end, unsigned *buf)
571 for (i = 0; p < end;)
574 buf[i++] = 0xFFFFFFFF, p += 2, negative = 1;
578 buf[i++] = 0xFFFFFFFF;
579 buf[i++] = gen_otf_tag (p + 1), p += 6;
582 buf[i++] = gen_otf_tag (p), p += 5;
588 parse_otf_command (MSymbol symbol, MFLTOtfSpec *spec)
590 char *str = MSYMBOL_NAME (symbol);
591 char *end = str + MSYMBOL_NAMELEN (symbol);
592 unsigned int script, langsys;
594 int gsub_count = 0, gpos_count = 0;
597 memset (spec, 0, sizeof (MFLTOtfSpec));
600 str += 5; /* skip the heading ":otf=" */
601 script = gen_otf_tag (str);
605 langsys = gen_otf_tag (str);
612 /* Apply all GSUB features. */
617 str = otf_count_features (p, end, '+', &gsub_count);
619 MERROR (MERROR_FLT, -1);
623 /* Apply all GPOS features. */
628 str = otf_count_features (p, end, '\0', &gpos_count);
630 MERROR (MERROR_FLT, -1);
633 spec->script = script;
634 spec->langsys = langsys;
637 spec->features[0] = malloc (sizeof (int) * (gsub_count + 1));
638 if (! spec->features[0])
641 otf_store_features (gsub + 1, gpos, spec->features[0]);
643 spec->features[0][0] = 0xFFFFFFFF, spec->features[0][1] = 0;
647 spec->features[1] = malloc (sizeof (int) * (gpos_count + 1));
648 if (! spec->features[1])
650 if (spec->features[0])
651 free (spec->features[0]);
655 otf_store_features (gpos + 1, str, spec->features[1]);
657 spec->features[1][0] = 0xFFFFFFFF, spec->features[1][1] = 0;
663 /* Parse OTF command name NAME and store the result in CMD.
665 :SCRIPT[/[LANGSYS][=[GSUB-FEATURES][+GPOS-FEATURES]]]
666 where GSUB-FEATURES and GPOS-FEATURES have this form:
667 [FEATURE[,FEATURE]*] | ' ' */
670 load_otf_command (FontLayoutCmd *cmd, MSymbol sym)
672 char *name = MSYMBOL_NAME (sym);
677 /* This is old format of "otf:...". Change it to ":otf=...". */
678 char *str = alloca (MSYMBOL_NAMELEN (sym) + 2);
680 sprintf (str, ":otf=");
681 strcat (str, name + 4);
685 result = parse_otf_command (sym, &cmd->body.otf);
688 cmd->type = FontLayoutCmdTypeOTF;
693 /* Read a decimal number from STR preceded by one of "+-><". '+' and
694 '>' means a plus sign, '-' and '<' means a minus sign. If the
695 number is greater than 127, limit it to 127. */
698 read_decimal_number (char **str)
701 int sign = (*p == '-' || *p == '<') ? -1 : 1;
705 while (*p >= '0' && *p <= '9')
706 n = n * 10 + *p++ - '0';
710 return (n < 127 ? n * sign : 127 * sign);
714 /* Read a horizontal and vertical combining positions from STR, and
715 store them in the place pointed by X and Y. The horizontal
716 position left, center, and right are represented by 0, 1, and 2
717 respectively. The vertical position top, center, bottom, and base
718 are represented by 0, 1, 2, and 3 respectively. If successfully
719 read, return 0, else return -1. */
722 read_combining_position (char *str, int *x, int *y)
727 /* Vertical position comes first. */
728 for (i = 0; i < 4; i++)
737 /* Then comse horizontal position. */
738 for (i = 0; i < 3; i++)
748 /* Return a combining code corresponding to SYM. */
751 get_combining_command (MSymbol sym)
753 char *str = msymbol_name (sym);
754 int base_x, base_y, add_x, add_y, off_x, off_y;
757 if (read_combining_position (str, &base_x, &base_y) < 0)
768 if (c == '+' || c == '-')
770 off_y = read_decimal_number (&str) + 128;
775 if (c == '<' || c == '>')
776 off_x = read_decimal_number (&str) + 128;
780 if (read_combining_position (str, &add_x, &add_y) < 0)
783 c = MAKE_COMBINING_CODE (base_y, base_x, add_y, add_x, off_y, off_x);
784 return (COMBINING_CODE_TO_CMD_ID (c));
788 /* Load a command from PLIST into STAGE, and return that
789 identification number. If ID is not INVALID_CMD_ID, that means we
790 are loading a top level command or a macro. In that case, use ID
791 as the identification number of the command. Otherwise, generate a
792 new id number for the command. MACROS is a list of raw macros. */
795 load_command (FontLayoutStage *stage, MPlist *plist,
796 MPlist *macros, int id)
801 if (MPLIST_INTEGER_P (plist))
803 int code = MPLIST_INTEGER (plist);
806 MERROR (MERROR_DRAW, INVALID_CMD_ID);
809 else if (MPLIST_PLIST_P (plist))
811 /* PLIST ::= ( cond ... ) | ( STRING ... ) | ( INTEGER ... )
812 | ( ( INTEGER INTEGER ) ... )
813 | ( ( range INTEGER INTEGER ) ... )
814 | ( ( font-facilty [ INTEGER ] ) ... )
815 | ( ( font-facilty OTF-SPEC ) ... ) */
816 MPlist *elt = MPLIST_PLIST (plist);
817 int len = MPLIST_LENGTH (elt) - 1;
820 if (id == INVALID_CMD_ID)
823 id = INDEX_TO_CMD_ID (stage->used);
824 MLIST_APPEND1 (stage, cmds, dummy, MERROR_DRAW);
826 cmd = stage->cmds + CMD_ID_TO_INDEX (id);
828 if (MPLIST_SYMBOL_P (elt))
830 FontLayoutCmdCond *cond;
832 if (MPLIST_SYMBOL (elt) != Mcond)
833 MERROR (MERROR_DRAW, INVALID_CMD_ID);
834 elt = MPLIST_NEXT (elt);
835 cmd->type = FontLayoutCmdTypeCond;
836 cond = &cmd->body.cond;
837 cond->seq_beg = cond->seq_end = -1;
838 cond->seq_from = cond->seq_to = 0;
840 MTABLE_CALLOC (cond->cmd_ids, len, MERROR_DRAW);
841 for (i = 0; i < len; i++, elt = MPLIST_NEXT (elt))
843 int this_id = load_command (stage, elt, macros, INVALID_CMD_ID);
845 if (this_id == INVALID_CMD_ID || this_id == -2)
846 MERROR (MERROR_DRAW, this_id);
847 /* The above load_command may relocate stage->cmds. */
848 cmd = stage->cmds + CMD_ID_TO_INDEX (id);
849 cond = &cmd->body.cond;
850 cond->cmd_ids[i] = this_id;
851 if (this_id <= CMD_ID_OFFSET_INDEX)
853 FontLayoutCmd *this_cmd
854 = stage->cmds + CMD_ID_TO_INDEX (this_id);
856 if (this_cmd->type == FontLayoutCmdTypeRule
857 && this_cmd->body.rule.src_type == SRC_SEQ)
859 int first_char = this_cmd->body.rule.src.seq.codes[0];
861 if (cond->seq_beg < 0)
863 /* The first SEQ command. */
865 cond->seq_from = cond->seq_to = first_char;
867 else if (cond->seq_end < 0)
869 /* The following SEQ command. */
870 if (cond->seq_from > first_char)
871 cond->seq_from = first_char;
872 else if (cond->seq_to < first_char)
873 cond->seq_to = first_char;
878 if (cond->seq_beg >= 0 && cond->seq_end < 0)
879 /* The previous one is the last SEQ command. */
885 if (cond->seq_beg >= 0 && cond->seq_end < 0)
886 /* The previous one is the last SEQ command. */
890 if (cond->seq_beg >= 0 && cond->seq_end < 0)
891 /* The previous one is the last SEQ command. */
896 cmd->type = FontLayoutCmdTypeRule;
897 if (MPLIST_MTEXT_P (elt))
899 MText *mt = MPLIST_MTEXT (elt);
900 char *str = (char *) MTEXT_DATA (mt);
904 mtext_ins_char (mt, 0, '^', 1);
905 str = (char *) MTEXT_DATA (mt);
907 if (regcomp (&cmd->body.rule.src.re.preg, str, REG_EXTENDED))
908 MERROR (MERROR_FONT, INVALID_CMD_ID);
909 cmd->body.rule.src_type = SRC_REGEX;
910 cmd->body.rule.src.re.pattern = strdup (str);
912 else if (MPLIST_INTEGER_P (elt))
914 cmd->body.rule.src_type = SRC_INDEX;
915 cmd->body.rule.src.match_idx = MPLIST_INTEGER (elt);
917 else if (MPLIST_PLIST_P (elt))
919 MPlist *pl = MPLIST_PLIST (elt);
920 int size = MPLIST_LENGTH (pl);
922 if (MPLIST_INTEGER_P (pl))
926 cmd->body.rule.src_type = SRC_SEQ;
927 cmd->body.rule.src.seq.n_codes = size;
928 MTABLE_CALLOC (cmd->body.rule.src.seq.codes, size,
930 for (i = 0; i < size; i++, pl = MPLIST_NEXT (pl))
932 if (! MPLIST_INTEGER_P (pl))
933 MERROR (MERROR_DRAW, INVALID_CMD_ID);
934 cmd->body.rule.src.seq.codes[i]
935 = (unsigned) MPLIST_INTEGER (pl);
938 else if (MPLIST_SYMBOL_P (pl) && size == 3)
940 if (MPLIST_SYMBOL (pl) != Mrange)
941 MERROR (MERROR_FLT, INVALID_CMD_ID);
942 cmd->body.rule.src_type = SRC_RANGE;
943 pl = MPLIST_NEXT (pl);
944 if (! MPLIST_INTEGER_P (pl))
945 MERROR (MERROR_DRAW, INVALID_CMD_ID);
946 cmd->body.rule.src.range.from
947 = (unsigned) MPLIST_INTEGER (pl);
948 pl = MPLIST_NEXT (pl);
949 if (! MPLIST_INTEGER_P (pl))
950 MERROR (MERROR_DRAW, INVALID_CMD_ID);
951 cmd->body.rule.src.range.to
952 = (unsigned) MPLIST_INTEGER (pl);
954 else if (MPLIST_SYMBOL_P (pl) && size <= 2)
956 if (MPLIST_SYMBOL (pl) != Mfont_facility)
957 MERROR (MERROR_FLT, INVALID_CMD_ID);
958 pl = MPLIST_NEXT (pl);
959 if (MPLIST_SYMBOL_P (pl))
961 MSymbol sym = MPLIST_SYMBOL (pl);
962 char *otf_spec = MSYMBOL_NAME (sym);
964 if (otf_spec[0] == ':' && otf_spec[1] == 'o'
965 && otf_spec[2] == 't' && otf_spec[3] == 'f')
966 parse_otf_command (sym, &cmd->body.rule.src.otf_spec);
968 MERROR (MERROR_FLT, INVALID_CMD_ID);
969 cmd->body.rule.src_type = SRC_OTF_SPEC;
973 cmd->body.rule.src_type = SRC_HAS_GLYPH;
974 if (MPLIST_INTEGER_P (pl))
975 cmd->body.rule.src.supported_glyph
976 = MPLIST_INTEGER (pl);
978 cmd->body.rule.src.supported_glyph = -1;
982 MERROR (MERROR_DRAW, INVALID_CMD_ID);
985 MERROR (MERROR_DRAW, INVALID_CMD_ID);
987 elt = MPLIST_NEXT (elt);
988 cmd->body.rule.n_cmds = len;
989 MTABLE_CALLOC (cmd->body.rule.cmd_ids, len, MERROR_DRAW);
990 for (i = 0; i < len; i++, elt = MPLIST_NEXT (elt))
992 int this_id = load_command (stage, elt, macros, INVALID_CMD_ID);
994 if (this_id == INVALID_CMD_ID || this_id == -2)
995 MERROR (MERROR_DRAW, this_id);
996 /* The above load_command may relocate stage->cmds. */
997 cmd = stage->cmds + CMD_ID_TO_INDEX (id);
998 cmd->body.rule.cmd_ids[i] = this_id;
1002 else if (MPLIST_SYMBOL_P (plist))
1005 MSymbol sym = MPLIST_SYMBOL (plist);
1006 char *name = msymbol_name (sym);
1007 int len = strlen (name);
1011 && ((name[0] == 'o' && name[1] == 't'
1012 && name[2] == 'f' && name[3] == ':')
1013 || (name[0] == ':' && name[1] == 'o' && name[2] == 't'
1014 && name[3] == 'f' && name[4] == '=')))
1016 result = load_otf_command (&cmd, sym);
1019 if (id == INVALID_CMD_ID)
1021 id = INDEX_TO_CMD_ID (stage->used);
1022 MLIST_APPEND1 (stage, cmds, cmd, MERROR_DRAW);
1025 stage->cmds[CMD_ID_TO_INDEX (id)] = cmd;
1033 else if (*name == '*')
1034 return CMD_ID_REPEAT;
1035 else if (*name == '<')
1036 return CMD_ID_CLUSTER_BEGIN;
1037 else if (*name == '>')
1038 return CMD_ID_CLUSTER_END;
1039 else if (*name == '|')
1040 return CMD_ID_SEPARATOR;
1041 else if (*name == '[')
1042 return CMD_ID_LEFT_PADDING;
1043 else if (*name == ']')
1044 return CMD_ID_RIGHT_PADDING;
1050 id = get_combining_command (sym);
1056 MPLIST_DO (elt, macros)
1058 if (sym == MPLIST_SYMBOL (MPLIST_PLIST (elt)))
1060 id = INDEX_TO_CMD_ID (i);
1061 if (stage->cmds[i].type == FontLayoutCmdTypeMAX)
1062 id = load_command (stage, MPLIST_NEXT (MPLIST_PLIST (elt)),
1068 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1071 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1077 free_flt_command (FontLayoutCmd *cmd)
1079 if (cmd->type == FontLayoutCmdTypeRule)
1081 FontLayoutCmdRule *rule = &cmd->body.rule;
1083 if (rule->src_type == SRC_REGEX)
1085 free (rule->src.re.pattern);
1086 regfree (&rule->src.re.preg);
1088 else if (rule->src_type == SRC_SEQ)
1089 free (rule->src.seq.codes);
1090 free (rule->cmd_ids);
1092 else if (cmd->type == FontLayoutCmdTypeCond)
1093 free (cmd->body.cond.cmd_ids);
1094 else if (cmd->type == FontLayoutCmdTypeOTF)
1096 if (cmd->body.otf.features[0])
1097 free (cmd->body.otf.features[0]);
1098 if (cmd->body.otf.features[1])
1099 free (cmd->body.otf.features[1]);
1103 /* Load a generator from PLIST into a newly allocated FontLayoutStage,
1104 and return it. PLIST has this form:
1105 PLIST ::= ( COMMAND ( CMD-NAME COMMAND ) * )
1108 static FontLayoutStage *
1109 load_generator (MPlist *plist)
1111 FontLayoutStage *stage;
1113 FontLayoutCmd dummy;
1116 MSTRUCT_CALLOC (stage, MERROR_DRAW);
1117 MLIST_INIT1 (stage, cmds, 32);
1118 dummy.type = FontLayoutCmdTypeMAX;
1119 MLIST_APPEND1 (stage, cmds, dummy, MERROR_FONT);
1120 MPLIST_DO (elt, MPLIST_NEXT (plist))
1122 if (! MPLIST_PLIST_P (elt))
1123 MERROR (MERROR_FONT, NULL);
1124 pl = MPLIST_PLIST (elt);
1125 if (! MPLIST_SYMBOL_P (pl))
1126 MERROR (MERROR_FONT, NULL);
1127 MLIST_APPEND1 (stage, cmds, dummy, MERROR_FONT);
1130 /* Load the first command from PLIST into STAGE->cmds[0]. Macros
1131 called in the first command are also loaded from MPLIST_NEXT
1132 (PLIST) into STAGE->cmds[n]. */
1133 result = load_command (stage, plist, MPLIST_NEXT (plist),
1134 INDEX_TO_CMD_ID (0));
1135 if (result == INVALID_CMD_ID || result == -2)
1137 MLIST_FREE1 (stage, cmds);
1146 /* Load stages of the font layout table FLT. */
1149 load_flt (MFLT *flt, MPlist *key_list)
1151 MPlist *top, *plist, *pl, *p;
1152 MCharTable *category = NULL;
1156 top = (MPlist *) mdatabase__load_for_keys (flt->mdb, key_list);
1158 top = (MPlist *) mdatabase_load (flt->mdb);
1161 if (! MPLIST_PLIST_P (top))
1163 M17N_OBJECT_UNREF (top);
1164 MERROR (MERROR_FLT, -1);
1169 plist = mdatabase__props (flt->mdb);
1171 MERROR (MERROR_FLT, -1);
1172 MPLIST_DO (plist, plist)
1173 if (MPLIST_PLIST_P (plist))
1175 pl = MPLIST_PLIST (plist);
1176 if (! MPLIST_SYMBOL_P (pl)
1177 || MPLIST_SYMBOL (pl) != Mfont)
1179 pl = MPLIST_NEXT (pl);
1180 if (! MPLIST_PLIST_P (pl))
1182 p = MPLIST_PLIST (pl);
1183 if (! MPLIST_SYMBOL_P (p))
1185 p = MPLIST_NEXT (p);
1186 if (! MPLIST_SYMBOL_P (p))
1188 flt->family = MPLIST_SYMBOL (p);
1189 MPLIST_DO (p, MPLIST_NEXT (p))
1190 if (MPLIST_SYMBOL_P (p))
1192 sym = MPLIST_SYMBOL (p);
1193 if (MSYMBOL_NAME (sym)[0] != ':')
1194 flt->registry = sym, sym = Mnil;
1200 char *otf_spec = MSYMBOL_NAME (sym);
1202 if (otf_spec[0] == ':' && otf_spec[1] == 'o'
1203 && otf_spec[2] == 't' && otf_spec[3] == 'f')
1204 parse_otf_command (sym, &flt->otf);
1209 MPLIST_DO (plist, top)
1211 if (MPLIST_SYMBOL_P (plist)
1212 && MPLIST_SYMBOL (plist) == Mend)
1214 mplist_set (plist, Mnil, NULL);
1217 if (! MPLIST_PLIST (plist))
1219 pl = MPLIST_PLIST (plist);
1220 if (! MPLIST_SYMBOL_P (pl))
1222 sym = MPLIST_SYMBOL (pl);
1223 pl = MPLIST_NEXT (pl);
1226 if (sym == Mcategory)
1229 M17N_OBJECT_UNREF (category);
1230 else if (flt->coverage)
1232 category = flt->coverage;
1235 category = load_category_table (pl);
1236 if (! flt->coverage)
1238 flt->coverage = category;
1239 M17N_OBJECT_REF (category);
1242 else if (sym == Mgenerator)
1244 FontLayoutStage *stage;
1248 stage = load_generator (pl);
1251 stage->category = category;
1252 M17N_OBJECT_REF (category);
1254 flt->stages = mplist ();
1255 mplist_add (flt->stages, Mt, stage);
1259 M17N_OBJECT_UNREF (category);
1260 printf ("FLT:%s\n", MSYMBOL_NAME (flt->name));
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. */
1390 int cluster_begin_idx;
1391 int cluster_begin_pos;
1392 int cluster_end_pos;
1396 } FontLayoutContext;
1398 static int run_command (int, int, int, int, FontLayoutContext *);
1403 run_rule (int depth,
1404 FontLayoutCmdRule *rule, int from, int to, FontLayoutContext *ctx)
1406 int *saved_match_indices = ctx->match_indices;
1407 int match_indices[NMATCH * 2];
1410 int orig_from = from;
1412 if (rule->src_type == SRC_SEQ)
1416 len = rule->src.seq.n_codes;
1417 if (len > (to - from))
1419 for (i = 0; i < len; i++)
1420 if (rule->src.seq.codes[i] != GREF (ctx->in, from + i)->code)
1425 if (MDEBUG_FLAG () > 2)
1426 MDEBUG_PRINT3 ("\n [FLT] %*s(SEQ 0x%X", depth, "",
1427 rule->src.seq.codes[0]);
1429 else if (rule->src_type == SRC_RANGE)
1435 head = GREF (ctx->in, from)->code;
1436 if (head < rule->src.range.from || head > rule->src.range.to)
1438 ctx->code_offset = head - rule->src.range.from;
1440 if (MDEBUG_FLAG () > 2)
1441 MDEBUG_PRINT4 ("\n [FLT] %*s(RANGE 0x%X-0x%X", depth, "",
1442 rule->src.range.from, rule->src.range.to);
1444 else if (rule->src_type == SRC_REGEX)
1446 regmatch_t pmatch[NMATCH];
1452 saved_code = ctx->encoded[to];
1453 ctx->encoded[to] = '\0';
1454 result = regexec (&(rule->src.re.preg),
1455 ctx->encoded + from, NMATCH, pmatch, 0);
1456 if (result == 0 && pmatch[0].rm_so == 0)
1458 if (MDEBUG_FLAG () > 2)
1459 MDEBUG_PRINT5 ("\n [FLT] %*s(REGEX \"%s\" \"%s\" %d", depth, "",
1460 rule->src.re.pattern,
1461 ctx->encoded + from,
1463 ctx->encoded[to] = saved_code;
1464 for (i = 0; i < NMATCH; i++)
1466 if (pmatch[i].rm_so < 0)
1467 match_indices[i * 2] = match_indices[i * 2 + 1] = -1;
1470 match_indices[i * 2] = from + pmatch[i].rm_so;
1471 match_indices[i * 2 + 1] = from + pmatch[i].rm_eo;
1474 ctx->match_indices = match_indices;
1475 to = match_indices[1];
1479 ctx->encoded[to] = saved_code;
1483 else if (rule->src_type == SRC_INDEX)
1485 if (rule->src.match_idx >= NMATCH)
1487 from = ctx->match_indices[rule->src.match_idx * 2];
1490 to = ctx->match_indices[rule->src.match_idx * 2 + 1];
1491 if (MDEBUG_FLAG () > 2)
1492 MDEBUG_PRINT3 ("\n [FLT] %*s(INDEX %d", depth, "", rule->src.match_idx);
1494 else if (rule->src_type == SRC_HAS_GLYPH)
1499 if (rule->src.supported_glyph < 0)
1503 code = GREF (ctx->in, from)->code;
1505 encoded = GREF (ctx->in, from)->encoded;
1509 code = rule->src.supported_glyph;
1515 static MFLTGlyphString gstring;
1517 if (! gstring.glyph_size)
1519 gstring.glyph_size = ctx->in->glyph_size;
1520 gstring.glyphs = calloc (1, gstring.glyph_size);
1521 gstring.allocated = 1;
1524 gstring.glyphs[0].code = code;
1525 if (ctx->font->get_glyph_id (ctx->font, &gstring, 0, 1) < 0
1526 || ! gstring.glyphs[0].encoded)
1530 else if (rule->src_type == SRC_OTF_SPEC)
1532 MFLTOtfSpec *spec = &rule->src.otf_spec;
1534 if (! ctx->font->check_otf)
1536 if ((spec->features[0] && spec->features[0][0] != 0xFFFFFFFF)
1537 || (spec->features[1] && spec->features[1][0] != 0xFFFFFFFF))
1540 else if (! ctx->font->check_otf (ctx->font, spec))
1546 for (i = 0; i < rule->n_cmds; i++)
1550 if (rule->cmd_ids[i] == CMD_ID_REPEAT)
1556 pos = run_command (depth, rule->cmd_ids[i], from, to, ctx);
1559 consumed = pos > from;
1564 ctx->match_indices = saved_match_indices;
1565 if (MDEBUG_FLAG () > 2)
1567 return (rule->src_type == SRC_INDEX ? orig_from : to);
1571 run_cond (int depth,
1572 FontLayoutCmdCond *cond, int from, int to, FontLayoutContext *ctx)
1576 if (MDEBUG_FLAG () > 2)
1577 MDEBUG_PRINT2 ("\n [FLT] %*s(COND", depth, "");
1579 for (i = 0; i < cond->n_cmds; i++)
1581 /* TODO: Write a code for optimization utilizaing the info
1583 if ((pos = run_command (depth, cond->cmd_ids[i], from, to, ctx))
1589 if (MDEBUG_FLAG () > 2)
1596 MFLTOtfSpec *otf_spec, int from, int to, FontLayoutContext *ctx)
1598 MFLTFont *font = ctx->font;
1599 int from_idx = ctx->out->used;
1601 if (MDEBUG_FLAG () > 2)
1602 MDEBUG_PRINT3 ("\n [FLT] %*s%s", depth, "", MSYMBOL_NAME (otf_spec->sym));
1604 font->get_glyph_id (font, ctx->in, from, to);
1605 if (! font->drive_otf)
1607 if (ctx->out->used + (to - from) > ctx->out->allocated)
1609 font->get_metrics (font, ctx->in, from, to);
1610 GCPY (ctx->in, from, to - from, ctx->out, ctx->out->used);
1611 ctx->out->used += to - from;
1615 MFLTGlyphAdjustment *adjustment;
1619 adjustment = alloca ((sizeof *adjustment)
1620 * (ctx->out->allocated - ctx->out->used));
1622 MERROR (MERROR_FLT, -1);
1623 memset (adjustment, 0,
1624 (sizeof *adjustment) * (ctx->out->allocated - ctx->out->used));
1625 to = font->drive_otf (font, otf_spec, ctx->in, from, to, ctx->out,
1629 out_len = ctx->out->used - from_idx;
1630 if (otf_spec->features[1])
1632 MFLTGlyphAdjustment *a;
1635 for (i = 0, a = adjustment; i < out_len; i++, a++)
1640 font->get_metrics (font, ctx->out, from_idx, ctx->out->used);
1641 for (g = GREF (ctx->out, from_idx + i);
1642 i < out_len; i++, a++, g = NEXT (ctx->out, g))
1645 if (a->advance_is_absolute)
1650 else if (a->xadv || a->yadv)
1655 if (a->xoff || a->yoff)
1658 MFLTGlyph *gg = PREV (ctx->out, g);
1659 MFLTGlyphAdjustment *aa = a;
1663 while (aa->back > 0)
1665 for (j = 0; j < aa->back;
1666 j++, gg = PREV (ctx->out, gg))
1667 g->xoff -= gg->xadv;
1669 g->xoff += aa->xoff;
1670 g->yoff += aa->yoff;
1679 if (ctx->cluster_begin_idx >= 0)
1680 for (; from_idx < ctx->out->used; from_idx++)
1682 MFLTGlyph *g = GREF (ctx->out, from_idx);
1683 UPDATE_CLUSTER_RANGE (ctx, g);
1688 static char work[16];
1691 dump_combining_code (int code)
1693 char *vallign = "tcbB";
1694 char *hallign = "lcr";
1700 work[0] = vallign[COMBINING_CODE_BASE_Y (code)];
1701 work[1] = hallign[COMBINING_CODE_BASE_X (code)];
1702 off_y = COMBINING_CODE_OFF_Y (code);
1703 off_x = COMBINING_CODE_OFF_X (code);
1705 sprintf (work + 2, "+%d", off_y);
1707 sprintf (work + 2, "%d", off_y);
1708 else if (off_x == 0)
1709 sprintf (work + 2, ".");
1710 p = work + strlen (work);
1712 sprintf (p, ">%d", off_x);
1714 sprintf (p, "<%d", -off_x);
1716 p[0] = vallign[COMBINING_CODE_ADD_Y (code)];
1717 p[1] = hallign[COMBINING_CODE_ADD_X (code)];
1723 run_command (int depth, int id, int from, int to, FontLayoutContext *ctx)
1731 /* Direct code (== ctx->code_offset + id) output.
1732 The source is not consumed. */
1733 if (MDEBUG_FLAG () > 2)
1734 MDEBUG_PRINT3 ("\n [FLT] %*s(DIRECT 0x%X", depth, "",
1735 ctx->code_offset + id);
1736 i = (from < to || from == 0) ? from : from - 1;
1738 g = GREF (ctx->out, ctx->out->used - 1);
1739 g->code = ctx->code_offset + id;
1741 SET_MEASURED (g, 0);
1742 if (ctx->combining_code)
1743 SET_COMBINING_CODE (g, ctx, ctx->combining_code);
1744 if (ctx->left_padding)
1745 SET_LEFT_PADDING (g, ctx, LeftPaddingMask);
1746 for (i = from; i < to; i++)
1748 MFLTGlyph *tmp = GREF (ctx->in, i);
1750 if (g->from > tmp->from)
1751 g->from = tmp->from;
1752 else if (g->to < tmp->to)
1755 UPDATE_CLUSTER_RANGE (ctx, g);
1756 ctx->code_offset = ctx->combining_code = ctx->left_padding = 0;
1757 if (MDEBUG_FLAG () > 2)
1762 if (id <= CMD_ID_OFFSET_INDEX)
1764 int idx = CMD_ID_TO_INDEX (id);
1767 if (idx >= ctx->stage->used)
1768 MERROR (MERROR_DRAW, -1);
1769 cmd = ctx->stage->cmds + idx;
1770 if (cmd->type == FontLayoutCmdTypeRule)
1771 to = run_rule (depth, &cmd->body.rule, from, to, ctx);
1772 else if (cmd->type == FontLayoutCmdTypeCond)
1773 to = run_cond (depth, &cmd->body.cond, from, to, ctx);
1774 else if (cmd->type == FontLayoutCmdTypeOTF)
1775 to = run_otf (depth, &cmd->body.otf, from, to, ctx);
1779 if (id <= CMD_ID_OFFSET_COMBINING)
1781 ctx->combining_code = CMD_ID_TO_COMBINING_CODE (id);
1782 if (MDEBUG_FLAG () > 2)
1783 MDEBUG_PRINT3 ("\n [FLT] %*s(CMB %s)", depth, "",
1784 dump_combining_code (ctx->combining_code));
1795 g = GREF (ctx->out, ctx->out->used - 1);
1796 if (ctx->combining_code)
1797 SET_COMBINING_CODE (g, ctx, ctx->combining_code);
1798 if (ctx->left_padding)
1799 SET_LEFT_PADDING (g, ctx, LeftPaddingMask);
1800 UPDATE_CLUSTER_RANGE (ctx, g);
1801 if (MDEBUG_FLAG () > 2)
1804 MDEBUG_PRINT2 ("\n [FLT] %*s(COPY |)", depth, "");
1806 MDEBUG_PRINT3 ("\n [FLT] %*s(COPY 0x%X)", depth, "", g->code);
1808 ctx->code_offset = ctx->combining_code = ctx->left_padding = 0;
1812 case CMD_ID_CLUSTER_BEGIN:
1813 if (ctx->cluster_begin_idx < 0)
1815 if (MDEBUG_FLAG () > 2)
1816 MDEBUG_PRINT3 ("\n [FLT] %*s<%d", depth, "",
1817 GREF (ctx->in, from)->from);
1818 ctx->cluster_begin_idx = ctx->out->used;
1819 ctx->cluster_begin_pos = GREF (ctx->in, from)->from;
1820 ctx->cluster_end_pos = GREF (ctx->in, from)->to;
1824 case CMD_ID_CLUSTER_END:
1825 if (ctx->cluster_begin_idx >= 0
1826 && ctx->cluster_begin_idx < ctx->out->used)
1830 if (MDEBUG_FLAG () > 2)
1831 MDEBUG_PRINT1 (" %d>", ctx->cluster_end_pos + 1);
1832 for (i = ctx->cluster_begin_idx; i < ctx->out->used; i++)
1834 GREF (ctx->out, i)->from = ctx->cluster_begin_pos;
1835 GREF (ctx->out, i)->to = ctx->cluster_end_pos;
1837 ctx->cluster_begin_idx = -1;
1841 case CMD_ID_SEPARATOR:
1845 i = from < to ? from : from - 1;
1847 g = GREF (ctx->out, ctx->out->used - 1);
1848 g->c = -1, g->code = 0;
1849 g->xadv = g->yadv = 0;
1851 SET_MEASURED (g, 0);
1855 case CMD_ID_LEFT_PADDING:
1856 if (MDEBUG_FLAG () > 2)
1857 MDEBUG_PRINT2 ("\n [FLT] %*s[", depth, "");
1858 ctx->left_padding = 1;
1861 case CMD_ID_RIGHT_PADDING:
1862 if (ctx->out->used > 0)
1864 if (MDEBUG_FLAG () > 2)
1865 MDEBUG_PRINT2 ("\n [FLT] %*s]", depth, "");
1866 g = GREF (ctx->out, ctx->out->used - 1);
1867 SET_RIGHT_PADDING (g, ctx, RightPaddingMask);
1872 MERROR (MERROR_DRAW, -1);
1876 run_stages (MFLTGlyphString *gstring, int from, int to,
1877 MFLT *flt, FontLayoutContext *ctx)
1879 MFLTGlyphString buf, *temp;
1881 int orig_from = from, orig_to = to;
1882 int from_pos, to_pos, len;
1885 MPlist *stages = flt->stages;
1887 from_pos = GREF (ctx->in, from)->from;
1888 to_pos = GREF (ctx->in, to - 1)->to;
1889 len = to_pos - from_pos;
1893 GINIT (ctx->out, ctx->out->allocated);
1894 ctx->encoded = alloca (ctx->out->allocated);
1895 if (! ctx->out->glyphs || ! ctx->encoded)
1898 for (stage_idx = 0; 1; stage_idx++)
1903 ctx->stage = (FontLayoutStage *) MPLIST_VAL (stages);
1904 table = ctx->stage->category;
1905 ctx->code_offset = ctx->combining_code = ctx->left_padding = 0;
1906 for (i = from; i < to; i++)
1908 MFLTGlyph *g = GREF (ctx->in, i);
1909 char enc = (GET_ENCODED (g)
1910 ? (g->c > 0 ? (int) mchartable_lookup (table, g->c) : 1)
1912 ? (int) mchartable_lookup (table, g->code)
1915 ctx->encoded[i] = enc;
1916 if (! enc && stage_idx == 0)
1922 ctx->encoded[i] = '\0';
1923 ctx->match_indices[0] = from;
1924 ctx->match_indices[1] = to;
1925 for (i = 2; i < NMATCH; i++)
1926 ctx->match_indices[i] = -1;
1928 if (MDEBUG_FLAG () > 2)
1930 MDEBUG_PRINT2 ("\n [FLT] (STAGE %d \"%s\"", stage_idx,
1931 ctx->encoded + from);
1932 MDEBUG_PRINT (" (");
1933 for (i = from; i < to; i++)
1935 g = GREF (ctx->in, i);
1937 MDEBUG_PRINT2 ("%*s|", (i > 0), "");
1939 MDEBUG_PRINT3 ("%*s%04X", (i > 0), "", GREF (ctx->in, i)->code);
1943 result = run_command (4, INDEX_TO_CMD_ID (0), from, to, ctx);
1944 if (MDEBUG_FLAG () > 2)
1949 stages = MPLIST_NEXT (stages);
1950 /* If this is the last stage, break the loop. */
1951 if (MPLIST_TAIL_P (stages))
1954 /* Otherwise, prepare for the next stage. */
1961 GINIT (&buf, ctx->out->allocated);
1970 if (ctx->out->used > 0)
1973 int x_ppem = ctx->font->x_ppem << 6, y_ppem = ctx->font->y_ppem << 6;
1975 /* Remove separator glyphs. */
1976 for (i = 0; i < ctx->out->used;)
1978 g = GREF (ctx->out, i);
1980 GREPLACE (NULL, 0, 0, ctx->out, i, i + 1);
1985 /* Get actual glyph IDs of glyphs. */
1986 ctx->font->get_glyph_id (ctx->font, ctx->out, 0, ctx->out->used);
1988 /* Check if all characters in the range are covered by some
1989 glyph(s). If not, change <from> and <to> of glyphs to cover
1990 uncovered characters. */
1991 g_indices = alloca (sizeof (int) * len);
1994 for (i = 0; i < len; i++) g_indices[i] = -1;
1995 for (i = 0; i < ctx->out->used; i++)
1999 g = GREF (ctx->out, i);
2000 for (pos = g->from; pos <= g->to; pos++)
2001 if (g_indices[pos - orig_from] < 0)
2002 g_indices[pos - orig_from] = i;
2004 for (i = 0; i < len; i++)
2005 if (g_indices[i] < 0)
2011 for (i++; i < len && g_indices[i] < 0; i++);
2013 g = GREF (ctx->out, j);
2014 this_from = g->from;
2016 g->from = orig_from + i;
2017 } while (++j < ctx->out->used
2018 && (g = GREF (ctx->out, j))
2019 && g->from == this_from);
2025 j = g_indices[i - 1];
2026 g = GREF (ctx->out, j);
2029 g->to = orig_from + i + 1;
2031 && (g = GREF (ctx->out, j))
2032 && g->to == this_to);
2036 ctx->font->get_metrics (ctx->font, ctx->out, 0, ctx->out->used);
2038 /* Handle combining. */
2039 if (ctx->check_mask & CombiningCodeMask)
2041 MFLTGlyph *base = GREF (ctx->out, 0);
2042 int base_height = base->ascent + base->descent;
2045 for (i = 1; i < ctx->out->used; i++)
2047 if ((g = GREF (ctx->out, i))
2048 && (combining_code = GET_COMBINING_CODE (g)))
2050 int height = g->ascent + g->descent;
2051 int base_x, base_y, add_x, add_y, off_x, off_y;
2053 if (base->from > g->from)
2054 base->from = g->from;
2055 else if (base->to < g->to)
2058 base_x = COMBINING_CODE_BASE_X (combining_code);
2059 base_y = COMBINING_CODE_BASE_Y (combining_code);
2060 add_x = COMBINING_CODE_ADD_X (combining_code);
2061 add_y = COMBINING_CODE_ADD_Y (combining_code);
2062 off_x = COMBINING_CODE_OFF_X (combining_code);
2063 off_y = COMBINING_CODE_OFF_Y (combining_code);
2065 g->xoff = ((base->xadv * base_x - g->xadv * add_x) / 2
2066 + x_ppem * off_x / 100 - base->xadv);
2068 g->yoff = base_height * base_y / 2 - base->ascent;
2072 g->yoff -= height * add_y / 2 - g->ascent;
2073 g->yoff -= y_ppem * off_y / 100;
2074 if (base->lbearing > base->xadv + g->lbearing + g->xoff)
2075 base->lbearing = base->xadv + g->lbearing + g->xoff;
2076 if (base->rbearing < base->xadv + g->xadv + g->xoff)
2077 base->rbearing = base->xadv + g->xadv + g->xoff;
2078 if (base->ascent < g->ascent - g->yoff)
2079 base->ascent = g->ascent - g->yoff;
2080 if (base->descent < g->descent - g->yoff)
2081 base->descent = g->descent - g->yoff;
2082 g->xadv = g->yadv = 0;
2083 if (GET_RIGHT_PADDING (g))
2084 SET_RIGHT_PADDING (base, ctx, RightPaddingMask);
2090 base_height = g->ascent + g->descent;
2095 /* Handle padding */
2096 if (ctx->check_mask & (LeftPaddingMask | RightPaddingMask))
2097 for (i = 0; i < ctx->out->used; i++)
2099 g = GREF (ctx->out, i);
2100 if (! GET_COMBINING_CODE (g))
2102 if (GET_RIGHT_PADDING (g) && g->rbearing > g->xadv)
2104 g->xadv = g->rbearing;
2107 if (GET_LEFT_PADDING (g) && g->lbearing < 0)
2109 g->xoff += - g->lbearing;
2110 g->xadv += - g->lbearing;
2111 g->rbearing += - g->lbearing;
2119 GREPLACE (ctx->out, 0, ctx->out->used, gstring, orig_from, orig_to);
2120 to = orig_from + ctx->out->used;
2125 setup_combining_coverage (int from, int to, void *val, void *arg)
2127 int combining_class = (int) val;
2130 if (combining_class < 200)
2132 else if (combining_class <= 204)
2134 if ((combining_class % 2) == 0)
2135 category = "bcd"[(combining_class - 200) / 2];
2137 else if (combining_class <= 232)
2139 if ((combining_class % 2) == 0)
2140 category = "efghijklmnopq"[(combining_class - 208) / 2];
2142 else if (combining_class == 233)
2144 else if (combining_class == 234)
2146 else if (combining_class == 240)
2148 mchartable_set_range ((MCharTable *) arg, from, to, (void *) category);
2152 setup_combining_flt (MFLT *flt)
2155 MCharTable *combininig_class_table
2156 = mchar_get_prop_table (Mcombining_class, &type);
2158 mchartable_set_range (flt->coverage, 0, 0x10FFFF, (void *) 'u');
2159 if (combininig_class_table)
2160 mchartable_map (combininig_class_table, (void *) 0,
2161 setup_combining_coverage, flt->coverage);
2164 #define CHECK_FLT_STAGES(flt) ((flt)->stages || load_flt (flt, NULL) == 0)
2169 int m17n__flt_initialized;
2174 /* The following two are actually not exposed to a user but concealed
2175 by the macro M17N_INIT (). */
2178 m17n_init_flt (void)
2180 int mdebug_flag = MDEBUG_INIT;
2182 merror_code = MERROR_NONE;
2183 if (m17n__flt_initialized++)
2186 if (merror_code != MERROR_NONE)
2188 m17n__flt_initialized--;
2192 MDEBUG_PUSH_TIME ();
2194 Mcond = msymbol ("cond");
2195 Mrange = msymbol ("range");
2196 Mfont = msymbol ("font");
2197 Mlayouter = msymbol ("layouter");
2198 Mcombining = msymbol ("combining");
2199 Mfont_facility = msymbol ("font-facility");
2200 Mgenerator = msymbol ("generator");
2201 Mend = msymbol ("end");
2203 MDEBUG_PRINT_TIME ("INIT", (stderr, " to initialize the flt modules."));
2208 m17n_fini_flt (void)
2210 int mdebug_flag = MDEBUG_FINI;
2212 if (m17n__flt_initialized == 0
2213 || --m17n__flt_initialized > 0)
2216 MDEBUG_PUSH_TIME ();
2218 MDEBUG_PRINT_TIME ("FINI", (stderr, " to finalize the flt modules."));
2224 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
2226 /*** @addtogroup m17nFLT */
2232 @brief Return a FLT object whose name is NAME.
2234 The mflt_get () function returns a FLT object whose name is $NAME.
2237 If the operation was successfully, mflt_get () returns a pointer
2238 to a FLT object. Otherwise, it returns @c NULL. */
2241 mflt_get (MSymbol name)
2245 if (! flt_list && list_flt () < 0)
2247 flt = mplist_get (flt_list, name);
2248 if (! flt || ! CHECK_FLT_STAGES (flt))
2250 if (flt->name == Mcombining
2251 && ! mchartable_lookup (flt->coverage, 0))
2252 setup_combining_flt (flt);
2259 @brief Find a FLT suitable for a specified character and font.
2261 The mflt_find () function returns the most appropriate FLT for
2262 rendering the character $C by font $FONT.
2265 If the operation was successfully, mflt_find () returns a pointer
2266 to a FLT object. Otherwise, it returns @c NULL. */
2269 mflt_find (int c, MFLTFont *font)
2273 static MSymbol unicode_bmp = NULL, unicode_full = NULL;
2277 unicode_bmp = msymbol ("unicode-bmp");
2278 unicode_full = msymbol ("unicode-full");
2281 if (! flt_list && list_flt () < 0)
2287 MPLIST_DO (plist, flt_list)
2289 flt = MPLIST_VAL (plist);
2290 if (flt->registry != unicode_bmp
2291 && flt->registry != unicode_full)
2293 if (flt->family && flt->family != font->family)
2296 && ! mchartable_lookup (flt->coverage, c))
2300 MFLTOtfSpec *spec = &flt->otf;
2302 if (! font->check_otf)
2304 if ((spec->features[0] && spec->features[0][0] != 0xFFFFFFFF)
2305 || (spec->features[1] && spec->features[1][0] != 0xFFFFFFFF))
2308 else if (! font->check_otf (font, spec))
2318 MPLIST_DO (plist, flt_list)
2320 flt = MPLIST_VAL (plist);
2321 if (mchartable_lookup (flt->coverage, c))
2330 @brief Return a name of a FLT.
2332 The mflt_name () function returns the name of $FLT. */
2335 mflt_name (MFLT *flt)
2337 return MSYMBOL_NAME (flt->name);
2342 @brief Return a coverage of a FLT.
2344 The mflt_coverage () function returns a char-table that contains
2345 nonzero value for characters supported by $FLT. */
2348 mflt_coverage (MFLT *flt)
2350 return flt->coverage;
2355 @brief Layout characters by Font Layout Table.
2357 The mflt_run () function layout characters in $GSTRING between
2358 $FROM (inclusive) and $TO (exclusive) by $FONT. If $FLT is
2359 nonzero, it is used for all the charaters. Otherwise, appropriate
2360 FLTs are automatically chosen.
2363 The operation was successful. The value is an index to the
2364 $GSTRING->glyphs which was previously indexed by $TO.
2367 $GSTRING->glyphs is too short to store the result. A caller can
2368 call this fucntion again with the larger $GSTRING->glyphs.
2371 Some other error occurred. */
2374 mflt_run (MFLTGlyphString *gstring, int from, int to,
2375 MFLTFont *font, MFLT *flt)
2377 FontLayoutContext ctx;
2378 int match_indices[NMATCH];
2380 MFLTGlyphString out;
2381 int auto_flt = ! flt;
2383 int this_from, this_to;
2387 /* This is usually sufficient, but if not, we retry with the larger
2388 values at most 3 times. This value is also used for the
2389 allocating size of ctx.encoded. */
2390 out.allocated = (to - from) * 4;
2392 for (i = from; i < to; i++)
2394 g = GREF (gstring, i);
2396 memset (g, 0, sizeof (MFLTGlyph));
2398 g->from = g->to = i;
2401 for (this_from = from; this_from < to;)
2405 for (this_to = this_from; this_to < to; this_to++)
2406 if (mchartable_lookup (flt->coverage, GREF (gstring, this_to)->c))
2411 if (! flt_list && list_flt () < 0)
2413 font->get_glyph_id (font, gstring, this_from, to);
2414 font->get_metrics (font, gstring, this_from, to);
2418 for (this_to = this_from; this_to < to; this_to++)
2420 c = GREF (gstring, this_to)->c;
2421 if (c >= flt_min_coverage && c <= flt_max_coverage)
2424 for (; this_to < to; this_to++)
2426 c = GREF (gstring, this_to)->c;
2428 && mchartable_lookup (((MFLT *) font->internal)->coverage, c))
2430 flt = font->internal;
2433 flt = mflt_find (c, font);
2436 if (CHECK_FLT_STAGES (flt))
2438 font->internal = flt;
2445 if (this_from < this_to)
2447 font->get_glyph_id (font, gstring, this_from, this_to);
2448 font->get_metrics (font, gstring, this_from, this_to);
2449 this_from = this_to;
2454 MDEBUG_PRINT1 (" [FLT] (%s", MSYMBOL_NAME (flt->name));
2456 for (; this_to < to; this_to++)
2457 if (! mchartable_lookup (flt->coverage, GREF (gstring, this_to)->c))
2463 MDEBUG_PRINT1 (" (%s)", MSYMBOL_NAME (font->family));
2464 MDEBUG_PRINT ("\n [FLT] (SOURCE");
2465 for (i = this_from, j = 0; i < this_to; i++, j++)
2467 if (j > 0 && j % 8 == 0)
2468 MDEBUG_PRINT ("\n [FLT] ");
2469 MDEBUG_PRINT1 (" %04X", GREF (gstring, i)->c);
2474 for (i = 0; i < 3; i++)
2477 memset (&ctx, 0, sizeof ctx);
2478 ctx.match_indices = match_indices;
2480 ctx.cluster_begin_idx = -1;
2483 j = run_stages (gstring, this_from, this_to, flt, &ctx);
2497 MDEBUG_PRINT ("\n [FLT] (RESULT");
2498 if (MDEBUG_FLAG () > 1)
2499 for (i = 0; this_from < this_to; this_from++, i++)
2501 if (i > 0 && i % 4 == 0)
2502 MDEBUG_PRINT ("\n [FLT] ");
2503 g = GREF (gstring, this_from);
2504 MDEBUG_PRINT4 (" (%04X %d %d %d)",
2505 g->code, g->xadv, g->xoff, g->yoff);
2508 for (; this_from < this_to; this_from++)
2509 MDEBUG_PRINT1 (" %04X", GREF (gstring, this_from)->code);
2510 MDEBUG_PRINT ("))\n");
2512 this_from = this_to;
2517 int len = to - from;
2520 memcpy (((char *) out.glyphs),
2521 ((char *) gstring->glyphs) + gstring->glyph_size * from,
2522 gstring->glyph_size * len);
2523 for (i = from, j = to; i < to;)
2525 for (k = i + 1, j--; k < to && GREF (&out, k)->xadv == 0;
2527 GCPY (&out, i, (k - i), gstring, j);
2536 /* for debugging... */
2539 dump_flt_cmd (FontLayoutStage *stage, int id, int indent)
2541 char *prefix = (char *) alloca (indent + 1);
2543 memset (prefix, 32, indent);
2547 fprintf (stderr, "0x%02X", id);
2548 else if (id <= CMD_ID_OFFSET_INDEX)
2550 int idx = CMD_ID_TO_INDEX (id);
2551 FontLayoutCmd *cmd = stage->cmds + idx;
2553 if (cmd->type == FontLayoutCmdTypeRule)
2555 FontLayoutCmdRule *rule = &cmd->body.rule;
2558 fprintf (stderr, "(rule ");
2559 if (rule->src_type == SRC_REGEX)
2560 fprintf (stderr, "\"%s\"", rule->src.re.pattern);
2561 else if (rule->src_type == SRC_INDEX)
2562 fprintf (stderr, "%d", rule->src.match_idx);
2563 else if (rule->src_type == SRC_SEQ)
2564 fprintf (stderr, "(seq)");
2565 else if (rule->src_type == SRC_RANGE)
2566 fprintf (stderr, "(range)");
2568 fprintf (stderr, "(invalid src)");
2570 for (i = 0; i < rule->n_cmds; i++)
2572 fprintf (stderr, "\n%s ", prefix);
2573 dump_flt_cmd (stage, rule->cmd_ids[i], indent + 2);
2575 fprintf (stderr, ")");
2577 else if (cmd->type == FontLayoutCmdTypeCond)
2579 FontLayoutCmdCond *cond = &cmd->body.cond;
2582 fprintf (stderr, "(cond");
2583 for (i = 0; i < cond->n_cmds; i++)
2585 fprintf (stderr, "\n%s ", prefix);
2586 dump_flt_cmd (stage, cond->cmd_ids[i], indent + 2);
2588 fprintf (stderr, ")");
2590 else if (cmd->type == FontLayoutCmdTypeOTF)
2592 fprintf (stderr, "(otf)");
2595 fprintf (stderr, "(error-command)");
2597 else if (id <= CMD_ID_OFFSET_COMBINING)
2598 fprintf (stderr, "cominging-code");
2600 fprintf (stderr, "(predefiend %d)", id);
2604 mdebug_dump_flt (MFLT *flt, int indent)
2606 char *prefix = (char *) alloca (indent + 1);
2610 memset (prefix, 32, indent);
2612 fprintf (stderr, "(flt");
2613 MPLIST_DO (plist, flt->stages)
2615 FontLayoutStage *stage = (FontLayoutStage *) MPLIST_VAL (plist);
2618 fprintf (stderr, "\n%s (stage %d", prefix, stage_idx);
2619 for (i = 0; i < stage->used; i++)
2621 fprintf (stderr, "\n%s ", prefix);
2622 dump_flt_cmd (stage, INDEX_TO_CMD_ID (i), indent + 4);
2624 fprintf (stderr, ")");
2627 fprintf (stderr, ")");