[poppler] 5 commits - poppler/Form.cc
Carlos Garcia Campos
carlosgc at kemper.freedesktop.org
Sat Nov 3 02:01:02 PDT 2012
poppler/Form.cc | 136 ++++++++++++++++++++++++++++++++++++--------------------
1 file changed, 88 insertions(+), 48 deletions(-)
New commits:
commit 401de95f5ab42ab0f5d8fd92d76b5def50f84a2b
Author: Fabio D'Urso <fabiodurso at hotmail.it>
Date: Wed Oct 31 19:43:51 2012 +0100
FormFieldChoice ctor: Look for selected options in /I instead of /V if /I is available
Since /I stores the indices of the selected options, it can distinguish
duplicate option (i.e. options with the same name/export value).
diff --git a/poppler/Form.cc b/poppler/Form.cc
index 9998240..586482d 100644
--- a/poppler/Form.cc
+++ b/poppler/Form.cc
@@ -1130,44 +1130,57 @@ FormFieldChoice::FormFieldChoice(PDFDoc *docA, Object *aobj, const Ref& ref, For
}
obj1.free();
- // find selected items
- // Note: According to PDF specs, /V should *never* contain the exportVal.
- // However, if /Opt is an array of (exportVal,optionName) pairs, acroread
- // seems to expect the exportVal instead of the optionName and so we do too.
- if (Form::fieldLookup(dict, "V", &obj1)->isString()) {
- for (int i = 0; i < numChoices; i++) {
- if (choices[i].exportVal) {
- if (choices[i].exportVal->cmp(obj1.getString()) == 0) {
- choices[i].selected = true;
- }
- } else if (choices[i].optionName) {
- if (choices[i].optionName->cmp(obj1.getString()) == 0) {
- choices[i].selected = true;
- }
+ // Find selected items
+ // Note: PDF specs say that /V has precedence over /I, but acroread seems to
+ // do the opposite. We do the same.
+ if (Form::fieldLookup(dict, "I", &obj1)->isArray()) {
+ for (int i = 0; i < obj1.arrayGetLength(); i++) {
+ Object obj2;
+ if (obj1.arrayGet(i, &obj2)->isInt() && obj2.getInt() >= 0 && obj2.getInt() < numChoices) {
+ choices[obj2.getInt()].selected = true;
}
+ obj2.free();
}
- } else if (obj1.isArray()) {
- for (int i = 0; i < numChoices; i++) {
- for (int j = 0; j < obj1.arrayGetLength(); j++) {
- Object obj2;
- obj1.arrayGet(j, &obj2);
- GBool matches = gFalse;
-
+ } else {
+ obj1.free();
+ // Note: According to PDF specs, /V should *never* contain the exportVal.
+ // However, if /Opt is an array of (exportVal,optionName) pairs, acroread
+ // seems to expect the exportVal instead of the optionName and so we do too.
+ if (Form::fieldLookup(dict, "V", &obj1)->isString()) {
+ for (int i = 0; i < numChoices; i++) {
if (choices[i].exportVal) {
- if (choices[i].exportVal->cmp(obj2.getString()) == 0) {
- matches = gTrue;
+ if (choices[i].exportVal->cmp(obj1.getString()) == 0) {
+ choices[i].selected = true;
}
} else if (choices[i].optionName) {
- if (choices[i].optionName->cmp(obj2.getString()) == 0) {
- matches = gTrue;
+ if (choices[i].optionName->cmp(obj1.getString()) == 0) {
+ choices[i].selected = true;
}
}
+ }
+ } else if (obj1.isArray()) {
+ for (int i = 0; i < numChoices; i++) {
+ for (int j = 0; j < obj1.arrayGetLength(); j++) {
+ Object obj2;
+ obj1.arrayGet(j, &obj2);
+ GBool matches = gFalse;
- obj2.free();
+ if (choices[i].exportVal) {
+ if (choices[i].exportVal->cmp(obj2.getString()) == 0) {
+ matches = gTrue;
+ }
+ } else if (choices[i].optionName) {
+ if (choices[i].optionName->cmp(obj2.getString()) == 0) {
+ matches = gTrue;
+ }
+ }
- if (matches) {
- choices[i].selected = true;
- break; // We've determined that this option is selected. No need to keep on scanning
+ obj2.free();
+
+ if (matches) {
+ choices[i].selected = true;
+ break; // We've determined that this option is selected. No need to keep on scanning
+ }
}
}
}
commit cfd3a46a857100cb634e18192b762e7342165348
Author: Fabio D'Urso <fabiodurso at hotmail.it>
Date: Wed Oct 31 15:44:32 2012 +0100
FormFieldChoice: Handle /V values containing the export value instead of the option name
According to the PDF spec, /V should always contain an "option name" and
never an "export value" if /Opt is an array of couples. However, it
seems that acroread works the other way round: it is able to identify
selected options only if they are referred by their export value
instead of the option name.
With this patch, we mimic this behavior.
diff --git a/poppler/Form.cc b/poppler/Form.cc
index 53e6167..9998240 100644
--- a/poppler/Form.cc
+++ b/poppler/Form.cc
@@ -1131,29 +1131,44 @@ FormFieldChoice::FormFieldChoice(PDFDoc *docA, Object *aobj, const Ref& ref, For
obj1.free();
// find selected items
+ // Note: According to PDF specs, /V should *never* contain the exportVal.
+ // However, if /Opt is an array of (exportVal,optionName) pairs, acroread
+ // seems to expect the exportVal instead of the optionName and so we do too.
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].exportVal) {
+ if (choices[i].exportVal->cmp(obj1.getString()) == 0) {
+ choices[i].selected = true;
+ }
+ } else if (choices[i].optionName) {
+ if (choices[i].optionName->cmp(obj1.getString()) == 0) {
+ choices[i].selected = true;
+ }
+ }
}
} 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(j, &obj2);
- if (choices[i].optionName->cmp(obj2.getString()) == 0) {
- choices[i].selected = true;
- obj2.free();
- break;
+ GBool matches = gFalse;
+
+ if (choices[i].exportVal) {
+ if (choices[i].exportVal->cmp(obj2.getString()) == 0) {
+ matches = gTrue;
+ }
+ } else if (choices[i].optionName) {
+ if (choices[i].optionName->cmp(obj2.getString()) == 0) {
+ matches = gTrue;
+ }
}
+
obj2.free();
+
+ if (matches) {
+ choices[i].selected = true;
+ break; // We've determined that this option is selected. No need to keep on scanning
+ }
}
}
}
@@ -1204,7 +1219,9 @@ void FormFieldChoice::updateSelection() {
objI.arrayAdd(obj1.initInt(i));
}
- if (choices[i].optionName) {
+ if (choices[i].exportVal) {
+ objV.initString(choices[i].exportVal->copy());
+ } else if (choices[i].optionName) {
objV.initString(choices[i].optionName->copy());
}
@@ -1220,7 +1237,9 @@ void FormFieldChoice::updateSelection() {
objI.arrayAdd(obj1.initInt(i));
}
- if (choices[i].optionName) {
+ if (choices[i].exportVal) {
+ objV.arrayAdd(obj1.initString(choices[i].exportVal->copy()));
+ } else if (choices[i].optionName) {
objV.arrayAdd(obj1.initString(choices[i].optionName->copy()));
}
}
commit ce99940bcac0447f32ee2ad46efb09af93989c12
Author: Fabio D'Urso <fabiodurso at hotmail.it>
Date: Sat Oct 13 00:13:33 2012 +0200
FormFieldChoice::updateSelection: Write /I too
This improves handling of choice fields containing two or more entries
with the same name, and also makes sure that the previous value of /I
gets updated (failing to update it results in acroread still showing
the old selection).
diff --git a/poppler/Form.cc b/poppler/Form.cc
index 4a3f30d..53e6167 100644
--- a/poppler/Form.cc
+++ b/poppler/Form.cc
@@ -1179,35 +1179,57 @@ void FormFieldChoice::print(int indent)
#endif
void FormFieldChoice::updateSelection() {
- Object obj1;
+ Object objV, objI, obj1;
+ objI.initNull();
- //this is an editable combo-box with user-entered text
if (edit && editedChoice) {
- obj1.initString(editedChoice->copy());
+ // This is an editable combo-box with user-entered text
+ objV.initString(editedChoice->copy());
} else {
- int numSelected = getNumSelected();
+ const int numSelected = getNumSelected();
+
+ // Create /I array only if multiple selection is allowed (as per PDF spec)
+ if (multiselect) {
+ objI.initArray(xref);
+ }
+
if (numSelected == 0) {
- obj1.initString(new GooString(""));
+ // No options are selected
+ objV.initString(new GooString(""));
} else if (numSelected == 1) {
+ // Only one option is selected
for (int i = 0; i < numChoices; i++) {
- if (choices[i].optionName && choices[i].selected) {
- obj1.initString(choices[i].optionName->copy());
- break;
+ if (choices[i].selected) {
+ if (multiselect) {
+ objI.arrayAdd(obj1.initInt(i));
+ }
+
+ if (choices[i].optionName) {
+ objV.initString(choices[i].optionName->copy());
+ }
+
+ break; // We've just written the selected option. No need to keep on scanning
}
}
} else {
- obj1.initArray(xref);
+ // More than one option is selected
+ objV.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);
+ if (choices[i].selected) {
+ if (multiselect) {
+ objI.arrayAdd(obj1.initInt(i));
+ }
+
+ if (choices[i].optionName) {
+ objV.arrayAdd(obj1.initString(choices[i].optionName->copy()));
+ }
}
}
}
}
- obj.getDict()->set("V", &obj1);
+ obj.getDict()->set("V", &objV);
+ obj.getDict()->set("I", &objI);
xref->setModifiedObject(&obj, ref);
updateChildrenAppearance();
}
commit 102553e2104a1b223c8ac924aa6702829adebbdb
Author: Fabio D'Urso <fabiodurso at hotmail.it>
Date: Wed Oct 31 16:57:56 2012 +0100
FormFieldChoice::updateSelection: Fixed wrong loop condition
diff --git a/poppler/Form.cc b/poppler/Form.cc
index d396437..4a3f30d 100644
--- a/poppler/Form.cc
+++ b/poppler/Form.cc
@@ -1189,7 +1189,7 @@ void FormFieldChoice::updateSelection() {
if (numSelected == 0) {
obj1.initString(new GooString(""));
} else if (numSelected == 1) {
- for (int i = 0; numChoices; i++) {
+ for (int i = 0; i < numChoices; i++) {
if (choices[i].optionName && choices[i].selected) {
obj1.initString(choices[i].optionName->copy());
break;
commit d7522ea1d2e66beef64f705e8986142f15fcf613
Author: Fabio D'Urso <fabiodurso at hotmail.it>
Date: Wed Oct 31 15:26:37 2012 +0100
FormFieldChoice ctor: Don't convert "human-readable" option names to unicode
Despite that comment, they're not meant to be read by humans only, but they
are also used as option identifiers.
This patch stops poppler from forcing them to be unicode. Instead,
they now stay the same encoding as their corresponding /Opt entry.
This fixes poppler not being able to recognize selected entries
in documents produced by poppler itself: previously, the /V value was
always written in Unicode encoding, and therefore it was very often not
binary-equal to the corresponding /Opt entry.
Now the /V value is always binary-equal to the corresponding /Opt entry.
diff --git a/poppler/Form.cc b/poppler/Form.cc
index 68a4219..d396437 100644
--- a/poppler/Form.cc
+++ b/poppler/Form.cc
@@ -1130,7 +1130,7 @@ FormFieldChoice::FormFieldChoice(PDFDoc *docA, Object *aobj, const Ref& ref, For
}
obj1.free();
- // find selected items and convert choice's human readable strings to UTF16
+ // find selected items
if (Form::fieldLookup(dict, "V", &obj1)->isString()) {
for (int i = 0; i < numChoices; i++) {
if (!choices[i].optionName)
@@ -1138,13 +1138,6 @@ FormFieldChoice::FormFieldChoice(PDFDoc *docA, Object *aobj, const Ref& ref, For
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);
- delete [] buffer;
- }
}
} else if (obj1.isArray()) {
for (int i = 0; i < numChoices; i++) {
@@ -1162,13 +1155,6 @@ FormFieldChoice::FormFieldChoice(PDFDoc *docA, Object *aobj, const Ref& ref, For
}
obj2.free();
}
-
- if (!choices[i].optionName->hasUnicodeMarker()) {
- int len;
- char* buffer = pdfDocEncodingToUTF16(choices[i].optionName, &len);
- choices[i].optionName->Set(buffer, len);
- delete [] buffer;
- }
}
}
obj1.free();
More information about the poppler
mailing list