poppler/Annot.cc | 52 +++---- poppler/Form.cc | 400 ++++++++++++++++++++++++++----------------------------- poppler/Form.h | 21 +- 3 files changed, 230 insertions(+), 243 deletions(-)
New commits: commit 0585d7820455c93fe5b732b7a9a20d423df47075 Author: Carlos Garcia Campos <[email protected]> Date: Tue Mar 8 15:36:45 2011 +0100 forms: Handle field values (V entry) by field objects Rather than AnnotWidget or FormWidget, and use the form field object from AnnotWidget to get the values. diff --git a/poppler/Annot.cc b/poppler/Annot.cc index 048f0be..7b800ad 100644 --- a/poppler/Annot.cc +++ b/poppler/Annot.cc @@ -3646,35 +3646,33 @@ void AnnotWidget::drawBorder() { } void AnnotWidget::drawFormFieldButton(GfxResources *resources, GooString *da) { - Object obj1, obj2; + Object obj1; Dict *annot = widget->getObj()->getDict(); - Dict *fieldDict = field->getObj()->getDict(); GooString *caption = NULL; if (appearCharacs) caption = appearCharacs->getNormalCaption(); switch (static_cast<FormFieldButton *>(field)->getButtonType()) { - case formButtonRadio: + case formButtonRadio: { //~ Acrobat doesn't draw a caption if there is no AP dict (?) - if (Form::fieldLookup(fieldDict, "V", &obj1)->isName()) { - if (annot->lookup("AS", &obj2)->isName(obj1.getName()) && - strcmp (obj1.getName(), "Off") != 0) { - if (caption) { - drawText(caption, da, resources, gFalse, 0, fieldQuadCenter, - gFalse, gTrue); - } else if (appearCharacs) { - AnnotColor *aColor = appearCharacs->getBorderColor(); - if (aColor) { - double dx = rect->x2 - rect->x1; - double dy = rect->y2 - rect->y1; - setColor(aColor, gTrue); - drawCircle(0.5 * dx, 0.5 * dy, 0.2 * (dx < dy ? dx : dy), gTrue); - } + char *buttonState = static_cast<FormFieldButton *>(field)->getAppearanceState(); + if (buttonState && annot->lookup("AS", &obj1)->isName(buttonState) && + strcmp (buttonState, "Off") != 0) { + if (caption) { + drawText(caption, da, resources, gFalse, 0, fieldQuadCenter, + gFalse, gTrue); + } else if (appearCharacs) { + AnnotColor *aColor = appearCharacs->getBorderColor(); + if (aColor) { + double dx = rect->x2 - rect->x1; + double dy = rect->y2 - rect->y1; + setColor(aColor, gTrue); + drawCircle(0.5 * dx, 0.5 * dy, 0.2 * (dx < dy ? dx : dy), gTrue); } } - obj2.free(); } obj1.free(); + } break; case formButtonPush: if (caption) @@ -3696,38 +3694,36 @@ void AnnotWidget::drawFormFieldButton(GfxResources *resources, GooString *da) { } void AnnotWidget::drawFormFieldText(GfxResources *resources, GooString *da) { - Object obj1; VariableTextQuadding quadding; - Dict *fieldDict = field->getObj()->getDict(); + GooString *contents; FormFieldText *fieldText = static_cast<FormFieldText *>(field); - if (Form::fieldLookup(fieldDict, "V", &obj1)->isString()) { + contents = fieldText->getContent(); + if (contents) { quadding = field->hasTextQuadding() ? field->getTextQuadding() : form->getTextQuadding(); int comb = 0; if (fieldText->isComb()) comb = fieldText->getMaxLen(); - drawText(obj1.getString(), da, resources, + drawText(contents, da, resources, fieldText->isMultiline(), comb, quadding, gTrue, gFalse, fieldText->isPassword()); } - obj1.free(); } void AnnotWidget::drawFormFieldChoice(GfxResources *resources, GooString *da) { - Object obj1; - Dict *fieldDict = field->getObj()->getDict(); + GooString *selected; VariableTextQuadding quadding; FormFieldChoice *fieldChoice = static_cast<FormFieldChoice *>(field); quadding = field->hasTextQuadding() ? field->getTextQuadding() : form->getTextQuadding(); if (fieldChoice->isCombo()) { - if (Form::fieldLookup(fieldDict, "V", &obj1)->isString()) { - drawText(obj1.getString(), da, resources, gFalse, 0, quadding, gTrue, gFalse); + selected = fieldChoice->getSelectedChoice(); + if (selected) { + drawText(selected, da, resources, gFalse, 0, quadding, gTrue, gFalse); //~ Acrobat draws a popup icon on the right side } - obj1.free(); // list box } else { drawListBox(fieldChoice, da, resources, quadding); diff --git a/poppler/Form.cc b/poppler/Form.cc index 2abb10f..908b6fa 100644 --- a/poppler/Form.cc +++ b/poppler/Form.cc @@ -397,29 +397,6 @@ void FormWidgetText::loadDefaults () return; defaultsLoaded = gTrue; - - Dict *dict = obj.getDict(); - Object obj1; - - if (Form::fieldLookup(dict, "V", &obj1)->isString()) { - if (obj1.getString()->hasUnicodeMarker()) { - if (obj1.getString()->getLength() <= 2) { - } else { - parent->setContentCopy(obj1.getString()); - } - } else { - if (obj1.getString()->getLength() > 0) { - //non-unicode string -- assume pdfDocEncoding and try to convert to UTF16BE - int tmp_length; - char* tmp_str = pdfDocEncodingToUTF16(obj1.getString(), &tmp_length); - GooString str1(tmp_str, tmp_length); - parent->setContentCopy(&str1); - delete []tmp_str; - } - } - } - obj1.free(); - } GooString* FormWidgetText::getContent () @@ -480,22 +457,7 @@ void FormWidgetText::setContent(GooString* new_content) } modified = gTrue; - if (new_content == NULL) { - parent->setContentCopy(NULL); - } else { - //append the unicode marker <FE FF> if needed - if (!new_content->hasUnicodeMarker()) { - new_content->insert(0, 0xff); - new_content->insert(0, 0xfe); - } - - GooString *cont = new GooString(new_content); - parent->setContentCopy(cont); - - Object obj1; - obj1.initString(cont); - updateField ("V", &obj1); - } + parent->setContentCopy(new_content); } FormWidgetChoice::FormWidgetChoice(XRef *xrefA, Object *aobj, unsigned num, Ref ref, FormField *p) : @@ -511,138 +473,12 @@ void FormWidgetChoice::loadDefaults () return; defaultsLoaded = gTrue; - - Dict *dict = obj.getDict(); - Object obj1; - if (dict->lookup("Opt", &obj1)->isArray()) { - Object obj2; - parent->_setNumChoices(obj1.arrayGetLength()); - parent->_createChoicesTab(); - for(int i=0; i<parent->getNumChoices(); i++) { - obj1.arrayGet(i, &obj2); - if(obj2.isString()) { - parent->_setChoiceExportVal(i, obj2.getString()->copy()); - parent->_setChoiceOptionName(i, obj2.getString()->copy()); - } else if (obj2.isArray()) { // [Export_value, Displayed_text] - Object obj3,obj4; - if (obj2.arrayGetLength() < 2) { - error(-1, "FormWidgetChoice:: invalid Opt entry -- array's length < 2\n"); - parent->_setChoiceExportVal(i, new GooString("")); - parent->_setChoiceOptionName(i, new GooString("")); - continue; - } - obj2.arrayGet(0, &obj3); - obj2.arrayGet(1, &obj4); - parent->_setChoiceExportVal(i, obj3.getString()->copy()); - parent->_setChoiceOptionName(i, obj4.getString()->copy()); - obj3.free(); - obj4.free(); - } else { - error(-1, "FormWidgetChoice:: invalid %d Opt entry\n", i); - parent->_setChoiceExportVal(i, new GooString("")); - parent->_setChoiceOptionName(i, new GooString("")); - } - obj2.free(); - } - } else { - //empty choice - } - obj1.free(); - - bool* tmpCurrentChoice = new bool[parent->getNumChoices()]; - memset(tmpCurrentChoice, 0, sizeof(bool)*parent->getNumChoices()); - - //find default choice - if (Form::fieldLookup(dict, "V", &obj1)->isString()) { - for(int i=0; i<parent->getNumChoices(); i++) { - if (parent->getChoice(i)->cmp(obj1.getString()) == 0) { - tmpCurrentChoice[i] = true; - break; - } - } - } else if (obj1.isArray()) { - for(int i=0; i<obj1.arrayGetLength(); i++) { - Object obj2; - obj1.arrayGet(i, &obj2); - for(int j=0; j<parent->getNumChoices(); j++) { - if (parent->getChoice(j)->cmp(obj2.getString()) == 0) { - tmpCurrentChoice[i] = true; - } - } - - obj2.free(); - } - } - obj1.free(); - - //convert choice's human readable strings to UTF16 - //and update the /Opt dict entry to reflect this change -#ifdef UPDATE_OPT - Object *objOpt = new Object(); - objOpt->initArray(xref); -#endif - for(int i=0; i<parent->getNumChoices(); i++) { - if (parent->getChoice(i)->hasUnicodeMarker()) { //string already in UTF16, do nothing - - } else { //string in pdfdocencoding, convert to UTF16 - int len; - char* buffer = pdfDocEncodingToUTF16(parent->getChoice(i), &len); - parent->getChoice(i)->Set(buffer, len); - delete [] buffer; - } - #ifdef UPDATE_OPT - Object *obj2 = new Object(); - obj2->initString(choices[i]); - objOpt->getArray()->add(obj2); - #endif - } - //set default choice now that we have UTF16 strings - for (int i=0; i<parent->getNumChoices(); i++) { - if (tmpCurrentChoice[i]) - parent->select(i); - } -#ifdef UPDATE_OPT - updateField ("Opt", objOpt); -#endif - delete [] tmpCurrentChoice; } FormWidgetChoice::~FormWidgetChoice() { } -void FormWidgetChoice::_updateV () -{ - Object obj1; - //this is an editable combo-box with user-entered text - if (hasEdit() && parent->getEditChoice()) { - obj1.initString(new GooString(parent->getEditChoice())); - } else { - int numSelected = parent->getNumSelected(); - if (numSelected == 0) { - obj1.initString(new GooString("")); - } else if (numSelected == 1) { - for(int i=0; i<parent->getNumChoices(); i++) { - if (parent->isSelected(i)) { - obj1.initString(new GooString(parent->getChoice(i))); - break; - } - } - } else { - obj1.initArray(xref); - for(int i=0; i<parent->getNumChoices(); i++) { - if (parent->isSelected(i)) { - Object obj2; - obj2.initString(new GooString(parent->getChoice(i))); - obj1.arrayAdd(&obj2); - } - } - } - } - updateField ("V", &obj1); - modified = gTrue; -} - bool FormWidgetChoice::_checkRange (int i) { if (i < 0 || i >= parent->getNumChoices()) { @@ -661,7 +497,6 @@ void FormWidgetChoice::select (int i) if (!_checkRange(i)) return; modified = gTrue; parent->select(i); - _updateV(); } void FormWidgetChoice::toggle (int i) @@ -673,7 +508,6 @@ void FormWidgetChoice::toggle (int i) if (!_checkRange(i)) return; modified = gTrue; parent->toggle(i); - _updateV(); } void FormWidgetChoice::deselectAll () @@ -684,7 +518,6 @@ void FormWidgetChoice::deselectAll () } modified = gTrue; parent->deselectAll(); - _updateV(); } GooString* FormWidgetChoice::getEditChoice () @@ -714,17 +547,7 @@ void FormWidgetChoice::setEditChoice (GooString* new_content) } modified = gTrue; - if (new_content == NULL) { - parent->setEditChoice(NULL); - } else { - //append the unicode marker <FE FF> if needed - if (!new_content->hasUnicodeMarker()) { - new_content->insert(0, 0xff); - new_content->insert(0, 0xfe); - } - parent->setEditChoice(new_content); - } - _updateV(); + parent->setEditChoice(new_content); } int FormWidgetChoice::getNumChoices() @@ -998,6 +821,9 @@ FormFieldButton::FormFieldButton(XRef *xrefA, Object *aobj, const Ref& ref, std: error(-1, "FormFieldButton:: radiosInUnison flag unimplemented, please report a bug with a testcase\n"); } } + + if (btype != formButtonPush) + Form::fieldLookup(dict, "V", &appearanceState); } void FormFieldButton::fillChildrenSiblingsID() @@ -1043,26 +869,31 @@ GBool FormFieldButton::setState (int num, GBool s) //pearance state of whichever child field is currently in the on state if (active_child >= 0) { FormWidgetButton* actChild = static_cast<FormWidgetButton*>(widgets[active_child]); - if (actChild->getOnStr()) { - Object obj1; - obj1.initName(actChild->getOnStr()->getCString()); - obj.getDict()->set("V", &obj1); - xref->setModifiedObject(&obj, ref); - } + if (actChild->getOnStr()) + updateState(actChild->getOnStr()->getCString()); } } else { active_child = -1; - Object obj1; - obj1.initName("Off"); - obj.getDict()->set("V", &obj1); - xref->setModifiedObject(&obj, ref); + updateState("Off"); } } return gTrue; } +void FormFieldButton::updateState(char *state) { + Object obj1; + + appearanceState.free(); + appearanceState.initName(state); + + appearanceState.copy(&obj1); + obj.getDict()->set("V", &obj1); + xref->setModifiedObject(&obj, ref); +} + FormFieldButton::~FormFieldButton() { + appearanceState.free(); } //------------------------------------------------------------------------ @@ -1100,6 +931,19 @@ FormFieldText::FormFieldText(XRef *xrefA, Object *aobj, const Ref& ref, std::set maxLen = obj1.getInt(); } obj1.free(); + + if (Form::fieldLookup(dict, "V", &obj1)->isString()) { + if (obj1.getString()->hasUnicodeMarker()) { + if (obj1.getString()->getLength() > 2) + content = obj1.getString()->copy(); + } else if (obj1.getString()->getLength() > 0) { + //non-unicode string -- assume pdfDocEncoding and try to convert to UTF16BE + int tmp_length; + char* tmp_str = pdfDocEncodingToUTF16(obj1.getString(), &tmp_length); + content = new GooString(tmp_str, tmp_length); + } + } + obj1.free(); } GooString* FormFieldText::getContentCopy () @@ -1110,10 +954,23 @@ GooString* FormFieldText::getContentCopy () void FormFieldText::setContentCopy (GooString* new_content) { - if(content) { - delete content; + delete content; + content = NULL; + + if (new_content) { + content = new_content->copy(); + + //append the unicode marker <FE FF> if needed + if (!content->hasUnicodeMarker()) { + content->insert(0, 0xff); + content->insert(0, 0xfe); + } } - content = new_content->copy(); + + Object obj1; + obj1.initString(content ? content->copy() : new GooString("")); + obj.getDict()->set("V", &obj1); + xref->setModifiedObject(&obj, ref); } FormFieldText::~FormFieldText() @@ -1157,11 +1014,89 @@ FormFieldChoice::FormFieldChoice(XRef *xrefA, Object *aobj, const Ref& ref, std: topIdx = obj1.getInt(); obj1.free(); + if (dict->lookup("Opt", &obj1)->isArray()) { + Object obj2; + + numChoices = obj1.arrayGetLength(); + choices = new ChoiceOpt[numChoices]; + memset(choices, 0, sizeof(ChoiceOpt) * numChoices); + + for (int i = 0; i < numChoices; i++) { + if (obj1.arrayGet(i, &obj2)->isString()) { + choices[i].optionName = obj2.getString()->copy(); + } else if (obj2.isArray()) { // [Export_value, Displayed_text] + Object obj3; + + if (obj2.arrayGetLength() < 2) { + error(-1, "FormWidgetChoice:: invalid Opt entry -- array's length < 2\n"); + continue; + } + if (obj2.arrayGet(0, &obj3)->isString()) + choices[i].exportVal = obj3.getString()->copy(); + else + error(-1, "FormWidgetChoice:: invalid Opt entry -- exported value not a string\n"); + obj3.free(); + + if (obj2.arrayGet(1, &obj3)->isString()) + choices[i].optionName = obj3.getString()->copy(); + else + error(-1, "FormWidgetChoice:: invalid Opt entry -- choice name not a string\n"); + obj3.free(); + } else { + error(-1, "FormWidgetChoice:: invalid %d Opt entry\n", i); + } + obj2.free(); + } + } else { + //empty choice + } + obj1.free(); + + // find selected items and convert choice's human readable strings to UTF16 + if (Form::fieldLookup(dict, "V", &obj1)->isString()) { + for (int i = 0; i < numChoices; i++) { + if (!choices[i].optionName) + continue; + + if (choices[i].optionName->cmp(obj1.getString()) == 0) + choices[i].selected = true; + + if (!choices[i].optionName->hasUnicodeMarker()) { + int len; + char* buffer = pdfDocEncodingToUTF16(choices[i].optionName, &len); + choices[i].optionName->Set(buffer, len); + } + } + } else if (obj1.isArray()) { + for (int i = 0; i < numChoices; i++) { + if (!choices[i].optionName) + continue; + + for (int j = 0; j < obj1.arrayGetLength(); j++) { + Object obj2; + + obj1.arrayGet(i, &obj2); + if (choices[i].optionName->cmp(obj2.getString()) == 0) { + choices[i].selected = true; + obj2.free(); + break; + } + obj2.free(); + } + + if (!choices[i].optionName->hasUnicodeMarker()) { + int len; + char* buffer = pdfDocEncodingToUTF16(choices[i].optionName, &len); + choices[i].optionName->Set(buffer, len); + } + } + } + obj1.free(); } FormFieldChoice::~FormFieldChoice() { - for (int i=0; i<numChoices; i++) { + for (int i = 0; i < numChoices; i++) { delete choices[i].exportVal; delete choices[i].optionName; } @@ -1169,33 +1104,82 @@ FormFieldChoice::~FormFieldChoice() delete editedChoice; } -void FormFieldChoice::deselectAll () +void FormFieldChoice::updateSelection() { + Object obj1; + + //this is an editable combo-box with user-entered text + if (edit && editedChoice) { + obj1.initString(editedChoice->copy()); + } else { + int numSelected = getNumSelected(); + if (numSelected == 0) { + obj1.initString(new GooString("")); + } else if (numSelected == 1) { + for (int i = 0; numChoices; i++) { + if (choices[i].optionName && choices[i].selected) { + obj1.initString(choices[i].optionName->copy()); + break; + } + } + } else { + obj1.initArray(xref); + for (int i = 0; i < numChoices; i++) { + if (choices[i].optionName && choices[i].selected) { + Object obj2; + obj2.initString(choices[i].optionName->copy()); + obj1.arrayAdd(&obj2); + } + } + } + } + + obj.getDict()->set("V", &obj1); + xref->setModifiedObject(&obj, ref); +} + +void FormFieldChoice::unselectAll () { - for(int i=0; i<numChoices; i++) { + for (int i = 0; i < numChoices; i++) { choices[i].selected = false; } } +void FormFieldChoice::deselectAll () { + unselectAll(); + updateSelection(); +} + void FormFieldChoice::toggle (int i) { choices[i].selected = !choices[i].selected; + updateSelection(); } void FormFieldChoice::select (int i) { - if (!multiselect) - deselectAll(); + if (!multiselect) + unselectAll(); choices[i].selected = true; + updateSelection(); } void FormFieldChoice::setEditChoice (GooString* new_content) { - if (editedChoice) - delete editedChoice; + delete editedChoice; + editedChoice = NULL; + + unselectAll(); - deselectAll(); + if (new_content) { + editedChoice = new_content->copy(); - editedChoice = new_content->copy(); + //append the unicode marker <FE FF> if needed + if (!editedChoice->hasUnicodeMarker()) { + editedChoice->insert(0, 0xff); + editedChoice->insert(0, 0xfe); + } + } + updateSelection(); } GooString* FormFieldChoice::getEditChoice () @@ -1213,12 +1197,16 @@ int FormFieldChoice::getNumSelected () return cnt; } -void FormFieldChoice::_createChoicesTab () -{ - choices = new ChoiceOpt[numChoices]; - for(int i=0; i<numChoices; i++) { - choices[i].selected = false; +GooString *FormFieldChoice::getSelectedChoice() { + if (edit && editedChoice) + return editedChoice; + + for (int i = 0; numChoices; i++) { + if (choices[i].optionName && choices[i].selected) + return choices[i].optionName; } + + return NULL; } //------------------------------------------------------------------------ diff --git a/poppler/Form.h b/poppler/Form.h index 5bea2c1..8d25e2c 100644 --- a/poppler/Form.h +++ b/poppler/Form.h @@ -247,7 +247,6 @@ public: bool commitOnSelChange () const; bool isListBox () const; protected: - void _updateV (); bool _checkRange (int i); FormFieldChoice *parent; }; @@ -334,15 +333,20 @@ public: // returns gTrue if the state modification is accepted GBool setState (int num, GBool s); + + char *getAppearanceState() { return appearanceState.isName() ? appearanceState.getName() : NULL; } void fillChildrenSiblingsID (); virtual ~FormFieldButton(); protected: + void updateState(char *state); + FormButtonType btype; int size; int active_child; //only used for combo box bool noAllOff; + Object appearanceState; // V }; //------------------------------------------------------------------------ @@ -390,8 +394,10 @@ public: virtual ~FormFieldChoice(); int getNumChoices() { return numChoices; } - GooString* getChoice(int i) { return choices[i].optionName; } - GooString* getExportVal (int i) { return choices[i].exportVal; } + GooString* getChoice(int i) { return choices ? choices[i].optionName : NULL; } + GooString* getExportVal (int i) { return choices ? choices[i].exportVal : NULL; } + // For multi-select choices it returns the first one + GooString* getSelectedChoice(); //select the i-th choice void select (int i); @@ -420,13 +426,10 @@ public: int getTopIndex() const { return topIdx; } - /* these functions _must_ only be used by FormWidgetChoice */ - void _setNumChoices (int i) { numChoices = i; } - void _createChoicesTab (); - void _setChoiceExportVal (int i, GooString* str) { choices[i].exportVal = str; } - void _setChoiceOptionName (int i, GooString* str) { choices[i].optionName = str; } - protected: + void unselectAll(); + void updateSelection(); + bool combo; bool edit; bool multiselect; _______________________________________________ poppler mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/poppler
