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 poppler.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 */
88 void vpdfErrorFunction(int pos
, char *message
);
91 static void pdfErrorFunction(void *data
, ErrorCategory category
, Goffset pos
, char *msg
)
93 vpdfErrorFunction(pos
, msg
);
96 static CONSTRUCTOR_P(init_poppler
, 0)
98 InitSemaphore(&semaphore
);
99 setErrorCallback(pdfErrorFunction
, NULL
);
100 #if defined(__AROS__)
107 static DESTRUCTOR_P(cleanup_poppler
, 0)
109 D(kprintf("destroy poppler:%p\n", &semaphore
));
113 #define ENTER_SECTION \
114 { ObtainSemaphore(&semaphore);}
115 #else // time delay needed to enter critical section
116 #define ENTER_SECTION \
117 { clock_t t0 = clock(); ObtainSemaphore(&semaphore); t0 = clock() - t0; kprintf("section enter:%f:%s\n", (float)t0/CLOCKS_PER_SEC, __FUNCTION__);}
120 //#define ENTER_SECTION
121 #define LEAVE_SECTION ReleaseSemaphore(&semaphore);
122 //#define LEAVE_SECTION
124 //struct Library *CairoBase;
132 ({typeof(a) _a = (a); \
133 typeof(b) _b = (b); \
134 _a < _b ? _a : _b; })
137 ({typeof(a) _a = (a); \
138 typeof(b) _b = (b); \
139 _a > _b ? _a : _b; })
143 /// utility functions
145 static char *convertUTF16ToANSI(unsigned char *string
, int length
)
147 char *buff
= (char*)calloc(1, length
+ 1);
148 #if defined(__AROS__)
149 kprintf("[convertUTF16ToANSI] not implemented\n");
153 ConvertTagList((unsigned char*)string
+ 2, length
* 2 - 2, buff
, length
+ 1, MIBENUM_UTF_16BE
, MIBENUM_SYSTEM
, NULL
);
159 static char *convertUTF32ToANSI(Unicode
*string
, int length
)
161 char *buff
= (char*)calloc(1, length
+ 1);
162 #if defined(__AROS__)
163 kprintf("[convertUTF32ToANSI] not implemented\n");
167 ConvertTagList((unsigned char*)string
, length
* 4, buff
, length
+ 1, MIBENUM_UTF_32BE
, MIBENUM_SYSTEM
, NULL
);
174 static WCHAR
*convertToUCS4(const char *string
)
176 size_t length
= strlen(string
);
179 WCHAR
*buff
= (WCHAR
*)calloc(sizeof(WCHAR
), length
+ 1);
180 #if defined(__AROS__)
181 kprintf("[convertToUCS4] not implemented\n");
186 for(i
= 0; i
< length
; i
++)
187 buff
[i
] = ToUCS4(string
[i
], NULL
);
194 static char *convertToANSI(GooString
*s
)
196 if(s
->hasUnicodeMarker())
198 //printf("has unicode marker\n");
199 return convertUTF16ToANSI((unsigned char*)s
->getCString(), s
->getLength() - 2);
203 char *buffer
= (char*)calloc(1, s
->getLength() + 1);
206 //printf("no unicode marker\n");
207 for(i
= 0; i
< s
->getLength(); ++i
)
208 buffer
[i
] = s
->getChar(i
);
223 void *pdfNew(const char *fname
)
226 //CairoBase = OpenLibrary("cairo.library", 0);
228 //StackFrame[-1].LR-> Address 0x26870dd4 -> vpdf Hunk 1 Offset 0x00001284
229 //StackFrame[-2].LR-> Address 0x2686ff34 -> vpdf Hunk 1 Offset 0x000003e4
231 #if !defined(__AROS__) && !defined(USE_SPLASH)
232 kprintf("Cairo Base:%p. sema:%p, %p, %p\n", CairoBase
, &semaphore
, foo
, &foo
);
235 struct devicecontext
*ctx
= (struct devicecontext
*)calloc(1, sizeof(*ctx
));
248 if(globalParams
== NULL
)
250 globalParams
= new GlobalParams();
251 globalParams
->setScreenType(screenClustered
);
252 globalParams
->setScreenSize(3);
253 //globalParams->setPSBinary(true);
256 CachedFile
*cachedFile
= new CachedFile(new StdCacheLoader(), new GooString(fname
));
257 D(kprintf("pdf file opened...\n"));
258 ctx
->stream
= new CachedFileStream(cachedFile
, 0, gTrue
, cachedFile
->getLength(), &obj
);
259 D(kprintf("pdf stream created..\n"));
260 ctx
->doc
= new PDFDoc(ctx
->stream
, NULL
, NULL
);
261 D(kprintf("document opened...\n"));
263 if(ctx
->doc
== NULL
|| !ctx
->doc
->isOk() || ctx
->doc
->getNumPages() == 0)
265 D(kprintf("failed to open a document:%p...\n", ctx
->doc
));
272 SplashColor paperColor
;
278 ctx
->dev
= new SplashOutputDev(splashModeRGB8
, 4, gFalse
, paperColor
);
279 ctx
->dev
->startDoc(ctx
->doc
);
281 ctx
->dev
= new CairoOutputDev();
282 ctx
->dev
->setPrinting(false);
284 ctx
->dev
->startDoc(ctx
->doc
);
286 D(kprintf("media_box:%f,%f\n", ctx
->doc
->getPageMediaWidth(1), ctx
->doc
->getPageMediaHeight(1)));
287 D(kprintf("media_box:%f, %f\n", pdfGetPageMediaWidth(ctx
, 1), pdfGetPageMediaHeight(ctx
, 1)));
289 NEWLIST(&ctx
->search
.searchresultlist
);
291 /* cache some common values to remove need for locking */
292 ctx
->pagesnum
= ctx
->doc
->getNumPages();
293 ctx
->documentwidth
= ctx
->documentheight
= 0.0f
;
295 for(i
= 0; i
< ctx
->pagesnum
; i
++)
297 Page
*pdfpage
= ctx
->doc
->getCatalog()->getPage(i
+ 1);
298 int rotate
= pdfpage
->getRotate();
300 if(rotate
== 90 || rotate
== 270)
302 width
= pdfpage
->getMediaHeight();
303 height
= pdfpage
->getMediaWidth();
307 width
= pdfpage
->getMediaWidth();
308 height
= pdfpage
->getMediaHeight();
311 ctx
->documentwidth
= MAX(ctx
->documentwidth
, width
);
312 ctx
->documentheight
= MAX(ctx
->documentheight
, height
);
317 D(kprintf("exception while opening pdf document\n"));
328 void pdfDelete(void *_ctx
)
330 struct devicecontext
*ctx
= (struct devicecontext
*)_ctx
;
335 D(kprintf("delete output device:%p.\n", ctx
->dev
));
340 if (ctx
->selection_dev
!= NULL
)
341 delete ctx
->selection_dev
;
343 #if !defined(USE_SPLASH)
344 D(kprintf("delete surface:%p.\n", ctx
->surface
));
346 if(ctx
->surface
!= NULL
)
348 cairo_create(ctx
->surface
);
349 cairo_surface_destroy(ctx
->surface
);
353 D(kprintf("delete document\n"));
357 // Stream is disposed with document
358 //if (ctx->stream != NULL)
359 // delete ctx->stream;
362 //CloseLibrary(CairoBase);
366 float pdfGetPageMediaWidth(void *_ctx
, int page
)
369 struct devicecontext
*ctx
= (struct devicecontext
*)_ctx
;
370 //float width = ctx->doc->getPageMediaWidth(page);
371 Page
*pdfpage
= ctx
->doc
->getCatalog()->getPage(page
);
372 int rotate
= pdfpage
->getRotate();
374 if(rotate
== 90 || rotate
== 270)
375 width
= pdfpage
->getMediaHeight();
377 width
= pdfpage
->getMediaWidth();
382 float pdfGetPageMediaHeight(void *_ctx
, int page
)
385 struct devicecontext
*ctx
= (struct devicecontext
*)_ctx
;
386 Page
*pdfpage
= ctx
->doc
->getCatalog()->getPage(page
);
387 //float height = ctx->doc->getPageMediaHeight(page);
388 int rotate
= pdfpage
->getRotate();
390 if(rotate
== 90 || rotate
== 270)
391 height
= pdfpage
->getMediaWidth();
393 height
= pdfpage
->getMediaHeight();
398 int pdfGetDocumentDimensions(void *_ctx
, float *width
, float *height
)
400 struct devicecontext
*ctx
= (struct devicecontext
*)_ctx
;
402 *width
= ctx
->documentwidth
;
403 *height
= ctx
->documentheight
;
407 int pdfGetPagesNum(void *_ctx
)
409 struct devicecontext
*ctx
= (struct devicecontext
*)_ctx
;
410 return ctx
->pagesnum
;
413 static GBool
abortcheckcbk_wrapper(void *data
)
415 struct abortcallbackcontext
*abortctx
= (struct abortcallbackcontext
*)data
;
416 if (abortctx
->userfunction
!= NULL
)
417 return (GBool
)abortctx
->userfunction(abortctx
->userdata
);
419 //D(printf("abort check...\n"));
424 static void applyrotation(int *width
, int *height
, int rotation
)
426 if(rotation
== 90 || rotation
== 270)
434 int pdfDisplayPageSlice(void *_ctx
, int page
, double scale
, int rotate
,
435 int useMediaBox
, int crop
, int printing
, int sliceX
, int sliceY
, int sliceW
, int sliceH
, int (*abortcheckcbk
)(void *), void *abortcheckcbkdata
)
439 struct devicecontext
*ctx
= (struct devicecontext
*)_ctx
;
440 Page
*pdfpage
= ctx
->doc
->getCatalog()->getPage(page
);
441 int cropwidth
= (int)pdfGetPageMediaWidth(ctx
, page
);
442 int cropheight
= (int)pdfGetPageMediaHeight(ctx
, page
);
443 int width
= (int)ceil(cropwidth
* scale
);
444 int height
= (int)ceil(cropheight
* scale
);
447 applyrotation(&width
, &height
, rotate
);
448 applyrotation(&cropwidth
, &cropheight
, rotate
);
453 if(ctx
->surface
!= NULL
)
455 if(cairo_image_surface_get_width(ctx
->surface
) != width
|| cairo_image_surface_get_height(ctx
->surface
) != height
)
457 //cairo_destroy(ctx->cairo);
458 cairo_surface_destroy(ctx
->surface
);
463 if(ctx
->surface
== NULL
)
465 ctx
->surface
= cairo_image_surface_create(CAIRO_FORMAT_ARGB32
, width
, height
);
468 if(ctx
->surface
== NULL
)
474 ctx
->cairo
= cairo_create(ctx
->surface
);
477 //cairo_font_options_t *options = cairo_font_options_create ();
478 //cairo_get_font_options (ctx->cairo, options);
479 //cairo_font_options_set_antialias (options, CAIRO_ANTIALIAS_SUBPIXEL);
480 //cairo_font_options_set_subpixel_order (options, CAIRO_SUBPIXEL_ORDER_BGR);
481 //cairo_set_font_options (ctx->cairo, options);
482 //cairo_font_options_destroy (options);
485 cairo_save(ctx
->cairo
);
486 cairo_set_source_rgba(ctx
->cairo
, 1., 1., 1., 1);
487 cairo_paint(ctx
->cairo
);
488 cairo_restore(ctx
->cairo
);
489 ctx
->dev
->setCairo(ctx
->cairo
);
493 //cairo_save(ctx->cairo);
494 //printf("render:%d, %d, crop:%d, %d\n", width, height, cropwidth, cropheight);
497 struct abortcallbackcontext abortctx
;
498 abortctx
.userfunction
= abortcheckcbk
;
499 abortctx
.userdata
= abortcheckcbkdata
;
502 pdfpage
->displaySlice(ctx
->dev
, 72 * scale
, 72 * scale
, rotate
, gTrue
, gFalse
, sliceX
, sliceY
, sliceW
, sliceH
,
503 printing
, abortcheckcbk_wrapper
, &abortctx
);
508 D(kprintf("Exception during page rendering\n"));
511 //cairo_restore(ctx->cairo);
515 ctx
->dev
->setCairo(NULL
);
516 cairo_destroy(ctx
->cairo
);
519 //doc->displayPage(dev, page, hDPI, vDPI, rotate, useMediaBox, crop, printing);
526 unsigned char *pdfGetBitmapRowData(void *_ctx
, int row
)
528 struct devicecontext
*ctx
= (struct devicecontext
*)_ctx
;
530 return ctx
->dev
->getBitmap()->getDataPtr() + ctx
->dev
->getBitmap()->getRowSize() * row
;
532 //printf("getrow:%d\n", row);
533 unsigned char *data
= cairo_image_surface_get_data(ctx
->surface
);
534 data
= data
+ cairo_image_surface_get_stride(ctx
->surface
) * row
;
535 //printf("done:%d, %p\n", row, data);
540 int pdfGetBitmapWidth(void *_ctx
)
542 struct devicecontext
*ctx
= (struct devicecontext
*)_ctx
;
544 return ctx
->dev
->getBitmap()->getWidth();
546 return cairo_image_surface_get_width(ctx
->surface
);
550 int pdfGetBitmapHeight(void *_ctx
)
552 struct devicecontext
*ctx
= (struct devicecontext
*)_ctx
;
554 return ctx
->dev
->getBitmap()->getHeight();
556 return cairo_image_surface_get_height(ctx
->surface
);
560 void pdfGetBitmap(void *_ctx
, struct pdfBitmap
*bm
)
562 struct devicecontext
*ctx
= (struct devicecontext
*)_ctx
;
563 bm
->width
= pdfGetBitmapWidth(_ctx
);
564 bm
->height
= pdfGetBitmapHeight(_ctx
);
565 bm
->stride
= cairo_image_surface_get_stride(ctx
->surface
);
566 bm
->data
= cairo_image_surface_get_data(ctx
->surface
);
569 void pdfDisposeRegionForSelection(void *_ctx
, struct pdfSelectionRegion
*region
)
574 void pdfDisposeTextForSelection(void *_ctx
, struct pdfSelectionText
*text
)
579 struct pdfSelectionRegion
*pdfBuildRegionForSelection(void *_ctx
, int page
, double x1
, double y1
, double x2
, double y2
, struct pdfSelectionRegion
*previous
)
583 struct devicecontext
*ctx
= (struct devicecontext
*)_ctx
;
584 Page
*pdfpage
= ctx
->doc
->getCatalog()->getPage(page
);
585 double cropwidth
= pdfGetPageMediaWidth(ctx
, page
);
586 double cropheight
= pdfGetPageMediaHeight(ctx
, page
);
588 TextOutputDev
*text_dev
;
590 if (ctx
->selection_dev
== NULL
)
591 text_dev
= ctx
->selection_dev
= new TextOutputDev(NULL
, gTrue
, 0, gFalse
, gFalse
);
593 text_dev
= ctx
->selection_dev
;
595 if (page
!= ctx
->selection_pagenum
)
596 pdfpage
->display(text_dev
, 72, 72, 0, gTrue
, gTrue
, gFalse
);
598 ctx
->selection_pagenum
= page
;
600 PDFRectangle
rect(x1
* cropwidth
, y1
* cropheight
, x2
* cropwidth
, y2
* cropheight
);
601 GooList
*list
= text_dev
->getSelectionRegion(&rect
, selectionStyleGlyph
, 1.0f
);
603 /* use gfx.lib region functions to merge all pdf rectangles. this sucks a bit but hopefuly using scaled coords will be fine */
605 struct Region
*region
= NewRegion();
607 const float scale
= (float)(1<<12);
609 D(kprintf("source region:%f, %f, %f, %f\n", x1
,y1
,x2
,y2
));
611 for (i
= 0; i
< list
->getLength(); i
++)
615 PDFRectangle
*selection_rect
= (PDFRectangle
*) list
->get(i
);
616 rect
.MinX
= (int)(selection_rect
->x1
* scale
/ cropwidth
);
617 rect
.MinY
= (int)(selection_rect
->y1
* scale
/ cropheight
);
618 rect
.MaxX
= rect
.MinX
+ (int)((selection_rect
->x2
- selection_rect
->x1
) * scale
/ cropwidth
);
619 rect
.MaxY
= rect
.MinY
+ (int)((selection_rect
->y2
- selection_rect
->y1
) * scale
/ cropheight
);
620 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
));
622 OrRectRegion(region
, &rect
);
623 delete selection_rect
;
626 /* convert gfx.lib region to pdfregion and return to the caller */
631 RegionRectangle
*rrect
;
633 D(kprintf("count regions...\n"));
634 for(numrects
= 0, rrect
= region
->RegionRectangle
; rrect
!= NULL
; rrect
= rrect
->Next
, numrects
++) {};
636 struct pdfSelectionRegion
*selection
= (struct pdfSelectionRegion
*)malloc(sizeof(struct pdfSelectionRegion
) + numrects
* sizeof(struct pdfSelectionRectangle
));
637 if (selection
!= NULL
)
639 rrect
= region
->RegionRectangle
;
641 D(kprintf("build selection rectangles...\n"));
648 Rectangle rect
= rrect
->bounds
;
649 struct pdfSelectionRectangle
*pdfrect
= &selection
->rectangles
[rectind
++];
651 rect
.MinX
+= region
->bounds
.MinX
;
652 rect
.MinY
+= region
->bounds
.MinY
;
653 rect
.MaxX
+= region
->bounds
.MinX
;
654 rect
.MaxY
+= region
->bounds
.MinY
;
656 pdfrect
->x1
= rect
.MinX
/ scale
;
657 pdfrect
->y1
= rect
.MinY
/ scale
;
658 pdfrect
->x2
= rect
.MaxX
/ scale
;
659 pdfrect
->y2
= rect
.MaxY
/ scale
;
663 selection
->numrects
= numrects
;
666 DisposeRegion(region
);
673 struct pdfSelectionText
*pdfBuildTextForSelection(void *_ctx
, int page
, double x1
, double y1
, double x2
, double y2
)
677 struct devicecontext
*ctx
= (struct devicecontext
*)_ctx
;
678 Page
*pdfpage
= ctx
->doc
->getCatalog()->getPage(page
);
679 double cropwidth
= pdfGetPageMediaWidth(ctx
, page
);
680 double cropheight
= pdfGetPageMediaHeight(ctx
, page
);
682 TextOutputDev
*text_dev
= new TextOutputDev(NULL
, gTrue
, 0, gFalse
, gFalse
);
683 pdfpage
->display(text_dev
, 72, 72, 0, gTrue
, gTrue
, gFalse
);
684 PDFRectangle
rect(x1
* cropwidth
, y1
* cropheight
, x2
* cropwidth
, y2
* cropheight
);
685 GooString
*text
= text_dev
->getSelectionText(&rect
, selectionStyleGlyph
);
689 struct pdfSelectionText
*selection
= (struct pdfSelectionText
*)malloc(sizeof(struct pdfSelectionText
) + text
->getLength() + 1);
690 if (selection
!= NULL
)
692 memcpy(selection
->utf8
, text
->getCString(), text
->getLength());
693 selection
->utf8
[text
->getLength()] = 0;
703 static int actionGetPage(void *_doc
, void *_action
)
705 PDFDoc
*doc
= (PDFDoc
*)_doc
;
706 LinkAction
*link_action
= (LinkAction
*)_action
;
708 if(link_action
== NULL
)
713 // printf("linkk:%p\n", link_action);
714 // printf("linkkind:%d\n", link_action->getKind());
716 switch(link_action
->getKind())
720 LinkGoTo
*link_goto
= dynamic_cast<LinkGoTo
*>(link_action
);
721 if(link_goto
->getNamedDest() != NULL
|| link_goto
->getDest() != NULL
)
723 //printf("lookup dest for link_goto:%p\n", link_goto);
724 LinkDest
*d
= link_goto
->getDest() != NULL
? link_goto
->getDest() : doc
->findDest(link_goto
->getNamedDest());
728 if(d
->isPageRef() == FALSE
)
730 ret
= d
->getPageNum();
734 Ref ref
= d
->getPageRef();
735 //printf("page from ref:%p,%p\n", ref.num, ref.gen);
737 int page
= doc
->findPage(ref
.num
, ref
.gen
);
738 //printf("found pge:%d\n", page);
746 // this is a case where only getNamedDest() is not NULL but no idea how to handle that yet - kiero
748 //char *buff = convertToANSI(link_goto->getNamedDest());
749 //printf("%s\n", buff);
750 //printf("goto link. isok:%d\n", link_goto->getDest()->isOk());
752 if(link_goto
->getDest()->isPageRef() == FALSE
)
755 return link_goto
->getDest()->getPageNum();
759 Ref ref
= link_goto
->getDest()->getPageRef();
760 //printf("page from ref:%p,%p\n", ref.num, ref.gen);
762 int page
= doc
->findPage(ref
.num
, ref
.gen
);
763 //printf("found pge:%d\n", page);
773 //action->type = POPPLER_ACTION_GOTO_DEST;
774 //build_goto_dest (document, action, dynamic_cast <LinkGoTo *> (link));
777 //action->type = POPPLER_ACTION_GOTO_REMOTE;
778 //build_goto_remote (action, dynamic_cast <LinkGoToR *> (link));
781 //action->type = POPPLER_ACTION_LAUNCH;
782 //build_launch (action, dynamic_cast <LinkLaunch *> (link));
786 LinkURI
*link_uri
= dynamic_cast<LinkURI
*>(link_action
);
787 if(link_uri
->getURI() != NULL
)
789 //char *buff = convertToANSI(link_uri->getURI());
790 //printf("%s\n", buff);
793 //action->type = POPPLER_ACTION_URI;
794 //build_uri (action, dynamic_cast <LinkURI *> (link));
797 //action->type = POPPLER_ACTION_NAMED;
798 //build_named (action, dynamic_cast <LinkNamed *> (link));
801 //action->type = POPPLER_ACTION_MOVIE;
802 //build_movie (action, link);
806 //action->type = POPPLER_ACTION_UNKNOWN;
814 struct OutlineItemNode
818 struct MinList
*children
;
823 static struct MinList
*buildoutlineitemlist(PDFDoc
*doc
, GooList
*items
)
825 struct MinList
*l
= (struct MinList
*)calloc(1, sizeof(struct MinList
));
835 for(i
= 0; i
< items
->getLength(); i
++)
837 struct OutlineItemNode
*n
= (struct OutlineItemNode
*)calloc(1, sizeof(*n
));
841 n
->item
= (OutlineItem
*)items
->get(i
);
843 n
->title
= convertUTF32ToANSI(n
->item
->getTitle(), n
->item
->getTitleLength());
844 n
->page
= actionGetPage(doc
, n
->item
->getAction());
847 //printf("outline item:%s, page:%d\n", n->title, n->page);
849 if(n
->item
->hasKids())
851 //printf("has children, process...\n");
852 n
->children
= buildoutlineitemlist(doc
, n
->item
->getKids());
864 struct MinList
*pdfGetOutlines(void *_ctx
)
866 struct devicecontext
*ctx
= (struct devicecontext
*)_ctx
;
869 Outline
*outline
= ctx
->doc
->getOutline();
870 GooList
*items
= outline
->getItems();
871 struct MinList
*l
= buildoutlineitemlist(ctx
->doc
, items
);
876 int outlineHasChildren(void *_outline
)
878 struct OutlineItemNode
*outline
= (struct OutlineItemNode
*)_outline
;
879 return outline
->children
!= NULL
? TRUE
: FALSE
;
882 struct MinList
*outlineGetChildren(void *_outline
)
884 struct OutlineItemNode
*outline
= (struct OutlineItemNode
*)_outline
;
885 return outline
->children
;
889 char *outlineGetTitle(void *_outline
)
891 struct OutlineItemNode
*outline
= (struct OutlineItemNode
*)_outline
;
892 return outline
->title
;
895 int outlineGetPage(void *_outline
)
897 struct OutlineItemNode
*outline
= (struct OutlineItemNode
*)_outline
;
898 return outline
->page
;
904 poppler_page_get_size(Page
*page
,
908 double page_width
, page_height
;
913 rotate
= page
->getRotate();
914 if(rotate
== 90 || rotate
== 270)
916 page_height
= page
->getMediaWidth();
917 page_width
= page
->getMediaHeight();
921 page_width
= page
->getMediaWidth();
922 page_height
= page
->getMediaHeight();
928 *height
= page_height
;
933 void pdfConvertUserToDevice(void *_ctx
, double* x
, double* y
)
935 struct devicecontext
*ctx
= (struct devicecontext
*)_ctx
;
938 OutputDev
*dev
= ctx
->dev
;
940 dev
->cvtUserToDev(*x
, *y
, &dx
, &dy
);
946 void pdfConvertDeviceToUser(void *_ctx
, int page
, double x
, double y
, int *ix
, int *iy
)
948 struct devicecontext
*ctx
= (struct devicecontext
*)_ctx
;
951 OutputDev
*dev
= ctx
->dev
;
952 Page
*pdfpage
= ctx
->doc
->getCatalog()->getPage(page
);
955 pdfpage
->getDefaultCTM(ctm
, 72, 72, 0, gFalse
, gFalse
);
956 dev
->setDefaultCTM(ctm
);
957 dev
->cvtDevToUser(x
, y
, &dx
, &dy
);
963 void pdfLock(void *_ctx
)
967 void pdfRelease(void *_ctx
)
973 void *pdfFindLink(void *_ctx
, int pagenum
, int x
, int y
)
975 struct devicecontext
*ctx
= (struct devicecontext
*)_ctx
;
980 double width
, height
;
984 Catalog
*catalog
= ctx
->doc
->getCatalog();
985 //printf("catalog:%p\n", catalog);
993 page
= catalog
->getPage(pagenum
);
1002 links
= new Links(page
->getAnnots());
1011 poppler_page_get_size(page
, &width
, &height
);
1015 //printf("links:%p\n", links);
1016 int num
= links
->getNumLinks();
1019 //printf("num annots:%d\n", num);
1021 for(i
= 0; i
< num
; i
++)
1023 LinkAction
*link_action
;
1026 link
= links
->getLink(i
);
1027 link_action
= link
->getAction();
1029 if (link_action
== NULL
)
1032 switch(link_action
->getKind())
1036 LinkGoTo
*link_goto
= dynamic_cast<LinkGoTo
*>(link_action
);
1037 //if (link_goto->getDest() == NULL)
1039 //if (link_goto->getNamedDest() != NULL) {
1040 //char *buff = convertToANSI(link_goto->getNamedDest());
1041 //printf("%s\n", buff);
1044 //action->type = POPPLER_ACTION_GOTO_DEST;
1045 //build_goto_dest (document, action, dynamic_cast <LinkGoTo *> (link));
1048 //action->type = POPPLER_ACTION_GOTO_REMOTE;
1049 //build_goto_remote (action, dynamic_cast <LinkGoToR *> (link));
1052 //action->type = POPPLER_ACTION_LAUNCH;
1053 //build_launch (action, dynamic_cast <LinkLaunch *> (link));
1057 LinkURI
*link_uri
= dynamic_cast<LinkURI
*>(link_action
);
1058 if(link_uri
->getURI() != NULL
)
1060 //char *buff = convertToANSI(link_uri->getURI());
1061 //printf("%s\n", buff);
1064 //action->type = POPPLER_ACTION_URI;
1065 //build_uri (action, dynamic_cast <LinkURI *> (link));
1068 //action->type = POPPLER_ACTION_NAMED;
1069 //build_named (action, dynamic_cast <LinkNamed *> (link));
1072 //action->type = POPPLER_ACTION_MOVIE;
1073 //build_movie (action, link);
1077 //action->type = POPPLER_ACTION_UNKNOWN;
1081 double x1
, y1
, x2
, y2
;
1082 link
->getRect(&x1
, &y1
, &x2
, &y2
);
1084 pdfConvertUserToDevice(_ctx
, &x1
, &y1
);
1085 pdfConvertUserToDevice(_ctx
, &x2
, &y2
);
1094 //printf("area:%f,%f,%f,%f\n", (float)x1, (float)y1, (float)x2, (float)y2);
1096 if(x1
<= x
&& x2
>= x
&& y1
<= y
&& y2
>= y
)
1098 //printf("found link:%p\n", link);
1104 if (annot->getName() != NULL)
1106 printf("has name!\n");
1107 char *buff = convertToANSI(annot->getName());
1109 if (annot->getContents() != NULL)
1111 printf("has content\n");
1112 char *buff = convertToANSI(annot->getContents());
1115 //printf("annot%s\n", buff);
1117 //buff = convertToANSI(annot->get());
1118 //printf("annot%s\n", buff);
1130 void pdfListLinks(void *_ctx
, int pagenum
)
1132 struct devicecontext
*ctx
= (struct devicecontext
*)_ctx
;
1137 double width
, height
;
1139 Catalog
*catalog
= ctx
->doc
->getCatalog();
1140 //printf("catalog:%p\n", catalog);
1147 Page
*page
= catalog
->getPage(pagenum
);
1148 //printf("page:%p\n", page);
1156 links
= new Links(page
->getAnnots());
1165 poppler_page_get_size(page
, &width
, &height
);
1169 //printf("links:%p\n", links);
1170 int num
= links
->getNumLinks();
1173 //printf("num annots:%d\n", num);
1175 for(i
= 0; i
< num
; i
++)
1179 link
= links
->getLink(i
);
1182 double x1
, y1
, x2
, y2
;
1183 link
->getRect(&x1
, &y1
, &x2
, &y2
);
1185 D(kprintf("area:%f,%f,%f,%f\n", (float)x1
, (float)y1
, (float)x2
, (float)y2
));
1189 //printf("media:%f,%f\n", page->getMediaWidth(), page->getMediaHeight());
1194 char *linkGetDescription(void *_link
)
1196 AnnotLink
*link
= (AnnotLink
*)_link
;
1197 LinkAction
*link_action
= link
->getAction();
1201 switch(link_action
->getKind())
1205 LinkGoTo
*link_goto
= dynamic_cast<LinkGoTo
*>(link_action
);
1206 if(link_goto
->getNamedDest() != NULL
)
1208 //char *buff = convertToANSI(link_goto->getNamedDest());
1209 //printf("%s. page:%d\n", buff, link_goto->getDest()->getPageNum());
1211 else if(link_goto
->getDest() != NULL
)
1213 //printf("reference:%p\n", link_goto->getDest());
1216 //action->type = POPPLER_ACTION_GOTO_DEST;
1217 //build_goto_dest (document, action, dynamic_cast <LinkGoTo *> (link));
1220 //action->type = POPPLER_ACTION_GOTO_REMOTE;
1221 //build_goto_remote (action, dynamic_cast <LinkGoToR *> (link));
1224 //action->type = POPPLER_ACTION_LAUNCH;
1225 //build_launch (action, dynamic_cast <LinkLaunch *> (link));
1229 LinkURI
*link_uri
= dynamic_cast<LinkURI
*>(link_action
);
1230 if(link_uri
->getURI() != NULL
)
1232 //char *buff = convertToANSI(link_uri->getURI());
1233 //printf("%s\n", buff);
1236 //action->type = POPPLER_ACTION_URI;
1237 //build_uri (action, dynamic_cast <LinkURI *> (link));
1240 //action->type = POPPLER_ACTION_NAMED;
1241 //build_named (action, dynamic_cast <LinkNamed *> (link));
1244 //action->type = POPPLER_ACTION_MOVIE;
1245 //build_movie (action, link);
1249 //action->type = POPPLER_ACTION_UNKNOWN;
1257 int pdfGetActionPageFromLink(void *_ctx
, void *_link
)
1260 struct devicecontext
*ctx
= (struct devicecontext
*)_ctx
;
1261 AnnotLink
*link
= (AnnotLink
*)_link
;
1262 int page
= actionGetPage(ctx
->doc
, link
->getAction());
1267 static struct searchresult
*nextsearchresult(struct devicecontext
*ctx
, int direction
)
1271 return (struct searchresult
*)GetSucc(ctx
->search
.currentsearchresult
);
1275 return (struct searchresult
*)GetPred(ctx
->search
.currentsearchresult
);
1279 /* result list is always built in same order. it is traversal order that differs */
1281 int pdfSearch(void *_ctx
, int *page
, char *phrase
, int direction
, double *x1
, double *y1
, double *x2
, double *y2
)
1284 struct devicecontext
*ctx
= (struct devicecontext
*)_ctx
;
1287 if((ctx
->search
.phrase
== NULL
|| 0 == strcmp(ctx
->search
.phrase
, phrase
)) && ctx
->search
.page
== *page
&& (ctx
->search
.currentsearchresult
!= NULL
&& nextsearchresult(ctx
, direction
) == NULL
))
1289 /* if same search criteria, same page but no more results */
1291 free(ctx
->search
.phrase
);
1293 while(!IsListEmpty((struct List
*)&ctx
->search
.searchresultlist
))
1295 struct searchresult
*srn
= (struct searchresult
*)GetHead(&ctx
->search
.searchresultlist
);
1300 ctx
->search
.phrase
= strdup(phrase
);
1301 ctx
->search
.currentsearchresult
= NULL
;
1303 return PDFSEARCH_NEXTPAGE
;
1306 else if(ctx
->search
.phrase
== NULL
|| 0 != strcmp(ctx
->search
.phrase
, phrase
) || ctx
->search
.page
!= *page
)
1308 /* if new phrase or new page fill the list with new results */
1310 free(ctx
->search
.phrase
);
1312 while(!IsListEmpty((struct List
*)&ctx
->search
.searchresultlist
))
1314 struct searchresult
*srn
= (struct searchresult
*)GetHead(&ctx
->search
.searchresultlist
);
1319 ctx
->search
.phrase
= strdup(phrase
);
1320 ctx
->search
.page
= *page
;
1321 ctx
->search
.currentsearchresult
= NULL
;
1325 #if defined(__AROS__)
1326 kprintf("[pdfSearch] not implemented\n");
1329 WCHAR
*phraseUCS4
= convertToUCS4(phrase
);
1331 TextOutputDev
*text_dev
= new TextOutputDev(NULL
, gTrue
, 0, gFalse
, gFalse
);
1334 double xMin
, yMin
, xMax
, yMax
;
1336 Page
*pdfpage
= ctx
->doc
->getCatalog()->getPage(*page
);
1338 pdfpage
->display(text_dev
, 72, 72, 0,
1339 gTrue
, gTrue
, gFalse
);
1341 height
= pdfpage
->getMediaHeight();
1346 while(text_dev
->findText((Unicode
*)phraseUCS4
, strlen(phrase
),
1347 gFalse
, gTrue
, // startAtTop, stopAtBottom
1348 gTrue
, gFalse
, // startAtLast, stopAtLast
1349 gFalse
, gFalse
, // caseSensitive, backwards
1350 gFalse
, // wholeWord
1351 &xMin
, &yMin
, &xMax
, &yMax
))
1354 struct searchresult
*searchresult
= (struct searchresult
*)calloc(1, sizeof(*searchresult
));
1355 searchresult
->x1
= xMin
;
1356 searchresult
->y1
= height
- yMax
;
1357 searchresult
->x2
= xMax
;
1358 searchresult
->y2
= height
- yMin
;
1360 text_dev
->cvtDevToUser(searchresult
->x1
, searchresult
->y1
, &searchresult
->x1
, &searchresult
->y1
);
1361 text_dev
->cvtDevToUser(searchresult
->x2
, searchresult
->y2
, &searchresult
->x2
, &searchresult
->y2
);
1362 searchresult
->x1
/= pdfpage
->getMediaWidth();
1363 searchresult
->y1
/= pdfpage
->getMediaHeight();
1364 searchresult
->x2
/= pdfpage
->getMediaWidth();
1365 searchresult
->y2
/= pdfpage
->getMediaHeight();
1367 ADDTAIL(&ctx
->search
.searchresultlist
, searchresult
);
1378 return PDFSEARCH_NEXTPAGE
;
1384 ctx
->search
.currentsearchresult
= (struct searchresult
*)GetHead(&ctx
->search
.searchresultlist
);
1386 ctx
->search
.currentsearchresult
= (struct searchresult
*)GetTail(&ctx
->search
.searchresultlist
);
1388 ctx
->search
.page
= *page
;
1392 else if(ctx
->search
.phrase
!= NULL
&& 0 == strcmp(ctx
->search
.phrase
, phrase
) && ctx
->search
.page
== *page
&& ctx
->search
.currentsearchresult
!= NULL
&& nextsearchresult(ctx
, direction
) != NULL
)
1395 /* same phrase, same page and not empty pool of results */
1397 ctx
->search
.currentsearchresult
= nextsearchresult(ctx
, direction
);
1401 if (ctx
->search
.currentsearchresult
!= NULL
)
1403 *x1
= ctx
->search
.currentsearchresult
->x1
;
1404 *y1
= ctx
->search
.currentsearchresult
->y1
;
1405 *x2
= ctx
->search
.currentsearchresult
->x2
;
1406 *y2
= ctx
->search
.currentsearchresult
->y2
;
1410 return found
? PDFSEARCH_FOUND
: PDFSEARCH_NOTFOUND
;
1413 static char *goo_string_to_utf8(GooString
*s
)
1417 if(s
->hasUnicodeMarker())
1419 result
= convertToANSI(s
);
1427 len
= s
->getLength();
1428 ucs4_temp
= (Unicode
*)calloc(sizeof(*ucs4_temp
), len
+ 1);
1429 for(i
= 0; i
< len
; ++i
)
1431 ucs4_temp
[i
] = pdfDocEncoding
[(unsigned char)s
->getChar(i
)];
1435 result
= convertUTF32ToANSI(ucs4_temp
, s
->getLength());
1443 static char *info_dict_get_string(Dict
*info_dict
, const char *key
)
1445 GooString
*goo_value
;
1449 if(!info_dict
->lookup((char *)key
, &obj
)->isString())
1455 goo_value
= obj
.getString();
1456 result
= goo_string_to_utf8(goo_value
);
1462 static struct pdfAttribute
*buildStringAttribute(char *value
)
1464 struct pdfAttribute
*attr
= (struct pdfAttribute
*)malloc(sizeof(*attr
));
1467 attr
->type
= PDFATTRTYPE_STRING
;
1468 attr
->value
.s
= value
;
1474 struct pdfAttribute
*pdfGetAttr(void *_ctx
, int property
)
1477 struct devicecontext
*ctx
= (struct devicecontext
*)_ctx
;
1479 struct pdfAttribute
*ret
= NULL
;
1481 ctx
->doc
->getDocInfo(&obj
);
1491 ret
= buildStringAttribute(info_dict_get_string(obj
.getDict(), "Title"));
1500 void pdfFreeAttr(void *_ctx
, struct pdfAttribute
*attr
)
1504 if(attr
->value
.s
!= NULL
&& attr
->type
== PDFATTRTYPE_STRING
)
1505 free(attr
->value
.s
);
1513 struct MinList
*pdfGetAnnotations(void *_ctx
, int page
)
1516 struct devicecontext
*ctx
= (struct devicecontext
*)_ctx
;
1517 Page
*pdfpage
= ctx
->doc
->getCatalog()->getPage(page
);
1518 Annots
*annots
= pdfpage
->getAnnots();
1520 if (annots
== NULL
|| annots
->getNumAnnots() == 0)
1526 struct MinList
*l
= (struct MinList
*)calloc(1, sizeof(*l
));
1535 for(int i
=0; i
<annots
->getNumAnnots(); i
++)
1537 Annot
*pdfAnnot
= annots
->getAnnot(i
);
1538 struct pdfAnnotation
*annot
= NULL
;
1540 switch (pdfAnnot
->getType ())
1542 case Annot::typeText
:
1543 case Annot::typeLink
:
1544 case Annot::typeFreeText
:
1545 case Annot::typeLine
:
1546 case Annot::typeSquare
:
1547 case Annot::typeCircle
:
1548 case Annot::typePolygon
:
1549 case Annot::typePolyLine
:
1550 case Annot::typeHighlight
:
1551 case Annot::typeUnderline
:
1552 case Annot::typeSquiggly
:
1553 case Annot::typeStrikeOut
:
1554 case Annot::typeStamp
:
1555 case Annot::typeCaret
:
1556 case Annot::typeInk
:
1557 case Annot::typePopup
:
1558 case Annot::typeFileAttachment
:
1559 case Annot::typeSound
:
1560 case Annot::typeMovie
:
1561 case Annot::typeWidget
:
1562 case Annot::typeScreen
:
1563 case Annot::typePrinterMark
:
1564 case Annot::typeTrapNet
:
1565 case Annot::typeWatermark
:
1567 if (pdfAnnot
->getContents() != NULL
)
1569 annot
= (struct pdfAnnotation
*)calloc(1, sizeof(*annot
));
1572 annot
->type
= 0; // TODO
1573 //annot->author = convertToANSI(pdfAnnot->getAuthor());
1574 annot
->contents
= convertToANSI(pdfAnnot
->getContents());
1586 double width
= pdfGetPageMediaWidth(_ctx
, page
);
1587 double height
= pdfGetPageMediaHeight(_ctx
, page
);
1590 if (!(pdfAnnot
->getFlags () & Annot::flagNoRotate
))
1591 rotation
= pdfpage
->getRotate();
1593 rect
= *(pdfAnnot
->getRect());
1598 annot
->x1
= rect
.y1
;
1599 annot
->y1
= height
- rect
.x2
;
1600 annot
->x2
= annot
->x1
+ (rect
.y2
- rect
.y1
);
1601 annot
->y2
= annot
->y1
+ (rect
.x2
- rect
.x1
);
1604 annot
->x1
= width
- rect
.x2
;
1605 annot
->y1
= height
- rect
.y2
;
1606 annot
->x2
= annot
->x1
+ (rect
.x2
- rect
.x1
);
1607 annot
->y2
= annot
->y1
+ (rect
.y2
- rect
.y1
);
1610 annot
->x1
= width
- rect
.y2
;
1611 annot
->y1
= rect
.x1
;
1612 annot
->x2
= annot
->x1
+ (rect
.y2
- rect
.y1
);
1613 annot
->y2
= annot
->y1
+ (rect
.x2
- rect
.x1
);
1616 annot
->x1
= rect
.x1
;
1617 annot
->y1
= rect
.y1
;
1618 annot
->x2
= rect
.x2
;
1619 annot
->y2
= rect
.y2
;
1621 annot
->y1
= height
- annot
->y1
;
1622 annot
->y2
= height
- annot
->y2
;
1624 annot
->x1
/= pdfpage
->getMediaWidth();
1625 annot
->x2
/= pdfpage
->getMediaWidth();
1626 annot
->y1
/= pdfpage
->getMediaHeight();
1627 annot
->y2
/= pdfpage
->getMediaHeight();