forgotten commit. disabled until egl is adapted.
[AROS-Contrib.git] / vpdf / poppler.cpp
blobbb7c2d640ea00bc24214ba532a00eee53cf1c2bf
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 poppler.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 extern "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__)
101 return TRUE;
102 #else
103 return 0;
104 #endif
107 static DESTRUCTOR_P(cleanup_poppler, 0)
109 D(kprintf("destroy poppler:%p\n", &semaphore));
112 #if 1
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__);}
118 #endif
120 //#define ENTER_SECTION
121 #define LEAVE_SECTION ReleaseSemaphore(&semaphore);
122 //#define LEAVE_SECTION
124 //struct Library *CairoBase;
126 /// macros
128 #undef MIN
129 #undef MAX
131 #define MIN(a,b) \
132 ({typeof(a) _a = (a); \
133 typeof(b) _b = (b); \
134 _a < _b ? _a : _b; })
136 #define MAX(a,b) \
137 ({typeof(a) _a = (a); \
138 typeof(b) _b = (b); \
139 _a > _b ? _a : _b; })
141 ////
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");
150 // FIXME: AROS
151 #else
152 if(buff != NULL)
153 ConvertTagList((unsigned char*)string + 2, length * 2 - 2, buff, length + 1, MIBENUM_UTF_16BE, MIBENUM_SYSTEM, NULL);
154 #endif
156 return buff;
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");
164 // FIXME: AROS
165 #else
166 if(buff != NULL)
167 ConvertTagList((unsigned char*)string, length * 4, buff, length + 1, MIBENUM_UTF_32BE, MIBENUM_SYSTEM, NULL);
168 #endif
170 return buff;
174 static WCHAR *convertToUCS4(const char *string)
176 size_t length = strlen(string);
177 size_t i;
179 WCHAR *buff = (WCHAR*)calloc(sizeof(WCHAR), length + 1);
180 #if defined(__AROS__)
181 kprintf("[convertToUCS4] not implemented\n");
182 // FIXME: AROS
183 #else
184 if(buff != NULL)
186 for(i = 0; i < length; i++)
187 buff[i] = ToUCS4(string[i], NULL);
189 #endif
191 return buff;
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);
201 else
203 char *buffer = (char*)calloc(1, s->getLength() + 1);
204 int i;
206 //printf("no unicode marker\n");
207 for(i = 0; i < s->getLength(); ++i)
208 buffer[i] = s->getChar(i);
210 return buffer;
214 ////
216 struct foo
218 int bar;
221 struct foo foo;
223 void *pdfNew(const char *fname)
225 //base1 = CairoBase;
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);
233 #endif
235 struct devicecontext *ctx = (struct devicecontext*)calloc(1, sizeof(*ctx));
236 if(ctx == NULL)
237 return NULL;
239 ENTER_SECTION
244 int i;
245 PObject obj;
246 obj.initNull();
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));
266 pdfDelete(ctx);
267 LEAVE_SECTION
268 return NULL;
271 #ifdef USE_SPLASH
272 SplashColor paperColor;
274 paperColor[0] = 255;
275 paperColor[1] = 255;
276 paperColor[2] = 255;
278 ctx->dev = new SplashOutputDev(splashModeRGB8, 4, gFalse, paperColor);
279 ctx->dev->startDoc(ctx->doc);
280 #else
281 ctx->dev = new CairoOutputDev();
282 ctx->dev->setPrinting(false);
283 ctx->surface = NULL;
284 ctx->dev->startDoc(ctx->doc);
285 #endif
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();
299 float width, height;
300 if(rotate == 90 || rotate == 270)
302 width = pdfpage->getMediaHeight();
303 height = pdfpage->getMediaWidth();
305 else
307 width = pdfpage->getMediaWidth();
308 height = pdfpage->getMediaHeight();
311 ctx->documentwidth = MAX(ctx->documentwidth, width);
312 ctx->documentheight = MAX(ctx->documentheight, height);
315 catch(...)
317 D(kprintf("exception while opening pdf document\n"));
318 pdfDelete(ctx);
319 LEAVE_SECTION
320 return NULL;
323 LEAVE_SECTION
325 return ctx;
328 void pdfDelete(void *_ctx)
330 struct devicecontext *ctx = (struct devicecontext*)_ctx;
332 ENTER_SECTION
335 D(kprintf("delete output device:%p.\n", ctx->dev));
337 if(ctx->dev != NULL)
338 delete 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);
351 #endif
353 D(kprintf("delete document\n"));
354 if(ctx->doc != NULL)
355 delete ctx->doc;
357 // Stream is disposed with document
358 //if (ctx->stream != NULL)
359 // delete ctx->stream;
361 free(ctx);
362 //CloseLibrary(CairoBase);
363 LEAVE_SECTION
366 float pdfGetPageMediaWidth(void *_ctx, int page)
368 ENTER_SECTION
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();
373 float width;
374 if(rotate == 90 || rotate == 270)
375 width = pdfpage->getMediaHeight();
376 else
377 width = pdfpage->getMediaWidth();
378 LEAVE_SECTION
379 return width;
382 float pdfGetPageMediaHeight(void *_ctx, int page)
384 ENTER_SECTION
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();
389 float height;
390 if(rotate == 90 || rotate == 270)
391 height = pdfpage->getMediaWidth();
392 else
393 height = pdfpage->getMediaHeight();
394 LEAVE_SECTION
395 return height;
398 int pdfGetDocumentDimensions(void *_ctx, float *width, float *height)
400 struct devicecontext *ctx = (struct devicecontext*)_ctx;
402 *width = ctx->documentwidth;
403 *height = ctx->documentheight;
404 return 1;
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"));
420 return 0;
424 static void applyrotation(int *width, int *height, int rotation)
426 if(rotation == 90 || rotation == 270)
428 int t = *height;
429 *height = *width;
430 *width = t;
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)
437 ENTER_SECTION
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);
445 int rc = FALSE;
447 applyrotation(&width, &height, rotate);
448 applyrotation(&cropwidth, &cropheight, rotate);
450 #ifdef USE_SPLASH
451 #else
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);
459 ctx->surface = NULL;
463 if(ctx->surface == NULL)
465 ctx->surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
468 if(ctx->surface == NULL)
470 LEAVE_SECTION
471 return FALSE;
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);
490 #endif
492 //Delay(50);
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;
500 abortctx.ctx = ctx;
502 pdfpage->displaySlice(ctx->dev, 72 * scale, 72 * scale, rotate, gTrue, gFalse, sliceX, sliceY, sliceW, sliceH,
503 printing, abortcheckcbk_wrapper, &abortctx);
504 rc = TRUE;
506 catch(...)
508 D(kprintf("Exception during page rendering\n"));
511 //cairo_restore(ctx->cairo);
512 //Delay(20);
514 #ifndef USE_SPLASH
515 ctx->dev->setCairo(NULL);
516 cairo_destroy(ctx->cairo);
517 ctx->cairo = NULL;
518 #endif
519 //doc->displayPage(dev, page, hDPI, vDPI, rotate, useMediaBox, crop, printing);
521 LEAVE_SECTION
522 return rc;
526 unsigned char *pdfGetBitmapRowData(void *_ctx, int row)
528 struct devicecontext *ctx = (struct devicecontext*)_ctx;
529 #ifdef USE_SPLASH
530 return ctx->dev->getBitmap()->getDataPtr() + ctx->dev->getBitmap()->getRowSize() * row;
531 #else
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);
536 return data;
537 #endif
540 int pdfGetBitmapWidth(void *_ctx)
542 struct devicecontext *ctx = (struct devicecontext*)_ctx;
543 #ifdef USE_SPLASH
544 return ctx->dev->getBitmap()->getWidth();
545 #else
546 return cairo_image_surface_get_width(ctx->surface);
547 #endif
550 int pdfGetBitmapHeight(void *_ctx)
552 struct devicecontext *ctx = (struct devicecontext*)_ctx;
553 #ifdef USE_SPLASH
554 return ctx->dev->getBitmap()->getHeight();
555 #else
556 return cairo_image_surface_get_height(ctx->surface);
557 #endif
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)
571 free(region);
574 void pdfDisposeTextForSelection(void *_ctx, struct pdfSelectionText *text)
576 free(text);
579 struct pdfSelectionRegion *pdfBuildRegionForSelection(void *_ctx, int page, double x1, double y1, double x2, double y2, struct pdfSelectionRegion *previous)
581 ENTER_SECTION
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);
592 else
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();
606 int i;
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++)
613 Rectangle rect;
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 */
628 delete list;
630 int numrects = 0;
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;
640 int rectind = 0;
641 D(kprintf("build selection rectangles...\n"));
642 while(rrect != NULL)
644 int px, py;
645 int pw, ph;
647 int x, y;
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;
660 rrect = rrect->Next;
663 selection->numrects = numrects;
666 DisposeRegion(region);
668 LEAVE_SECTION
670 return selection;
673 struct pdfSelectionText *pdfBuildTextForSelection(void *_ctx, int page, double x1, double y1, double x2, double y2)
675 ENTER_SECTION
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);
687 delete text_dev;
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;
696 delete text;
698 LEAVE_SECTION
700 return selection;
703 static int actionGetPage(void *_doc, void *_action)
705 PDFDoc *doc = (PDFDoc*)_doc;
706 LinkAction *link_action = (LinkAction *)_action;
708 if(link_action == NULL)
709 return 0;
711 ENTER_SECTION
713 // printf("linkk:%p\n", link_action);
714 // printf("linkkind:%d\n", link_action->getKind());
716 switch(link_action->getKind())
718 case actionGoTo:
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());
725 if(d != NULL)
727 int ret;
728 if(d->isPageRef() == FALSE)
730 ret = d->getPageNum();
732 else
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);
739 ret = page;
741 LEAVE_SECTION
742 return ret;
745 #if 0
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)
754 LEAVE_SECTION
755 return link_goto->getDest()->getPageNum();
757 else
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);
764 LEAVE_SECTION
765 return page;
767 #endif
769 else
773 //action->type = POPPLER_ACTION_GOTO_DEST;
774 //build_goto_dest (document, action, dynamic_cast <LinkGoTo *> (link));
775 break;
776 case actionGoToR:
777 //action->type = POPPLER_ACTION_GOTO_REMOTE;
778 //build_goto_remote (action, dynamic_cast <LinkGoToR *> (link));
779 break;
780 case actionLaunch:
781 //action->type = POPPLER_ACTION_LAUNCH;
782 //build_launch (action, dynamic_cast <LinkLaunch *> (link));
783 break;
784 case actionURI:
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));
795 break;
796 case actionNamed:
797 //action->type = POPPLER_ACTION_NAMED;
798 //build_named (action, dynamic_cast <LinkNamed *> (link));
799 break;
800 case actionMovie:
801 //action->type = POPPLER_ACTION_MOVIE;
802 //build_movie (action, link);
803 break;
804 case actionUnknown:
805 default:
806 //action->type = POPPLER_ACTION_UNKNOWN;
807 break;
810 LEAVE_SECTION
811 return 0;
814 struct OutlineItemNode
816 struct MinNode n;
817 OutlineItem *item;
818 struct MinList *children;
819 char *title;
820 int page;
823 static struct MinList *buildoutlineitemlist(PDFDoc *doc, GooList *items)
825 struct MinList *l = (struct MinList*)calloc(1, sizeof(struct MinList));
826 if(l != NULL)
828 NEWLIST(l);
830 if(items != NULL)
833 int i;
835 for(i = 0; i < items->getLength(); i++)
837 struct OutlineItemNode *n = (struct OutlineItemNode*)calloc(1, sizeof(*n));
839 if(n != NULL)
841 n->item = (OutlineItem*)items->get(i);
842 n->item->open();
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());
855 ADDTAIL(l, n);
861 return l;
864 struct MinList *pdfGetOutlines(void *_ctx)
866 struct devicecontext *ctx = (struct devicecontext*)_ctx;
868 ENTER_SECTION
869 Outline *outline = ctx->doc->getOutline();
870 GooList *items = outline->getItems();
871 struct MinList *l = buildoutlineitemlist(ctx->doc, items);
872 LEAVE_SECTION
873 return l;
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;
903 void
904 poppler_page_get_size(Page *page,
905 double *width,
906 double *height)
908 double page_width, page_height;
909 int rotate;
911 ENTER_SECTION
913 rotate = page->getRotate();
914 if(rotate == 90 || rotate == 270)
916 page_height = page->getMediaWidth();
917 page_width = page->getMediaHeight();
919 else
921 page_width = page->getMediaWidth();
922 page_height = page->getMediaHeight();
925 if(width != NULL)
926 *width = page_width;
927 if(height != NULL)
928 *height = page_height;
930 LEAVE_SECTION
933 void pdfConvertUserToDevice(void *_ctx, double* x, double* y)
935 struct devicecontext *ctx = (struct devicecontext*)_ctx;
937 ENTER_SECTION
938 OutputDev *dev = ctx->dev;
939 int dx, dy;
940 dev->cvtUserToDev(*x, *y, &dx, &dy);
941 LEAVE_SECTION
942 *x = dx;
943 *y = dy;
946 void pdfConvertDeviceToUser(void *_ctx, int page, double x, double y, int *ix, int *iy)
948 struct devicecontext *ctx = (struct devicecontext*)_ctx;
950 ENTER_SECTION
951 OutputDev *dev = ctx->dev;
952 Page *pdfpage = ctx->doc->getCatalog()->getPage(page);
953 double dx, dy;
954 double ctm[6];
955 pdfpage->getDefaultCTM(ctm, 72, 72, 0, gFalse, gFalse);
956 dev->setDefaultCTM(ctm);
957 dev->cvtDevToUser(x, y, &dx, &dy);
958 LEAVE_SECTION
959 *ix = dx;
960 *iy = dy;
963 void pdfLock(void *_ctx)
965 ENTER_SECTION;
967 void pdfRelease(void *_ctx)
969 LEAVE_SECTION;
973 void *pdfFindLink(void *_ctx, int pagenum, int x, int y)
975 struct devicecontext *ctx = (struct devicecontext*)_ctx;
976 Links *links;
977 PObject obj;
978 Page *page;
980 double width, height;
982 ENTER_SECTION
984 Catalog *catalog = ctx->doc->getCatalog();
985 //printf("catalog:%p\n", catalog);
986 if(catalog == NULL)
988 LEAVE_SECTION
989 return NULL;
993 page = catalog->getPage(pagenum);
995 if(page == NULL)
997 LEAVE_SECTION
998 return NULL;
1002 links = new Links(page->getAnnots());
1003 obj.free();
1005 if(links == NULL)
1007 LEAVE_SECTION
1008 return NULL;
1011 poppler_page_get_size(page, &width, &height);
1013 if(links != NULL)
1015 //printf("links:%p\n", links);
1016 int num = links->getNumLinks();
1017 int i;
1019 //printf("num annots:%d\n", num);
1021 for(i = 0; i < num; i++)
1023 LinkAction *link_action;
1024 AnnotLink *link;
1026 link = links->getLink(i);
1027 link_action = link->getAction();
1029 if (link_action == NULL)
1030 continue;
1032 switch(link_action->getKind())
1034 case actionGoTo:
1036 LinkGoTo *link_goto = dynamic_cast<LinkGoTo*>(link_action);
1037 //if (link_goto->getDest() == NULL)
1038 // continue;
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));
1046 break;
1047 case actionGoToR:
1048 //action->type = POPPLER_ACTION_GOTO_REMOTE;
1049 //build_goto_remote (action, dynamic_cast <LinkGoToR *> (link));
1050 break;
1051 case actionLaunch:
1052 //action->type = POPPLER_ACTION_LAUNCH;
1053 //build_launch (action, dynamic_cast <LinkLaunch *> (link));
1054 break;
1055 case actionURI:
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));
1066 break;
1067 case actionNamed:
1068 //action->type = POPPLER_ACTION_NAMED;
1069 //build_named (action, dynamic_cast <LinkNamed *> (link));
1070 break;
1071 case actionMovie:
1072 //action->type = POPPLER_ACTION_MOVIE;
1073 //build_movie (action, link);
1074 break;
1075 case actionUnknown:
1076 default:
1077 //action->type = POPPLER_ACTION_UNKNOWN;
1078 break;
1081 double x1, y1, x2, y2;
1082 link->getRect(&x1, &y1, &x2, &y2);
1084 pdfConvertUserToDevice(_ctx, &x1, &y1);
1085 pdfConvertUserToDevice(_ctx, &x2, &y2);
1087 if(y1 > y2)
1089 double t = y1;
1090 y1 = y2;
1091 y2 = t;
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);
1099 LEAVE_SECTION
1100 return 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);
1116 //free(buff);
1117 //buff = convertToANSI(annot->get());
1118 //printf("annot%s\n", buff);
1119 //free(buff);
1124 delete links;
1126 LEAVE_SECTION
1127 return NULL;
1130 void pdfListLinks(void *_ctx, int pagenum)
1132 struct devicecontext *ctx = (struct devicecontext*)_ctx;
1134 Links *links;
1135 PObject obj;
1137 double width, height;
1138 ENTER_SECTION
1139 Catalog *catalog = ctx->doc->getCatalog();
1140 //printf("catalog:%p\n", catalog);
1141 if(catalog == NULL)
1143 LEAVE_SECTION
1144 return;
1147 Page *page = catalog->getPage(pagenum);
1148 //printf("page:%p\n", page);
1150 if(page == NULL)
1152 LEAVE_SECTION
1153 return;
1156 links = new Links(page->getAnnots());
1157 obj.free();
1159 if(links == NULL)
1161 LEAVE_SECTION;
1162 return;
1165 poppler_page_get_size(page, &width, &height);
1167 if(links != NULL)
1169 //printf("links:%p\n", links);
1170 int num = links->getNumLinks();
1171 int i;
1173 //printf("num annots:%d\n", num);
1175 for(i = 0; i < num; i++)
1177 AnnotLink *link;
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());
1190 LEAVE_SECTION
1191 delete links;
1194 char *linkGetDescription(void *_link)
1196 AnnotLink *link = (AnnotLink*)_link;
1197 LinkAction *link_action = link->getAction();
1199 ENTER_SECTION
1201 switch(link_action->getKind())
1203 case actionGoTo:
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));
1218 break;
1219 case actionGoToR:
1220 //action->type = POPPLER_ACTION_GOTO_REMOTE;
1221 //build_goto_remote (action, dynamic_cast <LinkGoToR *> (link));
1222 break;
1223 case actionLaunch:
1224 //action->type = POPPLER_ACTION_LAUNCH;
1225 //build_launch (action, dynamic_cast <LinkLaunch *> (link));
1226 break;
1227 case actionURI:
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));
1238 break;
1239 case actionNamed:
1240 //action->type = POPPLER_ACTION_NAMED;
1241 //build_named (action, dynamic_cast <LinkNamed *> (link));
1242 break;
1243 case actionMovie:
1244 //action->type = POPPLER_ACTION_MOVIE;
1245 //build_movie (action, link);
1246 break;
1247 case actionUnknown:
1248 default:
1249 //action->type = POPPLER_ACTION_UNKNOWN;
1250 break;
1253 LEAVE_SECTION
1254 return NULL;
1257 int pdfGetActionPageFromLink(void *_ctx, void *_link)
1259 ENTER_SECTION
1260 struct devicecontext *ctx = (struct devicecontext*)_ctx;
1261 AnnotLink *link = (AnnotLink*)_link;
1262 int page = actionGetPage(ctx->doc, link->getAction());
1263 LEAVE_SECTION
1264 return page;
1267 static struct searchresult *nextsearchresult(struct devicecontext *ctx, int direction)
1269 if(direction > 0)
1271 return (struct searchresult*)GetSucc(ctx->search.currentsearchresult);
1273 else
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)
1283 ENTER_SECTION
1284 struct devicecontext *ctx = (struct devicecontext*)_ctx;
1285 int found = FALSE;
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);
1296 REMOVE(srn);
1297 free(srn);
1300 ctx->search.phrase = strdup(phrase);
1301 ctx->search.currentsearchresult = NULL;
1302 LEAVE_SECTION
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);
1315 REMOVE(srn);
1316 free(srn);
1319 ctx->search.phrase = strdup(phrase);
1320 ctx->search.page = *page;
1321 ctx->search.currentsearchresult = NULL;
1323 /* new search */
1325 #if defined(__AROS__)
1326 kprintf("[pdfSearch] not implemented\n");
1327 // FIXME: AROS
1328 #else
1329 WCHAR *phraseUCS4 = convertToUCS4(phrase);
1331 TextOutputDev *text_dev = new TextOutputDev(NULL, gTrue, 0, gFalse, gFalse);
1334 double xMin, yMin, xMax, yMax;
1335 double height;
1336 Page *pdfpage = ctx->doc->getCatalog()->getPage(*page);
1338 pdfpage->display(text_dev, 72, 72, 0,
1339 gTrue, gTrue, gFalse);
1341 height = pdfpage->getMediaHeight();
1343 xMin = 0;
1344 yMin = 0;
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))
1353 double ctm[6];
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);
1368 found = TRUE;
1372 delete text_dev;
1373 free(phraseUCS4);
1374 #endif
1375 if (found == FALSE)
1377 LEAVE_SECTION
1378 return PDFSEARCH_NEXTPAGE;
1381 if (found)
1383 if(direction > 0)
1384 ctx->search.currentsearchresult = (struct searchresult*)GetHead(&ctx->search.searchresultlist);
1385 else
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);
1398 found = TRUE;
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;
1409 LEAVE_SECTION
1410 return found ? PDFSEARCH_FOUND : PDFSEARCH_NOTFOUND;
1413 static char *goo_string_to_utf8(GooString *s)
1415 char *result;
1417 if(s->hasUnicodeMarker())
1419 result = convertToANSI(s);
1421 else
1423 int len;
1424 Unicode *ucs4_temp;
1425 int i;
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)];
1433 ucs4_temp[i] = 0;
1435 result = convertUTF32ToANSI(ucs4_temp, s->getLength());
1437 free(ucs4_temp);
1440 return result;
1443 static char *info_dict_get_string(Dict *info_dict, const char *key)
1445 GooString *goo_value;
1446 char *result;
1447 PObject obj;
1449 if(!info_dict->lookup((char *)key, &obj)->isString())
1451 obj.free();
1452 return NULL;
1455 goo_value = obj.getString();
1456 result = goo_string_to_utf8(goo_value);
1458 obj.free();
1459 return result;
1462 static struct pdfAttribute *buildStringAttribute(char *value)
1464 struct pdfAttribute *attr = (struct pdfAttribute*)malloc(sizeof(*attr));
1465 if(attr != NULL)
1467 attr->type = PDFATTRTYPE_STRING;
1468 attr->value.s = value;
1471 return attr;
1474 struct pdfAttribute *pdfGetAttr(void *_ctx, int property)
1476 ENTER_SECTION
1477 struct devicecontext *ctx = (struct devicecontext*)_ctx;
1478 PObject obj;
1479 struct pdfAttribute *ret = NULL;
1481 ctx->doc->getDocInfo(&obj);
1482 if(!obj.isDict())
1484 LEAVE_SECTION;
1485 return NULL;
1488 switch(property)
1490 case PDFATTR_TITLE:
1491 ret = buildStringAttribute(info_dict_get_string(obj.getDict(), "Title"));
1492 break;
1495 LEAVE_SECTION;
1496 return ret;
1500 void pdfFreeAttr(void *_ctx, struct pdfAttribute *attr)
1502 if(attr != NULL)
1504 if(attr->value.s != NULL && attr->type == PDFATTRTYPE_STRING)
1505 free(attr->value.s);
1507 free(attr);
1511 /* annotations */
1513 struct MinList *pdfGetAnnotations(void *_ctx, int page)
1515 ENTER_SECTION
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)
1522 LEAVE_SECTION
1523 return NULL;
1526 struct MinList *l = (struct MinList*)calloc(1, sizeof(*l));
1527 if (l == NULL)
1529 LEAVE_SECTION
1530 return NULL;
1533 NEWLIST(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:
1566 case Annot::type3D:
1567 if (pdfAnnot->getContents() != NULL)
1569 annot = (struct pdfAnnotation*)calloc(1, sizeof(*annot));
1570 if (annot != NULL)
1572 annot->type = 0; // TODO
1573 //annot->author = convertToANSI(pdfAnnot->getAuthor());
1574 annot->contents = convertToANSI(pdfAnnot->getContents());
1577 break;
1578 default:
1583 if (annot != NULL)
1585 int rotation = 0;
1586 double width = pdfGetPageMediaWidth(_ctx, page);
1587 double height = pdfGetPageMediaHeight(_ctx, page);
1588 PDFRectangle rect;
1590 if (!(pdfAnnot->getFlags () & Annot::flagNoRotate))
1591 rotation = pdfpage->getRotate();
1593 rect = *(pdfAnnot->getRect());
1595 switch (rotation)
1597 case 90:
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);
1602 break;
1603 case 180:
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);
1608 break;
1609 case 270:
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);
1614 break;
1615 default:
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();
1629 ADDTAIL(l, annot);
1634 LEAVE_SECTION
1635 return l;