[poppler] 3 commits - poppler/Annot.cc poppler/Form.cc poppler/Form.h

Carlos Garcia Campos carlosgc at kemper.freedesktop.org
Sun Apr 3 04:15:21 PDT 2011


 poppler/Annot.cc |    4 
 poppler/Form.cc  |  317 +++++++++++++++++++++++++++++++++++--------------------
 poppler/Form.h   |   44 ++++++-
 3 files changed, 242 insertions(+), 123 deletions(-)

New commits:
commit d6786edc2549164214342a50782b72c2fd904b63
Author: Carlos Garcia Campos <carlosgc at gnome.org>
Date:   Sun Apr 3 13:11:18 2011 +0200

    forms: Remove unused parameter

diff --git a/poppler/Form.cc b/poppler/Form.cc
index fdc405f..b9a4a02 100644
--- a/poppler/Form.cc
+++ b/poppler/Form.cc
@@ -205,7 +205,7 @@ void FormWidgetButton::setAppearanceState(char *state) {
   widget->setAppearanceState(state);
 }
 
-void FormWidgetButton::setState (GBool astate, GBool calledByParent)
+void FormWidgetButton::setState (GBool astate)
 {
   //pushButtons don't have state
   if (parent->getButtonType() == formButtonPush)
diff --git a/poppler/Form.h b/poppler/Form.h
index 16bbe26..0cfc95b 100644
--- a/poppler/Form.h
+++ b/poppler/Form.h
@@ -148,7 +148,7 @@ public:
 
   FormButtonType getButtonType() const;
   
-  void setState (GBool state, GBool calledByParent=gFalse);
+  void setState (GBool state);
   GBool getState ();
 
   char* getOnStr();
commit 62692ff381f3b7907b330bfc2019416ed058ea46
Author: Carlos Garcia Campos <carlosgc at gnome.org>
Date:   Sun Apr 3 13:01:42 2011 +0200

    forms: rework the way form fields tree is built
    
    Now we build the tree as described by the doc, without ignoring
    container fields and always creating a child widget for composed (field
    + annot) dictionaries. The way check and radio buttons are set has been
    reworked too, since now it's possible to have a set of buttons where
    children are not widgets, but form fields with a child widget.

diff --git a/poppler/Annot.cc b/poppler/Annot.cc
index 7d1136c..fe8cb2d 100644
--- a/poppler/Annot.cc
+++ b/poppler/Annot.cc
@@ -3684,9 +3684,7 @@ void AnnotWidget::drawFormFieldButton(GfxResources *resources, GooString *da) {
   switch (static_cast<FormFieldButton *>(field)->getButtonType()) {
   case formButtonRadio: {
     //~ Acrobat doesn't draw a caption if there is no AP dict (?)
-    char *buttonState = static_cast<FormFieldButton *>(field)->getAppearanceState();
-    if (buttonState && appearState && appearState->cmp(buttonState) == 0 &&
-        strcmp (buttonState, "Off") != 0) {
+    if (appearState && appearState->cmp("Off") != 0) {
       if (caption) {
         drawText(caption, da, resources, gFalse, 0, fieldQuadCenter,
                  gFalse, gTrue);
diff --git a/poppler/Form.cc b/poppler/Form.cc
index 000381b..fdc405f 100644
--- a/poppler/Form.cc
+++ b/poppler/Form.cc
@@ -221,7 +221,7 @@ void FormWidgetButton::setState (GBool astate, GBool calledByParent)
 
 GBool FormWidgetButton::getState ()
 {
-  return (onStr && parent->getAppearanceState() && strcmp(parent->getAppearanceState(), onStr->getCString()) == 0);
+  return onStr ? parent->getState(onStr->getCString()) : gFalse;
 }
 
 void FormWidgetButton::setNumSiblingsID (int i)
@@ -428,13 +428,14 @@ FormWidgetSignature::FormWidgetSignature(XRef *xrefA, Object *aobj, unsigned num
 // FormField
 //========================================================================
 
-FormField::FormField(XRef* xrefA, Object *aobj, const Ref& aref, std::set<int> *usedParents, FormFieldType ty)
+FormField::FormField(XRef* xrefA, Object *aobj, const Ref& aref, FormField *parentA, std::set<int> *usedParents, FormFieldType ty)
 {
   xref = xrefA;
   aobj->copy(&obj);
   Dict* dict = obj.getDict();
   ref.num = ref.gen = 0;
   type = ty;
+  parent = parentA;
   numChildren = 0;
   children = NULL;
   terminal = false;
@@ -451,65 +452,60 @@ FormField::FormField(XRef* xrefA, Object *aobj, const Ref& aref, std::set<int> *
   Object obj1;
   //childs
   if (dict->lookup("Kids", &obj1)->isArray()) {
-    Array *array = obj1.getArray();
-    int length = array->getLength();
     // Load children
-    for(int i=0; i<length; i++) { 
-      Object obj2,obj3;
-      array->get(i, &obj2);
-      if (!obj2.isDict ()) {
-	      error (-1, "Reference to an invalid or non existant object");
-	      obj2.free();
-	      continue;
+    for (int i = 0 ; i < obj1.arrayGetLength(); i++) {
+      Object childRef, childObj;
+
+      if (!obj1.arrayGetNF(i, &childRef)->isRef()) {
+        error (-1, "Invalid form field renference");
+        childRef.free();
+        continue;
       }
-      Object childRef;
-      array->getNF(i, &childRef);
-      if (childRef.isRef()) {
-        const Ref ref = childRef.getRef();
-        if (usedParents->find(ref.num) == usedParents->end()) {
-          //field child
-          if (dict->lookup ("FT", &obj3)->isName()) {
-            // If I'm not a generic container field and my children
-            // are widgets, create widgets for them
-            Object obj4;
-
-            if (obj2.dictLookup("Subtype",&obj4)->isName()) {
-              _createWidget(&obj2, childRef.getRef());
-            }
-            obj4.free();
-          } else if(obj2.dictLookup("FT", &obj3)->isName() || obj2.dictLookup("Kids", &obj3)->isArray()) {
-            std::set<int> usedParentsAux = *usedParents;
-            usedParentsAux.insert(ref.num);
-            if(terminal) error(-1, "Field can't have both Widget AND Field as kids\n");
-
-            numChildren++;
-            children = (FormField**)greallocn(children, numChildren, sizeof(FormField*));
-
-            obj3.free();
-            children[numChildren-1] = Form::createFieldFromDict (&obj2, xref, childRef.getRef(), &usedParentsAux);
-          }
-          // 1 - we will handle 'collapsed' fields (field + annot in the same dict)
-          // as if the annot was in the Kids array of the field
-          else if (obj2.dictLookup("Subtype",&obj3)->isName()) {
-            _createWidget(&obj2, childRef.getRef());
-          }
+      if (!obj1.arrayGet(i, &childObj)->isDict()) {
+        error (-1, "Form field child is not a dictionary");
+        childObj.free();
+        childRef.free();
+        continue;
+      }
+
+      const Ref ref = childRef.getRef();
+      if (usedParents->find(ref.num) == usedParents->end()) {
+        Object obj2, obj3;
+        // Field child: it could be a form field or a widget or composed dict
+        if (childObj.dictLookupNF("Parent", &obj2)->isRef() || childObj.dictLookup("Parent", &obj3)->isDict()) {
+          // Child is a form field or composed dict
+          // We create the field, if it's composed
+          // it will create the widget as a child
+          std::set<int> usedParentsAux = *usedParents;
+          usedParentsAux.insert(ref.num);
+          obj2.free();
           obj3.free();
-        } else {
-          error(-1, "Found loop in FormField creation");
+
+          if (terminal) {
+            error(-1, "Field can't have both Widget AND Field as kids\n");
+            continue;
+          }
+
+          numChildren++;
+          children = (FormField**)greallocn(children, numChildren, sizeof(FormField*));
+          children[numChildren - 1] = Form::createFieldFromDict(&childObj, xref, ref, this, &usedParentsAux);
+        } else if (childObj.dictLookup("Subtype", &obj2)->isName("Widget")) {
+          // Child is a widget annotation
+          _createWidget(&childObj, ref);
         }
-      } else {
-        error(-1, "FormField child is not a Ref as expected");
+        obj2.free();
+        obj3.free();
       }
-      obj2.free();
+      childObj.free();
+      childRef.free();
     }
+  } else {
+    // No children, if it's a composed dict, create the child widget
+    obj1.free();
+    if (dict->lookup("Subtype", &obj1)->isName("Widget"))
+      _createWidget(&obj, ref);
+    obj1.free();
   }
-  obj1.free();
-  // As said in 1, if this is a 'collapsed' field, behave like if we had a
-  // child annot
-  if (dict->lookup("Subtype", &obj1)->isName()) {
-    _createWidget(&obj, ref);
-  }
-  obj1.free();
 
   //flags
   if (Form::fieldLookup(dict, "Ff", &obj1)->isInt()) {
@@ -620,6 +616,10 @@ void FormField::createWidgetAnnotations(Catalog *catalog) {
   }
 }
 
+GBool FormField::isModified() const {
+  return modified ? gTrue : parent ? parent->isModified() : gFalse;
+}
+
 void FormField::_createWidget (Object *obj, Ref aref)
 {
   terminal = true;
@@ -712,12 +712,13 @@ GooString* FormField::getFullyQualifiedName() {
 //------------------------------------------------------------------------
 // FormFieldButton
 //------------------------------------------------------------------------
-FormFieldButton::FormFieldButton(XRef *xrefA, Object *aobj, const Ref& ref, std::set<int> *usedParents)
-	: FormField(xrefA, aobj, ref, usedParents, formButton)
+FormFieldButton::FormFieldButton(XRef *xrefA, Object *aobj, const Ref& ref, FormField *parent, std::set<int> *usedParents)
+  : FormField(xrefA, aobj, ref, parent, usedParents, formButton)
 {
   Dict* dict = obj.getDict();
   active_child = -1;
   noAllOff = false;
+  appearanceState.initNull();
 
   Object obj1;
   btype = formButtonCheck; 
@@ -737,8 +738,11 @@ FormFieldButton::FormFieldButton(XRef *xrefA, Object *aobj, const Ref& ref, std:
     } 
   }
 
-  if (btype != formButtonPush)
-    Form::fieldLookup(dict, "V", &appearanceState);
+  if (btype != formButtonPush) {
+    // Even though V is inheritable we are interested in the value of this
+    // field, if not present it's probably because it's a button in a set.
+    dict->lookup("V", &appearanceState);
+  }
 }
 
 #ifdef DEBUG_FORMS
@@ -792,57 +796,68 @@ GBool FormFieldButton::setState(char *state)
 
   // A check button could behave as a radio button
   // when it's in a set of more than 1 buttons
-  if (btype == formButtonRadio || btype == formButtonCheck) {
-    GBool isOn = strcmp(state, "Off") != 0;
+  if (btype != formButtonRadio && btype != formButtonCheck)
+    return gFalse;
 
-    if (!isOn && noAllOff)
-      return gFalse; //don't allow to set all radio to off
+  if (terminal && parent && parent->getType() == formButton && appearanceState.isNull()) {
+    // It's button in a set, set state on parent
+    if (static_cast<FormFieldButton*>(parent)->setState(state)) {
+      modified = gTrue;
+      return gTrue;
+    }
+    return gFalse;
+  }
 
-    char *current = getAppearanceState();
+  GBool isOn = strcmp(state, "Off") != 0;
 
-    if (isOn) {
-      char *current = getAppearanceState();
-      GBool currentFound = gFalse, newFound = gFalse;
+  if (!isOn && noAllOff)
+    return gFalse; // Don't allow to set all radio to off
 
-      for (int i = 0; i < numChildren; i++) {
-        FormWidgetButton *widget = static_cast<FormWidgetButton*>(widgets[i]);
+  char *current = getAppearanceState();
+  GBool currentFound = gFalse, newFound = gFalse;
 
-        if (!widget->getOnStr())
-          continue;
+  for (int i = 0; i < numChildren; i++) {
+    FormWidgetButton *widget;
+
+    // If radio button is a terminal field we want the widget at i, but
+    // if it's not terminal, the child widget is a composed dict, so
+    // we want the ony child widget of the children at i
+    if (terminal)
+      widget = static_cast<FormWidgetButton*>(widgets[i]);
+    else
+      widget = static_cast<FormWidgetButton*>(children[i]->getWidget(0));
+
+    if (!widget->getOnStr())
+      continue;
+
+    char *onStr = widget->getOnStr();
+    if (current && strcmp(current, onStr) == 0) {
+      widget->setAppearanceState("Off");
+      if (!isOn)
+        break;
+      currentFound = gTrue;
+    }
 
-        char *onStr = widget->getOnStr();
-        if (current && strcmp(current, onStr) == 0) {
-          widget->setAppearanceState("Off");
-          currentFound = gTrue;
-        }
+    if (isOn && strcmp(state, onStr) == 0) {
+      widget->setAppearanceState(state);
+      newFound = gTrue;
+    }
 
-        if (strcmp(state, onStr) == 0) {
-          widget->setAppearanceState(state);
-          newFound = gTrue;
-        }
+    if (currentFound && newFound)
+      break;
+  }
 
-        if (currentFound && newFound)
-          break;
-      }
-    } else {
-      for (int i = 0; i < numChildren; i++) {
-        FormWidgetButton *widget = static_cast<FormWidgetButton*>(widgets[i]);
+  updateState(state);
+  modified = gTrue;
 
-        if (!widget->getOnStr())
-          continue;
+  return gTrue;
+}
 
-        char *onStr = widget->getOnStr();
-        if (current && strcmp(current, onStr) == 0) {
-          widget->setAppearanceState("Off");
-          break;
-        }
-      }
-    }
-    updateState(state);
-    modified = gTrue;
-  }
+GBool FormFieldButton::getState(char *state) {
+  if (appearanceState.isName(state))
+    return gTrue;
 
-  return gTrue;
+  return (parent && parent->getType() == formButton) ? static_cast<FormFieldButton*>(parent)->getState(state) : gFalse;
 }
 
 void FormFieldButton::updateState(char *state) {
@@ -864,8 +879,8 @@ FormFieldButton::~FormFieldButton()
 //------------------------------------------------------------------------
 // FormFieldText
 //------------------------------------------------------------------------
-FormFieldText::FormFieldText(XRef *xrefA, Object *aobj, const Ref& ref, std::set<int> *usedParents)
-	: FormField(xrefA, aobj, ref, usedParents, formText)
+FormFieldText::FormFieldText(XRef *xrefA, Object *aobj, const Ref& ref, FormField *parent, std::set<int> *usedParents)
+  : FormField(xrefA, aobj, ref, parent, usedParents, formText)
 {
   Dict* dict = obj.getDict();
   Object obj1;
@@ -957,8 +972,8 @@ FormFieldText::~FormFieldText()
 //------------------------------------------------------------------------
 // FormFieldChoice
 //------------------------------------------------------------------------
-FormFieldChoice::FormFieldChoice(XRef *xrefA, Object *aobj, const Ref& ref, std::set<int> *usedParents)
-	: FormField(xrefA, aobj, ref, usedParents, formChoice)
+FormFieldChoice::FormFieldChoice(XRef *xrefA, Object *aobj, const Ref& ref, FormField *parent, std::set<int> *usedParents)
+  : FormField(xrefA, aobj, ref, parent, usedParents, formChoice)
 {
   numChoices = 0;
   choices = NULL;
@@ -1198,8 +1213,8 @@ GooString *FormFieldChoice::getSelectedChoice() {
 //------------------------------------------------------------------------
 // FormFieldSignature
 //------------------------------------------------------------------------
-FormFieldSignature::FormFieldSignature(XRef *xrefA, Object *dict, const Ref& ref, std::set<int> *usedParents)
-	: FormField(xrefA, dict, ref, usedParents, formSignature)
+FormFieldSignature::FormFieldSignature(XRef *xrefA, Object *dict, const Ref& ref, FormField *parent, std::set<int> *usedParents)
+  : FormField(xrefA, dict, ref, parent, usedParents, formSignature)
 {
 }
 
@@ -1287,7 +1302,7 @@ Form::Form(XRef *xrefA, Object* acroFormA)
       }
 
       std::set<int> usedParents;
-      rootFields[numFields++] = createFieldFromDict (&obj2, xrefA, oref.getRef(), &usedParents);
+      rootFields[numFields++] = createFieldFromDict (&obj2, xrefA, oref.getRef(), NULL, &usedParents);
 
       obj2.free();
       oref.free();
@@ -1352,21 +1367,21 @@ Object *Form::fieldLookup(Dict *field, char *key, Object *obj) {
   return ::fieldLookup(field, key, obj, &usedParents);
 }
 
-FormField *Form::createFieldFromDict (Object* obj, XRef *xrefA, const Ref& pref, std::set<int> *usedParents)
+FormField *Form::createFieldFromDict (Object* obj, XRef *xrefA, const Ref& pref, FormField *parent, std::set<int> *usedParents)
 {
     Object obj2;
     FormField *field;
 
     if (Form::fieldLookup(obj->getDict (), "FT", &obj2)->isName("Btn")) {
-      field = new FormFieldButton(xrefA, obj, pref, usedParents);
+      field = new FormFieldButton(xrefA, obj, pref, parent, usedParents);
     } else if (obj2.isName("Tx")) {
-      field = new FormFieldText(xrefA, obj, pref, usedParents);
+      field = new FormFieldText(xrefA, obj, pref, parent, usedParents);
     } else if (obj2.isName("Ch")) {
-      field = new FormFieldChoice(xrefA, obj, pref, usedParents);
+      field = new FormFieldChoice(xrefA, obj, pref, parent, usedParents);
     } else if (obj2.isName("Sig")) {
-      field = new FormFieldSignature(xrefA, obj, pref, usedParents);
+      field = new FormFieldSignature(xrefA, obj, pref, parent, usedParents);
     } else { //we don't have an FT entry => non-terminal field
-      field = new FormField(xrefA, obj, pref, usedParents);
+      field = new FormField(xrefA, obj, pref, parent, usedParents);
     }
     obj2.free();
 
diff --git a/poppler/Form.h b/poppler/Form.h
index 1ddddb5..16bbe26 100644
--- a/poppler/Form.h
+++ b/poppler/Form.h
@@ -256,7 +256,7 @@ protected:
 
 class FormField {
 public:
-  FormField(XRef* xrefa, Object *aobj, const Ref& aref, std::set<int> *usedParents, FormFieldType t=formUndef);
+  FormField(XRef* xrefa, Object *aobj, const Ref& aref, FormField *parent, std::set<int> *usedParents, FormFieldType t=formUndef);
 
   virtual ~FormField();
 
@@ -268,7 +268,7 @@ public:
   void setReadOnly (bool b) { readOnly = b; }
   bool isReadOnly () const { return readOnly; }
 
-  GBool isModified () const { return modified; }
+  GBool isModified () const;
 
   GooString* getDefaultAppearance() const { return defaultAppearance; }
   GBool hasTextQuadding() const { return hasQuadding; }
@@ -280,6 +280,7 @@ public:
   GooString *getFullyQualifiedName();
 
   FormWidget* findWidgetByRef (Ref aref);
+  FormWidget *getWidget(int i) { return terminal ? widgets[i] : NULL; }
 
   // only implemented in FormFieldButton
   virtual void fillChildrenSiblingsID ();
@@ -302,6 +303,7 @@ public:
   Object obj;
   XRef *xref;
   FormField **children;
+  FormField *parent;
   int numChildren;
   FormWidget **widgets;
   bool readOnly;
@@ -328,7 +330,7 @@ private:
 
 class FormFieldButton: public FormField {
 public:
-  FormFieldButton(XRef *xrefA, Object *dict, const Ref& ref, std::set<int> *usedParents);
+  FormFieldButton(XRef *xrefA, Object *dict, const Ref& ref, FormField *parent, std::set<int> *usedParents);
 
   FormButtonType getButtonType () { return btype; }
 
@@ -336,6 +338,7 @@ public:
 
   // returns gTrue if the state modification is accepted
   GBool setState (char *state);
+  GBool getState(char *state);
 
   char *getAppearanceState() { return appearanceState.isName() ? appearanceState.getName() : NULL; }
 
@@ -362,7 +365,7 @@ protected:
 
 class FormFieldText: public FormField {
 public:
-  FormFieldText(XRef *xrefA, Object *dict, const Ref& ref, std::set<int> *usedParents);
+  FormFieldText(XRef *xrefA, Object *dict, const Ref& ref, FormField *parent, std::set<int> *usedParents);
   
   GooString* getContent () { return content; }
   GooString* getContentCopy ();
@@ -400,7 +403,7 @@ protected:
 
 class FormFieldChoice: public FormField {
 public:
-  FormFieldChoice(XRef *xrefA, Object *aobj, const Ref& ref, std::set<int> *usedParents);
+  FormFieldChoice(XRef *xrefA, Object *aobj, const Ref& ref, FormField *parent, std::set<int> *usedParents);
 
   virtual ~FormFieldChoice();
 
@@ -469,7 +472,7 @@ protected:
 
 class FormFieldSignature: public FormField {
 public:
-  FormFieldSignature(XRef *xrefA, Object *dict, const Ref& ref, std::set<int> *usedParents);
+  FormFieldSignature(XRef *xrefA, Object *dict, const Ref& ref, FormField *parent, std::set<int> *usedParents);
 
   virtual ~FormFieldSignature();
 
@@ -495,7 +498,7 @@ public:
   
   /* Creates a new Field of the type specified in obj's dict.
      used in Form::Form and FormField::FormField */
-  static FormField *createFieldFromDict (Object* obj, XRef *xref, const Ref& aref, std::set<int> *usedParents);
+  static FormField *createFieldFromDict (Object* obj, XRef *xref, const Ref& aref, FormField *parent, std::set<int> *usedParents);
 
   Object *getObj () const { return acroForm; }
   GBool getNeedAppearances () const { return needAppearances; }
commit a6802301d9c3ab8bf68bd8821f562f8ecced8491
Author: Carlos Garcia Campos <carlosgc at gnome.org>
Date:   Mon Mar 28 17:42:37 2011 +0200

    forms: Add debug methods to print the forms tree

diff --git a/poppler/Form.cc b/poppler/Form.cc
index 158cd57..000381b 100644
--- a/poppler/Form.cc
+++ b/poppler/Form.cc
@@ -80,6 +80,12 @@ FormWidget::~FormWidget()
   obj.free ();
 }
 
+#ifdef DEBUG_FORMS
+void FormWidget::print(int indent) {
+  printf ("%*s+ (%d %d): [widget]\n", indent, "", ref.num, ref.gen);
+}
+#endif
+
 void FormWidget::createWidgetAnnotation(Catalog *catalog) {
   if (widget)
     return;
@@ -575,6 +581,26 @@ FormField::~FormField()
   delete fullyQualifiedName;
 }
 
+#ifdef DEBUG_FORMS
+void FormField::print(int indent)
+{
+  printf ("%*s- (%d %d): [container] terminal: %s children: %d\n", indent, "", ref.num, ref.gen,
+          terminal ? "Yes" : "No", numChildren);
+}
+
+void FormField::printTree(int indent)
+{
+  print(indent);
+  if (terminal) {
+    for (int i = 0; i < numChildren; i++)
+      widgets[i]->print(indent + 4);
+  } else {
+    for (int i = 0; i < numChildren; i++)
+      children[i]->printTree(indent + 4);
+  }
+}
+#endif
+
 void FormField::fillChildrenSiblingsID()
 {
   if (terminal)
@@ -715,6 +741,29 @@ FormFieldButton::FormFieldButton(XRef *xrefA, Object *aobj, const Ref& ref, std:
     Form::fieldLookup(dict, "V", &appearanceState);
 }
 
+#ifdef DEBUG_FORMS
+static char *_getButtonType(FormButtonType type)
+{
+  switch (type) {
+  case formButtonPush:
+    return "push";
+  case formButtonCheck:
+    return "check";
+  case formButtonRadio:
+    return "radio";
+  default:
+    break;
+  }
+  return "unknown";
+}
+
+void FormFieldButton::print(int indent)
+{
+  printf ("%*s- (%d %d): [%s] terminal: %s children: %d\n", indent, "", ref.num, ref.gen,
+          _getButtonType(btype), terminal ? "Yes" : "No", numChildren);
+}
+#endif
+
 void FormFieldButton::fillChildrenSiblingsID()
 {
   if (!terminal) {
@@ -863,6 +912,14 @@ FormFieldText::FormFieldText(XRef *xrefA, Object *aobj, const Ref& ref, std::set
   obj1.free();
 }
 
+#ifdef DEBUG_FORMS
+void FormFieldText::print(int indent)
+{
+  printf ("%*s- (%d %d): [text] terminal: %s children: %d\n", indent, "", ref.num, ref.gen,
+          terminal ? "Yes" : "No", numChildren);
+}
+#endif
+
 GooString* FormFieldText::getContentCopy ()
 {
   if (!content) return NULL;
@@ -1024,6 +1081,14 @@ FormFieldChoice::~FormFieldChoice()
   delete editedChoice;
 }
 
+#ifdef DEBUG_FORMS
+void FormFieldChoice::print(int indent)
+{
+  printf ("%*s- (%d %d): [choice] terminal: %s children: %d\n", indent, "", ref.num, ref.gen,
+          terminal ? "Yes" : "No", numChildren);
+}
+#endif
+
 void FormFieldChoice::updateSelection() {
   Object obj1;
 
@@ -1143,6 +1208,14 @@ FormFieldSignature::~FormFieldSignature()
 
 }
 
+#ifdef DEBUG_FORMS
+void FormFieldSignature::print(int indent)
+{
+  printf ("%*s- (%d %d): [signature] terminal: %s children: %d\n", indent, "", ref.num, ref.gen,
+          terminal ? "Yes" : "No", numChildren);
+}
+#endif
+
 //------------------------------------------------------------------------
 // Form
 //------------------------------------------------------------------------
@@ -1223,6 +1296,11 @@ Form::Form(XRef *xrefA, Object* acroFormA)
     error(-1, "Can't get Fields array\n");
   }
   obj1.free ();
+
+#ifdef DEBUG_FORMS
+  for (int i = 0; i < numFields; i++)
+    rootFields[i]->printTree();
+#endif
 }
 
 Form::~Form() {
diff --git a/poppler/Form.h b/poppler/Form.h
index 8f0eeb3..1ddddb5 100644
--- a/poppler/Form.h
+++ b/poppler/Form.h
@@ -109,6 +109,10 @@ public:
   void createWidgetAnnotation(Catalog *catalog);
   AnnotWidget *getWidgetAnnotation() const { return widget; }
 
+#ifdef DEBUG_FORMS
+  void print(int indent = 0);
+#endif
+
 protected:
   FormWidget(XRef *xrefA, Object *aobj, unsigned num, Ref aref, FormField *fieldA);
 
@@ -282,6 +286,11 @@ public:
 
   void createWidgetAnnotations(Catalog *catalog);
 
+#ifdef DEBUG_FORMS
+  void printTree(int indent = 0);
+  virtual void print(int indent = 0);
+#endif
+
 
  protected:
   void _createWidget (Object *obj, Ref aref);
@@ -332,6 +341,10 @@ public:
 
   void fillChildrenSiblingsID ();
 
+#ifdef DEBUG_FORMS
+  void print(int indent = 0);
+#endif
+
   virtual ~FormFieldButton();
 protected:
   void updateState(char *state);
@@ -365,6 +378,10 @@ public:
   bool isRichText () const { return richText; }
 
   int getMaxLen () const { return maxLen; }
+
+#ifdef DEBUG_FORMS
+  void print(int indent = 0);
+#endif
 protected:
   GooString* content;
   bool multiline;
@@ -420,6 +437,10 @@ public:
 
   int getTopIndex() const { return topIdx; }
 
+#ifdef DEBUG_FORMS
+  void print(int indent = 0);
+#endif
+
 protected:
   void unselectAll();
   void updateSelection();
@@ -451,6 +472,10 @@ public:
   FormFieldSignature(XRef *xrefA, Object *dict, const Ref& ref, std::set<int> *usedParents);
 
   virtual ~FormFieldSignature();
+
+#ifdef DEBUG_FORMS
+  void print(int indent = 0);
+#endif
 };
 
 //------------------------------------------------------------------------


More information about the poppler mailing list