[poppler] poppler/Form.cc poppler/Form.h

Carlos Garcia Campos carlosgc at kemper.freedesktop.org
Tue Mar 8 11:18:16 PST 2011


 poppler/Form.cc |  227 +++++++++++++++++++++-----------------------------------
 poppler/Form.h  |   21 +----
 2 files changed, 91 insertions(+), 157 deletions(-)

New commits:
commit 14d145371e86ccb92f09b1ca750ced52171b2885
Author: Carlos Garcia Campos <carlosgc at gnome.org>
Date:   Tue Mar 8 20:14:57 2011 +0100

    forms: Remove loadDefaults method
    
    Moving the code to initialize form field stuff to form field
    constructors and widget stuff to form widget constructors. Clean up an
    simplify the code.

diff --git a/poppler/Form.cc b/poppler/Form.cc
index 908b6fa..4698124 100644
--- a/poppler/Form.cc
+++ b/poppler/Form.cc
@@ -67,7 +67,6 @@ FormWidget::FormWidget(XRef *xrefA, Object *aobj, unsigned num, Ref aref, FormFi
   ref = aref;
   double t;
   ID = 0;
-  defaultsLoaded = gFalse;
   fontSize = 0.0;
   modified = gFalse;
   childNum = num;
@@ -256,9 +255,36 @@ FormWidgetButton::FormWidgetButton (XRef *xrefA, Object *aobj, unsigned num, Ref
   type = formButton;
   parent = static_cast<FormFieldButton*>(field);
   onStr = NULL;
-  state = gFalse;
   siblingsID = NULL;
   numSiblingsID = 0;
+
+  Object obj1, obj2;
+
+  // Find the name of the ON state in the AP dictionnary
+  // The reference say the Off state, if it existe, _must_ be stored in the AP dict under the name /Off
+  // The "on" state may be stored under any other name
+  if (obj.dictLookup("AP", &obj1)->isDict()) {
+    if (obj1.dictLookup("N", &obj2)->isDict()) {
+      for (int i = 0; i < obj2.dictGetLength(); i++) {
+        char *key = obj2.dictGetKey(i);
+        if (strcmp (key, "Off") != 0) {
+          onStr = new GooString (key);
+          break;
+        }
+      }
+    }
+    obj2.free();
+  }
+  obj1.free();
+}
+
+char *FormWidgetButton::getOnStr() {
+  if (onStr)
+    return onStr->getCString();
+
+  // 12.7.4.2.3 Check Boxes
+  //  Yes should be used as the name for the on state
+  return parent->getButtonType() == formButtonCheck ? (char *)"Yes" : NULL;
 }
 
 FormWidgetButton::~FormWidgetButton ()
@@ -273,108 +299,32 @@ FormButtonType FormWidgetButton::getButtonType () const
   return parent->getButtonType ();
 }
 
