summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Gardiner <paul@glidos.net>2012-03-07 16:35:30 +0000
committerPaul Gardiner <paul@glidos.net>2012-03-15 11:37:50 +0000
commite98837c7b917f0801b446792ab642e669c371395 (patch)
tree0db909df2b70649a567e7b58fbe4e966782eff06
parentb5faea0723a43d0ae4953da6edffcb52b46ba315 (diff)
downloadmupdf-e98837c7b917f0801b446792ab642e669c371395.tar.xz
Android app: highlighting and inhibiting of links
-rw-r--r--android/jni/mupdf.c57
-rw-r--r--android/res/drawable-ldpi/ic_hl_link.pngbin0 -> 793 bytes
-rw-r--r--android/res/drawable-ldpi/ic_link.pngbin0 -> 406 bytes
-rw-r--r--android/res/drawable-ldpi/ic_nolink.pngbin0 -> 644 bytes
-rw-r--r--android/res/drawable-mdpi/ic_hl_link.pngbin0 -> 906 bytes
-rw-r--r--android/res/drawable-mdpi/ic_link.pngbin0 -> 379 bytes
-rw-r--r--android/res/drawable-mdpi/ic_nolink.pngbin0 -> 811 bytes
-rw-r--r--android/res/layout/buttons.xml11
-rw-r--r--android/res/values/strings.xml1
-rw-r--r--android/src/com/artifex/mupdf/LinkInfo.java12
-rw-r--r--android/src/com/artifex/mupdf/MuPDFActivity.java39
-rw-r--r--android/src/com/artifex/mupdf/MuPDFCore.java5
-rw-r--r--android/src/com/artifex/mupdf/MuPDFPageView.java9
-rw-r--r--android/src/com/artifex/mupdf/PageView.java39
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
new file mode 100644
index 00000000..b5fd1888
--- /dev/null
+++ b/android/res/drawable-ldpi/ic_hl_link.png
Binary files differ
diff --git a/android/res/drawable-ldpi/ic_link.png b/android/res/drawable-ldpi/ic_link.png
new file mode 100644
index 00000000..dad48af3
--- /dev/null
+++ b/android/res/drawable-ldpi/ic_link.png
Binary files differ
diff --git a/android/res/drawable-ldpi/ic_nolink.png b/android/res/drawable-ldpi/ic_nolink.png
new file mode 100644
index 00000000..6a821f42
--- /dev/null
+++ b/android/res/drawable-ldpi/ic_nolink.png
Binary files differ
diff --git a/android/res/drawable-mdpi/ic_hl_link.png b/android/res/drawable-mdpi/ic_hl_link.png
new file mode 100644
index 00000000..99f26dbb
--- /dev/null
+++ b/android/res/drawable-mdpi/ic_hl_link.png
Binary files differ
diff --git a/android/res/drawable-mdpi/ic_link.png b/android/res/drawable-mdpi/ic_link.png
new file mode 100644
index 00000000..3de21a5a
--- /dev/null
+++ b/android/res/drawable-mdpi/ic_link.png
Binary files differ
diff --git a/android/res/drawable-mdpi/ic_nolink.png b/android/res/drawable-mdpi/ic_nolink.png
new file mode 100644
index 00000000..2b12b9fa
--- /dev/null
+++ b/android/res/drawable-mdpi/ic_nolink.png
Binary files differ
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;