1 /* m17n-flt.c -- Font Layout Table sub-module.
2 Copyright (C) 2003, 2004, 2007, 2008, 2009, 2010, 2011, 2012
3 National Institute of Advanced Industrial Science and Technology (AIST)
4 Registration Number H15PRO112
5
6 This file is part of the m17n library.
7
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.
12
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.
17
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,
21 Boston, MA 02110-1301 USA. */
22
23 /***en
24 @addtogroup m17nFLT
25 @brief FLT support for a window system.
26
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. */
30
31 /***ja
32 @addtogroup m17nFLT
33 @brief ������ɥ������ƥ�Τ���� FLT ���ݡ���.
34
35 ���Υ��������Ǥϡ�FLT (Font Layout Table)
36 ���Ѥ���ʸ���쥤�����ȵ�ǽ�˴ؤ��� m17n FLT API ��������롣
37 FLT �η����� @ref mdbFLT �˵��Ҥ���Ƥ��롣 */
38
39 /*=*/
40
41 #if !defined (FOR_DOXYGEN) || defined (DOXYGEN_INTERNAL_MODULE)
42 /*** @addtogroup m17nInternal
43 @{ */
44
45 #include "config.h"
46
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <ctype.h>
51 #include <sys/types.h>
52 #include <regex.h>
53
54 #include "m17n-core.h"
55 #include "m17n-flt.h"
56 #include "m17n-misc.h"
57 #include "internal.h"
58 #include "mtext.h"
59 #include "symbol.h"
60 #include "plist.h"
61 #include "database.h"
62 #include "internal-flt.h"
63
64 /* Font Layouter */
65
66 /* Font Layout Table (FLT)
67
68 Predefined terms: SYMBOL, INTEGER, STRING
69
70 FLT ::= '(' STAGE + ')'
71
72 STAGE ::= CATEGORY-TABLE ? FONT-LAYOUT-RULE
73
74 ;; Each STAGE consumes a source (code sequence) and produces another
75 ;; code sequence that is given to the next STAGE as a source. The
76 ;; source given to the first stage is a sequence of character codes
77 ;; that are assigned category codes by CATEGORY-TABLE. The output of
78 ;; the last stage is a glyph code sequence given to the renderer.
79
80 CATEGORY-TABLE ::=
81 '(' 'category' CATEGORY-SPEC + ')'
82 CATEGORY-SPEC ::=
83 '(' CODE [ CODE ] CATEGORY ')'
84 CODE ::= INTEGER
85 CATEGORY ::= INTEGER
86 ;; ASCII character codes of alphabet ('A' .. 'Z' 'a' .. 'z').
87 ;; Ex: CATEGORY-TABLE
88 ;; (category
89 ;; (0x0900 0x097F ?E) ; All Devanagari characters
90 ;; (0x093C ?N)) ; DEVANAGARI-LETTER NUKTA
91 ;; Assign the category 'E' to all Devanagari characters but 0x093C,
92 ;; assign the category 'N' to 0x093C.
93
94 FONT-LAYOUT-RULE ::=
95 '(' 'generator' RULE MACRO-DEF * ')'
96
97 RULE ::= COMMAND | REGEXP-RULE | MATCH-RULE | MAP-RULE
98 | COND-STRUCT | MACRO-NAME
99
100 COMMAND ::=
101 DIRECT-CODE | COMBINING | PREDEFIND-COMMAND | OTF-COMMAND
102
103 DIRECT-CODE ::= INTEGER
104 ;; Always succeed. Produce the code. Consume no source.
105
106 PREDEFIND-COMMAND ::=
107 '=' | '*' | '<' | '>' | '|'
108
109 ;; '=': Succeed when the current run contains at least one code.
110 ;; Consume the first code in the current run, and produce it as is.
111
112 ;; '*': If the the previous command succeeded, repeat it until it
113 ;; fails.
114
115 ;; '<': Produce a special code that indicates the start of grapheme
116 ;; cluster. Succeed always, consume nothing.
117
118 ;; '>': Produce a special code that indicates the end of grapheme
119 ;; cluster. Succeed always, consume nothing.
120
121 ;; '|': Produce a special code whose category is ' '. Succeed always,
122 ;; consume nothing.
123
124 OTF-COMMAND ::=
125 ':otf=''SCRIPT'[':'['LANGSYS'][':'[GSUB-FEATURES][':'GPOS-FEATURES]]]
126 ;; Run the Open Type Layout Table on the current run. Succeed always,
127 ;; consume all glyphs in the current range.
128
129 SCRIPT ::= OTF-TAG
130 ;; OTF's ScriptTag name (four letters) listed at:
131 ;; <http://www.microsoft.om/typograph/otspec/scripttags.htm>
132 LANGSYS ::= OTF-TAG
133 ;; OTF's Language System name (four letters) listed at:
134 ;; <http://www.microsoft.om/typograph/otspec/languagetags.htm>
135
136 GSUB-FEATURES ::= [FEATURE[,FEATURE]*] | ' '
137 GPOS-FEATURES ::= [FEATURE[,FEATURE]*] | ' '
138 FEATURE ::= OTF-TAG
139 ;; OTF's Feature name (four letters) listed at:
140 ;; <http://www.microsoft.om/typograph/otspec/???.htm>
141
142 OTF-TAG ::= PRINTABLE-CHAR PRINTABLE-CHAR PRINTABLE-CHAR PRINTABLE-CHAR
143
144 ;; Ex. OTF-COMMAND
145 ;; 'otf:deva'
146 ;; Run all features in the default langsys of 'deva' script.
147 ;; 'otf:deva::nukt:haln'
148 ;; Run all GSUB features, run 'nukt' and 'haln' GPOS features.
149 ;; 'otf:deva:: :'
150 ;; Run all GSUB features, run no GPOS features.
151
152 REGEXP-RULE ::=
153 '(' REGEXP RULE * ')'
154
155 ;; Succeed if REGXP matches the head of source. Run RULEs while
156 ;; limiting the source to the matching part. Consume that part.
157
158 REGEXP ::= STRING
159 ;; Must be composed only from ASCII characters. 'A' - 'Z', 'a' - 'z'
160 ;; correspond to CATEGORY.
161
162 ;; Ex: REGEXP-RULE
163 ;; ("VA?"
164 ;; < | vowel * | >)
165
166 MATCH-RULE ::=
167 '(' MATCH-IDX RULE * ')'
168
169 ;; Succeed if the previous REGEXP-RULE found a matching part for
170 ;; MATCH-IDX. Run RULEs while limiting the source to the matching
171 ;; part. If MATCH-IDX is zero, consume the whole part, else consume
172 ;; nothing.
173
174 MATCH-IDX ::= INTEGER
175 ;; Must be 0..20.
176
177 ;; Ex. MATCH-RULE
178 ;; (2 consonant *)
179
180 MAP-RULE ::=
181 '(' ( SOURCE-SEQ | SOURCE-RANGE ) RULE * ')'
182
183 ;; Succeed if the source matches SOURCE-SEQ or SOURCE-RANGE. Run
184 ;; RULEs while limiting the source to the matching part. Consume that
185 ;; part.
186
187 SOURCE-SEQ ::=
188 '(' CODE + ')'
189 SOURCE-RANGE ::=
190 '(' 'range' CODE CODE ')'
191 ;; Ex. MAP-RULE
192 ;; ((0x0915 0x094D) 0x43)
193 ;; If the source code sequence is 0x0915 0x094D, produce 0x43.
194 ;; ((range 0x0F40 0x0F6A) 0x2221)
195 ;; If the first source code CODE is in the range 0x0F40..0x0F6A,
196 ;; produce (0x2221 + (CODE - 0x0F40)).
197
198 COND-STRUCT ::=
199 '(' 'cond' RULE + ')'
200
201 ;; Try each rule in sequence until one succeeds. Succeed if one
202 ;; succeeds. Consume nothing.
203
204 ;; Ex. COND-STRUCT
205 ;; (cond
206 ;; ((0x0915 0x094D) 0x43)
207 ;; ((range 0x0F40 0x0F6A) 0x2221)
208 ;; = )
209
210 COMBINING ::= 'V''H''O''V''H'
211 V ::= ( 't' | 'c' | 'b' | 'B' )
212 H ::= ( 'l' | 'c' | 'r' )
213 O ::= ( '.' | XOFF | YOFF | XOFF YOFF )
214 XOFF ::= '<'INTEGER | '>'INTEGER
215 YOFF ::= '+'INTEGER | '-'INTEGER
216 ;; INTEGER must be integer 0..127
217
218 ;; VH pair indicates 12 reference points of a glyph as below:
219 ;;
220 ;; 0----1----2 <---- ascent 0:tl (top-left)
221 ;; | | 1:tc (top-center)
222 ;; | | 2:tr (top-right)
223 ;; | | 3:Bl (base-left)
224 ;; 9 10 11 <---- center 4:Bc (base-center)
225 ;; | | 5:Br (base-right)
226 ;; --3----4----5-- <-- baseline 6:bl (bottom-left)
227 ;; | | 7:bc (bottom-center)
228 ;; 6----7----8 <---- descent 8:br (bottom-right)
229 ;; 9:cl (center-left)
230 ;; | | | 10:cc (center-center)
231 ;; left center right 11:cr (center-right)
232 ;;
233 ;; Ex. COMBINING
234 ;; 'tc.bc':
235 ;; Align top-left point of the previous glyph and bottom-center
236 ;; point of the current glyph.
237 ;; 'Bl<20-10Br'
238 ;; Align 20% left and 10% below of base-left point of the previous
239 ;; glyph and base-right point of the current glyph.
240
241 MACRO-DEF ::=
242 '(' MACRO-NAME RULE + ')'
243 MACRO-NAME ::= SYMBOL
244
245 */
246
247 static int mdebug_flag = MDEBUG_FLT;
248
249 MSymbol Mfont, Mlayouter, Mcombining;
250
251 static MSymbol Mgenerator, Mend;
252
253 static MPlist *flt_list;
254 static int flt_min_coverage, flt_max_coverage;
255
256 enum GlyphInfoMask
257 {
258 CategoryCodeMask = 0x7F,
259 CombiningCodeMask = 0xFFFFFF,
260 CombinedMask = 1 << 28,
261 LeftPaddingMask = 1 << 29,
262 RightPaddingMask = 1 << 30
263 };
264
265 #define SET_GLYPH_INFO(g, mask, ctx, info) \
266 ((g)->internal = (((g)->internal & ~(mask)) | (info)), \
267 (ctx)->check_mask |= (mask))
268
269 #define GET_CATEGORY_CODE(g) ((g)->internal & CategoryCodeMask)
270 #define SET_CATEGORY_CODE(g, code) \
271 ((g)->internal = (((g)->internal & ~(CombiningCodeMask | CombinedMask)) \
272 | (code)))
273 #define GET_COMBINED(g) ((g)->internal & CombinedMask)
274 #define GET_COMBINING_CODE(g) ((g)->internal & CombiningCodeMask)
275 #define SET_COMBINING_CODE(g, ctx, code) \
276 SET_GLYPH_INFO (g, CombiningCodeMask | CombinedMask, ctx, \
277 (code) | CombinedMask)
278 #define GET_LEFT_PADDING(g) ((g)->internal & LeftPaddingMask)
279 #define SET_LEFT_PADDING(g, ctx, flag) \
280 SET_GLYPH_INFO (g, LeftPaddingMask, ctx, flag)
281 #define GET_RIGHT_PADDING(g) ((g)->internal & RightPaddingMask)
282 #define SET_RIGHT_PADDING(g, ctx, flag) \
283 SET_GLYPH_INFO (g, RightPaddingMask, ctx, flag)
284 #define GET_ENCODED(g) ((g)->encoded)
285 #define SET_ENCODED(g, flag) ((g)->encoded = (flag))
286 #define GET_MEASURED(g) ((g)->measured)
287 #define SET_MEASURED(g, flag) ((g)->measured = (flag))
288
289 #define GINIT(gstring, n) \
290 do { \
291 if (! (gstring)->glyph_size) \
292 (gstring)->glyph_size = sizeof (MFLTGlyph); \
293 (gstring)->glyphs = alloca ((gstring)->glyph_size * (n)); \
294 (gstring)->allocated = (n); \
295 (gstring)->used = 0; \
296 } while (0)
297
298 #define GALLOCA (gstring) \
299 ((MFLTGlyph *) alloca ((gstring)->glyph_size))
300
301 #define GREF(gstring, idx) \
302 ((MFLTGlyph *) ((char *) ((gstring)->glyphs) + (gstring)->glyph_size * (idx)))
303
304 #define PREV(gstring, g) \
305 ((MFLTGlyph *) ((char *) (g) - (gstring)->glyph_size))
306
307 #define NEXT(gstring, g) \
308 ((MFLTGlyph *) ((char *) (g) + (gstring)->glyph_size))
309
310 #define GCPY(src, src_idx, n, tgt, tgt_idx) \
311 do { \
312 memcpy ((char *) ((tgt)->glyphs) + (tgt)->glyph_size * (tgt_idx), \
313 (char *) ((src)->glyphs) + (src)->glyph_size * (src_idx), \
314 (src)->glyph_size * (n)); \
315 } while (0)
316
317 #define GDUP(ctx, idx) \
318 do { \
319 MFLTGlyphString *src = (ctx)->in; \
320 MFLTGlyphString *tgt = (ctx)->out; \
321 if (tgt->allocated <= tgt->used) \
322 return -2; \
323 GCPY (src, (idx), 1, tgt, tgt->used); \
324 tgt->used++; \
325 } while (0)
326
327 static int
GREPLACE(MFLTGlyphString * src,int src_from,int src_to,MFLTGlyphString * tgt,int tgt_from,int tgt_to)328 GREPLACE (MFLTGlyphString *src, int src_from, int src_to,
329 MFLTGlyphString *tgt, int tgt_from, int tgt_to)
330 {
331 int src_len = src_to - src_from;
332 int tgt_len = tgt_to - tgt_from;
333 int inc = src_len - tgt_len;
334
335 if (tgt->allocated < tgt->used + inc)
336 return -2;
337 if (inc != 0 && tgt_to < tgt->used)
338 memmove ((char *) tgt->glyphs + tgt->glyph_size * (tgt_from + src_len),
339 (char *) tgt->glyphs + tgt->glyph_size * tgt_to,
340 tgt->glyph_size * (tgt->used - tgt_to));
341 if (src_len)
342 memcpy ((char *) tgt->glyphs + tgt->glyph_size * tgt_from,
343 (char *) src->glyphs + src->glyph_size * src_from,
344 src->glyph_size * src_len);
345 tgt->used += inc;
346 return 0;
347 }
348
349
350 /* Command ID:
351 0 ... : direct code
352 -1 : invalid
353 -0x0F .. -2 : builtin commands
354 -0x100000F .. -0x10 : combining code
355 ... -0x1000010: index to FontLayoutStage->cmds
356 */
357
358 #define INVALID_CMD_ID -1
359 #define CMD_ID_OFFSET_BUILTIN -3
360 #define CMD_ID_OFFSET_COMBINING -0x10
361 #define CMD_ID_OFFSET_INDEX -0x1000010
362
363 /* Builtin commands. */
364 #define CMD_ID_COPY -3 /* '=' */
365 #define CMD_ID_REPEAT -4 /* '*' */
366 #define CMD_ID_CLUSTER_BEGIN -5 /* '<' */
367 #define CMD_ID_CLUSTER_END -6 /* '>' */
368 #define CMD_ID_SEPARATOR -7 /* '|' */
369 #define CMD_ID_LEFT_PADDING -8 /* '[' */
370 #define CMD_ID_RIGHT_PADDING -9 /* ']' */
371
372 #define CMD_ID_TO_COMBINING_CODE(id) (CMD_ID_OFFSET_COMBINING - (id))
373 #define COMBINING_CODE_TO_CMD_ID(code) (CMD_ID_OFFSET_COMBINING - (code))
374
375 #define CMD_ID_TO_INDEX(id) (CMD_ID_OFFSET_INDEX - (id))
376 #define INDEX_TO_CMD_ID(idx) (CMD_ID_OFFSET_INDEX - (idx))
377
378 static MSymbol Mcond, Mrange, Mfont_facility, Mequal;
379
380 #define GLYPH_CODE_P(code) \
381 ((code) >= GLYPH_CODE_MIN && (code) <= GLYPH_CODE_MAX)
382
383 #define GLYPH_CODE_INDEX(code) ((code) - GLYPH_CODE_MIN)
384
385 #define UPDATE_CLUSTER_RANGE(ctx, g) \
386 do { \
387 if (ctx->cluster_begin_pos > (g)->from) \
388 ctx->cluster_begin_pos = (g)->from; \
389 if (ctx->cluster_end_pos < (g)->to) \
390 ctx->cluster_end_pos = (g)->to; \
391 } while (0)
392
393 enum FontLayoutCmdRuleSrcType
394 {
395 SRC_REGEX,
396 SRC_INDEX,
397 SRC_SEQ,
398 SRC_RANGE,
399 SRC_HAS_GLYPH,
400 SRC_OTF_SPEC
401 };
402
403 typedef struct
404 {
405 enum FontLayoutCmdRuleSrcType src_type;
406 union {
407 struct {
408 char *pattern;
409 regex_t preg;
410 } re;
411 int match_idx;
412 struct {
413 int n_codes;
414 int *codes;
415 } seq;
416 struct {
417 int from, to;
418 } range;
419 struct {
420 int len;
421 MPlist *codes;
422 MFLTOtfSpec otf_spec;
423 } facility;
424 } src;
425
426 int n_cmds;
427 int *cmd_ids;
428 } FontLayoutCmdRule;
429
430 typedef struct
431 {
432 /* Beginning and end indices of series of SEQ commands. */
433 int seq_beg, seq_end;
434 /* Range of the first character appears in the above series. */
435 int seq_from, seq_to;
436
437 int n_cmds;
438 int *cmd_ids;
439 } FontLayoutCmdCond;
440
441 enum FontLayoutCmdType
442 {
443 FontLayoutCmdTypeRule,
444 FontLayoutCmdTypeCond,
445 FontLayoutCmdTypeOTF,
446 FontLayoutCmdTypeOTFCategory,
447 FontLayoutCmdTypeMAX
448 };
449
450 typedef struct
451 {
452 enum FontLayoutCmdType type;
453 union {
454 FontLayoutCmdRule rule;
455 FontLayoutCmdCond cond;
456 MFLTOtfSpec otf;
457 } body;
458 } FontLayoutCmd;
459
460 typedef struct
461 {
462 int size;
463 unsigned int *tag;
464 char *code;
465 } FeatureCodeTable;
466
467 typedef struct
468 {
469 MCharTable *table;
470 FeatureCodeTable feature_table;
471 /* Non-null if the table must be re-configured by OTF specs included
472 in the definition. */
473 MPlist *definition;
474 } FontLayoutCategory;
475
476 typedef struct
477 {
478 FontLayoutCategory *category;
479 int size, inc, used;
480 FontLayoutCmd *cmds;
481 } FontLayoutStage;
482
483 struct _MFLT
484 {
485 MSymbol name;
486 MSymbol family;
487 MSymbol registry;
488 MFLTOtfSpec otf;
489 MDatabase *mdb;
490 FontLayoutCategory *coverage;
491 MPlist *stages;
492 int need_config;
493 /* Font for which coverage or some of categories are configured. */
494 MSymbol font_id;
495 };
496
497 /* Font layout table loader */
498
499 static int parse_otf_command (MSymbol symbol, MFLTOtfSpec *spec);
500
501 static void
apply_otf_feature(MFLTFont * font,MFLTOtfSpec * spec,int from,int to,MCharTable * table,int category)502 apply_otf_feature (MFLTFont *font, MFLTOtfSpec *spec,
503 int from, int to, MCharTable *table, int category)
504 {
505 unsigned char *buf;
506 int i;
507
508 if (! mflt_iterate_otf_feature)
509 return;
510 buf = alloca (to + 1 - from);
511 memset (buf, 0, to + 1 - from);
512 if (mflt_iterate_otf_feature (font, spec, from, to, buf) < 0)
513 return;
514 for (i = to - from; i >= 0; i--)
515 if (buf[i])
516 mchartable_set (table, from + i, (void *) category);
517 }
518
519 static unsigned int gen_otf_tag (char *p, int shift);
520
521 /* Load a category table from PLIST. PLIST has this form:
522 PLIST ::= ( FROM-CODE TO-CODE ? CATEGORY-CHAR ) *
523 */
524
525 static FontLayoutCategory *
load_category_table(MPlist * plist,MFLTFont * font)526 load_category_table (MPlist *plist, MFLTFont *font)
527 {
528 FontLayoutCategory *category;
529 MCharTable *table;
530 MPlist *feature_table_head = NULL;
531 int feature_table_size = 0;
532 MPlist *p;
533 int need_otf = 0;
534
535 table = mchartable (Minteger, (void *) 0);
536 MPLIST_DO (p, plist)
537 {
538 MPlist *elt;
539 int from, to, category_code;
540
541 if (! MPLIST_PLIST_P (p))
542 MERROR_GOTO (MERROR_FLT, end);
543 elt = MPLIST_PLIST (p);
544 if (MPLIST_SYMBOL_P (elt))
545 {
546 MPlist *next;
547
548 if (! mflt_enable_new_feature)
549 {
550 M17N_OBJECT_UNREF (table);
551 return NULL;
552 }
553 next = MPLIST_NEXT (elt);
554 if (! MPLIST_INTEGER_P (next))
555 MERROR_GOTO (MERROR_FLT, end);
556 if (! feature_table_head)
557 feature_table_head = p;
558 feature_table_size++;
559 continue;
560 }
561 if (! MPLIST_INTEGER_P (elt))
562 MERROR_GOTO (MERROR_FLT, end);
563 from = MPLIST_INTEGER (elt);
564 elt = MPLIST_NEXT (elt);
565 if (! MPLIST_INTEGER_P (elt))
566 MERROR_GOTO (MERROR_FLT, end);
567 to = MPLIST_INTEGER (elt);
568 elt = MPLIST_NEXT (elt);
569 if (MPLIST_TAIL_P (elt))
570 {
571 category_code = to;
572 to = from;
573 }
574 else if (MPLIST_SYMBOL_P (elt))
575 {
576 if (! mflt_enable_new_feature)
577 {
578 M17N_OBJECT_UNREF (table);
579 return NULL;
580 }
581 if (font)
582 {
583 MFLTOtfSpec spec;
584 if (parse_otf_command (MPLIST_SYMBOL (elt), &spec) < 0)
585 MERROR_GOTO (MERROR_FLT, end);
586 elt = MPLIST_NEXT (elt);
587 if (! MPLIST_INTEGER_P (elt))
588 MERROR_GOTO (MERROR_FLT, end);
589 category_code = MPLIST_INTEGER (elt);
590 if (! isalnum (category_code))
591 MERROR_GOTO (MERROR_FLT, end);
592 apply_otf_feature (font, &spec, from, to, table, category_code);
593 }
594 else
595 need_otf = 1;
596 continue;
597 }
598 else
599 {
600 if (! MPLIST_INTEGER_P (elt))
601 MERROR_GOTO (MERROR_FLT, end);
602 category_code = MPLIST_INTEGER (elt);
603 }
604 if (! isalnum (category_code))
605 MERROR_GOTO (MERROR_FLT, end);
606
607 if (from == to)
608 mchartable_set (table, from, (void *) category_code);
609 else
610 mchartable_set_range (table, from, to, (void *) category_code);
611 }
612
613 end:
614 category = calloc (1, sizeof (FontLayoutCategory));
615 category->table = table;
616 if (need_otf)
617 {
618 category->definition = plist;
619 M17N_OBJECT_REF (plist);
620 }
621 else
622 category->definition = NULL;
623 if (feature_table_head)
624 {
625 int i = 0;
626 category->feature_table.size = feature_table_size;
627 category->feature_table.tag = malloc (sizeof (unsigned int)
628 * feature_table_size);
629 category->feature_table.code = malloc (feature_table_size);
630
631 MPLIST_DO (p, feature_table_head)
632 {
633 MPlist *elt;
634 MSymbol feature;
635 if (! MPLIST_PLIST_P (p))
636 continue;
637 elt = MPLIST_PLIST (p);
638 if (! MPLIST_SYMBOL_P (elt))
639 continue;
640 feature = MPLIST_SYMBOL (elt);
641 elt = MPLIST_NEXT (elt);
642 if (! MPLIST_INTEGER_P (elt))
643 continue;
644 category->feature_table.tag[i]
645 = gen_otf_tag (MSYMBOL_NAME (feature), 7);
646 category->feature_table.code[i] = MPLIST_INTEGER (elt);
647 i++;
648 }
649 }
650 return category;
651 }
652
653 #define ref_category_table(CATEGORY) M17N_OBJECT_REF ((CATEGORY)->table)
654
655 static void
unref_category_table(FontLayoutCategory * category)656 unref_category_table (FontLayoutCategory *category)
657 {
658 M17N_OBJECT_UNREF (category->table);
659 if (! category->table)
660 {
661 if (category->definition)
662 M17N_OBJECT_UNREF (category->definition);
663 if (category->feature_table.size > 0)
664 {
665 free (category->feature_table.tag);
666 free (category->feature_table.code);
667 }
668 free (category);
669 }
670 }
671
672 static unsigned int
gen_otf_tag(char * p,int shift)673 gen_otf_tag (char *p, int shift)
674 {
675 unsigned int tag = 0;
676 int i;
677
678 for (i = 0; i < 4 && *p; i++, p++)
679 tag = (tag << shift) | *p;
680 for (; i < 4; i++)
681 tag = (tag << shift) | 0x20;
682 return tag;
683 }
684
685 static char *
otf_count_features(char * p,char * end,char stopper,int * count)686 otf_count_features (char *p, char *end, char stopper, int *count)
687 {
688 int negative = 0;
689
690 *count = 0;
691 if (*p != stopper && *p != '\0')
692 while (1)
693 {
694 (*count)++;
695 if (*p == '*')
696 {
697 p++;
698 if (*p == stopper || *p == '\0')
699 break;
700 return NULL;
701 }
702 if (*p == '~')
703 {
704 if (negative++ == 0)
705 (*count)++;
706 p += 5;
707 }
708 else
709 p += 4;
710 if (p > end)
711 return NULL;
712 if (*p == stopper || *p == '\0')
713 break;
714 if (*p != ',')
715 return NULL;
716 p++;
717 if (! *p)
718 return NULL;
719 }
720 return p;
721 }
722
723 static void
otf_store_features(char * p,char * end,unsigned * buf)724 otf_store_features (char *p, char *end, unsigned *buf)
725 {
726 int negative = 0;
727 int i;
728
729 for (i = 0; p < end;)
730 {
731 if (*p == '*')
732 buf[i++] = 0xFFFFFFFF, p += 2, negative = 1;
733 else if (*p == '~')
734 {
735 if (negative++ == 0)
736 buf[i++] = 0xFFFFFFFF;
737 buf[i++] = gen_otf_tag (p + 1, 8), p += 6;
738 }
739 else
740 buf[i++] = gen_otf_tag (p, 8), p += 5;
741 }
742 buf[i] = 0;
743 }
744
745 /* SYMBOL's name features[0] for checking for applying
746 features[1] GSUB GPOS GSUB GPOS
747 ------------- ------------------ ------------- ------------
748 SCRIPT [-1,0] [-1,0] any | any all all
749 SCRIPT= NULL [-1,0] none & 1 none all
750 SCRIPT+ [-1,0] NULL 1 & none all none
751 SCRIPT=+ NULL NULL none & none none none
752 SCRIPT=F1 [F1,0] [-1,0] F1 & 1 F1 all
753 SCRIPT+F1 [-1][0] [F1,0] 1 & F1 none F1
754 SCRIPT=F1+ [F1,0] NULL F1 & none F1 none
755 SCRIPT=~F2 [-1,F2,0] [-1,0] ~F2 & 1 all~F2 all
756 SCRIPT=F1,~F2 [F1,-1,F2,0][-1,0] F1&~F2 & 1 F1 (*1) all
757
758 (*1) Invalid specification
759 */
760
761 static int
parse_otf_command(MSymbol symbol,MFLTOtfSpec * spec)762 parse_otf_command (MSymbol symbol, MFLTOtfSpec *spec)
763 {
764 char *str = MSYMBOL_NAME (symbol);
765 char *end = str + MSYMBOL_NAMELEN (symbol);
766 unsigned int script, langsys;
767 char *features[3];
768 int feature_count[2]; /* [0]:GSUB, [1]:GPOS */
769 int i;
770 char *p;
771
772 memset (spec, 0, sizeof (MFLTOtfSpec));
773
774 spec->sym = symbol;
775 str += 5; /* skip the heading ":otf=" or ":otf?" */
776 if (str[-1] == '?')
777 {
778 if (! mflt_enable_new_feature)
779 /* The client can't use this command. */
780 return -1;
781 if (! *str)
782 /* This is a spec to reset category codes. */
783 return 0;
784 }
785 spec->script = gen_otf_tag (str, 8);
786 str += 4;
787 if (*str == '/')
788 {
789 spec->langsys = gen_otf_tag (str, 8);
790 str += 4;
791 }
792 else
793 spec->langsys = 0;
794 features[0] = str;
795 if (*str != '=')
796 /* Apply all GSUB features. */
797 feature_count[0] = -1;
798 else
799 {
800 p = str + 1;
801 str = otf_count_features (p, end, '+', feature_count);
802 if (! str)
803 MERROR (MERROR_FLT, -1);
804 }
805 features[1] = str;
806 if (*str != '+')
807 /* Apply all GPOS features. */
808 feature_count[1] = -1;
809 else
810 {
811 p = str + 1;
812 str = otf_count_features (p, end, '\0', feature_count + 1);
813 if (! str)
814 MERROR (MERROR_FLT, -1);
815 }
816 features[2] = str;
817 for (i = 0; i < 2; i++)
818 if (feature_count[i])
819 {
820 spec->features[i] = malloc (sizeof (int)
821 * (feature_count[i] < 0 ? 2
822 : feature_count[i] + 1));
823 if (! spec->features[i])
824 return -2;
825 if (feature_count[i] > 0)
826 otf_store_features (features[i] + 1, features[i + 1],
827 spec->features[i]);
828 else
829 spec->features[i][0] = 0xFFFFFFFF, spec->features[i][1] = 0;
830 }
831
832 return 0;
833 }
834
835
836 /* Parse OTF command name NAME and store the result in CMD.
837 NAME has this form:
838 :SCRIPT[/[LANGSYS][=[GSUB-FEATURES][+GPOS-FEATURES]]]
839 where GSUB-FEATURES and GPOS-FEATURES have this form:
840 [FEATURE[,FEATURE]*] | ' ' */
841
842 static int
load_otf_command(FontLayoutCmd * cmd,MSymbol sym)843 load_otf_command (FontLayoutCmd *cmd, MSymbol sym)
844 {
845 char *name = MSYMBOL_NAME (sym);
846 int result;
847
848 if (name[0] != ':')
849 {
850 /* This is old format of "otf:...". Change it to ":otf=...". */
851 char *str = alloca (MSYMBOL_NAMELEN (sym) + 2);
852
853 sprintf (str, ":otf=");
854 strcat (str, name + 4);
855 sym = msymbol (str);
856 }
857
858 result = parse_otf_command (sym, &cmd->body.otf);
859 if (result == -2)
860 return result;
861 cmd->type = (name[4] == '?' ? FontLayoutCmdTypeOTFCategory
862 : FontLayoutCmdTypeOTF);
863 return 0;
864 }
865
866
867 /* Read a decimal number from STR preceded by one of "+-><". '+' and
868 '>' means a plus sign, '-' and '<' means a minus sign. If the
869 number is greater than 127, limit it to 127. */
870
871 static int
read_decimal_number(char ** str)872 read_decimal_number (char **str)
873 {
874 char *p = *str;
875 int sign = (*p == '-' || *p == '<') ? -1 : 1;
876 int n = 0;
877
878 p++;
879 while (*p >= '0' && *p <= '9')
880 n = n * 10 + *p++ - '0';
881 *str = p;
882 if (n == 0)
883 n = 5;
884 return (n < 127 ? n * sign : 127 * sign);
885 }
886
887
888 /* Read a horizontal and vertical combining positions from STR, and
889 store them in the place pointed by X and Y. The horizontal
890 position left, center, and right are represented by 0, 1, and 2
891 respectively. The vertical position top, center, bottom, and base
892 are represented by 0, 1, 2, and 3 respectively. If successfully
893 read, return 0, else return -1. */
894
895 static int
read_combining_position(char * str,int * x,int * y)896 read_combining_position (char *str, int *x, int *y)
897 {
898 int c = *str++;
899 int i;
900
901 /* Vertical position comes first. */
902 for (i = 0; i < 4; i++)
903 if (c == "tcbB"[i])
904 {
905 *y = i;
906 break;
907 }
908 if (i == 4)
909 return -1;
910 c = *str;
911 /* Then comse horizontal position. */
912 for (i = 0; i < 3; i++)
913 if (c == "lcr"[i])
914 {
915 *x = i;
916 return 0;
917 }
918 return -1;
919 }
920
921
922 /* Return a combining code corresponding to SYM. */
923
924 static int
get_combining_command(MSymbol sym)925 get_combining_command (MSymbol sym)
926 {
927 char *str = msymbol_name (sym);
928 int base_x, base_y, add_x, add_y, off_x, off_y;
929 int c;
930
931 if (read_combining_position (str, &base_x, &base_y) < 0)
932 return 0;
933 str += 2;
934 c = *str;
935 if (c == '.')
936 {
937 off_x = off_y = 128;
938 str++;
939 }
940 else
941 {
942 if (c == '+' || c == '-')
943 {
944 off_y = read_decimal_number (&str) + 128;
945 c = *str;
946 }
947 else
948 off_y = 128;
949 if (c == '<' || c == '>')
950 off_x = read_decimal_number (&str) + 128;
951 else
952 off_x = 128;
953 }
954 if (read_combining_position (str, &add_x, &add_y) < 0)
955 return 0;
956
957 c = MAKE_COMBINING_CODE (base_y, base_x, add_y, add_x, off_y, off_x);
958 return (COMBINING_CODE_TO_CMD_ID (c));
959 }
960
961
962 /* Load a command from PLIST into STAGE, and return that
963 identification number. If ID is not INVALID_CMD_ID, that means we
964 are loading a top level command or a macro. In that case, use ID
965 as the identification number of the command. Otherwise, generate a
966 new id number for the command. MACROS is a list of raw macros. */
967
968 static int
load_command(FontLayoutStage * stage,MPlist * plist,MPlist * macros,int id)969 load_command (FontLayoutStage *stage, MPlist *plist,
970 MPlist *macros, int id)
971 {
972 int i;
973 int result;
974
975 if (MPLIST_INTEGER_P (plist))
976 {
977 int code = MPLIST_INTEGER (plist);
978
979 if (code < 0)
980 MERROR (MERROR_DRAW, INVALID_CMD_ID);
981 return code;
982 }
983 else if (MPLIST_PLIST_P (plist))
984 {
985 /* PLIST ::= ( cond ... ) | ( STRING ... ) | ( INTEGER ... )
986 | ( ( INTEGER INTEGER ) ... )
987 | ( ( range INTEGER INTEGER ) ... )
988 | ( ( SYMBOL STRING ) ... )
989 | ( ( font-facilty [ INTEGER ] ) ... )
990 | ( ( font-facilty OTF-SPEC ) ... ) */
991 MPlist *elt = MPLIST_PLIST (plist);
992 int len = MPLIST_LENGTH (elt) - 1;
993 FontLayoutCmd *cmd;
994
995 if (id == INVALID_CMD_ID)
996 {
997 FontLayoutCmd dummy;
998 id = INDEX_TO_CMD_ID (stage->used);
999 MLIST_APPEND1 (stage, cmds, dummy, MERROR_DRAW);
1000 }
1001 cmd = stage->cmds + CMD_ID_TO_INDEX (id);
1002
1003 if (MPLIST_SYMBOL_P (elt))
1004 {
1005 FontLayoutCmdCond *cond;
1006
1007 if (MPLIST_SYMBOL (elt) != Mcond)
1008 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1009 elt = MPLIST_NEXT (elt);
1010 cmd->type = FontLayoutCmdTypeCond;
1011 cond = &cmd->body.cond;
1012 cond->seq_beg = cond->seq_end = -1;
1013 cond->seq_from = cond->seq_to = 0;
1014 cond->n_cmds = len;
1015 MTABLE_CALLOC (cond->cmd_ids, len, MERROR_DRAW);
1016 for (i = 0; i < len; i++, elt = MPLIST_NEXT (elt))
1017 {
1018 int this_id = load_command (stage, elt, macros, INVALID_CMD_ID);
1019
1020 if (this_id == INVALID_CMD_ID || this_id == -2)
1021 MERROR (MERROR_DRAW, this_id);
1022 /* The above load_command may relocate stage->cmds. */
1023 cmd = stage->cmds + CMD_ID_TO_INDEX (id);
1024 cond = &cmd->body.cond;
1025 cond->cmd_ids[i] = this_id;
1026 if (this_id <= CMD_ID_OFFSET_INDEX)
1027 {
1028 FontLayoutCmd *this_cmd
1029 = stage->cmds + CMD_ID_TO_INDEX (this_id);
1030
1031 if (this_cmd->type == FontLayoutCmdTypeRule
1032 && this_cmd->body.rule.src_type == SRC_SEQ)
1033 {
1034 int first_char = this_cmd->body.rule.src.seq.codes[0];
1035
1036 if (cond->seq_beg < 0)
1037 {
1038 /* The first SEQ command. */
1039 cond->seq_beg = i;
1040 cond->seq_from = cond->seq_to = first_char;
1041 }
1042 else if (cond->seq_end < 0)
1043 {
1044 /* The following SEQ command. */
1045 if (cond->seq_from > first_char)
1046 cond->seq_from = first_char;
1047 else if (cond->seq_to < first_char)
1048 cond->seq_to = first_char;
1049 }
1050 }
1051 else
1052 {
1053 if (cond->seq_beg >= 0 && cond->seq_end < 0)
1054 /* The previous one is the last SEQ command. */
1055 cond->seq_end = i;
1056 }
1057 }
1058 else
1059 {
1060 if (cond->seq_beg >= 0 && cond->seq_end < 0)
1061 /* The previous one is the last SEQ command. */
1062 cond->seq_end = i;
1063 }
1064 }
1065 if (cond->seq_beg >= 0 && cond->seq_end < 0)
1066 /* The previous one is the last SEQ command. */
1067 cond->seq_end = i;
1068 }
1069 else
1070 {
1071 cmd->type = FontLayoutCmdTypeRule;
1072 if (MPLIST_MTEXT_P (elt))
1073 {
1074 MText *mt = MPLIST_MTEXT (elt);
1075 char *str = (char *) MTEXT_DATA (mt);
1076
1077 if (str[0] != '^')
1078 {
1079 mtext_ins_char (mt, 0, '^', 1);
1080 str = (char *) MTEXT_DATA (mt);
1081 }
1082 if (regcomp (&cmd->body.rule.src.re.preg, str, REG_EXTENDED))
1083 MERROR (MERROR_FONT, INVALID_CMD_ID);
1084 cmd->body.rule.src_type = SRC_REGEX;
1085 cmd->body.rule.src.re.pattern = strdup (str);
1086 }
1087 else if (MPLIST_INTEGER_P (elt))
1088 {
1089 cmd->body.rule.src_type = SRC_INDEX;
1090 cmd->body.rule.src.match_idx = MPLIST_INTEGER (elt);
1091 }
1092 else if (MPLIST_PLIST_P (elt))
1093 {
1094 MPlist *pl = MPLIST_PLIST (elt), *p;
1095 int size = MPLIST_LENGTH (pl);
1096
1097 if (MPLIST_INTEGER_P (pl))
1098 {
1099 int i;
1100
1101 cmd->body.rule.src_type = SRC_SEQ;
1102 cmd->body.rule.src.seq.n_codes = size;
1103 MTABLE_CALLOC (cmd->body.rule.src.seq.codes, size,
1104 MERROR_FONT);
1105 for (i = 0; i < size; i++, pl = MPLIST_NEXT (pl))
1106 {
1107 if (! MPLIST_INTEGER_P (pl))
1108 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1109 cmd->body.rule.src.seq.codes[i]
1110 = (unsigned) MPLIST_INTEGER (pl);
1111 }
1112 }
1113 else if (MPLIST_SYMBOL_P (pl))
1114 {
1115 if (MPLIST_SYMBOL (pl) == Mrange)
1116 {
1117 if (size != 3)
1118 MERROR (MERROR_FLT, INVALID_CMD_ID);
1119 cmd->body.rule.src_type = SRC_RANGE;
1120 pl = MPLIST_NEXT (pl);
1121 if (! MPLIST_INTEGER_P (pl))
1122 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1123 cmd->body.rule.src.range.from
1124 = (unsigned) MPLIST_INTEGER (pl);
1125 pl = MPLIST_NEXT (pl);
1126 if (! MPLIST_INTEGER_P (pl))
1127 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1128 cmd->body.rule.src.range.to
1129 = (unsigned) MPLIST_INTEGER (pl);
1130 }
1131 else if (MPLIST_SYMBOL (pl) == Mfont_facility)
1132 {
1133 FontLayoutCmdRule *rule = &cmd->body.rule;
1134
1135 pl = MPLIST_NEXT (pl);
1136 if (MPLIST_SYMBOL_P (pl))
1137 {
1138 MSymbol sym = MPLIST_SYMBOL (pl);
1139 char *otf_spec = MSYMBOL_NAME (sym);
1140
1141 if (otf_spec[0] == ':' && otf_spec[1] == 'o'
1142 && otf_spec[2] == 't' && otf_spec[3] == 'f')
1143 parse_otf_command (sym, &rule->src.facility.otf_spec);
1144 else
1145 MERROR (MERROR_FLT, INVALID_CMD_ID);
1146 rule->src_type = SRC_OTF_SPEC;
1147 pl = MPLIST_NEXT (pl);
1148 }
1149 else if (MPLIST_TAIL_P (pl))
1150 MERROR (MERROR_FLT, INVALID_CMD_ID);
1151 else
1152 rule->src_type = SRC_HAS_GLYPH;
1153 rule->src.facility.len = 0;
1154 MPLIST_DO (p, pl)
1155 {
1156 if (! MPLIST_INTEGER_P (p)
1157 && (MPLIST_SYMBOL_P (p)
1158 ? MPLIST_SYMBOL (p) != Mequal
1159 : 1))
1160 MERROR (MERROR_FLT, INVALID_CMD_ID);
1161 rule->src.facility.len++;
1162 }
1163 rule->src.facility.codes = pl;
1164 M17N_OBJECT_REF (pl);
1165 }
1166 }
1167 else
1168 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1169 }
1170 else
1171 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1172
1173 elt = MPLIST_NEXT (elt);
1174 cmd->body.rule.n_cmds = len;
1175 MTABLE_CALLOC (cmd->body.rule.cmd_ids, len, MERROR_DRAW);
1176 for (i = 0; i < len; i++, elt = MPLIST_NEXT (elt))
1177 {
1178 int this_id = load_command (stage, elt, macros, INVALID_CMD_ID);
1179
1180 if (this_id == INVALID_CMD_ID || this_id == -2)
1181 MERROR (MERROR_DRAW, this_id);
1182 /* The above load_command may relocate stage->cmds. */
1183 cmd = stage->cmds + CMD_ID_TO_INDEX (id);
1184 cmd->body.rule.cmd_ids[i] = this_id;
1185 }
1186 }
1187 }
1188 else if (MPLIST_SYMBOL_P (plist))
1189 {
1190 MPlist *elt;
1191 MSymbol sym = MPLIST_SYMBOL (plist);
1192 char *name = msymbol_name (sym);
1193 int len = strlen (name);
1194 FontLayoutCmd cmd;
1195
1196 if (len > 4
1197 && ((name[0] == 'o' && name[1] == 't'
1198 && name[2] == 'f' && name[3] == ':')
1199 || (name[0] == ':' && name[1] == 'o' && name[2] == 't'
1200 && name[3] == 'f' && (name[4] == '=' || name[4] == '?'))))
1201 {
1202 result = load_otf_command (&cmd, sym);
1203 if (result < 0)
1204 return result;
1205 if (id == INVALID_CMD_ID)
1206 {
1207 id = INDEX_TO_CMD_ID (stage->used);
1208 MLIST_APPEND1 (stage, cmds, cmd, MERROR_DRAW);
1209 }
1210 else
1211 stage->cmds[CMD_ID_TO_INDEX (id)] = cmd;
1212 return id;
1213 }
1214
1215 if (len == 1)
1216 {
1217 if (*name == '=')
1218 return CMD_ID_COPY;
1219 else if (*name == '*')
1220 return CMD_ID_REPEAT;
1221 else if (*name == '<')
1222 return CMD_ID_CLUSTER_BEGIN;
1223 else if (*name == '>')
1224 return CMD_ID_CLUSTER_END;
1225 else if (*name == '|')
1226 return CMD_ID_SEPARATOR;
1227 else if (*name == '[')
1228 return CMD_ID_LEFT_PADDING;
1229 else if (*name == ']')
1230 return CMD_ID_RIGHT_PADDING;
1231 else
1232 id = 0;
1233 }
1234 else
1235 {
1236 id = get_combining_command (sym);
1237 if (id)
1238 return id;
1239 }
1240
1241 i = 1;
1242 MPLIST_DO (elt, macros)
1243 {
1244 if (sym == MPLIST_SYMBOL (MPLIST_PLIST (elt)))
1245 {
1246 id = INDEX_TO_CMD_ID (i);
1247 if (stage->cmds[i].type == FontLayoutCmdTypeMAX)
1248 id = load_command (stage, MPLIST_NEXT (MPLIST_PLIST (elt)),
1249 macros, id);
1250 return id;
1251 }
1252 i++;
1253 }
1254 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1255 }
1256 else
1257 MERROR (MERROR_DRAW, INVALID_CMD_ID);
1258
1259 return id;
1260 }
1261
1262 static void
free_flt_command(FontLayoutCmd * cmd)1263 free_flt_command (FontLayoutCmd *cmd)
1264 {
1265 if (cmd->type == FontLayoutCmdTypeRule)
1266 {
1267 FontLayoutCmdRule *rule = &cmd->body.rule;
1268
1269 if (rule->src_type == SRC_REGEX)
1270 {
1271 free (rule->src.re.pattern);
1272 regfree (&rule->src.re.preg);
1273 }
1274 else if (rule->src_type == SRC_SEQ)
1275 free (rule->src.seq.codes);
1276 free (rule->cmd_ids);
1277 }
1278 else if (cmd->type == FontLayoutCmdTypeCond)
1279 free (cmd->body.cond.cmd_ids);
1280 else if (cmd->type == FontLayoutCmdTypeOTF
1281 || cmd->type == FontLayoutCmdTypeOTFCategory)
1282 {
1283 if (cmd->body.otf.features[0])
1284 free (cmd->body.otf.features[0]);
1285 if (cmd->body.otf.features[1])
1286 free (cmd->body.otf.features[1]);
1287 }
1288 }
1289
1290 /* Load a generator from PLIST into a newly allocated FontLayoutStage,
1291 and return it. PLIST has this form:
1292 PLIST ::= ( COMMAND ( CMD-NAME COMMAND ) * )
1293 */
1294
1295 static FontLayoutStage *
load_generator(MPlist * plist)1296 load_generator (MPlist *plist)
1297 {
1298 FontLayoutStage *stage;
1299 MPlist *elt, *pl;
1300 FontLayoutCmd dummy;
1301 int result;
1302
1303 MSTRUCT_CALLOC (stage, MERROR_DRAW);
1304 MLIST_INIT1 (stage, cmds, 32);
1305 dummy.type = FontLayoutCmdTypeMAX;
1306 MLIST_APPEND1 (stage, cmds, dummy, MERROR_FONT);
1307 MPLIST_DO (elt, MPLIST_NEXT (plist))
1308 {
1309 if (! MPLIST_PLIST_P (elt))
1310 MERROR (MERROR_FONT, NULL);
1311 pl = MPLIST_PLIST (elt);
1312 if (! MPLIST_SYMBOL_P (pl))
1313 MERROR (MERROR_FONT, NULL);
1314 MLIST_APPEND1 (stage, cmds, dummy, MERROR_FONT);
1315 }
1316
1317 /* Load the first command from PLIST into STAGE->cmds[0]. Macros
1318 called in the first command are also loaded from MPLIST_NEXT
1319 (PLIST) into STAGE->cmds[n]. */
1320 result = load_command (stage, plist, MPLIST_NEXT (plist),
1321 INDEX_TO_CMD_ID (0));
1322 if (result == INVALID_CMD_ID || result == -2)
1323 {
1324 MLIST_FREE1 (stage, cmds);
1325 free (stage);
1326 return NULL;
1327 }
1328
1329 return stage;
1330 }
1331
1332
1333 /* Load stages of the font layout table FLT. */
1334
1335 static int
load_flt(MFLT * flt,MPlist * key_list)1336 load_flt (MFLT *flt, MPlist *key_list)
1337 {
1338 MPlist *top, *plist, *pl, *p;
1339 FontLayoutCategory *category = NULL;
1340 MSymbol sym;
1341
1342 if (key_list)
1343 top = (MPlist *) mdatabase__load_for_keys (flt->mdb, key_list);
1344 else
1345 top = (MPlist *) mdatabase_load (flt->mdb);
1346 if (! top)
1347 return -1;
1348 if (! MPLIST_PLIST_P (top))
1349 {
1350 M17N_OBJECT_UNREF (top);
1351 MERROR (MERROR_FLT, -1);
1352 }
1353
1354 if (key_list)
1355 {
1356 plist = mdatabase__props (flt->mdb);
1357 if (! plist)
1358 MERROR (MERROR_FLT, -1);
1359 MPLIST_DO (plist, plist)
1360 if (MPLIST_PLIST_P (plist))
1361 {
1362 pl = MPLIST_PLIST (plist);
1363 if (! MPLIST_SYMBOL_P (pl)
1364 || MPLIST_SYMBOL (pl) != Mfont)
1365 continue;
1366 pl = MPLIST_NEXT (pl);
1367 if (! MPLIST_PLIST_P (pl))
1368 continue;
1369 p = MPLIST_PLIST (pl);
1370 if (! MPLIST_SYMBOL_P (p))
1371 continue;
1372 p = MPLIST_NEXT (p);
1373 if (! MPLIST_SYMBOL_P (p))
1374 continue;
1375 flt->family = MPLIST_SYMBOL (p);
1376 MPLIST_DO (p, MPLIST_NEXT (p))
1377 if (MPLIST_SYMBOL_P (p))
1378 {
1379 sym = MPLIST_SYMBOL (p);
1380 if (MSYMBOL_NAME (sym)[0] != ':')
1381 flt->registry = sym, sym = Mnil;
1382 else
1383 break;
1384 }
1385 if (sym)
1386 {
1387 char *otf_spec = MSYMBOL_NAME (sym);
1388
1389 if (otf_spec[0] == ':' && otf_spec[1] == 'o'
1390 && otf_spec[2] == 't' && otf_spec[3] == 'f')
1391 parse_otf_command (sym, &flt->otf);
1392 }
1393 break;
1394 }
1395 }
1396 MPLIST_DO (plist, top)
1397 {
1398 if (MPLIST_SYMBOL_P (plist)
1399 && MPLIST_SYMBOL (plist) == Mend)
1400 {
1401 mplist_set (plist, Mnil, NULL);
1402 break;
1403 }
1404 if (! MPLIST_PLIST (plist))
1405 continue;
1406 pl = MPLIST_PLIST (plist);
1407 if (! MPLIST_SYMBOL_P (pl))
1408 continue;
1409 sym = MPLIST_SYMBOL (pl);
1410 pl = MPLIST_NEXT (pl);
1411 if (! pl)
1412 continue;
1413 if (sym == Mcategory)
1414 {
1415 if (category)
1416 unref_category_table (category);
1417 else if (flt->coverage)
1418 {
1419 category = flt->coverage;
1420 ref_category_table (category);
1421 continue;
1422 }
1423 category = load_category_table (pl, NULL);
1424 if (! category)
1425 goto err;
1426 if (! flt->coverage)
1427 {
1428 flt->coverage = category;
1429 ref_category_table (category);
1430 }
1431 if (category->definition)
1432 flt->need_config = 1;
1433 }
1434 else if (sym == Mgenerator)
1435 {
1436 FontLayoutStage *stage;
1437
1438 if (! category)
1439 break;
1440 stage = load_generator (pl);
1441 if (! stage)
1442 break;
1443 stage->category = category;
1444 M17N_OBJECT_REF (category->table);
1445 if (! flt->stages)
1446 flt->stages = mplist ();
1447 mplist_add (flt->stages, Mt, stage);
1448 }
1449 }
1450 if (category)
1451 unref_category_table (category);
1452 err:
1453 if (! MPLIST_TAIL_P (plist))
1454 {
1455 M17N_OBJECT_UNREF (top);
1456 M17N_OBJECT_UNREF (flt->stages);
1457 MERROR (MERROR_FLT, -1);
1458 }
1459 M17N_OBJECT_UNREF (top);
1460 return 0;
1461 }
1462
1463
1464 static void
free_flt_stage(MFLT * flt,FontLayoutStage * stage)1465 free_flt_stage (MFLT *flt, FontLayoutStage *stage)
1466 {
1467 int i;
1468
1469 unref_category_table (stage->category);
1470 if (! flt->font_id)
1471 {
1472 for (i = 0; i < stage->used; i++)
1473 free_flt_command (stage->cmds + i);
1474 MLIST_FREE1 (stage, cmds);
1475 }
1476 free (stage);
1477 }
1478
1479 static void
free_flt_list()1480 free_flt_list ()
1481 {
1482 if (flt_list)
1483 {
1484 MPlist *plist, *pl;
1485
1486 MPLIST_DO (plist, flt_list)
1487 {
1488 MFLT *flt = MPLIST_VAL (plist);
1489
1490 if (flt->coverage)
1491 unref_category_table (flt->coverage);
1492 if (flt->stages)
1493 {
1494 MPLIST_DO (pl, MPLIST_NEXT (flt->stages))
1495 free_flt_stage (flt, MPLIST_VAL (pl));
1496 M17N_OBJECT_UNREF (flt->stages);
1497 }
1498 free (flt);
1499 MPLIST_VAL (plist) = NULL;
1500 }
1501 M17N_OBJECT_UNREF (flt_list);
1502 }
1503 }
1504
1505 static int
list_flt()1506 list_flt ()
1507 {
1508 MPlist *plist, *key_list = NULL;
1509 MPlist *pl;
1510 int result = 0;
1511
1512 if (! (plist = mdatabase_list (Mfont, Mlayouter, Mnil, Mnil)))
1513 return -1;
1514 if (! (flt_list = mplist ()))
1515 goto err;
1516 if (! (key_list = mplist ()))
1517 goto err;
1518 if (! mplist_add (key_list, Mcategory, Mt))
1519 goto err;
1520
1521 MPLIST_DO (pl, plist)
1522 {
1523 MDatabase *mdb = MPLIST_VAL (pl);
1524 MSymbol *tags = mdatabase_tag (mdb);
1525 MFLT *flt;
1526
1527 if (! MSTRUCT_CALLOC_SAFE (flt))
1528 goto err;
1529 flt->name = tags[2];
1530 flt->mdb = mdb;
1531 if (load_flt (flt, key_list) < 0)
1532 free (flt);
1533 else
1534 {
1535 if (MPLIST_TAIL_P (flt_list))
1536 {
1537 flt_min_coverage = mchartable_min_char (flt->coverage->table);
1538 flt_max_coverage = mchartable_max_char (flt->coverage->table);
1539 }
1540 else
1541 {
1542 int c;
1543
1544 c = mchartable_min_char (flt->coverage->table);
1545 if (flt_min_coverage > c)
1546 flt_min_coverage = c;
1547 c = mchartable_max_char (flt->coverage->table);
1548 if (flt_max_coverage < c)
1549 flt_max_coverage = c;
1550 }
1551 if (! mplist_push (flt_list, flt->name, flt))
1552 goto err;
1553 }
1554 }
1555 goto end;
1556
1557 err:
1558 free_flt_list ();
1559 result = -1;
1560 end:
1561 M17N_OBJECT_UNREF (plist);
1562 M17N_OBJECT_UNREF (key_list);
1563 return result;
1564 }
1565
1566 /* FLS (Font Layout Service) */
1567
1568 /* Structure to hold information about a context of FLS. */
1569
1570 typedef struct
1571 {
1572 /* Pointer to the current stage. */
1573 FontLayoutStage *stage;
1574
1575 /* Pointer to the category table of the next stage or NULL if none. */
1576 FontLayoutCategory *category;
1577
1578 /* Pointer to the font. */
1579 MFLTFont *font;
1580
1581 /* Input and output glyph string. */
1582 MFLTGlyphString *in, *out;
1583
1584 /* Encode each character or code of a glyph by the current category
1585 table into this array. An element is a category letter used for
1586 a regular expression matching. */
1587 char *encoded;
1588 int encoded_offset;
1589 int *match_indices;
1590 int code_offset;
1591 int cluster_begin_idx;
1592 int cluster_begin_pos;
1593 int cluster_end_pos;
1594 int combining_code;
1595 int left_padding;
1596 int check_mask;
1597 } FontLayoutContext;
1598
1599 static int run_command (int, int, int, int, FontLayoutContext *);
1600 static int run_otf (int, MFLTOtfSpec *, int, int, FontLayoutContext *);
1601 static int try_otf (int, MFLTOtfSpec *, int, int, FontLayoutContext *);
1602
1603 #define NMATCH 20
1604
1605 static int
run_rule(int depth,FontLayoutCmdRule * rule,int from,int to,FontLayoutContext * ctx)1606 run_rule (int depth,
1607 FontLayoutCmdRule *rule, int from, int to, FontLayoutContext *ctx)
1608 {
1609 int *saved_match_indices = ctx->match_indices;
1610 int match_indices[NMATCH * 2];
1611 int consumed;
1612 int i;
1613 int orig_from = from;
1614 int need_cluster_update = 0;
1615
1616 if (rule->src_type == SRC_REGEX)
1617 {
1618 regmatch_t pmatch[NMATCH];
1619 char saved_code;
1620 int result;
1621
1622 if (from > to)
1623 return 0;
1624 saved_code = ctx->encoded[to - ctx->encoded_offset];
1625 ctx->encoded[to - ctx->encoded_offset] = '\0';
1626 result = regexec (&(rule->src.re.preg),
1627 ctx->encoded + (from - ctx->encoded_offset),
1628 NMATCH, pmatch, 0);
1629 if (result == 0 && pmatch[0].rm_so == 0)
1630 {
1631 if (MDEBUG_FLAG () > 2)
1632 MDEBUG_PRINT5 ("\n [FLT] %*s(REGEX \"%s\" \"%s\" %d", depth, "",
1633 rule->src.re.pattern,
1634 ctx->encoded + (from - ctx->encoded_offset),
1635 pmatch[0].rm_eo);
1636 ctx->encoded[to - ctx->encoded_offset] = saved_code;
1637 for (i = 0; i < NMATCH; i++)
1638 {
1639 if (pmatch[i].rm_so < 0)
1640 match_indices[i * 2] = match_indices[i * 2 + 1] = -1;
1641 else
1642 {
1643 match_indices[i * 2] = from + pmatch[i].rm_so;
1644 match_indices[i * 2 + 1] = from + pmatch[i].rm_eo;
1645 }
1646 }
1647 ctx->match_indices = match_indices;
1648 to = match_indices[1];
1649 }
1650 else
1651 {
1652 ctx->encoded[to - ctx->encoded_offset] = saved_code;
1653 return 0;
1654 }
1655 need_cluster_update = 1;
1656 }
1657 else if (rule->src_type == SRC_SEQ)
1658 {
1659 int len;
1660
1661 len = rule->src.seq.n_codes;
1662 if (len > (to - from))
1663 return 0;
1664 for (i = 0; i < len; i++)
1665 if (rule->src.seq.codes[i] != GREF (ctx->in, from + i)->c)
1666 break;
1667 if (i < len)
1668 return 0;
1669 to = from + len;
1670 if (MDEBUG_FLAG () > 2)
1671 MDEBUG_PRINT3 ("\n [FLT] %*s(SEQ 0x%X", depth, "",
1672 rule->src.seq.codes[0]);
1673 need_cluster_update = 1;
1674 }
1675 else if (rule->src_type == SRC_RANGE)
1676 {
1677 int head;
1678
1679 if (from >= to)
1680 return 0;
1681 head = GREF (ctx->in, from)->c;
1682 if (head < rule->src.range.from || head > rule->src.range.to)
1683 return 0;
1684 ctx->code_offset = head - rule->src.range.from;
1685 to = from + 1;
1686 if (MDEBUG_FLAG () > 2)
1687 MDEBUG_PRINT4 ("\n [FLT] %*s(RANGE 0x%X-0x%X", depth, "",
1688 rule->src.range.from, rule->src.range.to);
1689 need_cluster_update = 1;
1690 }
1691 else if (rule->src_type == SRC_INDEX)
1692 {
1693 if (rule->src.match_idx >= NMATCH)
1694 return 0;
1695 from = ctx->match_indices[rule->src.match_idx * 2];
1696 if (from < 0)
1697 return 0;
1698 to = ctx->match_indices[rule->src.match_idx * 2 + 1];
1699 if (MDEBUG_FLAG () > 2)
1700 MDEBUG_PRINT3 ("\n [FLT] %*s(SUBPART %d", depth, "",
1701 rule->src.match_idx);
1702 need_cluster_update = 1;
1703 }
1704 else if (rule->src_type == SRC_HAS_GLYPH
1705 || rule->src_type == SRC_OTF_SPEC)
1706 {
1707 static MFLTGlyphString gstring;
1708 MPlist *p;
1709 int idx;
1710
1711 if (rule->src.facility.len > 0)
1712 {
1713 if (! gstring.glyph_size)
1714 {
1715 gstring.glyph_size = ctx->in->glyph_size;
1716 gstring.glyphs = calloc (rule->src.facility.len,
1717 gstring.glyph_size);
1718 gstring.allocated = rule->src.facility.len;
1719 gstring.used = rule->src.facility.len;
1720 }
1721 else if (rule->src.facility.len < gstring.allocated)
1722 {
1723 gstring.glyphs = realloc (gstring.glyphs,
1724 gstring.glyph_size
1725 * rule->src.facility.len);
1726 gstring.allocated = rule->src.facility.len;
1727 gstring.used = rule->src.facility.len;
1728 }
1729
1730 for (i = 0, p = rule->src.facility.codes, idx = from;
1731 i < rule->src.facility.len; i++, p = MPLIST_NEXT (p))
1732 {
1733 if (MPLIST_INTEGER_P (p))
1734 {
1735 GREF (&gstring, i)->c = MPLIST_INTEGER (p);
1736 GREF (&gstring, i)->encoded = 0;
1737 }
1738 else
1739 {
1740 GREF (&gstring, i)->c = GREF (ctx->in, idx)->code;
1741 GREF (&gstring, i)->encoded = GREF (ctx->in, idx)->encoded;
1742 idx++;
1743 }
1744 }
1745 }
1746
1747 if (MDEBUG_FLAG () > 2)
1748 {
1749 if (rule->src_type == SRC_HAS_GLYPH)
1750 MDEBUG_PRINT2 ("\n [FLT] %*s(HAS-GLYPH", depth, "");
1751 else
1752 MDEBUG_PRINT2 ("\n [FLT] %*s(OTF-SPEC", depth, "");
1753 for (i = 0; i < rule->src.facility.len; i++)
1754 MDEBUG_PRINT1 (" %04X", GREF (&gstring, i)->code);
1755 }
1756 if (ctx->font->get_glyph_id (ctx->font, &gstring, 0,
1757 rule->src.facility.len) < 0)
1758 {
1759 MDEBUG_PRINT (") FAIL!");
1760 return 0;
1761 }
1762 if (rule->src_type == SRC_OTF_SPEC)
1763 {
1764 MFLTOtfSpec *spec = &rule->src.facility.otf_spec;
1765
1766 if (! ctx->font->check_otf)
1767 {
1768 if ((spec->features[0] && spec->features[0][0] != 0xFFFFFFFF)
1769 || (spec->features[1] && spec->features[1][0] != 0xFFFFFFFF))
1770 return 0;
1771 }
1772 else
1773 {
1774 if (rule->src.facility.len == 0)
1775 {
1776 if (! ctx->font->check_otf (ctx->font, spec))
1777 return 0;
1778 }
1779 else
1780 {
1781 int prev_out_used = ctx->out->used, out_used;
1782 MFLTGlyphAdjustment *adjustment;
1783
1784 adjustment = alloca ((sizeof *adjustment)
1785 * (ctx->out->allocated - ctx->out->used));
1786 if (! adjustment)
1787 MERROR (MERROR_FLT, -1);
1788 memset (adjustment, 0,
1789 (sizeof *adjustment)
1790 * (ctx->out->allocated - ctx->out->used));
1791 ctx->font->drive_otf (ctx->font, &rule->src.facility.otf_spec,
1792 &gstring, 0, rule->src.facility.len,
1793 ctx->out,
1794 adjustment);
1795 out_used = ctx->out->used;
1796 ctx->out->used = prev_out_used;
1797 if (rule->src.facility.len == out_used - prev_out_used)
1798 {
1799 for (i = prev_out_used; i < out_used; i++)
1800 {
1801 if (GREF (&gstring, i - prev_out_used)->code
1802 != GREF (ctx->out, i)->code)
1803 break;
1804 if (adjustment[i - prev_out_used].set)
1805 break;
1806 }
1807 if (i == out_used)
1808 return 0;
1809 }
1810 }
1811 }
1812 }
1813 }
1814
1815 if (need_cluster_update && ctx->cluster_begin_idx >= 0)
1816 {
1817 for (i = from; i < to; i++)
1818 {
1819 MFLTGlyph *g = GREF (ctx->in, i);
1820 UPDATE_CLUSTER_RANGE (ctx, g);
1821 }
1822 }
1823
1824 consumed = 0;
1825 depth++;
1826 for (i = 0; i < rule->n_cmds; i++)
1827 {
1828 int pos;
1829
1830 if (rule->cmd_ids[i] == CMD_ID_REPEAT)
1831 {
1832 if (! consumed)
1833 continue;
1834 i--;
1835 }
1836 pos = run_command (depth, rule->cmd_ids[i], from, to, ctx);
1837 if (pos < 0)
1838 return pos;
1839 consumed = pos > from;
1840 if (consumed)
1841 from = pos;
1842 }
1843
1844 ctx->match_indices = saved_match_indices;
1845 if (MDEBUG_FLAG () > 2)
1846 MDEBUG_PRINT (")");
1847 return (rule->src_type == SRC_INDEX ? orig_from : to);
1848 }
1849
1850 static int
run_cond(int depth,FontLayoutCmdCond * cond,int from,int to,FontLayoutContext * ctx)1851 run_cond (int depth,
1852 FontLayoutCmdCond *cond, int from, int to, FontLayoutContext *ctx)
1853 {
1854 int i, pos = 0;
1855
1856 if (MDEBUG_FLAG () > 2)
1857 MDEBUG_PRINT2 ("\n [FLT] %*s(COND", depth, "");
1858 depth++;
1859 for (i = 0; i < cond->n_cmds; i++)
1860 {
1861 /* TODO: Write a code for optimization utilizaing the info
1862 cond->seq_XXX. */
1863 if ((pos = run_command (depth, cond->cmd_ids[i], from, to, ctx))
1864 != 0)
1865 break;
1866 }
1867 if (pos < 0)
1868 return pos;
1869 if (MDEBUG_FLAG () > 2)
1870 MDEBUG_PRINT (")");
1871 return (pos);
1872 }
1873
1874 static void
decode_packed_otf_tag(FontLayoutContext * ctx,MFLTGlyphString * gstring,int from,int to,FontLayoutCategory * category)1875 decode_packed_otf_tag (FontLayoutContext *ctx, MFLTGlyphString *gstring,
1876 int from, int to, FontLayoutCategory *category)
1877 {
1878 for (; from < to; from++)
1879 {
1880 MFLTGlyph *g = GREF (gstring, from);
1881 unsigned int tag = g->internal & 0xFFFFFFF;
1882 char enc;
1883
1884 if (GET_COMBINED (g))
1885 continue;
1886 if (! category)
1887 {
1888 SET_CATEGORY_CODE (g, 0);
1889 continue;
1890 }
1891 enc = '\0';
1892 if (tag & 0xFFFFF80)
1893 {
1894 int i;
1895
1896 /* Clear the feature tag code. */
1897 g->internal &= ~0xFFFFFFF;
1898 for (i = 0; i < category->feature_table.size; i++)
1899 if (category->feature_table.tag[i] == tag)
1900 {
1901 enc = category->feature_table.code[i];
1902 if (ctx->in == gstring)
1903 ctx->encoded[from - ctx->encoded_offset] = enc;
1904 break;
1905 }
1906 }
1907 if (! enc)
1908 enc = (g->c > 0 ? (int) mchartable_lookup (category->table, g->c)
1909 : g->c == 0 ? 1 : ' ');
1910 SET_CATEGORY_CODE (g, enc);
1911 }
1912 }
1913
1914 static int
run_otf(int depth,MFLTOtfSpec * otf_spec,int from,int to,FontLayoutContext * ctx)1915 run_otf (int depth,
1916 MFLTOtfSpec *otf_spec, int from, int to, FontLayoutContext *ctx)
1917 {
1918 MFLTFont *font = ctx->font;
1919 int from_idx = ctx->out->used;
1920
1921 if (MDEBUG_FLAG () > 2)
1922 MDEBUG_PRINT3 ("\n [FLT] %*s%s", depth, "", MSYMBOL_NAME (otf_spec->sym));
1923
1924 font->get_glyph_id (font, ctx->in, from, to);
1925 if (! font->drive_otf)
1926 {
1927 if (ctx->out->used + (to - from) > ctx->out->allocated)
1928 return -2;
1929 font->get_metrics (font, ctx->in, from, to);
1930 GCPY (ctx->in, from, to - from, ctx->out, ctx->out->used);
1931 ctx->out->used += to - from;
1932 }
1933 else
1934 {
1935 MFLTGlyphAdjustment *adjustment;
1936 int out_len;
1937 int i;
1938
1939 adjustment = alloca ((sizeof *adjustment)
1940 * (ctx->out->allocated - ctx->out->used));
1941 if (! adjustment)
1942 MERROR (MERROR_FLT, -1);
1943 memset (adjustment, 0,
1944 (sizeof *adjustment) * (ctx->out->allocated - ctx->out->used));
1945 to = font->drive_otf (font, otf_spec, ctx->in, from, to, ctx->out,
1946 adjustment);
1947 if (to < 0)
1948 return to;
1949 decode_packed_otf_tag (ctx, ctx->out, from_idx, ctx->out->used,
1950 ctx->category);
1951 out_len = ctx->out->used - from_idx;
1952 if (otf_spec->features[1])
1953 {
1954 MFLTGlyphAdjustment *a;
1955 MFLTGlyph *g;
1956
1957 for (i = 0, a = adjustment; i < out_len; i++, a++)
1958 if (a->set)
1959 break;
1960 if (i < out_len)
1961 {
1962 font->get_metrics (font, ctx->out, from_idx, ctx->out->used);
1963 for (g = GREF (ctx->out, from_idx + i);
1964 i < out_len; i++, a++, g = NEXT (ctx->out, g))
1965 if (a->set)
1966 {
1967 if (a->advance_is_absolute)
1968 {
1969 g->xadv = a->xadv;
1970 g->yadv = a->yadv;
1971 }
1972 else if (a->xadv || a->yadv)
1973 {
1974 g->xadv += a->xadv;
1975 g->yadv += a->yadv;
1976 }
1977 if (a->xoff || a->yoff || a->back)
1978 {
1979 int j;
1980 MFLTGlyph *gg = PREV (ctx->out, g);
1981 MFLTGlyphAdjustment *aa = a;
1982
1983 g->xoff = a->xoff;
1984 g->yoff = a->yoff;
1985 g->lbearing += a->xoff;
1986 g->rbearing += a->xoff;
1987 g->ascent -= a->yoff;
1988 g->descent -= a->yoff;
1989 while (aa->back > 0)
1990 {
1991 for (j = 0; j < aa->back;
1992 j++, gg = PREV (ctx->out, gg))
1993 {
1994 g->xoff -= gg->xadv;
1995 g->lbearing -= gg->xadv;
1996 g->rbearing -= gg->xadv;
1997 }
1998 aa = aa - aa->back;
1999 g->xoff += aa->xoff;
2000 g->yoff += aa->yoff;
2001 g->lbearing += aa->xoff;
2002 g->rbearing += aa->xoff;
2003 g->ascent -= aa->yoff;
2004 g->descent -= aa->yoff;
2005 }
2006 }
2007 g->adjusted = 1;
2008 }
2009 }
2010 }
2011 }
2012
2013 if (ctx->cluster_begin_idx >= 0)
2014 for (; from_idx < ctx->out->used; from_idx++)
2015 {
2016 MFLTGlyph *g = GREF (ctx->out, from_idx);
2017 UPDATE_CLUSTER_RANGE (ctx, g);
2018 }
2019 return to;
2020 }
2021
2022 static int
try_otf(int depth,MFLTOtfSpec * otf_spec,int from,int to,FontLayoutContext * ctx)2023 try_otf (int depth, MFLTOtfSpec *otf_spec, int from, int to,
2024 FontLayoutContext *ctx)
2025 {
2026 MFLTFont *font = ctx->font;
2027
2028 if (MDEBUG_FLAG () > 2)
2029 MDEBUG_PRINT3 ("\n [FLT] %*s%s", depth, "", MSYMBOL_NAME (otf_spec->sym));
2030
2031 if (! otf_spec->features[0] && ! otf_spec->features[1])
2032 {
2033 /* Reset categories. */
2034 MCharTable *table = ctx->category->table;
2035 int i;
2036
2037 for (i = from; i < to; i++)
2038 {
2039 MFLTGlyph *g = GREF (ctx->in, i);
2040
2041 if (! GET_COMBINED (g))
2042 {
2043 char enc = (GET_ENCODED (g)
2044 ? (g->c > 0 ? (int) mchartable_lookup (table, g->c)
2045 : 1)
2046 : g->code
2047 ? (int) mchartable_lookup (table, g->code)
2048 : ' ');
2049 SET_CATEGORY_CODE (g, enc);
2050 ctx->encoded[i - ctx->encoded_offset] = enc;
2051 }
2052 }
2053 return from;
2054 }
2055
2056 if (ctx->stage->category->feature_table.size == 0)
2057 return from;
2058
2059 font->get_glyph_id (font, ctx->in, from, to);
2060 if (mflt_try_otf)
2061 {
2062 to = mflt_try_otf (font, otf_spec, ctx->in, from, to);
2063 if (to < 0)
2064 return from;
2065 decode_packed_otf_tag (ctx, ctx->in, from, to, ctx->stage->category);
2066 }
2067 return from;
2068 }
2069
2070 static char work[16];
2071
2072 static char *
dump_combining_code(int code)2073 dump_combining_code (int code)
2074 {
2075 char *vallign = "tcbB";
2076 char *hallign = "lcr";
2077 char *p;
2078 int off_x, off_y;
2079
2080 if (! code)
2081 return "none";
2082 work[0] = vallign[COMBINING_CODE_BASE_Y (code)];
2083 work[1] = hallign[COMBINING_CODE_BASE_X (code)];
2084 off_y = COMBINING_CODE_OFF_Y (code);
2085 off_x = COMBINING_CODE_OFF_X (code);
2086 if (off_y > 0)
2087 sprintf (work + 2, "+%d", off_y);
2088 else if (off_y < 0)
2089 sprintf (work + 2, "%d", off_y);
2090 else if (off_x == 0)
2091 sprintf (work + 2, ".");
2092 p = work + strlen (work);
2093 if (off_x > 0)
2094 sprintf (p, ">%d", off_x);
2095 else if (off_x < 0)
2096 sprintf (p, "<%d", -off_x);
2097 p += strlen (p);
2098 p[0] = vallign[COMBINING_CODE_ADD_Y (code)];
2099 p[1] = hallign[COMBINING_CODE_ADD_X (code)];
2100 p[2] = '\0';
2101 return work;
2102 }
2103
2104 static int
run_command(int depth,int id,int from,int to,FontLayoutContext * ctx)2105 run_command (int depth, int id, int from, int to, FontLayoutContext *ctx)
2106 {
2107 MFLTGlyph *g;
2108
2109 if (id >= 0)
2110 {
2111 int i;
2112 MCharTable *table = ctx->category ? ctx->category->table : NULL;
2113 char enc;
2114
2115 /* Direct code (== ctx->code_offset + id) output.
2116 The source is not consumed. */
2117 if (MDEBUG_FLAG () > 2)
2118 MDEBUG_PRINT3 ("\n [FLT] %*s(DIRECT 0x%X", depth, "",
2119 ctx->code_offset + id);
2120 i = (from < to || from == 0) ? from : from - 1;
2121 GDUP (ctx, i);
2122 g = GREF (ctx->out, ctx->out->used - 1);
2123 g->c = g->code = ctx->code_offset + id;
2124 if (ctx->combining_code)
2125 SET_COMBINING_CODE (g, ctx, ctx->combining_code);
2126 else if (table)
2127 {
2128 enc = (GET_ENCODED (g)
2129 ? (g->c > 0 ? (int) mchartable_lookup (table, g->c) : 1)
2130 : g->code
2131 ? (int) mchartable_lookup (table, g->code)
2132 : ' ');
2133 SET_CATEGORY_CODE (g, enc);
2134 }
2135 SET_ENCODED (g, 0);
2136 SET_MEASURED (g, 0);
2137 if (ctx->left_padding)
2138 SET_LEFT_PADDING (g, ctx, LeftPaddingMask);
2139 for (i = from; i < to; i++)
2140 {
2141 MFLTGlyph *tmp = GREF (ctx->in, i);
2142
2143 if (g->from > tmp->from)
2144 g->from = tmp->from;
2145 else if (g->to < tmp->to)
2146 g->to = tmp->to;
2147 }
2148 if (ctx->cluster_begin_idx >= 0)
2149 UPDATE_CLUSTER_RANGE (ctx, g);
2150 ctx->code_offset = ctx->combining_code = ctx->left_padding = 0;
2151 if (MDEBUG_FLAG () > 2)
2152 MDEBUG_PRINT (")");
2153 return (from);
2154 }
2155
2156 if (id <= CMD_ID_OFFSET_INDEX)
2157 {
2158 int idx = CMD_ID_TO_INDEX (id);
2159 FontLayoutCmd *cmd;
2160
2161 if (idx >= ctx->stage->used)
2162 MERROR (MERROR_DRAW, -1);
2163 cmd = ctx->stage->cmds + idx;
2164 if (cmd->type == FontLayoutCmdTypeRule)
2165 to = run_rule (depth, &cmd->body.rule, from, to, ctx);
2166 else if (cmd->type == FontLayoutCmdTypeCond)
2167 to = run_cond (depth, &cmd->body.cond, from, to, ctx);
2168 else if (cmd->type == FontLayoutCmdTypeOTF)
2169 to = run_otf (depth, &cmd->body.otf, from, to, ctx);
2170 else if (cmd->type == FontLayoutCmdTypeOTFCategory)
2171 to = try_otf (depth, &cmd->body.otf, from, to, ctx);
2172 return to;
2173 }
2174
2175 if (id <= CMD_ID_OFFSET_COMBINING)
2176 {
2177 ctx->combining_code = CMD_ID_TO_COMBINING_CODE (id);
2178 if (MDEBUG_FLAG () > 2)
2179 MDEBUG_PRINT3 ("\n [FLT] %*s(CMB %s)", depth, "",
2180 dump_combining_code (ctx->combining_code));
2181 return from;
2182 }
2183
2184 switch (id)
2185 {
2186 case CMD_ID_COPY:
2187 {
2188 if (from >= to)
2189 return from;
2190 GDUP (ctx, from);
2191 g = GREF (ctx->out, ctx->out->used - 1);
2192 if (ctx->combining_code)
2193 SET_COMBINING_CODE (g, ctx, ctx->combining_code);
2194 if (ctx->left_padding)
2195 SET_LEFT_PADDING (g, ctx, LeftPaddingMask);
2196 if (ctx->cluster_begin_idx >= 0)
2197 UPDATE_CLUSTER_RANGE (ctx, g);
2198 if (MDEBUG_FLAG () > 2)
2199 {
2200 if (g->c < 0)
2201 MDEBUG_PRINT2 ("\n [FLT] %*s(COPY |)", depth, "");
2202 else
2203 MDEBUG_PRINT3 ("\n [FLT] %*s(COPY 0x%X)", depth, "", g->c);
2204 }
2205 ctx->code_offset = ctx->combining_code = ctx->left_padding = 0;
2206 return (from + 1);
2207 }
2208
2209 case CMD_ID_CLUSTER_BEGIN:
2210 if (ctx->cluster_begin_idx < 0)
2211 {
2212 if (MDEBUG_FLAG () > 2)
2213 MDEBUG_PRINT3 ("\n [FLT] %*s<%d", depth, "",
2214 GREF (ctx->in, from)->from);
2215 ctx->cluster_begin_idx = ctx->out->used;
2216 ctx->cluster_begin_pos = GREF (ctx->in, from)->from;
2217 ctx->cluster_end_pos = GREF (ctx->in, from)->to;
2218 }
2219 return from;
2220
2221 case CMD_ID_CLUSTER_END:
2222 if (ctx->cluster_begin_idx >= 0
2223 && ctx->cluster_begin_idx < ctx->out->used)
2224 {
2225 int i;
2226
2227 if (MDEBUG_FLAG () > 2)
2228 MDEBUG_PRINT1 (" %d>", ctx->cluster_end_pos + 1);
2229 for (i = ctx->cluster_begin_idx; i < ctx->out->used; i++)
2230 {
2231 GREF (ctx->out, i)->from = ctx->cluster_begin_pos;
2232 GREF (ctx->out, i)->to = ctx->cluster_end_pos;
2233 }
2234 ctx->cluster_begin_idx = -1;
2235 }
2236 return from;
2237
2238 case CMD_ID_SEPARATOR:
2239 {
2240 int i;
2241
2242 if (MDEBUG_FLAG () > 2)
2243 MDEBUG_PRINT2 ("\n [FLT] %*s|", depth, "");
2244 i = from < to ? from : from - 1;
2245 GDUP (ctx, i);
2246 g = GREF (ctx->out, ctx->out->used - 1);
2247 g->c = -1, g->code = 0;
2248 g->xadv = g->yadv = 0;
2249 SET_ENCODED (g, 1);
2250 SET_MEASURED (g, 0);
2251 SET_CATEGORY_CODE (g, ' ');
2252 return from;
2253 }
2254
2255 case CMD_ID_LEFT_PADDING:
2256 if (MDEBUG_FLAG () > 2)
2257 MDEBUG_PRINT2 ("\n [FLT] %*s[", depth, "");
2258 ctx->left_padding = 1;
2259 return from;
2260
2261 case CMD_ID_RIGHT_PADDING:
2262 if (ctx->out->used > 0)
2263 {
2264 if (MDEBUG_FLAG () > 2)
2265 MDEBUG_PRINT2 ("\n [FLT] %*s]", depth, "");
2266 g = GREF (ctx->out, ctx->out->used - 1);
2267 SET_RIGHT_PADDING (g, ctx, RightPaddingMask);
2268 }
2269 return from;
2270 }
2271
2272 MERROR (MERROR_DRAW, -1);
2273 }
2274
2275 static int
run_stages(MFLTGlyphString * gstring,int from,int to,MFLT * flt,FontLayoutContext * ctx)2276 run_stages (MFLTGlyphString *gstring, int from, int to,
2277 MFLT *flt, FontLayoutContext *ctx)
2278 {
2279 MFLTGlyphString buf, *temp;
2280 int stage_idx = 0;
2281 int orig_from = from, orig_to = to;
2282 int from_pos, to_pos, len;
2283 int i, j;
2284 MFLTGlyph *g;
2285 MPlist *stages = flt->stages;
2286 FontLayoutCategory *prev_category = NULL;
2287
2288 from_pos = GREF (ctx->in, from)->from;
2289 to_pos = GREF (ctx->in, to - 1)->to;
2290 len = to_pos - from_pos + 1;
2291
2292 buf = *(ctx->in);
2293 buf.glyphs = NULL;
2294 GINIT (ctx->out, ctx->out->allocated);
2295 ctx->encoded = alloca (ctx->out->allocated);
2296 if (! ctx->out->glyphs || ! ctx->encoded)
2297 return -1;
2298
2299 for (stage_idx = 0; 1; stage_idx++)
2300 {
2301 MCharTable *table;
2302 int result;
2303
2304 ctx->stage = (FontLayoutStage *) MPLIST_VAL (stages);
2305 table = ctx->stage->category->table;
2306 stages = MPLIST_NEXT (stages);
2307 if (MPLIST_TAIL_P (stages))
2308 ctx->category = NULL;
2309 else
2310 ctx->category = ((FontLayoutStage *) MPLIST_VAL (stages))->category;
2311 ctx->code_offset = ctx->combining_code = ctx->left_padding = 0;
2312 ctx->encoded_offset = from;
2313 for (i = from; i < to; i++)
2314 {
2315 MFLTGlyph *g = GREF (ctx->in, i);
2316 char enc;
2317
2318 if (GET_COMBINED (g)
2319 || (prev_category && prev_category != ctx->stage->category))
2320 {
2321 enc = (GET_ENCODED (g)
2322 ? (g->c > 0 ? (int) mchartable_lookup (table, g->c) : 1)
2323 : g->code
2324 ? (int) mchartable_lookup (table, g->code)
2325 : ' ');
2326 if (! GET_COMBINED (g))
2327 SET_CATEGORY_CODE (g, enc);
2328 }
2329 else
2330 enc = GET_CATEGORY_CODE (g);
2331 ctx->encoded[i - from] = enc;
2332 if (! enc && stage_idx == 0)
2333 {
2334 to = i;
2335 break;
2336 }
2337 }
2338 ctx->encoded[i - from] = '\0';
2339 ctx->match_indices[0] = from;
2340 ctx->match_indices[1] = to;
2341 for (i = 2; i < NMATCH; i++)
2342 ctx->match_indices[i] = -1;
2343
2344 if (MDEBUG_FLAG () > 2)
2345 {
2346 MDEBUG_PRINT2 ("\n [FLT] (STAGE %d \"%s\"", stage_idx,
2347 ctx->encoded);
2348 MDEBUG_PRINT (" (");
2349 for (i = from; i < to; i++)
2350 {
2351 g = GREF (ctx->in, i);
2352 if (g->c == -1)
2353 MDEBUG_PRINT2 ("%*s|", (i > 0), "");
2354 else
2355 MDEBUG_PRINT3 ("%*s%04X", (i > 0), "", GREF (ctx->in, i)->code);
2356 }
2357 MDEBUG_PRINT (")");
2358 }
2359 result = run_command (4, INDEX_TO_CMD_ID (0), from, to, ctx);
2360 if (MDEBUG_FLAG () > 2)
2361 MDEBUG_PRINT (")");
2362 if (result < 0)
2363 return result;
2364
2365 /* If this is the last stage, break the loop. */
2366 if (MPLIST_TAIL_P (stages))
2367 break;
2368
2369 /* Otherwise, prepare for the next stage. */
2370 prev_category = ctx->stage->category;
2371 temp = ctx->in;
2372 ctx->in = ctx->out;
2373 if (buf.glyphs)
2374 ctx->out = temp;
2375 else
2376 {
2377 GINIT (&buf, ctx->out->allocated);
2378 ctx->out = &buf;
2379 }
2380 ctx->out->used = 0;
2381
2382 from = 0;
2383 to = ctx->in->used;
2384 }
2385
2386 if (ctx->out->used > 0)
2387 {
2388 /* Remove separator glyphs. */
2389 for (i = 0; i < ctx->out->used;)
2390 {
2391 g = GREF (ctx->out, i);
2392 if (g->c < 0)
2393 GREPLACE (NULL, 0, 0, ctx->out, i, i + 1);
2394 else
2395 i++;
2396 }
2397 }
2398 if (ctx->out->used > 0)
2399 {
2400 int *g_indices;
2401 int x_ppem = ctx->font->x_ppem << 6, y_ppem = ctx->font->y_ppem << 6;
2402
2403 /* Get actual glyph IDs of glyphs. */
2404 ctx->font->get_glyph_id (ctx->font, ctx->out, 0, ctx->out->used);
2405
2406 /* Check if all characters in the range are covered by some
2407 glyph(s). If not, change <from> and <to> of glyphs to cover
2408 uncovered characters. */
2409 g_indices = alloca (sizeof (int) * len);
2410 if (! g_indices)
2411 return -1;
2412 for (i = 0; i < len; i++) g_indices[i] = -1;
2413 for (i = 0; i < ctx->out->used; i++)
2414 {
2415 int pos;
2416
2417 g = GREF (ctx->out, i);
2418 for (pos = g->from; pos <= g->to; pos++)
2419 if (g_indices[pos - from_pos] < 0)
2420 g_indices[pos - from_pos] = i;
2421 }
2422 for (i = 0; i < len; i++)
2423 if (g_indices[i] < 0)
2424 {
2425 if (i == 0)
2426 {
2427 int this_from;
2428
2429 for (i++; i < len && g_indices[i] < 0; i++);
2430 if (! (i < len))
2431 break;
2432 j = g_indices[i];
2433 g = GREF (ctx->out, j);
2434 this_from = g->from;
2435 do {
2436 g->from = orig_from + i;
2437 } while (++j < ctx->out->used
2438 && (g = GREF (ctx->out, j))
2439 && g->from == this_from);
2440 }
2441 else
2442 {
2443 int this_to;
2444
2445 j = g_indices[i - 1];
2446 g = GREF (ctx->out, j);
2447 this_to = g->to;
2448 do {
2449 g->to = orig_from + i + 1;
2450 } while (--j >= 0
2451 && (g = GREF (ctx->out, j))
2452 && g->to == this_to);
2453 }
2454 }
2455
2456 ctx->font->get_metrics (ctx->font, ctx->out, 0, ctx->out->used);
2457
2458 /* Handle combining. */
2459 if (ctx->check_mask & CombinedMask)
2460 {
2461 MFLTGlyph *base = GREF (ctx->out, 0);
2462 int base_height = base->ascent + base->descent;
2463 int base_width = base->rbearing - base->lbearing;
2464 int combining_code;
2465
2466 for (i = 1; i < ctx->out->used; i++)
2467 {
2468 if ((g = GREF (ctx->out, i))
2469 && GET_COMBINED (g)
2470 && (combining_code = GET_COMBINING_CODE (g)))
2471 {
2472 int height = g->ascent + g->descent;
2473 int width = g->rbearing - g->lbearing;
2474 int base_x, base_y, add_x, add_y, off_x, off_y;
2475
2476 if (base->from > g->from)
2477 base->from = g->from;
2478 else if (base->to < g->to)
2479 base->to = g->to;
2480
2481 base_x = COMBINING_CODE_BASE_X (combining_code);
2482 base_y = COMBINING_CODE_BASE_Y (combining_code);
2483 add_x = COMBINING_CODE_ADD_X (combining_code);
2484 add_y = COMBINING_CODE_ADD_Y (combining_code);
2485 off_x = COMBINING_CODE_OFF_X (combining_code);
2486 off_y = COMBINING_CODE_OFF_Y (combining_code);
2487
2488 g->xoff = ((base_width * base_x - width * add_x) / 2
2489 + x_ppem * off_x / 100
2490 - (base->xadv - base->lbearing) - g->lbearing);
2491 if (base_y < 3)
2492 g->yoff = base_height * base_y / 2 - base->ascent;
2493 else
2494 g->yoff = 0;
2495 if (add_y < 3)
2496 g->yoff -= height * add_y / 2 - g->ascent;
2497 g->yoff -= y_ppem * off_y / 100;
2498 if (base->lbearing > base->xadv + g->lbearing + g->xoff)
2499 base->lbearing = base->xadv + g->lbearing + g->xoff;
2500 if (base->rbearing < base->xadv + g->rbearing + g->xoff)
2501 base->rbearing = base->xadv + g->rbearing + g->xoff;
2502 if (base->ascent < g->ascent - g->yoff)
2503 base->ascent = g->ascent - g->yoff;
2504 if (base->descent < g->descent - g->yoff)
2505 base->descent = g->descent - g->yoff;
2506 g->xadv = g->yadv = 0;
2507 if (GET_RIGHT_PADDING (g))
2508 SET_RIGHT_PADDING (base, ctx, RightPaddingMask);
2509 g->adjusted = 1;
2510 }
2511 else
2512 {
2513 base = g;
2514 base_height = g->ascent + g->descent;
2515 base_width = g->rbearing - g->lbearing;
2516 }
2517 }
2518 }
2519
2520 /* Handle padding */
2521 if (ctx->check_mask & (LeftPaddingMask | RightPaddingMask))
2522 for (i = 0; i < ctx->out->used; i++)
2523 {
2524 g = GREF (ctx->out, i);
2525 if (! GET_COMBINED (g))
2526 {
2527 if (GET_RIGHT_PADDING (g) && g->rbearing > g->xadv)
2528 {
2529 g->xadv = g->rbearing;
2530 g->adjusted = 1;
2531 }
2532 if (GET_LEFT_PADDING (g) && g->lbearing < 0)
2533 {
2534 g->xoff += - g->lbearing;
2535 g->xadv += - g->lbearing;
2536 g->rbearing += - g->lbearing;
2537 g->lbearing = 0;
2538 g->adjusted = 1;
2539 }
2540 }
2541 }
2542 }
2543
2544 GREPLACE (ctx->out, 0, ctx->out->used, gstring, orig_from, orig_to);
2545 to = orig_from + ctx->out->used;
2546 return to;
2547 }
2548
2549 static void
setup_combining_coverage(int from,int to,void * val,void * arg)2550 setup_combining_coverage (int from, int to, void *val, void *arg)
2551 {
2552 int combining_class = (int) val;
2553 int category = 0;
2554
2555 if (combining_class < 200)
2556 category = 'a';
2557 else if (combining_class <= 204)
2558 {
2559 if ((combining_class % 2) == 0)
2560 category = "bcd"[(combining_class - 200) / 2];
2561 }
2562 else if (combining_class <= 232)
2563 {
2564 if ((combining_class % 2) == 0)
2565 category = "efghijklmnopq"[(combining_class - 208) / 2];
2566 }
2567 else if (combining_class == 233)
2568 category = 'r';
2569 else if (combining_class == 234)
2570 category = 's';
2571 else if (combining_class == 240)
2572 category = 't';
2573 mchartable_set_range ((MCharTable *) arg, from, to, (void *) category);
2574 }
2575
2576 static void
setup_combining_flt(MFLT * flt)2577 setup_combining_flt (MFLT *flt)
2578 {
2579 MSymbol type;
2580 MCharTable *combininig_class_table
2581 = mchar_get_prop_table (Mcombining_class, &type);
2582
2583 mchartable_set_range (flt->coverage->table, 0, 0x10FFFF, (void *) 'u');
2584 if (combininig_class_table)
2585 mchartable_map (combininig_class_table, (void *) 0,
2586 setup_combining_coverage, flt->coverage->table);
2587 }
2588
2589 #define CHECK_FLT_STAGES(flt) ((flt)->stages || load_flt (flt, NULL) == 0)
2590
2591 static FontLayoutCategory *
configure_category(FontLayoutCategory * category,MFLTFont * font)2592 configure_category (FontLayoutCategory *category, MFLTFont *font)
2593 {
2594 if (! mflt_font_id || ! mflt_iterate_otf_feature)
2595 {
2596 FontLayoutCategory *new = malloc (sizeof (FontLayoutCategory));
2597 new->definition = NULL;
2598 new->table = category->table;
2599 M17N_OBJECT_REF (new->table);
2600 return new;
2601 }
2602 return load_category_table (category->definition, font);
2603 }
2604
2605 static MFLT *
configure_flt(MFLT * flt,MFLTFont * font,MSymbol font_id)2606 configure_flt (MFLT *flt, MFLTFont *font, MSymbol font_id)
2607 {
2608 MPlist *plist;
2609 MFLT *configured;
2610
2611 if (! mflt_font_id || ! mflt_iterate_otf_feature)
2612 return flt;
2613 MPLIST_DO (plist, flt_list)
2614 {
2615 configured = MPLIST_VAL (plist);
2616 if (! configured->font_id)
2617 break;
2618 if (configured->name == flt->name
2619 && configured->font_id == font_id)
2620 return configured;
2621 }
2622 if (! MSTRUCT_CALLOC_SAFE (configured))
2623 return flt;
2624 *configured = *flt;
2625 configured->stages = mplist_copy (flt->stages);
2626 MPLIST_DO (plist, configured->stages)
2627 {
2628 FontLayoutStage *stage = MPLIST_VAL (plist);
2629 if (stage->category->definition)
2630 {
2631 MSTRUCT_CALLOC (stage, MERROR_FLT);
2632 *stage = *((FontLayoutStage *) MPLIST_VAL (plist));
2633 stage->category = configure_category (stage->category, font);
2634 MPLIST_VAL (plist) = stage;
2635 }
2636 else
2637 M17N_OBJECT_REF (stage->category->table);
2638 }
2639 configured->need_config = 0;
2640 configured->font_id = font_id;
2641 mplist_push (flt_list, flt->name, configured);
2642 return configured;
2643 }
2644
2645 /* Internal API */
2646
2647 int m17n__flt_initialized;
2648
2649
2650 /* External API */
2651
2652 /* The following two are actually not exposed to a user but concealed
2653 by the macro M17N_INIT (). */
2654
2655 void
m17n_init_flt(void)2656 m17n_init_flt (void)
2657 {
2658 int mdebug_flag = MDEBUG_INIT;
2659
2660 merror_code = MERROR_NONE;
2661 if (m17n__flt_initialized++)
2662 return;
2663 m17n_init_core ();
2664 if (merror_code != MERROR_NONE)
2665 {
2666 m17n__flt_initialized--;
2667 return;
2668 }
2669
2670 MDEBUG_PUSH_TIME ();
2671
2672 Mcond = msymbol ("cond");
2673 Mrange = msymbol ("range");
2674 Mfont = msymbol ("font");
2675 Mlayouter = msymbol ("layouter");
2676 Mcombining = msymbol ("combining");
2677 Mfont_facility = msymbol ("font-facility");
2678 Mequal = msymbol ("=");
2679 Mgenerator = msymbol ("generator");
2680 Mend = msymbol ("end");
2681
2682 mflt_enable_new_feature = 0;
2683 mflt_iterate_otf_feature = NULL;
2684 mflt_font_id = NULL;
2685 mflt_try_otf = NULL;
2686
2687 MDEBUG_PRINT_TIME ("INIT", (mdebug__output, " to initialize the flt modules."));
2688 MDEBUG_POP_TIME ();
2689 }
2690
2691 void
m17n_fini_flt(void)2692 m17n_fini_flt (void)
2693 {
2694 int mdebug_flag = MDEBUG_FINI;
2695
2696 if (m17n__flt_initialized == 0
2697 || --m17n__flt_initialized > 0)
2698 return;
2699
2700 MDEBUG_PUSH_TIME ();
2701 free_flt_list ();
2702 MDEBUG_PRINT_TIME ("FINI", (mdebug__output, " to finalize the flt modules."));
2703 MDEBUG_POP_TIME ();
2704 m17n_fini_core ();
2705 }
2706
2707 /*** @} */
2708 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
2709
2710 /*** @addtogroup m17nFLT */
2711 /*** @{ */
2712 /*=*/
2713
2714 /*=*/
2715 /***en
2716 @brief Return an FLT object that has a specified name.
2717
2718 The mflt_get () function returns an FLT object whose name is $NAME.
2719
2720 @return
2721 If the operation was successful, mflt_get () returns a pointer
2722 to the found FLT object. Otherwise, it returns @c NULL. */
2723
2724 /***ja
2725 @brief ���ꤵ�줿̾������� FLT ���֥������Ȥ��֤�.
2726
2727 �ؿ� mflt_get () �ϡ�$NAME �Ȥ���̾������� FLT ���֥������Ȥ��֤���
2728
2729 @return
2730 �⤷��������С�mflt_get () �ϸ��Ĥ��ä� FLT
2731 ���֥������ȤؤΥݥ����֤������Ԥ������� @c NULL ���֤��� */
2732
2733 MFLT *
mflt_get(MSymbol name)2734 mflt_get (MSymbol name)
2735 {
2736 MFLT *flt;
2737 MPlist *plist;
2738
2739 if (! flt_list && list_flt () < 0)
2740 return NULL;
2741 for (plist = flt_list; plist; plist = plist->next)
2742 if (((MFLT *) MPLIST_VAL (plist))->font_id == Mnil)
2743 break;
2744 flt = mplist_get (plist, name);
2745 if (! flt || ! CHECK_FLT_STAGES (flt))
2746 return NULL;
2747 if (flt->name == Mcombining
2748 && ! mchartable_lookup (flt->coverage->table, 0))
2749 setup_combining_flt (flt);
2750
2751 return flt;
2752 }
2753
2754 /*=*/
2755 /***en
2756 @brief Find an FLT suitable for the specified character and font.
2757
2758 The mflt_find () function returns the most appropriate FLT for
2759 layouting character $C with font $FONT.
2760
2761 @return
2762 If the operation was successful, mflt_find () returns a pointer
2763 to the found FLT object. Otherwise, it returns @c NULL. */
2764
2765 /***ja
2766 @brief ���ꤵ�줿ʸ���ȥե���Ȥ˹�ä� FLT ��õ��.
2767
2768 �ؿ� mflt_find () �ϡ�ʸ�� $C ��ե���� $FONT
2769 �ǥ쥤�����Ȥ��뤿��˺Ǥ�Ŭ�ڤ� FLT ���֤���
2770
2771 @return
2772 �⤷��������С�mflt_find () �ϸ��Ĥ��ä� FLT
2773 ���֥������ȤؤΥݥ����֤������Ԥ������� @c NULL ���֤��� */
2774
2775 MFLT *
mflt_find(int c,MFLTFont * font)2776 mflt_find (int c, MFLTFont *font)
2777 {
2778 MPlist *plist, *pl;
2779 MFLT *flt;
2780 static MSymbol unicode_bmp = NULL, unicode_full = NULL;
2781
2782 if (! unicode_bmp)
2783 {
2784 unicode_bmp = msymbol ("unicode-bmp");
2785 unicode_full = msymbol ("unicode-full");
2786 }
2787
2788 if (! flt_list && list_flt () < 0)
2789 return NULL;
2790 /* Skip configured FLTs. */
2791 MPLIST_DO (plist, flt_list)
2792 if (((MFLT *) MPLIST_VAL (plist))->font_id == Mnil)
2793 break;
2794 if (font)
2795 {
2796 MFLT *best = NULL;
2797
2798 MPLIST_DO (pl, plist)
2799 {
2800 flt = MPLIST_VAL (pl);
2801 if (flt->registry != unicode_bmp
2802 && flt->registry != unicode_full)
2803 continue;
2804 if (flt->family && flt->family != font->family)
2805 continue;
2806 if (flt->name == Mcombining
2807 && ! mchartable_lookup (flt->coverage->table, 0))
2808 setup_combining_flt (flt);
2809 if (c >= 0
2810 && ! mchartable_lookup (flt->coverage->table, c))
2811 continue;
2812 if (flt->otf.sym)
2813 {
2814 MFLTOtfSpec *spec = &flt->otf;
2815
2816 if (! font->check_otf)
2817 {
2818 if ((spec->features[0] && spec->features[0][0] != 0xFFFFFFFF)
2819 || (spec->features[1] && spec->features[1][0] != 0xFFFFFFFF))
2820 continue;
2821 }
2822 else if (! font->check_otf (font, spec))
2823 continue;
2824 goto found;
2825 }
2826 best = flt;
2827 }
2828 if (best == NULL)
2829 return NULL;
2830 flt = best;
2831 goto found;
2832 }
2833 if (c >= 0)
2834 {
2835 MPLIST_DO (pl, plist)
2836 {
2837 flt = MPLIST_VAL (pl);
2838 if (mchartable_lookup (flt->coverage->table, c))
2839 goto found;
2840 }
2841 }
2842 return NULL;
2843
2844 found:
2845 if (! CHECK_FLT_STAGES (flt))
2846 return NULL;
2847 if (font && flt->need_config && mflt_font_id)
2848 flt = configure_flt (flt, font, mflt_font_id (font));
2849 return flt;
2850 }
2851
2852 /*=*/
2853 /***en
2854 @brief Return the name of an FLT.
2855
2856 The mflt_name () function returns the name of $FLT. */
2857
2858 /***ja
2859 @brief FLT ��̾�����֤�.
2860
2861 �ؿ� mflt_name () �� $FLT ��̾�����֤��� */
2862
2863 const char *
mflt_name(MFLT * flt)2864 mflt_name (MFLT *flt)
2865 {
2866 return MSYMBOL_NAME (flt->name);
2867 }
2868
2869 /*=*/
2870 /***en
2871 @brief Return a coverage of a FLT.
2872
2873 The mflt_coverage () function returns a char-table that contains
2874 nonzero values for characters supported by $FLT. */
2875
2876 /***ja
2877 @brief FLT ���ϰϤ��֤�.
2878
2879 �ؿ� mflt_coverage () �ϡ�$FLT �����ݡ��Ȥ���ʸ�����Ф���
2880 0 �Ǥʤ��ͤ�ޤ�ʸ���ơ��֥���֤��� */
2881
2882 MCharTable *
mflt_coverage(MFLT * flt)2883 mflt_coverage (MFLT *flt)
2884 {
2885 return flt->coverage->table;
2886 }
2887
2888 /*=*/
2889 /***en
2890 @brief Layout characters with an FLT.
2891
2892 The mflt_run () function layouts characters in $GSTRING between
2893 $FROM (inclusive) and $TO (exclusive) with $FONT. If $FLT is
2894 nonzero, it is used for all the charaters. Otherwise, appropriate
2895 FLTs are automatically chosen.
2896
2897 @retval >=0
2898 The operation was successful. The value is the index to the
2899 glyph, which was previously indexed by $TO, in $GSTRING->glyphs.
2900
2901 @retval -2
2902 $GSTRING->glyphs is too short to store the result. The caller can
2903 call this fucntion again with a longer $GSTRING->glyphs.
2904
2905 @retval -1
2906 Some other error occurred. */
2907
2908 /***ja
2909 @brief FLT ��Ȥä�ʸ����쥤�����Ȥ���.
2910
2911 �ؿ� mflt_run () �ϡ�$GSTRING ��� $FROM ���� $TO ľ���ޤǤ�ʸ����
2912 $FONT ���Ѥ��ƥ쥤�����Ȥ��롣�⤷ $FLT
2913 ������Ǥʤ���С������ͤ٤Ƥ�ʸ�����Ф����Ѥ��롣
2914 �����Ǥʤ����Ŭ�ڤ� FLT ��ưŪ�����롣
2915
2916 @retval >=0
2917 �¹����������֤�����ͤϡ�$GSTRING->glyphs ��ǰ��� $TO
2918 �ˤ�äƼ�����Ƥ�������դؤΥ���ǥ����Ǥ��롣
2919
2920 @retval -2
2921 ��̤��Ǽ����ˤ� $GSTRING->glyphs ��û�����뤳�Ȥ���
2922 �ƤӽФ�¦�ϡ����Ĺ�� $GSTRING->glyphs
2923 ���Ѥ��ƺ��٤��δؿ���Ƥ֤��Ȥ��Ǥ��롣
2924
2925 @retval -1
2926 ����¾�Υ��顼�����������Ȥ��� */
2927
2928 int
mflt_run(MFLTGlyphString * gstring,int from,int to,MFLTFont * font,MFLT * flt)2929 mflt_run (MFLTGlyphString *gstring, int from, int to,
2930 MFLTFont *font, MFLT *flt)
2931 {
2932 FontLayoutContext ctx;
2933 int match_indices[NMATCH];
2934 MFLTGlyph *g;
2935 MFLTGlyphString out;
2936 int auto_flt = ! flt;
2937 int c, i, j, k;
2938 int this_from, this_to;
2939 MSymbol font_id = mflt_font_id ? mflt_font_id (font) : Mnil;
2940
2941 out = *gstring;
2942 out.glyphs = NULL;
2943 /* This is usually sufficient, but if not, we retry with the larger
2944 values at most 3 times. This value is also used for the
2945 allocating size of ctx.encoded. */
2946 out.allocated = (to - from) * 4;
2947
2948 for (i = from; i < to; i++)
2949 {
2950 g = GREF (gstring, i);
2951 if (! g->encoded)
2952 {
2953 c = g->c;
2954 memset (g, 0, sizeof (MFLTGlyph));
2955 g->code = g->c = c;
2956 }
2957 g->from = g->to = i;
2958 }
2959
2960 for (this_from = from; this_from < to;)
2961 {
2962 if (! auto_flt)
2963 {
2964 for (this_to = this_from; this_to < to; this_to++)
2965 if (mchartable_lookup (flt->coverage->table,
2966 GREF (gstring, this_to)->c))
2967 break;
2968 }
2969 else
2970 {
2971 if (! flt_list && list_flt () < 0)
2972 {
2973 font->get_glyph_id (font, gstring, this_from, to);
2974 font->get_metrics (font, gstring, this_from, to);
2975 this_from = to;
2976 break;
2977 }
2978 for (this_to = this_from; this_to < to; this_to++)
2979 {
2980 c = GREF (gstring, this_to)->c;
2981 if (c >= flt_min_coverage && c <= flt_max_coverage)
2982 break;
2983 }
2984 for (; this_to < to; this_to++)
2985 {
2986 c = GREF (gstring, this_to)->c;
2987 if (font->internal
2988 && mchartable_lookup (((MFLT *) font->internal)->coverage->table, c))
2989 {
2990 flt = font->internal;
2991 break;
2992 }
2993 flt = mflt_find (c, font);
2994 if (flt)
2995 {
2996 if (CHECK_FLT_STAGES (flt))
2997 {
2998 font->internal = flt;
2999 break;
3000 }
3001 }
3002 }
3003 }
3004
3005 if (this_from < this_to)
3006 {
3007 font->get_glyph_id (font, gstring, this_from, this_to);
3008 font->get_metrics (font, gstring, this_from, this_to);
3009 this_from = this_to;
3010 }
3011 if (this_to == to)
3012 break;
3013
3014 MDEBUG_PRINT1 (" [FLT] (%s", MSYMBOL_NAME (flt->name));
3015
3016 if (flt->need_config && font_id != Mnil)
3017 flt = configure_flt (flt, font, font_id);
3018
3019 for (; this_to < to; this_to++)
3020 {
3021 char enc;
3022 g = GREF (gstring, this_to);
3023 enc = (int) mchartable_lookup (flt->coverage->table, g->c);
3024 if (! enc)
3025 break;
3026 SET_CATEGORY_CODE (g, enc);
3027 }
3028
3029 if (MDEBUG_FLAG ())
3030 {
3031 if (font->family)
3032 MDEBUG_PRINT1 (" (%s)", MSYMBOL_NAME (font->family));
3033 MDEBUG_PRINT ("\n [FLT] (SOURCE");
3034 for (i = this_from, j = 0; i < this_to; i++, j++)
3035 {
3036 if (j > 0 && j % 8 == 0)
3037 MDEBUG_PRINT ("\n [FLT] ");
3038 MDEBUG_PRINT1 (" %04X", GREF (gstring, i)->c);
3039 }
3040 MDEBUG_PRINT (")");
3041 }
3042
3043 for (i = 0; i < 3; i++)
3044 {
3045 /* Setup CTX. */
3046 memset (&ctx, 0, sizeof ctx);
3047 ctx.match_indices = match_indices;
3048 ctx.font = font;
3049 ctx.cluster_begin_idx = -1;
3050 ctx.in = gstring;
3051 ctx.out = &out;
3052 j = run_stages (gstring, this_from, this_to, flt, &ctx);
3053 if (j != -2)
3054 break;
3055 out.allocated *= 2;
3056 }
3057
3058 if (j < 0)
3059 return j;
3060
3061 to += j - this_to;
3062 this_to = j;
3063
3064 if (MDEBUG_FLAG ())
3065 {
3066 MDEBUG_PRINT ("\n [FLT] (RESULT");
3067 if (MDEBUG_FLAG () > 1)
3068 {
3069 int idx = -1;
3070 for (i = 0; this_from < this_to; i++, this_from++)
3071 {
3072 g = GREF (gstring, this_from);
3073 if (g->from != idx)
3074 {
3075 if (i > 0)
3076 MDEBUG_PRINT2 ("\n [FLT] %02d-%02d",
3077 g->from, g->to);
3078 else
3079 MDEBUG_PRINT2 (" %02d-%02d", g->from, g->to);
3080 idx = g->from;
3081 }
3082 MDEBUG_PRINT4 (" (%04X %d %d %d)",
3083 g->code, g->xadv, g->xoff, g->yoff);
3084 }
3085 }
3086 else
3087 for (; this_from < this_to; this_from++)
3088 MDEBUG_PRINT1 (" %04X", GREF (gstring, this_from)->code);
3089 MDEBUG_PRINT ("))\n");
3090 }
3091 this_from = this_to;
3092 }
3093
3094 if (gstring->r2l)
3095 {
3096 int len = to - from;
3097
3098 GINIT (&out, len);
3099 memcpy (((char *) out.glyphs),
3100 ((char *) gstring->glyphs) + gstring->glyph_size * from,
3101 gstring->glyph_size * len);
3102 for (i = from, j = to; i < to;)
3103 {
3104 for (k = i + 1, j--; k < to && GREF (&out, k)->xadv == 0;
3105 k++, j--);
3106 GCPY (&out, i, (k - i), gstring, j);
3107 i = k;
3108 }
3109 }
3110
3111 return to;
3112 }
3113
3114 /***en
3115 @brief Flag to control several new OTF handling commands.
3116
3117 If the variable mflt_enable_new_feature is nonzero, the function
3118 #mflt_run () can drive a Font Layout Table that contains the new
3119 OTF-related commands ":otf?" and/or OTF feature specification in a
3120 category table. */
3121 int mflt_enable_new_feature;
3122
3123 int (*mflt_iterate_otf_feature) (struct _MFLTFont *font,
3124 MFLTOtfSpec *spec,
3125 int from, int to,
3126 unsigned char *table);
3127
3128 MSymbol (*mflt_font_id) (struct _MFLTFont *font);
3129
3130 int (*mflt_try_otf) (struct _MFLTFont *font, MFLTOtfSpec *spec,
3131 MFLTGlyphString *gstring, int from, int to);
3132
3133
3134 /* for debugging... */
3135
3136 static void
dump_flt_cmd(FontLayoutStage * stage,int id,int indent)3137 dump_flt_cmd (FontLayoutStage *stage, int id, int indent)
3138 {
3139 char *prefix = (char *) alloca (indent + 1);
3140
3141 memset (prefix, 32, indent);
3142 prefix[indent] = 0;
3143
3144 if (id >= 0)
3145 fprintf (mdebug__output, "0x%02X", id);
3146 else if (id <= CMD_ID_OFFSET_INDEX)
3147 {
3148 int idx = CMD_ID_TO_INDEX (id);
3149 FontLayoutCmd *cmd = stage->cmds + idx;
3150
3151 if (cmd->type == FontLayoutCmdTypeRule)
3152 {
3153 FontLayoutCmdRule *rule = &cmd->body.rule;
3154 int i;
3155
3156 fprintf (mdebug__output, "(rule ");
3157 if (rule->src_type == SRC_REGEX)
3158 fprintf (mdebug__output, "\"%s\"", rule->src.re.pattern);
3159 else if (rule->src_type == SRC_INDEX)
3160 fprintf (mdebug__output, "%d", rule->src.match_idx);
3161 else if (rule->src_type == SRC_SEQ)
3162 fprintf (mdebug__output, "(seq)");
3163 else if (rule->src_type == SRC_RANGE)
3164 fprintf (mdebug__output, "(range)");
3165 else
3166 fprintf (mdebug__output, "(invalid src)");
3167
3168 for (i = 0; i < rule->n_cmds; i++)
3169 {
3170 fprintf (mdebug__output, "\n%s ", prefix);
3171 dump_flt_cmd (stage, rule->cmd_ids[i], indent + 2);
3172 }
3173 fprintf (mdebug__output, ")");
3174 }
3175 else if (cmd->type == FontLayoutCmdTypeCond)
3176 {
3177 FontLayoutCmdCond *cond = &cmd->body.cond;
3178 int i;
3179
3180 fprintf (mdebug__output, "(cond");
3181 for (i = 0; i < cond->n_cmds; i++)
3182 {
3183 fprintf (mdebug__output, "\n%s ", prefix);
3184 dump_flt_cmd (stage, cond->cmd_ids[i], indent + 2);
3185 }
3186 fprintf (mdebug__output, ")");
3187 }
3188 else if (cmd->type == FontLayoutCmdTypeOTF)
3189 {
3190 fprintf (mdebug__output, "(otf)");
3191 }
3192 else
3193 fprintf (mdebug__output, "(error-command)");
3194 }
3195 else if (id <= CMD_ID_OFFSET_COMBINING)
3196 fprintf (mdebug__output, "cominging-code");
3197 else
3198 fprintf (mdebug__output, "(predefiend %d)", id);
3199 }
3200
3201 /***en
3202 @brief Dump a Font Layout Table.
3203
3204 The mdebug_dump_flt () function prints the Font Layout Table $FLT
3205 in a human readable way to the stderr or to what specified by the
3206 environment variable MDEBUG_OUTPUT_FILE. $INDENT specifies how
3207 many columns to indent the lines but the first one.
3208
3209 @return
3210 This function returns $FLT. */
3211
3212 MFLT *
mdebug_dump_flt(MFLT * flt,int indent)3213 mdebug_dump_flt (MFLT *flt, int indent)
3214 {
3215 char *prefix = (char *) alloca (indent + 1);
3216 MPlist *plist;
3217 int stage_idx = 0;
3218
3219 memset (prefix, 32, indent);
3220 prefix[indent] = 0;
3221 fprintf (mdebug__output, "(flt");
3222 MPLIST_DO (plist, flt->stages)
3223 {
3224 FontLayoutStage *stage = (FontLayoutStage *) MPLIST_VAL (plist);
3225 int i;
3226
3227 fprintf (mdebug__output, "\n%s (stage %d", prefix, stage_idx);
3228 for (i = 0; i < stage->used; i++)
3229 {
3230 fprintf (mdebug__output, "\n%s ", prefix);
3231 dump_flt_cmd (stage, INDEX_TO_CMD_ID (i), indent + 4);
3232 }
3233 fprintf (mdebug__output, ")");
3234 stage_idx++;
3235 }
3236 fprintf (mdebug__output, ")");
3237 return flt;
3238 }
3239
3240 /***en
3241 @brief Dump an MFLTGlyphString.
3242
3243 The mflt_dump_gstring () function prints the glyph sequence
3244 $GSTRING in a human readable way to the stderr or to what
3245 specified by the environment variable MDEBUG_OUTPUT_FILE. */
3246
3247 void
mflt_dump_gstring(MFLTGlyphString * gstring)3248 mflt_dump_gstring (MFLTGlyphString *gstring)
3249 {
3250 int i;
3251
3252 fprintf (mdebug__output, "(flt-gstring");
3253 for (i = 0; i < gstring->used; i++)
3254 {
3255 MFLTGlyph *g = GREF (gstring, i);
3256 fprintf (mdebug__output, "\n (%02d pos:%d-%d c:%04X code:%04X cat:%c)",
3257 i, g->from, g->to, g->c, g->code, GET_CATEGORY_CODE (g));
3258 }
3259 fprintf (mdebug__output, ")\n");
3260 }
3261
3262 /*** @} */
3263
3264 /*
3265 Local Variables:
3266 coding: euc-japan
3267 End:
3268 */
3269