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

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

poppler updated to version 0.5.3, related changes

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