[poppler] poppler/poppler: Annot.cc, 1.6, 1.7 Annot.h, 1.3,
1.4 Catalog.cc, 1.18, 1.19 Catalog.h, 1.10,
1.11 CharCodeToUnicode.cc, 1.4, 1.5 CharCodeToUnicode.h, 1.2,
1.3 Dict.cc, 1.5, 1.6 Dict.h, 1.4, 1.5 Form.cc, NONE,
1.1 Form.h, NONE, 1.1 GfxFont.cc, 1.9, 1.10 GfxFont.h, 1.4,
1.5 Makefile.am, 1.27, 1.28 Object.h, 1.3, 1.4 Page.cc, 1.15,
1.16 Page.h, 1.7, 1.8 XRef.cc, 1.13, 1.14 XRef.h, 1.6, 1.7
Albert Astals Cid
aacid at kemper.freedesktop.org
Sat Feb 24 15:32:26 PST 2007
- Previous message: [poppler] poppler/glib: poppler-document.cc, 1.39,
1.40 poppler-document.h, 1.22, 1.23 poppler-page.cc, 1.53,
1.54 poppler-page.h, 1.22, 1.23 poppler-private.h, 1.16,
1.17 poppler.h, 1.12, 1.13
- Next message: [poppler] poppler/test: gtk-splash-test.cc, 1.5,
1.6 pdf-inspector.cc, 1.5, 1.6
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]
Update of /cvs/poppler/poppler/poppler
In directory kemper:/tmp/cvs-serv6254/poppler
Modified Files:
Annot.cc Annot.h Catalog.cc Catalog.h CharCodeToUnicode.cc
CharCodeToUnicode.h Dict.cc Dict.h GfxFont.cc GfxFont.h
Makefile.am Object.h Page.cc Page.h XRef.cc XRef.h
Added Files:
Form.cc Form.h
Log Message:
2007-02-25 Julien Rebetez <julienr at svn.gnome.org>
reviewed by: <aacid at kde.org>
* glib/poppler-document.cc:
* glib/poppler-document.h:
* glib/poppler-page.cc:
* glib/poppler-page.h:
* glib/poppler-private.h:
* glib/poppler.h:
* poppler/Annot.cc:
* poppler/Annot.h:
* poppler/Catalog.cc:
* poppler/Catalog.h:
* poppler/CharCodeToUnicode.cc:
* poppler/CharCodeToUnicode.h:
* poppler/Dict.cc:
* poppler/Dict.h:
* poppler/Form.cc:
* poppler/Form.h:
* poppler/GfxFont.cc:
* poppler/GfxFont.h:
* poppler/Makefile.am:
* poppler/Object.h:
* poppler/Page.cc:
* poppler/Page.h:
* poppler/XRef.cc:
* poppler/XRef.h:
Beginning of Interactive Form support:
Add a bunch of new classes (FormWidget / FormField) to deal with form
fields.
Add support for object modification through XRef::setModifiedObject, as
well as a function to write the Xref to a file, which will be used
to implement PDF writing.
Add some functions to glib wrapper to expose the new form features.
Index: Annot.cc
===================================================================
RCS file: /cvs/poppler/poppler/poppler/Annot.cc,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- Annot.cc 27 Dec 2006 23:15:06 -0000 1.6
+++ Annot.cc 24 Feb 2007 23:32:23 -0000 1.7
@@ -20,19 +20,30 @@
#include "Lexer.h"
#include "UGooString.h"
#include "Annot.h"
+#include "GfxFont.h"
+#include "CharCodeToUnicode.h"
+#include "Form.h"
+#include "Error.h"
//------------------------------------------------------------------------
// Annot
//------------------------------------------------------------------------
-Annot::Annot(XRef *xrefA, Dict *acroForm, Dict *dict) {
+Annot::Annot(XRef *xrefA, Dict *acroForm, Dict *dict, Ref* aref, Catalog* catalog) {
Object apObj, asObj, obj1, obj2;
- GBool regen, isTextField;
double t;
ok = gTrue;
xref = xrefA;
appearBuf = NULL;
+ fontSize = 0;
+ widget = NULL;
+
+ if (aref) {
+ hasRef = true;
+ ref = *aref;
+ } else
+ hasRef = false;
if (dict->lookup("Rect", &obj1)->isArray() &&
obj1.arrayGetLength() == 4) {
@@ -59,6 +70,16 @@
}
obj1.free();
+ //check for hidden annot
+ hidden = false;
+ Object obj3;
+ if (dict->lookup("F", &obj3)->isInt()) {
+ int flags = obj3.getInt();
+ if (flags & 0x2)
+ hidden = true;
+ }
+ obj3.free();
+
// check if field apperances need to be regenerated
regen = gFalse;
if (acroForm) {
@@ -68,16 +89,38 @@
}
obj1.free();
}
+ regen = gTrue;
- // check for a text-type field
- isTextField = dict->lookup("FT", &obj1)->isName("Tx");
- obj1.free();
+ /*TODO: appearance generation isn't complete :
+ non-comprehensive list of missings things by Leonard Rosenthol :
+ * Doesn't support walking up the parents of the field for /DA information
+ * Doesn't support field attributes
+ border style (width, color, etc.)
+ background color
+ flags (password, comb, etc.)
+ etc.
+ * Only works for text fields, basic support for combos
+ */
+
+ //try to find the corresponding FormWidget
+ if (hasRef && catalog->getForm()) {
+ widget = catalog->getForm()->findWidgetByRef(ref);
+ }
+
+ isMultiline = isListbox = false;
+ if (widget) {
+ if (widget->getType() == formText) {
+ isTextField = true;
+ isMultiline = static_cast<FormWidgetText*>(widget)->isMultiline();
+ } else if (widget->getType() == formChoice) {
+ isTextField = true;
+ isListbox = static_cast<FormWidgetChoice*>(widget)->isListBox();
+ }
+ }
-#if 0 //~ appearance stream generation is not finished yet
if (regen && isTextField) {
generateAppearance(acroForm, dict);
} else {
-#endif
if (dict->lookup("AP", &apObj)->isDict()) {
if (dict->lookup("AS", &asObj)->isName()) {
if (apObj.dictLookup("N", &obj1)->isDict()) {
@@ -104,9 +147,7 @@
asObj.free();
}
apObj.free();
-#if 0 //~ appearance stream generation is not finished yet
}
-#endif
}
void Annot::readArrayNum(Object *pdfArray, int key, double *value) {
@@ -129,14 +170,81 @@
}
}
+void Annot::writeTextString (GooString* vStr, CharCodeToUnicode* ccToUnicode, GooString* appearBuf, GfxFont* font)
+{
+ int i0,i1; //i0 = line begin index, i1 = line end index
+ int charSize;
+ CharCode c;
+ char buf[256];
+ double currentLineWidth= 0.0; //width filled by displayed chars (used for multilines)
+
+ if (vStr->hasUnicodeMarker()) {
+ //skip unicode marker and go one char forward because we read character by pairs
+ i0 = 3;
+ charSize = 2;
+ } else {
+ i0 = 0;
+ charSize = 1;
+ }
+ while (i0 < vStr->getLength()) {
+ //find next end of line
+ for (i1 = i0; i1 < vStr->getLength(); i1++) {
+ if (vStr->getChar(i1) == '\n' || vStr->getChar(i1) == '\r')
+ break;
+ }
+ appearBuf->append('(');
+
+ for(; i0 < i1; i0 += charSize) {
+ c = vStr->getChar(i0);
+ if (ccToUnicode && vStr->hasUnicodeMarker()) {
+ char ctmp[2];
+ ctmp[0] = vStr->getChar(i0-1);
+ ctmp[1] = vStr->getChar(i0);
+ ccToUnicode->mapToCharCode((Unicode*)ctmp, &c, 2);
+ appearBuf->append(c);
+ } else {
+ c &= 0xff;
+ if (c == '(' || c == ')' || c == '\\') {
+ appearBuf->append('\\');
+ appearBuf->append(c);
+ } else if (c < 0x20 || c >= 0x80) {
+ sprintf(buf, "\\%03o", c);
+ appearBuf->append(buf);
+ } else {
+ appearBuf->append(c);
+ }
+ }
+ if (font) {
+ if (font->isCIDFont()) {
+ currentLineWidth += fontSize*static_cast<GfxCIDFont*>(font)->getWidth((char*)&c, 1);
+ } else { //Gfx8Bit
+ currentLineWidth += fontSize*static_cast<Gfx8BitFont*>(font)->getWidth((char)c);
+ }
+
+ if (isMultiline && (currentLineWidth >= xMax - xMin)) {
+ currentLineWidth = 0;
+ break;
+ }
+ } else {
+
+ }
+ }
+ appearBuf->append(") Tj\n");
+ appearBuf->append("T*\n");
+ i0 = i0 + charSize;
+ }
+}
+
void Annot::generateAppearance(Dict *acroForm, Dict *dict) {
MemStream *appearStream;
- Object daObj, vObj, drObj, appearDict, obj1, obj2;
+ Object daObj, vObj, drObj, appearDict, obj1, obj2, resObj;
GooString *daStr, *daStr1, *vStr, *s;
+ GooString *fontName=NULL;
char buf[256];
- double fontSize;
int c;
int i0, i1;
+ GfxFont *font = NULL;
+
//~ DA can be inherited
if (dict->lookup("DA", &daObj)->isString()) {
@@ -167,68 +275,24 @@
daStr->getLength() - i1);
}
}
- break;
- }
- }
- // build the appearance stream contents
- appearBuf = new GooString();
- appearBuf->append("/Tx BMC\n");
- appearBuf->append("q BT\n");
- appearBuf->append(daStr1 ? daStr1 : daStr)->append("\n");
- if (dict->lookup("V", &vObj)->isString()) {
- //~ handle quadding -- this requires finding the font and using
- //~ the encoding and char widths
- sprintf(buf, "1 0 0 1 %.2f %.2f Tm\n", 2.0, yMax - yMin - fontSize);
- appearBuf->append(buf);
- sprintf(buf, "%g TL\n", fontSize);
- appearBuf->append(buf);
- vStr = vObj.getString();
- i0 = 0;
- while (i0 < vStr->getLength()) {
- for (i1 = i0;
- i1 < vStr->getLength() &&
- vStr->getChar(i1) != '\n' && vStr->getChar(i1) != '\r';
- ++i1) ;
- if (i0 > 0) {
- appearBuf->append("T*\n");
- }
- appearBuf->append('(');
- for (; i0 < i1; ++i0) {
- c = vStr->getChar(i0);
- if (c == '(' || c == ')' || c == '\\') {
- appearBuf->append('\\');
- appearBuf->append(c);
- } else if (c < 0x20 || c >= 0x80) {
- sprintf(buf, "\\%03o", c);
- appearBuf->append(buf);
- } else {
- appearBuf->append(c);
- }
- }
- appearBuf->append(") Tj\n");
- if (i1 + 1 < vStr->getLength() &&
- vStr->getChar(i1) == '\r' && vStr->getChar(i1 + 1) == '\n') {
- i0 = i1 + 2;
- } else {
- i0 = i1 + 1;
+ //find the font name
+ i1=i0;
+ for (--i1; i1 >= 0 && Lexer::isSpace(daStr->getChar(i1)); --i1) ;
+ for (i0 = i1; i0 >= 0 && !Lexer::isSpace(daStr->getChar(i0)); --i0) ;
+ if (i0<0) i0=0;
+ if (i0 != i1) {
+ ++i0;
+ ++i1;
+ fontName = new GooString(daStr, i0, i1 - i0);
}
+
+ break;
}
}
- vObj.free();
- appearBuf->append("ET Q\n");
- appearBuf->append("EMC\n");
- // build the appearance stream dictionary
+ //init appearance dictionnary
appearDict.initDict(xref);
- appearDict.dictAdd("Length", obj1.initInt(appearBuf->getLength()));
- appearDict.dictAdd("Subtype", obj1.initName("Form"));
- obj1.initArray(xref);
- obj1.arrayAdd(obj2.initReal(0));
- obj1.arrayAdd(obj2.initReal(0));
- obj1.arrayAdd(obj2.initReal(xMax - xMin));
- obj1.arrayAdd(obj2.initReal(yMax - yMin));
- appearDict.dictAdd("BBox", &obj1);
// find the resource dictionary
dict->lookup("DR", &drObj);
@@ -252,14 +316,141 @@
}
}
}
+ CharCodeToUnicode* ccToUnicode = NULL;
if (drObj.isDict()) {
- appearDict.dictAdd("Resources", drObj.copy(&obj1));
+ //Lookup for the font name in the font entry of the ressource dictionnary
+ //also lookup in BaseFont/Name of each DR entry
+ //without that second lookup, forms-scribus.pdf doesn't find font
+ if (fontName && drObj.dictLookup("Font", &obj1)->isDict()) {
+ Object obj3, obj4;
+ //--
+ bool found = false;
+ if (obj1.dictLookup(*fontName, &obj3)->isDict() && obj3.dictLookup("Type", &obj4)->isName("Font")) {
+ found = true;
+ }
+ if (!found) { //font not found in DR, try to lookup in each entry BaseFont/Name
+ error(-1, "Can't find font name in DR, trying to lookup in BaseFont/Name");
+ for(int i=0; i<obj1.dictGetLength(); i++) {
+ if (!found && obj1.dictGetVal(i, &obj3)->isDict()) {
+ if (obj3.dictLookup("Type", &obj4)->isName("Font")) {
+ obj4.free();
+ if (obj3.dictLookup("Name", &obj4)->isName()) {
+ if (fontName->cmp(obj4.getName()) == 0) {
+ found = true;
+ break;
+ }
+ obj4.free();
+ }
+ if (obj3.dictLookup("BaseFont", &obj4)->isName()) {
+ if (fontName->cmp(obj4.getName()) == 0) {
+ found = true;
+ break;
+ }
+ obj4.free();
+ }
+ }
+ obj3.free();
+ }
+ }
+ }
+ if (found) {
+ obj4.free();
+ obj1.dictLookupNF(*fontName, &obj4);
+ Ref r;
+ if (obj4.isRef()) r = obj4.getRef();
+ else r.gen = r.num = 0;
+ font = GfxFont::makeFont(xref, "temp", r, obj3.getDict());
+ ccToUnicode = font->getToUnicode();
+ }
+ obj3.free();
+ }
+ obj1.free();
+ appearDict.dictAdd("Resources", drObj.copy(&resObj));
}
drObj.free();
+ // build the appearance stream contents
+ appearBuf = new GooString();
+
+ //TODO: support for dash and style options from BS dict
+ bool drawBorder = false;
+ if (dict->lookup("BS", &obj1)->isDict()) {
+ Object obj3,obj4;
+ Dict *bsDict = obj1.getDict();
+ if (bsDict->lookup("Type", &obj3)->isName("Border")) {
+ //width
+ if (bsDict->lookup("W", &obj4)->isInt()) {
+ sprintf(buf, "%i w\n", obj4.getInt());
+ appearBuf->append(buf);
+ drawBorder = true;
+ }
+ obj4.free();
+ }
+ obj3.free();
+ }
+ obj1.free();
+ //border rendering
+ if (drawBorder && !hidden) {
+ sprintf(buf, "0 0 %f %f re\n", xMax-xMin, yMax-yMin);
+ appearBuf->append(buf);
+ appearBuf->append("S\n");
+ }
+
+ appearBuf->append("/Tx BMC\n");
+ appearBuf->append("q BT\n");
+ appearBuf->append(daStr1 ? daStr1 : daStr)->append("\n");
+
+ sprintf(buf, "1 0 0 1 %.2f %.2f Tm\n", 2.0, yMax - yMin - fontSize);
+ appearBuf->append(buf);
+ sprintf(buf, "%g TL\n", fontSize);
+ appearBuf->append(buf);
+
+ if (hidden) {
+ //don't display hidden annot
+ } else if (isListbox) {
+ FormWidgetChoice* choice = static_cast<FormWidgetChoice*>(widget);
+ for(int i=0; i<choice->getNumChoices(); i++) {
+ if (choice->isSelected(i)) { //selected choice
+ //TODO: The color of the highlighting rect should depend on the color of the font.
+ //highlight with a black background rect
+ appearBuf->append("q\n");
+ sprintf(buf, "0 %f %f %f re\n", yMax-yMin-(i+1)*fontSize, xMax-xMin, fontSize);
+ appearBuf->append(buf);
+ appearBuf->append("f\n");
+ appearBuf->append("Q\n");
+ //draw the text in white
+ appearBuf->append("1.0 1.0 1.0 rg\n");
+ writeTextString(choice->getChoice(i), ccToUnicode, appearBuf, font);
+ appearBuf->append("0.0 0.0 0.0 rg\n");
+ } else
+ writeTextString(choice->getChoice(i), ccToUnicode, appearBuf, font);
+ }
+ vObj.free();
+ } else if (dict->lookup("V", &vObj)->isString()) {
+ //~ handle quadding -- this requires finding the font and using
+ //~ the encoding and char widths
+ vStr = vObj.getString();
+ writeTextString(vStr, ccToUnicode, appearBuf, font);
+ vObj.free();
+ }
+
+ appearBuf->append("ET Q\n");
+ appearBuf->append("EMC\n");
+
+ // build the appearance stream dictionary
+ appearDict.dictAdd("Length", obj1.initInt(appearBuf->getLength()));
+ appearDict.dictAdd("Subtype", obj1.initName("Form"));
+ obj1.initArray(xref);
+ obj1.arrayAdd(obj2.initReal(0));
+ obj1.arrayAdd(obj2.initReal(0));
+ obj1.arrayAdd(obj2.initReal(xMax - xMin));
+ obj1.arrayAdd(obj2.initReal(yMax - yMin));
+ appearDict.dictAdd("BBox", &obj1);
+
// build the appearance stream
appearStream = new MemStream(appearBuf->getCString(), 0,
appearBuf->getLength(), &appearDict);
+ appearance.free();
appearance.initStream(appearStream);
ok = gTrue;
@@ -268,11 +459,13 @@
}
}
daObj.free();
+
+ if (fontName) delete fontName;
+ if (font) delete font;
}
void Annot::draw(Gfx *gfx) {
Object obj;
-
if (appearance.fetch(xref, &obj)->isStream()) {
gfx->doAnnot(&obj, xMin, yMin, xMax, yMax);
}
@@ -298,8 +491,18 @@
catalog->getAcroForm()->getDict() : NULL;
if (annotsObj->isArray()) {
for (i = 0; i < annotsObj->arrayGetLength(); ++i) {
+ //get the Ref to this annot and pass it to Annot constructor
+ //this way, it'll be possible for the annot to retrieve the corresponding
+ //form widget
+ Object obj2;
+ Ref* pref;
+ if (annotsObj->arrayGetNF(i, &obj2)->isRef())
+ pref = &obj2.getRef();
+ else
+ pref = NULL;
+
if (annotsObj->arrayGet(i, &obj1)->isDict()) {
- annot = new Annot(xref, acroForm, obj1.getDict());
+ annot = new Annot(xref, acroForm, obj1.getDict(), pref, catalog);
if (annot->isOk()) {
if (nAnnots >= size) {
size += 16;
@@ -310,6 +513,7 @@
delete annot;
}
}
+ obj2.free();
obj1.free();
}
}
Index: Annot.h
===================================================================
RCS file: /cvs/poppler/poppler/poppler/Annot.h,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- Annot.h 27 Dec 2006 23:15:06 -0000 1.3
+++ Annot.h 24 Feb 2007 23:32:23 -0000 1.4
@@ -16,6 +16,9 @@
class XRef;
class Gfx;
class Catalog;
+class CharCodeToUnicode;
+class GfxFont;
+class FormWidget;
//------------------------------------------------------------------------
// Annot
@@ -24,7 +27,7 @@
class Annot {
public:
- Annot(XRef *xrefA, Dict *acroForm, Dict *dict);
+ Annot(XRef *xrefA, Dict *acroForm, Dict *dict, Ref* aref, Catalog* catalog);
~Annot();
GBool isOk() { return ok; }
@@ -32,9 +35,15 @@
// Get appearance object.
Object *getAppearance(Object *obj) { return appearance.fetch(xref, obj); }
+ GBool textField() { return isTextField; }
-private:
+ double getXMin() { return xMin; }
+ double getYMin() { return yMin; }
+
+ double getFontSize() { return fontSize; }
+private:
+ void writeTextString (GooString* vStr, CharCodeToUnicode* ccToUnicode, GooString* appearBuf, GfxFont* font);
void generateAppearance(Dict *acroForm, Dict *dict);
void readArrayNum(Object *pdfArray, int key, double *value);
@@ -44,7 +53,15 @@
GooString *appearBuf;
double xMin, yMin, // annotation rectangle
xMax, yMax;
+ double fontSize;
GBool ok;
+ GBool regen, isTextField;
+ GBool isMultiline, isListbox;
+
+ bool hasRef;
+ bool hidden;
+ Ref ref;
+ FormWidget* widget;
};
//------------------------------------------------------------------------
Index: Catalog.cc
===================================================================
RCS file: /cvs/poppler/poppler/poppler/Catalog.cc,v
retrieving revision 1.18
retrieving revision 1.19
diff -u -d -r1.18 -r1.19
--- Catalog.cc 11 Jan 2007 22:12:11 -0000 1.18
+++ Catalog.cc 24 Feb 2007 23:32:23 -0000 1.19
@@ -25,6 +25,7 @@
#include "PageLabelInfo.h"
#include "UGooString.h"
#include "Catalog.h"
+#include "Form.h"
// This define is used to limit the depth of recursive readPageTree calls
// This is needed because the page tree nodes can reference their parents
@@ -49,12 +50,21 @@
numPages = pagesSize = 0;
baseURI = NULL;
pageLabelInfo = NULL;
+ form = NULL;
xref->getCatalog(&catDict);
if (!catDict.isDict()) {
error(-1, "Catalog object is wrong type (%s)", catDict.getTypeName());
goto err1;
}
+ // get the AcroForm dictionary
+ catDict.dictLookup("AcroForm", &acroForm);
+
+ // load Forms
+ if (acroForm.isDict()) {
+ form = new Form(xref,&acroForm);
+ }
+
// read page tree
catDict.dictLookup("Pages", &pagesDict);
@@ -158,8 +168,9 @@
// get the outline dictionary
catDict.dictLookup("Outlines", &outline);
- // get the AcroForm dictionary
- catDict.dictLookup("AcroForm", &acroForm);
+ // perform form-related loading after all widgets have been loaded
+ if (form)
+ form->postWidgetsLoad();
catDict.free();
return;
@@ -242,7 +253,7 @@
kids.arrayGet(i, &kid);
if (kid.isDict("Page")) {
attrs2 = new PageAttrs(attrs1, kid.getDict());
- page = new Page(xref, start+1, kid.getDict(), attrs2);
+ page = new Page(xref, start+1, kid.getDict(), attrs2, form);
if (!page->isOk()) {
++start;
goto err3;
Index: Catalog.h
===================================================================
RCS file: /cvs/poppler/poppler/poppler/Catalog.h,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -d -r1.10 -r1.11
--- Catalog.h 11 Jan 2007 22:12:11 -0000 1.10
+++ Catalog.h 24 Feb 2007 23:32:23 -0000 1.11
@@ -21,6 +21,7 @@
class LinkDest;
class UGooString;
class PageLabelInfo;
+class Form;
//------------------------------------------------------------------------
// NameTree
@@ -151,6 +152,8 @@
Object *getAcroForm() { return &acroForm; }
+ Form* getForm() { return form; }
+
enum PageMode {
pageModeNone,
pageModeOutlines,
@@ -178,6 +181,7 @@
XRef *xref; // the xref table for this PDF file
Page **pages; // array of pages
Ref *pageRefs; // object ID for each page
+ Form *form;
int numPages; // number of pages
int pagesSize; // size of pages array
Object dests; // named destination dictionary
Index: CharCodeToUnicode.cc
===================================================================
RCS file: /cvs/poppler/poppler/poppler/CharCodeToUnicode.cc,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- CharCodeToUnicode.cc 18 Jan 2006 18:54:12 -0000 1.4
+++ CharCodeToUnicode.cc 24 Feb 2007 23:32:23 -0000 1.5
@@ -504,6 +504,40 @@
return 0;
}
+int CharCodeToUnicode::mapToCharCode(Unicode* u, CharCode *c, int usize) {
+ //look for charcode in map
+ if (usize == 1) {
+ for (int i=0; i<mapLen; i++) {
+ if (map[i] == ((*u)&0xff)) {
+ *c = (char)map[i];
+ return 1;
+ }
+ }
+ *c = 'x';
+ } else {
+ int i, j;
+ //for each entry in the sMap
+ for (i=0; i<sMapLen; i++) {
+ //if the entry's unicode length isn't the same are usize, the strings
+ // are obviously differents
+ if (sMap[i].len != usize) continue;
+ //compare the string char by char
+ for (j=0; j<sMap[i].len; j++) {
+ if (sMap[i].u[j] != u[j]) {
+ continue;
+ }
+ }
+
+ //we have the same strings
+ if (j==sMap[i].len) {
+ *c = sMap[i].c;
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
//------------------------------------------------------------------------
CharCodeToUnicodeCache::CharCodeToUnicodeCache(int sizeA) {
Index: CharCodeToUnicode.h
===================================================================
RCS file: /cvs/poppler/poppler/poppler/CharCodeToUnicode.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- CharCodeToUnicode.h 16 Sep 2005 18:38:58 -0000 1.2
+++ CharCodeToUnicode.h 24 Feb 2007 23:32:23 -0000 1.3
@@ -27,6 +27,7 @@
//------------------------------------------------------------------------
class CharCodeToUnicode {
+friend class UnicodeToCharCode;
public:
// Read the CID-to-Unicode mapping for <collection> from the file
@@ -66,6 +67,8 @@
// Map a CharCode to Unicode.
int mapToUnicode(CharCode c, Unicode *u, int size);
+ int mapToCharCode(Unicode* u, CharCode *c, int usize);
+
// Return the mapping's length, i.e., one more than the max char
// code supported by the mapping.
CharCode getLength() { return mapLen; }
Index: Dict.cc
===================================================================
RCS file: /cvs/poppler/poppler/poppler/Dict.cc,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- Dict.cc 3 Sep 2006 09:27:21 -0000 1.5
+++ Dict.cc 24 Feb 2007 23:32:23 -0000 1.6
@@ -65,6 +65,38 @@
return NULL;
}
+void Dict::remove(const UGooString &key) {
+ int i;
+ bool found = false;
+ DictEntry tmp;
+ if(length == 0) return;
+
+ for(i=0; i<length; i++) {
+ if (!key.cmp(entries[i].key)) {
+ found = true;
+ break;
+ }
+ }
+ if(!found) return;
+ //replace the deleted entry with the last entry
+ length -= 1;
+ tmp = entries[length];
+ if (i!=length) //don't copy the last entry if it is deleted
+ entries[i] = tmp;
+}
+
+void Dict::set(const UGooString &key, Object *val) {
+ DictEntry *e;
+ e = find (key);
+ if (e) {
+ e->val.free();
+ e->val = *val;
+ } else {
+ add (key, val);
+ }
+}
+
+
GBool Dict::is(char *type) {
DictEntry *e;
Index: Dict.h
===================================================================
RCS file: /cvs/poppler/poppler/poppler/Dict.h,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- Dict.h 3 Sep 2006 09:27:21 -0000 1.4
+++ Dict.h 24 Feb 2007 23:32:23 -0000 1.5
@@ -50,6 +50,10 @@
void addOwnVal(const char *key, Object *val) {
addOwnKeyVal(new UGooString(key), val);
}
+ // Update the value of an existing entry, otherwise create it
+ void set(const UGooString &key, Object *val);
+ // Remove an entry. This invalidate indexes
+ void remove(const UGooString &key);
// Check if dictionary is of specified type.
GBool is(char *type);
--- NEW FILE: Form.cc ---
//========================================================================
//
// Form.cc
//
// Copyright 2006 Julien Rebetez
//
//========================================================================
#include <config.h>
#ifdef USE_GCC_PRAGMAS
#pragma implementation
#endif
#include <stddef.h>
#include <string.h>
#include "goo/gmem.h"
#include "goo/GooString.h"
#include "Error.h"
[...1148 lines suppressed...]
FormWidget* tmp = form->findWidgetByRef(r);
if(tmp) {
// We've found a corresponding form field, link it
tmp->setID(FormWidget::encodeID(page, numWidgets));
widgets[numWidgets++] = tmp;
//create a temporary Annot to get the font size
Object obj2;
if (annots->arrayGet(i, &obj2)->isDict()) {
Annot* ann = new Annot(xref, NULL ,obj2.getDict(), NULL, NULL);
tmp->setFontSize(ann->getFontSize());
delete ann;
}
obj2.free();
}
obj1.free();
}
}
}
--- NEW FILE: Form.h ---
//========================================================================
//
// Form.h
//
// Copyright 2006 Julien Rebetez
//
//========================================================================
#ifndef FORM_H
#define FORM_H
#ifdef USE_GCC_PRAGMAS
#pragma interface
#endif
#include "Object.h"
#include "goo/GooVector.h"
class GooString;
class UGooString;
class Array;
class Dict;
class Annot;
class Catalog;
enum FormFieldType {
formButton,
formText,
formChoice,
formSignature,
formUndef,
};
enum FormButtonType {
formButtonCheck,
formButtonPush,
formButtonRadio
};
class Form;
class FormField;
class FormFieldButton;
class FormFieldText;
class FormFieldSignature;
class FormFieldChoice;
//------------------------------------------------------------------------
// FormWidget
// A FormWidget represents the graphical part of a field and is "attached"
// to a page.
//------------------------------------------------------------------------
class FormWidget {
public:
virtual ~FormWidget();
// see the description of FormField::LoadChildrenDefaults
virtual void loadDefaults () {}
// Check if point is inside the field bounding rect
GBool inRect(double x, double y)
{ return x1 <= x && x <= x2 && y1 <= y && y <= y2; }
// Get the field bounding rect
void getRect(double *xa1, double *ya1, double *xa2, double *ya2)
{ *xa1 = x1; *ya1 = y1; *xa2 = x2; *ya2 = y2; }
unsigned getID () { return ID; }
void setID (unsigned int i) { ID=i; }
FormFieldType getType() { return type; }
Object* getObj() { return &obj; }
Ref getRef() { return ref; }
void setChildNum (unsigned i) { childNum = i; }
unsigned getChildNum () { return childNum; }
void setFontSize(double f) { fontSize = f; }
double getFontSize () { return fontSize; }
virtual bool isReadOnly() const = 0;
// return the unique ID corresponding to pageNum/fieldNum
static int encodeID (unsigned pageNum, unsigned fieldNum);
// decode id and retrieve pageNum and fieldNum
static void decodeID (unsigned id, unsigned* pageNum, unsigned* fieldNum);
protected:
FormWidget(XRef *xrefA, Object *aobj, unsigned num, Ref aref);
FormWidget(FormWidget *dest);
FormField* field;
FormFieldType type;
Object obj;
Ref ref;
XRef *xref;
//index of this field in the parent's child list
unsigned childNum;
/*
Field ID is an (unsigned) integer, calculated as follow :
the first sizeof/2 bits are the field number, relative to the page
the last sizeof/2 bits are the page number
[page number | field number]
(encoding) id = (pageNum << 4*sizeof(unsigned)) + fieldNum;
(decoding) pageNum = id >> 4*sizeof(unsigned); fieldNum = (id << 4*sizeof(unsigned)) >> 4*sizeof(unsigned);
*/
unsigned ID;
double x1, y1; // lower left corner
double x2, y2; // upper right corner
double fontSize; //font size if this widget has text
};
//------------------------------------------------------------------------
// FormWidgetButton
//------------------------------------------------------------------------
class FormWidgetButton: public FormWidget {
public:
FormWidgetButton(XRef *xrefA, Object *dict, unsigned num, Ref ref, FormFieldButton *p);
~FormWidgetButton ();
void setState (GBool state, GBool calledByParent=gFalse);
GBool getState ();
char* getOnStr () { return onStr; }
void loadDefaults();
bool isReadOnly () const;
void setNumSiblingsID (int i);
void setSiblingsID (int i, unsigned id) { siblingsID[i] = id; }
//For radio buttons, return the IDs of the other radio buttons in the same group
unsigned* getSiblingsID () const { return siblingsID; }
int getNumSiblingsID () const { return numSiblingsID; }
protected:
unsigned* siblingsID; // IDs of dependent buttons (each button of a radio field has all the others buttons
// of the same field in this array)
int numSiblingsID;
char *onStr;
FormFieldButton *parent;
GBool state;
};
//------------------------------------------------------------------------
// FormWidgetText
//------------------------------------------------------------------------
class FormWidgetText: public FormWidget {
public:
FormWidgetText(XRef *xrefA, Object *dict, unsigned num, Ref ref, FormFieldText *p);
//return the field's content (UTF16BE)
GooString* getContent() ;
//return a copy of the field's content (UTF16BE)
GooString* getContentCopy();
//except a UTF16BE string
void setContent(GooString* new_content);
void loadDefaults ();
bool isMultiline () const;
bool isPassword () const;
bool isFileSelect () const;
bool noSpellCheck () const;
bool noScroll () const;
bool isComb () const;
bool isRichText () const;
bool isReadOnly () const;
protected:
FormFieldText *parent;
};
//------------------------------------------------------------------------
// FormWidgetChoice
//------------------------------------------------------------------------
class FormWidgetChoice: public FormWidget {
public:
FormWidgetChoice(XRef *xrefA, Object *dict, unsigned num, Ref ref, FormFieldChoice *p);
~FormWidgetChoice();
void loadDefaults ();
int getNumChoices();
//return the display name of the i-th choice (UTF16BE)
GooString* getChoice(int i);
//select the i-th choice
void select (int i);
//toggle selection of the i-th choice
void toggle (int i);
//deselect everything
void deselectAll ();
//except a UTF16BE string
//only work for editable combo box, set the user-entered text as the current choice
void setEditChoice(GooString* new_content);
GooString* getEditChoice ();
bool isSelected (int i);
bool isCombo () const;
bool hasEdit () const;
bool isMultiSelect () const;
bool noSpellCheck () const;
bool commitOnSelChange () const;
bool isReadOnly () const;
bool isListBox () const;
protected:
void _updateV ();
bool _checkRange (int i);
FormFieldChoice *parent;
};
//------------------------------------------------------------------------
// FormWidgetSignature
//------------------------------------------------------------------------
class FormWidgetSignature: public FormWidget {
public:
FormWidgetSignature(XRef *xrefA, Object *dict, unsigned num, Ref ref, FormFieldSignature *p);
bool isReadOnly () const;
protected:
FormFieldSignature *parent;
};
//------------------------------------------------------------------------
// FormField
// A FormField implements the logical side of a field and is "attached" to
// the Catalog. This is an internal class and client applications should
// only interact with FormWidgets.
//------------------------------------------------------------------------
class FormField {
public:
FormField(XRef* xrefa, Object *aobj, Ref *aref, Form* aform, FormFieldType t=formUndef);
virtual ~FormField();
FormField *copy() { return new FormField(this); }
// Accessors.
FormFieldType getType() { return type; }
Object* getObj() { return &obj; }
Ref getRef() { return ref; }
void setReadOnly (bool b) { readOnly = b; }
bool isReadOnly () const { return readOnly; }
FormWidget* findWidgetByRef (Ref aref);
// Since while loading their defaults, children may call parents methods, it's better
// to do that when parents are completly constructed
void loadChildrenDefaults();
// only implemented in FormFieldButton
virtual void fillChildrenSiblingsID ();
protected:
void _createWidget (Object *obj, Ref aref);
FormFieldType type; // field type
Ref ref;
bool direct;
bool terminal;
Object obj;
XRef *xref;
FormField **children;
int numChildren;
FormWidget **widgets;
Form* form;
bool readOnly;
private:
FormField() {}
FormField(FormField *dest);
};
//------------------------------------------------------------------------
// FormFieldButton
//------------------------------------------------------------------------
class FormFieldButton: public FormField {
public:
FormFieldButton(XRef *xrefA, Object *dict, Ref *ref, Form* form);
FormButtonType getButtonType () { return btype; }
bool noToggleToOff () const { return noAllOff; }
// returns gTrue if the state modification is accepted
GBool setState (int num, GBool s);
void fillChildrenSiblingsID ();
virtual ~FormFieldButton();
protected:
FormButtonType btype;
int size;
int active_child; //only used for combo box
bool noAllOff;
};
//------------------------------------------------------------------------
// FormFieldText
//------------------------------------------------------------------------
class FormFieldText: public FormField {
public:
FormFieldText(XRef *xrefA, Object *dict, Ref *ref, Form* form);
GooString* getContent () { return content; }
GooString* getContentCopy ();
void setContentCopy (GooString* new_content);
virtual ~FormFieldText();
bool isMultiline () const { return multiline; }
bool isPassword () const { return password; }
bool isFileSelect () const { return fileSelect; }
bool noSpellCheck () const { return doNotSpellCheck; }
bool noScroll () const { return doNotScroll; }
bool isComb () const { return comb; }
bool isRichText () const { return richText; }
protected:
GooString* content;
bool multiline;
bool password;
bool fileSelect;
bool doNotSpellCheck;
bool doNotScroll;
bool comb;
bool richText;
};
//------------------------------------------------------------------------
// FormFieldChoice
//------------------------------------------------------------------------
class FormFieldChoice: public FormField {
public:
FormFieldChoice(XRef *xrefA, Object *aobj, Ref *ref, Form* form);
virtual ~FormFieldChoice();
int getNumChoices() { return numChoices; }
GooString* getChoice(int i) { return choices[i].optionName; }
GooString* getExportVal (int i) { return choices[i].exportVal; }
//select the i-th choice
void select (int i);
//toggle selection of the i-th choice
void toggle (int i);
//deselect everything
void deselectAll ();
//only work for editable combo box, set the user-entered text as the current choice
void setEditChoice(GooString* new_content);
GooString* getEditChoice ();
bool isSelected (int i) { return choices[i].selected; }
int getNumSelected ();
bool isCombo () const { return combo; }
bool hasEdit () const { return edit; }
bool isMultiSelect () const { return multiselect; }
bool noSpellCheck () const { return doNotSpellCheck; }
bool commitOnSelChange () const { return doCommitOnSelChange; }
bool isListBox () const { return !combo; }
/* 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:
bool combo;
bool edit;
bool multiselect;
bool doNotSpellCheck;
bool doCommitOnSelChange;
struct ChoiceOpt {
GooString* exportVal; //the export value ("internal" name)
GooString* optionName; //displayed name
bool selected; //if this choice is selected
};
int numChoices;
ChoiceOpt* choices;
GooString* editedChoice;
};
//------------------------------------------------------------------------
// FormFieldSignature
//------------------------------------------------------------------------
class FormFieldSignature: public FormField {
public:
FormFieldSignature(XRef *xrefA, Object *dict, Ref *ref, Form* form);
virtual ~FormFieldSignature();
};
//------------------------------------------------------------------------
// Form
// This class handle the document-wide part of Form (things in the acroForm
// Catalog entry).
//------------------------------------------------------------------------
class Form {
public:
Form(XRef *xrefA, Object* acroForm);
~Form();
int getNumFields() const { return numFields; }
FormField* getRootField(int i) const { return rootFields[i]; }
FormWidget* findWidgetByRef (Ref aref);
/* Creates a new Field of the type specified in obj's dict.
used in Form::Form and FormField::FormField */
void createFieldFromDict (Object* obj, FormField** ptr, XRef *xref, Ref* pref);
void postWidgetsLoad();
void checkForNeedAppearances ();
private:
FormField** rootFields;
int numFields;
int size;
XRef* xref;
Catalog* catalog;
};
//------------------------------------------------------------------------
// FormPageWidgets
//------------------------------------------------------------------------
class FormPageWidgets {
public:
FormPageWidgets (XRef *xrefA, Object* annots, unsigned int page, Form *form);
~FormPageWidgets();
int getNumWidgets() const { return numWidgets; }
FormWidget* getWidget(int i) const { return widgets[i]; }
private:
FormWidget** widgets;
int numWidgets;
int size;
unsigned pageNum;
XRef* xref;
};
#endif
Index: GfxFont.cc
===================================================================
RCS file: /cvs/poppler/poppler/poppler/GfxFont.cc,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -d -r1.9 -r1.10
--- GfxFont.cc 2 May 2006 04:38:39 -0000 1.9
+++ GfxFont.cc 24 Feb 2007 23:32:23 -0000 1.10
@@ -1582,6 +1582,33 @@
return map;
}
+double GfxCIDFont::getWidth (char* s, int len) {
+ int nUsed;
+ double w, h, vx, vy;
+ int a, b, m;
+
+ CID cid = cMap->getCID(s, len, &nUsed);
+
+ w = widths.defWidth;
+ if (widths.nExceps > 0 && cid >= widths.exceps[0].first) {
+ a = 0;
+ b = widths.nExceps;
+ // invariant: widths.exceps[a].first <= cid < widths.exceps[b].first
+ while (b - a > 1) {
+ m = (a + b) / 2;
+ if (widths.exceps[m].first <= cid) {
+ a = m;
+ } else {
+ b = m;
+ }
+ }
+ if (cid <= widths.exceps[a].last) {
+ w = widths.exceps[a].width;
+ }
+ }
+ return w;
+}
+
//------------------------------------------------------------------------
// GfxFontDict
//------------------------------------------------------------------------
Index: GfxFont.h
===================================================================
RCS file: /cvs/poppler/poppler/poppler/GfxFont.h,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- GfxFont.h 2 May 2006 04:38:39 -0000 1.4
+++ GfxFont.h 24 Feb 2007 23:32:23 -0000 1.5
@@ -167,6 +167,9 @@
GBool isItalic() { return flags & fontItalic; }
GBool isBold() { return flags & fontBold; }
+ // Return the Unicode map.
+ virtual CharCodeToUnicode *getToUnicode() = 0;
+
// Return the font matrix.
double *getFontMatrix() { return fontMat; }
@@ -316,6 +319,8 @@
Gushort *getCodeToGIDMap(FoFiTrueType *ff, int *length);
+ double getWidth(char* s, int len);
+
private:
CMap *cMap; // char code --> CID
Index: Makefile.am
===================================================================
RCS file: /cvs/poppler/poppler/poppler/Makefile.am,v
retrieving revision 1.27
retrieving revision 1.28
diff -u -d -r1.27 -r1.28
--- Makefile.am 13 Jan 2007 18:29:39 -0000 1.27
+++ Makefile.am 24 Feb 2007 23:32:23 -0000 1.28
@@ -117,6 +117,7 @@
Error.h \
FontEncodingTables.h \
FontInfo.h \
+ Form.h \
Function.cc \
Function.h \
Gfx.h \
@@ -179,6 +180,7 @@
Dict.cc \
Error.cc \
FontEncodingTables.cc \
+ Form.cc \
FontInfo.cc \
Function.cc \
Gfx.cc \
Index: Object.h
===================================================================
RCS file: /cvs/poppler/poppler/poppler/Object.h,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- Object.h 3 Sep 2006 09:27:21 -0000 1.3
+++ Object.h 24 Feb 2007 23:32:23 -0000 1.4
@@ -171,6 +171,7 @@
void dictAddOwnKeyVal(UGooString *key, Object *val);
void dictAdd(const UGooString &key, Object *val);
void dictAddOwnVal(const char *key, Object *val);
+ void dictSet(const UGooString &key, Object *val);
GBool dictIs(char *dictType);
Object *dictLookup(const UGooString &key, Object *obj);
Object *dictLookupNF(const UGooString &key, Object *obj);
@@ -254,6 +255,9 @@
inline void Object::dictAddOwnKeyVal(UGooString *key, Object *val)
{ dict->addOwnKeyVal(key, val); }
+inline void Object::dictSet(const UGooString &key, Object *val)
+ { dict->set(key, val); }
+
inline GBool Object::dictIs(char *dictType)
{ return dict->is(dictType); }
Index: Page.cc
===================================================================
RCS file: /cvs/poppler/poppler/poppler/Page.cc,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -d -r1.15 -r1.16
--- Page.cc 26 Dec 2006 19:56:29 -0000 1.15
+++ Page.cc 24 Feb 2007 23:32:23 -0000 1.16
@@ -26,10 +26,12 @@
#include "GfxState.h"
#include "Annot.h"
#include "TextOutputDev.h"
+#include "Form.h"
#endif
#include "Error.h"
#include "Page.h"
#include "UGooString.h"
+#include "Form.h"
//------------------------------------------------------------------------
// PageAttrs
@@ -188,7 +190,7 @@
// Page
//------------------------------------------------------------------------
-Page::Page(XRef *xrefA, int numA, Dict *pageDict, PageAttrs *attrsA) {
+Page::Page(XRef *xrefA, int numA, Dict *pageDict, PageAttrs *attrsA, Form *form) {
Object tmp;
ok = gTrue;
@@ -226,6 +228,10 @@
goto err2;
}
+ // forms
+ pageWidgets = new FormPageWidgets(xrefA, this->getAnnots(&tmp),num,form);
+ tmp.free();
+
// contents
pageDict->lookupNF("Contents", &contents);
if (!(contents.isRef() || contents.isArray() ||
@@ -420,9 +426,10 @@
Annot *annot = annotList->getAnnot(i);
if ((annotDisplayDecideCbk &&
(*annotDisplayDecideCbk)(annot, annotDisplayDecideCbkData)) ||
- !annotDisplayDecideCbk)
+ !annotDisplayDecideCbk) {
annot->draw(gfx);
}
+ }
out->dump();
}
delete annotList;
Index: Page.h
===================================================================
RCS file: /cvs/poppler/poppler/poppler/Page.h,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- Page.h 26 Dec 2006 19:56:29 -0000 1.7
+++ Page.h 24 Feb 2007 23:32:23 -0000 1.8
@@ -23,6 +23,8 @@
class Annots;
class Annot;
class Gfx;
+class FormPageWidgets;
+class Form;
//------------------------------------------------------------------------
@@ -104,7 +106,7 @@
public:
// Constructor.
- Page(XRef *xrefA, int numA, Dict *pageDict, PageAttrs *attrsA);
+ Page(XRef *xrefA, int numA, Dict *pageDict, PageAttrs *attrsA, Form *form);
// Destructor.
~Page();
@@ -151,6 +153,9 @@
// Get transition.
Object *getTrans(Object *obj) { return trans.fetch(xref, obj); }
+ // Get form.
+ FormPageWidgets *getPageWidgets() { return pageWidgets; }
+
// Get duration, the maximum length of time, in seconds,
// that the page is displayed before the presentation automatically
// advances to the next page
@@ -200,6 +205,7 @@
PageAttrs *attrs; // page attributes
Object annots; // annotations array
Object contents; // page contents
+ FormPageWidgets *pageWidgets; // the form for that page
Object thumb; // page thumbnail
Object trans; // page transition
Object actions; // page addiction actions
Index: XRef.cc
===================================================================
RCS file: /cvs/poppler/poppler/poppler/XRef.cc,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -d -r1.13 -r1.14
--- XRef.cc 1 Apr 2006 11:25:57 -0000 1.13
+++ XRef.cc 24 Feb 2007 23:32:23 -0000 1.14
@@ -201,6 +201,16 @@
// XRef
//------------------------------------------------------------------------
+XRef::XRef() {
+ ok = gTrue;
+ errCode = errNone;
+ entries = NULL;
+ size = 0;
+ streamEnds = NULL;
+ streamEndsLen = 0;
+ objStr = NULL;
+}
+
XRef::XRef(BaseStream *strA) {
Guint pos;
Object obj;
@@ -264,7 +274,12 @@
}
XRef::~XRef() {
+ for(int i=0; i<size; i++) {
+ if (entries[i].obj)
+ delete entries[i].obj;
+ }
gfree(entries);
+
trailerDict.free();
if (streamEnds) {
gfree(streamEnds);
@@ -397,6 +412,7 @@
for (i = size; i < newSize; ++i) {
entries[i].offset = 0xffffffff;
entries[i].type = xrefEntryFree;
+ entries[i].obj = NULL;
}
size = newSize;
}
@@ -410,6 +426,7 @@
goto err1;
}
entry.gen = obj.getInt();
+ entry.obj = NULL;
obj.free();
parser->getObj(&obj);
if (obj.isCmd("n")) {
@@ -507,6 +524,7 @@
for (i = size; i < newSize; ++i) {
entries[i].offset = 0xffffffff;
entries[i].type = xrefEntryFree;
+ entries[i].obj = NULL;
}
size = newSize;
}
@@ -601,6 +619,7 @@
for (i = size; i < newSize; ++i) {
entries[i].offset = 0xffffffff;
entries[i].type = xrefEntryFree;
+ entries[i].obj = NULL;
}
size = newSize;
}
@@ -741,6 +760,7 @@
for (i = size; i < newSize; ++i) {
entries[i].offset = 0xffffffff;
entries[i].type = xrefEntryFree;
+ entries[i].obj = NULL;
}
size = newSize;
}
@@ -850,6 +870,10 @@
}
e = &entries[num];
+ if(e->obj) { //check for updated object
+ obj = e->obj->copy(obj);
+ return obj;
+ }
switch (e->type) {
case xrefEntryUncompressed:
@@ -967,3 +991,66 @@
}
return x;
}
+
+void XRef::add(int num, int gen, Guint offs, GBool used) {
+ size += 1;
+ entries = (XRefEntry *)greallocn(entries, size, sizeof(XRefEntry));
+ XRefEntry *e = &entries[size-1];
+
+ e->gen = gen;
+ e->num = num;
+ e->obj = NULL;
+ if (used) {
+ e->type = xrefEntryUncompressed;
+ e->offset = offs;
+ } else {
+ e->type = xrefEntryFree;
+ e->offset = 0;
+ }
+}
+
+void XRef::setModifiedObject (Object* o, Ref r) {
+ if (r.num < 0 || r.num >= size) {
+ error(-1,"XRef::setModifiedObject on unknown ref: %i, %i\n", r.num, r.gen);
+ return;
+ }
+ entries[r.num].obj = new Object();
+ o->copy(entries[r.num].obj);
+}
+
+//used to sort the entries
+int compare (const void* a, const void* b)
+{
+ return (((XRefEntry*)a)->num - ((XRefEntry*)b)->num);
+}
+
+void XRef::writeToFile(FILE* file) {
+ qsort(entries, size, sizeof(XRefEntry), compare);
+ //create free entries linked-list
+ if (entries[0].gen != 65535) {
+ error(-1, "XRef::writeToFile, entry 0 of the XRef is invalid (gen != 65535)\n");
+ }
+ int lastFreeEntry = 0;
+ for (int i=0; i<size; i++) {
+ if (entries[i].type == xrefEntryFree) {
+ entries[lastFreeEntry].offset = entries[i].num;
+ lastFreeEntry = i;
+ }
+ }
+ //write the new xref
+ int j;
+ fprintf(file,"xref\r\n");
+ for (int i=0; i<size; i++) {
+ for(j=i; j<size; j++) { //look for consecutive entry
+ if (j!=i && entries[j].num != entries[j-1].num+1)
+ break;
+ }
+ fprintf(file,"%i %i\r\n", entries[i].num, j-i);
+ for (int k=i; k<j; k++) {
+ if(entries[k].gen > 65535) entries[k].gen = 65535; //cap generation number to 65535 (required by PDFReference)
+ fprintf(file,"%010i %05i %c\r\n", entries[k].offset, entries[k].gen, (entries[k].type==xrefEntryFree)?'f':'n');
+ }
+ i = j-1;
+ }
+}
+
Index: XRef.h
===================================================================
RCS file: /cvs/poppler/poppler/poppler/XRef.h,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- XRef.h 17 Jan 2006 21:35:31 -0000 1.6
+++ XRef.h 24 Feb 2007 23:32:23 -0000 1.7
@@ -34,12 +34,16 @@
struct XRefEntry {
Guint offset;
int gen;
+ int num;
XRefEntryType type;
+ Object* obj;
};
class XRef {
public:
+ // Constructor, create an empty XRef, used for PDF writing
+ XRef();
// Constructor. Read xref table from stream.
XRef(BaseStream *strA);
@@ -102,6 +106,11 @@
XRefEntry *getEntry(int i) { return &entries[i]; }
Object *getTrailerDict() { return &trailerDict; }
+ // Write access
+ void setModifiedObject(Object* o, Ref r);
+ void add(int num, int gen, Guint offs, GBool used);
+ void writeToFile(FILE* f);
+
private:
BaseStream *str; // input stream
- Previous message: [poppler] poppler/glib: poppler-document.cc, 1.39,
1.40 poppler-document.h, 1.22, 1.23 poppler-page.cc, 1.53,
1.54 poppler-page.h, 1.22, 1.23 poppler-private.h, 1.16,
1.17 poppler.h, 1.12, 1.13
- Next message: [poppler] poppler/test: gtk-splash-test.cc, 1.5,
1.6 pdf-inspector.cc, 1.5, 1.6
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]
More information about the poppler
mailing list