source: trunk/Lucide/SOURCE/plugins/lupoppler/lupoppler.cpp @ 28

Last change on this file since 28 was 28, checked in by Eugene Romanenko, 15 years ago

fixes

File size: 41.1 KB
Line 
1
2/*
3 *  This file was generated by the SOM Compiler.
4 *  Generated using:
5 *     SOM incremental update: 2.24
6 */
7
8
9/*
10 *  This file was generated by the SOM Compiler and Emitter Framework.
11 *  Generated using template emitter:
12 *      SOM Emitter emitxtm: 2.23.1.9
13 */
14
15#ifndef SOM_Module_lupoppler_Source
16#define SOM_Module_lupoppler_Source
17#endif
18#define LuPopplerDocument_Class_Source
19
20#include "lupoppler.xih"
21
22#include <goo\GooString.h>
23#include <goo\GooList.h>
24#include <splash\SplashBitmap.h>
25#include <UGooString.h>
26#include <GlobalParams.h>
27#include <ErrorCodes.h>
28#include <PDFDoc.h>
29#include <SplashOutputDev.h>
30#include <TextOutputDev.h>
31#include <PSOutputDev.h>
32#include <FontInfo.h>
33#include <Outline.h>
34#include <UnicodeMap.h>
35#include <Gfx.h>
36#include <Link.h>
37
38#define INCL_DOS
39#include <os2.h>
40
41#include <vector>
42using namespace std;
43#include <time.h>
44#include "cpconv.h"
45
46typedef vector<LuRectangle> RectList;
47
48
49unsigned _System LibMain( unsigned hmod, unsigned termination )
50{
51    if ( termination ) {
52        /* DLL is detaching from process */
53    } else {
54        /* DLL is attaching to process */
55    }
56    return( 1 );
57}
58
59
60extern "C" LuDocument * _System createObject()
61{
62    return new LuPopplerDocument;
63}
64
65extern "C" char * _System getSupportedExtensions()
66{
67    return "PDF";
68}
69
70extern "C" char * _System getDescription()
71{
72    return "PDF plugin, based on poppler library.";
73}
74
75
76class PopplerPage
77{
78    public:
79
80        Page *page;
81        TextOutputDev *text_dev;
82        Gfx *gfx;
83
84        PopplerPage();
85        ~PopplerPage();
86};
87
88PopplerPage::PopplerPage()
89{
90    page = NULL;
91    text_dev = NULL;
92    gfx = NULL;
93}
94
95PopplerPage::~PopplerPage()
96{
97    delete text_dev;
98    delete gfx;
99}
100
101
102class PopplerDocument
103{
104    public:
105
106        PDFDoc *doc;
107        SplashOutputDev *output_dev;
108        PopplerPage *pages;
109        char *text;
110        HMTX mutex;
111
112        PopplerDocument();
113        ~PopplerDocument();
114};
115
116PopplerDocument::PopplerDocument()
117{
118    doc        = NULL;
119    output_dev = NULL;
120    pages      = NULL;
121    text       = NULL;
122    mutex      = NULLHANDLE;
123    DosCreateMutexSem( NULL, &mutex, 0, FALSE );
124}
125
126PopplerDocument::~PopplerDocument()
127{
128    delete [] pages;
129    delete doc;
130    delete output_dev;
131    delete text;
132    DosCloseMutexSem( mutex );
133}
134
135
136static char *newstrdup( const char *s )
137{
138    if ( s == NULL ) {
139        return NULL;
140    }
141    char *temp = new char[ strlen( s ) + 1 ];
142    strcpy( temp, s );
143    return temp;
144}
145
146static char *somstrdup( const char *s )
147{
148    if ( s == NULL ) {
149        return NULL;
150    }
151    char *temp = (char *)SOMMalloc( strlen( s ) + 1 );
152    strcpy( temp, s );
153    return temp;
154}
155
156
157SOM_Scope short  SOMLINK getBpp(LuPopplerDocument *somSelf,  Environment *ev)
158{
159    return 4;
160}
161
162SOM_Scope boolean  SOMLINK isScalable(LuPopplerDocument *somSelf,
163                                       Environment *ev)
164{
165    return TRUE;
166}
167
168
169SOM_Scope boolean  SOMLINK isRotable(LuPopplerDocument *somSelf,
170                                      Environment *ev)
171{
172    return TRUE;
173}
174
175
176SOM_Scope long  SOMLINK getPageCount(LuPopplerDocument *somSelf,
177                                      Environment *ev)
178{
179    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData(somSelf);
180    return ((PopplerDocument *)somThis->data)->doc->getNumPages();
181}
182
183
184SOM_Scope void  SOMLINK getPageSize(LuPopplerDocument *somSelf,
185                                    Environment *ev, long pagenum,
186                                    double* width, double* height)
187{
188    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData(somSelf);
189
190    Page *page = ((PopplerDocument *)somThis->data)->pages[ pagenum ].page;
191
192    double page_width, page_height;
193    int rotate = page->getRotate();
194    if ( rotate == 90 || rotate == 270 ) {
195        page_height = page->getCropWidth();
196        page_width = page->getCropHeight();
197    } else {
198        page_width = page->getCropWidth();
199        page_height = page->getCropHeight();
200    }
201
202    if ( width != NULL ) {
203        *width = page_width;
204    }
205    if ( height != NULL ) {
206        *height = page_height;
207    }
208}
209
210
211static void copy_page_to_pixbuf( Environment *ev, SplashBitmap *bitmap, LuPixbuf *pixbuf )
212{
213    int splash_width, splash_height, splash_rowstride;
214    int pixbuf_rowstride, pixbuf_height, pixbuf_width;
215    int height, width, rowstride;
216    char *pixbuf_data, *dst, *src;
217
218    SplashColorPtr color_ptr = bitmap->getDataPtr();
219
220    splash_width = bitmap->getWidth();
221    splash_height = bitmap->getHeight();
222    splash_rowstride = bitmap->getRowSize();
223
224    //somPrintf( "splash_width: %d   splash_height: %d   splash_rowstride: %d\n",
225    //            splash_width, splash_height, splash_rowstride );
226
227    pixbuf_data = (char *)pixbuf->getDataPtr( ev );
228    pixbuf_width = pixbuf->getWidth( ev );
229    pixbuf_height = pixbuf->getHeight( ev );
230    pixbuf_rowstride = pixbuf->getRowSize( ev );
231
232    width = __min( splash_width, pixbuf_width );
233    height = __min( splash_height, pixbuf_height );
234    rowstride = __min( splash_rowstride, pixbuf_rowstride );
235
236    int i, j;
237    for ( i = 0, j = ( height - 1 ); i < height; i++, j-- )
238    {
239        dst = pixbuf_data + i * pixbuf_rowstride;
240        src = ((char *)color_ptr) + j * splash_rowstride;
241        memcpy( dst, src, rowstride );
242    }
243
244    // test
245    //memcpy( pixbuf_data, color_ptr, pixbuf->getDataLen( ev ) );
246}
247
248
249SOM_Scope void  SOMLINK renderPageToPixbuf(LuPopplerDocument *somSelf,
250                                            Environment *ev,
251                                           long pagenum, long src_x,
252                                           long src_y, long src_width,
253                                           long src_height, double scale,
254                                           long rotation, LuPixbuf* pixbuf)
255{
256    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData(somSelf);
257    PopplerDocument *document = (PopplerDocument *)somThis->data;
258    Page *page = document->pages[ pagenum ].page;
259
260    if ( ( scale < 0.0 ) || ( pixbuf == NULL ) ) {
261        return;
262    }
263
264    DosRequestMutexSem( document->mutex, SEM_INDEFINITE_WAIT );
265
266    page->displaySlice( document->output_dev,
267                72.0 * scale, 72.0 * scale,
268                rotation,
269                gFalse, /* useMediaBox */
270                gTrue, /* Crop */
271                src_x, src_y,
272                src_width, src_height,
273                NULL, /* links */
274                document->doc->getCatalog() );
275
276    DosReleaseMutexSem( document->mutex );
277
278    copy_page_to_pixbuf( ev, document->output_dev->getBitmap(), pixbuf );
279}
280
281
282SOM_Scope boolean  SOMLINK isAsynchRenderingSupported(LuPopplerDocument *somSelf,
283                                                       Environment *ev)
284{
285    return TRUE;
286}
287
288
289struct asynchCallbackData
290{
291    Environment      *ev;
292    LuPixbuf         *pixbuf;
293    SplashBitmap     *bitmap;
294    void             *fndata;
295    _asynchCallbackFn fnd;
296    _asynchCallbackFn fna;
297    long              tmr;
298    bool              forceDraw;
299    long              delay;
300};
301
302static GBool abortCheckCbk( void *data )
303{
304    long now;
305    asynchCallbackData *cd = (asynchCallbackData *)data;
306    DosQuerySysInfo( QSV_MS_COUNT, QSV_MS_COUNT, &now, sizeof( long ) );
307    long dist = ( now - cd->tmr );
308    if ( ( dist > cd->delay ) || cd->forceDraw ) {
309        copy_page_to_pixbuf( cd->ev, cd->bitmap, cd->pixbuf );
310        cd->fnd( cd->fndata );
311        cd->tmr = now;
312        cd->delay += 100;
313    }
314    return (GBool)cd->fna( cd->fndata );
315}
316
317SOM_Scope void  SOMLINK renderPageToPixbufAsynch(LuPopplerDocument *somSelf,
318                                                  Environment *ev,
319                                                 long pagenum,
320                                                 long src_x,
321                                                 long src_y,
322                                                 long src_width,
323                                                 long src_height,
324                                                 double scale,
325                                                 long rotation,
326                                                 LuPixbuf* pixbuf,
327                                                 LuDocument_asynchCallbackFn fnd,
328                                                 LuDocument_asynchCallbackFn fna,
329                                                 somToken fndata)
330{
331    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData(somSelf);
332    PopplerDocument *document = (PopplerDocument *)somThis->data;
333    Page *page = document->pages[ pagenum ].page;
334
335    if ( ( scale < 0.0 ) || ( pixbuf == NULL ) ) {
336        return;
337    }
338
339    asynchCallbackData acd;
340    acd.ev        = ev;
341    acd.pixbuf    = pixbuf;
342    acd.bitmap    = document->output_dev->getBitmap();
343    acd.fndata    = fndata;
344    acd.fnd       = (_asynchCallbackFn)fnd;
345    acd.fna       = (_asynchCallbackFn)fna;
346    acd.forceDraw = false;
347    acd.delay     = 100;
348    DosQuerySysInfo( QSV_MS_COUNT, QSV_MS_COUNT, &acd.tmr, sizeof( long ) );
349
350    DosRequestMutexSem( document->mutex, SEM_INDEFINITE_WAIT );
351
352    //somPrintf( "src_x: %d, src_y: %d, src_width: %d, src_height: %d\n",
353    //           src_x, src_y, src_width, src_height );
354
355    page->displaySlice( document->output_dev,
356                72.0 * scale, 72.0 * scale,
357                rotation,
358                gFalse, /* useMediaBox */
359                gTrue, /* Crop */
360                src_x, src_y,
361                src_width, src_height,
362                NULL, /* links */
363                document->doc->getCatalog(),
364                abortCheckCbk, &acd );
365    DosReleaseMutexSem( document->mutex );
366
367    acd.forceDraw = true;
368    abortCheckCbk( &acd );
369}
370
371static TextOutputDev *get_text_output_dev( PopplerPage *page,
372                                           PopplerDocument *document )
373{
374    if ( page->text_dev == NULL )
375    {
376        DosRequestMutexSem( document->mutex, SEM_INDEFINITE_WAIT );
377        page->text_dev = new TextOutputDev( NULL, gTrue, gFalse, gFalse );
378
379        page->gfx = page->page->createGfx(page->text_dev,
380                          72.0, 72.0, 0,
381                          gFalse, /* useMediaBox */
382                          gTrue, /* Crop */
383                          -1, -1, -1, -1,
384                          NULL, /* links */
385                          document->doc->getCatalog(),
386                          NULL, NULL, NULL, NULL);
387
388        page->page->display( page->gfx );
389        page->text_dev->endPage();
390        DosReleaseMutexSem( document->mutex );
391    }
392
393    return page->text_dev;
394}
395
396
397SOM_Scope LuDocument_LuRectSequence*  SOMLINK getSelectionRectangles(LuPopplerDocument *somSelf,
398                                                                    Environment *ev,
399                                                                   long pagenum,
400                                                                   double scale,
401                                                                   LuRectangle* selection)
402{
403    LuDocument_LuRectSequence *rectangles = NULL;
404
405    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData(somSelf);
406    PopplerDocument *document = (PopplerDocument *)somThis->data;
407    PopplerPage *page = &( document->pages[ pagenum ] );
408
409    TextOutputDev *text_dev = get_text_output_dev( page, document );
410
411    PDFRectangle poppler_selection;
412    poppler_selection.x1 = selection->x1;
413    poppler_selection.y1 = selection->y1;
414    poppler_selection.x2 = selection->x2;
415    poppler_selection.y2 = selection->y2;
416
417    GooList *list = text_dev->getSelectionRegion( &poppler_selection, scale );
418    int len = list->getLength();
419
420    if ( len > 0 )
421    {
422        rectangles = (LuDocument_LuRectSequence *)SOMMalloc( sizeof( LuDocument_LuRectSequence ) );
423        rectangles->_maximum = len;
424        rectangles->_length = len;
425        rectangles->_buffer = (LuRectangle *)SOMMalloc( sizeof( LuRectangle ) * len );
426
427        for ( int i = 0; i < len; i++ )
428        {
429            PDFRectangle *selection_rect = (PDFRectangle *)list->get( i );
430            rectangles->_buffer[ i ].x1 = selection_rect->x1;
431            rectangles->_buffer[ i ].y1 = selection_rect->y1;
432            rectangles->_buffer[ i ].x2 = selection_rect->x2;
433            rectangles->_buffer[ i ].y2 = selection_rect->y2;
434            delete selection_rect;
435        }
436    }
437    delete list;
438
439    return rectangles;
440}
441
442
443SOM_Scope boolean  SOMLINK isHaveText(LuPopplerDocument *somSelf,
444                                      Environment *ev)
445{
446    return TRUE;
447}
448
449
450SOM_Scope string  SOMLINK getText(LuPopplerDocument *somSelf,
451                                   Environment *ev, long pagenum,
452                                  LuRectangle* selection)
453{
454    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData(somSelf);
455
456    if ( selection == NULL ) {
457        return NULL;
458    }
459
460    PopplerDocument *document = (PopplerDocument *)somThis->data;
461    PopplerPage *page = &( document->pages[ pagenum ] );
462
463    TextOutputDev *text_dev = get_text_output_dev( page, document );
464
465    GooString *sel_text = new GooString;
466    char *result;
467    PDFRectangle pdf_selection;
468
469    pdf_selection.x1 = selection->x1;
470    pdf_selection.y1 = selection->y1;
471    pdf_selection.x2 = selection->x2;
472    pdf_selection.y2 = selection->y2;
473
474    DosRequestMutexSem( document->mutex, SEM_INDEFINITE_WAIT );
475    sel_text = text_dev->getSelectionText( &pdf_selection );
476
477    delete document->text;
478    document->text = newstrdup( sel_text->getCString() );
479    delete sel_text;
480    DosReleaseMutexSem( document->mutex );
481
482    return document->text;
483}
484
485
486SOM_Scope boolean  SOMLINK isHaveLinks(LuPopplerDocument *somSelf,
487                                        Environment *ev)
488{
489    return TRUE;
490}
491
492
493static long find_dest_page( PDFDoc *doc, LinkDest *link_dest )
494{
495    long page_num = 0;
496
497    if ( link_dest == NULL ) {
498        return page_num;
499    }
500
501    if ( link_dest->isPageRef() )
502    {
503        Ref page_ref = link_dest->getPageRef();
504        page_num = doc->findPage( page_ref.num, page_ref.gen ) - 1;
505    }
506    else {
507        page_num = link_dest->getPageNum() - 1;
508    }
509
510    return page_num;
511}
512
513static void build_goto_dest( PDFDoc *doc, LuLink *evlink, LinkGoTo *link )
514{
515    LinkDest *link_dest;
516    UGooString *named_dest;
517
518    if ( !link->isOk() ) {
519        return;
520    }
521
522    link_dest = link->getDest();
523    named_dest = link->getNamedDest();
524
525    if ( link_dest != NULL ) {
526        evlink->page = find_dest_page( doc, link_dest );
527    } else if ( named_dest != NULL ) {
528        link_dest = doc->findDest( named_dest );
529        evlink->page = find_dest_page( doc, link_dest );
530        delete link_dest;
531    } else {
532        evlink->page = 0;
533    }
534}
535
536static void build_link( PDFDoc *doc, LuLink *evlink,
537                        const char *title, LinkAction *link_action )
538{
539    evlink->title = somstrdup( title );
540    evlink->uri = NULL;
541    evlink->type = LU_LINK_TYPE_TITLE;
542    evlink->page = 0;
543
544    if ( link_action == NULL ) {
545        return;
546    }
547
548    switch ( link_action->getKind() )
549    {
550        case actionGoTo:
551            {
552                evlink->type = LU_LINK_TYPE_PAGE;
553                LinkGoTo *lgt = dynamic_cast <LinkGoTo *> (link_action);
554                build_goto_dest( doc, evlink, lgt );
555            }
556            break;
557
558        case actionURI:
559            {
560                evlink->type = LU_LINK_TYPE_EXTERNAL_URI;
561                LinkURI *lu = dynamic_cast <LinkURI *> (link_action);
562                char *uri = lu->getURI()->getCString();
563                if ( uri != NULL ) {
564                    evlink->uri = somstrdup( uri );
565                }
566            }
567            break;
568    }
569}
570
571SOM_Scope LuDocument_LuLinkMapSequence*  SOMLINK getLinkMapping(LuPopplerDocument *somSelf,
572                                                                 Environment *ev,
573                                                                long pagenum)
574{
575    LuDocument_LuLinkMapSequence *mapping = NULL;
576
577    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData(somSelf);
578    PopplerDocument *document = (PopplerDocument *)somThis->data;
579    PopplerPage *page = &( document->pages[ pagenum ] );
580
581    Object obj;
582    Links *links = new Links( page->page->getAnnots( &obj ),
583                            document->doc->getCatalog()->getBaseURI() );
584    obj.free();
585
586    if ( links == NULL ) {
587        return NULL;
588    }
589
590    double height = 0;
591    getPageSize( somSelf, ev, pagenum, NULL, &height );
592
593    int len = links->getNumLinks();
594
595    if ( len > 0 )
596    {
597        mapping = (LuDocument_LuLinkMapSequence *)SOMMalloc( sizeof( LuDocument_LuLinkMapSequence ) );
598        mapping->_maximum = len;
599        mapping->_length = len;
600        mapping->_buffer = (LuLinkMapping *)SOMMalloc( sizeof( LuLinkMapping ) * len );
601
602        for ( int i = 0; i < len; i++ )
603        {
604            Link *link = links->getLink( i );
605            LinkAction *link_action = link->getAction();
606            build_link( document->doc, &(mapping->_buffer[ i ].link), NULL, link_action );
607
608            link->getRect( &(mapping->_buffer[ i ].area.x1),
609                           &(mapping->_buffer[ i ].area.y1),
610                           &(mapping->_buffer[ i ].area.x2),
611                           &(mapping->_buffer[ i ].area.y2) );
612
613            mapping->_buffer[ i ].area.x1 -= page->page->getCropBox()->x1;
614            mapping->_buffer[ i ].area.x2 -= page->page->getCropBox()->x1;
615            mapping->_buffer[ i ].area.y1 -= page->page->getCropBox()->y1;
616            mapping->_buffer[ i ].area.y2 -= page->page->getCropBox()->y1;
617
618            double y1 = mapping->_buffer[ i ].area.y1;
619            double y2 = mapping->_buffer[ i ].area.y2;
620            mapping->_buffer[ i ].area.y1 = height - y2;
621            mapping->_buffer[ i ].area.y2 = height - y1;
622        }
623    }
624
625    return mapping;
626}
627
628
629SOM_Scope boolean  SOMLINK isSaveable(LuPopplerDocument *somSelf,
630                                       Environment *ev)
631{
632    return TRUE;
633}
634
635
636SOM_Scope boolean  SOMLINK saveAs(LuPopplerDocument *somSelf,
637                                   Environment *ev, string filename)
638{
639    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData(somSelf);
640    PopplerDocument *document = (PopplerDocument *)somThis->data;
641
642    boolean retval = FALSE;
643
644    if ( filename != NULL ) {
645        retval = document->doc->saveAs( new GooString( filename ) );
646    }
647
648    return retval;
649}
650
651
652SOM_Scope boolean  SOMLINK isPSExportable(LuPopplerDocument *somSelf,
653                                           Environment *ev)
654{
655    return TRUE;
656}
657
658
659SOM_Scope void  SOMLINK exportToPS(LuPopplerDocument *somSelf,
660                                    Environment *ev, string filename,
661                                   long first_page, long last_page,
662                                   double width, double height,
663                                   boolean duplex)
664{
665    if ( filename == NULL ) {
666        return;
667    }
668    if ( last_page < first_page ) {
669        return;
670    }
671
672    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData(somSelf);
673    PDFDoc *doc = ((PopplerDocument *)somThis->data)->doc;
674
675
676    PSOutputDev *out = new PSOutputDev( filename, doc->getXRef(),
677                                        doc->getCatalog(),
678                                        first_page + 1, last_page + 1,
679                                        psModePS, (int)width, (int)height,
680                                        duplex, 0, 0, 0, 0, gFalse );
681
682
683    for ( long i = first_page; i < last_page; i++ ) {
684        doc->displayPage( out, i + 1, 72.0, 72.0, 0, gFalse, gTrue, gFalse );
685    }
686
687    delete out;
688}
689
690
691SOM_Scope boolean  SOMLINK isHaveFontInfo(LuPopplerDocument *somSelf,
692                                           Environment *ev)
693{
694    return TRUE;
695}
696
697
698SOM_Scope LuDocument_LuFontInfoSequence*  SOMLINK getFontInfo(LuPopplerDocument *somSelf,
699                                                               Environment *ev)
700{
701    LuDocument_LuFontInfoSequence *fonts = NULL;
702
703    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData(somSelf);
704    PopplerDocument *document = (PopplerDocument *)somThis->data;
705    PDFDoc *doc = document->doc;
706
707    DosRequestMutexSem( document->mutex, SEM_INDEFINITE_WAIT );
708    FontInfoScanner *scanner = new FontInfoScanner( doc );
709    GooList *items = scanner->scan( doc->getNumPages() );
710    delete scanner;
711    DosReleaseMutexSem( document->mutex );
712
713    if ( items == NULL ) {
714        return NULL;
715    }
716
717    int len = items->getLength();
718
719    if ( len == 0 ) {
720        delete items;
721        return NULL;
722    }
723
724    fonts = (LuDocument_LuFontInfoSequence *)SOMMalloc( sizeof( LuDocument_LuFontInfoSequence ) );
725    fonts->_maximum = len;
726    fonts->_length = len;
727    fonts->_buffer = (LuFontInfo *)SOMMalloc( sizeof( LuFontInfo ) * len );
728
729    for ( int i = 0; i < len; i++ )
730    {
731        fonts->_buffer[i].name = NULL;
732        fonts->_buffer[i].type = NULL;
733        fonts->_buffer[i].embedded = NULL;
734
735        FontInfo *info = (FontInfo *)items->get( i );
736
737        // name
738        GooString *gnm = info->getName();
739        if ( gnm != NULL )
740        {
741            char *nm = gnm->getCString();
742            if ( info->getSubset() && ( nm != NULL ) )
743            {
744                while ( *nm && ( *nm != '+' ) ) {
745                    nm++;
746                }
747                if ( *nm ) {
748                    nm++;
749                }
750            }
751            if ( nm != NULL ) {
752                if ( *nm ) {
753                    fonts->_buffer[i].name = somstrdup( nm );
754                }
755            }
756        }
757
758        // type
759        char *t = "Unknown font type";
760        switch ( info->getType() )
761        {
762            case FontInfo::Type1:        t = "Type 1";          break;
763            case FontInfo::Type1C:       t = "Type 1C";         break;
764            case FontInfo::Type3:        t = "Type 3";          break;
765            case FontInfo::TrueType:     t = "TrueType";        break;
766            case FontInfo::CIDType0:     t = "Type 1 (CID)";    break;
767            case FontInfo::CIDType0C:    t = "Type 1C (CID)";   break;
768            case FontInfo::CIDTrueType:  t = "TrueType (CID)";  break;
769        }
770        fonts->_buffer[i].type = somstrdup( t );
771
772        // embedded
773        char *e = NULL;
774        if ( info->getEmbedded() ) {
775            if ( info->getSubset() ) {
776                e = "Embedded subset";
777            } else {
778                e = "Embedded";
779            }
780        } else {
781            e = "Not embedded";
782        }
783        fonts->_buffer[i].embedded = somstrdup( e );
784
785    }
786
787    return fonts;
788}
789
790
791SOM_Scope boolean  SOMLINK isHaveIndex(LuPopplerDocument *somSelf,
792                                        Environment *ev)
793{
794    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData(somSelf);
795    PDFDoc *doc = ((PopplerDocument *)somThis->data)->doc;
796
797    Outline *outline = doc->getOutline();
798    if ( outline == NULL ) {
799        return FALSE;
800    }
801
802    GooList *items = outline->getItems();
803    if ( items == NULL ) {
804        return FALSE;
805    }
806
807    return TRUE;
808}
809
810static char *unicode_to_char( Unicode *unicode, int len )
811{
812    static UnicodeMap *uMap = NULL;
813    if ( uMap == NULL )
814    {
815        GooString *enc = new GooString( "UTF-8" );
816        uMap = globalParams->getUnicodeMap( enc );
817        uMap->incRefCnt();
818        delete enc;
819    }
820
821    GooString gstr;
822    char buf[8]; // 8 is enough for mapping an unicode char to a string
823    int i, n;
824
825    for ( i = 0; i < len; ++i ) {
826        n = uMap->mapUnicode( unicode[i], buf, sizeof( buf ) );
827        gstr.append( buf, n );
828    }
829
830    return newstrdup( gstr.getCString() );
831}
832
833static char *newstrFromUTF8( const char *s )
834{
835    unsigned blen = strlen( s ) + 1;
836    char *b = new char[ blen ];
837    memset( b, 0, blen );
838    char *bsav = b;
839    const char *from = s;
840    unsigned flen = strlen( s );
841    cnvUTF8ToSys( &from, &flen, &b, &blen );
842    return bsav;
843}
844
845static void add_item( Environment *ev, PDFDoc *doc, LuIndexNode *n, GooList *items )
846{
847    if ( items == NULL ) {
848        return;
849    }
850
851    int len = items->getLength();
852
853    for ( int i = 0; i < len; i++ )
854    {
855        OutlineItem *item = (OutlineItem *)items->get( i );
856        LinkAction *link_action = item->getAction();
857        LuLink evlink;
858        char *t1 = unicode_to_char( item->getTitle(), item->getTitleLength() );
859        char *t2 = newstrFromUTF8( t1 );
860        build_link( doc, &evlink, t2, link_action );
861        delete t2;
862        delete t1;
863        LuIndexNode *cn = new LuIndexNode( ev, &evlink );
864        n->addChild( ev, cn );
865
866        item->open();
867        if ( item->hasKids() )
868        {
869            GooList *citems = item->getKids();
870            add_item( ev, doc, cn, citems );
871        }
872    }
873}
874
875SOM_Scope LuIndexNode*  SOMLINK getIndex(LuPopplerDocument *somSelf,
876                                          Environment *ev)
877{
878    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData(somSelf);
879    PDFDoc *doc = ((PopplerDocument *)somThis->data)->doc;
880
881    Outline *outline = doc->getOutline();
882    if ( outline == NULL ) {
883        return NULL;
884    }
885
886    GooList *items = outline->getItems();
887    if ( items == NULL ) {
888        return NULL;
889    }
890
891    LuIndexNode *root = new LuIndexNode( ev, NULL );
892    add_item( ev, doc, root, items );
893
894    return root;
895}
896
897
898static bool has_unicode_marker( GooString *string )
899{
900    return ( ( (string->getChar(0) & 0xff) == 0xfe ) &&
901             ( (string->getChar(1) & 0xff) == 0xff ) );
902}
903
904// return SOMMalloc'ed string
905static char *propcnv( GooString *s )
906{
907    if ( has_unicode_marker( s ) )
908    {
909        unsigned blen = s->getLength() * 2;
910        char *b = (char *)SOMMalloc( blen );
911        memset( b, 0, blen );
912        char *bsav = b;
913        const char *from = s->getCString() + 2;
914        unsigned flen = s->getLength() - 2;
915        cnvUniBEToSys( &from, &flen, &b, &blen );
916        return bsav;
917    }
918
919    return somstrdup( s->getCString() );
920}
921
922static time_t propToDate( const char *date_string )
923{
924    int year, mon, day, hour, min, sec;
925    int scanned_items;
926
927    // See PDF Reference 1.3, Section 3.8.2 for PDF Date representation
928    if ( ( date_string[0] == 'D' ) && ( date_string[1] == ':' ) ) {
929        date_string += 2;
930    }
931
932    // FIXME only year is mandatory; parse optional timezone offset
933    scanned_items = sscanf( date_string, "%4d%2d%2d%2d%2d%2d",
934                            &year, &mon, &day, &hour, &min, &sec);
935
936    if ( scanned_items != 6 ) {
937        return (time_t)(-1);
938    }
939
940    // Workaround for y2k bug in Distiller 3, hoping that it won't
941    // be used after y2.2k
942    if ( ( year < 1930 ) && ( strlen( date_string ) > 14 ) )
943    {
944        int century, years_since_1900;
945        scanned_items = sscanf( date_string, "%2d%3d%2d%2d%2d%2d%2d",
946                &century, &years_since_1900, &mon, &day, &hour, &min, &sec );
947
948        if ( scanned_items != 7 ) {
949            return (time_t)(-1);
950        }
951
952        year = century * 100 + years_since_1900;
953    }
954
955    struct tm time = { 0 };
956    time.tm_year  = year - 1900;
957    time.tm_mon   = mon - 1;
958    time.tm_mday  = day;
959    time.tm_hour  = hour;
960    time.tm_min   = min;
961    time.tm_sec   = sec;
962    time.tm_wday  = -1;
963    time.tm_yday  = -1;
964    time.tm_isdst = -1; // 0 = DST off, 1 = DST on, -1 = don't know
965
966    return mktime( &time );
967}
968
969static long convPageMode( Catalog::PageMode pageMode )
970{
971    switch ( pageMode )
972    {
973        case Catalog::pageModeThumbs:
974            return LU_DOCUMENT_MODE_USE_THUMBS;
975        case Catalog::pageModeFullScreen:
976            return LU_DOCUMENT_MODE_FULL_SCREEN;
977        case Catalog::pageModeOC:
978            return LU_DOCUMENT_MODE_USE_OC;
979        case Catalog::pageModeAttach:
980            return LU_DOCUMENT_MODE_USE_ATTACHMENTS;
981        case Catalog::pageModeNone:
982            return LU_DOCUMENT_MODE_NONE;
983    }
984
985    return -1;
986}
987
988static long convLayout( Catalog::PageLayout pageLayout )
989{
990    switch ( pageLayout )
991    {
992        case Catalog::pageLayoutSinglePage:
993            return LU_DOCUMENT_LAYOUT_SINGLE_PAGE;
994        case Catalog::pageLayoutOneColumn:
995            return LU_DOCUMENT_LAYOUT_ONE_COLUMN;
996        case Catalog::pageLayoutTwoColumnLeft:
997            return LU_DOCUMENT_LAYOUT_TWO_COLUMN_LEFT;
998        case Catalog::pageLayoutTwoColumnRight:
999            return LU_DOCUMENT_LAYOUT_TWO_COLUMN_RIGHT;
1000        case Catalog::pageLayoutTwoPageLeft:
1001            return LU_DOCUMENT_LAYOUT_TWO_PAGE_LEFT;
1002        case Catalog::pageLayoutTwoPageRight:
1003            return LU_DOCUMENT_LAYOUT_TWO_PAGE_RIGHT;
1004    }
1005    return -1;
1006}
1007
1008SOM_Scope LuDocumentInfo*  SOMLINK getDocumentInfo(LuPopplerDocument *somSelf,
1009                                                    Environment *ev)
1010{
1011    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData(somSelf);
1012    PDFDoc *doc = ((PopplerDocument *)somThis->data)->doc;
1013
1014    LuDocumentInfo *info = (LuDocumentInfo *)SOMMalloc( sizeof( LuDocumentInfo ) );
1015    memset( info, 0, sizeof( LuDocumentInfo ) );
1016
1017    Object objdict;
1018    doc->getDocInfo( &objdict );
1019    if ( objdict.isDict() )
1020    {
1021        Dict *d = objdict.getDict();
1022        Object obj;
1023
1024        if ( d->lookup( "Title", &obj )->isString() ) {
1025            info->title = propcnv( obj.getString() );
1026            info->fields_mask |= LU_DOCUMENT_INFO_TITLE;
1027        }
1028        obj.free();
1029        if ( d->lookup( "Author", &obj )->isString() ) {
1030            info->author = propcnv( obj.getString() );
1031            info->fields_mask |= LU_DOCUMENT_INFO_AUTHOR;
1032        }
1033        obj.free();
1034        if ( d->lookup( "Subject", &obj )->isString() ) {
1035            info->subject = propcnv( obj.getString() );
1036            info->fields_mask |= LU_DOCUMENT_INFO_SUBJECT;
1037        }
1038        obj.free();
1039        if ( d->lookup( "Keywords", &obj )->isString() ) {
1040            info->keywords = propcnv( obj.getString() );
1041            info->fields_mask |= LU_DOCUMENT_INFO_KEYWORDS;
1042        }
1043        obj.free();
1044        if ( d->lookup( "Creator", &obj )->isString() ) {
1045            info->creator = propcnv( obj.getString() );
1046            info->fields_mask |= LU_DOCUMENT_INFO_CREATOR;
1047        }
1048        obj.free();
1049        if ( d->lookup( "Producer", &obj )->isString() ) {
1050            info->producer = propcnv( obj.getString() );
1051            info->fields_mask |= LU_DOCUMENT_INFO_PRODUCER;
1052        }
1053        obj.free();
1054        if ( d->lookup( "CreationDate", &obj )->isString() ) {
1055            char *d = propcnv( obj.getString() );
1056            info->creation_date = propToDate( d );
1057            if ( (long)info->creation_date != -1 ) {
1058                info->fields_mask |= LU_DOCUMENT_INFO_CREATION_DATE;
1059            }
1060            SOMFree( d );
1061        }
1062        obj.free();
1063        if ( d->lookup( "ModDate", &obj )->isString() ) {
1064            char *d = propcnv( obj.getString() );
1065            info->modified_date = propToDate( d );
1066            if ( (long)info->modified_date != -1 ) {
1067                info->fields_mask |= LU_DOCUMENT_INFO_MOD_DATE;
1068            }
1069            SOMFree( d );
1070        }
1071        obj.free();
1072    }
1073
1074    char *format = (char *)SOMMalloc( 16 );
1075    snprintf( format, 16, "PDF-%.2f", doc->getPDFVersion() );
1076    info->format = format;
1077    info->fields_mask |= LU_DOCUMENT_INFO_FORMAT;
1078
1079    info->linearized = doc->isLinearized();
1080    info->fields_mask |= LU_DOCUMENT_INFO_LINEARIZED;
1081
1082    Catalog *catalog = doc->getCatalog();
1083
1084    if ( ( catalog != NULL ) && catalog->isOk() )
1085    {
1086        info->layout = convLayout( catalog->getPageLayout() );
1087        if ( info->layout != -1 ) {
1088            info->fields_mask |= LU_DOCUMENT_INFO_LAYOUT;
1089        }
1090
1091        info->mode = convPageMode( catalog->getPageMode() );
1092        if ( info->mode != -1 ) {
1093            info->fields_mask |= LU_DOCUMENT_INFO_START_MODE;
1094        }
1095    }
1096
1097    info->fields_mask |= LU_DOCUMENT_INFO_PERMISSIONS;
1098    if ( doc->okToPrint() ) {
1099        info->permissions |= LU_DOCUMENT_PERMISSIONS_OK_TO_PRINT;
1100    }
1101    if ( doc->okToChange() ) {
1102        info->permissions |= LU_DOCUMENT_PERMISSIONS_OK_TO_MODIFY;
1103    }
1104    if ( doc->okToCopy() ) {
1105        info->permissions |= LU_DOCUMENT_PERMISSIONS_OK_TO_COPY;
1106    }
1107    if ( doc->okToAddNotes() ) {
1108        info->permissions |= LU_DOCUMENT_PERMISSIONS_OK_TO_ADD_NOTES;
1109    }
1110
1111    info->n_pages = doc->getNumPages();
1112    info->fields_mask |= LU_DOCUMENT_INFO_N_PAGES;
1113
1114    return info;
1115}
1116
1117
1118SOM_Scope boolean  SOMLINK getThumbnailSize(LuPopplerDocument *somSelf,
1119                                             Environment *ev,
1120                                            long pagenum,
1121                                            short suggested_width,
1122                                            short* width, short* height)
1123{
1124    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData(somSelf);
1125    Page *page = ((PopplerDocument *)somThis->data)->pages[ pagenum ].page;
1126
1127    Object thumb;
1128    Dict *dict;
1129    boolean retval = FALSE;
1130
1131    page->getThumb( &thumb );
1132    if ( thumb.isNull() )
1133    {
1134        thumb.free();
1135        return FALSE;
1136    }
1137
1138    dict = thumb.streamGetDict();
1139
1140    // Theoretically, this could succeed and you would still fail when
1141    // loading the thumb
1142    int w = 0, h = 0;
1143    if ( dict->lookupInt( "Width", "W", &w ) && dict->lookupInt( "Height", "H", &h ) )
1144    {
1145        if ( width != NULL ) {
1146            *width = w;
1147        }
1148        if ( height != NULL ) {
1149            *height = h;
1150        }
1151
1152        retval = TRUE;
1153    }
1154
1155    thumb.free();
1156
1157    return retval;
1158}
1159
1160SOM_Scope LuPixbuf*  SOMLINK getThumbnail(LuPopplerDocument *somSelf,
1161                                           Environment *ev, long pagenum,
1162                                          short suggested_width)
1163{
1164    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData(somSelf);
1165    Page *page = ((PopplerDocument *)somThis->data)->pages[ pagenum ].page;
1166
1167    unsigned char *data;
1168    int width, height, rowstride;
1169
1170    if ( !page->loadThumb( &data, &width, &height, &rowstride ) ) {
1171        return NULL;
1172    }
1173
1174    short bpp = getBpp( somSelf, ev );
1175    LuPixbuf *pixbuf = new LuPixbuf( ev, width, height, bpp );
1176    char *pixbuf_data = (char *)pixbuf->getDataPtr( ev );
1177    int pixbuf_rowstride = pixbuf->getRowSize( ev );
1178    char *src, *dst;
1179    int i, j;
1180    for ( i = 0, j = ( height - 1 ); i < height; i++, j-- )
1181    {
1182        src = data + ( j * rowstride );
1183        dst = pixbuf_data + (i * pixbuf_rowstride);
1184        for ( int k = 0; k < pixbuf_rowstride; k += bpp )
1185        {
1186            dst[ k ]     = src[ k + 2 ];
1187            dst[ k + 1 ] = src[ k + 1 ];
1188            dst[ k + 2 ] = src[ k ];
1189        }
1190    }
1191    gfree( data );
1192
1193    return pixbuf;
1194}
1195
1196
1197SOM_Scope LuDocument_LuRectSequence*  SOMLINK searchText(LuPopplerDocument *somSelf,
1198                                                          Environment *ev,
1199                                                         long pagenum,
1200                                                         string text,
1201                                                         boolean caseSensitive)
1202{
1203    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData(somSelf);
1204    PopplerDocument *document = (PopplerDocument *)somThis->data;
1205    Page *page = document->pages[ pagenum ].page;
1206
1207    DosRequestMutexSem( document->mutex, SEM_INDEFINITE_WAIT );
1208    TextOutputDev *output_dev = new TextOutputDev( NULL, gTrue, gFalse, gFalse );
1209    page->display( output_dev, 72, 72, 0, gFalse,
1210                   gTrue, NULL, document->doc->getCatalog() );
1211    DosReleaseMutexSem( document->mutex );
1212
1213
1214    // Convert string from system encoding to UCS-4
1215    // first, convert to UCS-2
1216    unsigned text_len = strlen( text );
1217    unsigned text_len_sav = text_len;
1218    unsigned ucs2_len = ( text_len + 1 ) * 2;
1219    char *ucs2 = new char[ ucs2_len ];
1220    memset( ucs2, 0, ucs2_len );
1221    char *ucs2sav = ucs2;
1222    cnvSysToUCS2( (const char **)&text, &text_len, &ucs2, &ucs2_len );
1223    // second, convert UCS-2 to UCS-4
1224    short *uucs2 = (short *)ucs2sav;
1225    unsigned ucs4_len = ( text_len_sav + 1 ) * 2;
1226    unsigned *ucs4 = new unsigned[ ucs4_len ];
1227    memset( ucs4, 0, ucs4_len * sizeof( unsigned ) );
1228    int real_ucs4_len = 0;
1229    for ( real_ucs4_len = 0; *uucs2; real_ucs4_len++ ) {
1230        ucs4[ real_ucs4_len ] = *uucs2++;
1231    }
1232    delete ucs2sav;
1233    // conversion end
1234
1235    RectList *rl = new RectList;
1236    double xMin, yMin, xMax, yMax;
1237    xMin = 0;
1238    yMin = 0;
1239    while ( output_dev->findText( ucs4, real_ucs4_len,
1240                   gFalse, gTrue, // startAtTop, stopAtBottom
1241                   gTrue, gFalse, // startAtLast, stopAtLast
1242                   caseSensitive, gFalse, // caseSensitive, backwards
1243                   &xMin, &yMin, &xMax, &yMax ) )
1244    {
1245        LuRectangle r;
1246        r.x1 = xMin;
1247        r.y1 = yMin;
1248        r.x2 = xMax;
1249        r.y2 = yMax;
1250        rl->push_back( r );
1251    }
1252    delete ucs4;
1253    delete output_dev;
1254
1255    LuDocument_LuRectSequence *rectangles = NULL;
1256    int len = rl->size();
1257    if ( len > 0 )
1258    {
1259        rectangles = (LuDocument_LuRectSequence *)SOMMalloc( sizeof( LuDocument_LuRectSequence ) );
1260        rectangles->_maximum = len;
1261        rectangles->_length = len;
1262        rectangles->_buffer = (LuRectangle *)SOMMalloc( sizeof( LuRectangle ) * len );
1263
1264        for ( int i = 0; i < len; i++ )
1265        {
1266            rectangles->_buffer[ i ].x1 = (*rl)[i].x1;
1267            rectangles->_buffer[ i ].y1 = (*rl)[i].y1;
1268            rectangles->_buffer[ i ].x2 = (*rl)[i].x2;
1269            rectangles->_buffer[ i ].y2 = (*rl)[i].y2;
1270        }
1271    }
1272    delete rl;
1273
1274    return rectangles;
1275}
1276
1277
1278SOM_Scope void SOMLINK somDefaultInit(LuPopplerDocument *somSelf,
1279                                      som3InitCtrl* ctrl)
1280{
1281    // generated section - do not modify
1282    LuPopplerDocumentData *somThis;
1283    somInitCtrl globalCtrl;
1284    somBooleanVector myMask;
1285    LuPopplerDocument_BeginInitializer_somDefaultInit;
1286    LuPopplerDocument_Init_LuDocument_somDefaultInit(somSelf, ctrl);
1287    // end of generated section
1288
1289    // local LuPopplerDocument initialization code
1290    PopplerDocument *d = new PopplerDocument;
1291    somThis->data = d;
1292}
1293
1294
1295static void set_error( char **error, const char *fmt, ... )
1296{
1297    if ( error == NULL ) {
1298        return;
1299    }
1300
1301    va_list argptr;
1302    va_start( argptr, fmt );
1303    char *msg = new char[ 1000 ];
1304    vsnprintf( msg, 1000, fmt, argptr );
1305    *error = somstrdup( msg );
1306    delete msg;
1307}
1308
1309
1310SOM_Scope boolean  SOMLINK loadFile(LuPopplerDocument *somSelf,
1311                                    Environment *ev, string filename,
1312                                    string password, string* error)
1313{
1314    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData( somSelf );
1315
1316    PDFDoc *newDoc;
1317    GooString *filename_g;
1318    GooString *password_g;
1319    int err;
1320
1321    if ( !globalParams ) {
1322        globalParams = new GlobalParams( NULL );
1323    }
1324
1325    filename_g = new GooString(filename);
1326
1327    password_g = NULL;
1328    if (password != NULL) {
1329        password_g = new GooString(password);
1330    }
1331
1332    newDoc = new PDFDoc(filename_g, password_g, password_g);
1333    if (password_g) {
1334        delete password_g;
1335    }
1336
1337    if (!newDoc->isOk()) {
1338        err = newDoc->getErrorCode();
1339        delete newDoc;
1340
1341        if (err == errEncrypted) {
1342            set_error(error, "Document is encrypted.");
1343        } else {
1344            set_error(error, "Failed to load document (error %d) '%s'\n", err, filename );
1345        }
1346
1347        return FALSE;
1348    }
1349
1350    PopplerDocument *document = (PopplerDocument *)somThis->data;
1351
1352    document->doc = newDoc;
1353    SplashColor white;
1354    white[0] = 255;
1355    white[1] = 255;
1356    white[2] = 255;
1357    document->output_dev = new SplashOutputDev( splashModeRGB8, 4, gFalse, white );
1358    document->output_dev->startDoc( document->doc->getXRef() );
1359
1360    long numpages = document->doc->getNumPages();
1361    document->pages = new PopplerPage[ numpages ];
1362    for ( long pagenum = 0; pagenum < numpages; pagenum++ ) {
1363        document->pages[ pagenum ].page =
1364            document->doc->getCatalog()->getPage( pagenum + 1 );
1365    }
1366
1367    return TRUE;
1368}
1369
1370
1371SOM_Scope void SOMLINK somDestruct(LuPopplerDocument *somSelf,
1372                                   octet doFree, som3DestructCtrl* ctrl)
1373{
1374    LuPopplerDocumentData *somThis;
1375    somDestructCtrl globalCtrl;
1376    somBooleanVector myMask;
1377    LuPopplerDocument_BeginDestructor;
1378
1379    // local LuPopplerDocument deinitialization code
1380    PopplerDocument *document = (PopplerDocument *)somThis->data;
1381    delete document;
1382    // end of local LuPopplerDocument deinitialization code
1383
1384    LuPopplerDocument_EndDestructor;
1385}
1386
1387
Note: See TracBrowser for help on using the repository browser.