summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTor Andersson <tor.andersson@artifex.com>2021-11-18 14:02:24 +0100
committerTor Andersson <tor.andersson@artifex.com>2021-12-08 12:24:05 +0100
commit2a951a4a53746b760ebd2ffd3b3bbcae30d99b28 (patch)
treea279c26a1bc8e807764d33a6e478d1f50771d6a9
parent115a027c8fc6d065bcd52a4b6d14efa15abb8c64 (diff)
Distinguish separate search hit results.
Add a new optional argument to mark search hits to all of the search functions. With the marker each individual hit on the page can be identified. A quad that starts a new array has a matching 1 in the 'hits' array. Each continuation quad is marked with a 0 instead. This is the minimally invasive API change, it just adds an optional extra int array for recording the hit markers. The Java and mutool run APIs have been changed to return an array of array of quads for the search results.
-rw-r--r--docs/api/changes.html29
-rw-r--r--include/mupdf/fitz/structured-text.h2
-rw-r--r--include/mupdf/fitz/util.h8
-rw-r--r--platform/gl/gl-annotate.c2
-rw-r--r--platform/gl/gl-main.c2
-rw-r--r--platform/java/example/Viewer.java10
-rw-r--r--platform/java/jni/displaylist.c7
-rw-r--r--platform/java/jni/document.c7
-rw-r--r--platform/java/jni/page.c7
-rw-r--r--platform/java/jni/structuredtext.c7
-rw-r--r--platform/java/jni/wrap.c59
-rw-r--r--platform/java/mupdf_native.c4
-rw-r--r--platform/java/mupdf_native.h8
-rw-r--r--platform/java/src/com/artifex/mupdf/fitz/DisplayList.java2
-rw-r--r--platform/java/src/com/artifex/mupdf/fitz/Document.java2
-rw-r--r--platform/java/src/com/artifex/mupdf/fitz/Page.java2
-rw-r--r--platform/java/src/com/artifex/mupdf/fitz/StructuredText.java2
-rw-r--r--platform/x11/pdfapp.c2
-rw-r--r--source/fitz/stext-search.c34
-rw-r--r--source/fitz/util.c16
-rw-r--r--source/tools/murun.c59
21 files changed, 205 insertions, 66 deletions
diff --git a/docs/api/changes.html b/docs/api/changes.html
index 31948d1b9..0dc5274df 100644
--- a/docs/api/changes.html
+++ b/docs/api/changes.html
@@ -39,6 +39,35 @@ changes that may be require to update between versions.
Note, that we only list changes in existing APIs here, not all additions
to the API.
+<h2>Changes from 1.19</h2>
+
+<p>
+The search API has been extended with one optional parameter: an integer array.
+If the 'hit_mark' array is provided it must be the same length as the quad array.
+Each entry corresponds to the quad of the same index.
+It will be filled in with 1 for each quad that starts a new search hit, and 0 for
+each quad that is a continuation of a search hit
+(for example when a match spans a line-break).
+
+<ul>
+<li>int fz_search_stext_page(ctx, text, needle, <i>int *hit_mark</i>, fz_quad *hit_bbox, int hit_max);
+<li>int fz_search_display_list(ctx, list, needle, <i>int *hit_mark</i>, fz_quad *hit_bbox, int hit_max);
+<li>int fz_search_page(ctx, page, needle, <i>int *hit_mark</i>, fz_quad *hit_bbox, int hit_max);
+<li>int fz_search_page_number(ctx, doc, page, needle, <i>int *hit_mark</i>, fz_quad *hit_bbox, int hit_max);
+<li>int fz_search_chapter_page_number(ctx, doc, c, p, needle, <i>int *hit_mark</i>, fz_quad *hit_bbox, int hit_max);
+</ul>
+
+<p>
+The Java search functions have also changed.
+They now return an array of array of quads instead of an array of quads.
+
+<ul>
+<li>Quad[][] StructuredText.search(String needle);
+<li>Quad[][] DisplayList.search(String needle);
+<li>Quad[][] Page.search(String needle);
+<li>Quad[][] Document.search(int chapter, int page, String needle);
+</ul>
+
<h2>Changes from 1.18 to 1.19</h2>
<p>We were inconsistent with the behaviour of fz_create_ and pdf_create_
diff --git a/include/mupdf/fitz/structured-text.h b/include/mupdf/fitz/structured-text.h
index c6a3a09db..26cdf26f8 100644
--- a/include/mupdf/fitz/structured-text.h
+++ b/include/mupdf/fitz/structured-text.h
@@ -244,7 +244,7 @@ void fz_print_stext_page_as_text(fz_context *ctx, fz_output *out, fz_stext_page
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_quad *quads, int max_quads);
+int fz_search_stext_page(fz_context *ctx, fz_stext_page *text, const char *needle, int *hit_mark, fz_quad *hit_bbox, int hit_max);
/**
Return a list of quads to highlight lines inside the selection
diff --git a/include/mupdf/fitz/util.h b/include/mupdf/fitz/util.h
index e7a1b9d5b..5fc86a4f6 100644
--- a/include/mupdf/fitz/util.h
+++ b/include/mupdf/fitz/util.h
@@ -95,10 +95,10 @@ 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_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_chapter_page_number(fz_context *ctx, fz_document *doc, int chapter, int page, 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);
+int fz_search_page(fz_context *ctx, fz_page *page, const char *needle, int *hit_mark, fz_quad *hit_bbox, int hit_max);
+int fz_search_page_number(fz_context *ctx, fz_document *doc, int number, const char *needle, int *hit_mark, fz_quad *hit_bbox, int hit_max);
+int fz_search_chapter_page_number(fz_context *ctx, fz_document *doc, int chapter, int page, const char *needle, int *hit_mark, fz_quad *hit_bbox, int hit_max);
+int fz_search_display_list(fz_context *ctx, fz_display_list *list, const char *needle, int *hit_mark, fz_quad *hit_bbox, int hit_max);
/**
Parse an SVG document into a display-list.
diff --git a/platform/gl/gl-annotate.c b/platform/gl/gl-annotate.c
index 6ecd8eea0..9ef493a9a 100644
--- a/platform/gl/gl-annotate.c
+++ b/platform/gl/gl-annotate.c
@@ -1299,7 +1299,7 @@ static int mark_search_step(int cancel)
return -1;
}
- count = fz_search_page_number(ctx, (fz_document*)pdf, rds_state.i-1, search_needle, quads, nelem(quads));
+ count = fz_search_page_number(ctx, (fz_document*)pdf, rds_state.i-1, search_needle, NULL, quads, nelem(quads));
if (count > 0)
{
pdf_page *page = pdf_load_page(ctx, pdf, rds_state.i-1);
diff --git a/platform/gl/gl-main.c b/platform/gl/gl-main.c
index 92ba717bf..8357fca3a 100644
--- a/platform/gl/gl-main.c
+++ b/platform/gl/gl-main.c
@@ -2534,7 +2534,7 @@ void do_main(void)
search_hit_count = fz_search_chapter_page_number(ctx, doc,
search_page.chapter, search_page.page,
search_needle,
- search_hit_quads, nelem(search_hit_quads));
+ NULL, search_hit_quads, nelem(search_hit_quads));
trace_action("hits = doc.loadPage(%d).search(%q);\n", fz_page_number_from_location(ctx, doc, search_page), search_needle);
trace_action("print('Search page %d:', repr(%q), hits.length, repr(hits));\n", fz_page_number_from_location(ctx, doc, search_page), search_needle);
if (search_hit_count)
diff --git a/platform/java/example/Viewer.java b/platform/java/example/Viewer.java
index a6839044a..a38716c44 100644
--- a/platform/java/example/Viewer.java
+++ b/platform/java/example/Viewer.java
@@ -61,7 +61,7 @@ public class Viewer extends Frame implements WindowListener, ActionListener, Ite
protected int searchDirection = 1;
protected Location searchPage = null;
protected Location searchHitPage = null;
- protected Quad[] searchHits = new Quad[0];
+ protected Quad[][] searchHits = new Quad[0][];
protected EventQueue eq = null;
protected SearchTask searchTask = null;
@@ -224,8 +224,10 @@ public class Viewer extends Frame implements WindowListener, ActionListener, Ite
if (currentPage.equals(searchHitPage) && searchHits != null) {
g2d.setColor(new Color(1, 0, 0, 0.4f));
for (int i = 0; i < searchHits.length; ++i) {
- Rect hit = new Rect(searchHits[i]).transform(pageCTM);
- g2d.fillRect((int)hit.x0, (int)hit.y0, (int)(hit.x1-hit.x0), (int)(hit.y1-hit.y0));
+ for (int k = 0; k < searchHits[i].length; ++k) {
+ Rect hit = new Rect(searchHits[i][k]).transform(pageCTM);
+ g2d.fillRect((int)hit.x0, (int)hit.y0, (int)(hit.x1-hit.x0), (int)(hit.y1-hit.y0));
+ }
}
}
@@ -763,7 +765,7 @@ public class Viewer extends Frame implements WindowListener, ActionListener, Ite
while (!done && !isCancelled() && System.currentTimeMillis() < executionUntil) {
searchHits = doc.search(searchPage.chapter, searchPage.page, needle);
if (searchHits != null && searchHits.length > 0) {
- searchHitPage = new Location(searchPage, searchHits[0].ul_x, searchHits[0].ul_y);
+ searchHitPage = new Location(searchPage, searchHits[0][0].ul_x, searchHits[0][0].ul_y);
jumpToLocation(searchHitPage);
done = true;
}
diff --git a/platform/java/jni/displaylist.c b/platform/java/jni/displaylist.c
index 66b093f34..c8263751f 100644
--- a/platform/java/jni/displaylist.c
+++ b/platform/java/jni/displaylist.c
@@ -139,7 +139,8 @@ FUN(DisplayList_search)(JNIEnv *env, jobject self, jstring jneedle)
{
fz_context *ctx = get_context(env);
fz_display_list *list = from_DisplayList(env, self);
- fz_quad hits[256];
+ fz_quad hits[500];
+ int marks[500];
const char *needle = NULL;
int n = 0;
@@ -150,11 +151,11 @@ FUN(DisplayList_search)(JNIEnv *env, jobject self, jstring jneedle)
if (!needle) return NULL;
fz_try(ctx)
- n = fz_search_display_list(ctx, list, needle, hits, nelem(hits));
+ n = fz_search_display_list(ctx, list, needle, marks, hits, nelem(hits));
fz_always(ctx)
(*env)->ReleaseStringUTFChars(env, jneedle, needle);
fz_catch(ctx)
jni_rethrow(env, ctx);
- return to_QuadArray_safe(ctx, env, hits, n);
+ return to_SearchHits_safe(ctx, env, marks, hits, n);
}
diff --git a/platform/java/jni/document.c b/platform/java/jni/document.c
index 115c558cc..61905126d 100644
--- a/platform/java/jni/document.c
+++ b/platform/java/jni/document.c
@@ -1006,7 +1006,8 @@ FUN(Document_search)(JNIEnv *env, jobject self, jint chapter, jint page, jstring
{
fz_context *ctx = get_context(env);
fz_document *doc = from_Document(env, self);
- fz_quad hits[256];
+ fz_quad hits[500];
+ int marks[500];
const char *needle = NULL;
int n = 0;
@@ -1017,11 +1018,11 @@ FUN(Document_search)(JNIEnv *env, jobject self, jint chapter, jint page, jstring
if (!needle) return 0;
fz_try(ctx)
- n = fz_search_chapter_page_number(ctx, doc, chapter, page, needle, hits, nelem(hits));
+ n = fz_search_chapter_page_number(ctx, doc, chapter, page, needle, marks, hits, nelem(hits));
fz_always(ctx)
(*env)->ReleaseStringUTFChars(env, jneedle, needle);
fz_catch(ctx)
jni_rethrow(env, ctx);
- return to_QuadArray_safe(ctx, env, hits, n);
+ return to_SearchHits_safe(ctx, env, marks, hits, n);
}
diff --git a/platform/java/jni/page.c b/platform/java/jni/page.c
index c0049f7d1..1e74d0c06 100644
--- a/platform/java/jni/page.c
+++ b/platform/java/jni/page.c
@@ -267,7 +267,8 @@ FUN(Page_search)(JNIEnv *env, jobject self, jstring jneedle)
{
fz_context *ctx = get_context(env);
fz_page *page = from_Page(env, self);
- fz_quad hits[256];
+ fz_quad hits[500];
+ int marks[500];
const char *needle = NULL;
int n = 0;
@@ -278,13 +279,13 @@ FUN(Page_search)(JNIEnv *env, jobject self, jstring jneedle)
if (!needle) return 0;
fz_try(ctx)
- n = fz_search_page(ctx, page, needle, hits, nelem(hits));
+ n = fz_search_page(ctx, page, needle, marks, hits, nelem(hits));
fz_always(ctx)
(*env)->ReleaseStringUTFChars(env, jneedle, needle);
fz_catch(ctx)
jni_rethrow(env, ctx);
- return to_QuadArray_safe(ctx, env, hits, n);
+ return to_SearchHits_safe(ctx, env, marks, hits, n);
}
JNIEXPORT jobject JNICALL
diff --git a/platform/java/jni/structuredtext.c b/platform/java/jni/structuredtext.c
index dade29150..a6c928637 100644
--- a/platform/java/jni/structuredtext.c
+++ b/platform/java/jni/structuredtext.c
@@ -37,7 +37,8 @@ FUN(StructuredText_search)(JNIEnv *env, jobject self, jstring jneedle)
{
fz_context *ctx = get_context(env);
fz_stext_page *text = from_StructuredText(env, self);
- fz_quad hits[256];
+ fz_quad hits[500];
+ int marks[500];
const char *needle = NULL;
int n = 0;
@@ -48,13 +49,13 @@ FUN(StructuredText_search)(JNIEnv *env, jobject self, jstring jneedle)
if (!needle) return NULL;
fz_try(ctx)
- n = fz_search_stext_page(ctx, text, needle, hits, nelem(hits));
+ n = fz_search_stext_page(ctx, text, needle, marks, hits, nelem(hits));
fz_always(ctx)
(*env)->ReleaseStringUTFChars(env, jneedle, needle);
fz_catch(ctx)
jni_rethrow(env, ctx);
- return to_QuadArray_safe(ctx, env, hits, n);
+ return to_SearchHits_safe(ctx, env, marks, hits, n);
}
JNIEXPORT jobject JNICALL
diff --git a/platform/java/jni/wrap.c b/platform/java/jni/wrap.c
index 95074337c..89350d0b5 100644
--- a/platform/java/jni/wrap.c
+++ b/platform/java/jni/wrap.c
@@ -403,6 +403,65 @@ static inline jobjectArray to_QuadArray_safe(fz_context *ctx, JNIEnv *env, const
return arr;
}
+static int count_next_hits(const int *marks, int a, int end)
+{
+ int b = a + 1;
+ while (b < end && !marks[b])
+ ++b;
+ return b - a;
+}
+
+/* Array of Array of Quad */
+static inline jobjectArray to_SearchHits_safe(fz_context *ctx, JNIEnv *env, const int *marks, const fz_quad *quads, jint n)
+{
+ jobjectArray toparr, arr;
+ int i, k, a, m;
+
+ if (!ctx || !marks || !quads)
+ return NULL;
+
+ /* Count total number of search hits */
+ i = a = 0;
+ while (a < n)
+ {
+ a += count_next_hits(marks, a, n);
+ ++i;
+ }
+
+ toparr = (*env)->NewObjectArray(env, i, cls_ArrayOfQuad, NULL);
+ if (!toparr || (*env)->ExceptionCheck(env))
+ return NULL;
+
+ i = a = 0;
+ while (a < n)
+ {
+ m = count_next_hits(marks, a, n);
+
+ arr = (*env)->NewObjectArray(env, m, cls_Quad, NULL);
+ if (!arr || (*env)->ExceptionCheck(env))
+ return NULL;
+ (*env)->SetObjectArrayElement(env, toparr, i++, arr);
+ if ((*env)->ExceptionCheck(env))
+ return NULL;
+
+ for (k = 0; k < m; ++k) {
+ jobject jquad = to_Quad_safe(ctx, env, quads[a+k]);
+ if (!jquad || (*env)->ExceptionCheck(env))
+ return NULL;
+ (*env)->SetObjectArrayElement(env, arr, k, jquad);
+ if ((*env)->ExceptionCheck(env))
+ return NULL;
+ (*env)->DeleteLocalRef(env, jquad);
+ }
+
+ (*env)->DeleteLocalRef(env, arr);
+
+ a += m;
+ }
+
+ return toparr;
+}
+
static inline jobject to_Rect_safe(fz_context *ctx, JNIEnv *env, fz_rect rect)
{
if (!ctx) return NULL;
diff --git a/platform/java/mupdf_native.c b/platform/java/mupdf_native.c
index 925ccad67..8504e5867 100644
--- a/platform/java/mupdf_native.c
+++ b/platform/java/mupdf_native.c
@@ -87,6 +87,7 @@ static JavaVM *jvm = NULL;
/* All the cached classes/mids/fids we need. */
+static jclass cls_ArrayOfQuad;
static jclass cls_Buffer;
static jclass cls_ColorSpace;
static jclass cls_Context;
@@ -938,6 +939,8 @@ static int find_fids(JNIEnv *env)
fid_Quad_lr_y = get_field(&err, env, "lr_y", "F");
mid_Quad_init = get_method(&err, env, "<init>", "(FFFFFFFF)V");
+ cls_ArrayOfQuad = get_class(&err, env, "[L"PKG"Quad;");
+
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");
@@ -1090,6 +1093,7 @@ static void jni_detach_thread(jboolean detach)
static void lose_fids(JNIEnv *env)
{
+ (*env)->DeleteGlobalRef(env, cls_ArrayOfQuad);
(*env)->DeleteGlobalRef(env, cls_Buffer);
(*env)->DeleteGlobalRef(env, cls_ColorSpace);
(*env)->DeleteGlobalRef(env, cls_Context);
diff --git a/platform/java/mupdf_native.h b/platform/java/mupdf_native.h
index ec2185b87..c66e89e38 100644
--- a/platform/java/mupdf_native.h
+++ b/platform/java/mupdf_native.h
@@ -387,7 +387,7 @@ JNIEXPORT jobject JNICALL Java_com_artifex_mupdf_fitz_DisplayList_toStructuredTe
/*
* Class: com_artifex_mupdf_fitz_DisplayList
* Method: search
- * Signature: (Ljava/lang/String;)[Lcom/artifex/mupdf/fitz/Quad;
+ * Signature: (Ljava/lang/String;)[[Lcom/artifex/mupdf/fitz/Quad;
*/
JNIEXPORT jobjectArray JNICALL Java_com_artifex_mupdf_fitz_DisplayList_search
(JNIEnv *, jobject, jstring);
@@ -581,7 +581,7 @@ JNIEXPORT jobject JNICALL Java_com_artifex_mupdf_fitz_Document_loadPage
/*
* Class: com_artifex_mupdf_fitz_Document
* Method: search
- * Signature: (IILjava/lang/String;)[Lcom/artifex/mupdf/fitz/Quad;
+ * Signature: (IILjava/lang/String;)[[Lcom/artifex/mupdf/fitz/Quad;
*/
JNIEXPORT jobjectArray JNICALL Java_com_artifex_mupdf_fitz_Document_search
(JNIEnv *, jobject, jint, jint, jstring);
@@ -3725,7 +3725,7 @@ JNIEXPORT jobject JNICALL Java_com_artifex_mupdf_fitz_Page_toStructuredText
/*
* Class: com_artifex_mupdf_fitz_Page
* Method: search
- * Signature: (Ljava/lang/String;)[Lcom/artifex/mupdf/fitz/Quad;
+ * Signature: (Ljava/lang/String;)[[Lcom/artifex/mupdf/fitz/Quad;
*/
JNIEXPORT jobjectArray JNICALL Java_com_artifex_mupdf_fitz_Page_search
(JNIEnv *, jobject, jstring);
@@ -4245,7 +4245,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/Quad;
+ * Signature: (Ljava/lang/String;)[[Lcom/artifex/mupdf/fitz/Quad;
*/
JNIEXPORT jobjectArray JNICALL Java_com_artifex_mupdf_fitz_StructuredText_search
(JNIEnv *, jobject, jstring);
diff --git a/platform/java/src/com/artifex/mupdf/fitz/DisplayList.java b/platform/java/src/com/artifex/mupdf/fitz/DisplayList.java
index b22aa4ebb..84d90a3ea 100644
--- a/platform/java/src/com/artifex/mupdf/fitz/DisplayList.java
+++ b/platform/java/src/com/artifex/mupdf/fitz/DisplayList.java
@@ -53,7 +53,7 @@ public class DisplayList
return toStructuredText(null);
}
- public native Quad[] search(String needle);
+ public native Quad[][] search(String needle);
public native void run(Device dev, Matrix ctm, Rect scissor, Cookie cookie);
diff --git a/platform/java/src/com/artifex/mupdf/fitz/Document.java b/platform/java/src/com/artifex/mupdf/fitz/Document.java
index 486b35f2d..43e7fe2c1 100644
--- a/platform/java/src/com/artifex/mupdf/fitz/Document.java
+++ b/platform/java/src/com/artifex/mupdf/fitz/Document.java
@@ -191,7 +191,7 @@ public class Document
return -1;
}
- public native Quad[] search(int chapter, int page, String needle);
+ public native Quad[][] search(int chapter, int page, String needle);
public native Location resolveLink(String uri);
public Location resolveLink(Outline link) {
diff --git a/platform/java/src/com/artifex/mupdf/fitz/Page.java b/platform/java/src/com/artifex/mupdf/fitz/Page.java
index 1344b6e29..101d0327b 100644
--- a/platform/java/src/com/artifex/mupdf/fitz/Page.java
+++ b/platform/java/src/com/artifex/mupdf/fitz/Page.java
@@ -68,7 +68,7 @@ public class Page
return toStructuredText(null);
}
- public native Quad[] search(String needle);
+ public native Quad[][] search(String needle);
public native byte[] textAsHtml();
diff --git a/platform/java/src/com/artifex/mupdf/fitz/StructuredText.java b/platform/java/src/com/artifex/mupdf/fitz/StructuredText.java
index 5834dfc2c..7019b227b 100644
--- a/platform/java/src/com/artifex/mupdf/fitz/StructuredText.java
+++ b/platform/java/src/com/artifex/mupdf/fitz/StructuredText.java
@@ -46,7 +46,7 @@ public class StructuredText
pointer = p;
}
- public native Quad[] search(String needle);
+ public native Quad[][] search(String needle);
public native Quad[] highlight(Point a, Point b);
public native Quad snapSelection(Point a, Point b, int mode);
public native String copy(Point a, Point b);
diff --git a/platform/x11/pdfapp.c b/platform/x11/pdfapp.c
index 4624551cc..0c94f6eb4 100644
--- a/platform/x11/pdfapp.c
+++ b/platform/x11/pdfapp.c
@@ -1186,7 +1186,7 @@ static void pdfapp_search_in_direction(pdfapp_t *app, enum panning *panto, int d
pdfapp_showpage(app, 1, 0, 0, 0, 1);
}
- app->hit_count = fz_search_stext_page(app->ctx, app->page_text, app->search, app->hit_bbox, nelem(app->hit_bbox));
+ app->hit_count = fz_search_stext_page(app->ctx, app->page_text, app->search, NULL, app->hit_bbox, nelem(app->hit_bbox));
if (app->hit_count > 0)
{
*panto = dir == 1 ? PAN_TO_TOP : PAN_TO_BOTTOM;
diff --git a/source/fitz/stext-search.c b/source/fitz/stext-search.c
index 0140340f3..56306b90e 100644
--- a/source/fitz/stext-search.c
+++ b/source/fitz/stext-search.c
@@ -496,8 +496,36 @@ static const char *find_string(const char *s, const char *needle, const char **e
return *endp = NULL, NULL;
}
+static void add_hit_char(fz_context *ctx, struct highlight *hits, int *hit_mark, fz_stext_line *line, fz_stext_char *ch, int is_at_start)
+{
+ float vfuzz = ch->size * hits->vfuzz;
+ float hfuzz = ch->size * hits->hfuzz;
+
+ if (hits->len > 0 && !is_at_start)
+ {
+ 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)
+ {
+ end->ur = ch->quad.ur;
+ end->lr = ch->quad.lr;
+ return;
+ }
+ }
+
+ if (hits->len < hits->cap)
+ {
+ if (hit_mark)
+ hit_mark[hits->len] = is_at_start;
+ hits->box[hits->len] = ch->quad;
+ hits->len++;
+ }
+}
+
int
-fz_search_stext_page(fz_context *ctx, fz_stext_page *page, const char *needle, fz_quad *quads, int max_quads)
+fz_search_stext_page(fz_context *ctx, fz_stext_page *page, const char *needle, int *hit_mark, fz_quad *quads, int max_quads)
{
struct highlight hits;
fz_stext_block *block;
@@ -542,7 +570,9 @@ try_new_match:
if (inside)
{
if (haystack < end)
- on_highlight_char(ctx, &hits, line, ch);
+ {
+ add_hit_char(ctx, &hits, hit_mark, line, ch, haystack == begin);
+ }
else
{
inside = 0;
diff --git a/source/fitz/util.c b/source/fitz/util.c
index 184a2ce88..1450ee293 100644
--- a/source/fitz/util.c
+++ b/source/fitz/util.c
@@ -349,14 +349,14 @@ fz_new_stext_page_from_chapter_page_number(fz_context *ctx, fz_document *doc, in
}
int
-fz_search_display_list(fz_context *ctx, fz_display_list *list, const char *needle, fz_quad *hit_bbox, int hit_max)
+fz_search_display_list(fz_context *ctx, fz_display_list *list, const char *needle, int *hit_mark, fz_quad *hit_bbox, int hit_max)
{
fz_stext_page *text;
int count = 0;
text = fz_new_stext_page_from_display_list(ctx, list, NULL);
fz_try(ctx)
- count = fz_search_stext_page(ctx, text, needle, hit_bbox, hit_max);
+ count = fz_search_stext_page(ctx, text, needle, hit_mark, hit_bbox, hit_max);
fz_always(ctx)
fz_drop_stext_page(ctx, text);
fz_catch(ctx)
@@ -365,7 +365,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_quad *hit_bbox, int hit_max)
+fz_search_page(fz_context *ctx, fz_page *page, const char *needle, int *hit_mark, fz_quad *hit_bbox, int hit_max)
{
fz_stext_options opts = { FZ_STEXT_DEHYPHENATE };
fz_stext_page *text;
@@ -373,7 +373,7 @@ fz_search_page(fz_context *ctx, fz_page *page, const char *needle, fz_quad *hit_
text = fz_new_stext_page_from_page(ctx, page, &opts);
fz_try(ctx)
- count = fz_search_stext_page(ctx, text, needle, hit_bbox, hit_max);
+ count = fz_search_stext_page(ctx, text, needle, hit_mark, hit_bbox, hit_max);
fz_always(ctx)
fz_drop_stext_page(ctx, text);
fz_catch(ctx)
@@ -382,14 +382,14 @@ fz_search_page(fz_context *ctx, fz_page *page, const char *needle, fz_quad *hit_
}
int
-fz_search_page_number(fz_context *ctx, fz_document *doc, int number, const char *needle, fz_quad *hit_bbox, int hit_max)
+fz_search_page_number(fz_context *ctx, fz_document *doc, int number, const char *needle, int *hit_mark, fz_quad *hit_bbox, int hit_max)
{
fz_page *page;
int count = 0;
page = fz_load_page(ctx, doc, number);
fz_try(ctx)
- count = fz_search_page(ctx, page, needle, hit_bbox, hit_max);
+ count = fz_search_page(ctx, page, needle, hit_mark, hit_bbox, hit_max);
fz_always(ctx)
fz_drop_page(ctx, page);
fz_catch(ctx)
@@ -398,14 +398,14 @@ fz_search_page_number(fz_context *ctx, fz_document *doc, int number, const char
}
int
-fz_search_chapter_page_number(fz_context *ctx, fz_document *doc, int chapter, int number, const char *needle, fz_quad *hit_bbox, int hit_max)
+fz_search_chapter_page_number(fz_context *ctx, fz_document *doc, int chapter, int number, const char *needle, int *hit_mark, fz_quad *hit_bbox, int hit_max)
{
fz_page *page;
int count = 0;
page = fz_load_chapter_page(ctx, doc, chapter, number);
fz_try(ctx)
- count = fz_search_page(ctx, page, needle, hit_bbox, hit_max);
+ count = fz_search_page(ctx, page, needle, hit_mark, hit_bbox, hit_max);
fz_always(ctx)
fz_drop_page(ctx, page);
fz_catch(ctx)
diff --git a/source/tools/murun.c b/source/tools/murun.c
index 10c1bcd35..afc3653c0 100644
--- a/source/tools/murun.c
+++ b/source/tools/murun.c
@@ -2836,24 +2836,41 @@ static void ffi_Page_toStructuredText(js_State *J)
js_newuserdata(J, "fz_stext_page", text, ffi_gc_fz_stext_page);
}
+static void ffi_pushsearch(js_State *J, int *marks, fz_quad *hits, int n)
+{
+ int a = 0;
+ js_newarray(J);
+ if (n > 0) {
+ int i, k = 0;
+ js_newarray(J);
+ for (i = 0; i < n; ++i) {
+ if (i > 0 && marks[i]) {
+ js_setindex(J, -2, a++);
+ js_newarray(J);
+ k = 0;
+ }
+ ffi_pushquad(J, hits[i]);
+ js_setindex(J, -2, k++);
+ }
+ js_setindex(J, -2, a);
+ }
+}
+
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_quad hits[256];
- int i, n = 0;
+ fz_quad hits[500];
+ int marks[500];
+ int n = 0;
fz_try(ctx)
- n = fz_search_page(ctx, page, needle, hits, nelem(hits));
+ n = fz_search_page(ctx, page, needle, marks, hits, nelem(hits));
fz_catch(ctx)
rethrow(J);
- js_newarray(J);
- for (i = 0; i < n; ++i) {
- ffi_pushquad(J, hits[i]);
- js_setindex(J, -2, i);
- }
+ ffi_pushsearch(J, marks, hits, n);
}
static void ffi_Page_getLinks(js_State *J)
@@ -3692,19 +3709,16 @@ 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_quad hits[256];
- int i, n = 0;
+ fz_quad hits[500];
+ int marks[500];
+ int n = 0;
fz_try(ctx)
- n = fz_search_display_list(ctx, list, needle, hits, nelem(hits));
+ n = fz_search_display_list(ctx, list, needle, marks, hits, nelem(hits));
fz_catch(ctx)
rethrow(J);
- js_newarray(J);
- for (i = 0; i < n; ++i) {
- ffi_pushquad(J, hits[i]);
- js_setindex(J, -2, i);
- }
+ ffi_pushsearch(J, marks, hits, n);
}
static void ffi_StructuredText_walk(js_State *J)
@@ -3789,19 +3803,16 @@ 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_quad hits[256];
- int i, n = 0;
+ fz_quad hits[500];
+ int marks[500];
+ int n = 0;
fz_try(ctx)
- n = fz_search_stext_page(ctx, text, needle, hits, nelem(hits));
+ n = fz_search_stext_page(ctx, text, needle, marks, hits, nelem(hits));
fz_catch(ctx)
rethrow(J);
- js_newarray(J);
- for (i = 0; i < n; ++i) {
- ffi_pushquad(J, hits[i]);
- js_setindex(J, -2, i);
- }
+ ffi_pushsearch(J, marks, hits, n);
}
static void ffi_StructuredText_highlight(js_State *J)