~ubuntu-branches/debian/experimental/cups-filters/experimental

« back to all changes in this revision

Viewing changes to filter/pdf.cxx

  • Committer: Package Import Robot
  • Author(s): Didier Raboud
  • Date: 2015-01-15 18:06:05 UTC
  • mfrom: (1.2.25)
  • mto: This revision was merged to the branch mainline in revision 39.
  • Revision ID: package-import@ubuntu.com-20150115180605-fnfbqv85k3y5zggk
Tags: upstream-1.0.62
ImportĀ upstreamĀ versionĀ 1.0.62

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
2
 * Copyright 2012 Canonical Ltd.
 
3
 * Copyright 2013 ALT Linux, Andrew V. Stepanov <stanv@altlinux.com>
3
4
 *
4
5
 * This program is free software: you can redistribute it and/or modify it
5
6
 * under the terms of the GNU General Public License version 3, as published
17
18
#include "pdf.h"
18
19
 
19
20
#include <PDFDoc.h>
20
 
 
 
21
#include <GlobalParams.h>
 
22
#include <Form.h>
 
23
#include <Gfx.h>
 
24
#include <GfxFont.h>
 
25
#include <Page.h>
 
26
#include <PDFDocEncoding.h>
 
27
#include <config.h>
 
28
#ifdef HAVE_CPP_POPPLER_VERSION_H
 
29
#include "cpp/poppler-version.h"
 
30
#endif
 
31
 
 
32
extern "C" {
 
33
#include <embed.h>
 
34
#include <sfnt.h>
 
35
}
 
36
 
 
37
#include <fontconfig/fontconfig.h>
 
38
 
 
39
/*
 
40
 * Useful reference:
 
41
 *
 
42
 * http://www.gnupdf.org/Indirect_Object
 
43
 * http://www.gnupdf.org/Introduction_to_PDF
 
44
 * http://blog.idrsolutions.com/2011/05/understanding-the-pdf-file-format-%E2%80%93-pdf-xref-tables-explained
 
45
 * http://labs.appligent.com/pdfblog/pdf-hello-world/
 
46
*/
 
47
 
 
48
static EMB_PARAMS *get_font(const char *font);
 
49
 
 
50
static const char *emb_pdf_escape_name(const char *name, int len);
 
51
 
 
52
static int utf8_to_utf16(const char *utf8, unsigned short **out_ptr);
 
53
 
 
54
static const char* get_next_wide(const char *utf8, int *unicode_out);
 
55
 
 
56
extern "C" {
 
57
    static int pdf_embed_font(
 
58
            pdf_t *doc,
 
59
            Page *page,
 
60
            const char *typeface);
 
61
}
 
62
 
 
63
static void fill_font_stream(
 
64
        const char *buf,
 
65
        int len,
 
66
        void *context);
 
67
 
 
68
static Object *make_fontdescriptor_dic(pdf_t *doc,
 
69
        EMB_PARAMS *emb,
 
70
        EMB_PDF_FONTDESCR *fdes,
 
71
        Ref fontfile_obj_ref);
 
72
 
 
73
static Object *make_font_dic(pdf_t *doc,
 
74
        EMB_PARAMS *emb,
 
75
        EMB_PDF_FONTDESCR *fdes,
 
76
        EMB_PDF_FONTWIDTHS *fwid,
 
77
        Ref fontdescriptor_obj_ref);
 
78
 
 
79
static Object *make_cidfont_dic(pdf_t *doc,
 
80
        EMB_PARAMS *emb,
 
81
        const char *fontname,
 
82
        Ref fontdescriptor_obj_ref);
 
83
 
 
84
/* Font to use to fill form */
 
85
static EMB_PARAMS *Font;
21
86
 
