3 This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks.
5 Copyright (C) 2002-2012 by Jin-Hwan Cho and Shunsaku Hirata,
6 the dvipdfmx project team.
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program 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
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
28 * Composite font (multiple descendants) - not supported in PDF
51 #define TYPE0FONT_DEBUG_STR "Type0"
52 #define TYPE0FONT_DEBUG 3
54 static int __verbose = 0;
56 static pdf_obj *pdf_read_ToUnicode_file (const char *cmap_name);
59 Type0Font_set_verbose(void)
67 * Single bit is used for each CIDs since used_chars can be reused as a
68 * stream content of CIDSet by doing so. See, cid.h for add_to_used() and
77 used_chars = NEW(8192, char);
78 memset(used_chars, 0, 8192);
84 #define FLAG_USED_CHARS_SHARED (1 << 0)
87 char *fontname; /* BaseFont */
88 char *encoding; /* "Identity-H" or "Identity-V" (not ID) */
89 char *used_chars; /* Used chars (CIDs) */
94 CIDFont *descendant; /* Only single descendant is allowed. */
103 pdf_obj *descriptor; /* MUST BE NULL */
107 Type0Font_init_font_struct (Type0Font *font)
111 font->fontname = NULL;
112 font->fontdict = NULL;
113 font->indirect = NULL;
114 font->descriptor = NULL;
115 font->encoding = NULL;
116 font->used_chars = NULL;
117 font->descendant = NULL;
119 font->flags = FLAG_NONE;
125 Type0Font_clean (Type0Font *font)
129 ERROR("%s: Object not flushed.", TYPE0FONT_DEBUG_STR);
131 ERROR("%s: Object not flushed.", TYPE0FONT_DEBUG_STR);
132 if (font->descriptor)
133 ERROR("%s: FontDescriptor unexpected for Type0 font.", TYPE0FONT_DEBUG_STR);
134 if (!(font->flags & FLAG_USED_CHARS_SHARED) && font->used_chars)
135 RELEASE(font->used_chars);
137 RELEASE(font->encoding);
139 RELEASE(font->fontname);
140 font->fontdict = NULL;
141 font->indirect = NULL;
142 font->descriptor = NULL;
143 font->used_chars = NULL;
144 font->encoding = NULL;
145 font->fontname = NULL;
149 /* PLEASE FIX THIS */
153 add_ToUnicode (Type0Font *font)
158 char *cmap_name, *fontname;
163 * ToUnicode CMaps are usually not required for standard character
164 * collections such as Adobe-Japan1. Identity-H is used for UCS
165 * ordering CID-keyed fonts. External resource must be loaded for
169 cidfont = font->descendant;
171 ERROR("%s: No descendant CID-keyed font.", TYPE0FONT_DEBUG_STR);
175 if (CIDFont_is_ACCFont(cidfont)) {
176 /* No need to embed ToUnicode */
178 } else if (CIDFont_is_UCSFont(cidfont)) {
180 * Old version of dvipdfmx mistakenly used Adobe-Identity as Unicode.
182 tounicode = pdf_read_ToUnicode_file("Adobe-Identity-UCS2");
183 if (!tounicode) { /* This should work */
184 tounicode = pdf_new_name("Identity-H");
186 pdf_add_dict(font->fontdict, pdf_new_name("ToUnicode"), tounicode);
191 csi = CIDFont_get_CIDSysInfo(cidfont);
192 fontname = CIDFont_get_fontname(cidfont);
193 if (CIDFont_get_embedding(cidfont)) {
194 fontname += 7; /* FIXME */
197 if (!strcmp(csi->registry, "Adobe") &&
198 !strcmp(csi->ordering, "Identity")) {
199 switch (CIDFont_get_subtype(cidfont)) {
201 /* PLEASE FIX THIS */
202 tounicode = otf_create_ToUnicode_stream(CIDFont_get_ident(cidfont),
203 CIDFont_get_opt_index(cidfont),
204 Type0Font_get_usedchars(font));
207 if (CIDFont_get_flag(cidfont, CIDFONT_FLAG_TYPE1C)) { /* FIXME */
208 tounicode = otf_create_ToUnicode_stream(CIDFont_get_ident(cidfont),
209 CIDFont_get_opt_index(cidfont),
210 Type0Font_get_usedchars(font));
211 } else if (CIDFont_get_flag(cidfont, CIDFONT_FLAG_TYPE1)) { /* FIXME */
212 /* Font loader will create ToUnicode and set. */
215 cmap_name = NEW(strlen(fontname) + 7, char);
216 sprintf(cmap_name, "%s-UTF16", fontname);
217 tounicode = pdf_read_ToUnicode_file(cmap_name);
219 sprintf(cmap_name, "%s-UCS2", fontname);
220 tounicode = pdf_read_ToUnicode_file(cmap_name);
227 cmap_name = NEW(strlen(csi->registry)+strlen(csi->ordering)+8, char);
228 sprintf(cmap_name, "%s-%s-UTF16", csi->registry, csi->ordering);
229 tounicode = pdf_read_ToUnicode_file(cmap_name);
231 sprintf(cmap_name, "%s-%s-UCS2", csi->registry, csi->ordering);
232 tounicode = pdf_read_ToUnicode_file(cmap_name);
238 pdf_add_dict(font->fontdict,
239 pdf_new_name("ToUnicode"), tounicode);
241 WARN("Failed to load ToUnicode CMap for font \"%s\"", fontname);
248 Type0Font_set_ToUnicode (Type0Font *font, pdf_obj *cmap_ref)
252 pdf_add_dict(font->fontdict,
253 pdf_new_name("ToUnicode"), cmap_ref);
257 Type0Font_dofont (Type0Font *font)
259 if (!font || !font->indirect)
262 if (!pdf_lookup_dict(font->fontdict, "ToUnicode")) { /* FIXME */
268 Type0Font_flush (Type0Font *font)
272 pdf_release_obj(font->fontdict);
273 font->fontdict = NULL;
275 pdf_release_obj(font->indirect);
276 font->indirect = NULL;
277 if (font->descriptor)
278 ERROR("%s: FontDescriptor unexpected for Type0 font.", TYPE0FONT_DEBUG_STR);
279 font->descriptor = NULL;
284 Type0Font_get_wmode (Type0Font *font)
293 Type0Font_get_encoding (Type0Font *font)
297 return font->encoding;
302 Type0Font_get_usedchars (Type0Font *font)
306 return font->used_chars;
310 Type0Font_get_resource (Type0Font *font)
315 * This looks somewhat strange.
317 if (!font->indirect) {
320 array = pdf_new_array();
321 pdf_add_array(array, CIDFont_get_resource(font->descendant));
322 pdf_add_dict(font->fontdict, pdf_new_name("DescendantFonts"), array);
323 font->indirect = pdf_ref_obj(font->fontdict);
326 return pdf_link_obj(font->indirect);
329 /******************************** CACHE ********************************/
331 #define CHECK_ID(n) do {\
332 if ((n) < 0 || (n) >= __cache.count)\
333 ERROR("%s: Invalid ID %d", TYPE0FONT_DEBUG_STR, (n));\
336 #define CACHE_ALLOC_SIZE 16u
338 static struct font_cache {
347 Type0Font_cache_init (void)
350 ERROR("%s: Already initialized.", TYPE0FONT_DEBUG_STR);
352 __cache.capacity = 0;
353 __cache.fonts = NULL;
357 Type0Font_cache_get (int id)
361 return &__cache.fonts[id];
365 Type0Font_cache_find (const char *map_name, int cmap_id, fontmap_opt *fmap_opt)
372 char *fontname = NULL;
373 int cid_id = -1, parent_id = -1, wmode = 0;
376 pdf_ver = pdf_get_version();
377 if (!map_name || cmap_id < 0 || pdf_ver < 2)
381 * Encoding is Identity-H or Identity-V according as thier WMode value.
383 * We do not use match against the map_name since fonts (TrueType) covers
384 * characters across multiple character collection (eg, Adobe-Japan1 and
385 * Adobe-Japan2) must be splited into multiple CID-keyed fonts.
388 cmap = CMap_cache_get(cmap_id);
389 csi = (CMap_is_Identity(cmap)) ? NULL : CMap_get_CIDSysInfo(cmap) ;
391 cid_id = CIDFont_cache_find(map_name, csi, fmap_opt);
397 * The descendant CID-keyed font has already been registerd.
398 * If CID-keyed font with ID = cid_id is new font, then create new parent
399 * Type 0 font. Otherwise, there already exists parent Type 0 font and
400 * then we find him and return his ID. We must check against their WMode.
403 cidfont = CIDFont_cache_get(cid_id);
404 wmode = CMap_get_wmode(cmap);
406 /* Does CID-keyed font already have parent ? */
407 parent_id = CIDFont_get_parent_id(cidfont, wmode);
409 return parent_id; /* If so, we don't need new one. */
412 * CIDFont does not have parent or his parent's WMode does not matched with
413 * wmode. Create new Type0 font.
416 if (__cache.count >= __cache.capacity) {
417 __cache.capacity += CACHE_ALLOC_SIZE;
418 __cache.fonts = RENEW(__cache.fonts, __cache.capacity, struct Type0Font);
420 font_id = __cache.count;
421 font = &__cache.fonts[font_id];
423 Type0Font_init_font_struct(font);
426 * All CJK double-byte characters are mapped so that resulting
427 * character codes coincide with CIDs of given character collection.
428 * So, the Encoding is always Identity-H for horizontal fonts or
429 * Identity-V for vertical fonts.
432 font->encoding = NEW(strlen("Identity-V")+1, char);
433 strcpy(font->encoding, "Identity-V");
435 font->encoding = NEW(strlen("Identity-H")+1, char);
436 strcpy(font->encoding, "Identity-H");
441 * Now we start font dictionary.
443 font->fontdict = pdf_new_dict();
444 pdf_add_dict(font->fontdict, pdf_new_name ("Type"), pdf_new_name ("Font"));
445 pdf_add_dict(font->fontdict, pdf_new_name ("Subtype"), pdf_new_name ("Type0"));
448 * Type0 font does not have FontDescriptor because it is not a simple font.
449 * Instead, DescendantFonts appears here.
451 * Up to PDF version 1.5, Type0 font must have single descendant font which
452 * is a CID-keyed font. Future PDF spec. will allow multiple desecendant
455 font->descendant = cidfont;
456 CIDFont_attach_parent(cidfont, font_id, wmode);
459 * PostScript Font name:
461 * Type0 font's fontname is usually descendant CID-keyed font's font name
462 * appended by -ENCODING.
464 fontname = CIDFont_get_fontname(cidfont);
467 if (CIDFont_get_embedding(cidfont) && strlen(fontname) > 7)
468 MESG("(CID:%s)", fontname+7); /* skip XXXXXX+ */
470 MESG("(CID:%s)", fontname);
474 * The difference between CID-keyed font and TrueType font appears here.
476 * Glyph substitution for vertical writing is done in CMap mapping process
477 * for CID-keyed fonts. But we must rely on OpenType layout table in the
478 * case of TrueType fonts. So, we must use different used_chars for each
479 * horizontal and vertical fonts in that case.
481 * In most PDF file, encoding name is not appended to fontname for Type0
482 * fonts having CIDFontType 2 font as their descendant.
485 font->used_chars = NULL;
486 font->flags = FLAG_NONE;
488 switch (CIDFont_get_subtype(cidfont)) {
490 font->fontname = NEW(strlen(fontname)+strlen(font->encoding)+2, char);
491 sprintf(font->fontname, "%s-%s", fontname, font->encoding);
492 pdf_add_dict(font->fontdict,
493 pdf_new_name("BaseFont"), pdf_new_name(font->fontname));
495 * Need used_chars to write W, W2.
497 if ((parent_id = CIDFont_get_parent_id(cidfont, wmode ? 0 : 1)) < 0)
498 font->used_chars = new_used_chars2();
500 /* Don't allocate new one. */
501 font->used_chars = Type0Font_get_usedchars(Type0Font_cache_get(parent_id));
502 font->flags |= FLAG_USED_CHARS_SHARED;
509 * Use different used_chars for H and V.
511 pdf_add_dict(font->fontdict,
512 pdf_new_name("BaseFont"), pdf_new_name(fontname));
513 font->used_chars = new_used_chars2();
516 ERROR("Unrecognized CIDFont Type");
520 pdf_add_dict(font->fontdict,
521 pdf_new_name("Encoding"), pdf_new_name(font->encoding));
529 Type0Font_cache_close (void)
534 * This need to be fixed.
536 * CIDFont_cache_close() before Type0Font_release because of used_chars.
537 * ToUnicode support want descendant CIDFont's CSI and fontname.
540 for (font_id = 0; font_id < __cache.count; font_id++)
541 Type0Font_dofont(&__cache.fonts[font_id]);
543 CIDFont_cache_close();
545 for (font_id = 0; font_id < __cache.count; font_id++) {
546 Type0Font_flush(&__cache.fonts[font_id]);
547 Type0Font_clean(&__cache.fonts[font_id]);
549 RELEASE(__cache.fonts);
551 __cache.fonts = NULL;
553 __cache.capacity = 0;
557 /************************************************************************/
560 pdf_font_findfont0 (const char *font_name, int cmap_id, fontmap_opt *fmap_opt)
562 return Type0Font_cache_find(font_name, cmap_id, fmap_opt);
565 /******************************** COMPAT ********************************/
567 #ifndef WITHOUT_COMPAT
569 #include "cmap_read.h"
570 #include "cmap_write.h"
571 #include "pdfresource.h"
572 #include "pdfencoding.h"
575 create_dummy_CMap (void)
581 #define CMAP_PART0 "\
582 %!PS-Adobe-3.0 Resource-CMap\n\
583 %%DocumentNeededResources: ProcSet (CIDInit)\n\
584 %%IncludeResource: ProcSet (CIDInit)\n\
585 %%BeginResource: CMap (Adobe-Identity-UCS2)\n\
586 %%Title: (Adobe-Identity-UCS2 Adobe UCS2 0)\n\
592 #define CMAP_PART1 "\
593 /CIDInit /ProcSet findresource begin\n\
595 12 dict begin\n\nbegincmap\n\n\
596 /CIDSystemInfo 3 dict dup begin\n\
597 /Registry (Adobe) def\n\
598 /Ordering (UCS2) def\n\
601 /CMapName /Adobe-Identity-UCS2 def\n\
602 /CMapVersion 1.0 def\n\
604 2 begincodespacerange\n\
608 #define CMAP_PART3 "\
610 CMapName currentdict /CMap defineresource pop\n\n\
616 stream = pdf_new_stream(STREAM_COMPRESS);
617 pdf_add_stream(stream, CMAP_PART0, strlen(CMAP_PART0));
618 pdf_add_stream(stream, CMAP_PART1, strlen(CMAP_PART1));
619 pdf_add_stream(stream, "\n100 beginbfrange\n", strlen("\n100 beginbfrange\n"));
620 for (i = 0; i < 0x64; i++) {
622 "<%02X00> <%02XFF> <%02X00>\n", i, i, i);
623 pdf_add_stream(stream, buf, n);
625 pdf_add_stream(stream, "endbfrange\n\n", strlen("endbfrange\n\n"));
627 pdf_add_stream(stream, "\n100 beginbfrange\n", strlen("\n100 beginbfrange\n"));
628 for (i = 0x64; i < 0xc8; i++) {
630 "<%02X00> <%02XFF> <%02X00>\n", i, i, i);
631 pdf_add_stream(stream, buf, n);
633 pdf_add_stream(stream, "endbfrange\n\n", strlen("endbfrange\n\n"));
635 pdf_add_stream(stream, "\n48 beginbfrange\n", strlen("\n48 beginbfrange\n"));
636 for (i = 0xc8; i <= 0xd7; i++) {
638 "<%02X00> <%02XFF> <%02X00>\n", i, i, i);
639 pdf_add_stream(stream, buf, n);
641 for (i = 0xe0; i <= 0xff; i++) {
643 "<%02X00> <%02XFF> <%02X00>\n", i, i, i);
644 pdf_add_stream(stream, buf, n);
646 pdf_add_stream(stream, "endbfrange\n\n", strlen("endbfrange\n\n"));
648 pdf_add_stream(stream, CMAP_PART3, strlen(CMAP_PART3));
654 pdf_read_ToUnicode_file (const char *cmap_name)
661 res_id = pdf_findresource("CMap", cmap_name);
663 if (!strcmp(cmap_name, "Adobe-Identity-UCS2"))
664 stream = create_dummy_CMap();
666 stream = pdf_load_ToUnicode_stream(cmap_name);
669 res_id = pdf_defineresource("CMap",
671 stream, PDF_RES_FLUSH_IMMEDIATE);
675 return (res_id < 0 ? NULL : pdf_get_resource_reference(res_id));
677 #endif /* !WITHOUT_COMPAT */