comparison mupdf-source/platform/java/jni/structuredtext.c @ 2:b50eed0cc0ef upstream

ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4. The directory name has changed: no version number in the expanded directory now.
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 15 Sep 2025 11:43:07 +0200
parents
children
comparison
equal deleted inserted replaced
1:1d09e1dec1d9 2:b50eed0cc0ef
1 // Copyright (C) 2004-2025 Artifex Software, Inc.
2 //
3 // This file is part of MuPDF.
4 //
5 // MuPDF is free software: you can redistribute it and/or modify it under the
6 // terms of the GNU Affero General Public License as published by the Free
7 // Software Foundation, either version 3 of the License, or (at your option)
8 // any later version.
9 //
10 // MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY
11 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 // FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
13 // details.
14 //
15 // You should have received a copy of the GNU Affero General Public License
16 // along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html>
17 //
18 // Alternative licensing terms are available from the licensor.
19 // For commercial licensing, see <https://www.artifex.com/> or contact
20 // Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco,
21 // CA 94129, USA, for further information.
22
23 /* StructuredText interface */
24
25 JNIEXPORT void JNICALL
26 FUN(StructuredText_finalize)(JNIEnv *env, jobject self)
27 {
28 fz_context *ctx = get_context(env);
29 fz_stext_page *text = from_StructuredText_safe(env, self);
30 if (!ctx || !text) return;
31 (*env)->SetLongField(env, self, fid_StructuredText_pointer, 0);
32 fz_drop_stext_page(ctx, text);
33 }
34
35 JNIEXPORT jobject JNICALL
36 FUN(StructuredText_search)(JNIEnv *env, jobject self, jstring jneedle)
37 {
38 fz_context *ctx = get_context(env);
39 fz_stext_page *text = from_StructuredText(env, self);
40 const char *needle = NULL;
41 search_state state = { env, NULL, 0 };
42
43 if (!ctx || !text) return NULL;
44 if (!jneedle) jni_throw_arg(env, "needle must not be null");
45
46 needle = (*env)->GetStringUTFChars(env, jneedle, NULL);
47 if (!needle) return NULL;
48
49 state.hits = (*env)->NewObject(env, cls_ArrayList, mid_ArrayList_init);
50 if (!state.hits || (*env)->ExceptionCheck(env)) return NULL;
51
52 fz_try(ctx)
53 fz_search_stext_page_cb(ctx, text, needle, hit_callback, &state);
54 fz_always(ctx)
55 (*env)->ReleaseStringUTFChars(env, jneedle, needle);
56 fz_catch(ctx)
57 jni_rethrow(env, ctx);
58
59 if (state.error)
60 return NULL;
61
62 return (*env)->CallObjectMethod(env, state.hits, mid_ArrayList_toArray);
63 }
64
65 JNIEXPORT jobject JNICALL
66 FUN(StructuredText_highlight)(JNIEnv *env, jobject self, jobject jpt1, jobject jpt2)
67 {
68 fz_context *ctx = get_context(env);
69 fz_stext_page *text = from_StructuredText(env, self);
70 fz_point pt1 = from_Point(env, jpt1);
71 fz_point pt2 = from_Point(env, jpt2);
72 fz_quad hits[1000];
73 int n = 0;
74
75 if (!ctx || !text) return NULL;
76
77 fz_try(ctx)
78 n = fz_highlight_selection(ctx, text, pt1, pt2, hits, nelem(hits));
79 fz_catch(ctx)
80 jni_rethrow(env, ctx);
81
82 return to_QuadArray_safe(ctx, env, hits, n);
83 }
84
85 JNIEXPORT jobject JNICALL
86 FUN(StructuredText_snapSelection)(JNIEnv *env, jobject self, jobject jpt1, jobject jpt2, jint mode)
87 {
88 fz_context *ctx = get_context(env);
89 fz_stext_page *text = from_StructuredText(env, self);
90 fz_point pt1 = from_Point(env, jpt1);
91 fz_point pt2 = from_Point(env, jpt2);
92 fz_quad quad;
93
94 if (!ctx || !text) return NULL;
95
96 fz_try(ctx)
97 quad = fz_snap_selection(ctx, text, &pt1, &pt2, mode);
98 fz_catch(ctx)
99 jni_rethrow(env, ctx);
100
101 (*env)->SetFloatField(env, jpt1, fid_Point_x, pt1.x);
102 (*env)->SetFloatField(env, jpt1, fid_Point_y, pt1.y);
103 (*env)->SetFloatField(env, jpt2, fid_Point_x, pt2.x);
104 (*env)->SetFloatField(env, jpt2, fid_Point_y, pt2.y);
105
106 return to_Quad_safe(ctx, env, quad);
107 }
108
109 JNIEXPORT jobject JNICALL
110 FUN(StructuredText_copy)(JNIEnv *env, jobject self, jobject jpt1, jobject jpt2)
111 {
112 fz_context *ctx = get_context(env);
113 fz_stext_page *text = from_StructuredText(env, self);
114 fz_point pt1 = from_Point(env, jpt1);
115 fz_point pt2 = from_Point(env, jpt2);
116 jstring jstring = NULL;
117 char *s = NULL;
118
119 if (!ctx || !text) return NULL;
120
121 fz_var(s);
122
123 fz_try(ctx)
124 {
125 s = fz_copy_selection(ctx, text, pt1, pt2, 0);
126 jstring = (*env)->NewStringUTF(env, s);
127 }
128 fz_always(ctx)
129 fz_free(ctx, s);
130 fz_catch(ctx)
131 jni_rethrow(env, ctx);
132
133 return jstring;
134 }
135
136 static void
137 java_stext_walk(JNIEnv *env, fz_context *ctx, jobject walker, fz_stext_block *block)
138 {
139 fz_stext_line *line = NULL;
140 fz_stext_char *ch = NULL;
141 jobject jbbox = NULL;
142 jobject jtrm = NULL;
143 jobject jimage = NULL;
144 jobject jdir = NULL;
145 jobject jorigin = NULL;
146 jobject jfont = NULL;
147 jobject jquad = NULL;
148 jobject jvecinfo = NULL;
149
150 if (block == NULL)
151 return; /* structured text has no blocks to walk */
152
153 for (; block; block = block->next)
154 {
155 if (block->type == FZ_STEXT_BLOCK_IMAGE)
156 {
157 jbbox = to_Rect_safe(ctx, env, block->bbox);
158 if (!jbbox) return;
159
160 jtrm = to_Matrix_safe(ctx, env, block->u.i.transform);
161 if (!jtrm) return;
162
163 jimage = to_Image_safe(ctx, env, block->u.i.image);
164 if (!jimage) return;
165
166 (*env)->CallVoidMethod(env, walker, mid_StructuredTextWalker_onImageBlock, jbbox, jtrm, jimage);
167 if ((*env)->ExceptionCheck(env)) return;
168
169 (*env)->DeleteLocalRef(env, jbbox);
170 (*env)->DeleteLocalRef(env, jimage);
171 (*env)->DeleteLocalRef(env, jtrm);
172 }
173 else if (block->type == FZ_STEXT_BLOCK_TEXT)
174 {
175 jbbox = to_Rect_safe(ctx, env, block->bbox);
176 if (!jbbox) return;
177
178 (*env)->CallVoidMethod(env, walker, mid_StructuredTextWalker_beginTextBlock, jbbox);
179 if ((*env)->ExceptionCheck(env)) return;
180
181 (*env)->DeleteLocalRef(env, jbbox);
182
183 for (line = block->u.t.first_line; line; line = line->next)
184 {
185 jbbox = to_Rect_safe(ctx, env, line->bbox);
186 if (!jbbox) return;
187
188 jdir = to_Point_safe(ctx, env, line->dir);
189 if (!jdir) return;
190
191 (*env)->CallVoidMethod(env, walker, mid_StructuredTextWalker_beginLine, jbbox, line->wmode, jdir);
192 if ((*env)->ExceptionCheck(env)) return;
193
194 (*env)->DeleteLocalRef(env, jdir);
195 (*env)->DeleteLocalRef(env, jbbox);
196
197 for (ch = line->first_char; ch; ch = ch->next)
198 {
199 jorigin = to_Point_safe(ctx, env, ch->origin);
200 if (!jorigin) return;
201
202 jfont = to_Font_safe(ctx, env, ch->font);
203 if (!jfont) return;
204
205 jquad = to_Quad_safe(ctx, env, ch->quad);
206 if (!jquad) return;
207
208 (*env)->CallVoidMethod(env, walker, mid_StructuredTextWalker_onChar,
209 ch->c, jorigin, jfont, ch->size, jquad);
210 if ((*env)->ExceptionCheck(env)) return;
211
212 (*env)->DeleteLocalRef(env, jquad);
213 (*env)->DeleteLocalRef(env, jfont);
214 (*env)->DeleteLocalRef(env, jorigin);
215 }
216
217 (*env)->CallVoidMethod(env, walker, mid_StructuredTextWalker_endLine);
218 if ((*env)->ExceptionCheck(env)) return;
219 }
220
221 (*env)->CallVoidMethod(env, walker, mid_StructuredTextWalker_endTextBlock);
222 if ((*env)->ExceptionCheck(env)) return;
223 }
224 else if (block->type == FZ_STEXT_BLOCK_STRUCT)
225 {
226 jstring jstandard = to_String_safe(ctx, env, fz_structure_to_string(block->u.s.down->standard));
227 if (!jstandard) return;
228
229 jstring jraw = to_String_safe(ctx, env, block->u.s.down->raw);
230 if (!jraw) return;
231
232 (*env)->CallVoidMethod(env, walker, mid_StructuredTextWalker_beginStruct, jstandard, jraw, block->u.s.index);
233 if ((*env)->ExceptionCheck(env)) return;
234
235 (*env)->DeleteLocalRef(env, jraw);
236 (*env)->DeleteLocalRef(env, jstandard);
237
238 if (block->u.s.down)
239 java_stext_walk(env, ctx, walker, block->u.s.down->first_block);
240
241 (*env)->CallVoidMethod(env, walker, mid_StructuredTextWalker_endStruct);
242 if ((*env)->ExceptionCheck(env)) return;
243 }
244 else if (block->type == FZ_STEXT_BLOCK_VECTOR)
245 {
246 jbbox = to_Rect_safe(ctx, env, block->bbox);
247 if (!jbbox) return;
248
249 jvecinfo = to_VectorInfo_safe(ctx, env, block->u.v.flags);
250 if (!jvecinfo) return;
251
252 (*env)->CallVoidMethod(env, walker, mid_StructuredTextWalker_onVector, jbbox, jvecinfo, block->u.v.argb);
253 if ((*env)->ExceptionCheck(env)) return;
254
255 (*env)->DeleteLocalRef(env, jvecinfo);
256 (*env)->DeleteLocalRef(env, jbbox);
257 }
258 }
259 }
260
261 JNIEXPORT void JNICALL
262 FUN(StructuredText_walk)(JNIEnv *env, jobject self, jobject walker)
263 {
264 fz_context *ctx = get_context(env);
265 fz_stext_page *page = from_StructuredText(env, self);
266
267 if (!ctx || !page) return;
268 if (!walker) jni_throw_arg_void(env, "walker must not be null");
269
270 java_stext_walk(env, ctx, walker, page->first_block);
271 }
272
273 JNIEXPORT jstring JNICALL
274 FUN(StructuredText_asJSON)(JNIEnv *env, jobject self, jfloat scale)
275 {
276 fz_context *ctx = get_context(env);
277 fz_stext_page *page = from_StructuredText(env, self);
278 fz_output *out = NULL;
279 fz_buffer *buf = NULL;
280 char *str = NULL;
281
282 if (!ctx || !page) return NULL;
283
284 fz_var(buf);
285 fz_var(out);
286
287 fz_try(ctx)
288 {
289 buf = fz_new_buffer(ctx, 1024);
290 out = fz_new_output_with_buffer(ctx, buf);
291 fz_print_stext_page_as_json(ctx, out, page, scale);
292 fz_close_output(ctx, out);
293 fz_terminate_buffer(ctx, buf);
294 (void)fz_buffer_extract(ctx, buf, (unsigned char**)&str);
295 }
296 fz_always(ctx)
297 fz_drop_output(ctx, out);
298 fz_catch(ctx)
299 {
300 fz_drop_buffer(ctx, buf);
301 jni_rethrow(env, ctx);
302 }
303
304 return to_String_safe_own(ctx, env, str);
305 }
306
307 JNIEXPORT jstring JNICALL
308 FUN(StructuredText_asHTML)(JNIEnv *env, jobject self, jint id)
309 {
310 fz_context *ctx = get_context(env);
311 fz_stext_page *page = from_StructuredText(env, self);
312 fz_output *out = NULL;
313 fz_buffer *buf = NULL;
314 char *str = NULL;
315
316 if (!ctx || !page) return NULL;
317
318 fz_var(buf);
319 fz_var(out);
320
321 fz_try(ctx)
322 {
323 buf = fz_new_buffer(ctx, 1024);
324 out = fz_new_output_with_buffer(ctx, buf);
325 fz_print_stext_page_as_html(ctx, out, page, id);
326 fz_close_output(ctx, out);
327 fz_terminate_buffer(ctx, buf);
328 (void)fz_buffer_extract(ctx, buf, (unsigned char**)&str);
329 }
330 fz_always(ctx)
331 fz_drop_output(ctx, out);
332 fz_catch(ctx)
333 {
334 fz_drop_buffer(ctx, buf);
335 jni_rethrow(env, ctx);
336 }
337
338 return to_String_safe_own(ctx, env, str);
339 }
340
341 JNIEXPORT jstring JNICALL
342 FUN(StructuredText_asText)(JNIEnv *env, jobject self)
343 {
344 fz_context *ctx = get_context(env);
345 fz_stext_page *page = from_StructuredText(env, self);
346 fz_output *out = NULL;
347 fz_buffer *buf = NULL;
348 char *str = NULL;
349
350 if (!ctx || !page) return NULL;
351
352 fz_var(buf);
353 fz_var(out);
354
355 fz_try(ctx)
356 {
357 buf = fz_new_buffer(ctx, 1024);
358 out = fz_new_output_with_buffer(ctx, buf);
359 fz_print_stext_page_as_text(ctx, out, page);
360 fz_close_output(ctx, out);
361 fz_terminate_buffer(ctx, buf);
362 (void)fz_buffer_extract(ctx, buf, (unsigned char**)&str);
363 }
364 fz_always(ctx)
365 fz_drop_output(ctx, out);
366 fz_catch(ctx)
367 {
368 fz_drop_buffer(ctx, buf);
369 jni_rethrow(env, ctx);
370 }
371
372 return to_String_safe_own(ctx, env, str);
373 }