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

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

Prevent getLinkMapping() call on every redraw if no links on page.

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