[poppler] 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:05 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 68d732ab2d55ae15e194ececfffa753977fae84c
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 bde6aae..aa34197 100644
--- a/poppler/Annot.cc
+++ b/poppler/Annot.cc
@@ -3810,6 +3810,8 @@ void AnnotWidget::initialize(PDFDoc *docA, Dict *dict) {
     parent = NULL;
   }
   obj1.free();
+
+  updatedAppearanceStream.num = updatedAppearanceStream.gen = -1;
 }
 
 LinkAction* AnnotWidget::getAdditionalAction(AdditionalActionsType type)
@@ -4907,8 +4909,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.
@@ -4919,19 +4924,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();
+
+    // 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);
+    // 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 978af47..68ddeb7 100644
--- a/poppler/Annot.h
+++ b/poppler/Annot.h
@@ -1320,6 +1320,7 @@ private:
   // AnnotBorderBS border;                // BS
   Dict *parent;                           // Parent
   GBool addDingbatsResource;
+  Ref updatedAppearanceStream; // {-1,-1} if updateAppearanceStream has never been called
 };
 
 //------------------------------------------------------------------------
commit e2993cc9551dc7521528904646f941c9747473f7
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 d55ebc7..bde6aae 100644
--- a/poppler/Annot.cc
+++ b/poppler/Annot.cc
@@ -4905,13 +4905,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 df924493922e8c0f7b1e19c2847d33b28a098913
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 53cbb67..d55ebc7 100644
--- a/poppler/Annot.cc
+++ b/poppler/Annot.cc
@@ -4905,6 +4905,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;
@@ -4916,13 +4924,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 e495d06..978af47 100644
--- a/poppler/Annot.h
+++ b/poppler/Annot.h
@@ -1291,6 +1291,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 76ab8c1..68a4219 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;
@@ -211,6 +208,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
@@ -247,7 +249,13 @@ GooString* FormWidgetText::getContentCopy ()
 {
   return parent->getContentCopy();
 }
-  
+
+void FormWidgetText::updateWidgetAppearance()
+{
+  if (widget)
+    widget->updateAppearanceStream();
+}
+
 bool FormWidgetText::isMultiline () const 
 { 
   return parent->isMultiline(); 
@@ -356,6 +364,12 @@ GooString* FormWidgetChoice::getEditChoice ()
   return parent->getEditChoice();
 }
 
+void FormWidgetChoice::updateWidgetAppearance()
+{
+  if (widget)
+    widget->updateAppearanceStream();
+}
+
 bool FormWidgetChoice::isSelected (int i)
 {
   if (!_checkRange(i)) return false;
@@ -423,6 +437,11 @@ FormWidgetSignature::FormWidgetSignature(PDFDoc *docA, Object *aobj, unsigned nu
   parent = static_cast<FormFieldSignature*>(field);
 }
 
+void FormWidgetSignature::updateWidgetAppearance()
+{
+  // Unimplemented
+}
+
 
 //========================================================================
 // FormField
@@ -446,7 +465,6 @@ FormField::FormField(PDFDoc *docA, Object *aobj, const Ref& aref, FormField *par
   fullyQualifiedName = NULL;
   quadding = quaddingLeftJustified;
   hasQuadding = gFalse;
-  modified = gFalse;
 
   ref = aref;
 
@@ -623,10 +641,6 @@ void FormField::createWidgetAnnotations() {
   }
 }
 
-GBool FormField::isModified() const {
-  return modified ? gTrue : parent ? parent->isModified() : gFalse;
-}
-
 void FormField::_createWidget (Object *obj, Ref aref)
 {
   terminal = true;
@@ -758,6 +772,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
 //------------------------------------------------------------------------
@@ -864,7 +890,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;
@@ -910,7 +935,6 @@ GBool FormFieldButton::setState(char *state)
   }
 
   updateState(state);
-  modified = gTrue;
 
   return gTrue;
 }
@@ -1024,7 +1048,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()
@@ -1199,7 +1223,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 303936a..ef67748 100644
--- a/poppler/Form.h
+++ b/poppler/Form.h
@@ -9,6 +9,7 @@
 // Copyright 2007-2010, 2012 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();
 
 protected:
   GooString *onStr;
@@ -175,6 +179,8 @@ public:
   //except a UTF16BE string
   void setContent(GooString* new_content);
 
+  void updateWidgetAppearance();
+
   bool isMultiline () const; 
   bool isPassword () const; 
   bool isFileSelect () const; 
@@ -214,6 +220,7 @@ public:
 
   GooString* getEditChoice ();
 
+  void updateWidgetAppearance();
   bool isSelected (int i);
 
   bool isCombo () const; 
@@ -234,6 +241,7 @@ protected:
 class FormWidgetSignature: public FormWidget {
 public:
   FormWidgetSignature(PDFDoc *docA, Object *dict, unsigned num, Ref ref, FormField *p);
+  void updateWidgetAppearance();
 protected:
   FormFieldSignature *parent;
 };
@@ -259,8 +267,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; }
@@ -288,6 +294,7 @@ public:
  protected:
   void _createWidget (Object *obj, Ref aref);
   void createChildren(std::set<int> *usedParents);
+  void updateChildrenAppearance();
 
   FormFieldType type;           // field type
   Ref ref;
@@ -300,7 +307,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