summaryrefslogtreecommitdiff
path: root/android
diff options
context:
space:
mode:
authorPaul Gardiner <paulg.artifex@glidos.net>2013-01-29 14:53:35 +0000
committerRobin Watts <robin.watts@artifex.com>2013-01-31 11:17:40 +0000
commitcea4109277d5e558f4cfa0707aee7e371ed06504 (patch)
treefa33497f5666cdf196f523fc412739ac63b2e04c /android
parentaeed1e16e440cefbf5137eef7f4af608b0c70569 (diff)
downloadmupdf-cea4109277d5e558f4cfa0707aee7e371ed06504.tar.xz
Android: implement strikeout annotation creation
Diffstat (limited to 'android')
-rw-r--r--android/jni/mupdf.c121
-rw-r--r--android/res/drawable-ldpi/ic_strike.pngbin0 -> 440 bytes
-rw-r--r--android/res/drawable-mdpi/ic_strike.pngbin0 -> 589 bytes
-rw-r--r--android/res/layout/buttons.xml10
-rw-r--r--android/res/values/strings.xml1
-rw-r--r--android/src/com/artifex/mupdfdemo/MuPDFActivity.java12
-rw-r--r--android/src/com/artifex/mupdfdemo/MuPDFCore.java6
-rw-r--r--android/src/com/artifex/mupdfdemo/MuPDFPageView.java5
-rw-r--r--android/src/com/artifex/mupdfdemo/PageView.java54
9 files changed, 208 insertions, 1 deletions
diff --git a/android/jni/mupdf.c b/android/jni/mupdf.c
index bc49ac6c..f0a625eb 100644
--- a/android/jni/mupdf.c
+++ b/android/jni/mupdf.c
@@ -685,6 +685,7 @@ static char *widget_type_string(int t)
case FZ_WIDGET_TYPE_TEXT: return "text";
case FZ_WIDGET_TYPE_LISTBOX: return "listbox";
case FZ_WIDGET_TYPE_COMBOBOX: return "combobox";
+ default: return "non-widget";
}
}
JNIEXPORT jboolean JNICALL
@@ -1230,7 +1231,7 @@ JNI_FN(MuPDFCore_text)(JNIEnv * env, jobject thiz)
{
jclass cls = (*env)->FindClass(env, "java/lang/OutOfMemoryError");
if (cls != NULL)
- (*env)->ThrowNew(env, cls, "Out of memory in MuPDFCore_searchPage");
+ (*env)->ThrowNew(env, cls, "Out of memory in MuPDFCore_text");
(*env)->DeleteLocalRef(env, cls);
return NULL;
@@ -1239,6 +1240,124 @@ JNI_FN(MuPDFCore_text)(JNIEnv * env, jobject thiz)
return barr;
}
+JNIEXPORT void JNICALL
+JNI_FN(MuPDFCore_addStrikeOutAnnotationInternal)(JNIEnv * env, jobject thiz, jobjectArray lines)
+{
+ globals *glo = get_globals(env, thiz);
+ fz_context *ctx = glo->ctx;
+ fz_document *doc = glo->doc;
+ fz_interactive *idoc = fz_interact(doc);
+ page_cache *pc = &glo->pages[glo->current];
+ jclass rect_cls;
+ jfieldID x0_fid, y0_fid, x1_fid, y1_fid;
+ int i, n;
+ fz_path *path = NULL;
+ fz_stroke_state *stroke = NULL;
+ fz_device *dev = NULL;
+ fz_display_list *strike_list;
+
+ if (idoc == NULL)
+ return;
+
+ strike_list = fz_new_display_list(ctx);
+
+ fz_var(path);
+ fz_var(stroke);
+ fz_var(dev);
+ fz_try(ctx)
+ {
+ fz_annot *annot;
+ fz_matrix ctm;
+
+ float color[3] = {1.0, 0.0, 0.0};
+ float zoom = glo->resolution / 72;
+ zoom = 1.0 / zoom;
+ ctm = fz_scale(zoom, zoom);
+ LOGI("P1 %f", zoom);
+ rect_cls = (*env)->FindClass(env, "android.graphics.RectF");
+ if (rect_cls == NULL) fz_throw(ctx, "FindClass");
+ LOGI("P2");
+ x0_fid = (*env)->GetFieldID(env, rect_cls, "left", "F");
+ if (x0_fid == NULL) fz_throw(ctx, "GetFieldID(left)");
+ LOGI("P3");
+ y0_fid = (*env)->GetFieldID(env, rect_cls, "top", "F");
+ if (y0_fid == NULL) fz_throw(ctx, "GetFieldID(top)");
+ LOGI("P4");
+ x1_fid = (*env)->GetFieldID(env, rect_cls, "right", "F");
+ if (x1_fid == NULL) fz_throw(ctx, "GetFieldID(right)");
+ LOGI("P5");
+ y1_fid = (*env)->GetFieldID(env, rect_cls, "bottom", "F");
+ if (y1_fid == NULL) fz_throw(ctx, "GetFieldID(bottom)");
+ LOGI("P6");
+
+ n = (*env)->GetArrayLength(env, lines);
+ LOGI("nlines=%d", n);
+
+ dev = fz_new_list_device(ctx, strike_list);
+
+ for (i = 0; i < n; i++)
+ {
+ jobject line = (*env)->GetObjectArrayElement(env, lines, i);
+ float x0 = (*env)->GetFloatField(env, line, x0_fid);
+ float y0 = (*env)->GetFloatField(env, line, y0_fid);
+ float x1 = (*env)->GetFloatField(env, line, x1_fid);
+ float y1 = (*env)->GetFloatField(env, line, y1_fid);
+ float vcenter = (y0 + y1)/2;
+ float thickness = y1 - y0;
+
+ if (!stroke || stroke->linewidth != thickness)
+ {
+ if (stroke)
+ {
+ // assert(path)
+ fz_stroke_path(dev, path, stroke, ctm, fz_device_rgb, color, 1.0);
+ LOGI("Path stroked");
+ fz_drop_stroke_state(ctx, stroke);
+ stroke = NULL;
+ fz_free_path(ctx, path);
+ path = NULL;
+ }
+
+ stroke = fz_new_stroke_state(ctx);
+ LOGI("thickness(%f)", thickness);
+ stroke->linewidth = thickness;
+ path = fz_new_path(ctx);
+ }
+
+ fz_moveto(ctx, path, x0, vcenter);
+ LOGI("moveto(%f,%f)", x0, vcenter);
+ fz_lineto(ctx, path, x1, vcenter);
+ LOGI("lineto(%f,%f)", x1, vcenter);
+ }
+
+ if (stroke)
+ {
+ fz_stroke_path(dev, path, stroke, ctm, fz_device_rgb, color, 1.0);
+ LOGI("Path stroked");
+ }
+
+ annot = fz_make_annot(idoc, pc->page, FZ_ANNOT_STRIKEOUT);
+ fz_set_annot_appearance(idoc, annot, strike_list);
+ dump_annotation_display_lists(glo);
+ }
+ fz_always(ctx)
+ {
+ fz_free_device(dev);
+ fz_drop_stroke_state(ctx, stroke);
+ fz_free_path(ctx, path);
+ fz_free_display_list(ctx, strike_list);
+ }
+ fz_catch(ctx)
+ {
+ fz_free_device(dev);
+ LOGE("addStrikeOutAnnotation: %s failed", ctx->error->message);
+ jclass cls = (*env)->FindClass(env, "java/lang/OutOfMemoryError");
+ if (cls != NULL)
+ (*env)->ThrowNew(env, cls, "Out of memory in MuPDFCore_searchPage");
+ (*env)->DeleteLocalRef(env, cls);
+ }
+}
+
static void close_doc(globals *glo)
{
int i;
diff --git a/android/res/drawable-ldpi/ic_strike.png b/android/res/drawable-ldpi/ic_strike.png
new file mode 100644
index 00000000..36ebe0f3
--- /dev/null
+++ b/android/res/drawable-ldpi/ic_strike.png
Binary files differ
diff --git a/android/res/drawable-mdpi/ic_strike.png b/android/res/drawable-mdpi/ic_strike.png
new file mode 100644
index 00000000..9b2cf71a
--- /dev/null
+++ b/android/res/drawable-mdpi/ic_strike.png
Binary files differ
diff --git a/android/res/layout/buttons.xml b/android/res/layout/buttons.xml
index 910076b7..6764dfd1 100644
--- a/android/res/layout/buttons.xml
+++ b/android/res/layout/buttons.xml
@@ -139,6 +139,16 @@
android:src="@drawable/ic_cancel" />
<ImageButton
+ android:id="@+id/strikeOutButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_toLeftOf="@+id/copySelectButton"
+ android:contentDescription="@string/strike_out"
+ android:background="@drawable/button"
+ android:src="@drawable/ic_strike" />
+
+ <ImageButton
android:id="@+id/copySelectButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
diff --git a/android/res/values/strings.xml b/android/res/values/strings.xml
index 1468d963..28995d2e 100644
--- a/android/res/values/strings.xml
+++ b/android/res/values/strings.xml
@@ -20,4 +20,5 @@
<string name="select">Select</string>
<string name="search">Search</string>
<string name="copy">Copy</string>
+ <string name="strike_out">Strike out</string>
</resources>
diff --git a/android/src/com/artifex/mupdfdemo/MuPDFActivity.java b/android/src/com/artifex/mupdfdemo/MuPDFActivity.java
index f095a041..5ad3d630 100644
--- a/android/src/com/artifex/mupdfdemo/MuPDFActivity.java
+++ b/android/src/com/artifex/mupdfdemo/MuPDFActivity.java
@@ -106,6 +106,7 @@ public class MuPDFActivity extends Activity
private ImageButton mSelectButton;
private ImageButton mCancelSelectButton;
private ImageButton mCopySelectButton;
+ private ImageButton mStrikeOutButton;
private ImageButton mCancelButton;
private ImageButton mOutlineButton;
private ViewAnimator mTopBarSwitcher;
@@ -652,6 +653,16 @@ public class MuPDFActivity extends Activity
}
});
+ mStrikeOutButton.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ PageView pageView = (PageView) mDocView.getDisplayedView();
+ if (pageView != null)
+ pageView.strikeOutSelection();
+ mSelecting = false;
+ mTopBarSwitcher.setDisplayedChild(0);
+ }
+ });
+
mCancelButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
searchModeOff();
@@ -943,6 +954,7 @@ public class MuPDFActivity extends Activity
mSelectButton = (ImageButton)mButtonsView.findViewById(R.id.selectButton);
mCancelSelectButton = (ImageButton)mButtonsView.findViewById(R.id.cancelSelectButton);
mCopySelectButton = (ImageButton)mButtonsView.findViewById(R.id.copySelectButton);
+ mStrikeOutButton = (ImageButton)mButtonsView.findViewById(R.id.strikeOutButton);
mCancelButton = (ImageButton)mButtonsView.findViewById(R.id.cancel);
mOutlineButton = (ImageButton)mButtonsView.findViewById(R.id.outlineButton);
mTopBarSwitcher = (ViewAnimator)mButtonsView.findViewById(R.id.switcher);
diff --git a/android/src/com/artifex/mupdfdemo/MuPDFCore.java b/android/src/com/artifex/mupdfdemo/MuPDFCore.java
index ed9ded92..73db5073 100644
--- a/android/src/com/artifex/mupdfdemo/MuPDFCore.java
+++ b/android/src/com/artifex/mupdfdemo/MuPDFCore.java
@@ -38,6 +38,7 @@ public class MuPDFCore
int patchW, int patchH);
private native RectF[] searchPage(String text);
private native TextChar[][][][] text();
+ private native void addStrikeOutAnnotationInternal(RectF[] lines);
private native int passClickEventInternal(int page, float x, float y);
private native void setFocusedWidgetChoiceSelectedInternal(String [] selected);
private native String [] getFocusedWidgetChoiceSelected();
@@ -235,6 +236,11 @@ public class MuPDFCore
return lns.toArray(new TextWord[lns.size()][]);
}
+ public synchronized void addStrikeOutAnnotation(int page, RectF[] lines) {
+ gotoPage(page);
+ addStrikeOutAnnotationInternal(lines);
+ }
+
public synchronized boolean hasOutline() {
return hasOutlineInternal();
}
diff --git a/android/src/com/artifex/mupdfdemo/MuPDFPageView.java b/android/src/com/artifex/mupdfdemo/MuPDFPageView.java
index 64877198..69157209 100644
--- a/android/src/com/artifex/mupdfdemo/MuPDFPageView.java
+++ b/android/src/com/artifex/mupdfdemo/MuPDFPageView.java
@@ -223,6 +223,11 @@ public class MuPDFPageView extends PageView {
}
@Override
+ protected void addStrikeOut(RectF[] lines) {
+ mCore.addStrikeOutAnnotation(mPageNumber, lines);
+ }
+
+ @Override
public void setPage(final int page, PointF size) {
mLoadWidgetAreas = new AsyncTask<Void,Void,RectF[]> () {
@Override
diff --git a/android/src/com/artifex/mupdfdemo/PageView.java b/android/src/com/artifex/mupdfdemo/PageView.java
index b793db3f..04065174 100644
--- a/android/src/com/artifex/mupdfdemo/PageView.java
+++ b/android/src/com/artifex/mupdfdemo/PageView.java
@@ -103,6 +103,8 @@ public abstract class PageView extends ViewGroup {
private static final int LINK_COLOR = 0x80AC7225;
private static final int BACKGROUND_COLOR = 0xFFFFFFFF;
private static final int PROGRESS_DIALOG_DELAY = 200;
+ private static final float LINE_THICKNESS = 0.07f;
+ private static final float STRIKE_HEIGHT = 0.375f;
private final Context mContext;
protected int mPageNumber;
private Point mParentSize;
@@ -112,6 +114,7 @@ public abstract class PageView extends ViewGroup {
private ImageView mEntire; // Image rendered at minimum zoom
private BitmapHolder mEntireBmh;
private AsyncTask<Void,Void,TextWord[][]> mGetText;
+ private AsyncTask<RectF[],Void,Void> mAddStrikeOut;
private AsyncTask<Void,Void,LinkInfo[]> mGetLinkInfo;
private AsyncTask<Void,Void,Bitmap> mDrawEntire;
@@ -144,6 +147,7 @@ public abstract class PageView extends ViewGroup {
protected abstract Bitmap updatePage(BitmapHolder h, int sizeX, int sizeY, int patchX, int patchY, int patchWidth, int patchHeight);
protected abstract LinkInfo[] getLinkInfo();
protected abstract TextWord[][] getText();
+ protected abstract void addStrikeOut(RectF[] lines);
private void reinit() {
// Cancel pending render task
@@ -441,6 +445,56 @@ public abstract class PageView extends ViewGroup {
return true;
}
+ public void strikeOutSelection() {
+ final ArrayList<RectF> lines = new ArrayList<RectF>();
+ TextSelector sel = new TextSelector(mText, mSelectBox) {
+ RectF rect;
+
+ @Override
+ protected void onStartLine() {
+ rect = new RectF();
+ }
+
+ @Override
+ protected void onWord(TextWord word) {
+ rect.union(word);
+ }
+
+ @Override
+ protected void onEndLine() {
+ if (!rect.isEmpty()) {
+ // These are vertical lines so we can specify
+ // both position and thickness with a RectF
+ float vcenter = rect.bottom - (rect.bottom - rect.top)*STRIKE_HEIGHT;
+ float thickness = (rect.bottom - rect.top)*LINE_THICKNESS;
+ rect.top = vcenter - thickness/2;
+ rect.bottom = vcenter + thickness/2;
+ lines.add(rect);
+ }
+ }
+ };
+
+ sel.select();
+
+ mAddStrikeOut = new AsyncTask<RectF[],Void,Void>() {
+ @Override
+ protected Void doInBackground(RectF[]... params) {
+ addStrikeOut(params[0]);
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(Void result) {
+ update();
+ }
+ };
+
+ mAddStrikeOut.execute(lines.toArray(new RectF[lines.size()]));
+
+ mSelectBox = null;
+ mSearchView.invalidate();
+ }
+
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int x, y;