diff options
author | Paul Gardiner <paul@glidos.net> | 2012-03-07 16:35:30 +0000 |
---|---|---|
committer | Paul Gardiner <paul@glidos.net> | 2012-03-15 11:37:50 +0000 |
commit | e98837c7b917f0801b446792ab642e669c371395 (patch) | |
tree | 0db909df2b70649a567e7b58fbe4e966782eff06 | |
parent | b5faea0723a43d0ae4953da6edffcb52b46ba315 (diff) | |
download | mupdf-e98837c7b917f0801b446792ab642e669c371395.tar.xz |
Android app: highlighting and inhibiting of links
-rw-r--r-- | android/jni/mupdf.c | 57 | ||||
-rw-r--r-- | android/res/drawable-ldpi/ic_hl_link.png | bin | 0 -> 793 bytes | |||
-rw-r--r-- | android/res/drawable-ldpi/ic_link.png | bin | 0 -> 406 bytes | |||
-rw-r--r-- | android/res/drawable-ldpi/ic_nolink.png | bin | 0 -> 644 bytes | |||
-rw-r--r-- | android/res/drawable-mdpi/ic_hl_link.png | bin | 0 -> 906 bytes | |||
-rw-r--r-- | android/res/drawable-mdpi/ic_link.png | bin | 0 -> 379 bytes | |||
-rw-r--r-- | android/res/drawable-mdpi/ic_nolink.png | bin | 0 -> 811 bytes | |||
-rw-r--r-- | android/res/layout/buttons.xml | 11 | ||||
-rw-r--r-- | android/res/values/strings.xml | 1 | ||||
-rw-r--r-- | android/src/com/artifex/mupdf/LinkInfo.java | 12 | ||||
-rw-r--r-- | android/src/com/artifex/mupdf/MuPDFActivity.java | 39 | ||||
-rw-r--r-- | android/src/com/artifex/mupdf/MuPDFCore.java | 5 | ||||
-rw-r--r-- | android/src/com/artifex/mupdf/MuPDFPageView.java | 9 | ||||
-rw-r--r-- | android/src/com/artifex/mupdf/PageView.java | 39 |
14 files changed, 157 insertions, 16 deletions
diff --git a/android/jni/mupdf.c b/android/jni/mupdf.c index 822095ec..537c90c3 100644 --- a/android/jni/mupdf.c +++ b/android/jni/mupdf.c @@ -557,6 +557,63 @@ Java_com_artifex_mupdf_MuPDFCore_destroying(JNIEnv * env, jobject thiz) doc = NULL; } +JNIEXPORT jobjectArray JNICALL +Java_com_artifex_mupdf_MuPDFCore_getPageLinksInternal(JNIEnv * env, jobject thiz, int pageNumber) +{ + jclass linkInfoClass; + jmethodID ctor; + jobjectArray arr; + jobject linkInfo; + fz_matrix ctm; + float zoom; + fz_link *list; + fz_link *link; + int count; + + linkInfoClass = (*env)->FindClass(env, "com/artifex/mupdf/LinkInfo"); + if (linkInfoClass == NULL) return NULL; + ctor = (*env)->GetMethodID(env, linkInfoClass, "<init>", "(FFFFI)V"); + if (ctor == NULL) return NULL; + + Java_com_artifex_mupdf_MuPDFCore_gotoPageInternal(env, thiz, pageNumber); + if (currentPageNumber == -1 || currentPage == NULL) + return NULL; + + zoom = resolution / 72; + ctm = fz_scale(zoom, zoom); + + list = fz_load_links(doc, currentPage); + count = 0; + for (link = list; link; link = link->next) + { + if (link->dest.kind == FZ_LINK_GOTO) + count++ ; + } + + arr = (*env)->NewObjectArray(env, count, linkInfoClass, NULL); + if (arr == NULL) return NULL; + + count = 0; + for (link = list; link; link = link->next) + { + if (link->dest.kind == FZ_LINK_GOTO) + { + fz_rect rect = fz_transform_rect(ctm, link->rect); + + linkInfo = (*env)->NewObject(env, linkInfoClass, ctor, + (float)rect.x0, (float)rect.y0, (float)rect.x1, (float)rect.y1, + link->dest.ld.gotor.page); + if (linkInfo == NULL) return NULL; + (*env)->SetObjectArrayElement(env, arr, count, linkInfo); + (*env)->DeleteLocalRef(env, linkInfo); + + count ++; + } + } + + return arr; +} + JNIEXPORT int JNICALL Java_com_artifex_mupdf_MuPDFCore_getPageLink(JNIEnv * env, jobject thiz, int pageNumber, float x, float y) { diff --git a/android/res/drawable-ldpi/ic_hl_link.png b/android/res/drawable-ldpi/ic_hl_link.png Binary files differnew file mode 100644 index 00000000..b5fd1888 --- /dev/null +++ b/android/res/drawable-ldpi/ic_hl_link.png diff --git a/android/res/drawable-ldpi/ic_link.png b/android/res/drawable-ldpi/ic_link.png Binary files differnew file mode 100644 index 00000000..dad48af3 --- /dev/null +++ b/android/res/drawable-ldpi/ic_link.png diff --git a/android/res/drawable-ldpi/ic_nolink.png b/android/res/drawable-ldpi/ic_nolink.png Binary files differnew file mode 100644 index 00000000..6a821f42 --- /dev/null +++ b/android/res/drawable-ldpi/ic_nolink.png diff --git a/android/res/drawable-mdpi/ic_hl_link.png b/android/res/drawable-mdpi/ic_hl_link.png Binary files differnew file mode 100644 index 00000000..99f26dbb --- /dev/null +++ b/android/res/drawable-mdpi/ic_hl_link.png diff --git a/android/res/drawable-mdpi/ic_link.png b/android/res/drawable-mdpi/ic_link.png Binary files differnew file mode 100644 index 00000000..3de21a5a --- /dev/null +++ b/android/res/drawable-mdpi/ic_link.png diff --git a/android/res/drawable-mdpi/ic_nolink.png b/android/res/drawable-mdpi/ic_nolink.png Binary files differnew file mode 100644 index 00000000..2b12b9fa --- /dev/null +++ b/android/res/drawable-mdpi/ic_nolink.png diff --git a/android/res/layout/buttons.xml b/android/res/layout/buttons.xml index e18ebbb2..94e2593e 100644 --- a/android/res/layout/buttons.xml +++ b/android/res/layout/buttons.xml @@ -38,13 +38,22 @@ android:contentDescription="@string/search_document" android:src="@drawable/ic_list" /> + <ImageButton + android:id="@+id/linkButton" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_centerVertical="true" + android:layout_toLeftOf="@+id/outlineButton" + android:contentDescription="@string/link_control" + android:src="@drawable/ic_link" /> + <TextView android:id="@+id/docNameText" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_centerVertical="true" - android:layout_toLeftOf="@+id/outlineButton" + android:layout_toLeftOf="@+id/linkButton" android:paddingLeft="15dp" android:singleLine="true" android:textAppearance="?android:attr/textAppearanceMedium" /> diff --git a/android/res/values/strings.xml b/android/res/values/strings.xml index 872b07b4..25a75b08 100644 --- a/android/res/values/strings.xml +++ b/android/res/values/strings.xml @@ -13,4 +13,5 @@ <string name="enter_password">Enter Password</string> <string name="text_not_found">Text not found</string> <string name="searching_">Searching...</string> + <string name="link_control">Link highlighting and enabling</string> </resources> diff --git a/android/src/com/artifex/mupdf/LinkInfo.java b/android/src/com/artifex/mupdf/LinkInfo.java new file mode 100644 index 00000000..c2a395e7 --- /dev/null +++ b/android/src/com/artifex/mupdf/LinkInfo.java @@ -0,0 +1,12 @@ +package com.artifex.mupdf; + +import android.graphics.RectF; + +public class LinkInfo extends RectF { + public int pageNumber; + + public LinkInfo(float l, float t, float r, float b, int p) { + super(l, t, r, b); + pageNumber = p; + } +} diff --git a/android/src/com/artifex/mupdf/MuPDFActivity.java b/android/src/com/artifex/mupdf/MuPDFActivity.java index 8895379a..416c1834 100644 --- a/android/src/com/artifex/mupdf/MuPDFActivity.java +++ b/android/src/com/artifex/mupdf/MuPDFActivity.java @@ -42,6 +42,7 @@ class SearchTaskResult { public class MuPDFActivity extends Activity { /* The core rendering instance */ + private enum LinkState {DEFAULT, HIGHLIGHT, INHIBIT}; private final int TAP_PAGE_MARGIN = 5; private MuPDFCore core; private String mFileName; @@ -56,7 +57,7 @@ public class MuPDFActivity extends Activity private ImageButton mCancelButton; private ImageButton mOutlineButton; private ViewSwitcher mTopBarSwitcher; - private View mLowerButtons; + private ImageButton mLinkButton; private boolean mTopBarIsSearch; private ImageButton mSearchBack; private ImageButton mSearchFwd; @@ -64,6 +65,7 @@ public class MuPDFActivity extends Activity private AsyncTask<Integer,Integer,SearchTaskResult> mSearchTask; private SearchTaskResult mSearchTaskResult; private AlertDialog.Builder mAlertBuilder; + private LinkState mLinkState = LinkState.DEFAULT; private MuPDFCore openFile(String path) { @@ -180,9 +182,11 @@ public class MuPDFActivity extends Activity super.moveToNext(); } else if (!showButtonsDisabled) { int linkPage = -1; - MuPDFPageView pageView = (MuPDFPageView) mDocView.getDisplayedView(); - if (pageView != null) { - linkPage = pageView.hitLinkPage(e.getX(), e.getY()); + if (mLinkState != LinkState.INHIBIT) { + MuPDFPageView pageView = (MuPDFPageView) mDocView.getDisplayedView(); + if (pageView != null) { + linkPage = pageView.hitLinkPage(e.getX(), e.getY()); + } } if (linkPage != -1) { @@ -225,6 +229,8 @@ public class MuPDFActivity extends Activity ((PageView)v).setSearchBoxes(mSearchTaskResult.searchBoxes); else ((PageView)v).setSearchBoxes(null); + + ((PageView)v).setLinkHighlighting(mLinkState == LinkState.HIGHLIGHT); } protected void onMoveToChild(int i) { @@ -332,6 +338,29 @@ public class MuPDFActivity extends Activity } }); + mLinkButton.setOnClickListener(new View.OnClickListener() { + public void onClick(View v) { + switch(mLinkState) { + case DEFAULT: + mLinkState = LinkState.HIGHLIGHT; + mLinkButton.setImageResource(R.drawable.ic_hl_link); + //Inform pages of the change. + mDocView.resetupChildren(); + break; + case HIGHLIGHT: + mLinkState = LinkState.INHIBIT; + mLinkButton.setImageResource(R.drawable.ic_nolink); + //Inform pages of the change. + mDocView.resetupChildren(); + break; + case INHIBIT: + mLinkState = LinkState.DEFAULT; + mLinkButton.setImageResource(R.drawable.ic_link); + break; + } + } + }); + if (core.hasOutline()) { mOutlineButton.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { @@ -530,7 +559,7 @@ public class MuPDFActivity extends Activity mSearchBack = (ImageButton)mButtonsView.findViewById(R.id.searchBack); mSearchFwd = (ImageButton)mButtonsView.findViewById(R.id.searchForward); mSearchText = (EditText)mButtonsView.findViewById(R.id.searchText); - mLowerButtons = mButtonsView.findViewById(R.id.lowerButtons); + mLinkButton = (ImageButton)mButtonsView.findViewById(R.id.linkButton); mTopBarSwitcher.setVisibility(View.INVISIBLE); mPageNumberView.setVisibility(View.INVISIBLE); mPageSlider.setVisibility(View.INVISIBLE); diff --git a/android/src/com/artifex/mupdf/MuPDFCore.java b/android/src/com/artifex/mupdf/MuPDFCore.java index fbdd3afa..a4b80fef 100644 --- a/android/src/com/artifex/mupdf/MuPDFCore.java +++ b/android/src/com/artifex/mupdf/MuPDFCore.java @@ -28,6 +28,7 @@ public class MuPDFCore 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(); @@ -90,6 +91,10 @@ public class MuPDFCore return getPageLink(page, x, y); } + public synchronized LinkInfo [] getPageLinks(int page) { + return getPageLinksInternal(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 fc5de6ba..4678fc9c 100644 --- a/android/src/com/artifex/mupdf/MuPDFPageView.java +++ b/android/src/com/artifex/mupdf/MuPDFPageView.java @@ -13,6 +13,10 @@ public class MuPDFPageView extends PageView { } public int hitLinkPage(float x, float y) { + // Since link highlighting was implemented, the super class + // PageView has had sufficient information to be able to + // perform this method directly. Making that change would + // make MuPDFCore.hitLinkPage superfluous. float scale = mSourceScale*(float)getWidth()/(float)mSize.x; float docRelX = (x - getLeft())/scale; float docRelY = (y - getTop())/scale; @@ -25,4 +29,9 @@ public class MuPDFPageView extends PageView { int patchX, int patchY, int patchWidth, int patchHeight) { mCore.drawPage(mPageNumber, bm, sizeX, sizeY, patchX, patchY, patchWidth, patchHeight); } + + @Override + protected LinkInfo[] getLinkInfo() { + return mCore.getPageLinks(mPageNumber); + } } diff --git a/android/src/com/artifex/mupdf/PageView.java b/android/src/com/artifex/mupdf/PageView.java index 4dce6d23..7c2e38d4 100644 --- a/android/src/com/artifex/mupdf/PageView.java +++ b/android/src/com/artifex/mupdf/PageView.java @@ -42,6 +42,7 @@ class OpaqueImageView extends ImageView { public abstract class PageView extends ViewGroup { private static final int HIGHLIGHT_COLOR = 0x805555FF; + private static final int LINK_COLOR = 0x80FFCC88; private static final int BACKGROUND_COLOR = 0xFFFFFFFF; private final Context mContext; protected int mPageNumber; @@ -51,16 +52,18 @@ public abstract class PageView extends ViewGroup { private ImageView mEntire; // Image rendered at minimum zoom private Bitmap mEntireBm; - private AsyncTask<Void,Void,Void> mDrawEntire; + private AsyncTask<Void,Void,LinkInfo[]> mDrawEntire; private Point mPatchViewSize; // View size on the basis of which the patch was created private Rect mPatchArea; private ImageView mPatch; private AsyncTask<PatchInfo,Void,PatchInfo> mDrawPatch; private RectF mSearchBoxes[]; + private LinkInfo mLinks[]; private View mSearchView; private boolean mIsBlank; private boolean mUsingHardwareAcceleration; + private boolean mHighlightLinks; private ProgressBar mBusyIndicator; @@ -73,6 +76,7 @@ public abstract class PageView extends ViewGroup { } protected abstract void drawPage(Bitmap bm, int sizeX, int sizeY, int patchX, int patchY, int patchWidth, int patchHeight); + protected abstract LinkInfo[] getLinkInfo(); public void blank(int page) { // Cancel pending render task @@ -137,10 +141,10 @@ public abstract class PageView extends ViewGroup { } // Render the page in the background - mDrawEntire = new AsyncTask<Void,Void,Void>() { - protected Void doInBackground(Void... v) { + mDrawEntire = new AsyncTask<Void,Void,LinkInfo[]>() { + protected LinkInfo[] doInBackground(Void... v) { drawPage(mEntireBm, mSize.x, mSize.y, 0, 0, mSize.x, mSize.y); - return null; + return getLinkInfo(); } protected void onPreExecute() { @@ -154,10 +158,11 @@ public abstract class PageView extends ViewGroup { } } - protected void onPostExecute(Void v) { + protected void onPostExecute(LinkInfo[] v) { removeView(mBusyIndicator); mBusyIndicator = null; mEntire.setImageBitmap(mEntireBm); + mLinks = v; invalidate(); } }; @@ -169,17 +174,27 @@ public abstract class PageView extends ViewGroup { @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); + float scale = mSourceScale*(float)getWidth()/(float)mSize.x; + Paint paint = new Paint(); if (!mIsBlank && mSearchBoxes != null) { // Work out current total scale factor // from source to view - float scale = mSourceScale*(float)getWidth()/(float)mSize.x; - Paint paint = new Paint(); paint.setColor(HIGHLIGHT_COLOR); for (RectF rect : mSearchBoxes) - canvas.drawRect(new RectF(rect.left * scale, - rect.top * scale, rect.right * scale, - rect.bottom * scale), paint); + canvas.drawRect(rect.left*scale, rect.top*scale, + rect.right*scale, rect.bottom*scale, + paint); + } + + if (!mIsBlank && mLinks != null && mHighlightLinks) { + // Work out current total scale factor + // from source to view + paint.setColor(LINK_COLOR); + for (RectF rect : mLinks) + canvas.drawRect(rect.left*scale, rect.top*scale, + rect.right*scale, rect.bottom*scale, + paint); } } }; @@ -193,6 +208,10 @@ public abstract class PageView extends ViewGroup { mSearchBoxes = searchBoxes; } + public void setLinkHighlighting(boolean f) { + mHighlightLinks = f; + } + @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int x, y; |