OSDN Git Service

0882175708da78a7aa2b92bc28ac5415e47cf9d1
[putex/putex.git] / src / dvipdfmx-pu / src / type0.c
1 /*  
2     
3     This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks.
4
5     Copyright (C) 2002-2012 by Jin-Hwan Cho and Shunsaku Hirata,
6     the dvipdfmx project team.
7     
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.
12     
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.
17     
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.
21 */
22
23 /*
24  * Type0 font support:
25  * 
26  * TODO:
27  *
28  *  Composite font (multiple descendants) - not supported in PDF
29  */
30
31 #if HAVE_CONFIG_H
32 #include "config.h"
33 #endif
34
35 #include <string.h>
36
37 #include "system.h"
38 #include "mem.h"
39 #include "error.h"
40 #include "dpxfile.h"
41
42 #include "pdfobj.h"
43 #include "fontmap.h"
44
45 #include "cmap.h"
46 #include "cid.h"
47
48 #include "type0.h"
49
50
51 #define TYPE0FONT_DEBUG_STR "Type0"
52 #define TYPE0FONT_DEBUG     3
53
54 static int __verbose = 0;
55
56 static pdf_obj *pdf_read_ToUnicode_file (const char *cmap_name);
57
58 void
59 Type0Font_set_verbose(void)
60 {
61   __verbose++;
62 }
63
64 /*
65  * used_chars:
66  *
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
69  *  is_used().
70  */
71
72 static char *
73 new_used_chars2(void)
74 {
75   char *used_chars;
76
77   used_chars = NEW(8192, char);
78   memset(used_chars, 0, 8192);
79
80   return used_chars;
81 }
82
83 #define FLAG_NONE              0
84 #define FLAG_USED_CHARS_SHARED (1 << 0)
85
86 struct Type0Font {
87   char    *fontname;   /* BaseFont */
88   char    *encoding;   /* "Identity-H" or "Identity-V" (not ID) */
89   char    *used_chars; /* Used chars (CIDs) */
90
91   /*
92    * Type0 only
93    */
94   CIDFont *descendant; /* Only single descendant is allowed. */
95   int      flags;
96   int      wmode;
97
98   /*
99    * PDF Font Resource
100    */
101   pdf_obj *indirect;
102   pdf_obj *fontdict;
103   pdf_obj *descriptor; /* MUST BE NULL */
104 };
105
106 static void
107 Type0Font_init_font_struct (Type0Font *font)
108 {
109   ASSERT(font);
110
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;
118   font->wmode      = -1;
119   font->flags      = FLAG_NONE;
120
121   return;
122 }
123
124 static void
125 Type0Font_clean (Type0Font *font)
126 {
127   if (font) {
128     if (font->fontdict)
129       ERROR("%s: Object not flushed.", TYPE0FONT_DEBUG_STR);
130     if (font->indirect)
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);
136     if (font->encoding)
137       RELEASE(font->encoding);
138     if (font->fontname)
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;
146   }
147 }
148
149 /* PLEASE FIX THIS */
150 #include "tt_cmap.h"
151
152 static void
153 add_ToUnicode (Type0Font *font)
154 {
155   pdf_obj    *tounicode;
156   CIDFont    *cidfont;
157   CIDSysInfo *csi;
158   char       *cmap_name, *fontname;
159
160   /*
161    * ToUnicode CMap:
162    *
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
166    *  others.
167    */
168
169   cidfont = font->descendant;
170   if (!cidfont) {
171     ERROR("%s: No descendant CID-keyed font.", TYPE0FONT_DEBUG_STR);
172     return;
173   }
174
175   if (CIDFont_is_ACCFont(cidfont)) {
176     /* No need to embed ToUnicode */
177     return;
178   } else if (CIDFont_is_UCSFont(cidfont)) {
179     /*
180      * Old version of dvipdfmx mistakenly used Adobe-Identity as Unicode.
181      */
182     tounicode = pdf_read_ToUnicode_file("Adobe-Identity-UCS2");
183     if (!tounicode) { /* This should work */
184       tounicode = pdf_new_name("Identity-H");
185     }
186     pdf_add_dict(font->fontdict, pdf_new_name("ToUnicode"), tounicode);
187     return;
188   }
189
190   tounicode = NULL;
191   csi       = CIDFont_get_CIDSysInfo(cidfont);
192   fontname  = CIDFont_get_fontname(cidfont);
193   if (CIDFont_get_embedding(cidfont)) {
194     fontname += 7; /* FIXME */
195   }
196
197   if (!strcmp(csi->registry, "Adobe")    &&
198       !strcmp(csi->ordering, "Identity")) {
199     switch (CIDFont_get_subtype(cidfont)) {
200     case CIDFONT_TYPE2:
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));
205       break;
206     default:
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. */
213         return;
214       } else {
215         cmap_name = NEW(strlen(fontname) + 7, char);
216         sprintf(cmap_name, "%s-UTF16", fontname);
217         tounicode = pdf_read_ToUnicode_file(cmap_name);
218         if (!tounicode) {
219           sprintf(cmap_name, "%s-UCS2", fontname);
220           tounicode = pdf_read_ToUnicode_file(cmap_name);
221         }
222         RELEASE(cmap_name);
223       }
224       break;
225     }
226   } else {
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);
230     if (!tounicode) {
231       sprintf(cmap_name, "%s-%s-UCS2", csi->registry, csi->ordering);
232       tounicode = pdf_read_ToUnicode_file(cmap_name);
233     }
234     RELEASE(cmap_name);
235   }
236
237   if (tounicode) {
238     pdf_add_dict(font->fontdict,
239                  pdf_new_name("ToUnicode"), tounicode);
240   } else {
241     WARN("Failed to load ToUnicode CMap for font \"%s\"", fontname);
242   }
243
244   return;
245 }
246
247 void
248 Type0Font_set_ToUnicode (Type0Font *font, pdf_obj *cmap_ref)
249 {
250   ASSERT(font);
251
252   pdf_add_dict(font->fontdict,
253                pdf_new_name("ToUnicode"), cmap_ref);
254 }
255
256 static void
257 Type0Font_dofont (Type0Font *font)
258 {
259   if (!font || !font->indirect)
260     return;
261
262   if (!pdf_lookup_dict(font->fontdict, "ToUnicode")) { /* FIXME */
263     add_ToUnicode(font);
264   }
265 }
266
267 static void
268 Type0Font_flush (Type0Font *font)
269 {
270   if (font) {
271     if (font->fontdict)
272       pdf_release_obj(font->fontdict);
273     font->fontdict = NULL;
274     if (font->indirect)
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;
280   }
281 }
282
283 int
284 Type0Font_get_wmode (Type0Font *font)
285 {
286   ASSERT(font);
287
288   return font->wmode;
289 }
290
291 #if 0
292 char *
293 Type0Font_get_encoding (Type0Font *font)
294 {
295   ASSERT(font);
296
297   return font->encoding;
298 }
299 #endif
300
301 char *
302 Type0Font_get_usedchars (Type0Font *font)
303 {
304   ASSERT(font);
305
306   return font->used_chars;
307 }
308
309 pdf_obj *
310 Type0Font_get_resource (Type0Font *font)
311 {
312   ASSERT(font);
313
314   /*
315    * This looks somewhat strange.
316    */
317   if (!font->indirect) {
318     pdf_obj *array;
319
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);
324   }
325
326   return pdf_link_obj(font->indirect);
327 }
328
329 /******************************** CACHE ********************************/
330
331 #define CHECK_ID(n) do {\
332   if ((n) < 0 || (n) >= __cache.count)\
333     ERROR("%s: Invalid ID %d", TYPE0FONT_DEBUG_STR, (n));\
334 } while (0)
335
336 #define CACHE_ALLOC_SIZE 16u
337
338 static struct font_cache {
339   int        count;
340   int        capacity;
341   Type0Font *fonts;
342 } __cache = {
343   0, 0, NULL
344 };
345
346 void
347 Type0Font_cache_init (void)
348 {
349   if (__cache.fonts)
350     ERROR("%s: Already initialized.", TYPE0FONT_DEBUG_STR);
351   __cache.count    = 0;
352   __cache.capacity = 0;
353   __cache.fonts    = NULL;
354 }
355
356 Type0Font *
357 Type0Font_cache_get (int id)
358 {
359   CHECK_ID(id);
360
361   return &__cache.fonts[id];
362 }
363
364 int
365 Type0Font_cache_find (const char *map_name, int cmap_id, fontmap_opt *fmap_opt)
366 {
367   int         font_id = -1;
368   Type0Font  *font;
369   CIDFont    *cidfont;
370   CMap       *cmap;
371   CIDSysInfo *csi;
372   char       *fontname = NULL;
373   int         cid_id = -1, parent_id = -1, wmode = 0;
374   int         pdf_ver;
375
376   pdf_ver = pdf_get_version();
377   if (!map_name || cmap_id < 0 || pdf_ver < 2)
378     return -1;
379
380   /*
381    * Encoding is Identity-H or Identity-V according as thier WMode value.
382    * 
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.
386    */
387
388   cmap = CMap_cache_get(cmap_id);
389   csi  = (CMap_is_Identity(cmap)) ? NULL : CMap_get_CIDSysInfo(cmap) ;
390
391   cid_id = CIDFont_cache_find(map_name, csi, fmap_opt);
392
393   if (cid_id < 0) 
394     return -1;
395
396   /*
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.
401    */
402
403   cidfont = CIDFont_cache_get(cid_id);
404   wmode   = CMap_get_wmode(cmap);
405
406   /* Does CID-keyed font already have parent ? */
407   parent_id = CIDFont_get_parent_id(cidfont, wmode);
408   if (parent_id >= 0)
409     return parent_id; /* If so, we don't need new one. */
410
411   /*
412    * CIDFont does not have parent or his parent's WMode does not matched with
413    * wmode. Create new Type0 font.
414    */
415
416   if (__cache.count >= __cache.capacity) {
417     __cache.capacity += CACHE_ALLOC_SIZE;
418     __cache.fonts     = RENEW(__cache.fonts, __cache.capacity, struct Type0Font);
419   }
420   font_id =  __cache.count;
421   font    = &__cache.fonts[font_id];
422
423   Type0Font_init_font_struct(font);
424
425   /*
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.
430    */
431   if (wmode) {
432     font->encoding = NEW(strlen("Identity-V")+1, char);
433     strcpy(font->encoding, "Identity-V");
434   } else {
435     font->encoding = NEW(strlen("Identity-H")+1, char);
436     strcpy(font->encoding, "Identity-H");
437   }
438   font->wmode = wmode;
439
440   /*
441    * Now we start font dictionary.
442    */
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"));
446
447   /*
448    * Type0 font does not have FontDescriptor because it is not a simple font.
449    * Instead, DescendantFonts appears here.
450    *
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
453    * fonts.
454    */
455   font->descendant = cidfont;
456   CIDFont_attach_parent(cidfont, font_id, wmode);
457
458   /*
459    * PostScript Font name:
460    *
461    *  Type0 font's fontname is usually descendant CID-keyed font's font name 
462    *  appended by -ENCODING.
463    */
464   fontname = CIDFont_get_fontname(cidfont);
465
466   if (__verbose) {
467     if (CIDFont_get_embedding(cidfont) && strlen(fontname) > 7)
468       MESG("(CID:%s)", fontname+7); /* skip XXXXXX+ */
469     else
470       MESG("(CID:%s)", fontname);
471   }
472
473   /*
474    * The difference between CID-keyed font and TrueType font appears here.
475    *
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.
480    *
481    * In most PDF file, encoding name is not appended to fontname for Type0
482    * fonts having CIDFontType 2 font as their descendant.
483    */
484
485   font->used_chars = NULL;
486   font->flags      = FLAG_NONE;
487
488   switch (CIDFont_get_subtype(cidfont)) {
489   case CIDFONT_TYPE0:
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));
494     /*
495      * Need used_chars to write W, W2.
496      */
497     if ((parent_id = CIDFont_get_parent_id(cidfont, wmode ? 0 : 1)) < 0)
498       font->used_chars = new_used_chars2();
499     else {
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;
503     }
504     break;
505   case CIDFONT_TYPE2:
506     /*
507      * TrueType:
508      *
509      *  Use different used_chars for H and V.
510      */
511     pdf_add_dict(font->fontdict,
512                  pdf_new_name("BaseFont"), pdf_new_name(fontname));
513     font->used_chars = new_used_chars2();
514     break;
515   default:
516     ERROR("Unrecognized CIDFont Type");
517     break;
518   }
519
520   pdf_add_dict(font->fontdict,
521                pdf_new_name("Encoding"), pdf_new_name(font->encoding));
522
523   __cache.count++;
524
525   return font_id;
526 }
527
528 void
529 Type0Font_cache_close (void)
530 {
531   int   font_id;
532
533   /*
534    * This need to be fixed.
535    *
536    * CIDFont_cache_close() before Type0Font_release because of used_chars.
537    * ToUnicode support want descendant CIDFont's CSI and fontname.
538    */
539   if (__cache.fonts) {
540     for (font_id = 0; font_id < __cache.count; font_id++)
541       Type0Font_dofont(&__cache.fonts[font_id]);
542   }
543   CIDFont_cache_close();
544   if (__cache.fonts) {
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]);
548     }
549     RELEASE(__cache.fonts);
550   }
551   __cache.fonts    = NULL;
552   __cache.count    = 0;
553   __cache.capacity = 0;
554 }
555
556
557 /************************************************************************/
558
559 int
560 pdf_font_findfont0 (const char *font_name, int cmap_id, fontmap_opt *fmap_opt)
561 {
562   return Type0Font_cache_find(font_name, cmap_id, fmap_opt);
563 }
564
565 /******************************** COMPAT ********************************/
566
567 #ifndef WITHOUT_COMPAT
568
569 #include "cmap_read.h"
570 #include "cmap_write.h"
571 #include "pdfresource.h"
572 #include "pdfencoding.h"
573
574 static pdf_obj *
575 create_dummy_CMap (void)
576 {
577   pdf_obj *stream;
578   char     buf[32];
579   int      i, n;
580
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\
587 %%Version: 1.0\n\
588 %%Copyright:\n\
589 %% ---\n\
590 %%EndComments\n\n\
591 "
592 #define CMAP_PART1 "\
593 /CIDInit /ProcSet findresource begin\n\
594 \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\
599   /Supplement 0 def\n\
600 end def\n\n\
601 /CMapName /Adobe-Identity-UCS2 def\n\
602 /CMapVersion 1.0 def\n\
603 /CMapType 2 def\n\n\
604 2 begincodespacerange\n\
605 <0000> <FFFF>\n\
606 endcodespacerange\n\
607 "
608 #define CMAP_PART3 "\
609 endcmap\n\n\
610 CMapName currentdict /CMap defineresource pop\n\n\
611 end\nend\n\n\
612 %%EndResource\n\
613 %%EOF\n\
614 "
615
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++) {
621     n = sprintf(buf,
622                 "<%02X00> <%02XFF> <%02X00>\n", i, i, i);
623     pdf_add_stream(stream, buf, n);
624   }
625   pdf_add_stream(stream, "endbfrange\n\n", strlen("endbfrange\n\n"));
626
627   pdf_add_stream(stream, "\n100 beginbfrange\n", strlen("\n100 beginbfrange\n"));
628   for (i = 0x64; i < 0xc8; i++) {
629     n = sprintf(buf,
630                 "<%02X00> <%02XFF> <%02X00>\n", i, i, i);
631     pdf_add_stream(stream, buf, n);
632   }
633   pdf_add_stream(stream, "endbfrange\n\n", strlen("endbfrange\n\n"));
634
635   pdf_add_stream(stream, "\n48 beginbfrange\n", strlen("\n48 beginbfrange\n"));
636   for (i = 0xc8; i <= 0xd7; i++) {
637     n = sprintf(buf,
638                 "<%02X00> <%02XFF> <%02X00>\n", i, i, i);
639     pdf_add_stream(stream, buf, n);
640   }
641   for (i = 0xe0; i <= 0xff; i++) {
642     n = sprintf(buf,
643                 "<%02X00> <%02XFF> <%02X00>\n", i, i, i);
644     pdf_add_stream(stream, buf, n);
645   }
646   pdf_add_stream(stream, "endbfrange\n\n", strlen("endbfrange\n\n"));
647
648   pdf_add_stream(stream, CMAP_PART3, strlen(CMAP_PART3));
649
650   return  stream;
651 }
652
653 static pdf_obj *
654 pdf_read_ToUnicode_file (const char *cmap_name)
655 {
656   pdf_obj *stream;
657   long     res_id = -1;
658
659   ASSERT(cmap_name);
660
661   res_id = pdf_findresource("CMap", cmap_name);
662   if (res_id < 0) {
663     if (!strcmp(cmap_name, "Adobe-Identity-UCS2"))
664       stream = create_dummy_CMap();
665     else {
666       stream = pdf_load_ToUnicode_stream(cmap_name);
667     }
668     if (stream) {
669       res_id   = pdf_defineresource("CMap",
670                                     cmap_name,
671                                     stream, PDF_RES_FLUSH_IMMEDIATE);
672     }
673   }
674
675   return  (res_id < 0 ? NULL : pdf_get_resource_reference(res_id));
676 }
677 #endif /* !WITHOUT_COMPAT */