diff options
author | Paul Gardiner <paulg.artifex@glidos.net> | 2012-10-11 11:38:32 +0100 |
---|---|---|
committer | Paul Gardiner <paulg.artifex@glidos.net> | 2012-10-11 11:38:32 +0100 |
commit | 84f84d86e6d7f079e12139fa3306c3bc71713f77 (patch) | |
tree | c97062f75ed879cd3cb8b7e08a0fb63be23030b2 /android | |
parent | eae647babea3730d2af1d1882707db355bd660ac (diff) | |
download | mupdf-84f84d86e6d7f079e12139fa3306c3bc71713f77.tar.xz |
Android Forms: pass in mouse events and handle updating
Also add a function to report whether the core has javascript support,
so that the additional features can be enabled only when the javascript
engine is present
Diffstat (limited to 'android')
-rw-r--r-- | android/jni/Core.mk | 1 | ||||
-rw-r--r-- | android/jni/mupdf.c | 124 | ||||
-rw-r--r-- | android/src/com/artifex/mupdf/MuPDFActivity.java | 38 | ||||
-rw-r--r-- | android/src/com/artifex/mupdf/MuPDFCore.java | 42 | ||||
-rw-r--r-- | android/src/com/artifex/mupdf/MuPDFPageView.java | 57 | ||||
-rw-r--r-- | android/src/com/artifex/mupdf/PageView.java | 33 |
6 files changed, 260 insertions, 35 deletions
diff --git a/android/jni/Core.mk b/android/jni/Core.mk index 202a8168..917b60b7 100644 --- a/android/jni/Core.mk +++ b/android/jni/Core.mk @@ -51,6 +51,7 @@ LOCAL_SRC_FILES := \ $(MY_ROOT)/fitz/doc_document.c \ $(MY_ROOT)/fitz/doc_link.c \ $(MY_ROOT)/fitz/doc_outline.c \ + $(MY_ROOT)/fitz/doc_interactive.c \ $(MY_ROOT)/fitz/filt_basic.c \ $(MY_ROOT)/fitz/filt_dctd.c \ $(MY_ROOT)/fitz/filt_faxd.c \ diff --git a/android/jni/mupdf.c b/android/jni/mupdf.c index 537c90c3..d4105115 100644 --- a/android/jni/mupdf.c +++ b/android/jni/mupdf.c @@ -101,11 +101,11 @@ Java_com_artifex_mupdf_MuPDFCore_gotoPageInternal(JNIEnv *env, jobject thiz, int float zoom; fz_matrix ctm; fz_bbox bbox; - fz_device *dev = NULL; - fz_var(dev); + if (page == pagenum && currentPage != NULL) + return; - if (currentPage != NULL && page != currentPageNumber) + if (currentPage != NULL) { fz_free_page(doc, currentPage); currentPage = NULL; @@ -135,11 +135,18 @@ Java_com_artifex_mupdf_MuPDFCore_gotoPageInternal(JNIEnv *env, jobject thiz, int } fz_catch(ctx) { - currentPageNumber = page; LOGE("cannot make displaylist from page %d", pagenum); } - fz_free_device(dev); - dev = NULL; +} + +JNIEXPORT void JNICALL +Java_com_artifex_mupdf_MuPDFCore_markDirtyInternal(JNIEnv *env, jobject thiz, int page) +{ + if (currentPage != NULL && page == pagenum) + { + fz_free_page(doc, currentPage); + currentPage = NULL; + } } JNIEXPORT float JNICALL @@ -157,6 +164,12 @@ Java_com_artifex_mupdf_MuPDFCore_getPageHeight(JNIEnv *env, jobject thiz) } JNIEXPORT jboolean JNICALL +Java_com_artifex_mupdf_MuPDFCore_javascriptSupported(JNIEnv *env, jobject thiz) +{ + return fz_javascript_supported(); +} + +JNIEXPORT jboolean JNICALL Java_com_artifex_mupdf_MuPDFCore_drawPage(JNIEnv *env, jobject thiz, jobject bitmap, int pageW, int pageH, int patchX, int patchY, int patchW, int patchH) { @@ -614,6 +627,59 @@ Java_com_artifex_mupdf_MuPDFCore_getPageLinksInternal(JNIEnv * env, jobject thiz return arr; } +JNIEXPORT jobjectArray JNICALL +Java_com_artifex_mupdf_MuPDFCore_getWidgetAreasInternal(JNIEnv * env, jobject thiz, int pageNumber) +{ + jclass rectFClass; + jmethodID ctor; + jobjectArray arr; + jobject rectF; + fz_interactive *idoc; + fz_widget *widget; + fz_matrix ctm; + float zoom; + int count; + + rectFClass = (*env)->FindClass(env, "android/graphics/RectF"); + if (rectFClass == NULL) return NULL; + ctor = (*env)->GetMethodID(env, rectFClass, "<init>", "(FFFF)V"); + if (ctor == NULL) return NULL; + + Java_com_artifex_mupdf_MuPDFCore_gotoPageInternal(env, thiz, pageNumber); + if (currentPageNumber == -1 || currentPage == NULL) + return NULL; + + idoc = fz_interact(doc); + if (idoc == NULL) + return NULL; + + zoom = resolution / 72; + ctm = fz_scale(zoom, zoom); + + count = 0; + for (widget = fz_first_widget(idoc, currentPage); widget; widget = fz_next_widget(idoc, widget)) + count ++; + + arr = (*env)->NewObjectArray(env, count, rectFClass, NULL); + if (arr == NULL) return NULL; + + count = 0; + for (widget = fz_first_widget(idoc, currentPage); widget; widget = fz_next_widget(idoc, widget)) + { + fz_rect rect = fz_transform_rect(ctm, *fz_widget_bbox(widget)); + + rectF = (*env)->NewObject(env, rectFClass, ctor, + (float)rect.x0, (float)rect.y0, (float)rect.x1, (float)rect.y1); + if (rectF == NULL) return NULL; + (*env)->SetObjectArrayElement(env, arr, count, rectF); + (*env)->DeleteLocalRef(env, rectF); + + count ++; + } + + return arr; +} + JNIEXPORT int JNICALL Java_com_artifex_mupdf_MuPDFCore_getPageLink(JNIEnv * env, jobject thiz, int pageNumber, float x, float y) { @@ -657,3 +723,49 @@ Java_com_artifex_mupdf_MuPDFCore_getPageLink(JNIEnv * env, jobject thiz, int pag return link->dest.ld.gotor.page; return -1; } + +JNIEXPORT int JNICALL +Java_com_artifex_mupdf_MuPDFCore_passClickEventInternal(JNIEnv * env, jobject thiz, int pageNumber, float x, float y) +{ + fz_matrix ctm; + fz_interactive *idoc = fz_interact(doc); + float zoom; + fz_point p; + fz_ui_event event; + int changed = 0; + + if (idoc == NULL) + return 0; + + Java_com_artifex_mupdf_MuPDFCore_gotoPageInternal(env, thiz, pageNumber); + if (currentPageNumber == -1 || currentPage == NULL) + return 0; + + p.x = x; + p.y = y; + + /* Ultimately we should probably return a pointer to a java structure + * with the link details in, but for now, page number will suffice. + */ + zoom = resolution / 72; + ctm = fz_scale(zoom, zoom); + ctm = fz_invert_matrix(ctm); + + p = fz_transform_point(ctm, p); + + fz_try(ctx) + { + event.etype = FZ_EVENT_TYPE_POINTER; + event.event.pointer.pt = p; + event.event.pointer.ptype = FZ_POINTER_DOWN; + changed = fz_pass_event(idoc, currentPage, &event); + event.event.pointer.ptype = FZ_POINTER_UP; + changed |= fz_pass_event(idoc, currentPage, &event); + } + fz_catch(ctx) + { + LOGE("passClickEvent: %s", ctx->error->message); + } + + return changed; +} diff --git a/android/src/com/artifex/mupdf/MuPDFActivity.java b/android/src/com/artifex/mupdf/MuPDFActivity.java index c530b01b..81d5e6ee 100644 --- a/android/src/com/artifex/mupdf/MuPDFActivity.java +++ b/android/src/com/artifex/mupdf/MuPDFActivity.java @@ -212,26 +212,30 @@ public class MuPDFActivity extends Activity private boolean showButtonsDisabled; public boolean onSingleTapUp(MotionEvent e) { - if (e.getX() < super.getWidth()/TAP_PAGE_MARGIN) { - super.moveToPrevious(); - } else if (e.getX() > super.getWidth()*(TAP_PAGE_MARGIN-1)/TAP_PAGE_MARGIN) { - super.moveToNext(); - } else if (!showButtonsDisabled) { - int linkPage = -1; - if (mLinkState != LinkState.INHIBIT) { - MuPDFPageView pageView = (MuPDFPageView) mDocView.getDisplayedView(); - if (pageView != null) { + if (!showButtonsDisabled) { + MuPDFPageView pageView = (MuPDFPageView) mDocView.getDisplayedView(); + if (MuPDFCore.javascriptSupported() && pageView.passClickEvent(e.getX(), e.getY())) { + // If the page consumes the event do nothing else + } else if (e.getX() < super.getWidth()/TAP_PAGE_MARGIN) { + super.moveToPrevious(); + } else if (e.getX() > super.getWidth()*(TAP_PAGE_MARGIN-1)/TAP_PAGE_MARGIN) { + super.moveToNext(); + } else { + int linkPage = -1; + if (mLinkState != LinkState.INHIBIT) { + if (pageView != null) { // XXX linkPage = pageView.hitLinkPage(e.getX(), e.getY()); + } } - } - if (linkPage != -1) { - mDocView.setDisplayedViewIndex(linkPage); - } else { - if (!mButtonsVisible) { - showButtons(); + if (linkPage != -1) { + mDocView.setDisplayedViewIndex(linkPage); } else { - hideButtons(); + if (!mButtonsVisible) { + showButtons(); + } else { + hideButtons(); + } } } } @@ -284,7 +288,7 @@ public class MuPDFActivity extends Activity protected void onSettle(View v) { // When the layout has settled ask the page to render // in HQ - ((PageView)v).addHq(); + ((PageView)v).addHq(false); } protected void onUnsettle(View v) { diff --git a/android/src/com/artifex/mupdf/MuPDFCore.java b/android/src/com/artifex/mupdf/MuPDFCore.java index b52a3682..e7653f9e 100644 --- a/android/src/com/artifex/mupdf/MuPDFCore.java +++ b/android/src/com/artifex/mupdf/MuPDFCore.java @@ -20,21 +20,26 @@ public class MuPDFCore /* The native functions */ private static native int openFile(String filename); private static native int countPagesInternal(); + private static native void markDirtyInternal(int page); private static native void gotoPageInternal(int localActionPageNum); private static native float getPageWidth(); private static native float getPageHeight(); - public static native void drawPage(Bitmap bitmap, + private static native void drawPage(Bitmap bitmap, int pageW, int pageH, int patchX, int patchY, int patchW, int patchH); - public static native RectF[] searchPage(String text); - public static native int getPageLink(int page, float x, float y); - public static native LinkInfo [] getPageLinksInternal(int page); - public static native OutlineItem [] getOutlineInternal(); - public static native boolean hasOutlineInternal(); - public static native boolean needsPasswordInternal(); - public static native boolean authenticatePasswordInternal(String password); - public static native void destroying(); + private static native RectF[] searchPage(String text); + private static native int getPageLink(int page, float x, float y); + private static native int passClickEventInternal(int page, float x, float y); + private static native LinkInfo [] getPageLinksInternal(int page); + private static native RectF[] getWidgetAreasInternal(int page); + private static native OutlineItem [] getOutlineInternal(); + private static native boolean hasOutlineInternal(); + private static native boolean needsPasswordInternal(); + private static native boolean authenticatePasswordInternal(String password); + private static native void destroying(); + + public static native boolean javascriptSupported(); public MuPDFCore(String filename) throws Exception { @@ -57,7 +62,7 @@ public class MuPDFCore } /* Shim function */ - public void gotoPage(int page) + private void gotoPage(int page) { if (page > numPages-1) page = numPages-1; @@ -90,6 +95,19 @@ public class MuPDFCore return bm; } + public synchronized boolean passClickEvent(int page, float x, float y) { + boolean changed = passClickEventInternal(page, x, y) != 0; + + if (changed) { + if (page == pageNum) + pageNum = -1; + + markDirtyInternal(page); + } + + return changed; + } + public synchronized int hitLinkPage(int page, float x, float y) { return getPageLink(page, x, y); } @@ -98,6 +116,10 @@ public class MuPDFCore return getPageLinksInternal(page); } + public synchronized RectF [] getWidgetAreas(int page) { + return getWidgetAreasInternal(page); + } + public synchronized RectF [] searchPage(int page, String text) { gotoPage(page); return searchPage(text); diff --git a/android/src/com/artifex/mupdf/MuPDFPageView.java b/android/src/com/artifex/mupdf/MuPDFPageView.java index 6294bc55..9cb430ef 100644 --- a/android/src/com/artifex/mupdf/MuPDFPageView.java +++ b/android/src/com/artifex/mupdf/MuPDFPageView.java @@ -3,9 +3,14 @@ package com.artifex.mupdf; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Point; +import android.graphics.PointF; +import android.graphics.RectF; public class MuPDFPageView extends PageView { private final MuPDFCore mCore; + private SafeAsyncTask<Void,Void,Boolean> mPassClick; + private RectF mWidgetAreas[]; + private SafeAsyncTask<Void,Void,RectF[]> mLoadWidgetAreas; public MuPDFPageView(Context c, MuPDFCore core, Point parentSize) { super(c, parentSize); @@ -24,6 +29,39 @@ public class MuPDFPageView extends PageView { return mCore.hitLinkPage(mPageNumber, docRelX, docRelY); } + public boolean passClickEvent(float x, float y) { + float scale = mSourceScale*(float)getWidth()/(float)mSize.x; + final float docRelX = (x - getLeft())/scale; + final float docRelY = (y - getTop())/scale; + boolean hitWidget = false; + + if (mWidgetAreas != null) { + for (int i = 0; i < mWidgetAreas.length && !hitWidget; i++) + if (mWidgetAreas[i].contains(docRelX, docRelY)) + hitWidget = true; + } + + if (hitWidget) { + mPassClick = new SafeAsyncTask<Void,Void,Boolean>() { + @Override + protected Boolean doInBackground(Void... arg0) { + return mCore.passClickEvent(mPageNumber, docRelX, docRelY); + } + + @Override + protected void onPostExecute(Boolean result) { + if (result) { + update(); + } + } + }; + + mPassClick.execute(); + } + + return hitWidget; + } + @Override protected Bitmap drawPage(int sizeX, int sizeY, int patchX, int patchY, int patchWidth, int patchHeight) { @@ -34,4 +72,23 @@ public class MuPDFPageView extends PageView { protected LinkInfo[] getLinkInfo() { return mCore.getPageLinks(mPageNumber); } + + @Override + public void setPage(final int page, PointF size) { + mLoadWidgetAreas = new SafeAsyncTask<Void,Void,RectF[]> () { + @Override + protected RectF[] doInBackground(Void... arg0) { + return mCore.getWidgetAreas(page); + } + + @Override + protected void onPostExecute(RectF[] result) { + mWidgetAreas = result; + } + }; + + mLoadWidgetAreas.execute(); + + super.setPage(page, size); + } } diff --git a/android/src/com/artifex/mupdf/PageView.java b/android/src/com/artifex/mupdf/PageView.java index 32ff7e74..072036f4 100644 --- a/android/src/com/artifex/mupdf/PageView.java +++ b/android/src/com/artifex/mupdf/PageView.java @@ -317,7 +317,7 @@ public abstract class PageView extends ViewGroup { } } - public void addHq() { + public void addHq(boolean force) { Rect viewArea = new Rect(getLeft(),getTop(),getRight(),getBottom()); // If the viewArea's size matches the unzoomed size, there is no need for an hq patch if (viewArea.width() != mSize.x || viewArea.height() != mSize.y) { @@ -332,7 +332,7 @@ public abstract class PageView extends ViewGroup { patchArea.offset(-viewArea.left, -viewArea.top); // If being asked for the same area as last time, nothing to do - if (patchArea.equals(mPatchArea) && patchViewSize.equals(mPatchViewSize)) + if (patchArea.equals(mPatchArea) && patchViewSize.equals(mPatchViewSize) && !force) return; // Stop the drawing of previous patch if still going @@ -373,6 +373,35 @@ public abstract class PageView extends ViewGroup { } } + public void update() { + // Cancel pending render task + if (mDrawEntire != null) { + mDrawEntire.cancel(true); + mDrawEntire = null; + } + + if (mDrawPatch != null) { + mDrawPatch.cancel(true); + mDrawPatch = null; + } + + // Render the page in the background + mDrawEntire = new SafeAsyncTask<Void,Void,Bitmap>() { + protected Bitmap doInBackground(Void... v) { + return drawPage(mSize.x, mSize.y, 0, 0, mSize.x, mSize.y); + } + + protected void onPostExecute(Bitmap bm) { + mEntire.setImageBitmap(bm); + invalidate(); + } + }; + + mDrawEntire.safeExecute(); + + addHq(true); + } + public void removeHq() { // Stop the drawing of the patch if still going if (mDrawPatch != null) { |