[poppler] Branch 'poppler-0.20' - 3 commits - poppler/Annot.cc poppler/Annot.h poppler/Form.cc poppler/Form.h

Carlos Garcia Campos carlosgc at kemper.freedesktop.org
Tue Oct 16 05:25:55 PDT 2012


 poppler/Annot.cc |   52 ++++++++++++++++++++++++++++++++++++++++++++++------
 poppler/Annot.h  |    2 ++
 poppler/Form.cc  |   52 ++++++++++++++++++++++++++++++++++++++--------------
 poppler/Form.h   |   12 +++++++++---
 4 files changed, 95 insertions(+), 23 deletions(-)

New commits:
commit 35c07fe40d7b18e19f6ef0f5615f9f5ac8195cf7
Author: Fabio D'Urso <fabiodurso at hotmail.it>
Date:   Tue Oct 9 15:24:02 2012 +0200

    AnnotWidget: Avoid repeatedly deleting and creating xref entries for appearance streams
    
    Previously updating the appearance stream always involved deleting the old
    stream's xref entry and creating a new one.
    Since xref entry deletion causes the generation number to be incremented, this
    behavior caused the generation number to quickly rise during user input.
    
    This patch stops it by reusing the same entry as the old appearance stream in
    case of repeated modifications.

diff --git a/poppler/Annot.cc b/poppler/Annot.cc
index dfbc6a3..675ec84 100644
--- a/poppler/Annot.cc
+++ b/poppler/Annot.cc
@@ -3774,6 +3774,8 @@ void AnnotWidget::initialize(PDFDoc *docA, Dict *dict) {
     parent = NULL;
   }
   obj1.free();
+
+  updatedAppearanceStream.num = updatedAppearanceStream.gen = -1;
 }
 
 // Grand unified handler for preparing text strings to be drawn into form
