summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Gardiner <paulg.artifex@glidos.net>2012-08-31 09:36:08 +0100
committerPaul Gardiner <paulg.artifex@glidos.net>2012-08-31 17:06:51 +0100
commit01ecb79f9bcdeb9280554aff2e26218c07d088dd (patch)
tree44e3ac51e7da2d990dea74cfb4af2ef61c573134
parent48f3bc177ff70e855bd7d602e38351d873bae999 (diff)
downloadmupdf-01ecb79f9bcdeb9280554aff2e26218c07d088dd.tar.xz
Forms: implement javascript doc.resetForm method
-rw-r--r--pdf/mupdf-internal.h1
-rw-r--r--pdf/pdf_form.c71
-rw-r--r--pdf/pdf_js.c144
3 files changed, 197 insertions, 19 deletions
diff --git a/pdf/mupdf-internal.h b/pdf/mupdf-internal.h
index d3326fb4..eec45acd 100644
--- a/pdf/mupdf-internal.h
+++ b/pdf/mupdf-internal.h
@@ -575,6 +575,7 @@ void pdf_field_setFillColor(pdf_document *doc, pdf_obj *field, pdf_obj *col);
void pdf_field_setTextColor(pdf_document *doc, pdf_obj *field, pdf_obj *col);
int pdf_field_getDisplay(pdf_document *doc, pdf_obj *field);
void pdf_field_setDisplay(pdf_document *doc, pdf_obj *field, int d);
+void pdf_field_reset(pdf_document *doc, pdf_obj *field);
/*
* Page tree, pages and related objects
diff --git a/pdf/pdf_form.c b/pdf/pdf_form.c
index 88aba204..451ba0c0 100644
--- a/pdf/pdf_form.c
+++ b/pdf/pdf_form.c
@@ -1462,6 +1462,77 @@ static void update_pushbutton_appearance(pdf_document *doc, pdf_obj *obj)
}
}
+void pdf_field_reset(pdf_document *doc, pdf_obj *field)
+{
+ fz_context *ctx = doc->ctx;
+ /* Descend through the hierarchy, setting V to DV where
+ * ever DV is present, and deleting V where DV is not.
+ * FIXME: we assume for now that V has not been set unequal
+ * to DV higher in the hierarchy than "field".
+ *
+ * At the bottom of the hierarchy we may find widget annotations
+ * that aren't also fields, but DV and V will not be present in their
+ * dictionaries, and attempts to remove V will be harmless. */
+ pdf_obj *dv = pdf_dict_gets(field, "DV");
+ pdf_obj *kids = pdf_dict_gets(field, "Kids");
+
+ if (dv)
+ pdf_dict_puts(field, "V", dv);
+ else
+ pdf_dict_dels(field, "V");
+
+ if (kids)
+ {
+ int i, n = pdf_array_len(kids);
+
+ for (i = 0; i < n; i++)
+ pdf_field_reset(doc, pdf_array_get(kids, i));
+ }
+ else
+ {
+ /* The leaves of the tree are widget annotations
+ * In some cases we need to update the appearance state;
+ * in others we need to mark the field as dirty so that
+ * the appearance stream will be regenerated. */
+ switch (pdf_field_getType(doc, field))
+ {
+ case FZ_WIDGET_TYPE_RADIOBUTTON:
+ case FZ_WIDGET_TYPE_CHECKBOX:
+ {
+ pdf_obj *leafv = get_inheritable(doc, field, "V");
+
+ if (leafv)
+ pdf_keep_obj(leafv);
+ else
+ leafv = pdf_new_name(ctx, "Off");
+
+ fz_try(ctx)
+ {
+ pdf_dict_puts(field, "AS", leafv);
+ }
+ fz_always(ctx)
+ {
+ pdf_drop_obj(leafv);
+ }
+ fz_catch(ctx)
+ {
+ fz_rethrow(ctx);
+ }
+ }
+ break;
+
+ case FZ_WIDGET_TYPE_PUSHBUTTON:
+ break;
+
+ default:
+ pdf_field_mark_dirty(ctx, field);
+ break;
+ }
+ }
+
+ doc->dirty = 1;
+}
+
static void reset_field(pdf_document *doc, pdf_obj *obj)
{
fz_context *ctx = doc->ctx;
diff --git a/pdf/pdf_js.c b/pdf/pdf_js.c
index f533b834..fb2f34cb 100644
--- a/pdf/pdf_js.c
+++ b/pdf/pdf_js.c
@@ -324,16 +324,38 @@ static char *utf8_to_pdf(fz_context *ctx, char *utf8)
return pdf;
}
+static pdf_obj *get_field(pdf_obj *form, char *name)
+{
+ char *dot;
+ char *namep;
+ pdf_obj *dict = NULL;
+ int len;
+
+ /* Process the fully qualified field name which has
+ * the partial names delimited by '.'. Pretend there
+ * was a preceding '.' to simplify the loop */
+ dot = name - 1;
+
+ while (dot && form)
+ {
+ namep = dot + 1;
+ dot = strchr(namep, '.');
+ len = dot ? dot - namep : strlen(namep);
+ dict = find_field(form, namep, len);
+ if (dot)
+ form = pdf_dict_gets(dict, "Kids");
+ }
+
+ return dict;
+}
+
static pdf_jsimp_obj *doc_getField(void *jsctx, void *obj, int argc, pdf_jsimp_obj *args[])
{
pdf_js *js = (pdf_js *)jsctx;
fz_context *ctx = js->doc->ctx;
- pdf_obj *arr = js->form;
pdf_obj *dict = NULL;
- int len;
- char *utf8, *dot;
+ char *utf8;
char *name = NULL;
- char *namep;
if (argc != 1)
return NULL;
@@ -347,21 +369,7 @@ static pdf_jsimp_obj *doc_getField(void *jsctx, void *obj, int argc, pdf_jsimp_o
if (utf8)
{
name = utf8_to_pdf(ctx, utf8);
-
- /* Process the fully qualified field name which has
- * the partial names delimited by '.'. Pretend there
- * was a preceding '.' to simplify the loop */
- dot = name - 1;
-
- while (dot && arr)
- {
- namep = dot + 1;
- dot = strchr(namep, '.');
- len = dot ? dot - namep : strlen(namep);
- dict = find_field(arr, namep, len);
- if (dot)
- arr = pdf_dict_gets(dict, "Kids");
- }
+ dict = get_field(js->form, name);
}
}
fz_always(ctx)
@@ -377,6 +385,103 @@ static pdf_jsimp_obj *doc_getField(void *jsctx, void *obj, int argc, pdf_jsimp_o
return dict ? pdf_jsimp_new_obj(js->imp, js->fieldtype, dict) : NULL;
}
+static void reset_field(pdf_js *js, pdf_jsimp_obj *item)
+{
+ fz_context *ctx = js->doc->ctx;
+ char *name = NULL;
+ char *utf8 = pdf_jsimp_toString(js->imp, item);
+
+ if (utf8)
+ {
+ pdf_obj *field;
+
+ fz_var(name);
+ fz_try(ctx)
+ {
+ name = utf8_to_pdf(ctx, utf8);
+ field = get_field(js->form, name);
+ if (field)
+ pdf_field_reset(js->doc, field);
+ }
+ fz_always(ctx)
+ {
+ fz_free(ctx, name);
+ }
+ fz_catch(ctx)
+ {
+ fz_rethrow(ctx);
+ }
+ }
+}
+
+static pdf_jsimp_obj *doc_resetForm(void *jsctx, void *obj, int argc, pdf_jsimp_obj *args[])
+{
+ pdf_js *js = (pdf_js *)jsctx;
+ fz_context *ctx = js->doc->ctx;
+ pdf_jsimp_obj *arr = NULL;
+ pdf_jsimp_obj *elem = NULL;
+
+ switch (argc)
+ {
+ case 0:
+ break;
+ case 1:
+ switch (pdf_jsimp_toType(js->imp, args[0]))
+ {
+ case JS_TYPE_NULL:
+ break;
+ case JS_TYPE_ARRAY:
+ arr = args[0];
+ break;
+ case JS_TYPE_STRING:
+ elem = args[0];
+ break;
+ default:
+ return NULL;
+ }
+ break;
+ default:
+ return NULL;
+ }
+
+ fz_try(ctx)
+ {
+ if(arr)
+ {
+ /* An array of fields has been passed in. Call
+ * pdf_reset_field on each */
+ int i, n = pdf_jsimp_array_len(js->imp, arr);
+
+ for (i = 0; i < n; i++)
+ {
+ pdf_jsimp_obj *item = pdf_jsimp_array_item(js->imp, arr, i);
+
+ if (item)
+ reset_field(js, item);
+
+ }
+ }
+ else if (elem)
+ {
+ reset_field(js, elem);
+ }
+ else
+ {
+ /* No argument or null passed in means reset all. */
+ int i, n = pdf_array_len(js->form);
+
+ for (i = 0; i < n; i++)
+ pdf_field_reset(js->doc, pdf_array_get(js->form, i));
+ }
+ }
+ fz_catch(ctx)
+ {
+ fz_warn(ctx, "doc_resetForm failed: %s", ctx->error->message);
+ }
+
+ return NULL;
+}
+
static void declare_dom(pdf_js *js)
{
pdf_jsimp *imp = js->imp;
@@ -384,6 +489,7 @@ static void declare_dom(pdf_js *js)
/* Create the document type */
js->doctype = pdf_jsimp_new_type(imp, NULL);
pdf_jsimp_addmethod(imp, js->doctype, "getField", doc_getField);
+ pdf_jsimp_addmethod(imp, js->doctype, "resetForm", doc_resetForm);
pdf_jsimp_addproperty(imp, js->doctype, "event", doc_getEvent, doc_setEvent);
pdf_jsimp_addproperty(imp, js->doctype, "app", doc_getApp, doc_setApp);