summaryrefslogtreecommitdiff
path: root/platform
diff options
context:
space:
mode:
authorfred ross-perry <fredross-perry@Fred-Ross-Perrys-Computer.local>2016-08-08 18:21:36 -0700
committerfredross-perry <fross-perry@conceptuamath.com>2016-08-16 11:21:02 -0700
commite7fa2ff8f4763ae18d194e82943a68c75cb9d28b (patch)
tree6d3305d973c3c67411da9e70952e84fd0f8be72d /platform
parent1bc2b7251071bc913b192f8e0fa86ca31afbfcc3 (diff)
downloadmupdf-e7fa2ff8f4763ae18d194e82943a68c75cb9d28b.tar.xz
Android example : improved text selection.
Diffstat (limited to 'platform')
-rwxr-xr-xplatform/android/example/mupdf/src/main/java/com/artifex/mupdf/android/DocPageView.java218
-rw-r--r--platform/android/example/mupdf/src/main/java/com/artifex/mupdf/android/DocView.java71
-rwxr-xr-xplatform/android/example/mupdf/src/main/java/com/artifex/mupdf/android/DocViewBase.java2
3 files changed, 208 insertions, 83 deletions
diff --git a/platform/android/example/mupdf/src/main/java/com/artifex/mupdf/android/DocPageView.java b/platform/android/example/mupdf/src/main/java/com/artifex/mupdf/android/DocPageView.java
index f6a4853f..536488f1 100755
--- a/platform/android/example/mupdf/src/main/java/com/artifex/mupdf/android/DocPageView.java
+++ b/platform/android/example/mupdf/src/main/java/com/artifex/mupdf/android/DocPageView.java
@@ -26,6 +26,8 @@ import com.artifex.mupdf.fitz.R;
import com.artifex.mupdf.fitz.StructuredText;
import com.artifex.mupdf.fitz.android.AndroidDrawDevice;
+import java.util.ArrayList;
+
public class DocPageView extends View implements Callback
{
private final Document mDoc;
@@ -73,10 +75,8 @@ public class DocPageView extends View implements Callback
// use this to control whether the blue dot is drawn in the upper left corner.
private boolean isMostVisible = false;
- /// structured text, defined once at page setup time.
- StructuredText mStructuredText = null;
- Rect mHighlightRects[] = null;
- Rect hlRect = new Rect();
+ // currently selected TextChars
+ ArrayList<StructuredText.TextChar> mSelection = null;
public DocPageView(Context context, Document theDoc)
{
@@ -135,9 +135,6 @@ public class DocPageView extends View implements Callback
mZoom = w / pagew;
mSize = new Point((int) (pagew * mZoom), (int) (pageH * mZoom));
-
- // get structured text
- mStructuredText = getPage().toStructuredText();
}
public Page getPage()
@@ -380,30 +377,88 @@ public class DocPageView extends View implements Callback
}
}
- public void setHighlight(Point ul, Point dr)
+ public Point getSelectionStart()
{
- // remember the rect we've been given
- hlRect.set(ul.x, ul.y, dr.x, dr.y);
+ if (mSelection == null)
+ return null;
+ if (mSelection.size()==0)
+ return null;
- // find the included text rects
- com.artifex.mupdf.fitz.Rect rects[] = mStructuredText.highlight(new com.artifex.mupdf.fitz.Rect(ul.x, ul.y, dr.x, dr.y));
- if (rects == null || rects.length <= 0)
- {
- mHighlightRects = null;
- return;
- }
+ StructuredText.TextChar tchar = mSelection.get(0);
+
+ return new Point((int)tchar.bbox.x0, (int)tchar.bbox.y0);
+ }
+
+ public Point getSelectionEnd()
+ {
+ if (mSelection == null)
+ return null;
+ if (mSelection.size()==0)
+ return null;
+
+ StructuredText.TextChar tchar = mSelection.get(mSelection.size()-1);
+
+ return new Point((int)tchar.bbox.x1, (int)tchar.bbox.y1);
+ }
+
+ public void setSelection(Point ul, Point dr)
+ {
+ mSelection = new ArrayList<>();
+
+ // get structured text and the block structure
+ StructuredText structuredText = getPage().toStructuredText();
+ StructuredText.TextBlock textBlocks[] = structuredText.getBlocks();
- // convert to Android Rects. They will be used to draw the highlights.
- mHighlightRects = new Rect[rects.length];
- for (int i = 0; i < rects.length; i++)
+ com.artifex.mupdf.fitz.Rect r = new com.artifex.mupdf.fitz.Rect(ul.x, ul.y, dr.x, dr.y);
+ for (StructuredText.TextBlock block : textBlocks)
{
- mHighlightRects[i] = new Rect((int) rects[i].x0, (int) rects[i].y0, (int) rects[i].x1, (int) rects[i].y1);
+ for (StructuredText.TextLine line : block.lines)
+ {
+ boolean firstLine = false;
+ boolean lastLine = false;
+ boolean middleLine = false;
+ if (line.bbox.contains(ul.x, ul.y))
+ firstLine = true;
+ if (line.bbox.contains(dr.x, dr.y))
+ lastLine = true;
+ if (line.bbox.y0 >= ul.y && line.bbox.y1 <= dr.y)
+ middleLine = true;
+
+ for (StructuredText.TextSpan span : line.spans)
+ {
+ for (StructuredText.TextChar tchar : span.chars)
+ {
+ if (firstLine && lastLine)
+ {
+ if (tchar.bbox.x0 >= ul.x && tchar.bbox.x1 <= dr.x)
+ mSelection.add(tchar);
+ }
+ else if (firstLine)
+ {
+ if (tchar.bbox.x0 >= ul.x)
+ mSelection.add(tchar);
+ }
+ else if (lastLine)
+ {
+ if (tchar.bbox.x1 <= dr.x)
+ mSelection.add(tchar);
+ }
+ else if (middleLine)
+ {
+ mSelection.add(tchar);
+ }
+ }
+ }
+ }
}
+
+ invalidate();
}
- public void removeHighlight()
+ public void removeSelection()
{
- mHighlightRects = null;
+ mSelection = new ArrayList<>();
+ invalidate();
}
@Override
@@ -440,10 +495,11 @@ public class DocPageView extends View implements Callback
canvas.drawBitmap(mDrawBitmap, mSrcRect, mDstRect, mPainter);
// highlights
- if (mHighlightRects != null)
+ if (mSelection != null && !mSelection.isEmpty())
{
- for (Rect r : mHighlightRects)
+ for (StructuredText.TextChar tchar : mSelection)
{
+ Rect r = new Rect((int) tchar.bbox.x0, (int) tchar.bbox.y0, (int) tchar.bbox.x1, (int) tchar.bbox.y1);
Rect r2 = pageToView(r);
canvas.drawRect(r2, mHighlightPainter);
}
@@ -458,30 +514,114 @@ public class DocPageView extends View implements Callback
canvas.restore();
}
- public Rect getTappedRect(Point p)
+ public Rect selectWord(Point p)
{
+ // in page units
Point pPage = screenToPage(p.x, p.y);
- com.artifex.mupdf.fitz.Rect bounds = mPage.getBounds();
- com.artifex.mupdf.fitz.Rect rects[] =
- mStructuredText.highlight(new com.artifex.mupdf.fitz.Rect(bounds.x0, bounds.y0, bounds.x1, bounds.y1));
- Rect rfound = null;
- for (com.artifex.mupdf.fitz.Rect r : rects)
+ // get structured text and the block structure
+ StructuredText structuredText = getPage().toStructuredText();
+ StructuredText.TextBlock textBlocks[] = structuredText.getBlocks();
+
+ StructuredText.TextBlock block = blockContainingPoint(textBlocks, pPage);
+ if (block == null)
+ return null;
+
+ StructuredText.TextLine line = lineContainingPoint(block.lines, pPage);
+ if (line == null)
+ return null;
+
+ StructuredText.TextSpan span = spanContainingPoint(line.spans, pPage);
+ if (span == null)
+ return null;
+
+ // find the char containing my point
+ int n = -1;
+ int i;
+ for (i = 0; i < span.chars.length; i++)
{
- if (r.contains(pPage.x, pPage.y))
- rfound = new Rect((int) r.x0, (int) r.y0, (int) r.x1, (int) r.y1);
+ if (span.chars[i].bbox.contains(pPage.x, pPage.y))
+ {
+ n = i;
+ break;
+ }
}
+ // not found
+ if (n == -1)
+ return null;
+ // must be non-blank
+ if (isBlank(span.chars[n].c))
+ return null;
- return rfound;
+ // look forward for a space, or the end
+ int nEnd = n;
+ while (nEnd + 1 < span.chars.length && !isBlank(span.chars[nEnd + 1].c))
+ nEnd++;
+
+ // look backward for a space, or the beginning
+ int nStart = n;
+ while (nStart - 1 >= 0 && !isBlank(span.chars[nStart - 1].c))
+ nStart--;
+
+ mSelection = new ArrayList<>();
+ com.artifex.mupdf.fitz.Rect rWord = new com.artifex.mupdf.fitz.Rect();
+ for (i = nStart; i <= nEnd; i++)
+ {
+ mSelection.add(span.chars[i]);
+ rWord.union(span.chars[i].bbox);
+ }
+
+ return new Rect((int) rWord.x0, (int) rWord.y0, (int) rWord.x1, (int) rWord.y1);
+ }
+
+ private boolean isBlank(int c)
+ {
+ String s = Character.toString((char) c);
+ return s.trim().isEmpty();
}
- public String getSelectedText()
+ private StructuredText.TextBlock blockContainingPoint(StructuredText.TextBlock blocks[], Point p)
{
- // convert to fitz rect
- com.artifex.mupdf.fitz.Rect r =
- new com.artifex.mupdf.fitz.Rect(hlRect.left, hlRect.top, hlRect.right, hlRect.bottom);
+ for (StructuredText.TextBlock block : blocks)
+ {
+ if (block.bbox.contains(p.x, p.y))
+ return block;
+ }
+
+ return null;
+ }
+
+ private StructuredText.TextLine lineContainingPoint(StructuredText.TextLine lines[], Point p)
+ {
+ for (StructuredText.TextLine line : lines)
+ {
+ if (line.bbox.contains(p.x, p.y))
+ return line;
+ }
+
+ return null;
+ }
+
+ private StructuredText.TextSpan spanContainingPoint(StructuredText.TextSpan spans[], Point p)
+ {
+ for (StructuredText.TextSpan span : spans)
+ {
+ if (span.bbox.contains(p.x, p.y))
+ return span;
+ }
+
+ return null;
+ }
+
+ private StructuredText.TextChar charContainingPoint(StructuredText.TextChar chars[], Point p)
+ {
+ for (StructuredText.TextChar tchar : chars)
+ {
+ if (tchar.bbox.contains(p.x, p.y))
+ return tchar;
+ }
- return mStructuredText.copy(r);
+ return null;
}
public Point screenToPage(Point p)
diff --git a/platform/android/example/mupdf/src/main/java/com/artifex/mupdf/android/DocView.java b/platform/android/example/mupdf/src/main/java/com/artifex/mupdf/android/DocView.java
index 71c0fbe6..c057da5c 100644
--- a/platform/android/example/mupdf/src/main/java/com/artifex/mupdf/android/DocView.java
+++ b/platform/android/example/mupdf/src/main/java/com/artifex/mupdf/android/DocView.java
@@ -6,7 +6,6 @@ import android.graphics.Point;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
-import android.util.Log;
import android.util.TypedValue;
import android.view.View;
import android.widget.RelativeLayout;
@@ -122,7 +121,7 @@ public class DocView extends DocViewBase implements DragHandleListener
for (int i = 0; i < numPages; i++)
{
DocPageView cv = (DocPageView) getOrCreateChild(i);
- cv.removeHighlight();
+ cv.removeSelection();
if (cv.isReallyVisible())
cv.invalidate();
}
@@ -130,7 +129,7 @@ public class DocView extends DocViewBase implements DragHandleListener
else
{
// point in screen coordinates, result in page coordinates
- Rect r = dpv.getTappedRect(p);
+ Rect r = dpv.selectWord(p);
if (r != null)
{
// show handles
@@ -142,34 +141,11 @@ public class DocView extends DocViewBase implements DragHandleListener
selectionEndPage = dpv;
selectionEndLoc.set(r.right, r.bottom);
- // do highlight
- doHighlight();
-
moveHandlesToCorners();
}
}
}
- private void doHighlight()
- {
- // TODO: for now, we're dealing with one page at a time
- int numPages = getPageCount();
- for (int i = 0; i < numPages; i++)
- {
- DocPageView cv = (DocPageView) getOrCreateChild(i);
- if (cv.isReallyVisible() && cv == selectionStartPage && cv == selectionEndPage)
- {
- cv.setHighlight(selectionStartLoc, selectionEndLoc);
- logSelectedText();
- }
- else
- {
- cv.removeHighlight();
- }
- cv.invalidate();
- }
- }
-
@Override
protected void doDoubleTap(float fx, float fy)
{
@@ -247,31 +223,30 @@ public class DocView extends DocViewBase implements DragHandleListener
}
}
- doHighlight();
- }
-
- @Override
- public void onEndDrag(DragHandle handle)
- {
- moveHandlesToCorners();
- logSelectedText();
- }
-
- private void logSelectedText()
- {
+ // TODO: for now, we're dealing with one page at a time
int numPages = getPageCount();
for (int i = 0; i < numPages; i++)
{
DocPageView cv = (DocPageView) getOrCreateChild(i);
- String s = cv.getSelectedText();
- if (s != null)
+ if (cv.isReallyVisible() && cv == selectionStartPage && cv == selectionEndPage)
{
- Log.i("example", s);
+ cv.setSelection(selectionStartLoc, selectionEndLoc);
}
+ else
+ {
+ cv.removeSelection();
+ }
+ cv.invalidate();
}
}
@Override
+ public void onEndDrag(DragHandle handle)
+ {
+ moveHandlesToCorners();
+ }
+
+ @Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom)
{
@@ -284,8 +259,18 @@ public class DocView extends DocViewBase implements DragHandleListener
{
if (selectionStartPage != null && selectionEndPage != null)
{
- positionHandle(mSelectionHandleTopLeft, selectionStartPage, selectionStartLoc.x, selectionStartLoc.y);
- positionHandle(mSelectionHandleBottomRight, selectionEndPage, selectionEndLoc.x, selectionEndLoc.y);
+ Point p1 = selectionStartPage.getSelectionStart();
+ Point p2 = selectionEndPage.getSelectionEnd();
+
+ if (p1 != null && p2 != null)
+ {
+ selectionStartLoc.set(p1.x, p1.y);
+ selectionEndLoc.set(p2.x, p2.y);
+ positionHandle(mSelectionHandleTopLeft, selectionStartPage, selectionStartLoc.x, selectionStartLoc.y);
+ positionHandle(mSelectionHandleBottomRight, selectionEndPage, selectionEndLoc.x, selectionEndLoc.y);
+ }
+
+
}
}
}
diff --git a/platform/android/example/mupdf/src/main/java/com/artifex/mupdf/android/DocViewBase.java b/platform/android/example/mupdf/src/main/java/com/artifex/mupdf/android/DocViewBase.java
index 23f60026..bb9d422d 100755
--- a/platform/android/example/mupdf/src/main/java/com/artifex/mupdf/android/DocViewBase.java
+++ b/platform/android/example/mupdf/src/main/java/com/artifex/mupdf/android/DocViewBase.java
@@ -45,7 +45,7 @@ public class DocViewBase
// bitmaps for rendering
// these are created by the activity and set using setBitmaps()
- private final static double OVERSIZE_FACTOR = 1.3;
+ private final static double OVERSIZE_FACTOR = 1.4;
private final Bitmap[] bitmaps = {null, null};
private int bitmapIndex = 0;