1
/* $Header: /home/cvsroot/dvipdfmx/src/fontmap.c,v 1.33 2005/07/30 11:44:18 hirata Exp $
3
This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks.
5
Copyright (C) 2002 by Jin-Hwan Cho and Shunsaku Hirata,
6
the dvipdfmx project team <dvipdfmx@project.ktug.or.kr>
8
Copyright (C) 1998, 1999 by Mark A. Wicks <mwicks@kettering.edu>
10
This program is free software; you can redistribute it and/or modify
11
it under the terms of the GNU General Public License as published by
12
the Free Software Foundation; either version 2 of the License, or
13
(at your option) any later version.
15
This program is distributed in the hope that it will be useful,
16
but WITHOUT ANY WARRANTY; without even the implied warranty of
17
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
GNU General Public License for more details.
20
You should have received a copy of the GNU General Public License
21
along with this program; if not, write to the Free Software
22
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
42
#include <CoreFoundation/CoreFoundation.h>
43
#include <ApplicationServices/ApplicationServices.h>
45
#include FT_FREETYPE_H
47
#include "fontconfig/fontconfig.h"
48
#include "fontconfig/fcfreetype.h"
53
static char *strip_options (const char *map_name, fontmap_opt *opt);
55
static int verbose = 0;
57
pdf_fontmap_set_verbose (void)
64
pdf_init_fontmap_record (fontmap_rec *mrec)
68
mrec->map_name = NULL;
70
/* SFD char mapping */
71
mrec->charmap.sfd_name = NULL;
72
mrec->charmap.subfont_id = NULL;
74
mrec->opt.mapc = -1; /* compatibility */
76
mrec->font_name = NULL;
77
mrec->enc_name = NULL;
79
mrec->opt.slant = 0.0;
80
mrec->opt.extend = 1.0;
85
mrec->opt.design_size = -1.0;
87
mrec->opt.tounicode = NULL;
88
mrec->opt.otl_tags = NULL; /* deactivated */
90
mrec->opt.charcoll = NULL;
91
mrec->opt.style = FONTMAP_STYLE_NONE;
94
mrec->opt.ft_face = NULL;
95
mrec->opt.glyph_widths = NULL;
100
pdf_clear_fontmap_record (fontmap_rec *mrec)
105
RELEASE(mrec->map_name);
106
if (mrec->charmap.sfd_name)
107
RELEASE(mrec->charmap.sfd_name);
108
if (mrec->charmap.subfont_id)
109
RELEASE(mrec->charmap.subfont_id);
111
RELEASE(mrec->enc_name);
113
RELEASE(mrec->font_name);
115
if (mrec->opt.tounicode)
116
RELEASE(mrec->opt.tounicode);
117
if (mrec->opt.otl_tags)
118
RELEASE(mrec->opt.otl_tags);
119
if (mrec->opt.charcoll)
120
RELEASE(mrec->opt.charcoll);
121
pdf_init_fontmap_record(mrec);
124
/* strdup: just returns NULL for NULL */
126
mstrdup (const char *s)
131
r = NEW(strlen(s) + 1, char);
137
pdf_copy_fontmap_record (fontmap_rec *dst, const fontmap_rec *src)
139
ASSERT( dst && src );
141
dst->map_name = mstrdup(src->map_name);
143
dst->charmap.sfd_name = mstrdup(src->charmap.sfd_name);
144
dst->charmap.subfont_id = mstrdup(src->charmap.subfont_id);
146
dst->font_name = mstrdup(src->font_name);
147
dst->enc_name = mstrdup(src->enc_name);
149
dst->opt.slant = src->opt.slant;
150
dst->opt.extend = src->opt.extend;
151
dst->opt.bold = src->opt.bold;
153
dst->opt.flags = src->opt.flags;
154
dst->opt.mapc = src->opt.mapc;
156
dst->opt.tounicode = mstrdup(src->opt.tounicode);
157
dst->opt.otl_tags = mstrdup(src->opt.otl_tags);
158
dst->opt.index = src->opt.index;
159
dst->opt.charcoll = mstrdup(src->opt.charcoll);
160
dst->opt.style = src->opt.style;
163
dst->opt.ft_face = src->opt.ft_face;
164
dst->opt.glyph_widths = src->opt.glyph_widths;
172
fontmap_rec *mrec = (fontmap_rec *) vp;
173
pdf_clear_fontmap_record(mrec);
179
fill_in_defaults (fontmap_rec *mrec, const char *tex_name)
181
if (mrec->enc_name &&
182
(!strcmp(mrec->enc_name, "default") ||
183
!strcmp(mrec->enc_name, "none"))) {
184
RELEASE(mrec->enc_name);
185
mrec->enc_name = NULL;
187
if (mrec->font_name &&
188
(!strcmp(mrec->font_name, "default") ||
189
!strcmp(mrec->font_name, "none"))) {
190
RELEASE(mrec->font_name);
191
mrec->font_name = NULL;
193
/* We *must* fill font_name either explicitly or by default */
194
if (!mrec->font_name) {
195
mrec->font_name = NEW(strlen(tex_name)+1, char);
196
strcpy(mrec->font_name, tex_name);
199
mrec->map_name = NEW(strlen(tex_name)+1, char);
200
strcpy(mrec->map_name, tex_name);
202
#ifndef WITHOUT_COMPAT
203
/* Use "UCS" character collection for Unicode SFD
204
* and Identity CMap combination. For backward
207
if (mrec->charmap.sfd_name && mrec->enc_name &&
208
!mrec->opt.charcoll) {
209
if ((!strcmp(mrec->enc_name, "Identity-H") ||
210
!strcmp(mrec->enc_name, "Identity-V"))
212
(strstr(mrec->charmap.sfd_name, "Uni") ||
213
strstr(mrec->charmap.sfd_name, "UBig") ||
214
strstr(mrec->charmap.sfd_name, "UBg") ||
215
strstr(mrec->charmap.sfd_name, "UGB") ||
216
strstr(mrec->charmap.sfd_name, "UKS") ||
217
strstr(mrec->charmap.sfd_name, "UJIS"))) {
218
mrec->opt.charcoll = NEW(strlen("UCS")+1, char);
219
strcpy(mrec->opt.charcoll, "UCS");
222
#endif /* WITHOUT_COMPAT */
228
readline (char *buf, int buf_len, FILE *fp)
231
ASSERT( buf && buf_len > 0 && fp );
232
p = mfgets(buf, buf_len, fp);
235
q = strchr(p, '%'); /* we don't have quoted string */
242
# define ISBLANK(c) ((c) == ' ' || (c) == '\t')
245
skip_blank (char **pp, char *endptr)
248
if (!p || p >= endptr)
250
for ( ; p < endptr && ISBLANK(*p); p++);
255
parse_string_value (char **pp, char *endptr)
257
char *q = NULL, *p = *pp;
260
if (!p || p >= endptr)
263
q = parse_c_string(&p, endptr);
265
for (n = 0; p < endptr && !isspace(*p); p++, n++);
268
q = NEW(n + 1, char);
269
memcpy(q, *pp, n); q[n] = '\0';
276
/* no preceeding spaces allowed */
278
parse_integer_value (char **pp, char *endptr, int base)
281
int has_sign = 0, has_prefix = 0, n;
283
ASSERT( base == 0 || (base >= 2 && base <= 36) );
285
if (!p || p >= endptr)
288
if (*p == '-' || *p == '+') {
291
if ((base == 0 || base == 16) &&
293
p[0] == '0' && p[1] == 'x') {
294
p += 2; has_prefix = 1;
299
else if (p < endptr && *p == '0')
305
#define ISDIGIT_WB(c,b) ( \
306
((b) <= 10 && (c) >= '0' && (c) < '0' + (b)) || \
308
((c) >= '0' && (c) <= '9') || \
309
((c) >= 'a' && (c) < 'a' + ((b) - 10)) || \
310
((c) >= 'A' && (c) < 'A' + ((b) - 10)) \
314
for (n = 0; p < endptr && ISDIGIT_WB(*p, base); p++, n++);
322
q = NEW(n + 1, char);
323
memcpy(q, *pp, n); q[n] = '\0';
330
fontmap_parse_mapdef (fontmap_rec *mrec,
331
const char *mapdef, char *endptr)
333
char *p = (char *) mapdef;
336
* Parse record line in map file. First two fields (after TeX font
337
* name) are position specific. Arguments start at the first token
338
* beginning with a '-'.
341
* Dvipdfm basically uses parse_ident() for parsing enc_name,
342
* font_name, and other string values which assumes PostScript-like
344
* skip_white() skips '\r' and '\n' but they should terminate
348
skip_blank(&p, endptr);
350
if (p < endptr && *p != '-') { /* May be NULL */
351
mrec->enc_name = parse_string_value(&p, endptr);
352
skip_blank(&p, endptr);
355
/* fontname or font filename field */
356
if (p < endptr && *p != '-') { /* May be NULL */
357
mrec->font_name = parse_string_value(&p, endptr);
358
skip_blank(&p, endptr);
360
if (mrec->font_name) {
362
/* Several options are encoded in font_name for
363
* compatibility with dvipdfm.
365
tmp = strip_options(mrec->font_name, &mrec->opt);
367
RELEASE(mrec->font_name);
368
mrec->font_name = tmp;
372
skip_blank(&p, endptr);
373
/* Parse any remaining arguments */
374
while (p + 1 < endptr &&
375
*p != '\r' && *p != '\n' && *p == '-') {
376
char *q, mopt = p[1];
379
p += 2; skip_blank(&p, endptr);
382
case 's': /* Slant option */
383
q = parse_float_decimal(&p, endptr);
385
WARN("Missing a number value for 's' option.");
388
mrec->opt.slant = atof(q);
391
case 'e': /* Extend option */
392
q = parse_float_decimal(&p, endptr);
394
WARN("Missing a number value for 'e' option.");
397
mrec->opt.extend = atof(q);
398
if (mrec->opt.extend <= 0.0) {
399
WARN("Invalid value for 'e' option: %s", q);
404
case 'b': /* Fake-bold option */
405
q = parse_float_decimal(&p, endptr);
407
WARN("Missing a number value for 'b' option.");
410
mrec->opt.bold = atof(q);
411
if (mrec->opt.bold <= 0.0) {
412
WARN("Invalid value for 'b' option: %s", q);
418
case 'r': /* Remap option */
419
mrec->opt.flags |= FONTMAP_OPT_REMAP;
423
case 'i': /* TTC index */
424
q = parse_integer_value(&p, endptr, 10);
426
WARN("Missing TTC index number...");
429
mrec->opt.index = atoi(q);
430
if (mrec->opt.index < 0) {
431
WARN("Invalid TTC index number: %s", q);
437
case 'p': /* UCS plane: just for testing */
438
q = parse_integer_value(&p, endptr, 0);
440
WARN("Missing a number for 'p' option.");
443
v = strtol(q, NULL, 0);
445
WARN("Invalid value for option 'p': %s", q);
447
mrec->opt.mapc = v << 16;
452
case 'u': /* ToUnicode */
453
q = parse_string_value(&p, endptr);
455
mrec->opt.tounicode = q;
457
WARN("Missing string value for option 'u'.");
463
/* Omega uses both single-byte and double-byte set_char command
464
* even for double-byte OFMs. This confuses CMap decoder.
467
/* Map single bytes char 0xab to double byte char 0xcdab */
468
if (p + 4 <= endptr &&
469
p[0] == '<' && p[3] == '>') {
471
q = parse_integer_value(&p, endptr, 16);
473
WARN("Invalid value for option 'm'.");
475
} else if (p < endptr && *p != '>') {
476
WARN("Invalid value for option 'm': %s", q);
480
v = strtol(q, NULL, 16);
481
mrec->opt.mapc = ((v << 8) & 0x0000ff00L);
483
} else if (p + 4 <= endptr &&
484
!memcmp(p, "sfd:", strlen("sfd:"))) {
486
/* SFD mapping: sfd:Big5,00 */
487
p += 4; skip_blank(&p, endptr);
488
q = parse_string_value(&p, endptr);
490
WARN("Missing value for option 'm'.");
495
WARN("Invalid value for option 'm': %s", q);
499
*r = 0; r++; skip_blank(&r, r + strlen(r));
501
WARN("Invalid value for option 'm': %s,", q);
505
mrec->charmap.sfd_name = mstrdup(q);
506
mrec->charmap.subfont_id = mstrdup(r);
508
} else if (p + 4 < endptr &&
509
!memcmp(p, "pad:", strlen("pad:"))) {
510
p += 4; skip_blank(&p, endptr);
511
q = parse_integer_value(&p, endptr, 16);
513
WARN("Invalid value for option 'm'.");
515
} else if (p < endptr && !isspace(*p)) {
516
WARN("Invalid value for option 'm': %s", q);
520
v = strtol(q, NULL, 16);
521
mrec->opt.mapc = ((v << 8) & 0x0000ff00L);
524
WARN("Invalid value for option 'm'.");
530
case 'w': /* Writing mode (for unicode encoding) */
531
if (!mrec->enc_name ||
532
strcmp(mrec->enc_name, "unicode")) {
533
WARN("Fontmap option 'w' meaningless for encoding other than \"unicode\".");
536
q = parse_integer_value(&p, endptr, 10);
538
WARN("Missing wmode value...");
542
mrec->opt.flags |= FONTMAP_OPT_VERT;
543
else if (atoi(q) == 0)
544
mrec->opt.flags &= ~FONTMAP_OPT_VERT;
546
WARN("Invalid value for option 'w': %s", q);
553
WARN("Unrecognized font map option: '%c'", mopt);
557
skip_blank(&p, endptr);
560
if (p < endptr && *p != '\r' && *p != '\n') {
561
WARN("Invalid char in fontmap line: %c", *p);
570
static struct ht_table *fontmap = NULL;
572
#define fontmap_invalid(m) (!(m) || !(m)->map_name || !(m)->font_name)
574
chop_sfd_name (const char *tex_name, char **sfd_name)
582
p = strchr((char *) tex_name, '@');
584
p[1] == '\0' || p == tex_name) {
587
m = (int) (p - tex_name);
596
len = strlen(tex_name) - n;
597
fontname = NEW(len+1, char);
598
memcpy(fontname, tex_name, m);
603
*sfd_name = NEW(n+1, char);
604
memcpy(*sfd_name, p, n);
605
(*sfd_name)[n] = '\0';
611
make_subfont_name (const char *map_name, const char *sfd_name, const char *sub_id)
617
p = strchr(map_name, '@');
618
if (!p || p == map_name)
620
m = (int) (p - map_name);
621
q = strchr(p + 1, '@');
622
if (!q || q == p + 1)
624
n = (int) (q - p) + 1; /* including two '@' */
625
if (strlen(sfd_name) != n - 2 ||
626
memcmp(p + 1, sfd_name, n - 2))
628
tfm_name = NEW(strlen(map_name) - n + strlen(sub_id) + 1, char);
629
memcpy(tfm_name, map_name, m);
631
strcat(tfm_name, sub_id);
632
if (q[1]) /* not ending with '@' */
633
strcat(tfm_name, q + 1);
638
/* "foo@A@ ..." is expanded to
639
* fooab ... -m sfd:A,ab
641
* fooyz ... -m sfd:A,yz
642
* where 'ab' ... 'yz' is subfont IDs in SFD 'A'.
645
pdf_append_fontmap_record (const char *kp, const fontmap_rec *vp)
648
char *fnt_name, *sfd_name = NULL;
650
if (!kp || fontmap_invalid(vp)) {
651
WARN("Invalid fontmap record...");
656
MESG("fontmap>> append key=\"%s\"...", kp);
658
fnt_name = chop_sfd_name(kp, &sfd_name);
659
if (fnt_name && sfd_name) {
663
subfont_ids = sfd_get_subfont_ids(sfd_name, &n);
667
tfm_name = make_subfont_name(kp, sfd_name, subfont_ids[n]);
670
mrec = ht_lookup_table(fontmap, tfm_name, strlen(tfm_name));
672
mrec = NEW(1, fontmap_rec);
673
pdf_init_fontmap_record(mrec);
674
mrec->map_name = mstrdup(kp); /* link */
675
mrec->charmap.sfd_name = mstrdup(sfd_name);
676
mrec->charmap.subfont_id = mstrdup(subfont_ids[n]);
677
ht_insert_table(fontmap, tfm_name, strlen(tfm_name), mrec, hval_free);
685
mrec = ht_lookup_table(fontmap, kp, strlen(kp));
687
mrec = NEW(1, fontmap_rec);
688
pdf_copy_fontmap_record(mrec, vp);
689
if (mrec->map_name && !strcmp(kp, mrec->map_name)) {
690
RELEASE(mrec->map_name);
691
mrec->map_name = NULL;
693
ht_insert_table(fontmap, kp, strlen(kp), mrec, hval_free);
702
pdf_remove_fontmap_record (const char *kp)
704
char *fnt_name, *sfd_name = NULL;
710
MESG("fontmap>> remove key=\"%s\"...", kp);
712
fnt_name = chop_sfd_name(kp, &sfd_name);
713
if (fnt_name && sfd_name) {
717
subfont_ids = sfd_get_subfont_ids(sfd_name, &n);
721
MESG("\nfontmap>> Expand @%s@:", sfd_name);
723
tfm_name = make_subfont_name(kp, sfd_name, subfont_ids[n]);
727
MESG(" %s", tfm_name);
728
ht_remove_table(fontmap, tfm_name, strlen(tfm_name), hval_free);
735
ht_remove_table(fontmap, kp, strlen(kp), hval_free);
744
pdf_insert_fontmap_record (const char *kp, const fontmap_rec *vp)
747
char *fnt_name, *sfd_name;
749
if (!kp || fontmap_invalid(vp)) {
750
WARN("Invalid fontmap record...");
755
MESG("fontmap>> insert key=\"%s\"...", kp);
757
fnt_name = chop_sfd_name(kp, &sfd_name);
758
if (fnt_name && sfd_name) {
762
subfont_ids = sfd_get_subfont_ids(sfd_name, &n);
766
MESG("\nfontmap>> Expand @%s@:", sfd_name);
768
tfm_name = make_subfont_name(kp, sfd_name, subfont_ids[n]);
772
MESG(" %s", tfm_name);
773
mrec = NEW(1, fontmap_rec);
774
pdf_init_fontmap_record(mrec);
775
mrec->map_name = mstrdup(kp); /* link to this entry */
776
mrec->charmap.sfd_name = mstrdup(sfd_name);
777
mrec->charmap.subfont_id = mstrdup(subfont_ids[n]);
778
ht_insert_table(fontmap, tfm_name, strlen(tfm_name), mrec, hval_free);
785
mrec = NEW(1, fontmap_rec);
786
pdf_copy_fontmap_record(mrec, vp);
787
if (mrec->map_name && !strcmp(kp, mrec->map_name)) {
788
RELEASE(mrec->map_name);
789
mrec->map_name = NULL;
791
ht_insert_table(fontmap, kp, strlen(kp), mrec, hval_free);
801
pdf_read_fontmap_line (fontmap_rec *mrec, const char *mline, long mline_len)
804
char *q, *p, *endptr;
810
endptr = p + mline_len;
812
skip_blank(&p, endptr);
816
q = parse_string_value(&p, endptr);
820
error = fontmap_parse_mapdef(mrec, p, endptr);
822
char *fnt_name, *sfd_name = NULL;
823
fnt_name = chop_sfd_name(q, &sfd_name);
824
if (fnt_name && sfd_name) {
825
if (!mrec->font_name) {
826
/* In the case of subfonts, the base name (before the character '@')
827
* will be used as a font_name by default.
828
* Otherwise tex_name will be used as a font_name by default.
830
mrec->font_name = fnt_name;
834
if (mrec->charmap.sfd_name)
835
RELEASE(mrec->charmap.sfd_name);
836
mrec->charmap.sfd_name = sfd_name ;
838
fill_in_defaults(mrec, q);
846
* String enclosed by '"' --> PostScript code(!)
847
* '<' or '<<' followed by *.enc, *.pfb, or *.pfa
850
is_pdfm_mapline (const char *mline) /* NULL terminated. */
853
char *q, *p, *endptr;
856
endptr = p + strlen(mline);
858
skip_blank(&p, endptr);
859
/* Break if '-' preceeded by blanks is found. */
860
while (r && p < endptr && *p != '-') {
863
q = parse_c_string(&p, endptr); /* wrong */
865
if (strstr(q, "SlantFont") ||
866
strstr(q, "ExtendFont") ||
867
strstr(q, "ReEncodeFont")) {
877
for ( ; p < endptr && !ISBLANK(*p); p++);
878
skip_blank(&p, endptr);
885
delete_records (FILE *fp, long num_lines)
889
while (num_lines-- > 0 &&
890
(p = readline(work_buffer, WORK_BUFFER_SIZE, fp)) != NULL) {
891
skip_blank(&p, p + strlen(p));
894
q = parse_string_value(&p, p + strlen(p));
896
WARN("Deleting fontmap record for \"%s\"", q);
897
pdf_remove_fontmap_record(q);
905
pdf_load_fontmap_file (const char *filename, int mode)
909
char *p = NULL, *endptr;
917
MESG("<FONTMAP:%s", filename);
919
fp = DPXFOPEN(filename, DPX_RES_TYPE_FONTMAP);
921
WARN("Couldn't open font map file \"%s\".", filename);
926
(p = readline(work_buffer, WORK_BUFFER_SIZE, fp)) != NULL) {
929
llen = strlen(work_buffer);
932
skip_blank(&p, endptr);
936
if (!is_pdfm_mapline(p)) {
937
WARN("This .map file looks like a dvips format fontmap file.");
938
WARN("-- Current input buffer is: %s", p);
939
WARN("-- Reading fontmap file stopped at: file=\"%s\", line=%d.",
942
delete_records(fp, lpos - 1);
946
mrec = NEW(1, fontmap_rec);
947
pdf_init_fontmap_record(mrec);
948
error = pdf_read_fontmap_line(mrec, p, llen);
950
WARN("Invalid map record in fontmap file.");
951
WARN("-- Current input buffer is: %s", p);
952
WARN("-- Reading fontmap file stopped at: file=\"%s\", line=%d.",
955
delete_records(fp, lpos - 1);
958
case FONTMAP_RMODE_REPLACE:
959
pdf_insert_fontmap_record(mrec->map_name, mrec);
961
case FONTMAP_RMODE_APPEND:
962
pdf_append_fontmap_record(mrec->map_name, mrec);
964
case FONTMAP_RMODE_REMOVE:
965
pdf_remove_fontmap_record(mrec->map_name);
969
pdf_clear_fontmap_record(mrec);
983
pdf_insert_native_fontmap_record (const char *name, const char *path, int index, FT_Face face, int layout_dir)
989
ASSERT(path || face);
991
fontmap_key = malloc(strlen(name) + 3);
992
sprintf(fontmap_key, "%s/%c", name, layout_dir == 0 ? 'H' : 'V');
995
MESG("<NATIVE-FONTMAP:%s", fontmap_key);
997
mrec = NEW(1, fontmap_rec);
998
pdf_init_fontmap_record(mrec);
1000
mrec->map_name = mstrdup(fontmap_key);
1001
mrec->enc_name = mstrdup(layout_dir == 0 ? "Identity-H" : "Identity-V");
1002
mrec->font_name = (path != NULL) ? mstrdup(path) : NULL;
1003
mrec->opt.index = index;
1004
mrec->opt.ft_face = face;
1005
mrec->opt.glyph_widths = NULL;
1006
if (layout_dir != 0)
1007
mrec->opt.flags |= FONTMAP_OPT_VERT;
1009
fill_in_defaults(mrec, fontmap_key);
1010
pdf_insert_fontmap_record(mrec->map_name, mrec);
1011
pdf_clear_fontmap_record(mrec);
1020
static FT_Library ftLib;
1023
pdf_load_native_font_from_path(const char *ps_name, int layout_dir)
1026
char *filename = NEW(strlen(ps_name), char);
1029
FT_Face face = NULL;
1033
for (p = ps_name + 1; *p && *p != ']'; ++p) {
1035
if (p == ps_name+2 && isalpha(*(p-1)) && (*(p+1) == '/' || *(p+1) == '\\'))
1044
for (p = ps_name + 1; *p && *p != ':' && *p != ']'; ++p)
1050
while (*p && *p != ']')
1051
index = index * 10 + *p++ - '0';
1054
if ( (q = dpx_find_opentype_file(filename)) != NULL
1055
|| (q = dpx_find_truetype_file(filename)) != NULL
1056
|| (q = dpx_find_type1_file(filename)) != NULL) {
1057
error = FT_New_Face(ftLib, q, index, &face);
1062
return pdf_insert_native_fontmap_record(ps_name, filename, index, face, layout_dir);
1068
pdf_load_native_font (const char *ps_name,
1069
const char *fam_name, const char *sty_name,
1072
static int sInitialized = 0;
1077
if (!sInitialized) {
1078
if (FT_Init_FreeType(&ftLib) != 0) {
1079
WARN("FreeType initialization failed.");
1085
if (ps_name[0] == '[') {
1086
error = pdf_load_native_font_from_path(ps_name, layout_dir);
1090
CFStringRef theName = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault,
1091
ps_name, kCFStringEncodingASCII, kCFAllocatorNull);
1092
fontRef = ATSFontFindFromPostScriptName(theName, kATSOptionFlagsDefault);
1095
CFStringRef atsName = NULL;
1096
OSStatus status = ATSFontGetName(fontRef, kATSOptionFlagsDefault, &atsName);
1097
if (status == noErr) {
1100
int bufferSize = CFStringGetLength(atsName) * 4 + 1;
1101
char* fontName = NEW(bufferSize, char);
1102
if (CFStringGetCString(atsName, fontName, bufferSize, kCFStringEncodingUTF8)) {
1103
FT_Error ftErr = FT_GetFile_From_Mac_ATS_Name(fontName, &pathSpec, &index);
1106
ftErr = FT_New_Face_From_FSSpec(ftLib, &pathSpec, index, &face);
1108
error = pdf_insert_native_fontmap_record(ps_name, NULL, 0, face, layout_dir);
1126
if (!sInitialized) {
1127
if (FcInit() == FcFalse) {
1128
WARN("Fontconfig initialization failed.");
1131
if (FT_Init_FreeType(&ftLib) != 0) {
1132
WARN("FreeType initialization failed.");
1138
if (ps_name[0] == '[') {
1139
error = pdf_load_native_font_from_path(ps_name, layout_dir);
1142
os = FcObjectSetBuild(FC_FILE, FC_INDEX, FC_FAMILY, FC_STYLE, NULL);
1143
pat = FcPatternBuild(0, FC_FAMILY, FcTypeString, fam_name,
1144
FC_STYLE, FcTypeString, sty_name,
1145
FC_OUTLINE, FcTypeBool, FcTrue, NULL);
1146
matches = FcFontList(FcConfigGetCurrent(), pat, os);
1147
FcObjectSetDestroy(os);
1148
FcPatternDestroy(pat);
1150
for (i = 0; i < matches->nfont; i++) {
1155
if (FcPatternGetString(matches->fonts[i],
1156
FC_FILE, 0, &path) == FcResultMatch &&
1157
FcPatternGetInteger(matches->fonts[i],
1158
FC_INDEX, 0, &index) == FcResultMatch) {
1159
FT_New_Face(ftLib, (char*)path, index, &face);
1160
name = (char *)FT_Get_Postscript_Name(face);
1161
if (!strcmp(name, ps_name)) {
1162
error = pdf_insert_native_fontmap_record(ps_name, (char*)path, index, face, layout_dir);
1163
/* don't dispose of the FT_Face, as we'll be using it to retrieve font data */
1178
/* tfm_name="dmjhira10", map_name="dmj@DNP@10", sfd_name="DNP"
1180
* Test if tfm_name can be really considered as subfont.
1183
test_subfont (const char *tfm_name, const char *map_name, const char *sfd_name)
1188
char *p = (char *) map_name;
1189
char *q = (char *) tfm_name;
1191
ASSERT( tfm_name && map_name && sfd_name );
1193
/* until first occurence of '@' */
1194
for ( ; *p && *q && *p == *q && *p != '@'; p++, q++);
1198
/* compare sfd_name (should be always true here) */
1199
if (strlen(p) <= strlen(sfd_name) ||
1200
memcmp(p, sfd_name, strlen(sfd_name)) ||
1201
p[strlen(sfd_name)] != '@')
1203
/* check tfm_name follows second '@' */
1204
p += strlen(sfd_name) + 1;
1206
char *r = (char *) tfm_name;
1207
r += strlen(tfm_name) - strlen(p);
1211
/* Now 'p' is located at next to SFD name terminator
1212
* (second '@') in map_name and 'q' is at first char
1213
* of subfont_id substring in tfm_name.
1215
n = strlen(q) - strlen(p); /* length of subfont_id string */
1218
/* check if n-length substring 'q' is valid as subfont ID */
1219
ids = sfd_get_subfont_ids(sfd_name, &m);
1222
while (!r && m-- > 0) {
1223
if (strlen(ids[m]) == n &&
1224
!memcmp(q, ids[m], n)) {
1235
pdf_lookup_fontmap_record (const char *tfm_name)
1237
fontmap_rec *mrec = NULL;
1239
if (fontmap && tfm_name)
1240
mrec = ht_lookup_table(fontmap, tfm_name, strlen(tfm_name));
1247
pdf_init_fontmaps (void)
1249
fontmap = NEW(1, struct ht_table);
1250
ht_init_table(fontmap);
1254
pdf_close_fontmaps (void)
1257
ht_clear_table(fontmap, hval_free);
1264
pdf_clear_fontmaps (void)
1266
pdf_close_fontmaps();
1267
pdf_init_fontmaps();
1274
* (:int:)?!?string(/string)?(,string)?
1278
substr (char **str, char stop)
1280
char *sstr, *endptr;
1282
endptr = strchr(*str, stop);
1283
if (!endptr || endptr == *str)
1285
sstr = NEW(endptr-(*str)+1, char);
1286
memcpy(sstr, *str, endptr-(*str));
1287
sstr[endptr-(*str)] = '\0';
1294
#define CID_MAPREC_CSI_DELIM '/'
1297
strip_options (const char *map_name, fontmap_opt *opt)
1300
char *p, *next = NULL;
1301
int have_csi = 0, have_style = 0;
1305
p = (char *) map_name;
1307
opt->charcoll = NULL;
1309
opt->style = FONTMAP_STYLE_NONE;
1312
if (*p == ':' && isdigit(*(p+1))) {
1313
opt->index = (int) strtoul(p+1, &next, 10);
1320
if (*p == '!') { /* no-embedding */
1322
ERROR("Invalid map record: %s (--> %s)", map_name, p);
1323
opt->flags |= FONTMAP_OPT_NOEMBED;
1326
if ((next = strchr(p, CID_MAPREC_CSI_DELIM)) != NULL) {
1328
ERROR("Invalid map record: %s (--> %s)", map_name, p);
1329
font_name = substr(&p, CID_MAPREC_CSI_DELIM);
1331
} else if ((next = strchr(p, ',')) != NULL) {
1333
ERROR("Invalid map record: %s (--> %s)", map_name, p);
1334
font_name = substr(&p, ',');
1337
font_name = NEW(strlen(p)+1, char);
1338
strcpy(font_name, p);
1342
if ((next = strchr(p, ',')) != NULL) {
1343
opt->charcoll = substr(&p, ',');
1345
} else if (p[0] == '\0') {
1346
ERROR("Invalid map record: %s.", map_name);
1348
opt->charcoll = NEW(strlen(p)+1, char);
1349
strcpy(opt->charcoll, p);
1354
if (!strncmp(p, "BoldItalic", 10)) {
1356
ERROR("Invalid map record: %s (--> %s)", map_name, p);
1357
opt->style = FONTMAP_STYLE_BOLDITALIC;
1358
} else if (!strncmp(p, "Bold", 4)) {
1360
ERROR("Invalid map record: %s (--> %s)", map_name, p);
1361
opt->style = FONTMAP_STYLE_BOLD;
1362
} else if (!strncmp(p, "Italic", 6)) {
1364
ERROR("Invalid map record: %s (--> %s)", map_name, p);
1365
opt->style = FONTMAP_STYLE_ITALIC;
1374
dump_fontmap_rec (const char *key, const fontmap_rec *mrec)
1376
fontmap_opt *opt = (fontmap_opt *) &mrec->opt;
1379
fprintf(stdout, " <!-- subfont");
1381
fprintf(stdout, " <insert");
1382
fprintf(stdout, " id=\"%s\"", key);
1384
fprintf(stdout, " map-name=\"%s\"", mrec->map_name);
1386
fprintf(stdout, " enc-name=\"%s\"", mrec->enc_name);
1387
if (mrec->font_name)
1388
fprintf(stdout, " font-name=\"%s\"", mrec->font_name);
1389
if (mrec->charmap.sfd_name && mrec->charmap.subfont_id) {
1390
fprintf(stdout, " charmap=\"sfd:%s,%s\"",
1391
mrec->charmap.sfd_name, mrec->charmap.subfont_id);
1393
if (opt->slant != 0.0)
1394
fprintf(stdout, " font-slant=\"%g\"", opt->slant);
1395
if (opt->extend != 1.0)
1396
fprintf(stdout, " font-extend=\"%g\"", opt->extend);
1398
fprintf(stdout, " glyph-order=\"%s\"", opt->charcoll);
1400
fprintf(stdout, " tounicode=\"%s\"", opt->tounicode);
1401
if (opt->index != 0)
1402
fprintf(stdout, " ttc-index=\"%d\"", opt->index);
1403
if (opt->flags & FONTMAP_OPT_REMAP)
1404
fprintf(stdout, " remap=\"true\"");
1405
if (opt->flags & FONTMAP_OPT_NOEMBED)
1406
fprintf(stdout, " embedding=\"no\"");
1407
if (opt->mapc >= 0) {
1408
fprintf(stdout, " charmap=\"pad:");
1409
if (opt->mapc > 0xffff)
1410
fprintf(stdout, "%02x %02x", (opt->mapc >> 16) & 0xff, (opt->mapc >> 8) & 0xff);
1412
fprintf(stdout, "%02x", (opt->mapc >> 8) & 0xff);
1413
fprintf(stdout, "\"");
1415
if (opt->flags & FONTMAP_OPT_VERT)
1416
fprintf(stdout, " writing-mode=\"vertical\"");
1417
if (opt->style != FONTMAP_STYLE_NONE) {
1418
fprintf(stdout, " font-style=\"");
1419
switch (opt->style) {
1420
case FONTMAP_STYLE_BOLD:
1421
fprintf(stdout, "bold");
1423
case FONTMAP_STYLE_ITALIC:
1424
fprintf(stdout, "italic");
1426
case FONTMAP_STYLE_BOLDITALIC:
1427
fprintf(stdout, "bolditalic");
1430
fprintf(stdout, "\"");
1433
fprintf(stdout, " / -->\n");
1435
fprintf(stdout, " />\n");
1439
dump_fontmaps (void)
1441
struct ht_iter iter;
1449
fprintf(stdout, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
1450
fprintf(stdout, "<!DOCTYPE fontmap SYSTEM \"fontmap.dtd\">\n");
1451
fprintf(stdout, "<fontmap id=\"%s\">\n", "foo");
1452
if (ht_set_iter(fontmap, &iter) == 0) {
1454
kp = ht_iter_getkey(&iter, &kl);
1455
mrec = ht_iter_getval(&iter);
1458
memcpy(key, kp, kl); key[kl] = 0;
1459
dump_fontmap_rec(key, mrec);
1460
} while (!ht_iter_next(&iter));
1462
ht_clear_iter(&iter);
1463
fprintf(stdout, "</fontmap>\n");
1469
test_fontmap_help (void)
1471
fprintf(stdout, "usage: fontmap [options] [mapfile...]\n");
1472
fprintf(stdout, "-l, --lookup string\n");
1473
fprintf(stdout, " Lookup fontmap entry for 'string' after loading mapfile(s).\n");
1477
test_fontmap_main (int argc, char *argv[])
1484
static struct option long_options[] = {
1485
{"lookup", 1, 0, 'l'},
1486
{"help", 0, 0, 'h'},
1489
c = getopt_long(argc, argv, "l:h", long_options, &optidx);
1498
test_fontmap_help();
1502
test_fontmap_help();
1508
pdf_init_fontmaps();
1509
for (i = optind; i < argc; i++)
1510
pdf_load_fontmap_file(argv[i], FONTMAP_RMODE_REPLACE);
1516
mrec = pdf_lookup_fontmap_record(key);
1518
dump_fontmap_rec(key, mrec);
1520
WARN("Fontmap entry \"%s\" not found.", key);
1523
pdf_close_fontmaps();
1527
#endif /* DPXTEST */