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

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

interface changes as per Heiko Nitzsche suggestions, compatibility changes

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