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 <[email protected]> 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 <[email protected]> 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 <[email protected]> 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 }; //------------------------------------------------------------------------ _______________________________________________ poppler mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/poppler