22
87
extern "C" pdf_t * pdf_load_template(const char *filename)
23
88
{
 
89
    /* Init poppler */
 
90
    globalParams = new GlobalParams();
 
91
 
24
92
    PDFDoc *doc = new PDFDoc(new GooString(filename));
25
93
 
26
94
    if (!doc->isOk()) {
33
101
 
34
102
    if (doc->getNumPages() != 1) {
35
103
        fprintf(stderr,
36
 
                "Error: template documents must contain exactly one page\n",
 
104
                "Error: PDF template must contain exactly 1 page: %s\n",
37
105
                filename);
38
106
        delete doc;
39
107
        return NULL;
110
178
    return o;
111
179
}
112
180
 
 
181
/*
 
182
 * Create new PDF integer type object.
 
183
 */
 
184
static Object * int_object(int i)
 
185
{
 
186
    Object *o = new Object();
 
187
    o->initInt(i);
 
188
    return o;
 
189
}
113
190
 
114
191
static Object * get_resource_dict(XRef *xref,
115
192
                                  Dict *pagedict,
167
244
    font.dictSet("BaseFont", name_object(name));
168
245
    xref->addIndirectObject(&font);
169
246
 
170
 
    resdict.dictLookup("Font", &fonts);
 
247
    resdict.dictLookupNF("Font", &fonts);
171
248
    if (fonts.isNull()) {
 
249
        /* Create new font dic obj in page's resources */
172
250
        fonts.initDict(xref);
173
251
        resdict.dictSet("Font", &fonts);
174
252
    }
175
 
    fonts.dictSet("bannertopdf-font", &font);
 
253
 
 
254
    Object *fonts_dic;
 
255
    Object dereferenced_obj;
 
256
 
 
257
    if ( fonts.isDict() ) {
 
258
        /* "Font" resource is dictionary object */
 
259
        fonts_dic = &fonts;
 
260
    } else if ( fonts.isRef() ) {
 
261
        /* "Font" resource is indirect reference object */
 
262
        xref->fetch(fonts.getRefNum(), fonts.getRefGen(), &dereferenced_obj);
 
263
        fonts_dic = &dereferenced_obj;
 
264
    }
 
265
 
 
266
    if ( ! fonts_dic->isDict() ) {
 
267
        fprintf(stderr, "Can't recognize Font resource in PDF template.\n");
 
268
        return;
 
269
    }
 
270
 
 
271
    /* Add new entry to "Font" resource */
 
272
    fonts_dic->dictSet("bannertopdf-font", &font);
 
273
 
 
274
    /* Notify poppler about changes */
 
275
    if ( fonts.isRef() ) {
 
276
        xref->setModifiedObject(fonts_dic, fonts.getRef());
 
277
    }
176
278
 
177
279
    if (resref.num == 0)
178
280
        xref->setModifiedObject(&pageobj, *pageref);
184
286
 
185
287
 
186
288
static bool dict_lookup_rect(Object *dict,
187
 
                             char *key,
 
289
                             const char *key,
188
290
                             float rect[4])
189
291
{
190
292
    Object o;
214
316
 
215
317
static void dict_set_rect(XRef *xref,
216
318
                          Object *dict,
217
 
                          char *key,
 
319
                          const char *key,
218
320
                          float rect[4])
219
321
{
220
322
    Object array;
343
445
    {
344
446
    }
345
447
 
 
448
#if POPPLER_VERSION_MAJOR > 0 || POPPLER_VERSION_MINOR >= 23
 
449
    Goffset getPos()
 
450
#else
346
451
    int getPos()
 
452
#endif
347
453
    {
348
454
        return this->pos;
349
455
    }
375
481
    doc->saveAs(&outs, writeForceRewrite);
376
482
}
377
483
 
 
484
/*
 
485
 * Get value according to key.
 
486
 */
 
487
const char *lookup_opt(opt_t *opt, const char *key) {
 
488
    if ( ! opt || ! key ) {
 
489
        return NULL;
 
490
    }
 
491
 
 
492
    while (opt) {
 
493
        if (opt->key && opt->val) {
 
494
            if ( strcmp(opt->key, key) == 0 ) {
 
495
                return opt->val;
 
496
            }
 
497
        }
 
498
        opt = opt->next;
 
499
    }
 
500
 
 
501
    return NULL;
 
502
}
 
503
 
 
504
/*
 
505
 * 1. Lookup in PDF template file for form.
 
506
 * 2. Lookup for form fields' names.
 
507
 * 3. Fill recognized fields with information.
 
508
 */
 
509
extern "C" int pdf_fill_form(pdf_t *doc, opt_t *opt)
 
510
{
 
511
    XRef *xref = doc->getXRef();
 
512
    Catalog *catalog = doc->getCatalog();
 
513
    Catalog::FormType form_type = catalog->getFormType();
 
514
    if ( form_type == Catalog::NoForm ) {
 
515
        fprintf(stderr, "PDF template file doesn't have form. It's okay.\n");
 
516
        return 0;
 
517
    }
 
518
 
 
519
    Page *page = catalog->getPage(1);
 
520
    if ( !page ) {
 
521
        fprintf(stderr, "Can't get page from PDF tamplate file.\n");
 
522
        return 0;
 
523
    }
 
524
    Object pageobj;
 
525
    Ref pageref = page->getRef();
 
526
    xref->fetch(pageref.num, pageref.gen, &pageobj);
 
527
 
 
528
    const char *font_size = lookup_opt(opt, "banner-font-size");
 
529
    if ( ! font_size ) {
 
530
        /* Font size isn't specified use next one. */
 
531
        font_size = "14";
 
532
    }
 
533
 
 
534
    /* Embed font into PDF */
 
535
    const char *font = lookup_opt(opt, "banner-font");
 
536
    if ( ! font ) {
 
537
        /* Font isn't specified use next one. */
 
538
        font = "FreeMono";
 
539
    }
 
540
    int res = pdf_embed_font(doc, page, font);
 
541
    if ( ! res ) {
 
542
        fprintf(stderr, "Can't integrate %s font into PDF file.\n", font);
 
543
        return 0;
 
544
    }
 
545
 
 
546
    /* Page's resources dictionary */
 
547
    Object resdict;
 
548
    Ref resref;
 
549
    Object *ret = get_resource_dict(xref, pageobj.getDict(), &resdict, &resref);
 
550
 
 
551
    FormPageWidgets *widgets = page->getFormWidgets();
 
552
    if ( !widgets ) {
 
553
        fprintf(stderr, "Can't get page's widgets.\n");
 
554
        return 0;
 
555
    }
 
556
    int num_widgets = widgets->getNumWidgets();
 
557
 
 
558
    /* Go through widgets and fill them as necessary */
 
559
    for (int i=0; i < num_widgets; ++i)
 
560
    {
 
561
        FormWidget *fm = widgets->getWidget(i);
 
562
 
 
563
        /* Take into consideration only Text widgets */
 
564
        if ( fm->getType() != formText ) {
 
565
            continue;
 
566
        }
 
567
 
 
568
        FormWidgetText *fm_text = static_cast<FormWidgetText*>(fm);
 
569
 
 
570
        /* Ignore R/O widget */
 
571
        if ( fm_text->isReadOnly() ) {
 
572
            continue;
 
573
        }
 
574
 
 
575
        FormField *ff = fm_text->getField();
 
576
        GooString *field_name;
 
577
        field_name = ff->getFullyQualifiedName();
 
578
        if ( ! field_name )
 
579
            field_name = ff->getPartialName();
 
580
        if ( ! field_name ) {
 
581
            fprintf(stderr, "Ignore widget #%d (unknown name)\n", i);
 
582
            continue;
 
583
        }
 
584
 
 
585
        const char *name = field_name->getCString();
 
586
        const char *fill_with = lookup_opt(opt, name);
 
587
        if ( ! fill_with ) {
 
588
            fprintf(stderr, "Lack information for widget: %s.\n", name);
 
589
            fill_with = "N/A";
 
590
        }
 
591
 
 
592
        fprintf(stderr, "Fill widget name %s with value %s.\n", name, fill_with);
 
593
 
 
594
        unsigned short *fill_with_w;
 
595
        int len = utf8_to_utf16(fill_with, &fill_with_w);
 
596
        if ( !len ) {
 
597
            fprintf(stderr, "Bad data for widget: %s.\n", name);
 
598
            continue;
 
599
        }
 
600
 
 
601
        GooString *content = new GooString((char*)fill_with_w, len);
 
602
        fm_text->setContent(content);
 
603
 
 
604
        /* Object for form field */
 
605
        Object *field_obj = ff->getObj();
 
606
        Ref field_ref = ff->getRef();
 
607
 
 
608
        /* Construct appearance object in form of: "/stanv_font 12 Tf" */
 
609
        GooString *appearance = new GooString();
 
610
        appearance->append("/stanv_font ");
 
611
        appearance->append(font_size);
 
612
        appearance->append(" Tf");
 
613
 
 
614
        /* Modify field's appearance */
 
615
        Object appearance_obj;
 
616
        appearance_obj.initString(appearance);
 
617
        field_obj->getDict()->set("DA", &appearance_obj);
 
618
 
 
619
        /*
 
620
         * Create /AP - entry stuff.
 
621
         * This is right way to display characters other then Latin1
 
622
         */
 
623
 
 
624
        /* UTF8 '/0' ending string */
 
625
        const char *ptr_text = fill_with;
 
626
 
 
627
        GooString *ap_text = new GooString("<");
 
628
        while ( *ptr_text ) {
 
629
            int unicode;
 
630
            /* Get next character in Unicode */
 
631
            ptr_text = get_next_wide(ptr_text, &unicode);
 
632
            const unsigned short gid = emb_get(Font, unicode);
 
633
            char text[5];
 
634
            memset(text, 0, sizeof(text));
 
635
            sprintf(text,"%04x", gid);
 
636
            ap_text->append(text, 4);
 
637
        }
 
638
        ap_text->append("> Tj\n");
 
639
 
 
640
        /* Create empty string for stream */
 
641
        GooString *appearance_stream = new GooString();
 
642
 
 
643
        /* Orde has matter */
 
644
        appearance_stream->append("/Tx BMC \n");
 
645
        appearance_stream->append("BT\n");      // Begin text object
 
646
        appearance_stream->append("/stanv_font ");
 
647
        appearance_stream->append(font_size);
 
648
        appearance_stream->append(" Tf\n");
 
649
        appearance_stream->append("2 12.763 Td\n");
 
650
        appearance_stream->append(ap_text);
 
651
        appearance_stream->append("ET\n");
 
652
        appearance_stream->append("EMC\n");
 
653
 
 
654
        Object appearance_stream_dic;
 
655
        appearance_stream_dic.initDict(xref);
 
656
 
 
657
        /*
 
658
         * Appearance stream dic.
 
659
         * See: 4.9 Form XObjects
 
660
         * TABLE 4.41 Additional entries specific to a type 1 form dictionary
 
661
         */
 
662
        appearance_stream_dic.dictSet("Type", name_object("XObject"));
 
663
        appearance_stream_dic.dictSet("Subtype", name_object("Form"));
 
664
        appearance_stream_dic.dictSet("FormType", int_object(1));
 
665
        Object obj_ref_x;
 
666
        obj_ref_x.initRef(resref.num, resref.gen);
 
667
        appearance_stream_dic.dictSet("Resources", &obj_ref_x);
 
668
 
 
669
        /* BBox array: TODO. currently out of the head. */
 
670
        Object array;
 
671
        array.initArray(xref);
 
672
        Object el;
 
673
        el.initReal(0);
 
674
        array.arrayAdd(&el);
 
675
        el.initReal(0);
 
676
        array.arrayAdd(&el);
 
677
        el.initReal(237);
 
678
        array.arrayAdd(&el);
 
679
        el.initReal(25);
 
680
        array.arrayAdd(&el);
 
681
        appearance_stream_dic.dictSet("BBox", &array);
 
682
        appearance_stream_dic.dictSet("Length", int_object(appearance_stream->getLength()));
 
683
 
 
684
        MemStream *mem_stream = new MemStream(appearance_stream->getCString(),
 
685
                0, appearance_stream->getLength(), &appearance_stream_dic);
 
686
 
 
687
        /* Make obj stream */
 
688
        Object stream;
 
689
        stream.initStream(mem_stream);
 
690
 
 
691
        Ref r;
 
692
        r = xref->addIndirectObject(&stream);
 
693
 
 
694
        /* Update Xref table */
 
695
        Object obj_ref;
 
696
        obj_ref.initRef(r.num, r.gen);
 
697
 
 
698
        /* 
 
699
         * Fill Annotation's appearance streams dic /AP
 
700
         * See: 8.4.4 Appearance Streams
 
701
         */
 
702
        Object appearance_streams_dic;
 
703
        appearance_streams_dic.initDict(xref);
 
704
        appearance_streams_dic.dictSet("N", &obj_ref);
 
705
 
 
706
        field_obj->getDict()->set("AP", &appearance_streams_dic);
 
707
 
 
708
        /* Notify poppler about changes */
 
709
        xref->setModifiedObject(field_obj, field_ref);
 
710
    }
 
711
 
 
712
    /*
 
713
     * Adjust form's NeedAppearances flag.
 
714
     * We need to fill form's fields with specified font.
 
715
     * The right way to this is via /AP.
 
716
     *
 
717
     * false - is default value for PDF. See:
 
718
     * PDFReference.pdf - table 8.47 Entries in the interactive form dictionary
 
719
     *
 
720
     * OpenOffice - by default sets it to 'true'.
 
721
     */
 
722
    Object *obj_form = catalog->getAcroForm();
 
723
    Object obj1;
 
724
    obj1.initBool(gFalse);
 
725
    obj_form->dictSet("NeedAppearances", &obj1);
 
726
    /* Add AccroForm as indirect obj */
 
727
    Ref ref_form = xref->addIndirectObject(obj_form);
 
728
 
 
729
    /*
 
730
     * So update Catalog object.
 
731
     */
 
732
    Object* catObj = new Object();
 
733
    catObj = xref->getCatalog(catObj);
 
734
    Ref catRef;
 
735
    catRef.gen = xref->getRootGen();
 
736
    catRef.num = xref->getRootNum();
 
737
    Object obj2;
 
738
    obj2.initRef(ref_form.num, ref_form.gen);
 
739
    catObj->dictSet("AcroForm", &obj2);
 
740
    xref->setModifiedObject(catObj, catRef);
 
741
 
 
742
    /* Success */
 
743
    return 1;
 
744
}
 
745
 
 
746
/* Embeded font into PDF */
 
747
static int pdf_embed_font(pdf_t *doc,
 
748
        Page *page,
 
749
        const char *typeface) {
 
750
 
 
751
    /* Load font using libfontconfig */
 
752
    Font = get_font(typeface);
 
753
    if ( ! Font ) {
 
754
        fprintf(stderr, "Can't load font: %s\n", typeface);
 
755
        return 0;
 
756
    }
 
757
 
 
758
    /* Font's description */
 
759
    EMB_PDF_FONTDESCR *Fdes = emb_pdf_fontdescr(Font);
 
760
    if ( ! Fdes ) {
 
761
        return 0;
 
762
    }
 
763
 
 
764
    /* Font's widths description */
 
765
    EMB_PDF_FONTWIDTHS *Fwid=emb_pdf_fontwidths(Font);
 
766
    if ( ! Fwid ) {
 
767
        return 0;
 
768
    }
 
769
 
 
770
    /* Create empty string for stream */
 
771
    GooString *font_stream = new GooString();
 
772
 
 
773
    /* Fill stream */
 
774
    const int outlen = emb_embed(Font, fill_font_stream, font_stream);
 
775
    assert( font_stream->getLength() == outlen );
 
776
 
 
777
    /* Get XREF table */
 
778
    XRef *xref = doc->getXRef();
 
779
 
 
780
    /* Font dictionary object for embeded font */
 
781
    Object f_dic;
 
782
    f_dic.initDict(xref);
 
783
    f_dic.dictSet("Type", name_object("Font"));
 
784
 
 
785
    /* Stream lenght */
 
786
    f_dic.dictSet("Length", int_object(outlen));
 
787
 
 
788
    /* Lenght for EMB_FMT_TTF font type */
 
789
    if ( Font->outtype == EMB_FMT_TTF ) {
 
790
        f_dic.dictSet("Length1", int_object(outlen));
 
791
    }
 
792
 
 
793
    /* Add font subtype */
 
794
    const char *subtype = emb_pdf_get_fontfile_subtype(Font);
 
795
    if ( subtype ) {
 
796
        f_dic.dictSet("Subtype", name_object(copyString(subtype)));
 
797
    }
 
798
 
 
799
    /* Create memory stream font. Add it to font dic. */
 
800
    MemStream *mem_stream = new MemStream(font_stream->getCString(),
 
801
            0, outlen, &f_dic);
 
802
 
 
803
    /* Make obj stream */
 
804
    Object stream;
 
805
    stream.initStream(mem_stream);
 
806
 
 
807
    Ref r;
 
808
 
 
809
    /* Update Xref table */
 
810
    r = xref->addIndirectObject(&stream);
 
811
 
 
812
    /* Get page object */
 
813
    Object pageobj;
 
814
    Ref pageref = page->getRef();
 
815
    xref->fetch(pageref.num, pageref.gen, &pageobj);
 
816
    if (!pageobj.isDict()) {
 
817
        fprintf(stderr, "Error: malformed pdf.\n");
 
818
        return 0;
 
819
    }
 
820
 
 
821
    /* Page's resources dictionary */
 
822
    Object resdict;
 
823
    Ref resref;
 
824
    Object *ret = get_resource_dict(xref, pageobj.getDict(), &resdict, &resref);
 
825
    if ( !ret ) {
 
826
        fprintf(stderr, "Error: malformed pdf\n");
 
827
        pageobj.free();
 
828
        return 0;
 
829
    }
 
830
 
 
831
    /* Dictionary for all fonts in page's resources */
 
832
    Object fonts;
 
833
 
 
834
    resdict.dictLookupNF("Font", &fonts);
 
835
    if (fonts.isNull()) {
 
836
        /* Create new one, if doesn't exists */
 
837
        fonts.initDict(xref);
 
838
        resdict.dictSet("Font", &fonts);
 
839
        fprintf(stderr, "Create new font dict in page's resources.\n");
 
840
    }
 
841
 
 
842
    /*
 
843
     * For embeded font there are 4 inderect objects and 4 reference obj.
 
844
     * Each next point to previsious one.
 
845
     * Last one object goes to Font dic.
 
846
     *
 
847
     * 1. Font stream obj + reference obj
 
848
     * 2. FontDescriptor obj + reference obj
 
849
     * 3. Width resource obj + reference obj
 
850
     * 4. Multibyte resourcse obj + reference obj
 
851
     *
 
852
     */
 
853
 
 
854
    /* r - indirect object refrence to dict with stream */
 
855
    Object *font_desc_resource_dic = make_fontdescriptor_dic(doc, Font, Fdes, r);
 
856
    r = xref->addIndirectObject(font_desc_resource_dic);
 
857
 
 
858
    /* r - indirect object reference to dict font descriptor resource */
 
859
    Object *font_resource_dic = make_font_dic(doc, Font, Fdes, Fwid, r);
 
860
    r = xref->addIndirectObject(font_resource_dic);
 
861
 
 
862
    /* r - widths resource dic */
 
863
    Object *cidfont_resource_dic = make_cidfont_dic(doc, Font, Fdes->fontname, r);
 
864
    r = xref->addIndirectObject(cidfont_resource_dic);
 
865
 
 
866
    /* r - cid resource dic */
 
867
    Object font_res_obj_ref;
 
868
    font_res_obj_ref.initRef(r.num, r.gen);
 
869
 
 
870
    Object *fonts_dic;
 
871
    Object dereferenced_obj;
 
872
 
 
873
    if ( fonts.isDict() ) {
 
874
        /* "Font" resource is dictionary object */
 
875
        fonts_dic = &fonts;
 
876
    } else if ( fonts.isRef() ) {
 
877
        /* "Font" resource is indirect reference object */
 
878
        xref->fetch(fonts.getRefNum(), fonts.getRefGen(), &dereferenced_obj);
 
879
        fonts_dic = &dereferenced_obj;
 
880
    }
 
881
 
 
882
    if ( ! fonts_dic->isDict() ) {
 
883
        fprintf(stderr, "Can't recognize Font resource in PDF template.\n");
 
884
        return 0;
 
885
    }
 
886
 
 
887
    /* Add to fonts dic new font */
 
888
    fonts_dic->dictSet("stanv_font", &font_res_obj_ref);
 
889
 
 
890
    /* Notify poppler about changes in fonts dic */
 
891
    if ( fonts.isRef() ) {
 
892
        xref->setModifiedObject(fonts_dic, fonts.getRef());
 
893
    }
 
894
 
 
895
    /* Notify poppler about changes in resources dic */
 
896
    xref->setModifiedObject(&resdict, resref);
 
897
    fprintf(stderr, "Resource dict was changed.\n");
 
898
 
 
899
    pageobj.free();
 
900
 
 
901
    /* Success */
 
902
    return 1;
 
903
}
 
904
 
 
905
/*
 
906
 * Call-back function to fill font stream object.
 
907
 */
 
908
static void fill_font_stream(const char *buf, int len, void *context)
 
909
{
 
910
    GooString *s = (GooString *)context;
 
911
    s->append(buf, len);
 
912
}
 
913
 
 
914
/*
 
915
 * Use libfontconfig to pick up suitable font.
 
916
 * Memory should be freed.
 
917
 * XXX: doesn't work correctly. Need to do some revise.
 
918
 */
 
919
static char *get_font_libfontconfig(const char *font) {
 
920
    FcPattern *pattern = NULL;
 
921
    FcFontSet *candidates = NULL;
 
922
    FcChar8* found_font = NULL;
 
923
    FcResult result;
 
924
 
 
925
    FcInit ();
 
926
    pattern = FcNameParse ((const FcChar8 *)font);
 
927
 
 
928
    /* guide fc, in case substitution becomes necessary */
 
929
    FcPatternAddInteger (pattern, FC_SPACING, FC_MONO);
 
930
    FcConfigSubstitute (0, pattern, FcMatchPattern);
 
931
    FcDefaultSubstitute (pattern);
 
932
 
 
933
    /* Receive a sorted list of fonts matching our pattern */
 
934
    candidates = FcFontSort (0, pattern, FcFalse, 0, &result);
 
935
    FcPatternDestroy (pattern);
 
936
 
 
937
    /* In the list of fonts returned by FcFontSort()
 
938
       find the first one that is both in TrueType format and monospaced */
 
939
    for (int i = 0; i < candidates->nfont; i++) {
 
940
 
 
941
        /* TODO? or just try? */
 
942
        FcChar8 *fontformat=NULL;
 
943
 
 
944
        /* sane default, as FC_MONO == 100 */
 
945
        int spacing=0;
 
946
        FcPatternGetString(
 
947
                candidates->fonts[i],
 
948
                FC_FONTFORMAT,
 
949
                0,
 
950
                &fontformat);
 
951
 
 
952
        FcPatternGetInteger(
 
953
                candidates->fonts[i],
 
954
                FC_SPACING,
 
955
                0,
 
956
                &spacing);
 
957
 
 
958
        if ( (fontformat) && (spacing == FC_MONO) ) {
 
959
            if (strcmp((const char *)fontformat, "TrueType") == 0) {
 
960
                found_font = FcPatternFormat (
 
961
                        candidates->fonts[i],
 
962
                        (const FcChar8 *)"%{file|cescape}/%{index}");
 
963
 
 
964
                /* Don't take into consideration remain candidates */
 
965
                break;
 
966
            } else if (strcmp((const char *)fontformat, "CFF") == 0) {
 
967
 
 
968
                /* TTC only possible with non-cff glyphs! */
 
969
                found_font = FcPatternFormat (
 
970
                        candidates->fonts[i],
 
971
                        (const FcChar8 *)"%{file|cescape}");
 
972
 
 
973
                /* Don't take into consideration remain candidates */
 
974
                break;
 
975
            }
 
976
        }
 
977
    }
 
978
 
 
979
    FcFontSetDestroy (candidates);
 
980
 
 
981
    if ( ! found_font ) {
 
982
        fprintf(stderr,"No viable font found\n");
 
983
        return NULL;
 
984
    }
 
985
 
 
986
    return (char *)found_font;
 
987
}
 
988
 
 
989
/*
 
990
 * Load font file using fontembed file.
 
991
 * Test for requirements.
 
992
 */
 
993
static EMB_PARAMS *load_font(const char *font) {
 
994
    assert(font);
 
995
 
 
996
    OTF_FILE *otf;
 
997
    otf = otf_load(font);
 
998
    if ( ! otf ) {
 
999
        return NULL;
 
1000
    }
 
1001
 
 
1002
    FONTFILE *ff=fontfile_open_sfnt(otf);
 
1003
    if ( ! ff ) {
 
1004
        return NULL;
 
1005
    }
 
1006
 
 
1007
    EMB_PARAMS *emb=emb_new(ff,
 
1008
            EMB_DEST_PDF16,
 
1009
            static_cast<EMB_CONSTRAINTS>( /* bad fontembed */
 
1010
                EMB_C_FORCE_MULTIBYTE|
 
1011
                EMB_C_TAKE_FONTFILE|
 
1012
                EMB_C_NEVER_SUBSET));
 
1013
    if ( ! emb ) {
 
1014
        return NULL;
 
1015
    }
 
1016
 
 
1017
    if ( ! (emb->plan & EMB_A_MULTIBYTE) ) {
 
1018
        return NULL;
 
1019
    }
 
1020
 
 
1021
    EMB_PDF_FONTDESCR *fdes=emb_pdf_fontdescr(emb);
 
1022
    if ( ! fdes ) {
 
1023
        return NULL;
 
1024
    }
 
1025
 
 
1026
    /* Success */
 
1027
    return emb;
 
1028
}
 
1029
 
 
1030
/*
 
1031
 * Return fontembed library object that corresponds requirements.
 
1032
 */
 
1033
static EMB_PARAMS *get_font(const char *font)
 
1034
{
 
1035
    assert(font);
 
1036
 
 
1037
    char *fontname = NULL;
 
1038
    EMB_PARAMS *emb = NULL;
 
1039
 
 
1040
    /* Font file specified. */
 
1041
    if ( (font[0]=='/') || (font[0]=='.') ) {
 
1042
        fontname = strdup(font);
 
1043
        emb = load_font(fontname);
 
1044
    }
 
1045
 
 
1046
    /* Use libfontconfig. */
 
1047
    if ( ! emb ) {
 
1048
        fontname = get_font_libfontconfig(font);
 
1049
        emb = load_font(fontname);
 
1050
    }
 
1051
 
 
1052
    free(fontname);
 
1053
 
 
1054
    return emb;
 
1055
}
 
1056
 
 
1057
/*
 
1058
 * Was taken from ./fontembed/embed_pdf.c
 
1059
 */
 
1060
static const char *emb_pdf_escape_name(const char *name, int len)
 
1061
{
 
1062
    assert(name);
 
1063
    if (len==-1) {
 
1064
        len=strlen(name);
 
1065
    }
 
1066
 
 
1067
    /* PDF implementation limit */
 
1068
    assert(len<=127);
 
1069
 
 
1070
    static char buf[128*3];
 
1071
    int iA,iB;
 
1072
    const char hex[]="0123456789abcdef";
 
1073
 
 
1074
    for (iA=0,iB=0;iA<len;iA++,iB++) {
 
1075
        if ( ((unsigned char)name[iA]<33)||((unsigned char)name[iA]>126)||
 
1076
                (strchr("#()<>[]{}/%",name[iA])) ) {
 
1077
            buf[iB]='#';
 
1078
            buf[++iB]=hex[(name[iA]>>4)&0x0f];
 
1079
            buf[++iB]=hex[name[iA]&0xf];
 
1080
        } else {
 
1081
            buf[iB]=name[iA];
 
1082
        }
 
1083
    }
 
1084
    buf[iB]=0;
 
1085
    return buf;
 
1086
}
 
1087
 
 
1088
/*
 
1089
 * Construct font description dictionary.
 
1090
 * Translated to Poppler function emb_pdf_simple_fontdescr() from
 
1091
 * cups-filters/fontembed/embed_pdf.c
 
1092
 */
 
1093
static Object *make_fontdescriptor_dic(
 
1094
        pdf_t *doc,
 
1095
        EMB_PARAMS *emb,
 
1096
        EMB_PDF_FONTDESCR *fdes,
 
1097
        Ref fontfile_obj_ref)
 
1098
{
 
1099
    assert(emb);
 
1100
    assert(fdes);
 
1101
 
 
1102
    /* Get XREF table */
 
1103
    XRef *xref = doc->getXRef();
 
1104
 
 
1105
    /* Font dictionary for embeded font */
 
1106
    Object *dic = new Object();
 
1107
    dic->initDict(xref);
 
1108
 
 
1109
    dic->dictSet("Type", name_object("FontDescriptor"));
 
1110
    dic->dictSet(
 
1111
            "FontName",
 
1112
            name_object(copyString(emb_pdf_escape_name(fdes->fontname,-1))));
 
1113
    dic->dictSet("Flags", int_object(fdes->flags));
 
1114
    dic->dictSet("ItalicAngle", int_object(fdes->italicAngle));
 
1115
    dic->dictSet("Ascent", int_object(fdes->ascent));
 
1116
    dic->dictSet("Descent", int_object(fdes->descent));
 
1117
    dic->dictSet("CapHeight", int_object(fdes->capHeight));
 
1118
    dic->dictSet("StemV", int_object(fdes->stemV));
 
1119
 
 
1120
    /* FontBox array */
 
1121
    Object array;
 
1122
    array.initArray(xref);
 
1123
 
 
1124
    Object el;
 
1125
 
 
1126
    el.initReal(fdes->bbxmin);
 
1127
    array.arrayAdd(&el);
 
1128
 
 
1129
    el.initReal(fdes->bbymin);
 
1130
    array.arrayAdd(&el);
 
1131
 
 
1132
    el.initReal(fdes->bbxmax);
 
1133
    array.arrayAdd(&el);
 
1134
 
 
1135
    el.initReal(fdes->bbymax);
 
1136
    array.arrayAdd(&el);
 
1137
 
 
1138
    dic->dictSet("FontBBox", &array);
 
1139
 
 
1140
    if (fdes->xHeight) {
 
1141
        dic->dictSet("XHeight", int_object(fdes->xHeight));
 
1142
    }
 
1143
 
 
1144
    if (fdes->avgWidth) {
 
1145
        dic->dictSet("AvgWidth", int_object(fdes->avgWidth));
 
1146
    }
 
1147
 
 
1148
    if (fdes->panose) {
 
1149
        /* Font dictionary for embeded font */
 
1150
        Object style_dic;
 
1151
        style_dic.initDict(xref);
 
1152
 
 
1153
        Object panose;
 
1154
 
 
1155
        GooString *panose_str = new GooString(fdes->panose, 12);
 
1156
        panose.initString(panose_str);
 
1157
        style_dic.dictSet("Panose", &panose);
 
1158
 
 
1159
        dic->dictSet("Style", &style_dic);
 
1160
    }
 
1161
 
 
1162
    Object ref_obj;
 
1163
    ref_obj.initRef(fontfile_obj_ref.num, fontfile_obj_ref.gen);
 
1164
    dic->dictSet(emb_pdf_get_fontfile_key(emb), &ref_obj);
 
1165
 
 
1166
    return dic;
 
1167
}
 
1168
 
 
1169
static Object *make_font_dic(
 
1170
        pdf_t *doc,
 
1171
        EMB_PARAMS *emb,
 
1172
        EMB_PDF_FONTDESCR *fdes,
 
1173
        EMB_PDF_FONTWIDTHS *fwid,
 
1174
        Ref fontdescriptor_obj_ref)
 
1175
{
 
1176
    assert(emb);
 
1177
    assert(fdes);
 
1178
    assert(fwid);
 
1179
 
 
1180
    /* Get XREF table */
 
1181
    XRef *xref = doc->getXRef();
 
1182
 
 
1183
    Object *dic = new Object();
 
1184
    dic->initDict(xref);
 
1185
 
 
1186
    dic->dictSet("Type", name_object("Font"));
 
1187
    dic->dictSet(
 
1188
            "Subtype",
 
1189
            name_object(copyString(emb_pdf_get_font_subtype(emb))));
 
1190
    dic->dictSet(
 
1191
            "BaseFont",
 
1192
            name_object(copyString(emb_pdf_escape_name(fdes->fontname,-1))));
 
1193
 
 
1194
    Object ref_obj;
 
1195
    ref_obj.initRef(fontdescriptor_obj_ref.num, fontdescriptor_obj_ref.gen);
 
1196
    dic->dictSet("FontDescriptor", &ref_obj);
 
1197
 
 
1198
    if ( emb->plan & EMB_A_MULTIBYTE ) {
 
1199
        assert(fwid->warray);
 
1200
 
 
1201
        Object CIDSystemInfo_dic;
 
1202
        CIDSystemInfo_dic.initDict(xref);
 
1203
 
 
1204
        Object registry;
 
1205
        Object ordering;
 
1206
 
 
1207
        GooString *str;
 
1208
 
 
1209
        str = new GooString(copyString(fdes->registry));
 
1210
        registry.initString(str);
 
1211
        CIDSystemInfo_dic.dictSet("Registry", &registry);
 
1212
 
 
1213
        str = new GooString(copyString(fdes->ordering));
 
1214
        ordering.initString(str);
 
1215
        CIDSystemInfo_dic.dictSet("Ordering", &ordering);
 
1216
 
 
1217
        CIDSystemInfo_dic.dictSet("Supplement", int_object(fdes->supplement));
 
1218
 
 
1219
        dic->dictSet("CIDSystemInfo", &CIDSystemInfo_dic);
 
1220
 
 
1221
        dic->dictSet("DW", int_object(fwid->default_width));
 
1222
    }
 
1223
 
 
1224
    return dic;
 
1225
}
 
1226
 
 
1227
 
 
1228
static Object *make_cidfont_dic(
 
1229
        pdf_t *doc,
 
1230
        EMB_PARAMS *emb,
 
1231
        const char *fontname,
 
1232
        Ref fontdescriptor_obj_ref)
 
1233
{
 
1234
    assert(emb);
 
1235
    assert(fontname);
 
1236
 
 
1237
    /*
 
1238
     * For CFF: one of:
 
1239
     * UniGB-UCS2-H, UniCNS-UCS2-H, UniJIS-UCS2-H, UniKS-UCS2-H
 
1240
     */
 
1241
    const char *encoding="Identity-H";
 
1242
    const char *addenc="-";
 
1243
 
 
1244
    if ( emb->outtype == EMB_FMT_TTF ) { // !=CidType0
 
1245
        addenc="";
 
1246
    }
 
1247
 
 
1248
    /* Get XREF table */
 
1249
    XRef *xref = doc->getXRef();
 
1250
 
 
1251
    Object *dic = new Object();
 
1252
    dic->initDict(xref);
 
1253
 
 
1254
    dic->dictSet("Type", name_object("Font"));
 
1255
    dic->dictSet("Subtype", name_object("Type0"));
 
1256
 
 
1257
 
 
1258
    GooString * basefont = new GooString();
 
1259
    basefont->append(emb_pdf_escape_name(fontname,-1));
 
1260
    basefont->append(addenc);
 
1261
    basefont->append((addenc[0])?encoding:"");
 
1262
 
 
1263
    dic->dictSet("BaseFont",
 
1264
            name_object(copyString(basefont->getCString())));
 
1265
 
 
1266
    dic->dictSet("Encoding", name_object(copyString(encoding)));
 
1267
 
 
1268
    Object obj;
 
1269
    obj.initRef(fontdescriptor_obj_ref.num, fontdescriptor_obj_ref.gen);
 
1270
 
 
1271
    Object array;
 
1272
    array.initArray(xref);
 
1273
    array.arrayAdd(&obj);
 
1274
 
 
1275
    dic->dictSet("DescendantFonts", &array);
 
1276
 
 
1277
    return dic;
 
1278
}
 
1279
 
 
1280
 
 
1281
/*
 
1282
 * Convert UTF8 to UTF16.
 
1283
 * Version for poppler - UTF16BE.
 
1284
 *
 
1285
 * Reference:
 
1286
 * http://stackoverflow.com/questions/7153935/how-to-convert-utf-8-stdstring-to-utf-16-stdwstring
 
1287
 */
 
1288
static int utf8_to_utf16(const char *utf8, unsigned short **out_ptr)
 
1289
{
 
1290
    unsigned long *unicode, *head;
 
1291
 
 
1292
    int strl = strlen(utf8);
 
1293
 
 
1294
    unicode = head = (unsigned long*) malloc(strl * sizeof(unsigned long));
 
1295
 
 
1296
    if ( ! head ) {
 
1297
        fprintf(stderr,"stanv: 1\n");
 
1298
        return 0;
 
1299
    }
 
1300
 
 
1301
    while (*utf8){
 
1302
        unsigned long uni;
 
1303
        size_t todo;
 
1304
        unsigned char ch = *utf8;
 
1305
 
 
1306
        if (ch <= 0x7F)
 
1307
        {
 
1308
            uni = ch;
 
1309
            todo = 0;
 
1310
        }
 
1311
        else if (ch <= 0xBF)
 
1312
        {
 
1313
            /* not a UTF-8 string */
 
1314
            return 0;
 
1315
        }
 
1316
        else if (ch <= 0xDF)
 
1317
        {
 
1318
            uni = ch&0x1F;
 
1319
            todo = 1;
 
1320
        }
 
1321
        else if (ch <= 0xEF)
 
1322
        {
 
1323
            uni = ch&0x0F;
 
1324
            todo = 2;
 
1325
        }
 
1326
        else if (ch <= 0xF7)
 
1327
        {
 
1328
            uni = ch&0x07;
 
1329
            todo = 3;
 
1330
        }
 
1331
        else
 
1332
        {
 
1333
            /* not a UTF-8 string */
 
1334
            return 0;
 
1335
        }
 
1336
 
 
1337
        for (size_t j = 0; j < todo; ++j)
 
1338
        {
 
1339
            utf8++;
 
1340
            if ( ! *utf8 ) {
 
1341
                /* not a UTF-8 string */
 
1342
                return 0;
 
1343
            }
 
1344
 
 
1345
            unsigned char ch = *utf8;
 
1346
 
 
1347
            if (ch < 0x80 || ch > 0xBF) {
 
1348
                /* not a UTF-8 string */
 
1349
                return 0;
 
1350
            }
 
1351
 
 
1352
            uni <<= 6;
 
1353
            uni += ch & 0x3F;
 
1354
        }
 
1355
 
 
1356
        if (uni >= 0xD800 && uni <= 0xDFFF) {
 
1357
            /* not a UTF-8 string */
 
1358
            return 0;
 
1359
        }
 
1360
 
 
1361
        if (uni > 0x10FFFF) {
 
1362
            /* not a UTF-8 string */
 
1363
            return 0;
 
1364
        }
 
1365
 
 
1366
        *unicode = uni;
 
1367
        unicode++;
 
1368
        utf8++;
 
1369
    }
 
1370
 
 
1371
    ssize_t len = sizeof(unsigned short) * (unicode - head + 1) * 2;
 
1372
    unsigned short * out = (unsigned short *)malloc(len);
 
1373
 
 
1374
    if ( ! out ) {
 
1375
        return 0;
 
1376
    }
 
1377
 
 
1378
    *out_ptr = out;
 
1379
 
 
1380
    while ( head != unicode ) {
 
1381
        unsigned long uni = *head;
 
1382
 
 
1383
        if (uni <= 0xFFFF)
 
1384
        {
 
1385
            *out = (unsigned short)uni;
 
1386
            *out = ((0xff & uni) << 8) | ((uni & 0xff00) >> 8);
 
1387
        }
 
1388
        else
 
1389
        {
 
1390
            uni -= 0x10000;
 
1391
 
 
1392
            *out += (unsigned short)((uni >> 10) + 0xD800);
 
1393
            *out = ((0xff & uni) << 8) | ((uni & 0xff00) >> 8);
 
1394
            out++;
 
1395
            *out += (unsigned short)((uni >> 10) + 0xD800);
 
1396
            *out = ((0xff & uni) << 8) | ((uni & 0xff00) >> 8);
 
1397
        }
 
1398
 
 
1399
        head++;
 
1400
        out++;
 
1401
    }
 
1402
 
 
1403
    return (out - *out_ptr) * sizeof (unsigned short);
 
1404
}
 
1405
 
 
1406
const char *get_next_wide(const char *utf8, int *unicode_out) {
 
1407
 
 
1408
    unsigned long uni;
 
1409
    size_t todo;
 
1410
 
 
1411
    if ( !utf8 || !*utf8 ) {
 
1412
        return utf8;
 
1413
    }
 
1414
 
 
1415
    unsigned char ch = *utf8;
 
1416
 
 
1417
    *unicode_out = 0;
 
1418
 
 
1419
    if (ch <= 0x7F)
 
1420
    {
 
1421
        uni = ch;
 
1422
        todo = 0;
 
1423
    }
 
1424
    else if (ch <= 0xBF)
 
1425
    {
 
1426
        /* not a UTF-8 string */
 
1427
        return utf8;
 
1428
    }
 
1429
    else if (ch <= 0xDF)
 
1430
    {
 
1431
        uni = ch&0x1F;
 
1432
        todo = 1;
 
1433
    }
 
1434
    else if (ch <= 0xEF)
 
1435
    {
 
1436
        uni = ch&0x0F;
 
1437
        todo = 2;
 
1438
    }
 
1439
    else if (ch <= 0xF7)
 
1440
    {
 
1441
        uni = ch&0x07;
 
1442
        todo = 3;
 
1443
    }
 
1444
    else
 
1445
    {
 
1446
        /* not a UTF-8 string */
 
1447
        return utf8;
 
1448
    }
 
1449
 
 
1450
    for (size_t j = 0; j < todo; ++j)
 
1451
    {
 
1452
        utf8++;
 
1453
        if ( ! *utf8 ) {
 
1454
            /* not a UTF-8 string */
 
1455
            return utf8;
 
1456
        }
 
1457
 
 
1458
        unsigned char ch = *utf8;
 
1459
 
 
1460
        if (ch < 0x80 || ch > 0xBF) {
 
1461
            /* not a UTF-8 string */
 
1462
            return utf8;
 
1463
        }
 
1464
 
 
1465
        uni <<= 6;
 
1466
        uni += ch & 0x3F;
 
1467
    }
 
1468
 
 
1469
    if (uni >= 0xD800 && uni <= 0xDFFF) {
 
1470
        /* not a UTF-8 string */
 
1471
        return utf8;
 
1472
    }
 
1473
 
 
1474
    if (uni > 0x10FFFF) {
 
1475
        /* not a UTF-8 string */
 
1476
        return utf8;
 
1477
    }
 
1478
 
 
1479
    *unicode_out = (int)uni;
 
1480
    utf8++;
 
1481
 
 
1482
    return utf8;
 
1483
}