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

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

poppler updated to version 0.5.2, also needed changes to be compatible with new poppler

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