diff options
-rw-r--r-- | include/mupdf/pdf/appearance.h | 1 | ||||
-rw-r--r-- | include/mupdf/pdf/widget.h | 6 | ||||
-rw-r--r-- | platform/android/jni/mupdf.c | 4 | ||||
-rw-r--r-- | platform/ios/Classes/MuPageViewNormal.m | 4 | ||||
-rw-r--r-- | platform/x11/pdfapp.c | 4 | ||||
-rw-r--r-- | source/pdf/pdf-appearance.c | 252 | ||||
-rw-r--r-- | source/pdf/pdf-form.c | 19 |
7 files changed, 272 insertions, 18 deletions
diff --git a/include/mupdf/pdf/appearance.h b/include/mupdf/pdf/appearance.h index ddf64516..5ea92c63 100644 --- a/include/mupdf/pdf/appearance.h +++ b/include/mupdf/pdf/appearance.h @@ -15,6 +15,7 @@ void pdf_fzbuf_print_da(fz_context *ctx, fz_buffer *fzbuf, pdf_da_info *di); void pdf_update_text_appearance(fz_context *ctx, pdf_document *doc, pdf_obj *obj, char *eventValue); void pdf_update_combobox_appearance(fz_context *ctx, pdf_document *doc, pdf_obj *obj); +void pdf_update_listbox_appearance(fz_context *ctx, pdf_document *doc, pdf_obj *obj); void pdf_update_pushbutton_appearance(fz_context *ctx, pdf_document *doc, pdf_obj *obj); void pdf_update_text_markup_appearance(fz_context *ctx, pdf_document *doc, pdf_annot *annot, fz_annot_type type); void pdf_update_ink_appearance(fz_context *ctx, pdf_document *doc, pdf_annot *annot); diff --git a/include/mupdf/pdf/widget.h b/include/mupdf/pdf/widget.h index 45441e55..a4b5bd5e 100644 --- a/include/mupdf/pdf/widget.h +++ b/include/mupdf/pdf/widget.h @@ -96,9 +96,11 @@ int pdf_text_widget_set_text(fz_context *ctx, pdf_document *doc, pdf_widget *tw, pdf_choice_widget_options: get the list of options for a list box or combo box. Returns the number of options and fills in their names within the supplied array. Should first be called with a - NULL array to find out how big the array should be. + NULL array to find out how big the array should be. If exportval + is true, then the export values will be returned and not the list + values if there are export values present. */ -int pdf_choice_widget_options(fz_context *ctx, pdf_document *doc, pdf_widget *tw, char *opts[]); +int pdf_choice_widget_options(fz_context *ctx, pdf_document *doc, pdf_widget *tw, int exportval, char *opts[]); /* pdf_choice_widget_is_multiselect: returns whether a list box or diff --git a/platform/android/jni/mupdf.c b/platform/android/jni/mupdf.c index 20026e81..72214597 100644 --- a/platform/android/jni/mupdf.c +++ b/platform/android/jni/mupdf.c @@ -2151,9 +2151,9 @@ JNI_FN(MuPDFCore_getFocusedWidgetChoiceOptions)(JNIEnv * env, jobject thiz) fz_var(opts); fz_try(ctx) { - nopts = pdf_choice_widget_options(ctx, idoc, focus, NULL); + nopts = pdf_choice_widget_options(ctx, idoc, focus, 0, NULL); opts = fz_malloc(ctx, nopts * sizeof(*opts)); - (void)pdf_choice_widget_options(ctx, idoc, focus, opts); + (void)pdf_choice_widget_options(ctx, idoc, focus, 0, opts); } fz_catch(ctx) { diff --git a/platform/ios/Classes/MuPageViewNormal.m b/platform/ios/Classes/MuPageViewNormal.m index 671702fe..429785fe 100644 --- a/platform/ios/Classes/MuPageViewNormal.m +++ b/platform/ios/Classes/MuPageViewNormal.m @@ -1301,9 +1301,9 @@ static void updatePixmap(fz_document *doc, fz_display_list *page_list, fz_displa case PDF_WIDGET_TYPE_LISTBOX: case PDF_WIDGET_TYPE_COMBOBOX: { - int nopts = pdf_choice_widget_options(ctx, idoc, focus, NULL); + int nopts = pdf_choice_widget_options(ctx, idoc, focus, 0, NULL); opts = fz_malloc(ctx, nopts * sizeof(*opts)); - (void)pdf_choice_widget_options(ctx, idoc, focus, opts); + (void)pdf_choice_widget_options(ctx, idoc, focus, 0, opts); NSMutableArray *arr = [[NSMutableArray arrayWithCapacity:nopts] retain]; for (int i = 0; i < nopts; i++) { diff --git a/platform/x11/pdfapp.c b/platform/x11/pdfapp.c index 006cba1b..5a036d04 100644 --- a/platform/x11/pdfapp.c +++ b/platform/x11/pdfapp.c @@ -1665,9 +1665,9 @@ void pdfapp_onmouse(pdfapp_t *app, int x, int y, int btn, int modifiers, int sta fz_try(ctx) { - nopts = pdf_choice_widget_options(ctx, idoc, widget, NULL); + nopts = pdf_choice_widget_options(ctx, idoc, widget, 0, NULL); opts = fz_malloc(ctx, nopts * sizeof(*opts)); - (void)pdf_choice_widget_options(ctx, idoc, widget, opts); + (void)pdf_choice_widget_options(ctx, idoc, widget, 0, opts); nvals = pdf_choice_widget_value(ctx, idoc, widget, NULL); vals = fz_malloc(ctx, MAX(nvals,nopts) * sizeof(*vals)); diff --git a/source/pdf/pdf-appearance.c b/source/pdf/pdf-appearance.c index b0fa2207..cd1f0f93 100644 --- a/source/pdf/pdf-appearance.c +++ b/source/pdf/pdf-appearance.c @@ -9,6 +9,9 @@ #define UNDERLINE_HEIGHT (0.075f) #define LINE_THICKNESS (0.07f) #define SMALL_FLOAT (0.00001) +#define LIST_SEL_COLOR_R (0.6) +#define LIST_SEL_COLOR_G (0.75) +#define LIST_SEL_COLOR_B (0.85) enum { @@ -258,6 +261,38 @@ static void fzbuf_print_color(fz_context *ctx, fz_buffer *fzbuf, pdf_obj *arr, i } } +static void fzbuf_print_rect_fill(fz_context *ctx, fz_buffer *fzbuf, const fz_rect *clip, + float col[4], int col_size, const fz_matrix *tm, const fz_rect *rect) +{ + if (clip) + { + fz_buffer_printf(ctx, fzbuf, fmt_re, clip->x0, clip->y0, clip->x1 - clip->x0, clip->y1 - clip->y0); + fz_buffer_printf(ctx, fzbuf, fmt_W); + } + if (col_size > 0) + { + switch (col_size) + { + case 1: + fz_buffer_printf(ctx, fzbuf, "%f g\n", col[0]); + break; + case 3: + fz_buffer_printf(ctx, fzbuf, "%f %f %f rg\n", col[0], col[1], col[2]); + break; + case 4: + fz_buffer_printf(ctx, fzbuf, "%f %f %f %f k\n", col[0], col[1], col[2], col[3]); + break; + default: + break; + } + } + if (tm) + fz_buffer_printf(ctx, fzbuf, fmt_Tm, tm->a, tm->b, tm->c, tm->d, tm->e, tm->f); + + fz_buffer_printf(ctx, fzbuf, fmt_re, rect->x0, rect->y0, rect->x1 - rect->x0, rect->y1 - rect->y0); + fz_buffer_printf(ctx, fzbuf, fmt_f); +} + static void fzbuf_print_text(fz_context *ctx, fz_buffer *fzbuf, const fz_rect *clip, pdf_obj *col, font_info *font_rec, const fz_matrix *tm, char *text) { fz_buffer_printf(ctx, fzbuf, fmt_q); @@ -521,7 +556,7 @@ static void text_splitter_retry(text_splitter *splitter) } } -static void fzbuf_print_text_start(fz_context *ctx, fz_buffer *fzbuf, const fz_rect *clip, pdf_obj *col, font_info *font, const fz_matrix *tm) +static void fzbuf_print_text_start1(fz_context *ctx, fz_buffer *fzbuf, const fz_rect *clip, pdf_obj *col) { fz_buffer_printf(ctx, fzbuf, fmt_Tx_BMC); fz_buffer_printf(ctx, fzbuf, fmt_q); @@ -540,7 +575,10 @@ static void fzbuf_print_text_start(fz_context *ctx, fz_buffer *fzbuf, const fz_r fz_buffer_printf(ctx, fzbuf, fmt_n); } } +} +static void fzbuf_print_text_start2(fz_context *ctx, fz_buffer *fzbuf, font_info *font, const fz_matrix *tm) +{ fz_buffer_printf(ctx, fzbuf, fmt_BT); pdf_fzbuf_print_da(ctx, fzbuf, &font->da_rec); @@ -662,7 +700,8 @@ static fz_buffer *create_text_appearance(fz_context *ctx, pdf_document *doc, con tm.e = rect.x0; tm.f = rect.y1 - (1.0+ascent-descent)*fontsize*splitter.scale/2.0; - fzbuf_print_text_start(ctx, fzbuf, &rect, info->col, &info->font_rec, &tm); + fzbuf_print_text_start1(ctx, fzbuf, &rect, info->col); + fzbuf_print_text_start2(ctx, fzbuf, &info->font_rec, &tm); fz_buffer_cat(ctx, fzbuf, fztmp); @@ -679,7 +718,8 @@ static fz_buffer *create_text_appearance(fz_context *ctx, pdf_document *doc, con fzbuf = fz_new_buffer(ctx, 0); - fzbuf_print_text_start(ctx, fzbuf, &rect, info->col, &info->font_rec, &tm); + fzbuf_print_text_start1(ctx, fzbuf, &rect, info->col); + fzbuf_print_text_start2(ctx, fzbuf, &info->font_rec, &tm); for (i = 0; i < n; i++) fzbuf_print_text_word(ctx, fzbuf, i == 0 ? init_skip : comb_width, 0.0, text+i, 1); @@ -1134,6 +1174,208 @@ void pdf_update_text_appearance(fz_context *ctx, pdf_document *doc, pdf_obj *obj } } +void pdf_update_listbox_appearance(fz_context *ctx, pdf_document *doc, pdf_obj *obj) +{ + text_widget_info info; + pdf_xobject *form = NULL; + fz_buffer *fzbuf = NULL; + fz_matrix tm; + fz_rect clip_rect; + fz_rect fill_rect; + int has_tm; + pdf_obj *valarr; + pdf_obj *optarr; + char *text; + int n, m, i, j; + char **opts = NULL; + char **vals = NULL; + int *sel_indices = NULL; + char **pos; + char *val_sel; + int index = -1; + float height, width; + float ascent, descent, lineheight; + int variable; + int fontsize; + float items_height; + fz_rect bbox; + int num_sel = 0; + int found_count; + int val_opt_ok = 1; + float color[4]; + + memset(&info, 0, sizeof(info)); + + fz_var(info); + fz_var(form); + fz_var(fzbuf); + fz_var(opts); + fz_var(vals); + fz_var(sel_indices); + fz_try(ctx) + { + optarr = pdf_dict_get(ctx, obj, PDF_NAME_Opt); + n = pdf_array_len(ctx, optarr); + opts = (char **)fz_malloc(ctx, n * sizeof(*opts)); + vals = (char **)fz_malloc(ctx, n * sizeof(*vals)); + sel_indices = (int*)fz_malloc(ctx, n * sizeof(int)); + for (i = 0; i < n; i++) + { + m = pdf_array_len(ctx, pdf_array_get(ctx, optarr, i)); + if (m == 2) + { + vals[i] = pdf_to_str_buf(ctx, pdf_array_get(ctx, pdf_array_get(ctx, optarr, i), 0)); + opts[i] = pdf_to_str_buf(ctx, pdf_array_get(ctx, pdf_array_get(ctx, optarr, i), 1)); + } + else + { + opts[i] = pdf_to_str_buf(ctx, pdf_array_get(ctx, optarr, i)); + val_opt_ok = 0; + } + } + + /* If ANY of the entries are not an array then just use the opts not + the vals. */ + if (val_opt_ok) + pos = vals; + else + pos = opts; + + get_text_widget_info(ctx, doc, obj, &info); + form = load_or_create_form(ctx, doc, obj, &clip_rect); + has_tm = get_matrix(ctx, doc, form, info.q, &tm); + + /* See which ones are selected */ + valarr = pdf_get_inheritable(ctx, doc, obj, PDF_NAME_V); + if (pdf_is_array(ctx, valarr)) + { + num_sel = pdf_array_len(ctx, valarr); + /* Multiple selected */ + found_count = 0; + for (i = 0; i < num_sel; i++) + { + text = pdf_to_str_buf(ctx, pdf_array_get(ctx, valarr, i)); + /* See if we can find it. */ + index = -1; + for (j = 0; j < n; j++) + { + if (!strcmp(text, pos[j])) + { + index = j; + break; + } + } + if (index > -1) + { + sel_indices[found_count] = index; + found_count += 1; + } + } + num_sel = found_count; + } + else + { + /* One or none selected */ + text = pdf_to_str_buf(ctx, valarr); + num_sel = 0; + if (text) + { + index = -1; + for (i = 0; i < n; i++) + { + if (!strcmp(text, pos[i])) + { + index = i; + break; + } + } + if (index > -1) + { + num_sel = 1; + sel_indices[0] = index; + } + } + } + + if (clip_rect.x1 - clip_rect.x0 > 3.0 && clip_rect.y1 - clip_rect.y0 > 3.0) + { + clip_rect.x0 += 1.0; + clip_rect.x1 -= 1.0; + clip_rect.y0 += 1.0; + clip_rect.y1 -= 1.0; + } + height = clip_rect.y1 - clip_rect.y0; + width = clip_rect.x1 - clip_rect.x0; + variable = (info.font_rec.da_rec.font_size == 0); + fontsize = variable + ? (info.multiline ? 14.0 : height / info.font_rec.lineheight) + : info.font_rec.da_rec.font_size; + + /* Get the ascent, descent across the items list. */ + ascent = 0; + descent = 0; + info.font_rec.da_rec.font_size = 1; + for (i = 0; i < n; i++) + { + measure_text(ctx, doc, &(info.font_rec), &fz_identity, opts[i], &bbox); + descent = fz_min(-bbox.y0, descent); + ascent = fz_max(bbox.y1, ascent); + } + info.font_rec.da_rec.font_size = fontsize; + lineheight = ascent - descent; + + /* Check if all items will fit. If not, then place the "selected" item + at the top of our widget rect. */ + items_height = n * fontsize * lineheight; + if (items_height <= height || !num_sel) + fz_translate(&tm, clip_rect.x0, clip_rect.y1 - lineheight * fontsize); + else + fz_translate(&tm, clip_rect.x0, clip_rect.y1 + (sel_indices[0] - 1) * lineheight * fontsize); + + fzbuf = fz_new_buffer(ctx, 0); + /* Start the marked content */ + fzbuf_print_text_start1(ctx, fzbuf, &clip_rect, NULL); + /* Add the selection rects */ + if (num_sel > 0) + { + color[0] = LIST_SEL_COLOR_R; + color[1] = LIST_SEL_COLOR_G; + color[2] = LIST_SEL_COLOR_B; + fill_rect.x0 = 0.0; + fill_rect.x1 = width; + for (i = 0; i < num_sel; i++) + { + fill_rect.y0 = height - fontsize * lineheight * (sel_indices[i] + 1); + fill_rect.y1 = fill_rect.y0 + lineheight * fontsize; + fzbuf_print_rect_fill(ctx, fzbuf, NULL, color, 3, NULL, &fill_rect); + } + } + /* Continue with text related details */ + fzbuf_print_text_start2(ctx, fzbuf, &info.font_rec, &tm); + /* And now finish with the text content */ + for (i = 0; i < n; i++) + { + fzbuf_print_text_word(ctx, fzbuf, 0.0, i == 0 ? 0 : -fontsize * + lineheight, opts[i], strlen(opts[i])); + } + fzbuf_print_text_end(ctx, fzbuf); + update_marked_content(ctx, doc, form, fzbuf); + } + fz_always(ctx) + { + fz_free(ctx, opts); + fz_free(ctx, vals); + fz_free(ctx, sel_indices); + pdf_drop_xobject(ctx, form); + fz_drop_buffer(ctx, fzbuf); + font_info_fin(ctx, &info.font_rec); + } + fz_catch(ctx) + { + fz_warn(ctx, "update_text_appearance failed"); + } +} + void pdf_update_combobox_appearance(fz_context *ctx, pdf_document *doc, pdf_obj *obj) { text_widget_info info; @@ -2234,9 +2476,9 @@ void pdf_update_appearance(fz_context *ctx, pdf_document *doc, pdf_annot *annot) pdf_update_pushbutton_appearance(ctx, doc, obj); break; case PDF_WIDGET_TYPE_LISTBOX: + pdf_update_listbox_appearance(ctx, doc, obj); + break; case PDF_WIDGET_TYPE_COMBOBOX: - /* Treating listbox and combobox identically for now, - * and the behaviour is most appropriate for a combobox */ pdf_update_combobox_appearance(ctx, doc, obj); break; } diff --git a/source/pdf/pdf-form.c b/source/pdf/pdf-form.c index dcb08bc7..ce51ae4f 100644 --- a/source/pdf/pdf-form.c +++ b/source/pdf/pdf-form.c @@ -1276,26 +1276,35 @@ int pdf_text_widget_set_text(fz_context *ctx, pdf_document *doc, pdf_widget *tw, return accepted; } -int pdf_choice_widget_options(fz_context *ctx, pdf_document *doc, pdf_widget *tw, char *opts[]) +/* Get either the listed value or the export value. */ +int pdf_choice_widget_options(fz_context *ctx, pdf_document *doc, pdf_widget *tw, int exportval, char *opts[]) { pdf_annot *annot = (pdf_annot *)tw; pdf_obj *optarr; - int i, n; + int i, n, m; if (!annot) return 0; optarr = pdf_dict_get(ctx, annot->obj, PDF_NAME_Opt); n = pdf_array_len(ctx, optarr); - + if (opts) { for (i = 0; i < n; i++) { - opts[i] = pdf_to_str_buf(ctx, pdf_array_get(ctx, optarr, i)); + m = pdf_array_len(ctx, pdf_array_get(ctx, optarr, i)); + /* If it is a two element array, the second item is the one that we want + if we want the listing value */ + if (m == 2) + if (exportval) + opts[i] = pdf_to_str_buf(ctx, pdf_array_get(ctx, pdf_array_get(ctx, optarr, i), 0)); + else + opts[i] = pdf_to_str_buf(ctx, pdf_array_get(ctx, pdf_array_get(ctx, optarr, i), 1)); + else + opts[i] = pdf_to_str_buf(ctx, pdf_array_get(ctx, optarr, i)); } } - return n; } |