summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTor Andersson <tor.andersson@artifex.com>2018-06-18 16:55:30 +0200
committerRobin Watts <robin.watts@artifex.com>2018-06-22 16:48:50 +0100
commit66a23e616670fe19e966c833ac4c0db5edf57c7c (patch)
treeb682ae17bbc253c13a36b70100d4c548d1f7ac61
parenta69f71e89bc9c325bc91fc0ec69f3ca231c83efe (diff)
downloadmupdf-66a23e616670fe19e966c833ac4c0db5edf57c7c.tar.xz
Use fz_quad type in structured text and selection/highlighting.
-rw-r--r--include/mupdf/fitz/structured-text.h10
-rw-r--r--include/mupdf/fitz/util.h6
-rw-r--r--include/mupdf/pdf/annot.h2
-rw-r--r--platform/gl/gl-annotate.c13
-rw-r--r--platform/gl/gl-main.c33
-rw-r--r--platform/java/mupdf_native.c76
-rw-r--r--platform/java/mupdf_native.h15
-rw-r--r--platform/java/src/com/artifex/mupdf/fitz/Quad.java74
-rw-r--r--platform/java/src/com/artifex/mupdf/fitz/StructuredText.java6
-rw-r--r--platform/x11/pdfapp.c5
-rw-r--r--platform/x11/pdfapp.h2
-rw-r--r--source/fitz/stext-device.c23
-rw-r--r--source/fitz/stext-output.c8
-rw-r--r--source/fitz/stext-search.c107
-rw-r--r--source/fitz/util.c6
-rw-r--r--source/pdf/pdf-annot.c20
-rw-r--r--source/tools/murun.c29
17 files changed, 267 insertions, 168 deletions
diff --git a/include/mupdf/fitz/structured-text.h b/include/mupdf/fitz/structured-text.h
index 0ad6cd3c..44219f4d 100644
--- a/include/mupdf/fitz/structured-text.h
+++ b/include/mupdf/fitz/structured-text.h
@@ -95,7 +95,7 @@ struct fz_stext_char_s
{
int c;
fz_point origin;
- fz_rect bbox;
+ fz_quad quad;
float size;
fz_font *font;
fz_stext_char *next;
@@ -141,16 +141,16 @@ void fz_print_stext_page_as_text(fz_context *ctx, fz_output *out, fz_stext_page
/*
fz_search_stext_page: Search for occurrence of 'needle' in text page.
- Return the number of hits and store hit bboxes in the passed in array.
+ Return the number of hits and store hit quads in the passed in array.
NOTE: This is an experimental interface and subject to change without notice.
*/
-int fz_search_stext_page(fz_context *ctx, fz_stext_page *text, const char *needle, fz_rect *hit_bbox, int hit_max);
+int fz_search_stext_page(fz_context *ctx, fz_stext_page *text, const char *needle, fz_quad *quads, int max_quads);
/*
- fz_highlight_selection: Return a list of rectangles to highlight lines inside the selection points.
+ fz_highlight_selection: Return a list of quads to highlight lines inside the selection points.
*/
-int fz_highlight_selection(fz_context *ctx, fz_stext_page *page, fz_point a, fz_point b, fz_rect *hit_bbox, int hit_max);
+int fz_highlight_selection(fz_context *ctx, fz_stext_page *page, fz_point a, fz_point b, fz_quad *quads, int max_quads);
/*
fz_copy_selection: Return a newly allocated UTF-8 string with the text for a given selection.
diff --git a/include/mupdf/fitz/util.h b/include/mupdf/fitz/util.h
index 49409cbb..05119fd5 100644
--- a/include/mupdf/fitz/util.h
+++ b/include/mupdf/fitz/util.h
@@ -55,9 +55,9 @@ fz_buffer *fz_new_buffer_from_display_list(fz_context *ctx, fz_display_list *lis
Record the hits in the hit_bbox array and return the number of hits.
Will stop looking once it has filled hit_max rectangles.
*/
-int fz_search_page(fz_context *ctx, fz_page *page, const char *needle, fz_rect *hit_bbox, int hit_max);
-int fz_search_page_number(fz_context *ctx, fz_document *doc, int number, const char *needle, fz_rect *hit_bbox, int hit_max);
-int fz_search_display_list(fz_context *ctx, fz_display_list *list, const char *needle, fz_rect *hit_bbox, int hit_max);
+int fz_search_page(fz_context *ctx, fz_page *page, const char *needle, fz_quad *hit_bbox, int hit_max);
+int fz_search_page_number(fz_context *ctx, fz_document *doc, int number, const char *needle, fz_quad *hit_bbox, int hit_max);
+int fz_search_display_list(fz_context *ctx, fz_display_list *list, const char *needle, fz_quad *hit_bbox, int hit_max);
/*
Parse an SVG document into a display-list.
diff --git a/include/mupdf/pdf/annot.h b/include/mupdf/pdf/annot.h
index d616436c..869678c0 100644
--- a/include/mupdf/pdf/annot.h
+++ b/include/mupdf/pdf/annot.h
@@ -184,7 +184,7 @@ void pdf_set_annot_quadding(fz_context *ctx, pdf_annot *annot, int q);
void pdf_set_annot_quad_points(fz_context *ctx, pdf_annot *annot, int n, const float *v);
void pdf_clear_annot_quad_points(fz_context *ctx, pdf_annot *annot);
-void pdf_add_annot_quad_point(fz_context *ctx, pdf_annot *annot, fz_rect bbox);
+void pdf_add_annot_quad_point(fz_context *ctx, pdf_annot *annot, fz_quad quad);
void pdf_set_annot_ink_list(fz_context *ctx, pdf_annot *annot, int n, const int *count, const fz_point *v);
void pdf_clear_annot_ink_list(fz_context *ctx, pdf_annot *annot);
diff --git a/platform/gl/gl-annotate.c b/platform/gl/gl-annotate.c
index 9d88dabc..873612c7 100644
--- a/platform/gl/gl-annotate.c
+++ b/platform/gl/gl-annotate.c
@@ -1040,7 +1040,7 @@ static void do_edit_quad_points(void)
{
static fz_point pt = { 0, 0 };
static int marking = 0;
- fz_rect hits[1000];
+ fz_quad hits[1000];
int i, n;
if (ui_mouse_inside(&view_page_area))
@@ -1071,12 +1071,17 @@ static void do_edit_quad_points(void)
glEnable(GL_BLEND);
glColor4f(1, 1, 1, 1);
+ glBegin(GL_QUADS);
for (i = 0; i < n; ++i)
{
- fz_rect thit = hits[i];
- fz_transform_rect(&thit, &view_page_ctm);
- glRectf(thit.x0, thit.y0, thit.x1 + 1, thit.y1 + 1);
+ fz_quad thit = hits[i];
+ fz_transform_quad(&thit, &view_page_ctm);
+ glVertex2f(thit.ul.x, thit.ul.y);
+ glVertex2f(thit.ur.x, thit.ur.y);
+ glVertex2f(thit.lr.x, thit.lr.y);
+ glVertex2f(thit.ll.x, thit.ll.y);
}
+ glEnd();
glDisable(GL_BLEND);
diff --git a/platform/gl/gl-main.c b/platform/gl/gl-main.c
index ce63c4d2..726de1c0 100644
--- a/platform/gl/gl-main.c
+++ b/platform/gl/gl-main.c
@@ -142,7 +142,7 @@ static int search_dir = 1;
static int search_page = -1;
static int search_hit_page = -1;
static int search_hit_count = 0;
-static fz_rect search_hit_bbox[5000];
+static fz_quad search_hit_quads[5000];
static char error_message[256];
static void error_dialog(void)
@@ -467,7 +467,7 @@ static void do_links(fz_link *link)
static void do_page_selection(void)
{
static fz_point pt = { 0, 0 };
- fz_rect hits[1000];
+ fz_quad hits[1000];
int i, n;
if (ui_mouse_inside(&view_page_area))
@@ -495,11 +495,17 @@ static void do_page_selection(void)
glEnable(GL_BLEND);
glColor4f(1, 1, 1, 1);
+ glBegin(GL_QUADS);
for (i = 0; i < n; ++i)
{
- fz_transform_rect(&hits[i], &view_page_ctm);
- glRectf(hits[i].x0, hits[i].y0, hits[i].x1 + 1, hits[i].y1 + 1);
+ fz_quad thit = hits[i];
+ fz_transform_quad(&thit, &view_page_ctm);
+ glVertex2f(thit.ul.x, thit.ul.y);
+ glVertex2f(thit.ur.x, thit.ur.y);
+ glVertex2f(thit.lr.x, thit.lr.y);
+ glVertex2f(thit.ll.x, thit.ll.y);
}
+ glEnd();
glDisable(GL_BLEND);
@@ -519,23 +525,24 @@ static void do_page_selection(void)
static void do_search_hits(void)
{
- fz_rect bounds;
- fz_irect area;
int i;
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
+ glColor4f(1, 0, 0, 0.4f);
+ glBegin(GL_QUADS);
for (i = 0; i < search_hit_count; ++i)
{
- bounds = search_hit_bbox[i];
- fz_transform_rect(&bounds, &view_page_ctm);
- fz_irect_from_rect(&area, &bounds);
-
- glColor4f(1, 0, 0, 0.4f);
- glRectf(area.x0, area.y0, area.x1, area.y1);
+ fz_quad thit = search_hit_quads[i];
+ fz_transform_quad(&thit, &view_page_ctm);
+ glVertex2f(thit.ul.x, thit.ul.y);
+ glVertex2f(thit.ur.x, thit.ur.y);
+ glVertex2f(thit.lr.x, thit.lr.y);
+ glVertex2f(thit.ll.x, thit.ll.y);
}
+ glEnd();
glDisable(GL_BLEND);
}
@@ -1192,7 +1199,7 @@ void do_main(void)
while (glutGet(GLUT_ELAPSED_TIME) < start_time + 200)
{
search_hit_count = fz_search_page_number(ctx, doc, search_page, search_needle,
- search_hit_bbox, nelem(search_hit_bbox));
+ search_hit_quads, nelem(search_hit_quads));
if (search_hit_count)
{
search_active = 0;
diff --git a/platform/java/mupdf_native.c b/platform/java/mupdf_native.c
index 8e9e9f3f..5a1b0cb7 100644
--- a/platform/java/mupdf_native.c
+++ b/platform/java/mupdf_native.c
@@ -86,6 +86,7 @@ static jclass cls_Path;
static jclass cls_PathWalker;
static jclass cls_Pixmap;
static jclass cls_Point;
+static jclass cls_Quad;
static jclass cls_Rect;
static jclass cls_RuntimeException;
static jclass cls_SeekableInputStream;
@@ -133,6 +134,14 @@ static jfieldID fid_Path_pointer;
static jfieldID fid_Pixmap_pointer;
static jfieldID fid_Point_x;
static jfieldID fid_Point_y;
+static jfieldID fid_Quad_ul_x;
+static jfieldID fid_Quad_ul_y;
+static jfieldID fid_Quad_ur_x;
+static jfieldID fid_Quad_ur_y;
+static jfieldID fid_Quad_ll_x;
+static jfieldID fid_Quad_ll_y;
+static jfieldID fid_Quad_lr_x;
+static jfieldID fid_Quad_lr_y;
static jfieldID fid_Rect_x0;
static jfieldID fid_Rect_x1;
static jfieldID fid_Rect_y0;
@@ -142,7 +151,7 @@ static jfieldID fid_StrokeState_pointer;
static jfieldID fid_StructuredText_pointer;
static jfieldID fid_TextBlock_bbox;
static jfieldID fid_TextBlock_lines;
-static jfieldID fid_TextChar_bbox;
+static jfieldID fid_TextChar_quad;
static jfieldID fid_TextChar_c;
static jfieldID fid_TextLine_bbox;
static jfieldID fid_TextLine_chars;
@@ -195,6 +204,7 @@ static jmethodID mid_PathWalker_moveTo;
static jmethodID mid_Path_init;
static jmethodID mid_Pixmap_init;
static jmethodID mid_Point_init;
+static jmethodID mid_Quad_init;
static jmethodID mid_Rect_init;
static jmethodID mid_SeekableInputStream_read;
static jmethodID mid_SeekableOutputStream_write;
@@ -556,6 +566,17 @@ static int find_fids(JNIEnv *env)
fid_Point_x = get_field(&err, env, "x", "F");
fid_Point_y = get_field(&err, env, "y", "F");
+ cls_Quad = get_class(&err, env, PKG"Quad");
+ fid_Quad_ul_x = get_field(&err, env, "ul_x", "F");
+ fid_Quad_ul_y = get_field(&err, env, "ul_y", "F");
+ fid_Quad_ur_x = get_field(&err, env, "ur_x", "F");
+ fid_Quad_ur_y = get_field(&err, env, "ur_y", "F");
+ fid_Quad_ll_x = get_field(&err, env, "ll_x", "F");
+ fid_Quad_ll_y = get_field(&err, env, "ll_y", "F");
+ fid_Quad_lr_x = get_field(&err, env, "lr_x", "F");
+ fid_Quad_lr_y = get_field(&err, env, "lr_y", "F");
+ mid_Quad_init = get_method(&err, env, "<init>", "(FFFFFFFF)V");
+
cls_Rect = get_class(&err, env, PKG"Rect");
fid_Rect_x0 = get_field(&err, env, "x0", "F");
fid_Rect_x1 = get_field(&err, env, "x1", "F");
@@ -596,7 +617,7 @@ static int find_fids(JNIEnv *env)
cls_TextChar = get_class(&err, env, PKG"StructuredText$TextChar");
mid_TextChar_init = get_method(&err, env, "<init>", "(L"PKG"StructuredText;)V");
- fid_TextChar_bbox = get_field(&err, env, "bbox", "L"PKG"Rect;");
+ fid_TextChar_quad = get_field(&err, env, "bbox", "L"PKG"Quad;");
fid_TextChar_c = get_field(&err, env, "c", "I");
cls_TextLine = get_class(&err, env, PKG"StructuredText$TextLine");
@@ -702,6 +723,7 @@ static void lose_fids(JNIEnv *env)
(*env)->DeleteGlobalRef(env, cls_PDFObject);
(*env)->DeleteGlobalRef(env, cls_Pixmap);
(*env)->DeleteGlobalRef(env, cls_Point);
+ (*env)->DeleteGlobalRef(env, cls_Quad);
(*env)->DeleteGlobalRef(env, cls_Rect);
(*env)->DeleteGlobalRef(env, cls_RuntimeException);
(*env)->DeleteGlobalRef(env, cls_SeekableStream);
@@ -1447,25 +1469,36 @@ static inline jobject to_Rect_safe(fz_context *ctx, JNIEnv *env, const fz_rect *
return (*env)->NewObject(env, cls_Rect, mid_Rect_init, rect->x0, rect->y0, rect->x1, rect->y1);
}
-static inline jobjectArray to_jRectArray_safe(fz_context *ctx, JNIEnv *env, const fz_rect *rects, jint n)
+static inline jobject to_Quad_safe(fz_context *ctx, JNIEnv *env, const fz_quad *quad)
+{
+ if (!ctx || !quad) return NULL;
+
+ return (*env)->NewObject(env, cls_Quad, mid_Quad_init,
+ quad->ul.x, quad->ul.y,
+ quad->ur.x, quad->ur.y,
+ quad->ll.x, quad->ll.y,
+ quad->lr.x, quad->lr.y);
+}
+
+static inline jobjectArray to_jQuadArray_safe(fz_context *ctx, JNIEnv *env, const fz_quad *quads, jint n)
{
jobjectArray arr;
int i;
- if (!ctx || !rects) return NULL;
+ if (!ctx || !quads) return NULL;
- arr = (*env)->NewObjectArray(env, n, cls_Rect, NULL);
+ arr = (*env)->NewObjectArray(env, n, cls_Quad, NULL);
if (!arr) return NULL;
for (i = 0; i < n; i++)
{
- jobject jrect = to_Rect_safe(ctx, env, &rects[i]);
- if (!jrect) return NULL;
+ jobject jquad = to_Quad_safe(ctx, env, &quads[i]);
+ if (!jquad) return NULL;
- (*env)->SetObjectArrayElement(env, arr, i, jrect);
+ (*env)->SetObjectArrayElement(env, arr, i, jquad);
if ((*env)->ExceptionCheck(env)) return NULL;
- (*env)->DeleteLocalRef(env, jrect);
+ (*env)->DeleteLocalRef(env, jquad);
}
return arr;
@@ -5554,7 +5587,7 @@ FUN(Page_search)(JNIEnv *env, jobject self, jstring jneedle)
{
fz_context *ctx = get_context(env);
fz_page *page = from_Page(env, self);
- fz_rect hits[256];
+ fz_quad hits[256];
const char *needle = NULL;
int n = 0;
@@ -5574,7 +5607,7 @@ FUN(Page_search)(JNIEnv *env, jobject self, jstring jneedle)
return NULL;
}
- return to_jRectArray_safe(ctx, env, hits, n);
+ return to_jQuadArray_safe(ctx, env, hits, n);
}
JNIEXPORT jobject JNICALL
@@ -5872,7 +5905,7 @@ FUN(DisplayList_search)(JNIEnv *env, jobject self, jstring jneedle)
{
fz_context *ctx = get_context(env);
fz_display_list *list = from_DisplayList(env, self);
- fz_rect hits[256];
+ fz_quad hits[256];
const char *needle = NULL;
int n = 0;
@@ -5892,7 +5925,7 @@ FUN(DisplayList_search)(JNIEnv *env, jobject self, jstring jneedle)
return NULL;
}
- return to_jRectArray_safe(ctx, env, hits, n);
+ return to_jQuadArray_safe(ctx, env, hits, n);
}
/* Buffer interface */
@@ -6359,7 +6392,7 @@ FUN(StructuredText_search)(JNIEnv *env, jobject self, jstring jneedle)
{
fz_context *ctx = get_context(env);
fz_stext_page *text = from_StructuredText(env, self);
- fz_rect hits[256];
+ fz_quad hits[256];
const char *needle = NULL;
int n = 0;
@@ -6379,7 +6412,7 @@ FUN(StructuredText_search)(JNIEnv *env, jobject self, jstring jneedle)
return NULL;
}
- return to_jRectArray_safe(ctx, env, hits, n);
+ return to_jQuadArray_safe(ctx, env, hits, n);
}
JNIEXPORT jobject JNICALL
@@ -6389,7 +6422,7 @@ FUN(StructuredText_highlight)(JNIEnv *env, jobject self, jobject jpt1, jobject j
fz_stext_page *text = from_StructuredText(env, self);
fz_point pt1 = from_Point(env, jpt1);
fz_point pt2 = from_Point(env, jpt2);
- fz_rect hits[1000];
+ fz_quad hits[1000];
int n = 0;
if (!ctx || !text) return NULL;
@@ -6402,7 +6435,7 @@ FUN(StructuredText_highlight)(JNIEnv *env, jobject self, jobject jpt1, jobject j
return NULL;
}
- return to_jRectArray_safe(ctx, env, hits, n);
+ return to_jQuadArray_safe(ctx, env, hits, n);
}
JNIEXPORT jobject JNICALL
@@ -6443,6 +6476,7 @@ FUN(StructuredText_getBlocks)(JNIEnv *env, jobject self)
jobject larr = NULL;
jobject carr = NULL;
jobject jrect = NULL;
+ jobject jquad = NULL;
int len;
int b;
@@ -6522,11 +6556,11 @@ FUN(StructuredText_getBlocks)(JNIEnv *env, jobject self)
if (!jchar) return NULL;
/* set the char's bbox */
- jrect = to_Rect_safe(ctx, env, &(ch->bbox));
- if (!jrect) return NULL;
+ jquad = to_Quad_safe(ctx, env, &ch->quad);
+ if (!jquad) return NULL;
- (*env)->SetObjectField(env, jchar, fid_TextChar_bbox, jrect);
- (*env)->DeleteLocalRef(env, jrect);
+ (*env)->SetObjectField(env, jchar, fid_TextChar_quad, jquad);
+ (*env)->DeleteLocalRef(env, jquad);
/* set the char's value */
(*env)->SetIntField(env, jchar, fid_TextChar_c, ch->c);
diff --git a/platform/java/mupdf_native.h b/platform/java/mupdf_native.h
index 1813aa18..3f223a13 100644
--- a/platform/java/mupdf_native.h
+++ b/platform/java/mupdf_native.h
@@ -2896,6 +2896,17 @@ extern "C" {
}
#endif
#endif
+/* Header for class com_artifex_mupdf_fitz_Quad */
+
+#ifndef _Included_com_artifex_mupdf_fitz_Quad
+#define _Included_com_artifex_mupdf_fitz_Quad
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
/* Header for class com_artifex_mupdf_fitz_Rect */
#ifndef _Included_com_artifex_mupdf_fitz_Rect
@@ -3185,7 +3196,7 @@ JNIEXPORT void JNICALL Java_com_artifex_mupdf_fitz_StructuredText_finalize
/*
* Class: com_artifex_mupdf_fitz_StructuredText
* Method: search
- * Signature: (Ljava/lang/String;)[Lcom/artifex/mupdf/fitz/Rect;
+ * Signature: (Ljava/lang/String;)[Lcom/artifex/mupdf/fitz/Quad;
*/
JNIEXPORT jobjectArray JNICALL Java_com_artifex_mupdf_fitz_StructuredText_search
(JNIEnv *, jobject, jstring);
@@ -3193,7 +3204,7 @@ JNIEXPORT jobjectArray JNICALL Java_com_artifex_mupdf_fitz_StructuredText_search
/*
* Class: com_artifex_mupdf_fitz_StructuredText
* Method: highlight
- * Signature: (Lcom/artifex/mupdf/fitz/Point;Lcom/artifex/mupdf/fitz/Point;)[Lcom/artifex/mupdf/fitz/Rect;
+ * Signature: (Lcom/artifex/mupdf/fitz/Point;Lcom/artifex/mupdf/fitz/Point;)[Lcom/artifex/mupdf/fitz/Quad;
*/
JNIEXPORT jobjectArray JNICALL Java_com_artifex_mupdf_fitz_StructuredText_highlight
(JNIEnv *, jobject, jobject, jobject);
diff --git a/platform/java/src/com/artifex/mupdf/fitz/Quad.java b/platform/java/src/com/artifex/mupdf/fitz/Quad.java
new file mode 100644
index 00000000..6e69a7b1
--- /dev/null
+++ b/platform/java/src/com/artifex/mupdf/fitz/Quad.java
@@ -0,0 +1,74 @@
+package com.artifex.mupdf.fitz;
+
+public class Quad
+{
+ public float ul_x, ul_y;
+ public float ur_x, ur_y;
+ public float ll_x, ll_y;
+ public float lr_x, lr_y;
+
+ public Quad(float ul_x, float ul_y, float ur_x, float ur_y, float ll_x, float ll_y, float lr_x, float lr_y) {
+ this.ul_x = ul_x;
+ this.ul_y = ul_y;
+ this.ur_x = ur_x;
+ this.ur_y = ur_y;
+ this.ll_x = ll_x;
+ this.ll_y = ll_y;
+ this.lr_x = lr_x;
+ this.lr_y = lr_y;
+ }
+
+ public Rect toRect() {
+ float x0 = Math.min(Math.min(ul_x, ur_x), Math.min(ll_x, lr_x));
+ float y0 = Math.min(Math.min(ul_y, ur_y), Math.min(ll_y, lr_y));
+ float x1 = Math.max(Math.max(ul_x, ur_x), Math.max(ll_x, lr_x));
+ float y1 = Math.max(Math.max(ul_y, ur_y), Math.max(ll_y, lr_y));
+ return new Rect(x0, y0, x1, y1);
+ }
+
+ public Quad transformed(Matrix m) {
+ float t_ul_x = ul_x * m.a + ul_y * m.c + m.e;
+ float t_ul_y = ul_x * m.b + ul_y * m.d + m.f;
+ float t_ur_x = ur_x * m.a + ur_y * m.c + m.e;
+ float t_ur_y = ur_x * m.b + ur_y * m.d + m.f;
+ float t_ll_x = ll_x * m.a + ll_y * m.c + m.e;
+ float t_ll_y = ll_x * m.b + ll_y * m.d + m.f;
+ float t_lr_x = lr_x * m.a + lr_y * m.c + m.e;
+ float t_lr_y = lr_x * m.b + lr_y * m.d + m.f;
+ return new Quad(
+ t_ul_x, t_ul_y,
+ t_ur_x, t_ur_y,
+ t_ll_x, t_ll_y,
+ t_lr_x, t_lr_y
+ );
+ }
+
+ public Quad transform(Matrix m) {
+ float t_ul_x = ul_x * m.a + ul_y * m.c + m.e;
+ float t_ul_y = ul_x * m.b + ul_y * m.d + m.f;
+ float t_ur_x = ur_x * m.a + ur_y * m.c + m.e;
+ float t_ur_y = ur_x * m.b + ur_y * m.d + m.f;
+ float t_ll_x = ll_x * m.a + ll_y * m.c + m.e;
+ float t_ll_y = ll_x * m.b + ll_y * m.d + m.f;
+ float t_lr_x = lr_x * m.a + lr_y * m.c + m.e;
+ float t_lr_y = lr_x * m.b + lr_y * m.d + m.f;
+ ul_x = t_ul_x;
+ ul_y = t_ul_y;
+ ur_x = t_ur_x;
+ ur_y = t_ur_y;
+ ll_x = t_ll_x;
+ ll_y = t_ll_y;
+ lr_x = t_lr_x;
+ lr_y = t_lr_y;
+ return this;
+ }
+
+ public String toString() {
+ return "["
+ + ul_x + " " + ul_y + " "
+ + ur_x + " " + ur_y + " "
+ + ll_x + " " + ll_y + " "
+ + lr_x + " " + lr_y
+ + "]";
+ }
+}
diff --git a/platform/java/src/com/artifex/mupdf/fitz/StructuredText.java b/platform/java/src/com/artifex/mupdf/fitz/StructuredText.java
index 12ec5be3..82aa55ea 100644
--- a/platform/java/src/com/artifex/mupdf/fitz/StructuredText.java
+++ b/platform/java/src/com/artifex/mupdf/fitz/StructuredText.java
@@ -19,8 +19,8 @@ public class StructuredText
pointer = p;
}
- public native Rect[] search(String needle);
- public native Rect[] highlight(Point a, Point b);
+ public native Quad[] search(String needle);
+ public native Quad[] highlight(Point a, Point b);
public native String copy(Point a, Point b);
public native TextBlock[] getBlocks();
@@ -37,7 +37,7 @@ public class StructuredText
public class TextChar {
public int c;
- public Rect bbox;
+ public Quad quad;
public boolean isWhitespace() {
return Character.isWhitespace(c);
}
diff --git a/platform/x11/pdfapp.c b/platform/x11/pdfapp.c
index 1c5ae45d..17af3d0f 100644
--- a/platform/x11/pdfapp.c
+++ b/platform/x11/pdfapp.c
@@ -1050,7 +1050,7 @@ void pdfapp_inverthit(pdfapp_t *app)
for (i = 0; i < app->hit_count; i++)
{
- bbox = app->hit_bbox[i];
+ bbox = fz_rect_from_quad(app->hit_bbox[i]);
pdfapp_invert(app, fz_transform_rect(&bbox, &ctm));
}
}
@@ -1938,10 +1938,11 @@ void pdfapp_oncopy(pdfapp_t *app, unsigned short *ucsbuf, int ucslen)
int saw_text = 0;
for (ch = line->first_char; ch; ch = ch->next)
{
+ fz_rect bbox = fz_rect_from_quad(ch->quad);
int c = ch->c;
if (c < 32)
c = 0xFFFD;
- if (ch->bbox.x1 >= sel.x0 && ch->bbox.x0 <= sel.x1 && ch->bbox.y1 >= sel.y0 && ch->bbox.y0 <= sel.y1)
+ if (bbox.x1 >= sel.x0 && bbox.x0 <= sel.x1 && bbox.y1 >= sel.y0 && bbox.y0 <= sel.y1)
{
saw_text = 1;
if (need_newline)
diff --git a/platform/x11/pdfapp.h b/platform/x11/pdfapp.h
index b6c2127c..0315bfd0 100644
--- a/platform/x11/pdfapp.h
+++ b/platform/x11/pdfapp.h
@@ -131,7 +131,7 @@ struct pdfapp_s
int searchdir;
char search[512];
int searchpage;
- fz_rect hit_bbox[512];
+ fz_quad hit_bbox[512];
int hit_count;
/* client context storage */
diff --git a/source/fitz/stext-device.c b/source/fitz/stext-device.c
index 40b203b3..ffff886a 100644
--- a/source/fitz/stext-device.c
+++ b/source/fitz/stext-device.c
@@ -124,16 +124,6 @@ add_line_to_block(fz_context *ctx, fz_stext_page *page, fz_stext_block *block, c
return line;
}
-static float min4(float a, float b, float c, float d)
-{
- return fz_min(fz_min(a, b), fz_min(c, d));
-}
-
-static float max4(float a, float b, float c, float d)
-{
- return fz_max(fz_max(a, b), fz_max(c, d));
-}
-
static fz_stext_char *
add_char_to_line(fz_context *ctx, fz_stext_page *page, fz_stext_line *line, const fz_matrix *trm, fz_font *font, float size, int c, fz_point *p, fz_point *q)
{
@@ -171,10 +161,10 @@ add_char_to_line(fz_context *ctx, fz_stext_page *page, fz_stext_line *line, cons
fz_transform_vector(&a, trm);
fz_transform_vector(&d, trm);
- ch->bbox.x0 = min4(p->x + a.x, q->x + a.x, p->x + d.x, q->x + d.x);
- ch->bbox.x1 = max4(p->x + a.x, q->x + a.x, p->x + d.x, q->x + d.x);
- ch->bbox.y0 = min4(p->y + a.y, q->y + a.y, p->y + d.y, q->y + d.y);
- ch->bbox.y1 = max4(p->y + a.y, q->y + a.y, p->y + d.y, q->y + d.y);
+ ch->quad.ll = fz_make_point(p->x + d.x, p->y + d.y);
+ ch->quad.ul = fz_make_point(p->x + a.x, p->y + a.y);
+ ch->quad.lr = fz_make_point(q->x + d.x, q->y + d.y);
+ ch->quad.ur = fz_make_point(q->x + a.x, q->y + a.y);
return ch;
}
@@ -648,7 +638,10 @@ fz_stext_close_device(fz_context *ctx, fz_device *dev)
for (line = block->u.t.first_line; line; line = line->next)
{
for (ch = line->first_char; ch; ch = ch->next)
- fz_union_rect(&line->bbox, &ch->bbox);
+ {
+ fz_rect bbox = fz_rect_from_quad(ch->quad);
+ fz_union_rect(&line->bbox, &bbox);
+ }
fz_union_rect(&block->bbox, &line->bbox);
}
}
diff --git a/source/fitz/stext-output.c b/source/fitz/stext-output.c
index 492885cb..66433489 100644
--- a/source/fitz/stext-output.c
+++ b/source/fitz/stext-output.c
@@ -364,8 +364,12 @@ fz_print_stext_page_as_xml(fz_context *ctx, fz_output *out, fz_stext_page *page)
name = font_full_name(ctx, font);
fz_write_printf(ctx, out, "<font name=\"%s\" size=\"%g\">\n", name, size);
}
- fz_write_printf(ctx, out, "<char bbox=\"%g %g %g %g\" x=\"%g\" y=\"%g\" c=\"",
- ch->bbox.x0, ch->bbox.y0, ch->bbox.x1, ch->bbox.y1, ch->origin.x, ch->origin.y);
+ fz_write_printf(ctx, out, "<char quad=\"%g %g %g %g %g %g %g %g\" x=\"%g\" y=\"%g\" c=\"",
+ ch->quad.ul.x, ch->quad.ul.y,
+ ch->quad.ur.x, ch->quad.ur.y,
+ ch->quad.ll.x, ch->quad.ll.y,
+ ch->quad.lr.x, ch->quad.lr.y,
+ ch->origin.x, ch->origin.y);
switch (ch->c)
{
case '<': fz_write_string(ctx, out, "&lt;"); break;
diff --git a/source/fitz/stext-search.c b/source/fitz/stext-search.c
index b73296e3..0805d3dc 100644
--- a/source/fitz/stext-search.c
+++ b/source/fitz/stext-search.c
@@ -11,6 +11,20 @@ static float dist2(float a, float b)
return a * a + b * b;
}
+static float hdist(fz_point *dir, fz_point *a, fz_point *b)
+{
+ float dx = b->x - a->x;
+ float dy = b->y - a->y;
+ return fz_abs(dx * dir->x + dy * dir->y);
+}
+
+static float vdist(fz_point *dir, fz_point *a, fz_point *b)
+{
+ float dx = b->x - a->x;
+ float dy = b->y - a->y;
+ return fz_abs(dx * dir->y + dy * dir->x);
+}
+
static int line_length(fz_stext_line *line)
{
fz_stext_char *ch;
@@ -43,8 +57,8 @@ static int find_closest_in_line(fz_stext_line *line, int idx, fz_point p)
for (ch = line->first_char; ch; ch = ch->next)
{
- float mid_x = (ch->bbox.x0 + ch->bbox.x1) / 2;
- float mid_y = (ch->bbox.y0 + ch->bbox.y1) / 2;
+ float mid_x = (ch->quad.ul.x + ch->quad.ur.x + ch->quad.ll.x + ch->quad.lr.x) / 4;
+ float mid_y = (ch->quad.ul.y + ch->quad.ur.y + ch->quad.ll.y + ch->quad.lr.y) / 4;
float this_dist = dist2(p.x - mid_x, p.y - mid_y);
if (this_dist < closest_dist)
{
@@ -171,7 +185,7 @@ fz_enumerate_selection(fz_context *ctx, fz_stext_page *page, fz_point a, fz_poin
struct highlight
{
int len, cap;
- fz_rect *box;
+ fz_quad *box;
float hfuzz, vfuzz;
};
@@ -180,80 +194,23 @@ static void on_highlight_char(fz_context *ctx, void *arg, fz_stext_line *line, f
struct highlight *hits = arg;
float vfuzz = ch->size * hits->vfuzz;
float hfuzz = ch->size * hits->hfuzz;
- fz_rect bbox;
-
- if (line->dir.x > line->dir.y)
- {
- bbox.x0 = ch->bbox.x0;
- bbox.x1 = ch->bbox.x1;
- bbox.y0 = line->bbox.y0;
- bbox.y1 = line->bbox.y1;
- }
- else
- {
- bbox.x0 = line->bbox.x0;
- bbox.x1 = line->bbox.x1;
- bbox.y0 = ch->bbox.y0;
- bbox.y1 = ch->bbox.y1;
- }
if (hits->len > 0)
{
- fz_rect *end = &hits->box[hits->len-1];
- if (fz_abs(bbox.y0 - end->y0) < vfuzz && fz_abs(bbox.y1 - end->y1) < vfuzz)
+ fz_quad *end = &hits->box[hits->len-1];
+ if (hdist(&line->dir, &end->lr, &ch->quad.ll) < hfuzz
+ && vdist(&line->dir, &end->lr, &ch->quad.ll) < vfuzz
+ && hdist(&line->dir, &end->ur, &ch->quad.ul) < hfuzz
+ && vdist(&line->dir, &end->ur, &ch->quad.ul) < vfuzz)
{
- if (bbox.x1 < end->x0)
- {
- if (end->x0 - bbox.x1 < hfuzz)
- {
- end->x0 = bbox.x0;
- return;
- }
- }
- else if (bbox.x0 > end->x1)
- {
- if (bbox.x0 - end->x1 < hfuzz)
- {
- end->x1 = bbox.x1;
- return;
- }
- }
- else
- {
- end->x0 = fz_min(bbox.x0, end->x0);
- end->x1 = fz_max(bbox.x1, end->x1);
- return;
- }
- }
- if (fz_abs(bbox.x0 - end->x0) < vfuzz && fz_abs(bbox.x1 - end->x1) < vfuzz)
- {
- if (bbox.y1 < end->y0)
- {
- if (end->y0 - bbox.y1 < hfuzz)
- {
- end->y0 = bbox.y0;
- return;
- }
- }
- else if (bbox.y0 > end->y1)
- {
- if (bbox.y0 - end->y1 < hfuzz)
- {
- end->y1 = bbox.y1;
- return;
- }
- }
- else
- {
- end->y0 = fz_min(bbox.y0, end->y0);
- end->y1 = fz_max(bbox.y1, end->y1);
- return;
- }
+ end->ur = ch->quad.ur;
+ end->lr = ch->quad.lr;
+ return;
}
}
if (hits->len < hits->cap)
- hits->box[hits->len++] = bbox;
+ hits->box[hits->len++] = ch->quad;
}
static void on_highlight_line(fz_context *ctx, void *arg, fz_stext_line *line)
@@ -261,14 +218,14 @@ static void on_highlight_line(fz_context *ctx, void *arg, fz_stext_line *line)
}
int
-fz_highlight_selection(fz_context *ctx, fz_stext_page *page, fz_point a, fz_point b, fz_rect *hit_bbox, int hit_max)
+fz_highlight_selection(fz_context *ctx, fz_stext_page *page, fz_point a, fz_point b, fz_quad *quads, int max_quads)
{
struct callbacks cb;
struct highlight hits;
hits.len = 0;
- hits.cap = hit_max;
- hits.box = hit_bbox;
+ hits.cap = max_quads;
+ hits.box = quads;
hits.hfuzz = 0.5f;
hits.vfuzz = 0.1f;
@@ -387,7 +344,7 @@ static const char *find_string(const char *s, const char *needle, const char **e
}
int
-fz_search_stext_page(fz_context *ctx, fz_stext_page *page, const char *needle, fz_rect *hit_bbox, int hit_max)
+fz_search_stext_page(fz_context *ctx, fz_stext_page *page, const char *needle, fz_quad *quads, int max_quads)
{
struct highlight hits;
fz_stext_block *block;
@@ -401,8 +358,8 @@ fz_search_stext_page(fz_context *ctx, fz_stext_page *page, const char *needle, f
return 0;
hits.len = 0;
- hits.cap = hit_max;
- hits.box = hit_bbox;
+ hits.cap = max_quads;
+ hits.box = quads;
hits.hfuzz = 0.1f;
hits.vfuzz = 0.1f;
diff --git a/source/fitz/util.c b/source/fitz/util.c
index 85ee1e45..0f935e53 100644
--- a/source/fitz/util.c
+++ b/source/fitz/util.c
@@ -343,7 +343,7 @@ fz_new_stext_page_from_page_number(fz_context *ctx, fz_document *doc, int number
}
int
-fz_search_display_list(fz_context *ctx, fz_display_list *list, const char *needle, fz_rect *hit_bbox, int hit_max)
+fz_search_display_list(fz_context *ctx, fz_display_list *list, const char *needle, fz_quad *hit_bbox, int hit_max)
{
fz_stext_page *text;
int count = 0;
@@ -359,7 +359,7 @@ fz_search_display_list(fz_context *ctx, fz_display_list *list, const char *needl
}
int
-fz_search_page(fz_context *ctx, fz_page *page, const char *needle, fz_rect *hit_bbox, int hit_max)
+fz_search_page(fz_context *ctx, fz_page *page, const char *needle, fz_quad *hit_bbox, int hit_max)
{
fz_stext_page *text;
int count = 0;
@@ -375,7 +375,7 @@ fz_search_page(fz_context *ctx, fz_page *page, const char *needle, fz_rect *hit_
}
int
-fz_search_page_number(fz_context *ctx, fz_document *doc, int number, const char *needle, fz_rect *hit_bbox, int hit_max)
+fz_search_page_number(fz_context *ctx, fz_document *doc, int number, const char *needle, fz_quad *hit_bbox, int hit_max)
{
fz_page *page;
int count = 0;
diff --git a/source/pdf/pdf-annot.c b/source/pdf/pdf-annot.c
index ba92b7ef..cf072c60 100644
--- a/source/pdf/pdf-annot.c
+++ b/source/pdf/pdf-annot.c
@@ -1058,7 +1058,7 @@ pdf_clear_annot_quad_points(fz_context *ctx, pdf_annot *annot)
}
void
-pdf_add_annot_quad_point(fz_context *ctx, pdf_annot *annot, fz_rect bbox)
+pdf_add_annot_quad_point(fz_context *ctx, pdf_annot *annot, fz_quad quad)
{
pdf_document *doc = annot->page->doc;
fz_matrix page_ctm, inv_page_ctm;
@@ -1080,15 +1080,15 @@ pdf_add_annot_quad_point(fz_context *ctx, pdf_annot *annot, fz_rect bbox)
* in a counterclockwise fashion. Experiments with Adobe's implementation
* indicates a cross-wise ordering is intended: ul, ur, ll, lr.
*/
- fz_transform_rect(&bbox, &inv_page_ctm);
- pdf_array_push_real(ctx, quad_points, bbox.x0); /* ul */
- pdf_array_push_real(ctx, quad_points, bbox.y1);
- pdf_array_push_real(ctx, quad_points, bbox.x1); /* ur */
- pdf_array_push_real(ctx, quad_points, bbox.y1);
- pdf_array_push_real(ctx, quad_points, bbox.x0); /* ll */
- pdf_array_push_real(ctx, quad_points, bbox.y0);
- pdf_array_push_real(ctx, quad_points, bbox.x1); /* lr */
- pdf_array_push_real(ctx, quad_points, bbox.y0);
+ fz_transform_quad(&quad, &inv_page_ctm);
+ pdf_array_push_real(ctx, quad_points, quad.ul.x);
+ pdf_array_push_real(ctx, quad_points, quad.ul.y);
+ pdf_array_push_real(ctx, quad_points, quad.ur.x);
+ pdf_array_push_real(ctx, quad_points, quad.ur.y);
+ pdf_array_push_real(ctx, quad_points, quad.ll.x);
+ pdf_array_push_real(ctx, quad_points, quad.ll.y);
+ pdf_array_push_real(ctx, quad_points, quad.lr.x);
+ pdf_array_push_real(ctx, quad_points, quad.lr.y);
pdf_dirty_annot(ctx, annot);
}
diff --git a/source/tools/murun.c b/source/tools/murun.c
index c74e4bbc..f7a890b2 100644
--- a/source/tools/murun.c
+++ b/source/tools/murun.c
@@ -489,6 +489,19 @@ static void ffi_pushrect(js_State *J, fz_rect rect)
js_pushnumber(J, rect.y1); js_setindex(J, -2, 3);
}
+static void ffi_pushquad(js_State *J, fz_quad quad)
+{
+ js_newarray(J);
+ js_pushnumber(J, quad.ul.x); js_setindex(J, -2, 0);
+ js_pushnumber(J, quad.ul.y); js_setindex(J, -2, 1);
+ js_pushnumber(J, quad.ur.x); js_setindex(J, -2, 0);
+ js_pushnumber(J, quad.ur.y); js_setindex(J, -2, 1);
+ js_pushnumber(J, quad.ll.x); js_setindex(J, -2, 0);
+ js_pushnumber(J, quad.ll.y); js_setindex(J, -2, 1);
+ js_pushnumber(J, quad.lr.x); js_setindex(J, -2, 0);
+ js_pushnumber(J, quad.lr.y); js_setindex(J, -2, 1);
+}
+
static fz_irect ffi_toirect(js_State *J, int idx)
{
fz_irect irect;
@@ -1922,7 +1935,7 @@ static void ffi_Page_search(js_State *J)
fz_context *ctx = js_getcontext(J);
fz_page *page = ffi_topage(J, 0);
const char *needle = js_tostring(J, 1);
- fz_rect hits[256];
+ fz_quad hits[256];
int i, n = 0;
fz_try(ctx)
@@ -1932,7 +1945,7 @@ static void ffi_Page_search(js_State *J)
js_newarray(J);
for (i = 0; i < n; ++i) {
- ffi_pushrect(J, hits[i]);
+ ffi_pushquad(J, hits[i]);
js_setindex(J, -2, i);
}
}
@@ -2777,7 +2790,7 @@ static void ffi_DisplayList_search(js_State *J)
fz_context *ctx = js_getcontext(J);
fz_display_list *list = js_touserdata(J, 0, "fz_display_list");
const char *needle = js_tostring(J, 1);
- fz_rect hits[256];
+ fz_quad hits[256];
int i, n = 0;
fz_try(ctx)
@@ -2787,7 +2800,7 @@ static void ffi_DisplayList_search(js_State *J)
js_newarray(J);
for (i = 0; i < n; ++i) {
- ffi_pushrect(J, hits[i]);
+ ffi_pushquad(J, hits[i]);
js_setindex(J, -2, i);
}
}
@@ -2797,7 +2810,7 @@ static void ffi_StructuredText_search(js_State *J)
fz_context *ctx = js_getcontext(J);
fz_stext_page *text = js_touserdata(J, 0, "fz_stext_page");
const char *needle = js_tostring(J, 1);
- fz_rect hits[256];
+ fz_quad hits[256];
int i, n = 0;
fz_try(ctx)
@@ -2807,7 +2820,7 @@ static void ffi_StructuredText_search(js_State *J)
js_newarray(J);
for (i = 0; i < n; ++i) {
- ffi_pushrect(J, hits[i]);
+ ffi_pushquad(J, hits[i]);
js_setindex(J, -2, i);
}
}
@@ -2818,7 +2831,7 @@ static void ffi_StructuredText_highlight(js_State *J)
fz_stext_page *text = js_touserdata(J, 0, "fz_stext_page");
fz_point a = ffi_topoint(J, 1);
fz_point b = ffi_topoint(J, 2);
- fz_rect hits[256];
+ fz_quad hits[256];
int i, n = 0;
fz_try(ctx)
@@ -2828,7 +2841,7 @@ static void ffi_StructuredText_highlight(js_State *J)
js_newarray(J);
for (i = 0; i < n; ++i) {
- ffi_pushrect(J, hits[i]);
+ ffi_pushquad(J, hits[i]);
js_setindex(J, -2, i);
}
}