2 * Wrap poppler document class functions into c functions.
7 #define AROS_ALMOST_COMPATIBLE
11 #if defined(__MORPHOS__)
12 #include <proto/charsets.h>
15 #include <proto/keymap.h>
16 #include <proto/exec.h>
17 #include <proto/dos.h>
18 #include <proto/graphics.h>
19 #include <clib/debug_protos.h>
20 #include <exec/semaphores.h>
21 #include <exec/lists.h>
22 #include <constructor.h>
27 #include <poppler-config.h>
39 #include "GlobalParams.h"
40 #include "PDFDocEncoding.h"
41 #include "goo/GooList.h"
45 #include "splash/SplashBitmap.h"
46 #include "splash/Splash.h"
47 #include "SplashOutputDev.h"
48 #include "TextOutputDev.h"
50 #include "CairoOutputDev.h"
52 #include "PSOutputDev.h"
55 #include "poppler_io.h"
56 #include "poppler_device.h"
60 typedef wchar_t WCHAR
;
61 #include <aros/debug.h>
64 extern struct Library
*LocaleBase
;
65 #define LOCALE_BASE_NAME LocaleBase
67 #warning TODO: make the semaphore per-document
69 struct SignalSemaphore semaphore
;
71 #if defined(__MORPHOS__)
72 // AROS has static linklib
73 extern struct Library
*CairoBase
;
76 /* all of this is just to not having to expose GBool in ppoppler.h... */
78 struct abortcallbackcontext
80 int (*userfunction
)(void *);
82 struct devicecontext
*ctx
;
85 /* this is bit hacky but we can't/shouldn't use boopsi in poppler.c */
90 void vpdfErrorFunction(int pos
, char *message
);
93 static void pdfErrorFunction(void *data
, ErrorCategory category
, Goffset pos
, char *msg
)
95 vpdfErrorFunction(pos
, msg
);
98 static CONSTRUCTOR_P(init_poppler
, 0)
100 InitSemaphore(&semaphore
);
101 setErrorCallback(pdfErrorFunction
, NULL
);
102 #if defined(__AROS__)
109 static DESTRUCTOR_P(cleanup_poppler
, 0)
111 D(kprintf("destroy poppler:%p\n", &semaphore
));
115 #define ENTER_SECTION \
116 { ObtainSemaphore(&semaphore);}
117 #else // time delay needed to enter critical section
118 #define ENTER_SECTION \
119 { clock_t t0 = clock(); ObtainSemaphore(&semaphore); t0 = clock() - t0; kprintf("section enter:%f:%s\n", (float)t0/CLOCKS_PER_SEC, __FUNCTION__);}
122 //#define ENTER_SECTION
123 #define LEAVE_SECTION ReleaseSemaphore(&semaphore);
124 //#define LEAVE_SECTION
126 //struct Library *CairoBase;
134 ({typeof(a) _a = (a); \
135 typeof(b) _b = (b); \
136 _a < _b ? _a : _b; })
139 ({typeof(a) _a = (a); \
140 typeof(b) _b = (b); \
141 _a > _b ? _a : _b; })
145 /// utility functions
147 static char *convertUTF16ToANSI(unsigned char *string
, int length
)
149 char *buff
= (char*)calloc(1, length
+ 1);
150 #if defined(__AROS__)
151 kprintf("[convertUTF16ToANSI] not implemented\n");
155 ConvertTagList((unsigned char*)string
+ 2, length
* 2 - 2, buff
, length
+ 1, MIBENUM_UTF_16BE
, MIBENUM_SYSTEM
, NULL
);
161 static char *convertUTF32ToANSI(Unicode
*string
, int length
)
163 char *buff
= (char*)calloc(1, length
+ 1);
164 #if defined(__AROS__)
165 kprintf("[convertUTF32ToANSI] not implemented\n");
169 ConvertTagList((unsigned char*)string
, length
* 4, buff
, length
+ 1, MIBENUM_UTF_32BE
, MIBENUM_SYSTEM
, NULL
);
176 static WCHAR
*convertToUCS4(const char *string
)
178 size_t length
= strlen(string
);
181 WCHAR
*buff
= (WCHAR
*)calloc(sizeof(WCHAR
), length
+ 1);
182 #if defined(__AROS__)
183 kprintf("[convertToUCS4] not implemented\n");
188 for(i
= 0; i
< length
; i
++)
189 buff
[i
] = ToUCS4(string
[i
], NULL
);
196 static char *convertToANSI(GooString
*s
)
198 if(s
->hasUnicodeMarker())
200 //printf("has unicode marker\n");
201 return convertUTF16ToANSI((unsigned char*)s
->getCString(), s
->getLength() - 2);
205 char *buffer
= (char*)calloc(1, s
->getLength() + 1);
208 //printf("no unicode marker\n");
209 for(i
= 0; i
< s
->getLength(); ++i
)
210 buffer
[i
] = s
->getChar(i
);
225 void *pdfNew(const char *fname
)
228 //CairoBase = OpenLibrary("cairo.library", 0);
230 //StackFrame[-1].LR-> Address 0x26870dd4 -> vpdf Hunk 1 Offset 0x00001284
231 //StackFrame[-2].LR-> Address 0x2686ff34 -> vpdf Hunk 1 Offset 0x000003e4
233 #if !defined(__AROS__) && !defined(USE_SPLASH)
234 kprintf("Cairo Base:%p. sema:%p, %p, %p\n", CairoBase
, &semaphore
, foo
, &foo
);
237 struct devicecontext
*ctx
= (struct devicecontext
*)calloc(1, sizeof(*ctx
));
250 if(globalParams
== NULL
)
252 globalParams
= new GlobalParams();
253 globalParams
->setScreenType(screenClustered
);
254 globalParams
->setScreenSize(3);
255 //globalParams->setPSBinary(true);
258 CachedFile
*cachedFile
= new CachedFile(new StdCacheLoader(), new GooString(fname
));
259 D(kprintf("pdf file opened...\n"));
260 ctx
->stream
= new CachedFileStream(cachedFile
, 0, gTrue
, cachedFile
->getLength(), &obj
);
261 D(kprintf("pdf stream created..\n"));
262 ctx
->doc
= new PDFDoc(ctx
->stream
, NULL
, NULL
);
263 D(kprintf("document opened...\n"));
265 if(ctx
->doc
== NULL
|| !ctx
->doc
->isOk() || ctx
->doc
->getNumPages() == 0)
267 D(kprintf("failed to open a document:%p...\n", ctx
->doc
));
274 SplashColor paperColor
;
280 ctx
->dev
= new SplashOutputDev(splashModeRGB8
, 4, gFalse
, paperColor
);
281 ctx
->dev
->startDoc(ctx
->doc
);
283 ctx
->dev
= new CairoOutputDev();
284 ctx
->dev
->setPrinting(false);
286 ctx
->dev
->startDoc(ctx
->doc
);
288 D(kprintf("media_box:%f,%f\n", ctx
->doc
->getPageMediaWidth(1), ctx
->doc
->getPageMediaHeight(1)));
289 D(kprintf("media_box:%f, %f\n", pdfGetPageMediaWidth(ctx
, 1), pdfGetPageMediaHeight(ctx
, 1)));
291 NEWLIST(&ctx
->search
.searchresultlist
);
293 /* cache some common values to remove need for locking */
294 ctx
->pagesnum
= ctx
->doc
->getNumPages();
295 ctx
->documentwidth
= ctx
->documentheight
= 0.0f
;
297 for(i
= 0; i
< ctx
->pagesnum
; i
++)
299 Page
*pdfpage
= ctx
->doc
->getCatalog()->getPage(i
+ 1);
300 int rotate
= pdfpage
->getRotate();
302 if(rotate
== 90 || rotate
== 270)
304 width
= pdfpage
->getMediaHeight();
305 height
= pdfpage
->getMediaWidth();
309 width
= pdfpage
->getMediaWidth();
310 height
= pdfpage
->getMediaHeight();
313 ctx
->documentwidth
= MAX(ctx
->documentwidth
, width
);
314 ctx
->documentheight
= MAX(ctx
->documentheight
, height
);
319 D(kprintf("exception while opening pdf document\n"));
330 void pdfDelete(void *_ctx
)
332 struct devicecontext
*ctx
= (struct devicecontext
*)_ctx
;
337 D(kprintf("delete output device:%p.\n", ctx
->dev
));
342 if (ctx
->selection_dev
!= NULL
)
343 delete ctx
->selection_dev
;
345 #if !defined(USE_SPLASH)
346 D(kprintf("delete surface:%p.\n", ctx
->surface
));
348 if(ctx
->surface
!= NULL
)
350 cairo_create(ctx
->surface
);
351 cairo_surface_destroy(ctx
->surface
);
355 D(kprintf("delete document\n"));
359 // Stream is disposed with document
360 //if (ctx->stream != NULL)
361 // delete ctx->stream;
364 //CloseLibrary(CairoBase);
368 float pdfGetPageMediaWidth(void *_ctx
, int page
)
371 struct devicecontext
*ctx
= (struct devicecontext
*)_ctx
;
372 //float width = ctx->doc->getPageMediaWidth(page);
373 Page
*pdfpage
= ctx
->doc
->getCatalog()->getPage(page
);
374 int rotate
= pdfpage
->getRotate();
376 if(rotate
== 90 || rotate
== 270)
377 width
= pdfpage
->getMediaHeight();
379 width
= pdfpage
->getMediaWidth();
384 float pdfGetPageMediaHeight(void *_ctx
, int page
)
387 struct devicecontext
*ctx
= (struct devicecontext
*)_ctx
;
388 Page
*pdfpage
= ctx
->doc
->getCatalog()->getPage(page
);
389 //float height = ctx->doc->getPageMediaHeight(page);
390 int rotate
= pdfpage
->getRotate();
392 if(rotate
== 90 || rotate
== 270)
393 height
= pdfpage
->getMediaWidth();
395 height
= pdfpage
->getMediaHeight();
400 int pdfGetDocumentDimensions(void *_ctx
, float *width
, float *height
)
402 struct devicecontext
*ctx
= (struct devicecontext
*)_ctx
;
404 *width
= ctx
->documentwidth
;
405 *height
= ctx
->documentheight
;
409 int pdfGetPagesNum(void *_ctx
)
411 struct devicecontext
*ctx
= (struct devicecontext
*)_ctx
;
412 return ctx
->pagesnum
;
415 static GBool
abortcheckcbk_wrapper(void *data
)
417 struct abortcallbackcontext
*abortctx
= (struct abortcallbackcontext
*)data
;
418 if (abortctx
->userfunction
!= NULL
)
419 return (GBool
)abortctx
->userfunction(abortctx
->userdata
);
421 //D(printf("abort check...\n"));
426 static void applyrotation(int *width
, int *height
, int rotation
)
428 if(rotation
== 90 || rotation
== 270)
436 int pdfDisplayPageSlice(void *_ctx
, int page
, double scale
, int rotate
,
437 int useMediaBox
, int crop
, int printing
, int sliceX
, int sliceY
, int sliceW
, int sliceH
, int (*abortcheckcbk
)(void *), void *abortcheckcbkdata
)
441 struct devicecontext
*ctx
= (struct devicecontext
*)_ctx
;
442 Page
*pdfpage
= ctx
->doc
->getCatalog()->getPage(page
);
443 int cropwidth
= (int)pdfGetPageMediaWidth(ctx
, page
);
444 int cropheight
= (int)pdfGetPageMediaHeight(ctx
, page
);
445 int width
= (int)ceil(cropwidth
* scale
);
446 int height
= (int)ceil(cropheight
* scale
);
449 applyrotation(&width
, &height
, rotate
);
450 applyrotation(&cropwidth
, &cropheight
, rotate
);
455 if(ctx
->surface
!= NULL
)
457 if(cairo_image_surface_get_width(ctx
->surface
) != width
|| cairo_image_surface_get_height(ctx
->surface
) != height
)
459 //cairo_destroy(ctx->cairo);
460 cairo_surface_destroy(ctx
->surface
);
465 if(ctx
->surface
== NULL
)
467 ctx
->surface
= cairo_image_surface_create(CAIRO_FORMAT_ARGB32
, width
, height
);
470 if(ctx
->surface
== NULL
)
476 ctx
->cairo
= cairo_create(ctx
->surface
);
479 //cairo_font_options_t *options = cairo_font_options_create ();
480 //cairo_get_font_options (ctx->cairo, options);
481 //cairo_font_options_set_antialias (options, CAIRO_ANTIALIAS_SUBPIXEL);
482 //cairo_font_options_set_subpixel_order (options, CAIRO_SUBPIXEL_ORDER_BGR);
483 //cairo_set_font_options (ctx->cairo, options);
484 //cairo_font_options_destroy (options);
487 cairo_save(ctx
->cairo
);
488 cairo_set_source_rgba(ctx
->cairo
, 1., 1., 1., 1);
489 cairo_paint(ctx
->cairo
);
490 cairo_restore(ctx
->cairo
);
491 ctx
->dev
->setCairo(ctx
->cairo
);
495 //cairo_save(ctx->cairo);
496 //printf("render:%d, %d, crop:%d, %d\n", width, height, cropwidth, cropheight);
499 struct abortcallbackcontext abortctx
;
500 abortctx
.userfunction
= abortcheckcbk
;
501 abortctx
.userdata
= abortcheckcbkdata
;
504 pdfpage
->displaySlice(ctx
->dev
, 72 * scale
, 72 * scale
, rotate
, gTrue
, gFalse
, sliceX
, sliceY
, sliceW
, sliceH
,
505 printing
, abortcheckcbk_wrapper
, &abortctx
);
510 D(kprintf("Exception during page rendering\n"));
513 //cairo_restore(ctx->cairo);
517 ctx
->dev
->setCairo(NULL
);
518 cairo_destroy(ctx
->cairo
);
521 //doc->displayPage(dev, page, hDPI, vDPI, rotate, useMediaBox, crop, printing);
528 unsigned char *pdfGetBitmapRowData(void *_ctx
, int row
)
530 struct devicecontext
*ctx
= (struct devicecontext
*)_ctx
;
532 return ctx
->dev
->getBitmap()->getDataPtr() + ctx
->dev
->getBitmap()->getRowSize() * row
;
534 //printf("getrow:%d\n", row);
535 unsigned char *data
= cairo_image_surface_get_data(ctx
->surface
);
536 data
= data
+ cairo_image_surface_get_stride(ctx
->surface
) * row
;
537 //printf("done:%d, %p\n", row, data);
542 int pdfGetBitmapWidth(void *_ctx
)
544 struct devicecontext
*ctx
= (struct devicecontext
*)_ctx
;
546 return ctx
->dev
->getBitmap()->getWidth();
548 return cairo_image_surface_get_width(ctx
->surface
);
552 int pdfGetBitmapHeight(void *_ctx
)
554 struct devicecontext
*ctx
= (struct devicecontext
*)_ctx
;
556 return ctx
->dev
->getBitmap()->getHeight();
558 return cairo_image_surface_get_height(ctx
->surface
);
562 void pdfGetBitmap(void *_ctx
, struct pdfBitmap
*bm
)
564 struct devicecontext
*ctx
= (struct devicecontext
*)_ctx
;
565 bm
->width
= pdfGetBitmapWidth(_ctx
);
566 bm
->height
= pdfGetBitmapHeight(_ctx
);
567 bm
->stride
= cairo_image_surface_get_stride(ctx
->surface
);
568 bm
->data
= cairo_image_surface_get_data(ctx
->surface
);
571 void pdfDisposeRegionForSelection(void *_ctx
, struct pdfSelectionRegion
*region
)
576 void pdfDisposeTextForSelection(void *_ctx
, struct pdfSelectionText
*text
)
581 struct pdfSelectionRegion
*pdfBuildRegionForSelection(void *_ctx
, int page
, double x1
, double y1
, double x2
, double y2
, struct pdfSelectionRegion
*previous
)
585 struct devicecontext
*ctx
= (struct devicecontext
*)_ctx
;
586 Page
*pdfpage
= ctx
->doc
->getCatalog()->getPage(page
);
587 double cropwidth
= pdfGetPageMediaWidth(ctx
, page
);
588 double cropheight
= pdfGetPageMediaHeight(ctx
, page
);
590 TextOutputDev
*text_dev
;
592 if (ctx
->selection_dev
== NULL
)
593 text_dev
= ctx
->selection_dev
= new TextOutputDev(NULL
, gTrue
, 0, gFalse
, gFalse
);
595 text_dev
= ctx
->selection_dev
;
597 if (page
!= ctx
->selection_pagenum
)
598 pdfpage
->display(text_dev
, 72, 72, 0, gTrue
, gTrue
, gFalse
);
600 ctx
->selection_pagenum
= page
;
602 PDFRectangle
rect(x1
* cropwidth
, y1
* cropheight
, x2
* cropwidth
, y2
* cropheight
);
603 GooList
*list
= text_dev
->getSelectionRegion(&rect
, selectionStyleGlyph
, 1.0f
);
605 /* use gfx.lib region functions to merge all pdf rectangles. this sucks a bit but hopefuly using scaled coords will be fine */
607 struct Region
*region
= NewRegion();
609 const float scale
= (float)(1<<12);
611 D(kprintf("source region:%f, %f, %f, %f\n", x1
,y1
,x2
,y2
));
613 for (i
= 0; i
< list
->getLength(); i
++)
617 PDFRectangle
*selection_rect
= (PDFRectangle
*) list
->get(i
);
618 rect
.MinX
= (int)(selection_rect
->x1
* scale
/ cropwidth
);
619 rect
.MinY
= (int)(selection_rect
->y1
* scale
/ cropheight
);
620 rect
.MaxX
= rect
.MinX
+ (int)((selection_rect
->x2
- selection_rect
->x1
) * scale
/ cropwidth
);
621 rect
.MaxY
= rect
.MinY
+ (int)((selection_rect
->y2
- selection_rect
->y1
) * scale
/ cropheight
);
622 D(kprintf("reg:%d, %d, %d, %d, %f, %f, %f, %f\n", rect
.MinX
, rect
.MinY
, rect
.MaxX
, rect
.MaxY
, selection_rect
->x1
/cropwidth
, selection_rect
->y1
/cropheight
, selection_rect
->x2
/cropwidth
, selection_rect
->y2
/cropheight
));
624 OrRectRegion(region
, &rect
);
625 delete selection_rect
;
628 /* convert gfx.lib region to pdfregion and return to the caller */
633 RegionRectangle
*rrect
;
635 D(kprintf("count regions...\n"));
636 for(numrects
= 0, rrect
= region
->RegionRectangle
; rrect
!= NULL
; rrect
= rrect
->Next
, numrects
++) {};
638 struct pdfSelectionRegion
*selection
= (struct pdfSelectionRegion
*)malloc(sizeof(struct pdfSelectionRegion
) + numrects
* sizeof(struct pdfSelectionRectangle
));
639 if (selection
!= NULL
)
641 rrect
= region
->RegionRectangle
;
643 D(kprintf("build selection rectangles...\n"));
650 Rectangle rect
= rrect
->bounds
;
651 struct pdfSelectionRectangle
*pdfrect
= &selection
->rectangles
[rectind
++];
653 rect
.MinX
+= region
->bounds
.MinX
;
654 rect
.MinY
+= region
->bounds
.MinY
;
655 rect
.MaxX
+= region
->bounds
.MinX
;
656 rect
.MaxY
+= region
->bounds
.MinY
;
658 pdfrect
->x1
= rect
.MinX
/ scale
;
659 pdfrect
->y1
= rect
.MinY
/ scale
;
660 pdfrect
->x2
= rect
.MaxX
/ scale
;
661 pdfrect
->y2
= rect
.MaxY
/ scale
;
665 selection
->numrects
= numrects
;
668 DisposeRegion(region
);
675 struct pdfSelectionText
*pdfBuildTextForSelection(void *_ctx
, int page
, double x1
, double y1
, double x2
, double y2
)
679 struct devicecontext
*ctx
= (struct devicecontext
*)_ctx
;
680 Page
*pdfpage
= ctx
->doc
->getCatalog()->getPage(page
);
681 double cropwidth
= pdfGetPageMediaWidth(ctx
, page
);
682 double cropheight
= pdfGetPageMediaHeight(ctx
, page
);
684 TextOutputDev
*text_dev
= new TextOutputDev(NULL
, gTrue
, 0, gFalse
, gFalse
);
685 pdfpage
->display(text_dev
, 72, 72, 0, gTrue
, gTrue
, gFalse
);
686 PDFRectangle
rect(x1
* cropwidth
, y1
* cropheight
, x2
* cropwidth
, y2
* cropheight
);
687 GooString
*text
= text_dev
->getSelectionText(&rect
, selectionStyleGlyph
);
691 struct pdfSelectionText
*selection
= (struct pdfSelectionText
*)malloc(sizeof(struct pdfSelectionText
) + text
->getLength() + 1);
692 if (selection
!= NULL
)
694 memcpy(selection
->utf8
, text
->getCString(), text
->getLength());
695 selection
->utf8
[text
->getLength()] = 0;
705 static int actionGetPage(void *_doc
, void *_action
)
707 PDFDoc
*doc
= (PDFDoc
*)_doc
;
708 LinkAction
*link_action
= (LinkAction
*)_action
;
710 if(link_action
== NULL
)
715 // printf("linkk:%p\n", link_action);
716 // printf("linkkind:%d\n", link_action->getKind());
718 switch(link_action
->getKind())
722 LinkGoTo
*link_goto
= dynamic_cast<LinkGoTo
*>(link_action
);
723 if(link_goto
->getNamedDest() != NULL
|| link_goto
->getDest() != NULL
)
725 //printf("lookup dest for link_goto:%p\n", link_goto);
726 LinkDest
*d
= link_goto
->getDest() != NULL
? link_goto
->getDest() : doc
->findDest(link_goto
->getNamedDest());
730 if(d
->isPageRef() == FALSE
)
732 ret
= d
->getPageNum();
736 Ref ref
= d
->getPageRef();
737 //printf("page from ref:%p,%p\n", ref.num, ref.gen);
739 int page
= doc
->findPage(ref
.num
, ref
.gen
);
740 //printf("found pge:%d\n", page);
748 // this is a case where only getNamedDest() is not NULL but no idea how to handle that yet - kiero
750 //char *buff = convertToANSI(link_goto->getNamedDest());
751 //printf("%s\n", buff);
752 //printf("goto link. isok:%d\n", link_goto->getDest()->isOk());
754 if(link_goto
->getDest()->isPageRef() == FALSE
)
757 return link_goto
->getDest()->getPageNum();
761 Ref ref
= link_goto
->getDest()->getPageRef();
762 //printf("page from ref:%p,%p\n", ref.num, ref.gen);
764 int page
= doc
->findPage(ref
.num
, ref
.gen
);
765 //printf("found pge:%d\n", page);
775 //action->type = POPPLER_ACTION_GOTO_DEST;
776 //build_goto_dest (document, action, dynamic_cast <LinkGoTo *> (link));
779 //action->type = POPPLER_ACTION_GOTO_REMOTE;
780 //build_goto_remote (action, dynamic_cast <LinkGoToR *> (link));
783 //action->type = POPPLER_ACTION_LAUNCH;
784 //build_launch (action, dynamic_cast <LinkLaunch *> (link));
788 LinkURI
*link_uri
= dynamic_cast<LinkURI
*>(link_action
);
789 if(link_uri
->getURI() != NULL
)
791 //char *buff = convertToANSI(link_uri->getURI());
792 //printf("%s\n", buff);
795 //action->type = POPPLER_ACTION_URI;
796 //build_uri (action, dynamic_cast <LinkURI *> (link));
799 //action->type = POPPLER_ACTION_NAMED;
800 //build_named (action, dynamic_cast <LinkNamed *> (link));
803 //action->type = POPPLER_ACTION_MOVIE;
804 //build_movie (action, link);
808 //action->type = POPPLER_ACTION_UNKNOWN;
816 struct OutlineItemNode
820 struct MinList
*children
;
825 static struct MinList
*buildoutlineitemlist(PDFDoc
*doc
, GooList
*items
)
827 struct MinList
*l
= (struct MinList
*)calloc(1, sizeof(struct MinList
));
837 for(i
= 0; i
< items
->getLength(); i
++)
839 struct OutlineItemNode
*n
= (struct OutlineItemNode
*)calloc(1, sizeof(*n
));
843 n
->item
= (OutlineItem
*)items
->get(i
);
845 n
->title
= convertUTF32ToANSI(n
->item
->getTitle(), n
->item
->getTitleLength());
846 n
->page
= actionGetPage(doc
, n
->item
->getAction());
849 //printf("outline item:%s, page:%d\n", n->title, n->page);
851 if(n
->item
->hasKids())
853 //printf("has children, process...\n");
854 n
->children
= buildoutlineitemlist(doc
, n
->item
->getKids());
866 struct MinList
*pdfGetOutlines(void *_ctx
)
868 struct devicecontext
*ctx
= (struct devicecontext
*)_ctx
;
871 Outline
*outline
= ctx
->doc
->getOutline();
872 GooList
*items
= outline
->getItems();
873 struct MinList
*l
= buildoutlineitemlist(ctx
->doc
, items
);
878 int outlineHasChildren(void *_outline
)
880 struct OutlineItemNode
*outline
= (struct OutlineItemNode
*)_outline
;
881 return outline
->children
!= NULL
? TRUE
: FALSE
;
884 struct MinList
*outlineGetChildren(void *_outline
)
886 struct OutlineItemNode
*outline
= (struct OutlineItemNode
*)_outline
;
887 return outline
->children
;
891 char *outlineGetTitle(void *_outline
)
893 struct OutlineItemNode
*outline
= (struct OutlineItemNode
*)_outline
;
894 return outline
->title
;
897 int outlineGetPage(void *_outline
)
899 struct OutlineItemNode
*outline
= (struct OutlineItemNode
*)_outline
;
900 return outline
->page
;
906 poppler_page_get_size(Page
*page
,
910 double page_width
, page_height
;
915 rotate
= page
->getRotate();
916 if(rotate
== 90 || rotate
== 270)
918 page_height
= page
->getMediaWidth();
919 page_width
= page
->getMediaHeight();
923 page_width
= page
->getMediaWidth();
924 page_height
= page
->getMediaHeight();
930 *height
= page_height
;
935 void pdfConvertUserToDevice(void *_ctx
, double* x
, double* y
)
937 struct devicecontext
*ctx
= (struct devicecontext
*)_ctx
;
940 OutputDev
*dev
= ctx
->dev
;
942 dev
->cvtUserToDev(*x
, *y
, &dx
, &dy
);
948 void pdfConvertDeviceToUser(void *_ctx
, int page
, double x
, double y
, int *ix
, int *iy
)
950 struct devicecontext
*ctx
= (struct devicecontext
*)_ctx
;
953 OutputDev
*dev
= ctx
->dev
;
954 Page
*pdfpage
= ctx
->doc
->getCatalog()->getPage(page
);
957 pdfpage
->getDefaultCTM(ctm
, 72, 72, 0, gFalse
, gFalse
);
958 dev
->setDefaultCTM(ctm
);
959 dev
->cvtDevToUser(x
, y
, &dx
, &dy
);
965 void pdfLock(void *_ctx
)
969 void pdfRelease(void *_ctx
)
975 void *pdfFindLink(void *_ctx
, int pagenum
, int x
, int y
)
977 struct devicecontext
*ctx
= (struct devicecontext
*)_ctx
;
982 double width
, height
;
986 Catalog
*catalog
= ctx
->doc
->getCatalog();
987 //printf("catalog:%p\n", catalog);
995 page
= catalog
->getPage(pagenum
);
1004 links
= new Links(page
->getAnnots());
1013 poppler_page_get_size(page
, &width
, &height
);
1017 //printf("links:%p\n", links);
1018 int num
= links
->getNumLinks();
1021 //printf("num annots:%d\n", num);
1023 for(i
= 0; i
< num
; i
++)
1025 LinkAction
*link_action
;
1028 link
= links
->getLink(i
);
1029 link_action
= link
->getAction();
1031 if (link_action
== NULL
)
1034 switch(link_action
->getKind())
1038 LinkGoTo
*link_goto
= dynamic_cast<LinkGoTo
*>(link_action
);
1039 //if (link_goto->getDest() == NULL)
1041 //if (link_goto->getNamedDest() != NULL) {
1042 //char *buff = convertToANSI(link_goto->getNamedDest());
1043 //printf("%s\n", buff);
1046 //action->type = POPPLER_ACTION_GOTO_DEST;
1047 //build_goto_dest (document, action, dynamic_cast <LinkGoTo *> (link));
1050 //action->type = POPPLER_ACTION_GOTO_REMOTE;
1051 //build_goto_remote (action, dynamic_cast <LinkGoToR *> (link));
1054 //action->type = POPPLER_ACTION_LAUNCH;
1055 //build_launch (action, dynamic_cast <LinkLaunch *> (link));
1059 LinkURI
*link_uri
= dynamic_cast<LinkURI
*>(link_action
);
1060 if(link_uri
->getURI() != NULL
)
1062 //char *buff = convertToANSI(link_uri->getURI());
1063 //printf("%s\n", buff);
1066 //action->type = POPPLER_ACTION_URI;
1067 //build_uri (action, dynamic_cast <LinkURI *> (link));
1070 //action->type = POPPLER_ACTION_NAMED;
1071 //build_named (action, dynamic_cast <LinkNamed *> (link));
1074 //action->type = POPPLER_ACTION_MOVIE;
1075 //build_movie (action, link);
1079 //action->type = POPPLER_ACTION_UNKNOWN;
1083 double x1
, y1
, x2
, y2
;
1084 link
->getRect(&x1
, &y1
, &x2
, &y2
);
1086 pdfConvertUserToDevice(_ctx
, &x1
, &y1
);
1087 pdfConvertUserToDevice(_ctx
, &x2
, &y2
);
1096 //printf("area:%f,%f,%f,%f\n", (float)x1, (float)y1, (float)x2, (float)y2);
1098 if(x1
<= x
&& x2
>= x
&& y1
<= y
&& y2
>= y
)
1100 //printf("found link:%p\n", link);
1106 if (annot->getName() != NULL)
1108 printf("has name!\n");
1109 char *buff = convertToANSI(annot->getName());
1111 if (annot->getContents() != NULL)
1113 printf("has content\n");
1114 char *buff = convertToANSI(annot->getContents());
1117 //printf("annot%s\n", buff);
1119 //buff = convertToANSI(annot->get());
1120 //printf("annot%s\n", buff);
1132 void pdfListLinks(void *_ctx
, int pagenum
)
1134 struct devicecontext
*ctx
= (struct devicecontext
*)_ctx
;
1139 double width
, height
;
1141 Catalog
*catalog
= ctx
->doc
->getCatalog();
1142 //printf("catalog:%p\n", catalog);
1149 Page
*page
= catalog
->getPage(pagenum
);
1150 //printf("page:%p\n", page);
1158 links
= new Links(page
->getAnnots());
1167 poppler_page_get_size(page
, &width
, &height
);
1171 //printf("links:%p\n", links);
1172 int num
= links
->getNumLinks();
1175 //printf("num annots:%d\n", num);
1177 for(i
= 0; i
< num
; i
++)
1181 link
= links
->getLink(i
);
1184 double x1
, y1
, x2
, y2
;
1185 link
->getRect(&x1
, &y1
, &x2
, &y2
);
1187 D(kprintf("area:%f,%f,%f,%f\n", (float)x1
, (float)y1
, (float)x2
, (float)y2
));
1191 //printf("media:%f,%f\n", page->getMediaWidth(), page->getMediaHeight());
1196 char *linkGetDescription(void *_link
)
1198 AnnotLink
*link
= (AnnotLink
*)_link
;
1199 LinkAction
*link_action
= link
->getAction();
1203 switch(link_action
->getKind())
1207 LinkGoTo
*link_goto
= dynamic_cast<LinkGoTo
*>(link_action
);
1208 if(link_goto
->getNamedDest() != NULL
)
1210 //char *buff = convertToANSI(link_goto->getNamedDest());
1211 //printf("%s. page:%d\n", buff, link_goto->getDest()->getPageNum());
1213 else if(link_goto
->getDest() != NULL
)
1215 //printf("reference:%p\n", link_goto->getDest());
1218 //action->type = POPPLER_ACTION_GOTO_DEST;
1219 //build_goto_dest (document, action, dynamic_cast <LinkGoTo *> (link));
1222 //action->type = POPPLER_ACTION_GOTO_REMOTE;
1223 //build_goto_remote (action, dynamic_cast <LinkGoToR *> (link));
1226 //action->type = POPPLER_ACTION_LAUNCH;
1227 //build_launch (action, dynamic_cast <LinkLaunch *> (link));
1231 LinkURI
*link_uri
= dynamic_cast<LinkURI
*>(link_action
);
1232 if(link_uri
->getURI() != NULL
)
1234 //char *buff = convertToANSI(link_uri->getURI());
1235 //printf("%s\n", buff);
1238 //action->type = POPPLER_ACTION_URI;
1239 //build_uri (action, dynamic_cast <LinkURI *> (link));
1242 //action->type = POPPLER_ACTION_NAMED;
1243 //build_named (action, dynamic_cast <LinkNamed *> (link));
1246 //action->type = POPPLER_ACTION_MOVIE;
1247 //build_movie (action, link);
1251 //action->type = POPPLER_ACTION_UNKNOWN;
1259 int pdfGetActionPageFromLink(void *_ctx
, void *_link
)
1262 struct devicecontext
*ctx
= (struct devicecontext
*)_ctx
;
1263 AnnotLink
*link
= (AnnotLink
*)_link
;
1264 int page
= actionGetPage(ctx
->doc
, link
->getAction());
1269 static struct searchresult
*nextsearchresult(struct devicecontext
*ctx
, int direction
)
1273 return (struct searchresult
*)GetSucc(ctx
->search
.currentsearchresult
);
1277 return (struct searchresult
*)GetPred(ctx
->search
.currentsearchresult
);
1281 /* result list is always built in same order. it is traversal order that differs */
1283 int pdfSearch(void *_ctx
, int *page
, char *phrase
, int direction
, double *x1
, double *y1
, double *x2
, double *y2
)
1286 struct devicecontext
*ctx
= (struct devicecontext
*)_ctx
;
1289 if((ctx
->search
.phrase
== NULL
|| 0 == strcmp(ctx
->search
.phrase
, phrase
)) && ctx
->search
.page
== *page
&& (ctx
->search
.currentsearchresult
!= NULL
&& nextsearchresult(ctx
, direction
) == NULL
))
1291 /* if same search criteria, same page but no more results */
1293 free(ctx
->search
.phrase
);
1295 while(!IsListEmpty((struct List
*)&ctx
->search
.searchresultlist
))
1297 struct searchresult
*srn
= (struct searchresult
*)GetHead(&ctx
->search
.searchresultlist
);
1302 ctx
->search
.phrase
= strdup(phrase
);
1303 ctx
->search
.currentsearchresult
= NULL
;
1305 return PDFSEARCH_NEXTPAGE
;
1308 else if(ctx
->search
.phrase
== NULL
|| 0 != strcmp(ctx
->search
.phrase
, phrase
) || ctx
->search
.page
!= *page
)
1310 /* if new phrase or new page fill the list with new results */
1312 free(ctx
->search
.phrase
);
1314 while(!IsListEmpty((struct List
*)&ctx
->search
.searchresultlist
))
1316 struct searchresult
*srn
= (struct searchresult
*)GetHead(&ctx
->search
.searchresultlist
);
1321 ctx
->search
.phrase
= strdup(phrase
);
1322 ctx
->search
.page
= *page
;
1323 ctx
->search
.currentsearchresult
= NULL
;
1327 #if defined(__AROS__)
1328 kprintf("[pdfSearch] not implemented\n");
1331 WCHAR
*phraseUCS4
= convertToUCS4(phrase
);
1333 TextOutputDev
*text_dev
= new TextOutputDev(NULL
, gTrue
, 0, gFalse
, gFalse
);
1336 double xMin
, yMin
, xMax
, yMax
;
1338 Page
*pdfpage
= ctx
->doc
->getCatalog()->getPage(*page
);
1340 pdfpage
->display(text_dev
, 72, 72, 0,
1341 gTrue
, gTrue
, gFalse
);
1343 height
= pdfpage
->getMediaHeight();
1348 while(text_dev
->findText((Unicode
*)phraseUCS4
, strlen(phrase
),
1349 gFalse
, gTrue
, // startAtTop, stopAtBottom
1350 gTrue
, gFalse
, // startAtLast, stopAtLast
1351 gFalse
, gFalse
, // caseSensitive, backwards
1352 gFalse
, // wholeWord
1353 &xMin
, &yMin
, &xMax
, &yMax
))
1356 struct searchresult
*searchresult
= (struct searchresult
*)calloc(1, sizeof(*searchresult
));
1357 searchresult
->x1
= xMin
;
1358 searchresult
->y1
= height
- yMax
;
1359 searchresult
->x2
= xMax
;
1360 searchresult
->y2
= height
- yMin
;
1362 text_dev
->cvtDevToUser(searchresult
->x1
, searchresult
->y1
, &searchresult
->x1
, &searchresult
->y1
);
1363 text_dev
->cvtDevToUser(searchresult
->x2
, searchresult
->y2
, &searchresult
->x2
, &searchresult
->y2
);
1364 searchresult
->x1
/= pdfpage
->getMediaWidth();
1365 searchresult
->y1
/= pdfpage
->getMediaHeight();
1366 searchresult
->x2
/= pdfpage
->getMediaWidth();
1367 searchresult
->y2
/= pdfpage
->getMediaHeight();
1369 ADDTAIL(&ctx
->search
.searchresultlist
, searchresult
);
1380 return PDFSEARCH_NEXTPAGE
;
1386 ctx
->search
.currentsearchresult
= (struct searchresult
*)GetHead(&ctx
->search
.searchresultlist
);
1388 ctx
->search
.currentsearchresult
= (struct searchresult
*)GetTail(&ctx
->search
.searchresultlist
);
1390 ctx
->search
.page
= *page
;
1394 else if(ctx
->search
.phrase
!= NULL
&& 0 == strcmp(ctx
->search
.phrase
, phrase
) && ctx
->search
.page
== *page
&& ctx
->search
.currentsearchresult
!= NULL
&& nextsearchresult(ctx
, direction
) != NULL
)
1397 /* same phrase, same page and not empty pool of results */
1399 ctx
->search
.currentsearchresult
= nextsearchresult(ctx
, direction
);
1403 if (ctx
->search
.currentsearchresult
!= NULL
)
1405 *x1
= ctx
->search
.currentsearchresult
->x1
;
1406 *y1
= ctx
->search
.currentsearchresult
->y1
;
1407 *x2
= ctx
->search
.currentsearchresult
->x2
;
1408 *y2
= ctx
->search
.currentsearchresult
->y2
;
1412 return found
? PDFSEARCH_FOUND
: PDFSEARCH_NOTFOUND
;
1415 static char *goo_string_to_utf8(GooString
*s
)
1419 if(s
->hasUnicodeMarker())
1421 result
= convertToANSI(s
);
1429 len
= s
->getLength();
1430 ucs4_temp
= (Unicode
*)calloc(sizeof(*ucs4_temp
), len
+ 1);
1431 for(i
= 0; i
< len
; ++i
)
1433 ucs4_temp
[i
] = pdfDocEncoding
[(unsigned char)s
->getChar(i
)];
1437 result
= convertUTF32ToANSI(ucs4_temp
, s
->getLength());
1445 static char *info_dict_get_string(Dict
*info_dict
, const char *key
)
1447 GooString
*goo_value
;
1451 if(!info_dict
->lookup((char *)key
, &obj
)->isString())
1457 goo_value
= obj
.getString();
1458 result
= goo_string_to_utf8(goo_value
);
1464 static struct pdfAttribute
*buildStringAttribute(char *value
)
1466 struct pdfAttribute
*attr
= (struct pdfAttribute
*)malloc(sizeof(*attr
));
1469 attr
->type
= PDFATTRTYPE_STRING
;
1470 attr
->value
.s
= value
;
1476 struct pdfAttribute
*pdfGetAttr(void *_ctx
, int property
)
1479 struct devicecontext
*ctx
= (struct devicecontext
*)_ctx
;
1481 struct pdfAttribute
*ret
= NULL
;
1483 ctx
->doc
->getDocInfo(&obj
);
1493 ret
= buildStringAttribute(info_dict_get_string(obj
.getDict(), "Title"));
1502 void pdfFreeAttr(void *_ctx
, struct pdfAttribute
*attr
)
1506 if(attr
->value
.s
!= NULL
&& attr
->type
== PDFATTRTYPE_STRING
)
1507 free(attr
->value
.s
);
1515 struct MinList
*pdfGetAnnotations(void *_ctx
, int page
)
1518 struct devicecontext
*ctx
= (struct devicecontext
*)_ctx
;
1519 Page
*pdfpage
= ctx
->doc
->getCatalog()->getPage(page
);
1520 Annots
*annots
= pdfpage
->getAnnots();
1522 if (annots
== NULL
|| annots
->getNumAnnots() == 0)
1528 struct MinList
*l
= (struct MinList
*)calloc(1, sizeof(*l
));
1537 for(int i
=0; i
<annots
->getNumAnnots(); i
++)
1539 Annot
*pdfAnnot
= annots
->getAnnot(i
);
1540 struct pdfAnnotation
*annot
= NULL
;
1542 switch (pdfAnnot
->getType ())
1544 case Annot::typeText
:
1545 case Annot::typeLink
:
1546 case Annot::typeFreeText
:
1547 case Annot::typeLine
:
1548 case Annot::typeSquare
:
1549 case Annot::typeCircle
:
1550 case Annot::typePolygon
:
1551 case Annot::typePolyLine
:
1552 case Annot::typeHighlight
:
1553 case Annot::typeUnderline
:
1554 case Annot::typeSquiggly
:
1555 case Annot::typeStrikeOut
:
1556 case Annot::typeStamp
:
1557 case Annot::typeCaret
:
1558 case Annot::typeInk
:
1559 case Annot::typePopup
:
1560 case Annot::typeFileAttachment
:
1561 case Annot::typeSound
:
1562 case Annot::typeMovie
:
1563 case Annot::typeWidget
:
1564 case Annot::typeScreen
:
1565 case Annot::typePrinterMark
:
1566 case Annot::typeTrapNet
:
1567 case Annot::typeWatermark
:
1569 if (pdfAnnot
->getContents() != NULL
)
1571 annot
= (struct pdfAnnotation
*)calloc(1, sizeof(*annot
));
1574 annot
->type
= 0; // TODO
1575 //annot->author = convertToANSI(pdfAnnot->getAuthor());
1576 annot
->contents
= convertToANSI(pdfAnnot
->getContents());
1588 double width
= pdfGetPageMediaWidth(_ctx
, page
);
1589 double height
= pdfGetPageMediaHeight(_ctx
, page
);
1592 if (!(pdfAnnot
->getFlags () & Annot::flagNoRotate
))
1593 rotation
= pdfpage
->getRotate();
1595 rect
= *(pdfAnnot
->getRect());
1600 annot
->x1
= rect
.y1
;
1601 annot
->y1
= height
- rect
.x2
;
1602 annot
->x2
= annot
->x1
+ (rect
.y2
- rect
.y1
);
1603 annot
->y2
= annot
->y1
+ (rect
.x2
- rect
.x1
);
1606 annot
->x1
= width
- rect
.x2
;
1607 annot
->y1
= height
- rect
.y2
;
1608 annot
->x2
= annot
->x1
+ (rect
.x2
- rect
.x1
);
1609 annot
->y2
= annot
->y1
+ (rect
.y2
- rect
.y1
);
1612 annot
->x1
= width
- rect
.y2
;
1613 annot
->y1
= rect
.x1
;
1614 annot
->x2
= annot
->x1
+ (rect
.y2
- rect
.y1
);
1615 annot
->y2
= annot
->y1
+ (rect
.x2
- rect
.x1
);
1618 annot
->x1
= rect
.x1
;
1619 annot
->y1
= rect
.y1
;
1620 annot
->x2
= rect
.x2
;
1621 annot
->y2
= rect
.y2
;
1623 annot
->y1
= height
- annot
->y1
;
1624 annot
->y2
= height
- annot
->y2
;
1626 annot
->x1
/= pdfpage
->getMediaWidth();
1627 annot
->x2
/= pdfpage
->getMediaWidth();
1628 annot
->y1
/= pdfpage
->getMediaHeight();
1629 annot
->y2
/= pdfpage
->getMediaHeight();