Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
7639 views
1
#include <jni.h>
2
#include <time.h>
3
#include <pthread.h>
4
#include <android/log.h>
5
#include <android/bitmap.h>
6
7
#include <stdio.h>
8
#include <stdlib.h>
9
#include <math.h>
10
11
#ifdef NDK_PROFILER
12
#include "prof.h"
13
#endif
14
15
#include "mupdf/fitz.h"
16
#include "mupdf/pdf.h"
17
18
#define JNI_FN(A) Java_com_artifex_mupdfdemo_ ## A
19
#define PACKAGENAME "com/artifex/mupdfdemo"
20
21
#define LOG_TAG "libmupdf"
22
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
23
#define LOGT(...) __android_log_print(ANDROID_LOG_INFO,"alert",__VA_ARGS__)
24
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
25
26
/* Set to 1 to enable debug log traces. */
27
#define DEBUG 0
28
29
/* Enable to log rendering times (render each frame 100 times and time) */
30
#undef TIME_DISPLAY_LIST
31
32
#define MAX_SEARCH_HITS (500)
33
#define NUM_CACHE (3)
34
#define STRIKE_HEIGHT (0.375f)
35
#define UNDERLINE_HEIGHT (0.075f)
36
#define LINE_THICKNESS (0.07f)
37
#define INK_THICKNESS (4.0f)
38
#define SMALL_FLOAT (0.00001)
39
40
enum
41
{
42
NONE,
43
TEXT,
44
LISTBOX,
45
COMBOBOX,
46
SIGNATURE
47
};
48
49
typedef struct rect_node_s rect_node;
50
51
struct rect_node_s
52
{
53
fz_rect rect;
54
rect_node *next;
55
};
56
57
typedef struct
58
{
59
int number;
60
int width;
61
int height;
62
fz_rect media_box;
63
fz_page *page;
64
rect_node *changed_rects;
65
rect_node *hq_changed_rects;
66
fz_display_list *page_list;
67
fz_display_list *annot_list;
68
} page_cache;
69
70
typedef struct globals_s globals;
71
72
struct globals_s
73
{
74
fz_colorspace *colorspace;
75
fz_document *doc;
76
int resolution;
77
fz_context *ctx;
78
fz_rect *hit_bbox;
79
int current;
80
char *current_path;
81
82
page_cache pages[NUM_CACHE];
83
84
int alerts_initialised;
85
// fin_lock and fin_lock2 are used during shutdown. The two waiting tasks
86
// show_alert and waitForAlertInternal respectively take these locks while
87
// waiting. During shutdown, the conditions are signaled and then the fin_locks
88
// are taken momentarily to ensure the blocked threads leave the controlled
89
// area of code before the mutexes and condition variables are destroyed.
90
pthread_mutex_t fin_lock;
91
pthread_mutex_t fin_lock2;
92
// alert_lock is the main lock guarding the variables directly below.
93
pthread_mutex_t alert_lock;
94
// Flag indicating if the alert system is active. When not active, both
95
// show_alert and waitForAlertInternal return immediately.
96
int alerts_active;
97
// Pointer to the alert struct passed in by show_alert, and valid while
98
// show_alert is blocked.
99
pdf_alert_event *current_alert;
100
// Flag and condition varibles to signal a request is present and a reply
101
// is present, respectively. The condition variables alone are not sufficient
102
// because of the pthreads permit spurious signals.
103
int alert_request;
104
int alert_reply;
105
pthread_cond_t alert_request_cond;
106
pthread_cond_t alert_reply_cond;
107
108
// For the buffer reading mode, we need to implement stream reading, which
109
// needs access to the following.
110
JNIEnv *env;
111
jclass thiz;
112
};
113
114
static jfieldID global_fid;
115
static jfieldID buffer_fid;
116
117
static void drop_changed_rects(fz_context *ctx, rect_node **nodePtr)
118
{
119
rect_node *node = *nodePtr;
120
while (node)
121
{
122
rect_node *tnode = node;
123
node = node->next;
124
fz_free(ctx, tnode);
125
}
126
127
*nodePtr = NULL;
128
}
129
130
static void drop_page_cache(globals *glo, page_cache *pc)
131
{
132
fz_context *ctx = glo->ctx;
133
fz_document *doc = glo->doc;
134
135
LOGI("Drop page %d", pc->number);
136
fz_drop_display_list(ctx, pc->page_list);
137
pc->page_list = NULL;
138
fz_drop_display_list(ctx, pc->annot_list);
139
pc->annot_list = NULL;
140
fz_drop_page(ctx, pc->page);
141
pc->page = NULL;
142
drop_changed_rects(ctx, &pc->changed_rects);
143
drop_changed_rects(ctx, &pc->hq_changed_rects);
144
}
145
146
static void dump_annotation_display_lists(globals *glo)
147
{
148
fz_context *ctx = glo->ctx;
149
int i;
150
151
for (i = 0; i < NUM_CACHE; i++) {
152
fz_drop_display_list(ctx, glo->pages[i].annot_list);
153
glo->pages[i].annot_list = NULL;
154
}
155
}
156
157
static void show_alert(globals *glo, pdf_alert_event *alert)
158
{
159
pthread_mutex_lock(&glo->fin_lock2);
160
pthread_mutex_lock(&glo->alert_lock);
161
162
LOGT("Enter show_alert: %s", alert->title);
163
alert->button_pressed = 0;
164
165
if (glo->alerts_active)
166
{
167
glo->current_alert = alert;
168
glo->alert_request = 1;
169
pthread_cond_signal(&glo->alert_request_cond);
170
171
while (glo->alerts_active && !glo->alert_reply)
172
pthread_cond_wait(&glo->alert_reply_cond, &glo->alert_lock);
173
glo->alert_reply = 0;
174
glo->current_alert = NULL;
175
}
176
177
LOGT("Exit show_alert");
178
179
pthread_mutex_unlock(&glo->alert_lock);
180
pthread_mutex_unlock(&glo->fin_lock2);
181
}
182
183
static void event_cb(fz_context *ctx, pdf_document *doc, pdf_doc_event *event, void *data)
184
{
185
globals *glo = (globals *)data;
186
187
switch (event->type)
188
{
189
case PDF_DOCUMENT_EVENT_ALERT:
190
show_alert(glo, pdf_access_alert_event(ctx, event));
191
break;
192
}
193
}
194
195
static void alerts_init(globals *glo)
196
{
197
fz_context *ctx = glo->ctx;
198
pdf_document *idoc = pdf_specifics(ctx, glo->doc);
199
200
if (!idoc || glo->alerts_initialised)
201
return;
202
203
if (idoc)
204
pdf_enable_js(ctx, idoc);
205
206
glo->alerts_active = 0;
207
glo->alert_request = 0;
208
glo->alert_reply = 0;
209
pthread_mutex_init(&glo->fin_lock, NULL);
210
pthread_mutex_init(&glo->fin_lock2, NULL);
211
pthread_mutex_init(&glo->alert_lock, NULL);
212
pthread_cond_init(&glo->alert_request_cond, NULL);
213
pthread_cond_init(&glo->alert_reply_cond, NULL);
214
215
pdf_set_doc_event_callback(ctx, idoc, event_cb, glo);
216
LOGT("alert_init");
217
glo->alerts_initialised = 1;
218
}
219
220
static void alerts_fin(globals *glo)
221
{
222
fz_context *ctx = glo->ctx;
223
pdf_document *idoc = pdf_specifics(ctx, glo->doc);
224
if (!glo->alerts_initialised)
225
return;
226
227
LOGT("Enter alerts_fin");
228
if (idoc)
229
pdf_set_doc_event_callback(ctx, idoc, NULL, NULL);
230
231
// Set alerts_active false and wake up show_alert and waitForAlertInternal,
232
pthread_mutex_lock(&glo->alert_lock);
233
glo->current_alert = NULL;
234
glo->alerts_active = 0;
235
pthread_cond_signal(&glo->alert_request_cond);
236
pthread_cond_signal(&glo->alert_reply_cond);
237
pthread_mutex_unlock(&glo->alert_lock);
238
239
// Wait for the fin_locks.
240
pthread_mutex_lock(&glo->fin_lock);
241
pthread_mutex_unlock(&glo->fin_lock);
242
pthread_mutex_lock(&glo->fin_lock2);
243
pthread_mutex_unlock(&glo->fin_lock2);
244
245
pthread_cond_destroy(&glo->alert_reply_cond);
246
pthread_cond_destroy(&glo->alert_request_cond);
247
pthread_mutex_destroy(&glo->alert_lock);
248
pthread_mutex_destroy(&glo->fin_lock2);
249
pthread_mutex_destroy(&glo->fin_lock);
250
LOGT("Exit alerts_fin");
251
glo->alerts_initialised = 0;
252
}
253
254
// Should only be called from the single background AsyncTask thread
255
static globals *get_globals(JNIEnv *env, jobject thiz)
256
{
257
globals *glo = (globals *)(intptr_t)((*env)->GetLongField(env, thiz, global_fid));
258
if (glo != NULL)
259
{
260
glo->env = env;
261
glo->thiz = thiz;
262
}
263
return glo;
264
}
265
266
// May be called from any thread, provided the values of glo->env and glo->thiz
267
// are not used.
268
static globals *get_globals_any_thread(JNIEnv *env, jobject thiz)
269
{
270
return (globals *)(intptr_t)((*env)->GetLongField(env, thiz, global_fid));
271
}
272
273
JNIEXPORT jlong JNICALL
274
JNI_FN(MuPDFCore_openFile)(JNIEnv * env, jobject thiz, jstring jfilename)
275
{
276
const char *filename;
277
globals *glo;
278
fz_context *ctx;
279
jclass clazz;
280
281
#ifdef NDK_PROFILER
282
monstartup("libmupdf.so");
283
#endif
284
285
clazz = (*env)->GetObjectClass(env, thiz);
286
global_fid = (*env)->GetFieldID(env, clazz, "globals", "J");
287
288
glo = calloc(1, sizeof(*glo));
289
if (glo == NULL)
290
return 0;
291
glo->resolution = 160;
292
glo->alerts_initialised = 0;
293
294
filename = (*env)->GetStringUTFChars(env, jfilename, NULL);
295
if (filename == NULL)
296
{
297
LOGE("Failed to get filename");
298
free(glo);
299
return 0;
300
}
301
302
/* 128 MB store for low memory devices. Tweak as necessary. */
303
glo->ctx = ctx = fz_new_context(NULL, NULL, 128 << 20);
304
if (!ctx)
305
{
306
LOGE("Failed to initialise context");
307
(*env)->ReleaseStringUTFChars(env, jfilename, filename);
308
free(glo);
309
return 0;
310
}
311
312
fz_register_document_handlers(ctx);
313
314
glo->doc = NULL;
315
fz_try(ctx)
316
{
317
glo->colorspace = fz_device_rgb(ctx);
318
319
LOGI("Opening document...");
320
fz_try(ctx)
321
{
322
glo->current_path = fz_strdup(ctx, (char *)filename);
323
glo->doc = fz_open_document(ctx, (char *)filename);
324
alerts_init(glo);
325
}
326
fz_catch(ctx)
327
{
328
fz_throw(ctx, FZ_ERROR_GENERIC, "Cannot open document: '%s'", filename);
329
}
330
LOGI("Done!");
331
}
332
fz_catch(ctx)
333
{
334
LOGE("Failed: %s", ctx->error->message);
335
fz_drop_document(ctx, glo->doc);
336
glo->doc = NULL;
337
fz_drop_context(ctx);
338
glo->ctx = NULL;
339
free(glo);
340
glo = NULL;
341
}
342
343
(*env)->ReleaseStringUTFChars(env, jfilename, filename);
344
345
return (jlong)(intptr_t)glo;
346
}
347
348
typedef struct buffer_state_s
349
{
350
globals *globals;
351
char buffer[4096];
352
}
353
buffer_state;
354
355
static int bufferStreamNext(fz_context *ctx, fz_stream *stream, int max)
356
{
357
buffer_state *bs = (buffer_state *)stream->state;
358
globals *glo = bs->globals;
359
JNIEnv *env = glo->env;
360
jbyteArray array = (jbyteArray)(void *)((*env)->GetObjectField(env, glo->thiz, buffer_fid));
361
int arrayLength = (*env)->GetArrayLength(env, array);
362
int len = sizeof(bs->buffer);
363
364
if (stream->pos > arrayLength)
365
stream->pos = arrayLength;
366
if (stream->pos < 0)
367
stream->pos = 0;
368
if (len + stream->pos > arrayLength)
369
len = arrayLength - stream->pos;
370
371
(*env)->GetByteArrayRegion(env, array, stream->pos, len, bs->buffer);
372
(*env)->DeleteLocalRef(env, array);
373
374
stream->rp = bs->buffer;
375
stream->wp = stream->rp + len;
376
stream->pos += len;
377
if (len == 0)
378
return EOF;
379
return *stream->rp++;
380
}
381
382
static void bufferStreamClose(fz_context *ctx, void *state)
383
{
384
fz_free(ctx, state);
385
}
386
387
static void bufferStreamSeek(fz_context *ctx, fz_stream *stream, int offset, int whence)
388
{
389
buffer_state *bs = (buffer_state *)stream->state;
390
globals *glo = bs->globals;
391
JNIEnv *env = glo->env;
392
jbyteArray array = (jbyteArray)(void *)((*env)->GetObjectField(env, glo->thiz, buffer_fid));
393
int arrayLength = (*env)->GetArrayLength(env, array);
394
395
(*env)->DeleteLocalRef(env, array);
396
397
if (whence == 0) /* SEEK_SET */
398
stream->pos = offset;
399
else if (whence == 1) /* SEEK_CUR */
400
stream->pos += offset;
401
else if (whence == 2) /* SEEK_END */
402
stream->pos = arrayLength + offset;
403
404
if (stream->pos > arrayLength)
405
stream->pos = arrayLength;
406
if (stream->pos < 0)
407
stream->pos = 0;
408
409
stream->wp = stream->rp;
410
}
411
412
JNIEXPORT jlong JNICALL
413
JNI_FN(MuPDFCore_openBuffer)(JNIEnv * env, jobject thiz, jstring jmagic)
414
{
415
globals *glo;
416
fz_context *ctx;
417
jclass clazz;
418
fz_stream *stream = NULL;
419
buffer_state *bs;
420
const char *magic;
421
422
#ifdef NDK_PROFILER
423
monstartup("libmupdf.so");
424
#endif
425
426
clazz = (*env)->GetObjectClass(env, thiz);
427
global_fid = (*env)->GetFieldID(env, clazz, "globals", "J");
428
429
glo = calloc(1, sizeof(*glo));
430
if (glo == NULL)
431
return 0;
432
glo->resolution = 160;
433
glo->alerts_initialised = 0;
434
glo->env = env;
435
glo->thiz = thiz;
436
buffer_fid = (*env)->GetFieldID(env, clazz, "fileBuffer", "[B");
437
438
magic = (*env)->GetStringUTFChars(env, jmagic, NULL);
439
if (magic == NULL)
440
{
441
LOGE("Failed to get magic");
442
free(glo);
443
return 0;
444
}
445
446
/* 128 MB store for low memory devices. Tweak as necessary. */
447
glo->ctx = ctx = fz_new_context(NULL, NULL, 128 << 20);
448
if (!ctx)
449
{
450
LOGE("Failed to initialise context");
451
(*env)->ReleaseStringUTFChars(env, jmagic, magic);
452
free(glo);
453
return 0;
454
}
455
456
fz_register_document_handlers(ctx);
457
fz_var(stream);
458
459
glo->doc = NULL;
460
fz_try(ctx)
461
{
462
bs = fz_malloc_struct(ctx, buffer_state);
463
bs->globals = glo;
464
stream = fz_new_stream(ctx, bs, bufferStreamNext, bufferStreamClose);
465
stream->seek = bufferStreamSeek;
466
467
glo->colorspace = fz_device_rgb(ctx);
468
469
LOGI("Opening document...");
470
fz_try(ctx)
471
{
472
glo->current_path = NULL;
473
glo->doc = fz_open_document_with_stream(ctx, magic, stream);
474
alerts_init(glo);
475
}
476
fz_catch(ctx)
477
{
478
fz_throw(ctx, FZ_ERROR_GENERIC, "Cannot open memory document");
479
}
480
LOGI("Done!");
481
}
482
fz_always(ctx)
483
{
484
fz_drop_stream(ctx, stream);
485
}
486
fz_catch(ctx)
487
{
488
LOGE("Failed: %s", ctx->error->message);
489
fz_drop_document(ctx, glo->doc);
490
glo->doc = NULL;
491
fz_drop_context(ctx);
492
glo->ctx = NULL;
493
free(glo);
494
glo = NULL;
495
}
496
497
(*env)->ReleaseStringUTFChars(env, jmagic, magic);
498
499
return (jlong)(intptr_t)glo;
500
}
501
502
JNIEXPORT int JNICALL
503
JNI_FN(MuPDFCore_countPagesInternal)(JNIEnv *env, jobject thiz)
504
{
505
globals *glo = get_globals(env, thiz);
506
fz_context *ctx = glo->ctx;
507
int count = 0;
508
509
fz_try(ctx)
510
{
511
count = fz_count_pages(ctx, glo->doc);
512
}
513
fz_catch(ctx)
514
{
515
LOGE("exception while counting pages: %s", ctx->error->message);
516
}
517
return count;
518
}
519
520
JNIEXPORT jstring JNICALL
521
JNI_FN(MuPDFCore_fileFormatInternal)(JNIEnv * env, jobject thiz)
522
{
523
char info[64];
524
globals *glo = get_globals(env, thiz);
525
fz_context *ctx = glo->ctx;
526
527
fz_lookup_metadata(ctx, glo->doc, FZ_META_FORMAT, info, sizeof(info));
528
529
return (*env)->NewStringUTF(env, info);
530
}
531
532
JNIEXPORT jboolean JNICALL
533
JNI_FN(MuPDFCore_isUnencryptedPDFInternal)(JNIEnv * env, jobject thiz)
534
{
535
globals *glo = get_globals_any_thread(env, thiz);
536
if (glo == NULL)
537
return JNI_FALSE;
538
539
fz_context *ctx = glo->ctx;
540
pdf_document *idoc = pdf_specifics(ctx, glo->doc);
541
if (idoc == NULL)
542
return JNI_FALSE; // Not a PDF
543
544
int cryptVer = pdf_crypt_version(ctx, idoc);
545
return (cryptVer == 0) ? JNI_TRUE : JNI_FALSE;
546
}
547
548
JNIEXPORT void JNICALL
549
JNI_FN(MuPDFCore_gotoPageInternal)(JNIEnv *env, jobject thiz, int page)
550
{
551
int i;
552
int furthest;
553
int furthest_dist = -1;
554
float zoom;
555
fz_matrix ctm;
556
fz_irect bbox;
557
page_cache *pc;
558
globals *glo = get_globals(env, thiz);
559
if (glo == NULL)
560
return;
561
fz_context *ctx = glo->ctx;
562
563
for (i = 0; i < NUM_CACHE; i++)
564
{
565
if (glo->pages[i].page != NULL && glo->pages[i].number == page)
566
{
567
/* The page is already cached */
568
glo->current = i;
569
return;
570
}
571
572
if (glo->pages[i].page == NULL)
573
{
574
/* cache record unused, and so a good one to use */
575
furthest = i;
576
furthest_dist = INT_MAX;
577
}
578
else
579
{
580
int dist = abs(glo->pages[i].number - page);
581
582
/* Further away - less likely to be needed again */
583
if (dist > furthest_dist)
584
{
585
furthest_dist = dist;
586
furthest = i;
587
}
588
}
589
}
590
591
glo->current = furthest;
592
pc = &glo->pages[glo->current];
593
594
drop_page_cache(glo, pc);
595
596
/* In the event of an error, ensure we give a non-empty page */
597
pc->width = 100;
598
pc->height = 100;
599
600
pc->number = page;
601
LOGI("Goto page %d...", page);
602
fz_try(ctx)
603
{
604
fz_rect rect;
605
LOGI("Load page %d", pc->number);
606
pc->page = fz_load_page(ctx, glo->doc, pc->number);
607
zoom = glo->resolution / 72;
608
fz_bound_page(ctx, pc->page, &pc->media_box);
609
fz_scale(&ctm, zoom, zoom);
610
rect = pc->media_box;
611
fz_round_rect(&bbox, fz_transform_rect(&rect, &ctm));
612
pc->width = bbox.x1-bbox.x0;
613
pc->height = bbox.y1-bbox.y0;
614
}
615
fz_catch(ctx)
616
{
617
LOGE("cannot make displaylist from page %d", pc->number);
618
}
619
}
620
621
JNIEXPORT float JNICALL
622
JNI_FN(MuPDFCore_getPageWidth)(JNIEnv *env, jobject thiz)
623
{
624
globals *glo = get_globals(env, thiz);
625
LOGI("PageWidth=%d", glo->pages[glo->current].width);
626
return glo->pages[glo->current].width;
627
}
628
629
JNIEXPORT float JNICALL
630
JNI_FN(MuPDFCore_getPageHeight)(JNIEnv *env, jobject thiz)
631
{
632
globals *glo = get_globals(env, thiz);
633
LOGI("PageHeight=%d", glo->pages[glo->current].height);
634
return glo->pages[glo->current].height;
635
}
636
637
JNIEXPORT jboolean JNICALL
638
JNI_FN(MuPDFCore_javascriptSupported)(JNIEnv *env, jobject thiz)
639
{
640
globals *glo = get_globals(env, thiz);
641
fz_context *ctx = glo->ctx;
642
pdf_document *idoc = pdf_specifics(ctx, glo->doc);
643
if (idoc)
644
return pdf_js_supported(ctx, idoc);
645
return 0;
646
}
647
648
static void update_changed_rects(globals *glo, page_cache *pc, pdf_document *idoc)
649
{
650
fz_context *ctx = glo->ctx;
651
fz_annot *annot;
652
653
pdf_update_page(ctx, idoc, (pdf_page *)pc->page);
654
while ((annot = (fz_annot *)pdf_poll_changed_annot(ctx, idoc, (pdf_page *)pc->page)) != NULL)
655
{
656
/* FIXME: We bound the annot twice here */
657
rect_node *node = fz_malloc_struct(glo->ctx, rect_node);
658
fz_bound_annot(ctx, pc->page, annot, &node->rect);
659
node->next = pc->changed_rects;
660
pc->changed_rects = node;
661
662
node = fz_malloc_struct(glo->ctx, rect_node);
663
fz_bound_annot(ctx, pc->page, annot, &node->rect);
664
node->next = pc->hq_changed_rects;
665
pc->hq_changed_rects = node;
666
}
667
}
668
669
JNIEXPORT jboolean JNICALL
670
JNI_FN(MuPDFCore_drawPage)(JNIEnv *env, jobject thiz, jobject bitmap,
671
int pageW, int pageH, int patchX, int patchY, int patchW, int patchH, jlong cookiePtr)
672
{
673
AndroidBitmapInfo info;
674
void *pixels;
675
int ret;
676
fz_device *dev = NULL;
677
float zoom;
678
fz_matrix ctm;
679
fz_irect bbox;
680
fz_rect rect;
681
fz_pixmap *pix = NULL;
682
float xscale, yscale;
683
globals *glo = get_globals(env, thiz);
684
fz_context *ctx = glo->ctx;
685
fz_document *doc = glo->doc;
686
page_cache *pc = &glo->pages[glo->current];
687
int hq = (patchW < pageW || patchH < pageH);
688
fz_matrix scale;
689
fz_cookie *cookie = (fz_cookie *)(intptr_t)cookiePtr;
690
691
if (pc->page == NULL)
692
return 0;
693
694
fz_var(pix);
695
fz_var(dev);
696
697
LOGI("In native method\n");
698
if ((ret = AndroidBitmap_getInfo(env, bitmap, &info)) < 0) {
699
LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret);
700
return 0;
701
}
702
703
LOGI("Checking format\n");
704
if (info.format != ANDROID_BITMAP_FORMAT_RGBA_8888) {
705
LOGE("Bitmap format is not RGBA_8888 !");
706
return 0;
707
}
708
709
LOGI("locking pixels\n");
710
if ((ret = AndroidBitmap_lockPixels(env, bitmap, &pixels)) < 0) {
711
LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret);
712
return 0;
713
}
714
715
/* Call mupdf to render display list to screen */
716
LOGI("Rendering page(%d)=%dx%d patch=[%d,%d,%d,%d]",
717
pc->number, pageW, pageH, patchX, patchY, patchW, patchH);
718
719
fz_try(ctx)
720
{
721
fz_irect pixbbox;
722
pdf_document *idoc = pdf_specifics(ctx, doc);
723
724
if (idoc)
725
{
726
/* Update the changed-rects for both hq patch and main bitmap */
727
update_changed_rects(glo, pc, idoc);
728
729
/* Then drop the changed-rects for the bitmap we're about to
730
render because we are rendering the entire area */
731
drop_changed_rects(ctx, hq ? &pc->hq_changed_rects : &pc->changed_rects);
732
}
733
734
if (pc->page_list == NULL)
735
{
736
/* Render to list */
737
pc->page_list = fz_new_display_list(ctx);
738
dev = fz_new_list_device(ctx, pc->page_list);
739
fz_run_page_contents(ctx, pc->page, dev, &fz_identity, cookie);
740
fz_drop_device(ctx, dev);
741
dev = NULL;
742
if (cookie != NULL && cookie->abort)
743
{
744
fz_drop_display_list(ctx, pc->page_list);
745
pc->page_list = NULL;
746
fz_throw(ctx, FZ_ERROR_GENERIC, "Render aborted");
747
}
748
}
749
if (pc->annot_list == NULL)
750
{
751
fz_annot *annot;
752
pc->annot_list = fz_new_display_list(ctx);
753
dev = fz_new_list_device(ctx, pc->annot_list);
754
for (annot = fz_first_annot(ctx, pc->page); annot; annot = fz_next_annot(ctx, pc->page, annot))
755
fz_run_annot(ctx, pc->page, annot, dev, &fz_identity, cookie);
756
fz_drop_device(ctx, dev);
757
dev = NULL;
758
if (cookie != NULL && cookie->abort)
759
{
760
fz_drop_display_list(ctx, pc->annot_list);
761
pc->annot_list = NULL;
762
fz_throw(ctx, FZ_ERROR_GENERIC, "Render aborted");
763
}
764
}
765
bbox.x0 = patchX;
766
bbox.y0 = patchY;
767
bbox.x1 = patchX + patchW;
768
bbox.y1 = patchY + patchH;
769
pixbbox = bbox;
770
pixbbox.x1 = pixbbox.x0 + info.width;
771
/* pixmaps cannot handle right-edge padding, so the bbox must be expanded to
772
* match the pixels data */
773
pix = fz_new_pixmap_with_bbox_and_data(ctx, glo->colorspace, &pixbbox, pixels);
774
if (pc->page_list == NULL && pc->annot_list == NULL)
775
{
776
fz_clear_pixmap_with_value(ctx, pix, 0xd0);
777
break;
778
}
779
fz_clear_pixmap_with_value(ctx, pix, 0xff);
780
781
zoom = glo->resolution / 72;
782
fz_scale(&ctm, zoom, zoom);
783
rect = pc->media_box;
784
fz_round_rect(&bbox, fz_transform_rect(&rect, &ctm));
785
/* Now, adjust ctm so that it would give the correct page width
786
* heights. */
787
xscale = (float)pageW/(float)(bbox.x1-bbox.x0);
788
yscale = (float)pageH/(float)(bbox.y1-bbox.y0);
789
fz_concat(&ctm, &ctm, fz_scale(&scale, xscale, yscale));
790
rect = pc->media_box;
791
fz_transform_rect(&rect, &ctm);
792
dev = fz_new_draw_device(ctx, pix);
793
#ifdef TIME_DISPLAY_LIST
794
{
795
clock_t time;
796
int i;
797
798
LOGI("Executing display list");
799
time = clock();
800
for (i=0; i<100;i++) {
801
#endif
802
if (pc->page_list)
803
fz_run_display_list(ctx, pc->page_list, dev, &ctm, &rect, cookie);
804
if (cookie != NULL && cookie->abort)
805
fz_throw(ctx, FZ_ERROR_GENERIC, "Render aborted");
806
807
if (pc->annot_list)
808
fz_run_display_list(ctx, pc->annot_list, dev, &ctm, &rect, cookie);
809
if (cookie != NULL && cookie->abort)
810
fz_throw(ctx, FZ_ERROR_GENERIC, "Render aborted");
811
812
#ifdef TIME_DISPLAY_LIST
813
}
814
time = clock() - time;
815
LOGI("100 renders in %d (%d per sec)", time, CLOCKS_PER_SEC);
816
}
817
#endif
818
fz_drop_device(ctx, dev);
819
dev = NULL;
820
fz_drop_pixmap(ctx, pix);
821
LOGI("Rendered");
822
}
823
fz_always(ctx)
824
{
825
fz_drop_device(ctx, dev);
826
dev = NULL;
827
}
828
fz_catch(ctx)
829
{
830
LOGE("Render failed");
831
}
832
833
AndroidBitmap_unlockPixels(env, bitmap);
834
835
return 1;
836
}
837
838
static char *widget_type_string(int t)
839
{
840
switch(t)
841
{
842
case PDF_WIDGET_TYPE_PUSHBUTTON: return "pushbutton";
843
case PDF_WIDGET_TYPE_CHECKBOX: return "checkbox";
844
case PDF_WIDGET_TYPE_RADIOBUTTON: return "radiobutton";
845
case PDF_WIDGET_TYPE_TEXT: return "text";
846
case PDF_WIDGET_TYPE_LISTBOX: return "listbox";
847
case PDF_WIDGET_TYPE_COMBOBOX: return "combobox";
848
case PDF_WIDGET_TYPE_SIGNATURE: return "signature";
849
default: return "non-widget";
850
}
851
}
852
853
JNIEXPORT jboolean JNICALL
854
JNI_FN(MuPDFCore_updatePageInternal)(JNIEnv *env, jobject thiz, jobject bitmap, int page,
855
int pageW, int pageH, int patchX, int patchY, int patchW, int patchH, jlong cookiePtr)
856
{
857
AndroidBitmapInfo info;
858
void *pixels;
859
int ret;
860
fz_device *dev = NULL;
861
float zoom;
862
fz_matrix ctm;
863
fz_irect bbox;
864
fz_rect rect;
865
fz_pixmap *pix = NULL;
866
float xscale, yscale;
867
pdf_document *idoc;
868
page_cache *pc = NULL;
869
int hq = (patchW < pageW || patchH < pageH);
870
int i;
871
globals *glo = get_globals(env, thiz);
872
fz_context *ctx = glo->ctx;
873
fz_document *doc = glo->doc;
874
rect_node *crect;
875
fz_matrix scale;
876
fz_cookie *cookie = (fz_cookie *)(intptr_t)cookiePtr;
877
878
for (i = 0; i < NUM_CACHE; i++)
879
{
880
if (glo->pages[i].page != NULL && glo->pages[i].number == page)
881
{
882
pc = &glo->pages[i];
883
break;
884
}
885
}
886
887
if (pc == NULL)
888
{
889
/* Without a cached page object we cannot perform a partial update so
890
render the entire bitmap instead */
891
JNI_FN(MuPDFCore_gotoPageInternal)(env, thiz, page);
892
return JNI_FN(MuPDFCore_drawPage)(env, thiz, bitmap, pageW, pageH, patchX, patchY, patchW, patchH, (jlong)(intptr_t)cookie);
893
}
894
895
idoc = pdf_specifics(ctx, doc);
896
897
fz_var(pix);
898
fz_var(dev);
899
900
LOGI("In native method\n");
901
if ((ret = AndroidBitmap_getInfo(env, bitmap, &info)) < 0) {
902
LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret);
903
return 0;
904
}
905
906
LOGI("Checking format\n");
907
if (info.format != ANDROID_BITMAP_FORMAT_RGBA_8888) {
908
LOGE("Bitmap format is not RGBA_8888 !");
909
return 0;
910
}
911
912
LOGI("locking pixels\n");
913
if ((ret = AndroidBitmap_lockPixels(env, bitmap, &pixels)) < 0) {
914
LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret);
915
return 0;
916
}
917
918
/* Call mupdf to render display list to screen */
919
LOGI("Rendering page(%d)=%dx%d patch=[%d,%d,%d,%d]",
920
pc->number, pageW, pageH, patchX, patchY, patchW, patchH);
921
922
fz_try(ctx)
923
{
924
fz_annot *annot;
925
fz_irect pixbbox;
926
927
if (idoc)
928
{
929
/* Update the changed-rects for both hq patch and main bitmap */
930
update_changed_rects(glo, pc, idoc);
931
}
932
933
if (pc->page_list == NULL)
934
{
935
/* Render to list */
936
pc->page_list = fz_new_display_list(ctx);
937
dev = fz_new_list_device(ctx, pc->page_list);
938
fz_run_page_contents(ctx, pc->page, dev, &fz_identity, cookie);
939
fz_drop_device(ctx, dev);
940
dev = NULL;
941
if (cookie != NULL && cookie->abort)
942
{
943
fz_drop_display_list(ctx, pc->page_list);
944
pc->page_list = NULL;
945
fz_throw(ctx, FZ_ERROR_GENERIC, "Render aborted");
946
}
947
}
948
949
if (pc->annot_list == NULL) {
950
pc->annot_list = fz_new_display_list(ctx);
951
dev = fz_new_list_device(ctx, pc->annot_list);
952
for (annot = fz_first_annot(ctx, pc->page); annot; annot = fz_next_annot(ctx, pc->page, annot))
953
fz_run_annot(ctx, pc->page, annot, dev, &fz_identity, cookie);
954
fz_drop_device(ctx, dev);
955
dev = NULL;
956
if (cookie != NULL && cookie->abort)
957
{
958
fz_drop_display_list(ctx, pc->annot_list);
959
pc->annot_list = NULL;
960
fz_throw(ctx, FZ_ERROR_GENERIC, "Render aborted");
961
}
962
}
963
964
bbox.x0 = patchX;
965
bbox.y0 = patchY;
966
bbox.x1 = patchX + patchW;
967
bbox.y1 = patchY + patchH;
968
pixbbox = bbox;
969
pixbbox.x1 = pixbbox.x0 + info.width;
970
/* pixmaps cannot handle right-edge padding, so the bbox must be expanded to
971
* match the pixels data */
972
pix = fz_new_pixmap_with_bbox_and_data(ctx, glo->colorspace, &pixbbox, pixels);
973
974
zoom = glo->resolution / 72;
975
fz_scale(&ctm, zoom, zoom);
976
rect = pc->media_box;
977
fz_round_rect(&bbox, fz_transform_rect(&rect, &ctm));
978
/* Now, adjust ctm so that it would give the correct page width
979
* heights. */
980
xscale = (float)pageW/(float)(bbox.x1-bbox.x0);
981
yscale = (float)pageH/(float)(bbox.y1-bbox.y0);
982
fz_concat(&ctm, &ctm, fz_scale(&scale, xscale, yscale));
983
rect = pc->media_box;
984
fz_transform_rect(&rect, &ctm);
985
986
LOGI("Start partial update");
987
for (crect = hq ? pc->hq_changed_rects : pc->changed_rects; crect; crect = crect->next)
988
{
989
fz_irect abox;
990
fz_rect arect = crect->rect;
991
fz_intersect_rect(fz_transform_rect(&arect, &ctm), &rect);
992
fz_round_rect(&abox, &arect);
993
994
LOGI("Update rectangle (%d, %d, %d, %d)", abox.x0, abox.y0, abox.x1, abox.y1);
995
if (!fz_is_empty_irect(&abox))
996
{
997
LOGI("And it isn't empty");
998
fz_clear_pixmap_rect_with_value(ctx, pix, 0xff, &abox);
999
dev = fz_new_draw_device_with_bbox(ctx, pix, &abox);
1000
if (pc->page_list)
1001
fz_run_display_list(ctx, pc->page_list, dev, &ctm, &arect, cookie);
1002
if (cookie != NULL && cookie->abort)
1003
fz_throw(ctx, FZ_ERROR_GENERIC, "Render aborted");
1004
1005
if (pc->annot_list)
1006
fz_run_display_list(ctx, pc->annot_list, dev, &ctm, &arect, cookie);
1007
if (cookie != NULL && cookie->abort)
1008
fz_throw(ctx, FZ_ERROR_GENERIC, "Render aborted");
1009
1010
fz_drop_device(ctx, dev);
1011
dev = NULL;
1012
}
1013
}
1014
LOGI("End partial update");
1015
1016
/* Drop the changed rects we've just rendered */
1017
drop_changed_rects(ctx, hq ? &pc->hq_changed_rects : &pc->changed_rects);
1018
1019
LOGI("Rendered");
1020
}
1021
fz_always(ctx)
1022
{
1023
fz_drop_device(ctx, dev);
1024
dev = NULL;
1025
}
1026
fz_catch(ctx)
1027
{
1028
LOGE("Render failed");
1029
}
1030
1031
fz_drop_pixmap(ctx, pix);
1032
AndroidBitmap_unlockPixels(env, bitmap);
1033
1034
return 1;
1035
}
1036
1037
static int
1038
charat(fz_context *ctx, fz_text_page *page, int idx)
1039
{
1040
fz_char_and_box cab;
1041
return fz_text_char_at(ctx, &cab, page, idx)->c;
1042
}
1043
1044
static fz_rect
1045
bboxcharat(fz_context *ctx, fz_text_page *page, int idx)
1046
{
1047
fz_char_and_box cab;
1048
return fz_text_char_at(ctx, &cab, page, idx)->bbox;
1049
}
1050
1051
static int
1052
textlen(fz_text_page *page)
1053
{
1054
int len = 0;
1055
int block_num;
1056
1057
for (block_num = 0; block_num < page->len; block_num++)
1058
{
1059
fz_text_block *block;
1060
fz_text_line *line;
1061
1062
if (page->blocks[block_num].type != FZ_PAGE_BLOCK_TEXT)
1063
continue;
1064
block = page->blocks[block_num].u.text;
1065
for (line = block->lines; line < block->lines + block->len; line++)
1066
{
1067
fz_text_span *span;
1068
1069
for (span = line->first_span; span; span = span->next)
1070
{
1071
len += span->len;
1072
}
1073
len++; /* pseudo-newline */
1074
}
1075
}
1076
return len;
1077
}
1078
1079
static int
1080
countOutlineItems(fz_outline *outline)
1081
{
1082
int count = 0;
1083
1084
while (outline)
1085
{
1086
if (outline->dest.kind == FZ_LINK_GOTO
1087
&& outline->dest.ld.gotor.page >= 0
1088
&& outline->title)
1089
count++;
1090
1091
count += countOutlineItems(outline->down);
1092
outline = outline->next;
1093
}
1094
1095
return count;
1096
}
1097
1098
static int
1099
fillInOutlineItems(JNIEnv * env, jclass olClass, jmethodID ctor, jobjectArray arr, int pos, fz_outline *outline, int level)
1100
{
1101
while (outline)
1102
{
1103
if (outline->dest.kind == FZ_LINK_GOTO)
1104
{
1105
int page = outline->dest.ld.gotor.page;
1106
if (page >= 0 && outline->title)
1107
{
1108
jobject ol;
1109
jstring title = (*env)->NewStringUTF(env, outline->title);
1110
if (title == NULL) return -1;
1111
ol = (*env)->NewObject(env, olClass, ctor, level, title, page);
1112
if (ol == NULL) return -1;
1113
(*env)->SetObjectArrayElement(env, arr, pos, ol);
1114
(*env)->DeleteLocalRef(env, ol);
1115
(*env)->DeleteLocalRef(env, title);
1116
pos++;
1117
}
1118
}
1119
pos = fillInOutlineItems(env, olClass, ctor, arr, pos, outline->down, level+1);
1120
if (pos < 0) return -1;
1121
outline = outline->next;
1122
}
1123
1124
return pos;
1125
}
1126
1127
JNIEXPORT jboolean JNICALL
1128
JNI_FN(MuPDFCore_needsPasswordInternal)(JNIEnv * env, jobject thiz)
1129
{
1130
globals *glo = get_globals(env, thiz);
1131
fz_context *ctx = glo->ctx;
1132
1133
return fz_needs_password(ctx, glo->doc) ? JNI_TRUE : JNI_FALSE;
1134
}
1135
1136
JNIEXPORT jboolean JNICALL
1137
JNI_FN(MuPDFCore_authenticatePasswordInternal)(JNIEnv *env, jobject thiz, jstring password)
1138
{
1139
const char *pw;
1140
int result;
1141
globals *glo = get_globals(env, thiz);
1142
fz_context *ctx = glo->ctx;
1143
1144
pw = (*env)->GetStringUTFChars(env, password, NULL);
1145
if (pw == NULL)
1146
return JNI_FALSE;
1147
1148
result = fz_authenticate_password(ctx, glo->doc, (char *)pw);
1149
(*env)->ReleaseStringUTFChars(env, password, pw);
1150
return result;
1151
}
1152
1153
JNIEXPORT jboolean JNICALL
1154
JNI_FN(MuPDFCore_hasOutlineInternal)(JNIEnv * env, jobject thiz)
1155
{
1156
globals *glo = get_globals(env, thiz);
1157
fz_context *ctx = glo->ctx;
1158
fz_outline *outline = fz_load_outline(ctx, glo->doc);
1159
1160
fz_drop_outline(glo->ctx, outline);
1161
return (outline == NULL) ? JNI_FALSE : JNI_TRUE;
1162
}
1163
1164
JNIEXPORT jobjectArray JNICALL
1165
JNI_FN(MuPDFCore_getOutlineInternal)(JNIEnv * env, jobject thiz)
1166
{
1167
jclass olClass;
1168
jmethodID ctor;
1169
jobjectArray arr;
1170
jobject ol;
1171
fz_outline *outline;
1172
int nItems;
1173
globals *glo = get_globals(env, thiz);
1174
fz_context *ctx = glo->ctx;
1175
jobjectArray ret;
1176
1177
olClass = (*env)->FindClass(env, PACKAGENAME "/OutlineItem");
1178
if (olClass == NULL) return NULL;
1179
ctor = (*env)->GetMethodID(env, olClass, "<init>", "(ILjava/lang/String;I)V");
1180
if (ctor == NULL) return NULL;
1181
1182
outline = fz_load_outline(ctx, glo->doc);
1183
nItems = countOutlineItems(outline);
1184
1185
arr = (*env)->NewObjectArray(env,
1186
nItems,
1187
olClass,
1188
NULL);
1189
if (arr == NULL) return NULL;
1190
1191
ret = fillInOutlineItems(env, olClass, ctor, arr, 0, outline, 0) > 0
1192
? arr
1193
:NULL;
1194
fz_drop_outline(glo->ctx, outline);
1195
return ret;
1196
}
1197
1198
JNIEXPORT jobjectArray JNICALL
1199
JNI_FN(MuPDFCore_searchPage)(JNIEnv * env, jobject thiz, jstring jtext)
1200
{
1201
jclass rectClass;
1202
jmethodID ctor;
1203
jobjectArray arr;
1204
jobject rect;
1205
fz_text_sheet *sheet = NULL;
1206
fz_text_page *text = NULL;
1207
fz_device *dev = NULL;
1208
float zoom;
1209
fz_matrix ctm;
1210
int pos;
1211
int len;
1212
int i, n;
1213
int hit_count = 0;
1214
const char *str;
1215
globals *glo = get_globals(env, thiz);
1216
fz_context *ctx = glo->ctx;
1217
fz_document *doc = glo->doc;
1218
page_cache *pc = &glo->pages[glo->current];
1219
1220
rectClass = (*env)->FindClass(env, "android/graphics/RectF");
1221
if (rectClass == NULL) return NULL;
1222
ctor = (*env)->GetMethodID(env, rectClass, "<init>", "(FFFF)V");
1223
if (ctor == NULL) return NULL;
1224
str = (*env)->GetStringUTFChars(env, jtext, NULL);
1225
if (str == NULL) return NULL;
1226
1227
fz_var(sheet);
1228
fz_var(text);
1229
fz_var(dev);
1230
1231
fz_try(ctx)
1232
{
1233
if (glo->hit_bbox == NULL)
1234
glo->hit_bbox = fz_malloc_array(ctx, MAX_SEARCH_HITS, sizeof(*glo->hit_bbox));
1235
1236
zoom = glo->resolution / 72;
1237
fz_scale(&ctm, zoom, zoom);
1238
sheet = fz_new_text_sheet(ctx);
1239
text = fz_new_text_page(ctx);
1240
dev = fz_new_text_device(ctx, sheet, text);
1241
fz_run_page(ctx, pc->page, dev, &ctm, NULL);
1242
fz_drop_device(ctx, dev);
1243
dev = NULL;
1244
1245
hit_count = fz_search_text_page(ctx, text, str, glo->hit_bbox, MAX_SEARCH_HITS);
1246
}
1247
fz_always(ctx)
1248
{
1249
fz_drop_text_page(ctx, text);
1250
fz_drop_text_sheet(ctx, sheet);
1251
fz_drop_device(ctx, dev);
1252
}
1253
fz_catch(ctx)
1254
{
1255
jclass cls;
1256
(*env)->ReleaseStringUTFChars(env, jtext, str);
1257
cls = (*env)->FindClass(env, "java/lang/OutOfMemoryError");
1258
if (cls != NULL)
1259
(*env)->ThrowNew(env, cls, "Out of memory in MuPDFCore_searchPage");
1260
(*env)->DeleteLocalRef(env, cls);
1261
1262
return NULL;
1263
}
1264
1265
(*env)->ReleaseStringUTFChars(env, jtext, str);
1266
1267
arr = (*env)->NewObjectArray(env,
1268
hit_count,
1269
rectClass,
1270
NULL);
1271
if (arr == NULL) return NULL;
1272
1273
for (i = 0; i < hit_count; i++) {
1274
rect = (*env)->NewObject(env, rectClass, ctor,
1275
(float) (glo->hit_bbox[i].x0),
1276
(float) (glo->hit_bbox[i].y0),
1277
(float) (glo->hit_bbox[i].x1),
1278
(float) (glo->hit_bbox[i].y1));
1279
if (rect == NULL)
1280
return NULL;
1281
(*env)->SetObjectArrayElement(env, arr, i, rect);
1282
(*env)->DeleteLocalRef(env, rect);
1283
}
1284
1285
return arr;
1286
}
1287
1288
JNIEXPORT jobjectArray JNICALL
1289
JNI_FN(MuPDFCore_text)(JNIEnv * env, jobject thiz)
1290
{
1291
jclass textCharClass;
1292
jclass textSpanClass;
1293
jclass textLineClass;
1294
jclass textBlockClass;
1295
jmethodID ctor;
1296
jobjectArray barr = NULL;
1297
fz_text_sheet *sheet = NULL;
1298
fz_text_page *text = NULL;
1299
fz_device *dev = NULL;
1300
float zoom;
1301
fz_matrix ctm;
1302
globals *glo = get_globals(env, thiz);
1303
fz_context *ctx = glo->ctx;
1304
fz_document *doc = glo->doc;
1305
page_cache *pc = &glo->pages[glo->current];
1306
1307
textCharClass = (*env)->FindClass(env, PACKAGENAME "/TextChar");
1308
if (textCharClass == NULL) return NULL;
1309
textSpanClass = (*env)->FindClass(env, "[L" PACKAGENAME "/TextChar;");
1310
if (textSpanClass == NULL) return NULL;
1311
textLineClass = (*env)->FindClass(env, "[[L" PACKAGENAME "/TextChar;");
1312
if (textLineClass == NULL) return NULL;
1313
textBlockClass = (*env)->FindClass(env, "[[[L" PACKAGENAME "/TextChar;");
1314
if (textBlockClass == NULL) return NULL;
1315
ctor = (*env)->GetMethodID(env, textCharClass, "<init>", "(FFFFC)V");
1316
if (ctor == NULL) return NULL;
1317
1318
fz_var(sheet);
1319
fz_var(text);
1320
fz_var(dev);
1321
1322
fz_try(ctx)
1323
{
1324
int b, l, s, c;
1325
1326
zoom = glo->resolution / 72;
1327
fz_scale(&ctm, zoom, zoom);
1328
sheet = fz_new_text_sheet(ctx);
1329
text = fz_new_text_page(ctx);
1330
dev = fz_new_text_device(ctx, sheet, text);
1331
fz_run_page(ctx, pc->page, dev, &ctm, NULL);
1332
fz_drop_device(ctx, dev);
1333
dev = NULL;
1334
1335
barr = (*env)->NewObjectArray(env, text->len, textBlockClass, NULL);
1336
if (barr == NULL) fz_throw(ctx, FZ_ERROR_GENERIC, "NewObjectArray failed");
1337
1338
for (b = 0; b < text->len; b++)
1339
{
1340
fz_text_block *block;
1341
jobjectArray *larr;
1342
1343
if (text->blocks[b].type != FZ_PAGE_BLOCK_TEXT)
1344
continue;
1345
block = text->blocks[b].u.text;
1346
larr = (*env)->NewObjectArray(env, block->len, textLineClass, NULL);
1347
if (larr == NULL) fz_throw(ctx, FZ_ERROR_GENERIC, "NewObjectArray failed");
1348
1349
for (l = 0; l < block->len; l++)
1350
{
1351
fz_text_line *line = &block->lines[l];
1352
jobjectArray *sarr;
1353
fz_text_span *span;
1354
int len = 0;
1355
1356
for (span = line->first_span; span; span = span->next)
1357
len++;
1358
1359
sarr = (*env)->NewObjectArray(env, len, textSpanClass, NULL);
1360
if (sarr == NULL) fz_throw(ctx, FZ_ERROR_GENERIC, "NewObjectArray failed");
1361
1362
for (s=0, span = line->first_span; span; s++, span = span->next)
1363
{
1364
jobjectArray *carr = (*env)->NewObjectArray(env, span->len, textCharClass, NULL);
1365
if (carr == NULL) fz_throw(ctx, FZ_ERROR_GENERIC, "NewObjectArray failed");
1366
1367
for (c = 0; c < span->len; c++)
1368
{
1369
fz_text_char *ch = &span->text[c];
1370
fz_rect bbox;
1371
fz_text_char_bbox(ctx, &bbox, span, c);
1372
jobject cobj = (*env)->NewObject(env, textCharClass, ctor, bbox.x0, bbox.y0, bbox.x1, bbox.y1, ch->c);
1373
if (cobj == NULL) fz_throw(ctx, FZ_ERROR_GENERIC, "NewObjectfailed");
1374
1375
(*env)->SetObjectArrayElement(env, carr, c, cobj);
1376
(*env)->DeleteLocalRef(env, cobj);
1377
}
1378
1379
(*env)->SetObjectArrayElement(env, sarr, s, carr);
1380
(*env)->DeleteLocalRef(env, carr);
1381
}
1382
1383
(*env)->SetObjectArrayElement(env, larr, l, sarr);
1384
(*env)->DeleteLocalRef(env, sarr);
1385
}
1386
1387
(*env)->SetObjectArrayElement(env, barr, b, larr);
1388
(*env)->DeleteLocalRef(env, larr);
1389
}
1390
}
1391
fz_always(ctx)
1392
{
1393
fz_drop_text_page(ctx, text);
1394
fz_drop_text_sheet(ctx, sheet);
1395
fz_drop_device(ctx, dev);
1396
}
1397
fz_catch(ctx)
1398
{
1399
jclass cls = (*env)->FindClass(env, "java/lang/OutOfMemoryError");
1400
if (cls != NULL)
1401
(*env)->ThrowNew(env, cls, "Out of memory in MuPDFCore_text");
1402
(*env)->DeleteLocalRef(env, cls);
1403
1404
return NULL;
1405
}
1406
1407
return barr;
1408
}
1409
1410
JNIEXPORT jbyteArray JNICALL
1411
JNI_FN(MuPDFCore_textAsHtml)(JNIEnv * env, jobject thiz)
1412
{
1413
fz_text_sheet *sheet = NULL;
1414
fz_text_page *text = NULL;
1415
fz_device *dev = NULL;
1416
fz_matrix ctm;
1417
globals *glo = get_globals(env, thiz);
1418
fz_context *ctx = glo->ctx;
1419
fz_document *doc = glo->doc;
1420
page_cache *pc = &glo->pages[glo->current];
1421
jbyteArray bArray = NULL;
1422
fz_buffer *buf = NULL;
1423
fz_output *out = NULL;
1424
1425
fz_var(sheet);
1426
fz_var(text);
1427
fz_var(dev);
1428
fz_var(buf);
1429
fz_var(out);
1430
1431
fz_try(ctx)
1432
{
1433
int b, l, s, c;
1434
1435
ctm = fz_identity;
1436
sheet = fz_new_text_sheet(ctx);
1437
text = fz_new_text_page(ctx);
1438
dev = fz_new_text_device(ctx, sheet, text);
1439
fz_run_page(ctx, pc->page, dev, &ctm, NULL);
1440
fz_drop_device(ctx, dev);
1441
dev = NULL;
1442
1443
fz_analyze_text(ctx, sheet, text);
1444
1445
buf = fz_new_buffer(ctx, 256);
1446
out = fz_new_output_with_buffer(ctx, buf);
1447
fz_printf(ctx, out, "<html>\n");
1448
fz_printf(ctx, out, "<style>\n");
1449
fz_printf(ctx, out, "body{margin:0;}\n");
1450
fz_printf(ctx, out, "div.page{background-color:white;}\n");
1451
fz_printf(ctx, out, "div.block{margin:0pt;padding:0pt;}\n");
1452
fz_printf(ctx, out, "div.metaline{display:table;width:100%%}\n");
1453
fz_printf(ctx, out, "div.line{display:table-row;}\n");
1454
fz_printf(ctx, out, "div.cell{display:table-cell;padding-left:0.25em;padding-right:0.25em}\n");
1455
//fz_printf(ctx, out, "p{margin:0;padding:0;}\n");
1456
fz_printf(ctx, out, "</style>\n");
1457
fz_printf(ctx, out, "<body style=\"margin:0\"><div style=\"padding:10px\" id=\"content\">");
1458
fz_print_text_page_html(ctx, out, text);
1459
fz_printf(ctx, out, "</div></body>\n");
1460
fz_printf(ctx, out, "<style>\n");
1461
fz_print_text_sheet(ctx, out, sheet);
1462
fz_printf(ctx, out, "</style>\n</html>\n");
1463
fz_drop_output(ctx, out);
1464
out = NULL;
1465
1466
bArray = (*env)->NewByteArray(env, buf->len);
1467
if (bArray == NULL)
1468
fz_throw(ctx, FZ_ERROR_GENERIC, "Failed to make byteArray");
1469
(*env)->SetByteArrayRegion(env, bArray, 0, buf->len, buf->data);
1470
1471
}
1472
fz_always(ctx)
1473
{
1474
fz_drop_text_page(ctx, text);
1475
fz_drop_text_sheet(ctx, sheet);
1476
fz_drop_device(ctx, dev);
1477
fz_drop_output(ctx, out);
1478
fz_drop_buffer(ctx, buf);
1479
}
1480
fz_catch(ctx)
1481
{
1482
jclass cls = (*env)->FindClass(env, "java/lang/OutOfMemoryError");
1483
if (cls != NULL)
1484
(*env)->ThrowNew(env, cls, "Out of memory in MuPDFCore_textAsHtml");
1485
(*env)->DeleteLocalRef(env, cls);
1486
1487
return NULL;
1488
}
1489
1490
return bArray;
1491
}
1492
1493
JNIEXPORT void JNICALL
1494
JNI_FN(MuPDFCore_addMarkupAnnotationInternal)(JNIEnv * env, jobject thiz, jobjectArray points, fz_annot_type type)
1495
{
1496
globals *glo = get_globals(env, thiz);
1497
fz_context *ctx = glo->ctx;
1498
fz_document *doc = glo->doc;
1499
pdf_document *idoc = pdf_specifics(ctx, doc);
1500
page_cache *pc = &glo->pages[glo->current];
1501
jclass pt_cls;
1502
jfieldID x_fid, y_fid;
1503
int i, n;
1504
fz_point *pts = NULL;
1505
float color[3];
1506
float alpha;
1507
float line_height;
1508
float line_thickness;
1509
1510
if (idoc == NULL)
1511
return;
1512
1513
switch (type)
1514
{
1515
case FZ_ANNOT_HIGHLIGHT:
1516
color[0] = 1.0;
1517
color[1] = 1.0;
1518
color[2] = 0.0;
1519
alpha = 0.5;
1520
line_thickness = 1.0;
1521
line_height = 0.5;
1522
break;
1523
case FZ_ANNOT_UNDERLINE:
1524
color[0] = 0.0;
1525
color[1] = 0.0;
1526
color[2] = 1.0;
1527
alpha = 1.0;
1528
line_thickness = LINE_THICKNESS;
1529
line_height = UNDERLINE_HEIGHT;
1530
break;
1531
case FZ_ANNOT_STRIKEOUT:
1532
color[0] = 1.0;
1533
color[1] = 0.0;
1534
color[2] = 0.0;
1535
alpha = 1.0;
1536
line_thickness = LINE_THICKNESS;
1537
line_height = STRIKE_HEIGHT;
1538
break;
1539
default:
1540
return;
1541
}
1542
1543
fz_var(pts);
1544
fz_try(ctx)
1545
{
1546
fz_annot *annot;
1547
fz_matrix ctm;
1548
1549
float zoom = glo->resolution / 72;
1550
zoom = 1.0 / zoom;
1551
fz_scale(&ctm, zoom, zoom);
1552
pt_cls = (*env)->FindClass(env, "android/graphics/PointF");
1553
if (pt_cls == NULL) fz_throw(ctx, FZ_ERROR_GENERIC, "FindClass");
1554
x_fid = (*env)->GetFieldID(env, pt_cls, "x", "F");
1555
if (x_fid == NULL) fz_throw(ctx, FZ_ERROR_GENERIC, "GetFieldID(x)");
1556
y_fid = (*env)->GetFieldID(env, pt_cls, "y", "F");
1557
if (y_fid == NULL) fz_throw(ctx, FZ_ERROR_GENERIC, "GetFieldID(y)");
1558
1559
n = (*env)->GetArrayLength(env, points);
1560
1561
pts = fz_malloc_array(ctx, n, sizeof(fz_point));
1562
1563
for (i = 0; i < n; i++)
1564
{
1565
jobject opt = (*env)->GetObjectArrayElement(env, points, i);
1566
pts[i].x = opt ? (*env)->GetFloatField(env, opt, x_fid) : 0.0f;
1567
pts[i].y = opt ? (*env)->GetFloatField(env, opt, y_fid) : 0.0f;
1568
fz_transform_point(&pts[i], &ctm);
1569
}
1570
1571
annot = (fz_annot *)pdf_create_annot(ctx, idoc, (pdf_page *)pc->page, type);
1572
1573
pdf_set_markup_annot_quadpoints(ctx, idoc, (pdf_annot *)annot, pts, n);
1574
pdf_set_markup_appearance(ctx, idoc, (pdf_annot *)annot, color, alpha, line_thickness, line_height);
1575
1576
dump_annotation_display_lists(glo);
1577
}
1578
fz_always(ctx)
1579
{
1580
fz_free(ctx, pts);
1581
}
1582
fz_catch(ctx)
1583
{
1584
LOGE("addStrikeOutAnnotation: %s failed", ctx->error->message);
1585
jclass cls = (*env)->FindClass(env, "java/lang/OutOfMemoryError");
1586
if (cls != NULL)
1587
(*env)->ThrowNew(env, cls, "Out of memory in MuPDFCore_searchPage");
1588
(*env)->DeleteLocalRef(env, cls);
1589
}
1590
}
1591
1592
JNIEXPORT void JNICALL
1593
JNI_FN(MuPDFCore_addInkAnnotationInternal)(JNIEnv * env, jobject thiz, jobjectArray arcs)
1594
{
1595
globals *glo = get_globals(env, thiz);
1596
fz_context *ctx = glo->ctx;
1597
fz_document *doc = glo->doc;
1598
pdf_document *idoc = pdf_specifics(ctx, doc);
1599
page_cache *pc = &glo->pages[glo->current];
1600
jclass pt_cls;
1601
jfieldID x_fid, y_fid;
1602
int i, j, k, n;
1603
fz_point *pts = NULL;
1604
int *counts = NULL;
1605
int total = 0;
1606
float color[3];
1607
1608
if (idoc == NULL)
1609
return;
1610
1611
color[0] = 1.0;
1612
color[1] = 0.0;
1613
color[2] = 0.0;
1614
1615
fz_var(pts);
1616
fz_var(counts);
1617
fz_try(ctx)
1618
{
1619
fz_annot *annot;
1620
fz_matrix ctm;
1621
1622
float zoom = glo->resolution / 72;
1623
zoom = 1.0 / zoom;
1624
fz_scale(&ctm, zoom, zoom);
1625
pt_cls = (*env)->FindClass(env, "android/graphics/PointF");
1626
if (pt_cls == NULL) fz_throw(ctx, FZ_ERROR_GENERIC, "FindClass");
1627
x_fid = (*env)->GetFieldID(env, pt_cls, "x", "F");
1628
if (x_fid == NULL) fz_throw(ctx, FZ_ERROR_GENERIC, "GetFieldID(x)");
1629
y_fid = (*env)->GetFieldID(env, pt_cls, "y", "F");
1630
if (y_fid == NULL) fz_throw(ctx, FZ_ERROR_GENERIC, "GetFieldID(y)");
1631
1632
n = (*env)->GetArrayLength(env, arcs);
1633
1634
counts = fz_malloc_array(ctx, n, sizeof(int));
1635
1636
for (i = 0; i < n; i++)
1637
{
1638
jobjectArray arc = (jobjectArray)(*env)->GetObjectArrayElement(env, arcs, i);
1639
int count = (*env)->GetArrayLength(env, arc);
1640
1641
counts[i] = count;
1642
total += count;
1643
}
1644
1645
pts = fz_malloc_array(ctx, total, sizeof(fz_point));
1646
1647
k = 0;
1648
for (i = 0; i < n; i++)
1649
{
1650
jobjectArray arc = (jobjectArray)(*env)->GetObjectArrayElement(env, arcs, i);
1651
int count = counts[i];
1652
1653
for (j = 0; j < count; j++)
1654
{
1655
jobject pt = (*env)->GetObjectArrayElement(env, arc, j);
1656
1657
pts[k].x = pt ? (*env)->GetFloatField(env, pt, x_fid) : 0.0f;
1658
pts[k].y = pt ? (*env)->GetFloatField(env, pt, y_fid) : 0.0f;
1659
(*env)->DeleteLocalRef(env, pt);
1660
fz_transform_point(&pts[k], &ctm);
1661
k++;
1662
}
1663
(*env)->DeleteLocalRef(env, arc);
1664
}
1665
1666
annot = (fz_annot *)pdf_create_annot(ctx, idoc, (pdf_page *)pc->page, FZ_ANNOT_INK);
1667
1668
pdf_set_ink_annot_list(ctx, idoc, (pdf_annot *)annot, pts, counts, n, color, INK_THICKNESS);
1669
1670
dump_annotation_display_lists(glo);
1671
}
1672
fz_always(ctx)
1673
{
1674
fz_free(ctx, pts);
1675
fz_free(ctx, counts);
1676
}
1677
fz_catch(ctx)
1678
{
1679
LOGE("addInkAnnotation: %s failed", ctx->error->message);
1680
jclass cls = (*env)->FindClass(env, "java/lang/OutOfMemoryError");
1681
if (cls != NULL)
1682
(*env)->ThrowNew(env, cls, "Out of memory in MuPDFCore_searchPage");
1683
(*env)->DeleteLocalRef(env, cls);
1684
}
1685
}
1686
1687
JNIEXPORT void JNICALL
1688
JNI_FN(MuPDFCore_deleteAnnotationInternal)(JNIEnv * env, jobject thiz, int annot_index)
1689
{
1690
globals *glo = get_globals(env, thiz);
1691
fz_context *ctx = glo->ctx;
1692
fz_document *doc = glo->doc;
1693
pdf_document *idoc = pdf_specifics(ctx, doc);
1694
page_cache *pc = &glo->pages[glo->current];
1695
fz_annot *annot;
1696
int i;
1697
1698
if (idoc == NULL)
1699
return;
1700
1701
fz_try(ctx)
1702
{
1703
annot = fz_first_annot(ctx, pc->page);
1704
for (i = 0; i < annot_index && annot; i++)
1705
annot = fz_next_annot(ctx, pc->page, annot);
1706
1707
if (annot)
1708
{
1709
pdf_delete_annot(ctx, idoc, (pdf_page *)pc->page, (pdf_annot *)annot);
1710
dump_annotation_display_lists(glo);
1711
}
1712
}
1713
fz_catch(ctx)
1714
{
1715
LOGE("deleteAnnotationInternal: %s", ctx->error->message);
1716
}
1717
}
1718
1719
/* Close the document, at least enough to be able to save over it. This
1720
* may be called again later, so must be idempotent. */
1721
static void close_doc(globals *glo)
1722
{
1723
int i;
1724
1725
fz_free(glo->ctx, glo->hit_bbox);
1726
glo->hit_bbox = NULL;
1727
1728
for (i = 0; i < NUM_CACHE; i++)
1729
drop_page_cache(glo, &glo->pages[i]);
1730
1731
alerts_fin(glo);
1732
1733
fz_drop_document(glo->ctx, glo->doc);
1734
glo->doc = NULL;
1735
}
1736
1737
JNIEXPORT void JNICALL
1738
JNI_FN(MuPDFCore_destroying)(JNIEnv * env, jobject thiz)
1739
{
1740
globals *glo = get_globals(env, thiz);
1741
1742
if (glo == NULL)
1743
return;
1744
LOGI("Destroying");
1745
fz_free(glo->ctx, glo->current_path);
1746
glo->current_path = NULL;
1747
close_doc(glo);
1748
fz_drop_context(glo->ctx);
1749
glo->ctx = NULL;
1750
free(glo);
1751
#ifdef MEMENTO
1752
LOGI("Destroying dump start");
1753
Memento_listBlocks();
1754
Memento_stats();
1755
LOGI("Destroying dump end");
1756
#endif
1757
#ifdef NDK_PROFILER
1758
// Apparently we should really be writing to whatever path we get
1759
// from calling getFilesDir() in the java part, which supposedly
1760
// gives /sdcard/data/data/com.artifex.MuPDF/gmon.out, but that's
1761
// unfriendly.
1762
setenv("CPUPROFILE", "/sdcard/gmon.out", 1);
1763
moncleanup();
1764
#endif
1765
}
1766
1767
JNIEXPORT jobjectArray JNICALL
1768
JNI_FN(MuPDFCore_getPageLinksInternal)(JNIEnv * env, jobject thiz, int pageNumber)
1769
{
1770
jclass linkInfoClass;
1771
jclass linkInfoInternalClass;
1772
jclass linkInfoExternalClass;
1773
jclass linkInfoRemoteClass;
1774
jmethodID ctorInternal;
1775
jmethodID ctorExternal;
1776
jmethodID ctorRemote;
1777
jobjectArray arr;
1778
jobject linkInfo;
1779
fz_matrix ctm;
1780
float zoom;
1781
fz_link *list;
1782
fz_link *link;
1783
int count;
1784
page_cache *pc;
1785
globals *glo = get_globals(env, thiz);
1786
1787
linkInfoClass = (*env)->FindClass(env, PACKAGENAME "/LinkInfo");
1788
if (linkInfoClass == NULL) return NULL;
1789
linkInfoInternalClass = (*env)->FindClass(env, PACKAGENAME "/LinkInfoInternal");
1790
if (linkInfoInternalClass == NULL) return NULL;
1791
linkInfoExternalClass = (*env)->FindClass(env, PACKAGENAME "/LinkInfoExternal");
1792
if (linkInfoExternalClass == NULL) return NULL;
1793
linkInfoRemoteClass = (*env)->FindClass(env, PACKAGENAME "/LinkInfoRemote");
1794
if (linkInfoRemoteClass == NULL) return NULL;
1795
ctorInternal = (*env)->GetMethodID(env, linkInfoInternalClass, "<init>", "(FFFFI)V");
1796
if (ctorInternal == NULL) return NULL;
1797
ctorExternal = (*env)->GetMethodID(env, linkInfoExternalClass, "<init>", "(FFFFLjava/lang/String;)V");
1798
if (ctorExternal == NULL) return NULL;
1799
ctorRemote = (*env)->GetMethodID(env, linkInfoRemoteClass, "<init>", "(FFFFLjava/lang/String;IZ)V");
1800
if (ctorRemote == NULL) return NULL;
1801
1802
JNI_FN(MuPDFCore_gotoPageInternal)(env, thiz, pageNumber);
1803
pc = &glo->pages[glo->current];
1804
if (pc->page == NULL || pc->number != pageNumber)
1805
return NULL;
1806
1807
zoom = glo->resolution / 72;
1808
fz_scale(&ctm, zoom, zoom);
1809
1810
list = fz_load_links(glo->ctx, pc->page);
1811
count = 0;
1812
for (link = list; link; link = link->next)
1813
{
1814
switch (link->dest.kind)
1815
{
1816
case FZ_LINK_GOTO:
1817
case FZ_LINK_GOTOR:
1818
case FZ_LINK_URI:
1819
count++ ;
1820
}
1821
}
1822
1823
arr = (*env)->NewObjectArray(env, count, linkInfoClass, NULL);
1824
if (arr == NULL)
1825
{
1826
fz_drop_link(glo->ctx, list);
1827
return NULL;
1828
}
1829
1830
count = 0;
1831
for (link = list; link; link = link->next)
1832
{
1833
fz_rect rect = link->rect;
1834
fz_transform_rect(&rect, &ctm);
1835
1836
switch (link->dest.kind)
1837
{
1838
case FZ_LINK_GOTO:
1839
{
1840
linkInfo = (*env)->NewObject(env, linkInfoInternalClass, ctorInternal,
1841
(float)rect.x0, (float)rect.y0, (float)rect.x1, (float)rect.y1,
1842
link->dest.ld.gotor.page);
1843
break;
1844
}
1845
1846
case FZ_LINK_GOTOR:
1847
{
1848
jstring juri = (*env)->NewStringUTF(env, link->dest.ld.gotor.file_spec);
1849
linkInfo = (*env)->NewObject(env, linkInfoRemoteClass, ctorRemote,
1850
(float)rect.x0, (float)rect.y0, (float)rect.x1, (float)rect.y1,
1851
juri, link->dest.ld.gotor.page, link->dest.ld.gotor.new_window ? JNI_TRUE : JNI_FALSE);
1852
break;
1853
}
1854
1855
case FZ_LINK_URI:
1856
{
1857
jstring juri = (*env)->NewStringUTF(env, link->dest.ld.uri.uri);
1858
linkInfo = (*env)->NewObject(env, linkInfoExternalClass, ctorExternal,
1859
(float)rect.x0, (float)rect.y0, (float)rect.x1, (float)rect.y1,
1860
juri);
1861
break;
1862
}
1863
1864
default:
1865
continue;
1866
}
1867
1868
if (linkInfo == NULL)
1869
{
1870
fz_drop_link(glo->ctx, list);
1871
return NULL;
1872
}
1873
(*env)->SetObjectArrayElement(env, arr, count, linkInfo);
1874
(*env)->DeleteLocalRef(env, linkInfo);
1875
count++;
1876
}
1877
fz_drop_link(glo->ctx, list);
1878
1879
return arr;
1880
}
1881
1882
JNIEXPORT jobjectArray JNICALL
1883
JNI_FN(MuPDFCore_getWidgetAreasInternal)(JNIEnv * env, jobject thiz, int pageNumber)
1884
{
1885
jclass rectFClass;
1886
jmethodID ctor;
1887
jobjectArray arr;
1888
jobject rectF;
1889
pdf_document *idoc;
1890
pdf_widget *widget;
1891
fz_matrix ctm;
1892
float zoom;
1893
int count;
1894
page_cache *pc;
1895
globals *glo = get_globals(env, thiz);
1896
if (glo == NULL)
1897
return NULL;
1898
fz_context *ctx = glo->ctx;
1899
1900
rectFClass = (*env)->FindClass(env, "android/graphics/RectF");
1901
if (rectFClass == NULL) return NULL;
1902
ctor = (*env)->GetMethodID(env, rectFClass, "<init>", "(FFFF)V");
1903
if (ctor == NULL) return NULL;
1904
1905
JNI_FN(MuPDFCore_gotoPageInternal)(env, thiz, pageNumber);
1906
pc = &glo->pages[glo->current];
1907
if (pc->number != pageNumber || pc->page == NULL)
1908
return NULL;
1909
1910
idoc = pdf_specifics(ctx, glo->doc);
1911
if (idoc == NULL)
1912
return NULL;
1913
1914
zoom = glo->resolution / 72;
1915
fz_scale(&ctm, zoom, zoom);
1916
1917
count = 0;
1918
for (widget = pdf_first_widget(ctx, idoc, (pdf_page *)pc->page); widget; widget = pdf_next_widget(ctx, widget))
1919
count ++;
1920
1921
arr = (*env)->NewObjectArray(env, count, rectFClass, NULL);
1922
if (arr == NULL) return NULL;
1923
1924
count = 0;
1925
for (widget = pdf_first_widget(ctx, idoc, (pdf_page *)pc->page); widget; widget = pdf_next_widget(ctx, widget))
1926
{
1927
fz_rect rect;
1928
pdf_bound_widget(ctx, widget, &rect);
1929
fz_transform_rect(&rect, &ctm);
1930
1931
rectF = (*env)->NewObject(env, rectFClass, ctor,
1932
(float)rect.x0, (float)rect.y0, (float)rect.x1, (float)rect.y1);
1933
if (rectF == NULL) return NULL;
1934
(*env)->SetObjectArrayElement(env, arr, count, rectF);
1935
(*env)->DeleteLocalRef(env, rectF);
1936
1937
count ++;
1938
}
1939
1940
return arr;
1941
}
1942
1943
JNIEXPORT jobjectArray JNICALL
1944
JNI_FN(MuPDFCore_getAnnotationsInternal)(JNIEnv * env, jobject thiz, int pageNumber)
1945
{
1946
jclass annotClass;
1947
jmethodID ctor;
1948
jobjectArray arr;
1949
jobject jannot;
1950
fz_annot *annot;
1951
fz_matrix ctm;
1952
float zoom;
1953
int count;
1954
page_cache *pc;
1955
globals *glo = get_globals(env, thiz);
1956
if (glo == NULL)
1957
return NULL;
1958
fz_context *ctx = glo->ctx;
1959
1960
annotClass = (*env)->FindClass(env, PACKAGENAME "/Annotation");
1961
if (annotClass == NULL) return NULL;
1962
ctor = (*env)->GetMethodID(env, annotClass, "<init>", "(FFFFI)V");
1963
if (ctor == NULL) return NULL;
1964
1965
JNI_FN(MuPDFCore_gotoPageInternal)(env, thiz, pageNumber);
1966
pc = &glo->pages[glo->current];
1967
if (pc->number != pageNumber || pc->page == NULL)
1968
return NULL;
1969
1970
zoom = glo->resolution / 72;
1971
fz_scale(&ctm, zoom, zoom);
1972
1973
count = 0;
1974
for (annot = fz_first_annot(ctx, pc->page); annot; annot = fz_next_annot(ctx, pc->page, annot))
1975
count ++;
1976
1977
arr = (*env)->NewObjectArray(env, count, annotClass, NULL);
1978
if (arr == NULL) return NULL;
1979
1980
count = 0;
1981
for (annot = fz_first_annot(ctx, pc->page); annot; annot = fz_next_annot(ctx, pc->page, annot))
1982
{
1983
fz_rect rect;
1984
fz_annot_type type = pdf_annot_type(ctx, (pdf_annot *)annot);
1985
fz_bound_annot(ctx, pc->page, annot, &rect);
1986
fz_transform_rect(&rect, &ctm);
1987
1988
jannot = (*env)->NewObject(env, annotClass, ctor,
1989
(float)rect.x0, (float)rect.y0, (float)rect.x1, (float)rect.y1, type);
1990
if (jannot == NULL) return NULL;
1991
(*env)->SetObjectArrayElement(env, arr, count, jannot);
1992
(*env)->DeleteLocalRef(env, jannot);
1993
1994
count ++;
1995
}
1996
1997
return arr;
1998
}
1999
2000
JNIEXPORT int JNICALL
2001
JNI_FN(MuPDFCore_passClickEventInternal)(JNIEnv * env, jobject thiz, int pageNumber, float x, float y)
2002
{
2003
globals *glo = get_globals(env, thiz);
2004
fz_context *ctx = glo->ctx;
2005
fz_matrix ctm;
2006
pdf_document *idoc = pdf_specifics(ctx, glo->doc);
2007
float zoom;
2008
fz_point p;
2009
pdf_ui_event event;
2010
int changed = 0;
2011
page_cache *pc;
2012
2013
if (idoc == NULL)
2014
return 0;
2015
2016
JNI_FN(MuPDFCore_gotoPageInternal)(env, thiz, pageNumber);
2017
pc = &glo->pages[glo->current];
2018
if (pc->number != pageNumber || pc->page == NULL)
2019
return 0;
2020
2021
p.x = x;
2022
p.y = y;
2023
2024
/* Ultimately we should probably return a pointer to a java structure
2025
* with the link details in, but for now, page number will suffice.
2026
*/
2027
zoom = glo->resolution / 72;
2028
fz_scale(&ctm, zoom, zoom);
2029
fz_invert_matrix(&ctm, &ctm);
2030
2031
fz_transform_point(&p, &ctm);
2032
2033
fz_try(ctx)
2034
{
2035
event.etype = PDF_EVENT_TYPE_POINTER;
2036
event.event.pointer.pt = p;
2037
event.event.pointer.ptype = PDF_POINTER_DOWN;
2038
changed = pdf_pass_event(ctx, idoc, (pdf_page *)pc->page, &event);
2039
event.event.pointer.ptype = PDF_POINTER_UP;
2040
changed |= pdf_pass_event(ctx, idoc, (pdf_page *)pc->page, &event);
2041
if (changed) {
2042
dump_annotation_display_lists(glo);
2043
}
2044
}
2045
fz_catch(ctx)
2046
{
2047
LOGE("passClickEvent: %s", ctx->error->message);
2048
}
2049
2050
return changed;
2051
}
2052
2053
JNIEXPORT jstring JNICALL
2054
JNI_FN(MuPDFCore_getFocusedWidgetTextInternal)(JNIEnv * env, jobject thiz)
2055
{
2056
char *text = "";
2057
globals *glo = get_globals(env, thiz);
2058
fz_context *ctx = glo->ctx;
2059
2060
fz_try(ctx)
2061
{
2062
pdf_document *idoc = pdf_specifics(ctx, glo->doc);
2063
2064
if (idoc)
2065
{
2066
pdf_widget *focus = pdf_focused_widget(ctx, idoc);
2067
2068
if (focus)
2069
text = pdf_text_widget_text(ctx, idoc, focus);
2070
}
2071
}
2072
fz_catch(ctx)
2073
{
2074
LOGE("getFocusedWidgetText failed: %s", ctx->error->message);
2075
}
2076
2077
return (*env)->NewStringUTF(env, text);
2078
}
2079
2080
JNIEXPORT int JNICALL
2081
JNI_FN(MuPDFCore_setFocusedWidgetTextInternal)(JNIEnv * env, jobject thiz, jstring jtext)
2082
{
2083
const char *text;
2084
int result = 0;
2085
globals *glo = get_globals(env, thiz);
2086
fz_context *ctx = glo->ctx;
2087
2088
text = (*env)->GetStringUTFChars(env, jtext, NULL);
2089
if (text == NULL)
2090
{
2091
LOGE("Failed to get text");
2092
return 0;
2093
}
2094
2095
fz_try(ctx)
2096
{
2097
pdf_document *idoc = pdf_specifics(ctx, glo->doc);
2098
2099
if (idoc)
2100
{
2101
pdf_widget *focus = pdf_focused_widget(ctx, idoc);
2102
2103
if (focus)
2104
{
2105
result = pdf_text_widget_set_text(ctx, idoc, focus, (char *)text);
2106
dump_annotation_display_lists(glo);
2107
}
2108
}
2109
}
2110
fz_catch(ctx)
2111
{
2112
LOGE("setFocusedWidgetText failed: %s", ctx->error->message);
2113
}
2114
2115
(*env)->ReleaseStringUTFChars(env, jtext, text);
2116
2117
return result;
2118
}
2119
2120
JNIEXPORT jobjectArray JNICALL
2121
JNI_FN(MuPDFCore_getFocusedWidgetChoiceOptions)(JNIEnv * env, jobject thiz)
2122
{
2123
globals *glo = get_globals(env, thiz);
2124
fz_context *ctx = glo->ctx;
2125
pdf_document *idoc = pdf_specifics(ctx, glo->doc);
2126
pdf_widget *focus;
2127
int type;
2128
int nopts, i;
2129
char **opts = NULL;
2130
jclass stringClass;
2131
jobjectArray arr;
2132
2133
if (idoc == NULL)
2134
return NULL;
2135
2136
focus = pdf_focused_widget(ctx, idoc);
2137
if (focus == NULL)
2138
return NULL;
2139
2140
type = pdf_widget_get_type(ctx, focus);
2141
if (type != PDF_WIDGET_TYPE_LISTBOX && type != PDF_WIDGET_TYPE_COMBOBOX)
2142
return NULL;
2143
2144
fz_var(opts);
2145
fz_try(ctx)
2146
{
2147
nopts = pdf_choice_widget_options(ctx, idoc, focus, NULL);
2148
opts = fz_malloc(ctx, nopts * sizeof(*opts));
2149
(void)pdf_choice_widget_options(ctx, idoc, focus, opts);
2150
}
2151
fz_catch(ctx)
2152
{
2153
fz_free(ctx, opts);
2154
LOGE("Failed in getFocuseedWidgetChoiceOptions");
2155
return NULL;
2156
}
2157
2158
stringClass = (*env)->FindClass(env, "java/lang/String");
2159
2160
arr = (*env)->NewObjectArray(env, nopts, stringClass, NULL);
2161
2162
for (i = 0; i < nopts; i++)
2163
{
2164
jstring s = (*env)->NewStringUTF(env, opts[i]);
2165
if (s != NULL)
2166
(*env)->SetObjectArrayElement(env, arr, i, s);
2167
2168
(*env)->DeleteLocalRef(env, s);
2169
}
2170
2171
fz_free(ctx, opts);
2172
2173
return arr;
2174
}
2175
2176
JNIEXPORT jobjectArray JNICALL
2177
JNI_FN(MuPDFCore_getFocusedWidgetChoiceSelected)(JNIEnv * env, jobject thiz)
2178
{
2179
globals *glo = get_globals(env, thiz);
2180
fz_context *ctx = glo->ctx;
2181
pdf_document *idoc = pdf_specifics(ctx, glo->doc);
2182
pdf_widget *focus;
2183
int type;
2184
int nsel, i;
2185
char **sel = NULL;
2186
jclass stringClass;
2187
jobjectArray arr;
2188
2189
if (idoc == NULL)
2190
return NULL;
2191
2192
focus = pdf_focused_widget(ctx, idoc);
2193
if (focus == NULL)
2194
return NULL;
2195
2196
type = pdf_widget_get_type(ctx, focus);
2197
if (type != PDF_WIDGET_TYPE_LISTBOX && type != PDF_WIDGET_TYPE_COMBOBOX)
2198
return NULL;
2199
2200
fz_var(sel);
2201
fz_try(ctx)
2202
{
2203
nsel = pdf_choice_widget_value(ctx, idoc, focus, NULL);
2204
sel = fz_malloc(ctx, nsel * sizeof(*sel));
2205
(void)pdf_choice_widget_value(ctx, idoc, focus, sel);
2206
}
2207
fz_catch(ctx)
2208
{
2209
fz_free(ctx, sel);
2210
LOGE("Failed in getFocuseedWidgetChoiceOptions");
2211
return NULL;
2212
}
2213
2214
stringClass = (*env)->FindClass(env, "java/lang/String");
2215
2216
arr = (*env)->NewObjectArray(env, nsel, stringClass, NULL);
2217
2218
for (i = 0; i < nsel; i++)
2219
{
2220
jstring s = (*env)->NewStringUTF(env, sel[i]);
2221
if (s != NULL)
2222
(*env)->SetObjectArrayElement(env, arr, i, s);
2223
2224
(*env)->DeleteLocalRef(env, s);
2225
}
2226
2227
fz_free(ctx, sel);
2228
2229
return arr;
2230
}
2231
2232
JNIEXPORT void JNICALL
2233
JNI_FN(MuPDFCore_setFocusedWidgetChoiceSelectedInternal)(JNIEnv * env, jobject thiz, jobjectArray arr)
2234
{
2235
globals *glo = get_globals(env, thiz);
2236
fz_context *ctx = glo->ctx;
2237
pdf_document *idoc = pdf_specifics(ctx, glo->doc);
2238
pdf_widget *focus;
2239
int type;
2240
int nsel, i;
2241
char **sel = NULL;
2242
jstring *objs = NULL;
2243
2244
if (idoc == NULL)
2245
return;
2246
2247
focus = pdf_focused_widget(ctx, idoc);
2248
if (focus == NULL)
2249
return;
2250
2251
type = pdf_widget_get_type(ctx, focus);
2252
if (type != PDF_WIDGET_TYPE_LISTBOX && type != PDF_WIDGET_TYPE_COMBOBOX)
2253
return;
2254
2255
nsel = (*env)->GetArrayLength(env, arr);
2256
2257
sel = calloc(nsel, sizeof(*sel));
2258
objs = calloc(nsel, sizeof(*objs));
2259
if (objs == NULL || sel == NULL)
2260
{
2261
free(sel);
2262
free(objs);
2263
LOGE("Failed in setFocusWidgetChoiceSelected");
2264
return;
2265
}
2266
2267
for (i = 0; i < nsel; i++)
2268
{
2269
objs[i] = (jstring)(*env)->GetObjectArrayElement(env, arr, i);
2270
sel[i] = (char *)(*env)->GetStringUTFChars(env, objs[i], NULL);
2271
}
2272
2273
fz_try(ctx)
2274
{
2275
pdf_choice_widget_set_value(ctx, idoc, focus, nsel, sel);
2276
dump_annotation_display_lists(glo);
2277
}
2278
fz_catch(ctx)
2279
{
2280
LOGE("Failed in setFocusWidgetChoiceSelected");
2281
}
2282
2283
for (i = 0; i < nsel; i++)
2284
(*env)->ReleaseStringUTFChars(env, objs[i], sel[i]);
2285
2286
free(sel);
2287
free(objs);
2288
}
2289
2290
JNIEXPORT int JNICALL
2291
JNI_FN(MuPDFCore_getFocusedWidgetTypeInternal)(JNIEnv * env, jobject thiz)
2292
{
2293
globals *glo = get_globals(env, thiz);
2294
fz_context *ctx = glo->ctx;
2295
pdf_document *idoc = pdf_specifics(ctx, glo->doc);
2296
pdf_widget *focus;
2297
2298
if (ctx, idoc == NULL)
2299
return NONE;
2300
2301
focus = pdf_focused_widget(ctx, idoc);
2302
2303
if (focus == NULL)
2304
return NONE;
2305
2306
switch (pdf_widget_get_type(ctx, focus))
2307
{
2308
case PDF_WIDGET_TYPE_TEXT: return TEXT;
2309
case PDF_WIDGET_TYPE_LISTBOX: return LISTBOX;
2310
case PDF_WIDGET_TYPE_COMBOBOX: return COMBOBOX;
2311
case PDF_WIDGET_TYPE_SIGNATURE: return SIGNATURE;
2312
}
2313
2314
return NONE;
2315
}
2316
2317
/* This enum should be kept in line with SignatureState in MuPDFPageView.java */
2318
enum
2319
{
2320
Signature_NoSupport,
2321
Signature_Unsigned,
2322
Signature_Signed
2323
};
2324
2325
JNIEXPORT int JNICALL
2326
JNI_FN(MuPDFCore_getFocusedWidgetSignatureState)(JNIEnv * env, jobject thiz)
2327
{
2328
globals *glo = get_globals(env, thiz);
2329
fz_context *ctx = glo->ctx;
2330
pdf_document *idoc = pdf_specifics(ctx, glo->doc);
2331
pdf_widget *focus;
2332
2333
if (ctx, idoc == NULL)
2334
return Signature_NoSupport;
2335
2336
focus = pdf_focused_widget(ctx, idoc);
2337
2338
if (focus == NULL)
2339
return Signature_NoSupport;
2340
2341
if (!pdf_signatures_supported())
2342
return Signature_NoSupport;
2343
2344
return pdf_dict_get(ctx, ((pdf_annot *)focus)->obj, PDF_NAME_V) ? Signature_Signed : Signature_Unsigned;
2345
}
2346
2347
JNIEXPORT jstring JNICALL
2348
JNI_FN(MuPDFCore_checkFocusedSignatureInternal)(JNIEnv * env, jobject thiz)
2349
{
2350
globals *glo = get_globals(env, thiz);
2351
fz_context *ctx = glo->ctx;
2352
pdf_document *idoc = pdf_specifics(ctx, glo->doc);
2353
pdf_widget *focus;
2354
char ebuf[256] = "Failed";
2355
2356
if (idoc == NULL)
2357
goto exit;
2358
2359
focus = pdf_focused_widget(ctx, idoc);
2360
2361
if (focus == NULL)
2362
goto exit;
2363
2364
if (pdf_check_signature(ctx, idoc, focus, glo->current_path, ebuf, sizeof(ebuf)))
2365
{
2366
strcpy(ebuf, "Signature is valid");
2367
}
2368
2369
exit:
2370
return (*env)->NewStringUTF(env, ebuf);
2371
}
2372
2373
JNIEXPORT jboolean JNICALL
2374
JNI_FN(MuPDFCore_signFocusedSignatureInternal)(JNIEnv * env, jobject thiz, jstring jkeyfile, jstring jpassword)
2375
{
2376
globals *glo = get_globals(env, thiz);
2377
fz_context *ctx = glo->ctx;
2378
pdf_document *idoc = pdf_specifics(ctx, glo->doc);
2379
pdf_widget *focus;
2380
const char *keyfile;
2381
const char *password;
2382
jboolean res;
2383
2384
if (idoc == NULL)
2385
return JNI_FALSE;
2386
2387
focus = pdf_focused_widget(ctx, idoc);
2388
2389
if (focus == NULL)
2390
return JNI_FALSE;
2391
2392
keyfile = (*env)->GetStringUTFChars(env, jkeyfile, NULL);
2393
password = (*env)->GetStringUTFChars(env, jpassword, NULL);
2394
if (keyfile == NULL || password == NULL)
2395
return JNI_FALSE;
2396
2397
fz_var(res);
2398
fz_try(ctx)
2399
{
2400
pdf_sign_signature(ctx, idoc, focus, keyfile, password);
2401
dump_annotation_display_lists(glo);
2402
res = JNI_TRUE;
2403
}
2404
fz_catch(ctx)
2405
{
2406
res = JNI_FALSE;
2407
}
2408
2409
return res;
2410
}
2411
2412
JNIEXPORT jobject JNICALL
2413
JNI_FN(MuPDFCore_waitForAlertInternal)(JNIEnv * env, jobject thiz)
2414
{
2415
globals *glo = get_globals(env, thiz);
2416
jclass alertClass;
2417
jmethodID ctor;
2418
jstring title;
2419
jstring message;
2420
int alert_present;
2421
pdf_alert_event alert;
2422
2423
LOGT("Enter waitForAlert");
2424
pthread_mutex_lock(&glo->fin_lock);
2425
pthread_mutex_lock(&glo->alert_lock);
2426
2427
while (glo->alerts_active && !glo->alert_request)
2428
pthread_cond_wait(&glo->alert_request_cond, &glo->alert_lock);
2429
glo->alert_request = 0;
2430
2431
alert_present = (glo->alerts_active && glo->current_alert);
2432
2433
if (alert_present)
2434
alert = *glo->current_alert;
2435
2436
pthread_mutex_unlock(&glo->alert_lock);
2437
pthread_mutex_unlock(&glo->fin_lock);
2438
LOGT("Exit waitForAlert %d", alert_present);
2439
2440
if (!alert_present)
2441
return NULL;
2442
2443
alertClass = (*env)->FindClass(env, PACKAGENAME "/MuPDFAlertInternal");
2444
if (alertClass == NULL)
2445
return NULL;
2446
2447
ctor = (*env)->GetMethodID(env, alertClass, "<init>", "(Ljava/lang/String;IILjava/lang/String;I)V");
2448
if (ctor == NULL)
2449
return NULL;
2450
2451
title = (*env)->NewStringUTF(env, alert.title);
2452
if (title == NULL)
2453
return NULL;
2454
2455
message = (*env)->NewStringUTF(env, alert.message);
2456
if (message == NULL)
2457
return NULL;
2458
2459
return (*env)->NewObject(env, alertClass, ctor, message, alert.icon_type, alert.button_group_type, title, alert.button_pressed);
2460
}
2461
2462
JNIEXPORT void JNICALL
2463
JNI_FN(MuPDFCore_replyToAlertInternal)(JNIEnv * env, jobject thiz, jobject alert)
2464
{
2465
globals *glo = get_globals(env, thiz);
2466
jclass alertClass;
2467
jfieldID field;
2468
int button_pressed;
2469
2470
alertClass = (*env)->FindClass(env, PACKAGENAME "/MuPDFAlertInternal");
2471
if (alertClass == NULL)
2472
return;
2473
2474
field = (*env)->GetFieldID(env, alertClass, "buttonPressed", "I");
2475
if (field == NULL)
2476
return;
2477
2478
button_pressed = (*env)->GetIntField(env, alert, field);
2479
2480
LOGT("Enter replyToAlert");
2481
pthread_mutex_lock(&glo->alert_lock);
2482
2483
if (glo->alerts_active && glo->current_alert)
2484
{
2485
// Fill in button_pressed and signal reply received.
2486
glo->current_alert->button_pressed = button_pressed;
2487
glo->alert_reply = 1;
2488
pthread_cond_signal(&glo->alert_reply_cond);
2489
}
2490
2491
pthread_mutex_unlock(&glo->alert_lock);
2492
LOGT("Exit replyToAlert");
2493
}
2494
2495
JNIEXPORT void JNICALL
2496
JNI_FN(MuPDFCore_startAlertsInternal)(JNIEnv * env, jobject thiz)
2497
{
2498
globals *glo = get_globals(env, thiz);
2499
2500
if (!glo->alerts_initialised)
2501
return;
2502
2503
LOGT("Enter startAlerts");
2504
pthread_mutex_lock(&glo->alert_lock);
2505
2506
glo->alert_reply = 0;
2507
glo->alert_request = 0;
2508
glo->alerts_active = 1;
2509
glo->current_alert = NULL;
2510
2511
pthread_mutex_unlock(&glo->alert_lock);
2512
LOGT("Exit startAlerts");
2513
}
2514
2515
JNIEXPORT void JNICALL
2516
JNI_FN(MuPDFCore_stopAlertsInternal)(JNIEnv * env, jobject thiz)
2517
{
2518
globals *glo = get_globals(env, thiz);
2519
2520
if (!glo->alerts_initialised)
2521
return;
2522
2523
LOGT("Enter stopAlerts");
2524
pthread_mutex_lock(&glo->alert_lock);
2525
2526
glo->alert_reply = 0;
2527
glo->alert_request = 0;
2528
glo->alerts_active = 0;
2529
glo->current_alert = NULL;
2530
pthread_cond_signal(&glo->alert_reply_cond);
2531
pthread_cond_signal(&glo->alert_request_cond);
2532
2533
pthread_mutex_unlock(&glo->alert_lock);
2534
LOGT("Exit stopAleerts");
2535
}
2536
2537
JNIEXPORT jboolean JNICALL
2538
JNI_FN(MuPDFCore_hasChangesInternal)(JNIEnv * env, jobject thiz)
2539
{
2540
globals *glo = get_globals(env, thiz);
2541
fz_context *ctx = glo->ctx;
2542
pdf_document *idoc = pdf_specifics(ctx, glo->doc);
2543
2544
return (idoc && pdf_has_unsaved_changes(ctx, idoc)) ? JNI_TRUE : JNI_FALSE;
2545
}
2546
2547
static char *tmp_path(char *path)
2548
{
2549
int f;
2550
char *buf = malloc(strlen(path) + 6 + 1);
2551
if (!buf)
2552
return NULL;
2553
2554
strcpy(buf, path);
2555
strcat(buf, "XXXXXX");
2556
2557
f = mkstemp(buf);
2558
2559
if (f >= 0)
2560
{
2561
close(f);
2562
return buf;
2563
}
2564
else
2565
{
2566
free(buf);
2567
return NULL;
2568
}
2569
}
2570
2571
JNIEXPORT void JNICALL
2572
JNI_FN(MuPDFCore_saveInternal)(JNIEnv * env, jobject thiz)
2573
{
2574
globals *glo = get_globals(env, thiz);
2575
fz_context *ctx = glo->ctx;
2576
2577
if (glo->doc && glo->current_path)
2578
{
2579
char *tmp;
2580
fz_write_options opts;
2581
opts.do_incremental = 1;
2582
opts.do_ascii = 0;
2583
opts.do_expand = 0;
2584
opts.do_garbage = 0;
2585
opts.do_linear = 0;
2586
2587
tmp = tmp_path(glo->current_path);
2588
if (tmp)
2589
{
2590
int written = 0;
2591
2592
fz_var(written);
2593
fz_try(ctx)
2594
{
2595
FILE *fin = fopen(glo->current_path, "rb");
2596
FILE *fout = fopen(tmp, "wb");
2597
char buf[256];
2598
int n, err = 1;
2599
2600
if (fin && fout)
2601
{
2602
while ((n = fread(buf, 1, sizeof(buf), fin)) > 0)
2603
fwrite(buf, 1, n, fout);
2604
err = (ferror(fin) || ferror(fout));
2605
}
2606
2607
if (fin)
2608
fclose(fin);
2609
if (fout)
2610
fclose(fout);
2611
2612
if (!err)
2613
{
2614
fz_write_document(ctx, glo->doc, tmp, &opts);
2615
written = 1;
2616
}
2617
}
2618
fz_catch(ctx)
2619
{
2620
written = 0;
2621
}
2622
2623
if (written)
2624
{
2625
close_doc(glo);
2626
rename(tmp, glo->current_path);
2627
}
2628
2629
free(tmp);
2630
}
2631
}
2632
}
2633
2634
JNIEXPORT void JNICALL
2635
JNI_FN(MuPDFCore_dumpMemoryInternal)(JNIEnv * env, jobject thiz)
2636
{
2637
globals *glo = get_globals(env, thiz);
2638
fz_context *ctx = glo->ctx;
2639
2640
#ifdef MEMENTO
2641
LOGE("dumpMemoryInternal start");
2642
Memento_listNewBlocks();
2643
Memento_stats();
2644
LOGE("dumpMemoryInternal end");
2645
#endif
2646
}
2647
2648
JNIEXPORT jlong JNICALL
2649
JNI_FN(MuPDFCore_createCookie)(JNIEnv * env, jobject thiz)
2650
{
2651
globals *glo = get_globals_any_thread(env, thiz);
2652
if (glo == NULL)
2653
return 0;
2654
fz_context *ctx = glo->ctx;
2655
2656
return (jlong) (intptr_t) fz_calloc_no_throw(ctx,1, sizeof(fz_cookie));
2657
}
2658
2659
JNIEXPORT void JNICALL
2660
JNI_FN(MuPDFCore_destroyCookie)(JNIEnv * env, jobject thiz, jlong cookiePtr)
2661
{
2662
fz_cookie *cookie = (fz_cookie *) (intptr_t) cookiePtr;
2663
globals *glo = get_globals_any_thread(env, thiz);
2664
if (glo == NULL)
2665
return;
2666
fz_context *ctx = glo->ctx;
2667
2668
fz_free(ctx, cookie);
2669
}
2670
2671
JNIEXPORT void JNICALL
2672
JNI_FN(MuPDFCore_abortCookie)(JNIEnv * env, jobject thiz, jlong cookiePtr)
2673
{
2674
fz_cookie *cookie = (fz_cookie *) (intptr_t) cookiePtr;
2675
if (cookie != NULL)
2676
cookie->abort = 1;
2677
}
2678
2679