Fix for a crash which happened when a document couldn't be opened.
[AROS-Contrib.git] / vpdf / poppler.cpp
blob6ac5420c8079172c268a2bfb8536520ff0cdd5e7
1 /*
2 * Wrap poppler document class functions into c functions.
3 */
5 //#define USE_SPLASH
7 #define AROS_ALMOST_COMPATIBLE
9 #include "Object.h"
11 #if defined(__MORPHOS__)
12 #include <proto/charsets.h>
13 #endif
14 #define _NO_PPCINLINE
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>
26 #define USE_FLOAT 1
27 #include <poppler-config.h>
28 #include <config.h>
30 #include <stddef.h>
31 #include <stdlib.h>
32 #include <memory.h>
33 #include <math.h>
34 #include <time.h>
36 #include "PDFDoc.h"
37 #include "Outline.h"
38 #include "Link.h"
39 #include "GlobalParams.h"
40 #include "PDFDocEncoding.h"
41 #include "goo/GooList.h"
43 //#define USE_SPLASH
44 #ifdef USE_SPLASH
45 #include "splash/SplashBitmap.h"
46 #include "splash/Splash.h"
47 #include "SplashOutputDev.h"
48 #include "TextOutputDev.h"
49 #else
50 #include "CairoOutputDev.h"
51 #endif
52 #include "PSOutputDev.h"
54 #include "poppler.h"
55 #include "poppler_io.h"
56 #include "poppler_device.h"
58 #if defined(__AROS__)
59 #include <wchar.h>
60 typedef wchar_t WCHAR;
61 #include <aros/debug.h>
62 #endif
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;
74 #endif
76 /* all of this is just to not having to expose GBool in ppoppler.h... */
78 struct abortcallbackcontext
80 int (*userfunction)(void *);
81 void *userdata;
82 struct devicecontext *ctx;
85 /* this is bit hacky but we can't/shouldn't use boopsi in poppler.c */
87 #define D(x) x
89 extern "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__)
103 return TRUE;
104 #else
105 return 0;
106 #endif
109 static DESTRUCTOR_P(cleanup_poppler, 0)
111 D(kprintf("destroy poppler:%p\n", &semaphore));
114 #if 1
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__);}
120 #endif
122 //#define ENTER_SECTION
123 #define LEAVE_SECTION ReleaseSemaphore(&semaphore);
124 //#define LEAVE_SECTION
126 //struct Library *CairoBase;
128 /// macros
130 #undef MIN
131 #undef MAX
133 #define MIN(a,b) \
134 ({typeof(a) _a = (a); \
135 typeof(b) _b = (b); \
136 _a < _b ? _a : _b; })
138 #define MAX(a,b) \
139 ({typeof(a) _a = (a); \
140 typeof(b) _b = (b); \
141 _a > _b ? _a : _b; })
143 ////
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");
152 // FIXME: AROS
153 #else
154 if(buff != NULL)
155 ConvertTagList((unsigned char*)string + 2, length * 2 - 2, buff, length + 1, MIBENUM_UTF_16BE, MIBENUM_SYSTEM, NULL);
156 #endif
158 return buff;
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");
166 // FIXME: AROS
167 #else
168 if(buff != NULL)
169 ConvertTagList((unsigned char*)string, length * 4, buff, length + 1, MIBENUM_UTF_32BE, MIBENUM_SYSTEM, NULL);
170 #endif
172 return buff;
176 static WCHAR *convertToUCS4(const char *string)
178 size_t length = strlen(string);
179 size_t i;
181 WCHAR *buff = (WCHAR*)calloc(sizeof(WCHAR), length + 1);
182 #if defined(__AROS__)
183 kprintf("[convertToUCS4] not implemented\n");
184 // FIXME: AROS
185 #else
186 if(buff != NULL)
188 for(i = 0; i < length; i++)
189 buff[i] = ToUCS4(string[i], NULL);
191 #endif
193 return buff;
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);
203 else
205 char *buffer = (char*)calloc(1, s->getLength() + 1);
206 int i;
208 //printf("no unicode marker\n");
209 for(i = 0; i < s->getLength(); ++i)
210 buffer[i] = s->getChar(i);
212 return buffer;
216 ////
218 struct foo
220 int bar;
223 struct foo foo;
225 void *pdfNew(const char *fname)
227 //base1 = CairoBase;
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);
235 #endif
237 struct devicecontext *ctx = (struct devicecontext*)calloc(1, sizeof(*ctx));
238 if(ctx == NULL)
239 return NULL;
241 ENTER_SECTION
246 int i;
247 PObject obj;
248 obj.initNull();
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));
268 pdfDelete(ctx);
269 LEAVE_SECTION
270 return NULL;
273 #ifdef USE_SPLASH
274 SplashColor paperColor;
276 paperColor[0] = 255;
277 paperColor[1] = 255;
278 paperColor[2] = 255;
280 ctx->dev = new SplashOutputDev(splashModeRGB8, 4, gFalse, paperColor);
281 ctx->dev->startDoc(ctx->doc);
282 #else
283 ctx->dev = new CairoOutputDev();
284 ctx->dev->setPrinting(false);
285 ctx->surface = NULL;
286 ctx->dev->startDoc(ctx->doc);
287 #endif
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();
301 float width, height;
302 if(rotate == 90 || rotate == 270)
304 width = pdfpage->getMediaHeight();
305 height = pdfpage->getMediaWidth();
307 else
309 width = pdfpage->getMediaWidth();
310 height = pdfpage->getMediaHeight();
313 ctx->documentwidth = MAX(ctx->documentwidth, width);
314 ctx->documentheight = MAX(ctx->documentheight, height);
317 catch(...)
319 D(kprintf("exception while opening pdf document\n"));
320 pdfDelete(ctx);
321 LEAVE_SECTION
322 return NULL;
325 LEAVE_SECTION
327 return ctx;
330 void pdfDelete(void *_ctx)
332 struct devicecontext *ctx = (struct devicecontext*)_ctx;
334 ENTER_SECTION
337 D(kprintf("delete output device:%p.\n", ctx->dev));
339 if(ctx->dev != NULL)
340 delete 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);
353 #endif
355 D(kprintf("delete document\n"));
356 if(ctx->doc != NULL)
357 delete ctx->doc;
359 // Stream is disposed with document
360 //if (ctx->stream != NULL)
361 // delete ctx->stream;
363 free(ctx);
364 //CloseLibrary(CairoBase);
365 LEAVE_SECTION
368 float pdfGetPageMediaWidth(void *_ctx, int page)
370 ENTER_SECTION
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();
375 float width;
376 if(rotate == 90 || rotate == 270)
377 width = pdfpage->getMediaHeight();
378 else
379 width = pdfpage->getMediaWidth();
380 LEAVE_SECTION
381 return width;
384 float pdfGetPageMediaHeight(void *_ctx, int page)
386 ENTER_SECTION
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();
391 float height;
392 if(rotate == 90 || rotate == 270)
393 height = pdfpage->getMediaWidth();
394 else
395 height = pdfpage->getMediaHeight();
396 LEAVE_SECTION
397 return height;
400 int pdfGetDocumentDimensions(void *_ctx, float *width, float *height)
402 struct devicecontext *ctx = (struct devicecontext*)_ctx;
404 *width = ctx->documentwidth;
405 *height = ctx->documentheight;
406 return 1;
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"));
422 return 0;
426 static void applyrotation(int *width, int *height, int rotation)
428 if(rotation == 90 || rotation == 270)
430 int t = *height;
431 *height = *width;
432 *width = t;
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)
439 ENTER_SECTION
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);
447 int rc = FALSE;
449 applyrotation(&width, &height, rotate);
450 applyrotation(&cropwidth, &cropheight, rotate);
452 #ifdef USE_SPLASH
453 #else
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);
461 ctx->surface = NULL;
465 if(ctx->surface == NULL)
467 ctx->surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
470 if(ctx->surface == NULL)
472 LEAVE_SECTION
473 return FALSE;
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);
492 #endif
494 //Delay(50);
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;
502 abortctx.ctx = ctx;
504 pdfpage->displaySlice(ctx->dev, 72 * scale, 72 * scale, rotate, gTrue, gFalse, sliceX, sliceY, sliceW, sliceH,
505 printing, abortcheckcbk_wrapper, &abortctx);
506 rc = TRUE;
508 catch(...)
510 D(kprintf("Exception during page rendering\n"));
513 //cairo_restore(ctx->cairo);
514 //Delay(20);
516 #ifndef USE_SPLASH
517 ctx->dev->setCairo(NULL);
518 cairo_destroy(ctx->cairo);
519 ctx->cairo = NULL;
520 #endif
521 //doc->displayPage(dev, page, hDPI, vDPI, rotate, useMediaBox, crop, printing);
523 LEAVE_SECTION
524 return rc;
528 unsigned char *pdfGetBitmapRowData(void *_ctx, int row)
530 struct devicecontext *ctx = (struct devicecontext*)_ctx;
531 #ifdef USE_SPLASH
532 return ctx->dev->getBitmap()->getDataPtr() + ctx->dev->getBitmap()->getRowSize() * row;
533 #else
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);
538 return data;
539 #endif
542 int pdfGetBitmapWidth(void *_ctx)
544 struct devicecontext *ctx = (struct devicecontext*)_ctx;
545 #ifdef USE_SPLASH
546 return ctx->dev->getBitmap()->getWidth();
547 #else
548 return cairo_image_surface_get_width(ctx->surface);
549 #endif
552 int pdfGetBitmapHeight(void *_ctx)
554 struct devicecontext *ctx = (struct devicecontext*)_ctx;
555 #ifdef USE_SPLASH
556 return ctx->dev->getBitmap()->getHeight();
557 #else
558 return cairo_image_surface_get_height(ctx->surface);
559 #endif
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)
573 free(region);
576 void pdfDisposeTextForSelection(void *_ctx, struct pdfSelectionText *text)
578 free(text);
581 struct pdfSelectionRegion *pdfBuildRegionForSelection(void *_ctx, int page, double x1, double y1, double x2, double y2, struct pdfSelectionRegion *previous)
583 ENTER_SECTION
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);
594 else
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();
608 int i;
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++)
615 Rectangle rect;
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 */
630 delete list;
632 int numrects = 0;
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;
642 int rectind = 0;
643 D(kprintf("build selection rectangles...\n"));
644 while(rrect != NULL)
646 int px, py;
647 int pw, ph;
649 int x, y;
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;
662 rrect = rrect->Next;
665 selection->numrects = numrects;
668 DisposeRegion(region);
670 LEAVE_SECTION
672 return selection;
675 struct pdfSelectionText *pdfBuildTextForSelection(void *_ctx, int page, double x1, double y1, double x2, double y2)
677 ENTER_SECTION
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);
689 delete text_dev;
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;
698 delete text;
700 LEAVE_SECTION
702 return selection;
705 static int actionGetPage(void *_doc, void *_action)
707 PDFDoc *doc = (PDFDoc*)_doc;
708 LinkAction *link_action = (LinkAction *)_action;
710 if(link_action == NULL)
711 return 0;
713 ENTER_SECTION
715 // printf("linkk:%p\n", link_action);
716 // printf("linkkind:%d\n", link_action->getKind());
718 switch(link_action->getKind())
720 case actionGoTo:
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());
727 if(d != NULL)
729 int ret;
730 if(d->isPageRef() == FALSE)
732 ret = d->getPageNum();
734 else
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);
741 ret = page;
743 LEAVE_SECTION
744 return ret;
747 #if 0
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)
756 LEAVE_SECTION
757 return link_goto->getDest()->getPageNum();
759 else
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);
766 LEAVE_SECTION
767 return page;
769 #endif
771 else
775 //action->type = POPPLER_ACTION_GOTO_DEST;
776 //build_goto_dest (document, action, dynamic_cast <LinkGoTo *> (link));
777 break;
778 case actionGoToR:
779 //action->type = POPPLER_ACTION_GOTO_REMOTE;
780 //build_goto_remote (action, dynamic_cast <LinkGoToR *> (link));
781 break;
782 case actionLaunch:
783 //action->type = POPPLER_ACTION_LAUNCH;
784 //build_launch (action, dynamic_cast <LinkLaunch *> (link));
785 break;
786 case actionURI:
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));
797 break;
798 case actionNamed:
799 //action->type = POPPLER_ACTION_NAMED;
800 //build_named (action, dynamic_cast <LinkNamed *> (link));
801 break;
802 case actionMovie:
803 //action->type = POPPLER_ACTION_MOVIE;
804 //build_movie (action, link);
805 break;
806 case actionUnknown:
807 default:
808 //action->type = POPPLER_ACTION_UNKNOWN;
809 break;
812 LEAVE_SECTION
813 return 0;
816 struct OutlineItemNode
818 struct MinNode n;
819 OutlineItem *item;
820 struct MinList *children;
821 char *title;
822 int page;
825 static struct MinList *buildoutlineitemlist(PDFDoc *doc, GooList *items)
827 struct MinList *l = (struct MinList*)calloc(1, sizeof(struct MinList));
828 if(l != NULL)
830 NEWLIST(l);
832 if(items != NULL)
835 int i;
837 for(i = 0; i < items->getLength(); i++)
839 struct OutlineItemNode *n = (struct OutlineItemNode*)calloc(1, sizeof(*n));
841 if(n != NULL)
843 n->item = (OutlineItem*)items->get(i);
844 n->item->open();
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());
857 ADDTAIL(l, n);
863 return l;
866 struct MinList *pdfGetOutlines(void *_ctx)
868 struct devicecontext *ctx = (struct devicecontext*)_ctx;
870 ENTER_SECTION
871 Outline *outline = ctx->doc->getOutline();
872 GooList *items = outline->getItems();
873 struct MinList *l = buildoutlineitemlist(ctx->doc, items);
874 LEAVE_SECTION
875 return l;
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;
905 void
906 poppler_page_get_size(Page *page,
907 double *width,
908 double *height)
910 double page_width, page_height;
911 int rotate;
913 ENTER_SECTION
915 rotate = page->getRotate();
916 if(rotate == 90 || rotate == 270)
918 page_height = page->getMediaWidth();
919 page_width = page->getMediaHeight();
921 else
923 page_width = page->getMediaWidth();
924 page_height = page->getMediaHeight();
927 if(width != NULL)
928 *width = page_width;
929 if(height != NULL)
930 *height = page_height;
932 LEAVE_SECTION
935 void pdfConvertUserToDevice(void *_ctx, double* x, double* y)
937 struct devicecontext *ctx = (struct devicecontext*)_ctx;
939 ENTER_SECTION
940 OutputDev *dev = ctx->dev;
941 int dx, dy;
942 dev->cvtUserToDev(*x, *y, &dx, &dy);
943 LEAVE_SECTION
944 *x = dx;
945 *y = dy;
948 void pdfConvertDeviceToUser(void *_ctx, int page, double x, double y, int *ix, int *iy)
950 struct devicecontext *ctx = (struct devicecontext*)_ctx;
952 ENTER_SECTION
953 OutputDev *dev = ctx->dev;
954 Page *pdfpage = ctx->doc->getCatalog()->getPage(page);
955 double dx, dy;
956 double ctm[6];
957 pdfpage->getDefaultCTM(ctm, 72, 72, 0, gFalse, gFalse);
958 dev->setDefaultCTM(ctm);
959 dev->cvtDevToUser(x, y, &dx, &dy);
960 LEAVE_SECTION
961 *ix = dx;
962 *iy = dy;
965 void pdfLock(void *_ctx)
967 ENTER_SECTION;
969 void pdfRelease(void *_ctx)
971 LEAVE_SECTION;
975 void *pdfFindLink(void *_ctx, int pagenum, int x, int y)
977 struct devicecontext *ctx = (struct devicecontext*)_ctx;
978 Links *links;
979 PObject obj;
980 Page *page;
982 double width, height;
984 ENTER_SECTION
986 Catalog *catalog = ctx->doc->getCatalog();
987 //printf("catalog:%p\n", catalog);
988 if(catalog == NULL)
990 LEAVE_SECTION
991 return NULL;
995 page = catalog->getPage(pagenum);
997 if(page == NULL)
999 LEAVE_SECTION
1000 return NULL;
1004 links = new Links(page->getAnnots());
1005 obj.free();
1007 if(links == NULL)
1009 LEAVE_SECTION
1010 return NULL;
1013 poppler_page_get_size(page, &width, &height);
1015 if(links != NULL)
1017 //printf("links:%p\n", links);
1018 int num = links->getNumLinks();
1019 int i;
1021 //printf("num annots:%d\n", num);
1023 for(i = 0; i < num; i++)
1025 LinkAction *link_action;
1026 AnnotLink *link;
1028 link = links->getLink(i);
1029 link_action = link->getAction();
1031 if (link_action == NULL)
1032 continue;
1034 switch(link_action->getKind())
1036 case actionGoTo:
1038 LinkGoTo *link_goto = dynamic_cast<LinkGoTo*>(link_action);
1039 //if (link_goto->getDest() == NULL)
1040 // continue;
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));
1048 break;
1049 case actionGoToR:
1050 //action->type = POPPLER_ACTION_GOTO_REMOTE;
1051 //build_goto_remote (action, dynamic_cast <LinkGoToR *> (link));
1052 break;
1053 case actionLaunch:
1054 //action->type = POPPLER_ACTION_LAUNCH;
1055 //build_launch (action, dynamic_cast <LinkLaunch *> (link));
1056 break;
1057 case actionURI:
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));
1068 break;
1069 case actionNamed:
1070 //action->type = POPPLER_ACTION_NAMED;
1071 //build_named (action, dynamic_cast <LinkNamed *> (link));
1072 break;
1073 case actionMovie:
1074 //action->type = POPPLER_ACTION_MOVIE;
1075 //build_movie (action, link);
1076 break;
1077 case actionUnknown:
1078 default:
1079 //action->type = POPPLER_ACTION_UNKNOWN;
1080 break;
1083 double x1, y1, x2, y2;
1084 link->getRect(&x1, &y1, &x2, &y2);
1086 pdfConvertUserToDevice(_ctx, &x1, &y1);
1087 pdfConvertUserToDevice(_ctx, &x2, &y2);
1089 if(y1 > y2)
1091 double t = y1;
1092 y1 = y2;
1093 y2 = t;
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);
1101 LEAVE_SECTION
1102 return 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);
1118 //free(buff);
1119 //buff = convertToANSI(annot->get());
1120 //printf("annot%s\n", buff);
1121 //free(buff);
1126 delete links;
1128 LEAVE_SECTION
1129 return NULL;
1132 void pdfListLinks(void *_ctx, int pagenum)
1134 struct devicecontext *ctx = (struct devicecontext*)_ctx;
1136 Links *links;
1137 PObject obj;
1139 double width, height;
1140 ENTER_SECTION
1141 Catalog *catalog = ctx->doc->getCatalog();
1142 //printf("catalog:%p\n", catalog);
1143 if(catalog == NULL)
1145 LEAVE_SECTION
1146 return;
1149 Page *page = catalog->getPage(pagenum);
1150 //printf("page:%p\n", page);
1152 if(page == NULL)
1154 LEAVE_SECTION
1155 return;
1158 links = new Links(page->getAnnots());
1159 obj.free();
1161 if(links == NULL)
1163 LEAVE_SECTION;
1164 return;
1167 poppler_page_get_size(page, &width, &height);
1169 if(links != NULL)
1171 //printf("links:%p\n", links);
1172 int num = links->getNumLinks();
1173 int i;
1175 //printf("num annots:%d\n", num);
1177 for(i = 0; i < num; i++)
1179 AnnotLink *link;
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());
1192 LEAVE_SECTION
1193 delete links;
1196 char *linkGetDescription(void *_link)
1198 AnnotLink *link = (AnnotLink*)_link;
1199 LinkAction *link_action = link->getAction();
1201 ENTER_SECTION
1203 switch(link_action->getKind())
1205 case actionGoTo:
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));
1220 break;
1221 case actionGoToR:
1222 //action->type = POPPLER_ACTION_GOTO_REMOTE;
1223 //build_goto_remote (action, dynamic_cast <LinkGoToR *> (link));
1224 break;
1225 case actionLaunch:
1226 //action->type = POPPLER_ACTION_LAUNCH;
1227 //build_launch (action, dynamic_cast <LinkLaunch *> (link));
1228 break;
1229 case actionURI:
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));
1240 break;
1241 case actionNamed:
1242 //action->type = POPPLER_ACTION_NAMED;
1243 //build_named (action, dynamic_cast <LinkNamed *> (link));
1244 break;
1245 case actionMovie:
1246 //action->type = POPPLER_ACTION_MOVIE;
1247 //build_movie (action, link);
1248 break;
1249 case actionUnknown:
1250 default:
1251 //action->type = POPPLER_ACTION_UNKNOWN;
1252 break;
1255 LEAVE_SECTION
1256 return NULL;
1259 int pdfGetActionPageFromLink(void *_ctx, void *_link)
1261 ENTER_SECTION
1262 struct devicecontext *ctx = (struct devicecontext*)_ctx;
1263 AnnotLink *link = (AnnotLink*)_link;
1264 int page = actionGetPage(ctx->doc, link->getAction());
1265 LEAVE_SECTION
1266 return page;
1269 static struct searchresult *nextsearchresult(struct devicecontext *ctx, int direction)
1271 if(direction > 0)
1273 return (struct searchresult*)GetSucc(ctx->search.currentsearchresult);
1275 else
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)
1285 ENTER_SECTION
1286 struct devicecontext *ctx = (struct devicecontext*)_ctx;
1287 int found = FALSE;
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);
1298 REMOVE(srn);
1299 free(srn);
1302 ctx->search.phrase = strdup(phrase);
1303 ctx->search.currentsearchresult = NULL;
1304 LEAVE_SECTION
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);
1317 REMOVE(srn);
1318 free(srn);
1321 ctx->search.phrase = strdup(phrase);
1322 ctx->search.page = *page;
1323 ctx->search.currentsearchresult = NULL;
1325 /* new search */
1327 #if defined(__AROS__)
1328 kprintf("[pdfSearch] not implemented\n");
1329 // FIXME: AROS
1330 #else
1331 WCHAR *phraseUCS4 = convertToUCS4(phrase);
1333 TextOutputDev *text_dev = new TextOutputDev(NULL, gTrue, 0, gFalse, gFalse);
1336 double xMin, yMin, xMax, yMax;
1337 double height;
1338 Page *pdfpage = ctx->doc->getCatalog()->getPage(*page);
1340 pdfpage->display(text_dev, 72, 72, 0,
1341 gTrue, gTrue, gFalse);
1343 height = pdfpage->getMediaHeight();
1345 xMin = 0;
1346 yMin = 0;
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))
1355 double ctm[6];
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);
1370 found = TRUE;
1374 delete text_dev;
1375 free(phraseUCS4);
1376 #endif
1377 if (found == FALSE)
1379 LEAVE_SECTION
1380 return PDFSEARCH_NEXTPAGE;
1383 if (found)
1385 if(direction > 0)
1386 ctx->search.currentsearchresult = (struct searchresult*)GetHead(&ctx->search.searchresultlist);
1387 else
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);
1400 found = TRUE;
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;
1411 LEAVE_SECTION
1412 return found ? PDFSEARCH_FOUND : PDFSEARCH_NOTFOUND;
1415 static char *goo_string_to_utf8(GooString *s)
1417 char *result;
1419 if(s->hasUnicodeMarker())
1421 result = convertToANSI(s);
1423 else
1425 int len;
1426 Unicode *ucs4_temp;
1427 int i;
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)];
1435 ucs4_temp[i] = 0;
1437 result = convertUTF32ToANSI(ucs4_temp, s->getLength());
1439 free(ucs4_temp);
1442 return result;
1445 static char *info_dict_get_string(Dict *info_dict, const char *key)
1447 GooString *goo_value;
1448 char *result;
1449 PObject obj;
1451 if(!info_dict->lookup((char *)key, &obj)->isString())
1453 obj.free();
1454 return NULL;
1457 goo_value = obj.getString();
1458 result = goo_string_to_utf8(goo_value);
1460 obj.free();
1461 return result;
1464 static struct pdfAttribute *buildStringAttribute(char *value)
1466 struct pdfAttribute *attr = (struct pdfAttribute*)malloc(sizeof(*attr));
1467 if(attr != NULL)
1469 attr->type = PDFATTRTYPE_STRING;
1470 attr->value.s = value;
1473 return attr;
1476 struct pdfAttribute *pdfGetAttr(void *_ctx, int property)
1478 ENTER_SECTION
1479 struct devicecontext *ctx = (struct devicecontext*)_ctx;
1480 PObject obj;
1481 struct pdfAttribute *ret = NULL;
1483 ctx->doc->getDocInfo(&obj);
1484 if(!obj.isDict())
1486 LEAVE_SECTION;
1487 return NULL;
1490 switch(property)
1492 case PDFATTR_TITLE:
1493 ret = buildStringAttribute(info_dict_get_string(obj.getDict(), "Title"));
1494 break;
1497 LEAVE_SECTION;
1498 return ret;
1502 void pdfFreeAttr(void *_ctx, struct pdfAttribute *attr)
1504 if(attr != NULL)
1506 if(attr->value.s != NULL && attr->type == PDFATTRTYPE_STRING)
1507 free(attr->value.s);
1509 free(attr);
1513 /* annotations */
1515 struct MinList *pdfGetAnnotations(void *_ctx, int page)
1517 ENTER_SECTION
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)
1524 LEAVE_SECTION
1525 return NULL;
1528 struct MinList *l = (struct MinList*)calloc(1, sizeof(*l));
1529 if (l == NULL)
1531 LEAVE_SECTION
1532 return NULL;
1535 NEWLIST(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:
1568 case Annot::type3D:
1569 if (pdfAnnot->getContents() != NULL)
1571 annot = (struct pdfAnnotation*)calloc(1, sizeof(*annot));
1572 if (annot != NULL)
1574 annot->type = 0; // TODO
1575 //annot->author = convertToANSI(pdfAnnot->getAuthor());
1576 annot->contents = convertToANSI(pdfAnnot->getContents());
1579 break;
1580 default:
1585 if (annot != NULL)
1587 int rotation = 0;
1588 double width = pdfGetPageMediaWidth(_ctx, page);
1589 double height = pdfGetPageMediaHeight(_ctx, page);
1590 PDFRectangle rect;
1592 if (!(pdfAnnot->getFlags () & Annot::flagNoRotate))
1593 rotation = pdfpage->getRotate();
1595 rect = *(pdfAnnot->getRect());
1597 switch (rotation)
1599 case 90:
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);
1604 break;
1605 case 180:
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);
1610 break;
1611 case 270:
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);
1616 break;
1617 default:
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();
1631 ADDTAIL(l, annot);
1636 LEAVE_SECTION
1637 return l;