diff options
author | Paul Gardiner <paulg.artifex@glidos.net> | 2012-10-31 11:21:11 +0000 |
---|---|---|
committer | Paul Gardiner <paulg.artifex@glidos.net> | 2012-10-31 11:21:11 +0000 |
commit | 58dafe4c6280390b9e6fc93848ec522b46019966 (patch) | |
tree | 6babd32118f52551c49262cde81716c50d02ed13 /android/jni/mupdf.c | |
parent | 12da2b4d0f1fdec7051b98bc63418b4a3ea2ea79 (diff) | |
download | mupdf-58dafe4c6280390b9e6fc93848ec522b46019966.tar.xz |
Android: use partial updates to speed rendering after interaction
Diffstat (limited to 'android/jni/mupdf.c')
-rw-r--r-- | android/jni/mupdf.c | 186 |
1 files changed, 166 insertions, 20 deletions
diff --git a/android/jni/mupdf.c b/android/jni/mupdf.c index 8ab342d9..1e05bffa 100644 --- a/android/jni/mupdf.c +++ b/android/jni/mupdf.c @@ -38,6 +38,7 @@ typedef struct int height; fz_rect media_box; fz_page *page; + fz_page *hq_page; fz_display_list *page_list; fz_display_list *annot_list; } page_cache; @@ -55,12 +56,15 @@ page_cache pages[NUM_CACHE] = {{0}}; static void drop_page_cache(page_cache *pc) { + LOGI("Drop page %d", pc->number); fz_free_display_list(ctx, pc->page_list); pc->page_list = NULL; fz_free_display_list(ctx, pc->annot_list); pc->annot_list = NULL; fz_free_page(doc, pc->page); pc->page = NULL; + fz_free_page(doc, pc->hq_page); + pc->hq_page = NULL; } JNIEXPORT int JNICALL @@ -173,6 +177,7 @@ Java_com_artifex_mupdf_MuPDFCore_gotoPageInternal(JNIEnv *env, jobject thiz, int LOGE("Goto page %d...", page); fz_try(ctx) { + LOGI("Load page %d", pc->number); pc->page = fz_load_page(doc, pc->number); zoom = resolution / 72; pc->media_box = fz_bound_page(doc, pc->page); @@ -187,26 +192,6 @@ Java_com_artifex_mupdf_MuPDFCore_gotoPageInternal(JNIEnv *env, jobject thiz, int } } -JNIEXPORT void JNICALL -Java_com_artifex_mupdf_MuPDFCore_markDirtyInternal(JNIEnv *env, jobject thiz, int page) -{ - int i; - - for (i = 0 ; i < NUM_CACHE; i++) - { - if (pages[i].page != NULL && pages[i].number == page) - { - fz_interactive *idoc = fz_interact(doc); - - if (idoc) - fz_update_page(idoc, pages[i].page); - - fz_free_display_list(ctx, pages[i].annot_list); - pages[i].annot_list = NULL; - } - } -} - JNIEXPORT float JNICALL Java_com_artifex_mupdf_MuPDFCore_getPageWidth(JNIEnv *env, jobject thiz) { @@ -242,6 +227,7 @@ Java_com_artifex_mupdf_MuPDFCore_drawPage(JNIEnv *env, jobject thiz, jobject bit float xscale, yscale; fz_bbox rect; page_cache *pc = &pages[current]; + int hq = (patchW < pageW || patchH < pageH); if (pc->page == NULL) return 0; @@ -273,6 +259,23 @@ Java_com_artifex_mupdf_MuPDFCore_drawPage(JNIEnv *env, jobject thiz, jobject bit fz_try(ctx) { + fz_interactive *idoc = fz_interact(doc); + + // Call fz_update_page now to ensure future calls yield the + // changes from the current state + fz_update_page(idoc, pc->page); + + if (hq) { + // This is a rendering of the hq patch. Ensure there's a second copy of the + // page for use when updating this patch + if (pc->hq_page) { + if (idoc) + fz_update_page(idoc, pc->hq_page); + } else { + pc->hq_page = fz_load_page(doc, pc->number); + } + } + if (pc->page_list == NULL) { /* Render to list */ @@ -350,6 +353,149 @@ Java_com_artifex_mupdf_MuPDFCore_drawPage(JNIEnv *env, jobject thiz, jobject bit return 1; } +JNIEXPORT jboolean JNICALL +Java_com_artifex_mupdf_MuPDFCore_updatePageInternal(JNIEnv *env, jobject thiz, jobject bitmap, int page, + int pageW, int pageH, int patchX, int patchY, int patchW, int patchH) +{ + AndroidBitmapInfo info; + void *pixels; + int ret; + fz_device *dev = NULL; + float zoom; + fz_matrix ctm; + fz_bbox bbox; + fz_pixmap *pix = NULL; + float xscale, yscale; + fz_bbox rect; + fz_interactive *idoc; + page_cache *pc = NULL; + int hq = (patchW < pageW || patchH < pageH); + int i; + + for (i = 0; i < NUM_CACHE; i++) + { + if (pages[i].page != NULL && pages[i].number == page) + { + pc = &pages[i]; + break; + } + } + + if (pc == NULL || (hq && pc->hq_page == NULL)) + { + Java_com_artifex_mupdf_MuPDFCore_gotoPageInternal(env, thiz, page); + return Java_com_artifex_mupdf_MuPDFCore_drawPage(env, thiz, bitmap, pageW, pageH, patchX, patchY, patchW, patchH); + } + + idoc = fz_interact(doc); + + fz_var(pix); + fz_var(dev); + + LOGI("In native method\n"); + if ((ret = AndroidBitmap_getInfo(env, bitmap, &info)) < 0) { + LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret); + return 0; + } + + LOGI("Checking format\n"); + if (info.format != ANDROID_BITMAP_FORMAT_RGBA_8888) { + LOGE("Bitmap format is not RGBA_8888 !"); + return 0; + } + + LOGI("locking pixels\n"); + if ((ret = AndroidBitmap_lockPixels(env, bitmap, &pixels)) < 0) { + LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret); + return 0; + } + + /* Call mupdf to render display list to screen */ + LOGE("Rendering page=%dx%d patch=[%d,%d,%d,%d]", + pageW, pageH, patchX, patchY, patchW, patchH); + + fz_try(ctx) + { + fz_annot *annot; + // Unimportant which page object we use for rendering but we + // must use the correct one for calculating updates + fz_page *page = hq ? pc->hq_page : pc->page; + + fz_update_page(idoc, page); + + if (pc->page_list == NULL) + { + /* Render to list */ + pc->page_list = fz_new_display_list(ctx); + dev = fz_new_list_device(ctx, pc->page_list); + fz_run_page_contents(doc, page, dev, fz_identity, NULL); + } + + fz_free_display_list(ctx, pc->annot_list); + pc->annot_list = NULL; + + if (dev) + { + fz_free_device(dev); + dev = NULL; + } + pc->annot_list = fz_new_display_list(ctx); + dev = fz_new_list_device(ctx, pc->annot_list); + for (annot = fz_first_annot(doc, page); annot; annot = fz_next_annot(doc, annot)) + fz_run_annot(doc, page, annot, dev, fz_identity, NULL); + + rect.x0 = patchX; + rect.y0 = patchY; + rect.x1 = patchX + patchW; + rect.y1 = patchY + patchH; + pix = fz_new_pixmap_with_bbox_and_data(ctx, colorspace, rect, pixels); + + zoom = resolution / 72; + ctm = fz_scale(zoom, zoom); + bbox = fz_round_rect(fz_transform_rect(ctm, pc->media_box)); + /* Now, adjust ctm so that it would give the correct page width + * heights. */ + xscale = (float)pageW/(float)(bbox.x1-bbox.x0); + yscale = (float)pageH/(float)(bbox.y1-bbox.y0); + ctm = fz_concat(ctm, fz_scale(xscale, yscale)); + bbox = fz_round_rect(fz_transform_rect(ctm, pc->media_box)); + + LOGI("Start polling for updates"); + while ((annot = fz_poll_changed_annot(idoc, page)) != NULL) + { + fz_bbox abox = fz_round_rect(fz_transform_rect(ctm, fz_bound_annot(doc, annot))); + abox = fz_intersect_bbox(abox, bbox); + + LOGI("Update rectangle"); + if (!fz_is_empty_bbox(abox)) + { + LOGI("And it isn't empty"); + fz_clear_pixmap_rect_with_value(ctx, pix, 0xff, abox); + dev = fz_new_draw_device_with_bbox(ctx, pix, abox); + if (pc->page_list) + fz_run_display_list(pc->page_list, dev, ctm, abox, NULL); + if (pc->annot_list) + fz_run_display_list(pc->annot_list, dev, ctm, abox, NULL); + fz_free_device(dev); + dev = NULL; + } + } + LOGI("Done polling for updates"); + + LOGE("Rendered"); + } + fz_catch(ctx) + { + fz_free_device(dev); + LOGE("Render failed"); + } + + fz_drop_pixmap(ctx, pix); + AndroidBitmap_unlockPixels(env, bitmap); + + return 1; +} + static fz_text_char textcharat(fz_text_page *page, int idx) { static fz_text_char emptychar = { {0,0,0,0}, ' ' }; |