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

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

fontconfig replacement fixes, removed wrong text in file headers

File size: 42.0 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 */
18
19/*
20 *  This file was generated by the SOM Compiler.
21 *  Generated using:
22 *     SOM incremental update: 2.24
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
598    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData(somSelf);
599    PopplerDocument *document = (PopplerDocument *)somThis->data;
600    PopplerPage *page = &( document->pages[ pagenum ] );
601
602    Object obj;
603    Links *links = new Links( page->page->getAnnots( &obj ),
604                            document->doc->getCatalog()->getBaseURI() );
605    obj.free();
606
607    if ( links == NULL ) {
608        return NULL;
609    }
610
611    double height = 0;
612    getPageSize( somSelf, ev, pagenum, NULL, &height );
613
614    int len = links->getNumLinks();
615
616    if ( len > 0 )
617    {
618        mapping = (LuDocument_LuLinkMapSequence *)SOMMalloc( sizeof( LuDocument_LuLinkMapSequence ) );
619        mapping->_maximum = len;
620        mapping->_length = len;
621        mapping->_buffer = (LuLinkMapping *)SOMMalloc( sizeof( LuLinkMapping ) * len );
622
623        for ( int i = 0; i < len; i++ )
624        {
625            Link *link = links->getLink( i );
626            LinkAction *link_action = link->getAction();
627            build_link( document->doc, &(mapping->_buffer[ i ].link), NULL, link_action );
628
629            link->getRect( &(mapping->_buffer[ i ].area.x1),
630                           &(mapping->_buffer[ i ].area.y1),
631                           &(mapping->_buffer[ i ].area.x2),
632                           &(mapping->_buffer[ i ].area.y2) );
633
634            mapping->_buffer[ i ].area.x1 -= page->page->getCropBox()->x1;
635            mapping->_buffer[ i ].area.x2 -= page->page->getCropBox()->x1;
636            mapping->_buffer[ i ].area.y1 -= page->page->getCropBox()->y1;
637            mapping->_buffer[ i ].area.y2 -= page->page->getCropBox()->y1;
638
639            double y1 = mapping->_buffer[ i ].area.y1;
640            double y2 = mapping->_buffer[ i ].area.y2;
641            mapping->_buffer[ i ].area.y1 = height - y2;
642            mapping->_buffer[ i ].area.y2 = height - y1;
643        }
644    }
645
646    return mapping;
647}
648
649
650SOM_Scope boolean  SOMLINK isSaveable(LuPopplerDocument *somSelf,
651                                       Environment *ev)
652{
653    return TRUE;
654}
655
656
657SOM_Scope boolean  SOMLINK saveAs(LuPopplerDocument *somSelf,
658                                   Environment *ev, string filename)
659{
660    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData(somSelf);
661    PopplerDocument *document = (PopplerDocument *)somThis->data;
662
663    boolean retval = FALSE;
664
665    if ( filename != NULL ) {
666        retval = document->doc->saveAs( new GooString( filename ) );
667    }
668
669    return retval;
670}
671
672
673SOM_Scope boolean  SOMLINK isPostScriptExportable(LuPopplerDocument *somSelf,
674                                           Environment *ev)
675{
676    return TRUE;
677}
678
679
680SOM_Scope void  SOMLINK exportToPostScript(LuPopplerDocument *somSelf,
681                                    Environment *ev, string filename,
682                                   long first_page, long last_page,
683                                   double width, double height,
684                                   boolean duplex)
685{
686    if ( filename == NULL ) {
687        return;
688    }
689    if ( last_page < first_page ) {
690        return;
691    }
692
693    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData(somSelf);
694    PDFDoc *doc = ((PopplerDocument *)somThis->data)->doc;
695
696
697    PSOutputDev *out = new PSOutputDev( filename, doc->getXRef(),
698                                        doc->getCatalog(),
699                                        first_page + 1, last_page + 1,
700                                        psModePS, (int)width, (int)height,
701                                        duplex, 0, 0, 0, 0, gFalse );
702
703
704    for ( long i = first_page; i < last_page; i++ ) {
705        doc->displayPage( out, i + 1, 72.0, 72.0, 0, gFalse, gTrue, gFalse );
706    }
707
708    delete out;
709}
710
711
712SOM_Scope boolean  SOMLINK isHaveFontInfo(LuPopplerDocument *somSelf,
713                                           Environment *ev)
714{
715    return TRUE;
716}
717
718
719SOM_Scope LuDocument_LuFontInfoSequence*  SOMLINK getFontInfo(LuPopplerDocument *somSelf,
720                                                               Environment *ev)
721{
722    LuDocument_LuFontInfoSequence *fonts = NULL;
723
724    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData(somSelf);
725    PopplerDocument *document = (PopplerDocument *)somThis->data;
726    PDFDoc *doc = document->doc;
727
728    DosRequestMutexSem( document->mutex, SEM_INDEFINITE_WAIT );
729    FontInfoScanner *scanner = new FontInfoScanner( doc );
730    GooList *items = scanner->scan( doc->getNumPages() );
731    delete scanner;
732    DosReleaseMutexSem( document->mutex );
733
734    if ( items == NULL ) {
735        return NULL;
736    }
737
738    int len = items->getLength();
739
740    if ( len == 0 ) {
741        delete items;
742        return NULL;
743    }
744
745    fonts = (LuDocument_LuFontInfoSequence *)SOMMalloc( sizeof( LuDocument_LuFontInfoSequence ) );
746    fonts->_maximum = len;
747    fonts->_length = len;
748    fonts->_buffer = (LuFontInfo *)SOMMalloc( sizeof( LuFontInfo ) * len );
749
750    for ( int i = 0; i < len; i++ )
751    {
752        fonts->_buffer[i].name = NULL;
753        fonts->_buffer[i].type = NULL;
754        fonts->_buffer[i].embedded = NULL;
755
756        FontInfo *info = (FontInfo *)items->get( i );
757
758        // name
759        GooString *gnm = info->getName();
760        if ( gnm != NULL )
761        {
762            char *nm = gnm->getCString();
763            if ( info->getSubset() && ( nm != NULL ) )
764            {
765                while ( *nm && ( *nm != '+' ) ) {
766                    nm++;
767                }
768                if ( *nm ) {
769                    nm++;
770                }
771            }
772            if ( nm != NULL ) {
773                if ( *nm ) {
774                    fonts->_buffer[i].name = somstrdup( nm );
775                }
776            }
777        }
778
779        // type
780        char *t = "Unknown font type";
781        switch ( info->getType() )
782        {
783            case FontInfo::Type1:        t = "Type 1";          break;
784            case FontInfo::Type1C:       t = "Type 1C";         break;
785            case FontInfo::Type3:        t = "Type 3";          break;
786            case FontInfo::TrueType:     t = "TrueType";        break;
787            case FontInfo::CIDType0:     t = "Type 1 (CID)";    break;
788            case FontInfo::CIDType0C:    t = "Type 1C (CID)";   break;
789            case FontInfo::CIDTrueType:  t = "TrueType (CID)";  break;
790        }
791        fonts->_buffer[i].type = somstrdup( t );
792
793        // embedded
794        char *e = NULL;
795        if ( info->getEmbedded() ) {
796            if ( info->getSubset() ) {
797                e = "Embedded subset";
798            } else {
799                e = "Embedded";
800            }
801        } else {
802            e = "Not embedded";
803        }
804        fonts->_buffer[i].embedded = somstrdup( e );
805
806    }
807
808    return fonts;
809}
810
811
812SOM_Scope boolean  SOMLINK isHaveIndex(LuPopplerDocument *somSelf,
813                                        Environment *ev)
814{
815    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData(somSelf);
816    PDFDoc *doc = ((PopplerDocument *)somThis->data)->doc;
817
818    Outline *outline = doc->getOutline();
819    if ( outline == NULL ) {
820        return FALSE;
821    }
822
823    GooList *items = outline->getItems();
824    if ( items == NULL ) {
825        return FALSE;
826    }
827
828    return TRUE;
829}
830
831static char *unicode_to_char( Unicode *unicode, int len )
832{
833    static UnicodeMap *uMap = NULL;
834    if ( uMap == NULL )
835    {
836        GooString *enc = new GooString( "UTF-8" );
837        uMap = globalParams->getUnicodeMap( enc );
838        uMap->incRefCnt();
839        delete enc;
840    }
841
842    GooString gstr;
843    char buf[8]; // 8 is enough for mapping an unicode char to a string
844    int i, n;
845
846    for ( i = 0; i < len; ++i ) {
847        n = uMap->mapUnicode( unicode[i], buf, sizeof( buf ) );
848        gstr.append( buf, n );
849    }
850
851    return newstrdup( gstr.getCString() );
852}
853
854static char *newstrFromUTF8( const char *s )
855{
856    unsigned blen = strlen( s ) + 1;
857    char *b = new char[ blen ];
858    memset( b, 0, blen );
859    char *bsav = b;
860    const char *from = s;
861    unsigned flen = strlen( s );
862    cnvUTF8ToSys( &from, &flen, &b, &blen );
863    return bsav;
864}
865
866static void add_item( Environment *ev, PDFDoc *doc, LuIndexNode *n, GooList *items )
867{
868    if ( items == NULL ) {
869        return;
870    }
871
872    int len = items->getLength();
873
874    for ( int i = 0; i < len; i++ )
875    {
876        OutlineItem *item = (OutlineItem *)items->get( i );
877        LinkAction *link_action = item->getAction();
878        LuLink evlink;
879        char *t1 = unicode_to_char( item->getTitle(), item->getTitleLength() );
880        char *t2 = newstrFromUTF8( t1 );
881        build_link( doc, &evlink, t2, link_action );
882        delete t2;
883        delete t1;
884        LuIndexNode *cn = new LuIndexNode( ev, &evlink );
885        n->addChild( ev, cn );
886
887        item->open();
888        if ( item->hasKids() )
889        {
890            GooList *citems = item->getKids();
891            add_item( ev, doc, cn, citems );
892        }
893    }
894}
895
896SOM_Scope LuIndexNode*  SOMLINK getIndex(LuPopplerDocument *somSelf,
897                                          Environment *ev)
898{
899    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData(somSelf);
900    PDFDoc *doc = ((PopplerDocument *)somThis->data)->doc;
901
902    Outline *outline = doc->getOutline();
903    if ( outline == NULL ) {
904        return NULL;
905    }
906
907    GooList *items = outline->getItems();
908    if ( items == NULL ) {
909        return NULL;
910    }
911
912    LuIndexNode *root = new LuIndexNode( ev, NULL );
913    add_item( ev, doc, root, items );
914
915    return root;
916}
917
918
919static bool has_unicode_marker( GooString *string )
920{
921    return ( ( (string->getChar(0) & 0xff) == 0xfe ) &&
922             ( (string->getChar(1) & 0xff) == 0xff ) );
923}
924
925// return SOMMalloc'ed string
926static char *propcnv( GooString *s )
927{
928    if ( has_unicode_marker( s ) )
929    {
930        unsigned blen = s->getLength() * 2;
931        char *b = (char *)SOMMalloc( blen );
932        memset( b, 0, blen );
933        char *bsav = b;
934        const char *from = s->getCString() + 2;
935        unsigned flen = s->getLength() - 2;
936        cnvUniBEToSys( &from, &flen, &b, &blen );
937        return bsav;
938    }
939
940    return somstrdup( s->getCString() );
941}
942
943static time_t propToDate( const char *date_string )
944{
945    int year, mon, day, hour, min, sec;
946    int scanned_items;
947
948    // See PDF Reference 1.3, Section 3.8.2 for PDF Date representation
949    if ( ( date_string[0] == 'D' ) && ( date_string[1] == ':' ) ) {
950        date_string += 2;
951    }
952
953    // FIXME only year is mandatory; parse optional timezone offset
954    scanned_items = sscanf( date_string, "%4d%2d%2d%2d%2d%2d",
955                            &year, &mon, &day, &hour, &min, &sec);
956
957    if ( scanned_items != 6 ) {
958        return (time_t)(-1);
959    }
960
961    // Workaround for y2k bug in Distiller 3, hoping that it won't
962    // be used after y2.2k
963    if ( ( year < 1930 ) && ( strlen( date_string ) > 14 ) )
964    {
965        int century, years_since_1900;
966        scanned_items = sscanf( date_string, "%2d%3d%2d%2d%2d%2d%2d",
967                &century, &years_since_1900, &mon, &day, &hour, &min, &sec );
968
969        if ( scanned_items != 7 ) {
970            return (time_t)(-1);
971        }
972
973        year = century * 100 + years_since_1900;
974    }
975
976    struct tm time = { 0 };
977    time.tm_year  = year - 1900;
978    time.tm_mon   = mon - 1;
979    time.tm_mday  = day;
980    time.tm_hour  = hour;
981    time.tm_min   = min;
982    time.tm_sec   = sec;
983    time.tm_wday  = -1;
984    time.tm_yday  = -1;
985    time.tm_isdst = -1; // 0 = DST off, 1 = DST on, -1 = don't know
986
987    return mktime( &time );
988}
989
990static long convPageMode( Catalog::PageMode pageMode )
991{
992    switch ( pageMode )
993    {
994        case Catalog::pageModeThumbs:
995            return LU_DOCUMENT_MODE_USE_THUMBS;
996        case Catalog::pageModeFullScreen:
997            return LU_DOCUMENT_MODE_FULL_SCREEN;
998        case Catalog::pageModeOC:
999            return LU_DOCUMENT_MODE_USE_OC;
1000        case Catalog::pageModeAttach:
1001            return LU_DOCUMENT_MODE_USE_ATTACHMENTS;
1002        case Catalog::pageModeNone:
1003            return LU_DOCUMENT_MODE_NONE;
1004    }
1005
1006    return -1;
1007}
1008
1009static long convLayout( Catalog::PageLayout pageLayout )
1010{
1011    switch ( pageLayout )
1012    {
1013        case Catalog::pageLayoutSinglePage:
1014            return LU_DOCUMENT_LAYOUT_SINGLE_PAGE;
1015        case Catalog::pageLayoutOneColumn:
1016            return LU_DOCUMENT_LAYOUT_ONE_COLUMN;
1017        case Catalog::pageLayoutTwoColumnLeft:
1018            return LU_DOCUMENT_LAYOUT_TWO_COLUMN_LEFT;
1019        case Catalog::pageLayoutTwoColumnRight:
1020            return LU_DOCUMENT_LAYOUT_TWO_COLUMN_RIGHT;
1021        case Catalog::pageLayoutTwoPageLeft:
1022            return LU_DOCUMENT_LAYOUT_TWO_PAGE_LEFT;
1023        case Catalog::pageLayoutTwoPageRight:
1024            return LU_DOCUMENT_LAYOUT_TWO_PAGE_RIGHT;
1025    }
1026    return -1;
1027}
1028
1029SOM_Scope LuDocumentInfo*  SOMLINK getDocumentInfo(LuPopplerDocument *somSelf,
1030                                                    Environment *ev)
1031{
1032    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData(somSelf);
1033    PDFDoc *doc = ((PopplerDocument *)somThis->data)->doc;
1034
1035    LuDocumentInfo *info = (LuDocumentInfo *)SOMMalloc( sizeof( LuDocumentInfo ) );
1036    memset( info, 0, sizeof( LuDocumentInfo ) );
1037
1038    Object objdict;
1039    doc->getDocInfo( &objdict );
1040    if ( objdict.isDict() )
1041    {
1042        Dict *d = objdict.getDict();
1043        Object obj;
1044
1045        if ( d->lookup( "Title", &obj )->isString() ) {
1046            info->title = propcnv( obj.getString() );
1047            info->fields_mask |= LU_DOCUMENT_INFO_TITLE;
1048        }
1049        obj.free();
1050        if ( d->lookup( "Author", &obj )->isString() ) {
1051            info->author = propcnv( obj.getString() );
1052            info->fields_mask |= LU_DOCUMENT_INFO_AUTHOR;
1053        }
1054        obj.free();
1055        if ( d->lookup( "Subject", &obj )->isString() ) {
1056            info->subject = propcnv( obj.getString() );
1057            info->fields_mask |= LU_DOCUMENT_INFO_SUBJECT;
1058        }
1059        obj.free();
1060        if ( d->lookup( "Keywords", &obj )->isString() ) {
1061            info->keywords = propcnv( obj.getString() );
1062            info->fields_mask |= LU_DOCUMENT_INFO_KEYWORDS;
1063        }
1064        obj.free();
1065        if ( d->lookup( "Creator", &obj )->isString() ) {
1066            info->creator = propcnv( obj.getString() );
1067            info->fields_mask |= LU_DOCUMENT_INFO_CREATOR;
1068        }
1069        obj.free();
1070        if ( d->lookup( "Producer", &obj )->isString() ) {
1071            info->producer = propcnv( obj.getString() );
1072            info->fields_mask |= LU_DOCUMENT_INFO_PRODUCER;
1073        }
1074        obj.free();
1075        if ( d->lookup( "CreationDate", &obj )->isString() ) {
1076            char *d = propcnv( obj.getString() );
1077            info->creation_date = propToDate( d );
1078            if ( (long)info->creation_date != -1 ) {
1079                info->fields_mask |= LU_DOCUMENT_INFO_CREATION_DATE;
1080            }
1081            SOMFree( d );
1082        }
1083        obj.free();
1084        if ( d->lookup( "ModDate", &obj )->isString() ) {
1085            char *d = propcnv( obj.getString() );
1086            info->modified_date = propToDate( d );
1087            if ( (long)info->modified_date != -1 ) {
1088                info->fields_mask |= LU_DOCUMENT_INFO_MOD_DATE;
1089            }
1090            SOMFree( d );
1091        }
1092        obj.free();
1093    }
1094
1095    char *format = (char *)SOMMalloc( 16 );
1096    snprintf( format, 16, "PDF-%.2f", doc->getPDFVersion() );
1097    info->format = format;
1098    info->fields_mask |= LU_DOCUMENT_INFO_FORMAT;
1099
1100    info->linearized = doc->isLinearized();
1101    info->fields_mask |= LU_DOCUMENT_INFO_LINEARIZED;
1102
1103    Catalog *catalog = doc->getCatalog();
1104
1105    if ( ( catalog != NULL ) && catalog->isOk() )
1106    {
1107        info->layout = convLayout( catalog->getPageLayout() );
1108        if ( info->layout != -1 ) {
1109            info->fields_mask |= LU_DOCUMENT_INFO_LAYOUT;
1110        }
1111
1112        info->mode = convPageMode( catalog->getPageMode() );
1113        if ( info->mode != -1 ) {
1114            info->fields_mask |= LU_DOCUMENT_INFO_START_MODE;
1115        }
1116    }
1117
1118    info->fields_mask |= LU_DOCUMENT_INFO_PERMISSIONS;
1119    if ( doc->okToPrint() ) {
1120        info->permissions |= LU_DOCUMENT_PERMISSIONS_OK_TO_PRINT;
1121    }
1122    if ( doc->okToChange() ) {
1123        info->permissions |= LU_DOCUMENT_PERMISSIONS_OK_TO_MODIFY;
1124    }
1125    if ( doc->okToCopy() ) {
1126        info->permissions |= LU_DOCUMENT_PERMISSIONS_OK_TO_COPY;
1127    }
1128    if ( doc->okToAddNotes() ) {
1129        info->permissions |= LU_DOCUMENT_PERMISSIONS_OK_TO_ADD_NOTES;
1130    }
1131
1132    info->n_pages = doc->getNumPages();
1133    info->fields_mask |= LU_DOCUMENT_INFO_N_PAGES;
1134
1135    return info;
1136}
1137
1138
1139SOM_Scope boolean  SOMLINK getThumbnailSize(LuPopplerDocument *somSelf,
1140                                             Environment *ev,
1141                                            long pagenum,
1142                                            short suggested_width,
1143                                            short* width, short* height)
1144{
1145    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData(somSelf);
1146    Page *page = ((PopplerDocument *)somThis->data)->pages[ pagenum ].page;
1147
1148    Object thumb;
1149    Dict *dict;
1150    boolean retval = FALSE;
1151
1152    page->getThumb( &thumb );
1153    if ( thumb.isNull() )
1154    {
1155        thumb.free();
1156        return FALSE;
1157    }
1158
1159    dict = thumb.streamGetDict();
1160
1161    // Theoretically, this could succeed and you would still fail when
1162    // loading the thumb
1163    int w = 0, h = 0;
1164    if ( dict->lookupInt( "Width", "W", &w ) && dict->lookupInt( "Height", "H", &h ) )
1165    {
1166        if ( width != NULL ) {
1167            *width = w;
1168        }
1169        if ( height != NULL ) {
1170            *height = h;
1171        }
1172
1173        retval = TRUE;
1174    }
1175
1176    thumb.free();
1177
1178    return retval;
1179}
1180
1181SOM_Scope LuPixbuf*  SOMLINK getThumbnail(LuPopplerDocument *somSelf,
1182                                           Environment *ev, long pagenum,
1183                                          short suggested_width)
1184{
1185    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData(somSelf);
1186    Page *page = ((PopplerDocument *)somThis->data)->pages[ pagenum ].page;
1187
1188    unsigned char *data;
1189    int width, height, rowstride;
1190
1191    if ( !page->loadThumb( &data, &width, &height, &rowstride ) ) {
1192        return NULL;
1193    }
1194
1195    short bpp = getBpp( somSelf, ev );
1196    LuPixbuf *pixbuf = new LuPixbuf( ev, width, height, bpp );
1197    char *pixbuf_data = (char *)pixbuf->getDataPtr( ev );
1198    int pixbuf_rowstride = pixbuf->getRowSize( ev );
1199    char *src, *dst;
1200    int i, j;
1201    for ( i = 0, j = ( height - 1 ); i < height; i++, j-- )
1202    {
1203        src = data + ( j * rowstride );
1204        dst = pixbuf_data + (i * pixbuf_rowstride);
1205        for ( int k = 0; k < pixbuf_rowstride; k += bpp )
1206        {
1207            dst[ k ]     = src[ k + 2 ];
1208            dst[ k + 1 ] = src[ k + 1 ];
1209            dst[ k + 2 ] = src[ k ];
1210        }
1211    }
1212    gfree( data );
1213
1214    return pixbuf;
1215}
1216
1217
1218SOM_Scope LuDocument_LuRectSequence*  SOMLINK searchText(LuPopplerDocument *somSelf,
1219                                                          Environment *ev,
1220                                                         long pagenum,
1221                                                         string text,
1222                                                         boolean caseSensitive)
1223{
1224    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData(somSelf);
1225    PopplerDocument *document = (PopplerDocument *)somThis->data;
1226    Page *page = document->pages[ pagenum ].page;
1227
1228    DosRequestMutexSem( document->mutex, SEM_INDEFINITE_WAIT );
1229    TextOutputDev *output_dev = new TextOutputDev( NULL, gTrue, gFalse, gFalse );
1230    page->display( output_dev, 72, 72, 0, gFalse,
1231                   gTrue, NULL, document->doc->getCatalog() );
1232    DosReleaseMutexSem( document->mutex );
1233
1234
1235    // Convert string from system encoding to UCS-4
1236    // first, convert to UCS-2
1237    unsigned text_len = strlen( text );
1238    unsigned text_len_sav = text_len;
1239    unsigned ucs2_len = ( text_len + 1 ) * 2;
1240    char *ucs2 = new char[ ucs2_len ];
1241    memset( ucs2, 0, ucs2_len );
1242    char *ucs2sav = ucs2;
1243    cnvSysToUCS2( (const char **)&text, &text_len, &ucs2, &ucs2_len );
1244    // second, convert UCS-2 to UCS-4
1245    short *uucs2 = (short *)ucs2sav;
1246    unsigned ucs4_len = ( text_len_sav + 1 ) * 2;
1247    unsigned *ucs4 = new unsigned[ ucs4_len ];
1248    memset( ucs4, 0, ucs4_len * sizeof( unsigned ) );
1249    int real_ucs4_len = 0;
1250    for ( real_ucs4_len = 0; *uucs2; real_ucs4_len++ ) {
1251        ucs4[ real_ucs4_len ] = *uucs2++;
1252    }
1253    delete ucs2sav;
1254    // conversion end
1255
1256    RectList *rl = new RectList;
1257    double xMin, yMin, xMax, yMax;
1258    xMin = 0;
1259    yMin = 0;
1260    while ( output_dev->findText( ucs4, real_ucs4_len,
1261                   gFalse, gTrue, // startAtTop, stopAtBottom
1262                   gTrue, gFalse, // startAtLast, stopAtLast
1263                   caseSensitive, gFalse, // caseSensitive, backwards
1264                   &xMin, &yMin, &xMax, &yMax ) )
1265    {
1266        LuRectangle r;
1267        r.x1 = xMin;
1268        r.y1 = yMin;
1269        r.x2 = xMax;
1270        r.y2 = yMax;
1271        rl->push_back( r );
1272    }
1273    delete ucs4;
1274    delete output_dev;
1275
1276    LuDocument_LuRectSequence *rectangles = NULL;
1277    int len = rl->size();
1278    if ( len > 0 )
1279    {
1280        rectangles = (LuDocument_LuRectSequence *)SOMMalloc( sizeof( LuDocument_LuRectSequence ) );
1281        rectangles->_maximum = len;
1282        rectangles->_length = len;
1283        rectangles->_buffer = (LuRectangle *)SOMMalloc( sizeof( LuRectangle ) * len );
1284
1285        for ( int i = 0; i < len; i++ )
1286        {
1287            rectangles->_buffer[ i ].x1 = (*rl)[i].x1;
1288            rectangles->_buffer[ i ].y1 = (*rl)[i].y1;
1289            rectangles->_buffer[ i ].x2 = (*rl)[i].x2;
1290            rectangles->_buffer[ i ].y2 = (*rl)[i].y2;
1291        }
1292    }
1293    delete rl;
1294
1295    return rectangles;
1296}
1297
1298
1299SOM_Scope void SOMLINK somDefaultInit(LuPopplerDocument *somSelf,
1300                                      som3InitCtrl* ctrl)
1301{
1302    // generated section - do not modify
1303    LuPopplerDocumentData *somThis;
1304    somInitCtrl globalCtrl;
1305    somBooleanVector myMask;
1306    LuPopplerDocument_BeginInitializer_somDefaultInit;
1307    LuPopplerDocument_Init_LuDocument_somDefaultInit(somSelf, ctrl);
1308    // end of generated section
1309
1310    // local LuPopplerDocument initialization code
1311    PopplerDocument *d = new PopplerDocument;
1312    somThis->data = d;
1313}
1314
1315
1316static void set_error( char **error, const char *fmt, ... )
1317{
1318    if ( error == NULL ) {
1319        return;
1320    }
1321
1322    va_list argptr;
1323    va_start( argptr, fmt );
1324    char *msg = new char[ 1000 ];
1325    vsnprintf( msg, 1000, fmt, argptr );
1326    *error = somstrdup( msg );
1327    delete msg;
1328}
1329
1330
1331SOM_Scope boolean  SOMLINK loadFile(LuPopplerDocument *somSelf,
1332                                    Environment *ev, string filename,
1333                                    string password, string* error)
1334{
1335    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData( somSelf );
1336
1337    PDFDoc *newDoc;
1338    GooString *filename_g;
1339    GooString *password_g;
1340    int err;
1341
1342    if ( !globalParams ) {
1343        globalParams = new GlobalParams( NULL );
1344    }
1345
1346    filename_g = new GooString(filename);
1347
1348    password_g = NULL;
1349    if (password != NULL) {
1350        password_g = new GooString(password);
1351    }
1352
1353    newDoc = new PDFDoc(filename_g, password_g, password_g);
1354    if (password_g) {
1355        delete password_g;
1356    }
1357
1358    if (!newDoc->isOk()) {
1359        err = newDoc->getErrorCode();
1360        delete newDoc;
1361
1362        if (err == errEncrypted) {
1363            set_error(error, "Document is encrypted.");
1364        } else {
1365            set_error(error, "Failed to load document (error %d) '%s'\n", err, filename );
1366        }
1367
1368        return FALSE;
1369    }
1370
1371    PopplerDocument *document = (PopplerDocument *)somThis->data;
1372
1373    document->doc = newDoc;
1374    SplashColor white;
1375    white[0] = 255;
1376    white[1] = 255;
1377    white[2] = 255;
1378    document->output_dev = new SplashOutputDev( splashModeBGR8, 4, gFalse, white );
1379    document->output_dev->startDoc( document->doc->getXRef() );
1380
1381    long numpages = document->doc->getNumPages();
1382    document->pages = new PopplerPage[ numpages ];
1383    for ( long pagenum = 0; pagenum < numpages; pagenum++ ) {
1384        document->pages[ pagenum ].page =
1385            document->doc->getCatalog()->getPage( pagenum + 1 );
1386    }
1387
1388    return TRUE;
1389}
1390
1391
1392SOM_Scope void SOMLINK somDestruct(LuPopplerDocument *somSelf,
1393                                   octet doFree, som3DestructCtrl* ctrl)
1394{
1395    LuPopplerDocumentData *somThis;
1396    somDestructCtrl globalCtrl;
1397    somBooleanVector myMask;
1398    LuPopplerDocument_BeginDestructor;
1399
1400    // local LuPopplerDocument deinitialization code
1401    PopplerDocument *document = (PopplerDocument *)somThis->data;
1402    delete document;
1403    // end of local LuPopplerDocument deinitialization code
1404
1405    LuPopplerDocument_EndDestructor;
1406}
1407
1408
Note: See TracBrowser for help on using the repository browser.