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

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

text selection in continuous view fully works

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