[poppler] poppler/Annot.cc poppler/Form.cc poppler/Form.h
Carlos Garcia Campos
carlosgc at kemper.freedesktop.org
Tue Mar 8 06:39:16 PST 2011
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 <carlosgc at gnome.org>
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;
More information about the poppler
mailing list