-void FormWidgetButton::setState (GBool astate, GBool calledByParent)
-{
-  //pushButtons don't have state
-  if (parent->getButtonType() == formButtonPush)
-    return;
-  //the state modification may be denied by the parent. e.g we don't want to let the user put all combo boxes to false
-  if (!calledByParent) { //avoid infinite recursion
-    modified = gTrue;
-    if (!parent->setState(childNum, astate)) {
-      return;
-    }
-  }
-  state = astate;
-  
-  //update appearance
-  char *offStr = "Off";
-  Object obj1;
-  obj1.initName(state ? onStr->getCString() : offStr);
-  updateField ("V", &obj1);
+void FormWidgetButton::setAppearanceState(char *state) {
+  modified = gTrue;
 
-  obj1.initName(state ? onStr->getCString() : offStr);
-  //modify the Appearance State entry as well
+  Object obj1;
+  obj1.initName(state);
   obj.getDict()->set("AS", &obj1);
-  //notify the xref about the update
   xref->setModifiedObject(&obj, ref);
 }
 
-void FormWidgetButton::loadDefaults ()
+void FormWidgetButton::setState (GBool astate, GBool calledByParent)
 {
-  if (defaultsLoaded)
-    return;
-
-  defaultsLoaded = gTrue;
-
-  Dict *dict = obj.getDict();
-  Object obj1;
-
   //pushButtons don't have state
-  if (parent->getButtonType() != formButtonPush ){
-    //find the name of the state in the AP dictionnary (/Yes, /Off)
-    //The reference say the Off state, if it existe, _must_ be stored in the AP dict under the name /Off
-    //The "on" state may be stored under any other name
-    if (dict->lookup("AP", &obj1)->isDict()) {
-      Dict *tmpDict = obj1.getDict();
-      int length = tmpDict->getLength();
-      for(int i=0; i<length; i++) {
-        Object obj2;
-        tmpDict->getVal(i, &obj2);
-        if (obj2.isDict()) {
-          Dict *tmpDict2 = obj2.getDict();
-          int length2 = tmpDict2->getLength();
-          for(int j=0; j<length2; j++) {
-            Object obj3;
-            tmpDict2->getVal(j, &obj3);
-            char *key = tmpDict2->getKey(j);
-            if(strcmp(key, "Off")) { //if we don't have Off, we have the name of the "on" state
-	      onStr = new GooString (key);
-            }
-            obj3.free();
-	    if (onStr)
-	      break;
-          }
-        } else if (obj2.isStream()) {
-          // TODO do something with str and obj3
-          Stream *str = obj2.getStream();
-          Dict *tmpDict2 = str->getDict();
-          Object obj3;
-          tmpDict2->lookup("Length", &obj3);
-          onStr = new GooString ("D");
-          obj3.free();
-        }
-        obj2.free();
-	if (onStr)
-	  break;
-      }
-    }
-    obj1.free();
+  if (parent->getButtonType() == formButtonPush)
+    return;
 
-    //We didn't found the "on" state for the button
-    if (!onStr) {
-      error(-1, "FormWidgetButton:: unable to find the on state for the button\n");
-      onStr = new GooString(""); // TODO is this the best solution?
-    }
-  }
+  // Silently return if can't set ON state
+  if (astate && !onStr)
+    return;
 
-  if (Form::fieldLookup(dict, "V", &obj1)->isName()) {
-    Object obj2;
-    if (dict->lookup("AS", &obj2)->isName(obj1.getName())) {
-      if (strcmp (obj1.getName(), "Off") != 0) {
-        setState(gTrue);
-      }
-    }
-    obj2.free();
-  } else if (obj1.isArray()) { //handle the case where we have multiple choices
-    error(-1, "FormWidgetButton:: multiple choice isn't supported yet\n");
-  }
-  obj1.free();
+  parent->setState(astate ? onStr->getCString() : (char *)"Off");
+  // Parent will call setAppearanceState()
 }
 
 GBool FormWidgetButton::getState ()
 {
-  return state;
+  return (onStr && parent->getAppearanceState() && strcmp(parent->getAppearanceState(), onStr->getCString()) == 0);
 }
 
 void FormWidgetButton::setNumSiblingsID (int i)
@@ -391,14 +341,6 @@ FormWidgetText::FormWidgetText (XRef *xrefA, Object *aobj, unsigned num, Ref ref
   parent = static_cast<FormFieldText*>(field);
 }
 
-void FormWidgetText::loadDefaults ()
-{
-  if (defaultsLoaded)
-    return;
-
-  defaultsLoaded = gTrue;
-}
-
 GooString* FormWidgetText::getContent ()
 {
   return parent->getContent(); 
@@ -467,14 +409,6 @@ FormWidgetChoice::FormWidgetChoice(XRef *xrefA, Object *aobj, unsigned num, Ref
   parent = static_cast<FormFieldChoice*>(field);
 }
 
-void FormWidgetChoice::loadDefaults ()
-{
-  if (defaultsLoaded)
-    return;
-
-  defaultsLoaded = gTrue;
-}
-
 FormWidgetChoice::~FormWidgetChoice()
 {
 }
@@ -658,7 +592,7 @@ FormField::FormField(XRef* xrefA, Object *aobj, const Ref& aref, std::set<int> *
             children = (FormField**)greallocn(children, numChildren, sizeof(FormField*));
 
             obj3.free();
-            children[numChildren-1] = Form::createFieldFromDict (&obj2, xrefA, childRef.getRef(), &usedParentsAux);
+            children[numChildren-1] = Form::createFieldFromDict (&obj2, xref, childRef.getRef(), &usedParentsAux);
           }
           // 1 - we will handle 'collapsed' fields (field + annot in the same dict)
           // as if the annot was in the Kids array of the field
@@ -679,10 +613,10 @@ FormField::FormField(XRef* xrefA, Object *aobj, const Ref& aref, std::set<int> *
   // As said in 1, if this is a 'collapsed' field, behave like if we had a
   // child annot
   if (dict->lookup("Subtype", &obj1)->isName()) {
-    _createWidget(aobj, ref);
+    _createWidget(&obj, ref);
   }
   obj1.free();
- 
+
   //flags
   if (Form::fieldLookup(dict, "Ff", &obj1)->isInt()) {
     int flags = obj1.getInt();
@@ -728,19 +662,6 @@ FormField::~FormField()
   delete defaultAppearance;
 }
 
-void FormField::loadChildrenDefaults ()
-{
-  if(!terminal) {
-    for(int i=0; i<numChildren; i++) {
-      children[i]->loadChildrenDefaults();
-    }
-  } else {
-    for (int i=0; i<numChildren; i++) {
-      widgets[i]->loadDefaults();
-    }
-  }
-}
-
 void FormField::fillChildrenSiblingsID()
 {
   if(terminal) return;
@@ -845,7 +766,7 @@ void FormFieldButton::fillChildrenSiblingsID()
   }
 }
 
-GBool FormFieldButton::setState (int num, GBool s) 
+GBool FormFieldButton::setState(char *state)
 {
   if (readOnly) {
     error(-1, "FormFieldButton::setState called on a readOnly field\n");
@@ -855,28 +776,54 @@ GBool FormFieldButton::setState (int num, GBool s)
   // A check button could behave as a radio button
   // when it's in a set of more than 1 buttons
   if (btype == formButtonRadio || btype == formButtonCheck) {
-    if (!s && noAllOff)
+    GBool isOn = strcmp(state, "Off") != 0;
+
+    if (!isOn && noAllOff)
       return gFalse; //don't allow to set all radio to off
 
-    if (s == gTrue) {
-      active_child = num;
-      for(int i=0; i<numChildren; i++) {
-        if (i==active_child) continue;
-        static_cast<FormWidgetButton*>(widgets[i])->setState(gFalse, gTrue);
-      }
+    char *current = getAppearanceState();
+
+    if (isOn) {
+      char *current = getAppearanceState();
+      GBool currentFound = gFalse, newFound = gFalse;
+
+      for (int i = 0; i < numChildren; i++) {
+        FormWidgetButton *widget = static_cast<FormWidgetButton*>(widgets[i]);
+
+        if (!widget->getOnStr())
+          continue;
+
+        char *onStr = widget->getOnStr();
+        if (current && strcmp(current, onStr) == 0) {
+          widget->setAppearanceState("Off");
+          currentFound = gTrue;
+        }
 
-      //The parent field's V entry holds a name object corresponding to the ap-
-      //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())
-          updateState(actChild->getOnStr()->getCString());
+        if (strcmp(state, onStr) == 0) {
+          widget->setAppearanceState(state);
+          newFound = gTrue;
+        }
+
+        if (currentFound && newFound)
+          break;
       }
     } else {
-      active_child = -1;
-      updateState("Off");
+      for (int i = 0; i < numChildren; i++) {
+        FormWidgetButton *widget = static_cast<FormWidgetButton*>(widgets[i]);
+
+        if (!widget->getOnStr())
+          continue;
+
+        char *onStr = widget->getOnStr();
+        if (current && strcmp(current, onStr) == 0) {
+          widget->setAppearanceState("Off");
+          break;
+        }
+      }
     }
+    updateState(state);
   }
+
   return gTrue;
 }
 
@@ -1370,8 +1317,6 @@ FormField *Form::createFieldFromDict (Object* obj, XRef *xrefA, const Ref& pref,
       field = new FormField(xrefA, obj, pref, usedParents);
     }
     obj2.free();
-    
-    field->loadChildrenDefaults();
 
     return field;
 }
diff --git a/poppler/Form.h b/poppler/Form.h
index 8d25e2c..74539ca 100644
--- a/poppler/Form.h
+++ b/poppler/Form.h
@@ -69,9 +69,6 @@ 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; }
@@ -121,7 +118,6 @@ protected:
   Object obj;
   Ref ref;
   XRef *xref;
-  GBool defaultsLoaded;
   GBool modified;
   GooString *partialName; // T field
   GooString *alternateUiName; // TU field
@@ -161,9 +157,8 @@ public:
   void setState (GBool state, GBool calledByParent=gFalse);
   GBool getState ();
 
-  GooString* getOnStr() { return onStr; }
-
-  void loadDefaults();
+  char* getOnStr();
+  void setAppearanceState(char *state);
 
   void setNumSiblingsID (int i);
   void setSiblingsID (int i, unsigned id) { siblingsID[i] = id; }
@@ -178,7 +173,6 @@ protected:
   int numSiblingsID;
   GooString *onStr;
   FormFieldButton *parent;
-  GBool state;
 };
 
 //------------------------------------------------------------------------
@@ -196,8 +190,6 @@ public:
   //except a UTF16BE string
   void setContent(GooString* new_content);
 
-  void loadDefaults ();
-
   bool isMultiline () const; 
   bool isPassword () const; 
   bool isFileSelect () const; 
@@ -219,7 +211,6 @@ public:
   FormWidgetChoice(XRef *xrefA, Object *dict, unsigned num, Ref ref, FormField *p);
   ~FormWidgetChoice();
 
-  void loadDefaults ();
   int getNumChoices();
   //return the display name of the i-th choice (UTF16BE)
   GooString* getChoice(int i);
@@ -288,9 +279,6 @@ public:
   VariableTextQuadding getTextQuadding() const { return quadding; }
 
   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 ();
@@ -298,6 +286,7 @@ public:
 
  protected:
   void _createWidget (Object *obj, Ref aref);
+  void createChildren(std::set<int> *usedParents);
 
   FormFieldType type;           // field type
   Ref ref;
@@ -332,10 +321,10 @@ public:
   bool noToggleToOff () const { return noAllOff; }
 
   // returns gTrue if the state modification is accepted
-  GBool setState (int num, GBool s);
+  GBool setState (char *state);
 
   char *getAppearanceState() { return appearanceState.isName() ? appearanceState.getName() : NULL; }
-  
+
   void fillChildrenSiblingsID ();
 
   virtual ~FormFieldButton();


More information about the poppler mailing list