@@ -4867,8 +4869,11 @@ void AnnotWidget::generateFieldAppearance() {
 
 void AnnotWidget::updateAppearanceStream()
 {
-  // Destroy the old appearance if any
-  invalidateAppearance();
+  // If this the first time updateAppearanceStream() is called on this widget,
+  // destroy the AP dictionary because we are going to create a new one.
+  if (updatedAppearanceStream.num == -1) {
+    invalidateAppearance(); // Delete AP dictionary and all referenced streams
+  }
 
   // There's no need to create a new appearance stream if NeedAppearances is
   // set, because it will be ignored next time anyway.
@@ -4879,19 +4884,30 @@ void AnnotWidget::updateAppearanceStream()
   generateFieldAppearance();
 
   // Fetch the appearance stream we've just created
-  Object obj1, obj2;
-  Ref apRef;
+  Object obj1;
   appearance.fetch(xref, &obj1);
-  apRef = xref->addIndirectObject(&obj1);
-  obj1.free();
 
-  // Write the AP dictionary
-  obj1.initDict(xref);
-  obj1.dictAdd(copyString("N"), obj2.initRef(apRef.num, apRef.gen));
-  update("AP", &obj1);
+  // If this the first time updateAppearanceStream() is called on this widget,
+  // create a new AP dictionary containing the new appearance stream.
+  // Otherwise, just update the stream we had created previously.
+  if (updatedAppearanceStream.num == -1) {
+    // Write the appearance stream
+    updatedAppearanceStream = xref->addIndirectObject(&obj1);
+    obj1.free();
 
-  // Update our internal pointers to the appearance dictionary
-  appearStreams = new AnnotAppearance(doc, &obj1);
+    // Write the AP dictionary
+    Object obj2;
+    obj1.initDict(xref);
+    obj1.dictAdd(copyString("N"), obj2.initRef(updatedAppearanceStream.num, updatedAppearanceStream.gen));
+    update("AP", &obj1);
+
+    // Update our internal pointers to the appearance dictionary
+    appearStreams = new AnnotAppearance(doc, &obj1);
+  } else {
+    // Replace the existing appearance stream
+    xref->setModifiedObject(&obj1, updatedAppearanceStream);
+    obj1.free();
+  }
 }
 
 void AnnotWidget::draw(Gfx *gfx, GBool printing) {
diff --git a/poppler/Annot.h b/poppler/Annot.h
index c208bc7..7cbc143 100644
--- a/poppler/Annot.h
+++ b/poppler/Annot.h
@@ -1298,6 +1298,7 @@ private:
   // AnnotBorderBS border;                // BS
   Dict *parent;                           // Parent
   GBool addDingbatsResource;
+  Ref updatedAppearanceStream; // {-1,-1} if updateAppearanceStream has never been called
 };
 
 //------------------------------------------------------------------------
commit 2127a977bbe9985aa58561116508ad4f08430a2c
Author: Fabio D'Urso <fabiodurso at hotmail.it>
Date:   Tue Oct 9 12:49:26 2012 +0200

    Generate and write the appearance stream in AnnotWidget::updateWidgetApperance()
    
    Note: At the moment the old appearance is deleted and a *new* xref entry is
    created every time AnnotWidget::updateWidgetApperance() is called.

diff --git a/poppler/Annot.cc b/poppler/Annot.cc
index dda85e9..dfbc6a3 100644
--- a/poppler/Annot.cc
+++ b/poppler/Annot.cc
@@ -4865,13 +4865,33 @@ void AnnotWidget::generateFieldAppearance() {
   appearStream->setNeedFree(gTrue);
 }
 
-// NOTE: This is a temporary implementation!
-// TODO: Generate new appearance stream *here* and write it
 void AnnotWidget::updateAppearanceStream()
 {
-  // Remove the old appearance so that AnnotWidget::draw will rebuild it next time
-  appearance.free();
-  appearance.initNull();
+  // Destroy the old appearance if any
+  invalidateAppearance();
+
+  // There's no need to create a new appearance stream if NeedAppearances is
+  // set, because it will be ignored next time anyway.
+  if (form && form->getNeedAppearances())
+    return;
+
+  // Create the new appearance
+  generateFieldAppearance();
+
+  // Fetch the appearance stream we've just created
+  Object obj1, obj2;
+  Ref apRef;
+  appearance.fetch(xref, &obj1);
+  apRef = xref->addIndirectObject(&obj1);
+  obj1.free();
+
+  // Write the AP dictionary
+  obj1.initDict(xref);
+  obj1.dictAdd(copyString("N"), obj2.initRef(apRef.num, apRef.gen));
+  update("AP", &obj1);
+
+  // Update our internal pointers to the appearance dictionary
+  appearStreams = new AnnotAppearance(doc, &obj1);
 }
 
 void AnnotWidget::draw(Gfx *gfx, GBool printing) {
commit 0446e2cc1073f4579a90284d28bc5872e46e0536
Author: Fabio D'Urso <fabiodurso at hotmail.it>
Date:   Tue Oct 9 10:47:40 2012 +0200

    Killed FormField::isModified() in favor of a new AnnotWidget callback
    
    Instead of having to ask FormField from AnnotWidget::draw if the
    widget's appearance needs to be rebuilt, now AnnotWidget gets notified
    of changes via the new AnnotWidget::updateAppearanceStream() callback.

diff --git a/poppler/Annot.cc b/poppler/Annot.cc
index aa8b9a8..dda85e9 100644
--- a/poppler/Annot.cc
+++ b/poppler/Annot.cc
@@ -4865,6 +4865,14 @@ void AnnotWidget::generateFieldAppearance() {
   appearStream->setNeedFree(gTrue);
 }
 
+// NOTE: This is a temporary implementation!
+// TODO: Generate new appearance stream *here* and write it
+void AnnotWidget::updateAppearanceStream()
+{
+  // Remove the old appearance so that AnnotWidget::draw will rebuild it next time
+  appearance.free();
+  appearance.initNull();
+}
 
 void AnnotWidget::draw(Gfx *gfx, GBool printing) {
   Object obj;
@@ -4876,13 +4884,9 @@ void AnnotWidget::draw(Gfx *gfx, GBool printing) {
 
   // Only construct the appearance stream when
   // - annot doesn't have an AP or
-  // - it's a field containing text (text and choices) and
-  // - NeedAppearances is true or
-  // - widget has been modified or
+  // - NeedAppearances is true
   if (field) {
-    if (appearance.isNull() || (form && form->getNeedAppearances()) ||
-        ((field->getType() == formText || field->getType() == formChoice) &&
-         field->isModified()))
+    if (appearance.isNull() || (form && form->getNeedAppearances()))
       generateFieldAppearance();
   }
 
diff --git a/poppler/Annot.h b/poppler/Annot.h
index 04a1301..c208bc7 100644
--- a/poppler/Annot.h
+++ b/poppler/Annot.h
@@ -1269,6 +1269,7 @@ public:
   void drawFormFieldText(GfxResources *resources, GooString *da);
   void drawFormFieldChoice(GfxResources *resources, GooString *da);
   void generateFieldAppearance ();
+  void updateAppearanceStream ();
 
   AnnotWidgetHighlightMode getMode() { return mode; }
   AnnotAppearanceCharacs *getAppearCharacs() { return appearCharacs; }
diff --git a/poppler/Form.cc b/poppler/Form.cc
index 8a242c4..a2be980 100644
--- a/poppler/Form.cc
+++ b/poppler/Form.cc
@@ -14,6 +14,7 @@
 // Copyright 2009 Matthias Drochner <M.Drochner at fz-juelich.de>
 // Copyright 2009 KDAB via Guillermo Amaral <gamaral at amaral.com.mx>
 // Copyright 2010, 2012 Mark Riedesel <mark at klowner.com>
+// Copyright 2012 Fabio D'Urso <fabiodurso at hotmail.it>
 // 
 //========================================================================
 
@@ -124,10 +125,6 @@ bool FormWidget::isReadOnly() const
   return field->isReadOnly();
 }
 
-GBool FormWidget::isModified() const {
-  return field->isModified();
-}
-
 int FormWidget::encodeID (unsigned pageNum, unsigned fieldNum)
 {
   return (pageNum << 4*sizeof(unsigned)) + fieldNum;
@@ -215,6 +212,11 @@ void FormWidgetButton::setAppearanceState(const char *state) {
   widget->setAppearanceState(state);
 }
 
+void FormWidgetButton::updateWidgetAppearance()
+{
+  // The appearance stream must NOT be regenerated for this widget type
+}
+
 void FormWidgetButton::setState (GBool astate)
 {
   //pushButtons don't have state
@@ -257,7 +259,13 @@ GooString* FormWidgetText::getContentCopy ()
 {
   return parent->getContentCopy();
 }
-  
+
+void FormWidgetText::updateWidgetAppearance()
+{
+  if (widget)
+    widget->updateAppearanceStream();
+}
+
 bool FormWidgetText::isMultiline () const 
 { 
   return parent->isMultiline(); 
@@ -366,6 +374,12 @@ GooString* FormWidgetChoice::getEditChoice ()
   return parent->getEditChoice();
 }
 
+void FormWidgetChoice::updateWidgetAppearance()
+{
+  if (widget)
+    widget->updateAppearanceStream();
+}
+
 bool FormWidgetChoice::isSelected (int i)
 {
   if (!_checkRange(i)) return false;
@@ -433,6 +447,11 @@ FormWidgetSignature::FormWidgetSignature(PDFDoc *docA, Object *aobj, unsigned nu
   parent = static_cast<FormFieldSignature*>(field);
 }
 
+void FormWidgetSignature::updateWidgetAppearance()
+{
+  // Unimplemented
+}
+
 
 //========================================================================
 // FormField
@@ -456,7 +475,6 @@ FormField::FormField(PDFDoc *docA, Object *aobj, const Ref& aref, FormField *par
   fullyQualifiedName = NULL;
   quadding = quaddingLeftJustified;
   hasQuadding = gFalse;
-  modified = gFalse;
 
   ref = aref;
 
@@ -633,10 +651,6 @@ void FormField::createWidgetAnnotations() {
   }
 }
 
-GBool FormField::isModified() const {
-  return modified ? gTrue : parent ? parent->isModified() : gFalse;
-}
-
 void FormField::_createWidget (Object *obj, Ref aref)
 {
   terminal = true;
@@ -768,6 +782,18 @@ GooString* FormField::getFullyQualifiedName() {
   return fullyQualifiedName;
 }
 
+void FormField::updateChildrenAppearance()
+{
+  // Recursively update each child's appearance
+  if (terminal) {
+    for (int i = 0; i < numChildren; i++)
+      widgets[i]->updateWidgetAppearance();
+  } else {
+    for (int i = 0; i < numChildren; i++)
+      children[i]->updateChildrenAppearance();
+  }
+}
+
 //------------------------------------------------------------------------
 // FormFieldButton
 //------------------------------------------------------------------------
@@ -861,7 +887,6 @@ GBool FormFieldButton::setState(char *state)
   if (terminal && parent && parent->getType() == formButton && appearanceState.isNull()) {
     // It's button in a set, set state on parent
     if (static_cast<FormFieldButton*>(parent)->setState(state)) {
-      modified = gTrue;
       return gTrue;
     }
     return gFalse;
@@ -907,7 +932,6 @@ GBool FormFieldButton::setState(char *state)
   }
 
   updateState(state);
-  modified = gTrue;
 
   return gTrue;
 }
@@ -1019,7 +1043,7 @@ void FormFieldText::setContentCopy (GooString* new_content)
   obj1.initString(content ? content->copy() : new GooString(""));
   obj.getDict()->set("V", &obj1);
   xref->setModifiedObject(&obj, ref);
-  modified = gTrue;
+  updateChildrenAppearance();
 }
 
 FormFieldText::~FormFieldText()
@@ -1194,7 +1218,7 @@ void FormFieldChoice::updateSelection() {
 
   obj.getDict()->set("V", &obj1);
   xref->setModifiedObject(&obj, ref);
-  modified = gTrue;
+  updateChildrenAppearance();
 }
 
 void FormFieldChoice::unselectAll ()
diff --git a/poppler/Form.h b/poppler/Form.h
index fa3c718..4146728 100644
--- a/poppler/Form.h
+++ b/poppler/Form.h
@@ -9,6 +9,7 @@
 // Copyright 2007-2010 Albert Astals Cid <aacid at kde.org>
 // Copyright 2010 Mark Riedesel <mark at klowner.com>
 // Copyright 2011 Pino Toscano <pino at kde.org>
+// Copyright 2012 Fabio D'Urso <fabiodurso at hotmail.it>
 //
 //========================================================================
 
@@ -109,6 +110,8 @@ public:
   void createWidgetAnnotation();
   AnnotWidget *getWidgetAnnotation() const { return widget; }
 
+  virtual void updateWidgetAppearance() = 0;
+
 #ifdef DEBUG_FORMS
   void print(int indent = 0);
 #endif
@@ -154,6 +157,7 @@ public:
 
   char* getOnStr();
   void setAppearanceState(const char *state);
+  void updateWidgetAppearance();
 
   void setNumSiblingsID (int i);
   void setSiblingsID (int i, unsigned id) { siblingsID[i] = id; }
@@ -185,6 +189,8 @@ public:
   //except a UTF16BE string
   void setContent(GooString* new_content);
 
+  void updateWidgetAppearance();
+
   bool isMultiline () const; 
   bool isPassword () const; 
   bool isFileSelect () const; 
@@ -224,6 +230,7 @@ public:
 
   GooString* getEditChoice ();
 
+  void updateWidgetAppearance();
   bool isSelected (int i);
 
   bool isCombo () const; 
@@ -244,6 +251,7 @@ protected:
 class FormWidgetSignature: public FormWidget {
 public:
   FormWidgetSignature(PDFDoc *docA, Object *dict, unsigned num, Ref ref, FormField *p);
+  void updateWidgetAppearance();
 protected:
   FormFieldSignature *parent;
 };
@@ -269,8 +277,6 @@ public:
   void setReadOnly (bool b) { readOnly = b; }
   bool isReadOnly () const { return readOnly; }
 
-  GBool isModified () const;
-
   GooString* getDefaultAppearance() const { return defaultAppearance; }
   GBool hasTextQuadding() const { return hasQuadding; }
   VariableTextQuadding getTextQuadding() const { return quadding; }
@@ -297,6 +303,7 @@ public:
  protected:
   void _createWidget (Object *obj, Ref aref);
   void createChildren(std::set<int> *usedParents);
+  void updateChildrenAppearance();
 
   FormFieldType type;           // field type
   Ref ref;
@@ -309,7 +316,6 @@ public:
   int numChildren;
   FormWidget **widgets;
   bool readOnly;
-  GBool modified;
 
   GooString *partialName; // T field
   GooString *alternateUiName; // TU field


More information about the poppler mailing list