source: trunk/poppler/mypoppler/poppler/Form.cc @ 261

Last change on this file since 261 was 261, checked in by Eugene Romanenko, 13 years ago

PDF plugin: Poppler library updated to version 0.10.2

File size: 31.6 KB
Line 
1//========================================================================
2//
3// Form.cc
4//
5// This file is licensed under the GPLv2 or later
6//
7// Copyright 2006-2008 Julien Rebetez <julienr@svn.gnome.org>
8// Copyright 2007-2008 Albert Astals Cid <aacid@kde.org>
9// Copyright 2007-2008 Carlos Garcia Campos <carlosgc@gnome.org>
10// Copyright 2007 Adrian Johnson <ajohnson@redneon.com>
11// Copyright 2007 Iñigo Martínez <inigomartinez@gmail.com>
12// Copyright 2008 Pino Toscano <pino@kde.org>
13// Copyright 2008 Michael Vrable <mvrable@cs.ucsd.edu>
14//
15//========================================================================
16
17#include <config.h>
18
19#ifdef USE_GCC_PRAGMAS
20#pragma implementation
21#endif
22
23#include <stddef.h>
24#include <string.h>
25#include "goo/gmem.h"
26#include "goo/GooString.h"
27#include "Error.h"
28#include "Object.h"
29#include "Array.h"
30#include "Dict.h"
31#include "Form.h"
32#include "XRef.h"
33#include "PDFDocEncoding.h"
34#include "Annot.h"
35#include "Catalog.h"
36
37//return a newly allocated char* containing an UTF16BE string of size length
38char* pdfDocEncodingToUTF16 (GooString* orig, int* length)
39{
40  //double size, a unicode char takes 2 char, add 2 for the unicode marker
41  *length = 2+2*orig->getLength();
42  char *result = new char[(*length)];
43  char *cstring = orig->getCString();
44  //unicode marker
45  result[0] = 0xfe;
46  result[1] = 0xff;
47  //convert to utf16
48  for(int i=2,j=0; i<(*length); i+=2,j++) {
49    Unicode u = pdfDocEncoding[(unsigned int)((unsigned char)cstring[j])]&0xffff;
50    result[i] = (u >> 8) & 0xff;
51    result[i+1] = u & 0xff;
52  }
53  return result;
54}
55
56
57
58FormWidget::FormWidget(XRef *xrefA, Object *aobj, unsigned num, Ref aref, FormField *fieldA) 
59{
60  Object obj1, obj2;
61  ref = aref;
62  double t;
63  ID = 0;
64  defaultsLoaded = gFalse;
65  fontSize = 0.0;
66  modified = gFalse;
67  childNum = num;
68  xref = xrefA;
69  aobj->copy(&obj);
70  type = formUndef;
71  field = fieldA;
72  Dict *dict = obj.getDict();
73
74  if (!dict->lookup("Rect", &obj1)->isArray()) {
75    error(-1, "Annotation rectangle is wrong type");
76    goto err2;
77  }
78  if (!obj1.arrayGet(0, &obj2)->isNum()) {
79    error(-1, "Bad annotation rectangle");
80    goto err1;
81  }
82  x1 = obj2.getNum();
83  obj2.free();
84  if (!obj1.arrayGet(1, &obj2)->isNum()) {
85    error(-1, "Bad annotation rectangle");
86    goto err1;
87  }
88  y1 = obj2.getNum();
89  obj2.free();
90  if (!obj1.arrayGet(2, &obj2)->isNum()) {
91    error(-1, "Bad annotation rectangle");
92    goto err1;
93  }
94  x2 = obj2.getNum();
95  obj2.free();
96  if (!obj1.arrayGet(3, &obj2)->isNum()) {
97    error(-1, "Bad annotation rectangle");
98    goto err1;
99  }
100  y2 = obj2.getNum();
101  obj2.free();
102  obj1.free();
103  //swap coords if needed
104  if (x1 > x2) {
105    t = x1;
106    x1 = x2;
107    x2 = t;
108  }
109  if (y1 > y2) {
110    t = y1;
111    y1 = y2;
112    y2 = t;
113  }
114 
115  err1:
116    obj2.free(); 
117  err2:
118    obj1.free();
119}
120
121FormWidget::FormWidget(FormWidget *dest)
122{
123  x1 = dest->x1;
124  y1 = dest->y1;
125  x2 = dest->x2;
126  y2 = dest->x2;
127
128  type = dest->type;
129  field = dest->field;
130}
131
132FormWidget::~FormWidget()
133{
134  obj.free ();
135}
136
137bool FormWidget::isReadOnly() const
138{
139  return field->isReadOnly();
140}
141
142int FormWidget::encodeID (unsigned pageNum, unsigned fieldNum)
143{
144  return (pageNum << 4*sizeof(unsigned)) + fieldNum;
145}
146
147void FormWidget::decodeID (unsigned id, unsigned* pageNum, unsigned* fieldNum)
148{
149  *pageNum = id >> 4*sizeof(unsigned);
150  *fieldNum = (id << 4*sizeof(unsigned)) >> 4*sizeof(unsigned);
151}
152
153void FormWidget::updateField (const char *key, Object *value)
154{
155  Object *obj1;
156  Ref ref1;
157  Object obj2;
158
159  if (obj.getDict()->lookup ("FT", &obj2)->isName ()) {
160    // It's a composed (annot + field) dict
161    obj1 = &obj;
162    ref1 = ref;
163  } else {
164    // It's an annot dict, we have to modify the Field (parent) dict
165    obj1 = field->getObj ();
166    ref1 = field->getRef ();
167  }
168  obj2.free ();
169
170  obj1->getDict ()->set (const_cast<char*>(key), value);
171  //notify the xref about the update
172  xref->setModifiedObject(obj1, ref1);
173}
174
175FormWidgetButton::FormWidgetButton (XRef *xrefA, Object *aobj, unsigned num, Ref ref, FormField *p) :
176        FormWidget(xrefA, aobj, num, ref, p)
177{
178  type = formButton;
179  parent = static_cast<FormFieldButton*>(field);
180  onStr = NULL;
181  state = gFalse;
182  siblingsID = NULL;
183  numSiblingsID = 0;
184}
185
186FormWidgetButton::~FormWidgetButton ()
187{
188  if (siblingsID)
189    gfree(siblingsID);
190  delete onStr;
191}
192
193FormButtonType FormWidgetButton::getButtonType () const
194{
195  return parent->getButtonType ();
196}
197
198void FormWidgetButton::setState (GBool astate, GBool calledByParent)
199{
200  //pushButtons don't have state
201  if (parent->getButtonType() == formButtonPush)
202    return;
203  //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
204  if (!calledByParent) { //avoid infinite recursion
205    modified = gTrue;
206    if (!parent->setState(childNum, astate)) {
207      return;
208    }
209  }
210  state = astate;
211 
212  //update appearance
213  char *offStr = "Off";
214  Object obj1;
215  obj1.initName(state?getOnStr():offStr);
216  updateField ("V", &obj1);
217
218  obj1.initName(state?getOnStr():offStr);
219  //modify the Appearance State entry as well
220  obj.getDict()->set("AS", &obj1);
221  //notify the xref about the update
222  xref->setModifiedObject(&obj, ref);
223}
224
225void FormWidgetButton::loadDefaults ()
226{
227  if (defaultsLoaded)
228    return;
229
230  defaultsLoaded = gTrue;
231
232  Dict *dict = obj.getDict();
233  Object obj1;
234
235  //pushButtons don't have state
236  if (parent->getButtonType() != formButtonPush ){
237    //find the name of the state in the AP dictionnary (/Yes, /Off)
238    //The reference say the Off state, if it existe, _must_ be stored in the AP dict under the name /Off
239    //The "on" state may be stored under any other name
240    if (dict->lookup("AP", &obj1)->isDict()) {
241      Dict *tmpDict = obj1.getDict();
242      int length = tmpDict->getLength();
243      for(int i=0; i<length; i++) {
244        Object obj2;
245        tmpDict->getVal(i, &obj2);
246        if (obj2.isDict()) {
247          Dict *tmpDict2 = obj2.getDict();
248          int length2 = tmpDict2->getLength();
249          for(int j=0; j<length2; j++) {
250            Object obj3;
251            tmpDict2->getVal(j, &obj3);
252            char *key = tmpDict2->getKey(j);
253            if(strcmp(key, "Off")) { //if we don't have Off, we have the name of the "on" state
254              onStr = new GooString (key);
255            }
256            obj3.free();
257            if (onStr)
258              break;
259          }
260        } else if (obj2.isStream()) {
261          Stream *str = obj2.getStream();
262          Dict *tmpDict2 = str->getDict();
263          Object obj3;
264          tmpDict2->lookup("Length", &obj3);
265          onStr = new GooString ("D");
266        }
267        obj2.free();
268        if (onStr)
269          break;
270      }
271    }
272    obj1.free();
273
274    //We didn't found the "on" state for the button
275    if (!onStr) {
276      error(-1, "FormWidgetButton:: unable to find the on state for the button\n");
277    }
278  }
279
280  if (Form::fieldLookup(dict, "V", &obj1)->isName()) {
281    Object obj2;
282    if (dict->lookup("AS", &obj2)->isName(obj1.getName())) {
283      if (strcmp (obj1.getName(), "Off") != 0) {
284        setState(gTrue);
285      }
286    }
287    obj2.free();
288  } else if (obj1.isArray()) { //handle the case where we have multiple choices
289    error(-1, "FormWidgetButton:: multiple choice isn't supported yet\n");
290  }
291  obj1.free();
292}
293
294GBool FormWidgetButton::getState ()
295{
296  return state;
297}
298
299void FormWidgetButton::setNumSiblingsID (int i)
300{ 
301  numSiblingsID = i; 
302  siblingsID = (unsigned*)greallocn(siblingsID, numSiblingsID, sizeof(unsigned));
303}
304
305
306FormWidgetText::FormWidgetText (XRef *xrefA, Object *aobj, unsigned num, Ref ref, FormField *p) :
307        FormWidget(xrefA, aobj, num, ref, p)
308{
309  type = formText;
310  parent = static_cast<FormFieldText*>(field);
311}
312
313void FormWidgetText::loadDefaults ()
314{
315  if (defaultsLoaded)
316    return;
317
318  defaultsLoaded = gTrue;
319
320  Dict *dict = obj.getDict();
321  Object obj1;
322
323  if (Form::fieldLookup(dict, "V", &obj1)->isString()) {
324    if (obj1.getString()->hasUnicodeMarker()) {
325      if (obj1.getString()->getLength() <= 2) {
326      } else {
327        parent->setContentCopy(obj1.getString());
328      }
329    } else {
330      if (obj1.getString()->getLength() > 0) {
331        //non-unicode string -- assume pdfDocEncoding and try to convert to UTF16BE
332        int tmp_length;
333        char* tmp_str = pdfDocEncodingToUTF16(obj1.getString(), &tmp_length);
334        GooString* str1 = new GooString(tmp_str, tmp_length);
335        parent->setContentCopy(str1);
336        delete str1;
337        delete []tmp_str;
338      }
339    }
340  }
341  obj1.free();
342
343}
344
345GooString* FormWidgetText::getContent ()
346{
347  return parent->getContent(); 
348}
349
350GooString* FormWidgetText::getContentCopy ()
351{
352  return parent->getContentCopy();
353}
354 
355bool FormWidgetText::isMultiline () const 
356{ 
357  return parent->isMultiline(); 
358}
359
360bool FormWidgetText::isPassword () const 
361{ 
362  return parent->isPassword(); 
363}
364
365bool FormWidgetText::isFileSelect () const 
366{ 
367  return parent->isFileSelect(); 
368}
369
370bool FormWidgetText::noSpellCheck () const 
371{ 
372  return parent->noSpellCheck(); 
373}
374
375bool FormWidgetText::noScroll () const 
376{ 
377  return parent->noScroll(); 
378}
379
380bool FormWidgetText::isComb () const 
381{ 
382  return parent->isComb(); 
383}
384
385bool FormWidgetText::isRichText () const 
386{ 
387  return parent->isRichText(); 
388}
389
390int FormWidgetText::getMaxLen () const
391{
392  return parent->getMaxLen ();
393}
394
395void FormWidgetText::setContent(GooString* new_content)
396{
397  if (isReadOnly()) {
398    error(-1, "FormWidgetText::setContentCopy called on a read only field\n");
399    return;
400  }
401
402  modified = gTrue;
403  if (new_content == NULL) {
404    parent->setContentCopy(NULL);
405  } else {
406    //append the unicode marker <FE FF> if needed
407    if (!new_content->hasUnicodeMarker()) {
408      new_content->insert(0, 0xff);
409      new_content->insert(0, 0xfe);
410    }
411   
412    GooString *cont = new GooString(new_content);
413    parent->setContentCopy(cont);
414   
415    Object obj1;
416    obj1.initString(cont);
417    updateField ("V", &obj1);
418  }
419}
420
421FormWidgetChoice::FormWidgetChoice(XRef *xrefA, Object *aobj, unsigned num, Ref ref, FormField *p) :
422        FormWidget(xrefA, aobj, num, ref, p)
423{
424  type = formChoice;
425  parent = static_cast<FormFieldChoice*>(field);
426}
427
428void FormWidgetChoice::loadDefaults ()
429{
430  if (defaultsLoaded)
431    return;
432
433  defaultsLoaded = gTrue;
434
435  Dict *dict = obj.getDict();
436  Object obj1;
437  if (dict->lookup("Opt", &obj1)->isArray()) {
438    Object obj2;
439    parent->_setNumChoices(obj1.arrayGetLength());
440    parent->_createChoicesTab();
441    for(int i=0; i<parent->getNumChoices(); i++) {
442      obj1.arrayGet(i, &obj2);
443      if(obj2.isString()) {
444        parent->_setChoiceExportVal(i, obj2.getString()->copy());
445        parent->_setChoiceOptionName(i, obj2.getString()->copy());
446      } else if (obj2.isArray()) { // [Export_value, Displayed_text]
447        Object obj3,obj4;
448        if (obj2.arrayGetLength() < 2) {
449          error(-1, "FormWidgetChoice:: invalid Opt entry -- array's length < 2\n");
450          parent->_setChoiceExportVal(i, new GooString(""));
451          parent->_setChoiceOptionName(i, new GooString(""));
452          continue;
453        }
454        obj2.arrayGet(0, &obj3);
455        obj2.arrayGet(1, &obj4);
456        parent->_setChoiceExportVal(i, obj3.getString()->copy());
457        parent->_setChoiceOptionName(i, obj4.getString()->copy());
458        obj3.free();
459        obj4.free();
460      } else {
461        error(-1, "FormWidgetChoice:: invalid Opt entry\n");
462      }
463      obj2.free();
464    }
465  } else {
466    //empty choice
467  }
468  obj1.free();
469
470  bool* tmpCurrentChoice = new bool[parent->getNumChoices()];
471  memset(tmpCurrentChoice, 0, sizeof(bool)*parent->getNumChoices());
472
473  //find default choice
474  if (Form::fieldLookup(dict, "V", &obj1)->isString()) {
475    for(int i=0; i<parent->getNumChoices(); i++) {
476      if (parent->getChoice(i)->cmp(obj1.getString()) == 0) {
477        tmpCurrentChoice[i] = true;
478        break;
479      }
480    }
481  } else if (obj1.isArray()) {
482    for(int i=0; i<obj1.arrayGetLength(); i++) {
483      Object obj2;
484      obj1.arrayGet(i, &obj2);
485      for(int j=0; j<parent->getNumChoices(); j++) {
486        if (parent->getChoice(j)->cmp(obj2.getString()) == 0) {
487          tmpCurrentChoice[i] = true;
488        }
489      }
490
491      obj2.free();
492    }
493  }
494  obj1.free();
495
496  //convert choice's human readable strings to UTF16
497  //and update the /Opt dict entry to reflect this change
498#ifdef UPDATE_OPT
499  Object *objOpt = new Object();
500  objOpt->initArray(xref);
501#endif
502  for(int i=0; i<parent->getNumChoices(); i++) {
503        if (parent->getChoice(i)->hasUnicodeMarker()) { //string already in UTF16, do nothing
504
505        } else { //string in pdfdocencoding, convert to UTF16
506          int len;
507          char* buffer = pdfDocEncodingToUTF16(parent->getChoice(i), &len);
508          parent->getChoice(i)->Set(buffer, len);
509          delete [] buffer;
510        }
511        #ifdef UPDATE_OPT
512        Object *obj2 = new Object();
513        obj2->initString(choices[i]);
514        objOpt->getArray()->add(obj2); 
515        #endif
516  }
517  //set default choice now that we have UTF16 strings
518  for (int i=0; i<parent->getNumChoices(); i++) {
519    if (tmpCurrentChoice[i])
520      parent->select(i);
521  }
522#ifdef UPDATE_OPT
523  updateField ("Opt", objOpt);
524#endif
525  delete [] tmpCurrentChoice;
526}
527
528FormWidgetChoice::~FormWidgetChoice()
529{
530}
531
532void FormWidgetChoice::_updateV ()
533{
534  Object obj1;
535  //this is an editable combo-box with user-entered text
536  if (hasEdit() && parent->getEditChoice()) { 
537    obj1.initString(new GooString(parent->getEditChoice()));
538  } else {
539    int numSelected = parent->getNumSelected();
540    if (numSelected == 0) {
541      obj1.initString(new GooString(""));
542    } else if (numSelected == 1) {
543      for(int i=0; i<parent->getNumChoices(); i++) {
544        if (parent->isSelected(i)) {
545          obj1.initString(new GooString(parent->getExportVal(i)));
546          break;
547        }
548      }
549    } else {
550      obj1.initArray(xref);
551      for(int i=0; i<parent->getNumChoices(); i++) {
552        if (parent->isSelected(i)) {
553          Object obj2;
554          obj2.initString(new GooString(parent->getExportVal(i)));
555          obj1.arrayAdd(&obj2);
556        }
557      }
558    }
559  }
560  updateField ("V", &obj1);
561  modified = gTrue;
562}
563
564bool FormWidgetChoice::_checkRange (int i)
565{
566  if (i < 0 || i >= parent->getNumChoices()) {
567    error(-1, "FormWidgetChoice::_checkRange i out of range : %i", i);
568    return false;
569  } 
570  return true;
571}
572
573void FormWidgetChoice::select (int i)
574{
575  if (isReadOnly()) {
576    error(-1, "FormWidgetChoice::select called on a read only field\n");
577    return;
578  }
579  if (!_checkRange(i)) return;
580  modified = gTrue;
581  parent->select(i);
582  _updateV();
583}
584
585void FormWidgetChoice::toggle (int i)
586{
587  if (isReadOnly()) {
588    error(-1, "FormWidgetChoice::toggle called on a read only field\n");
589    return;
590  }
591  if (!_checkRange(i)) return;
592  modified = gTrue;
593  parent->toggle(i);
594  _updateV();
595}
596
597void FormWidgetChoice::deselectAll ()
598{
599  if (isReadOnly()) {
600    error(-1, "FormWidgetChoice::deselectAll called on a read only field\n");
601    return;
602  }
603  modified = gTrue;
604  parent->deselectAll();
605  _updateV();
606}
607
608GooString* FormWidgetChoice::getEditChoice ()
609{
610  if (!hasEdit()) {
611    error(-1, "FormFieldChoice::getEditChoice called on a non-editable choice\n");
612    return NULL;
613  }
614  return parent->getEditChoice();
615}
616
617bool FormWidgetChoice::isSelected (int i)
618{
619  if (!_checkRange(i)) return false;
620  return parent->isSelected(i);
621}
622
623void FormWidgetChoice::setEditChoice (GooString* new_content)
624{
625  if (isReadOnly()) {
626    error(-1, "FormWidgetText::setEditChoice called on a read only field\n");
627    return;
628  }
629  if (!hasEdit()) {
630    error(-1, "FormFieldChoice::setEditChoice : trying to edit an non-editable choice\n");
631    return;
632  }
633
634  modified = gTrue;
635  if (new_content == NULL) {
636    parent->setEditChoice(NULL);
637  } else {
638    //append the unicode marker <FE FF> if needed
639    if (!new_content->hasUnicodeMarker()) {
640      new_content->insert(0, 0xff);
641      new_content->insert(0, 0xfe);
642    }
643    parent->setEditChoice(new_content);
644  }
645  _updateV();
646}
647
648int FormWidgetChoice::getNumChoices() 
649{ 
650  return parent->getNumChoices(); 
651}
652
653GooString* FormWidgetChoice::getChoice(int i) 
654{ 
655  return parent->getChoice(i); 
656}
657
658bool FormWidgetChoice::isCombo () const 
659{ 
660  return parent->isCombo(); 
661}
662
663bool FormWidgetChoice::hasEdit () const 
664{ 
665  return parent->hasEdit(); 
666}
667
668bool FormWidgetChoice::isMultiSelect () const 
669{ 
670  return parent->isMultiSelect(); 
671}
672
673bool FormWidgetChoice::noSpellCheck () const 
674{ 
675  return parent->noSpellCheck(); 
676}
677
678bool FormWidgetChoice::commitOnSelChange () const 
679{ 
680  return parent->commitOnSelChange(); 
681}
682
683bool FormWidgetChoice::isListBox () const
684{
685  return parent->isListBox();
686}
687
688FormWidgetSignature::FormWidgetSignature(XRef *xrefA, Object *aobj, unsigned num, Ref ref, FormField *p) :
689        FormWidget(xrefA, aobj, num, ref, p)
690{
691  type = formSignature;
692  parent = static_cast<FormFieldSignature*>(field);
693}
694
695
696//========================================================================
697// FormField
698//========================================================================
699
700FormField::FormField(XRef* xrefA, Object *aobj, const Ref& aref, FormFieldType ty) 
701{
702  xref = xrefA;
703  aobj->copy(&obj);
704  Dict* dict = obj.getDict();
705  ref.num = ref.gen = 0;
706  type = ty;
707  numChildren = 0;
708  children = NULL;
709  terminal = false;
710  widgets = NULL;
711  readOnly = false;
712  ref = aref;
713
714  Object obj1;
715  //childs
716  if (dict->lookup("Kids", &obj1)->isArray()) {
717    Array *array = obj1.getArray();
718    int length = array->getLength();
719    // Load children
720    for(int i=0; i<length; i++) { 
721      Object obj2,obj3;
722      Object childRef;
723      array->get(i, &obj2);
724      array->getNF(i, &childRef);
725      if (!obj2.isDict ()) {
726              error (-1, "Reference to an invalid or non existant object");
727              continue;
728      }
729      //field child
730      if (dict->lookup ("FT", &obj3)->isName()) {
731        // If I'm not a generic container field and my children
732        // are widgets, create widgets for them
733        Object obj4;
734
735        if (obj2.dictLookup("Subtype",&obj4)->isName()) {
736          _createWidget(&obj2, childRef.getRef());
737        }
738        obj4.free();
739      } else if(obj2.dictLookup("FT", &obj3)->isName() || obj2.dictLookup("Kids", &obj3)->isArray()) {
740        if(terminal) error(-1, "Field can't have both Widget AND Field as kids\n");
741
742        numChildren++;
743        children = (FormField**)greallocn(children, numChildren, sizeof(FormField*));
744
745        obj3.free();
746        children[numChildren-1] = Form::createFieldFromDict (&obj2, xrefA, childRef.getRef());
747      }
748      // 1 - we will handle 'collapsed' fields (field + annot in the same dict)
749      // as if the annot was in the Kids array of the field
750      else if (obj2.dictLookup("Subtype",&obj3)->isName()) {
751        _createWidget(&obj2, childRef.getRef());
752      }
753      obj2.free();
754      obj3.free();
755    }
756  }
757  obj1.free();
758  // As said in 1, if this is a 'collapsed' field, behave like if we had a
759  // child annot
760  if (dict->lookup("Subtype", &obj1)->isName()) {
761    _createWidget(aobj, ref);
762  }
763  obj1.free();
764 
765  //flags
766  if (Form::fieldLookup(dict, "Ff", &obj1)->isInt()) {
767    int flags = obj1.getInt();
768    if (flags & 0x1) { // 1 -> ReadOnly
769      readOnly = true;
770    }
771    if (flags & 0x2) { // 2 -> Required
772      //TODO
773    }
774    if (flags & 0x4) { // 3 -> NoExport
775      //TODO
776    }
777  }
778  obj1.free();
779}
780
781FormField::~FormField()
782{
783  if (!terminal) {
784    if(children) {
785      for (int i=0; i<numChildren; i++)
786        delete children[i];
787      gfree(children);
788    }
789  } else {
790    for (int i = 0; i < numChildren; ++i)
791      delete widgets[i];
792    gfree (widgets);
793  }
794  obj.free();
795}
796
797void FormField::loadChildrenDefaults ()
798{
799  if(!terminal) {
800    for(int i=0; i<numChildren; i++) {
801      children[i]->loadChildrenDefaults();
802    }
803  } else {
804    for (int i=0; i<numChildren; i++) {
805      widgets[i]->loadDefaults();
806    }
807  }
808}
809
810void FormField::fillChildrenSiblingsID()
811{
812  if(terminal) return;
813  for (int i=0; i<numChildren; i++) {
814    children[i]->loadChildrenDefaults();
815  }
816}
817
818
819void FormField::_createWidget (Object *obj, Ref aref)
820{
821  terminal = true;
822  numChildren++;
823  widgets = (FormWidget**)greallocn(widgets, numChildren, sizeof(FormWidget*));
824  //ID = index in "widgets" table
825  switch (type) {
826  case formButton:
827    widgets[numChildren-1] = new FormWidgetButton(xref, obj, numChildren-1, aref, this);
828    break;
829  case formText:
830    widgets[numChildren-1] = new FormWidgetText(xref, obj, numChildren-1, aref, this);
831    break;
832  case formChoice:
833    widgets[numChildren-1] = new FormWidgetChoice(xref, obj, numChildren-1, aref, this);
834    break;
835  case formSignature:
836    widgets[numChildren-1] = new FormWidgetSignature(xref, obj, numChildren-1, aref, this);
837    break;
838  default:
839    error(-1, "SubType on non-terminal field, invalid document?");
840    numChildren--;
841    terminal = false;
842  }
843}
844
845FormWidget* FormField::findWidgetByRef (Ref aref)
846{
847  if (terminal) {
848    for(int i=0; i<numChildren; i++) {
849      if (widgets[i]->getRef().num == aref.num
850          && widgets[i]->getRef().gen == aref.gen)
851        return widgets[i];
852    }
853  } else {
854    for(int i=0; i<numChildren; i++) {
855      FormWidget* result = children[i]->findWidgetByRef(aref);
856      if(result) return result;
857    }
858  }
859  return NULL;
860}
861
862
863//------------------------------------------------------------------------
864// FormFieldButton
865//------------------------------------------------------------------------
866FormFieldButton::FormFieldButton(XRef *xrefA, Object *aobj, const Ref& ref) 
867        : FormField(xrefA, aobj, ref, formButton)
868{
869  Dict* dict = obj.getDict();
870  active_child = -1;
871  noAllOff = false;
872
873  Object obj1;
874  btype = formButtonCheck; 
875  if (Form::fieldLookup(dict, "Ff", &obj1)->isInt()) {
876    int flags = obj1.getInt();
877   
878    if (flags & 0x10000) { // 17 -> push button
879      btype = formButtonPush;
880    } else if (flags & 0x8000) { // 16 -> radio button
881      btype = formButtonRadio;
882      if (flags & 0x4000) { // 15 -> noToggleToOff
883        noAllOff = true;
884      }
885    } 
886    if (flags & 0x1000000) { // 26 -> radiosInUnison
887      error(-1, "FormFieldButton:: radiosInUnison flag unimplemented, please report a bug with a testcase\n");
888    } 
889  }
890}
891
892void FormFieldButton::fillChildrenSiblingsID()
893{
894  if (!terminal) {
895    for(int i=0; i<numChildren; i++) {
896      children[i]->fillChildrenSiblingsID();
897    }
898  } else {
899    for(int i=0; i<numChildren; i++) {
900      FormWidgetButton *btn = static_cast<FormWidgetButton*>(widgets[i]);
901      btn->setNumSiblingsID(numChildren-1);
902      for(int j=0, counter=0; j<numChildren; j++) {
903        if (i == j) continue;
904        btn->setSiblingsID(counter, widgets[j]->getID());
905        counter++;
906      }
907    }
908  }
909}
910
911GBool FormFieldButton::setState (int num, GBool s) 
912{
913  if (readOnly) {
914    error(-1, "FormFieldButton::setState called on a readOnly field\n");
915    return gFalse;
916  }
917
918  // A check button could behave as a radio button
919  // when it's in a set of more than 1 buttons
920  if (btype == formButtonRadio || btype == formButtonCheck) {
921    if (!s && noAllOff)
922      return gFalse; //don't allow to set all radio to off
923
924    if (s == gTrue) {
925      active_child = num;
926      for(int i=0; i<numChildren; i++) {
927        if (i==active_child) continue;
928        static_cast<FormWidgetButton*>(widgets[i])->setState(gFalse, gTrue);
929      }
930
931      //The parent field's V entry holds a name object corresponding to the ap-
932      //pearance state of whichever child field is currently in the on state
933      if (active_child >= 0) {
934        FormWidgetButton* actChild = static_cast<FormWidgetButton*>(widgets[active_child]);
935        if (actChild->getOnStr()) {
936          Object obj1;
937          obj1.initName(actChild->getOnStr());
938          obj.getDict()->set("V", &obj1);
939          xref->setModifiedObject(&obj, ref);
940        }
941      }
942    } else {
943      active_child = -1;
944      Object obj1;
945      obj1.initName("Off");
946      obj.getDict()->set("V", &obj1);
947      xref->setModifiedObject(&obj, ref);
948    }
949  }
950  return gTrue;
951}
952
953FormFieldButton::~FormFieldButton()
954{
955}
956
957//------------------------------------------------------------------------
958// FormFieldText
959//------------------------------------------------------------------------
960FormFieldText::FormFieldText(XRef *xrefA, Object *aobj, const Ref& ref) 
961        : FormField(xrefA, aobj, ref, formText)
962{
963  Dict* dict = obj.getDict();
964  Object obj1;
965  content = NULL;
966  multiline = password = fileSelect = doNotSpellCheck = doNotScroll = comb = richText = false;
967  maxLen = 0;
968
969  if (Form::fieldLookup(dict, "Ff", &obj1)->isInt()) {
970    int flags = obj1.getInt();
971    if (flags & 0x1000) // 13 -> Multiline
972      multiline = true;
973    if (flags & 0x2000) // 14 -> Password
974      password = true;
975    if (flags & 0x100000) // 21 -> FileSelect
976      fileSelect = true;
977    if (flags & 0x400000)// 23 -> DoNotSpellCheck
978      doNotSpellCheck = true;
979    if (flags & 0x800000) // 24 -> DoNotScroll
980      doNotScroll = true;
981    if (flags & 0x1000000) // 25 -> Comb
982      comb = true;
983    if (flags & 0x2000000)// 26 -> RichText
984      richText = true;
985  }
986  obj1.free();
987
988  if (Form::fieldLookup(dict, "MaxLen", &obj1)->isInt()) {
989    maxLen = obj1.getInt();
990  }
991  obj1.free();
992}
993
994GooString* FormFieldText::getContentCopy ()
995{
996  if (!content) return NULL;
997  return new GooString(*content);
998}
999
1000void FormFieldText::setContentCopy (GooString* new_content)
1001{
1002  if(content) {
1003    delete content; 
1004  }
1005  content = new_content->copy();
1006}
1007
1008FormFieldText::~FormFieldText()
1009{
1010  delete content;
1011}
1012
1013
1014//------------------------------------------------------------------------
1015// FormFieldChoice
1016//------------------------------------------------------------------------
1017FormFieldChoice::FormFieldChoice(XRef *xrefA, Object *aobj, const Ref& ref) 
1018        : FormField(xrefA, aobj, ref, formChoice)
1019{
1020  numChoices = 0;
1021  choices = NULL;
1022  editedChoice = NULL;
1023
1024  Dict* dict = obj.getDict();
1025  Object obj1;
1026
1027  combo = edit = multiselect = doNotSpellCheck = doCommitOnSelChange = false;
1028
1029  if (Form::fieldLookup(dict, "Ff", &obj1)->isInt()) {
1030    int flags = obj1.getInt();
1031    if (flags & 0x20000) // 18 -> Combo
1032      combo = true; 
1033    if (flags & 0x40000) // 19 -> Edit
1034      edit = true;
1035    if (flags & 0x200000) // 22 -> MultiSelect
1036      multiselect = true;
1037    if (flags & 0x400000) // 23 -> DoNotSpellCheck
1038      doNotSpellCheck = true;
1039    if (flags & 0x4000000) // 27 -> CommitOnSelChange
1040      doCommitOnSelChange = true;
1041  }
1042  obj1.free();
1043
1044}
1045
1046FormFieldChoice::~FormFieldChoice()
1047{
1048  for (int i=0; i<numChoices; i++) {
1049    delete choices[i].exportVal;
1050    delete choices[i].optionName;
1051  }
1052  delete [] choices;
1053  delete editedChoice;
1054}
1055
1056void FormFieldChoice::deselectAll ()
1057{
1058  for(int i=0; i<numChoices; i++) {
1059    choices[i].selected = false;
1060  }
1061}
1062
1063void FormFieldChoice::toggle (int i)
1064{
1065  choices[i].selected = !choices[i].selected;
1066}
1067
1068void FormFieldChoice::select (int i)
1069{
1070  if (!multiselect) 
1071    deselectAll();
1072  choices[i].selected = true;
1073}
1074
1075void FormFieldChoice::setEditChoice (GooString* new_content)
1076{
1077  if (editedChoice)
1078    delete editedChoice;
1079
1080  deselectAll();
1081
1082  editedChoice = new_content->copy();
1083}
1084
1085GooString* FormFieldChoice::getEditChoice ()
1086{
1087  return editedChoice;
1088}
1089
1090int FormFieldChoice::getNumSelected ()
1091{
1092  int cnt = 0;
1093  for(int i=0; i<numChoices; i++) {
1094    if (choices[i].selected)
1095      cnt++;
1096  }
1097  return cnt;
1098}
1099
1100void FormFieldChoice::_createChoicesTab ()
1101{
1102  choices = new ChoiceOpt[numChoices]; 
1103  for(int i=0; i<numChoices; i++) {
1104    choices[i].selected = false;
1105  }
1106}
1107
1108//------------------------------------------------------------------------
1109// FormFieldSignature
1110//------------------------------------------------------------------------
1111FormFieldSignature::FormFieldSignature(XRef *xrefA, Object *dict, const Ref& ref)
1112        : FormField(xrefA, dict, ref, formSignature)
1113{
1114}
1115
1116FormFieldSignature::~FormFieldSignature()
1117{
1118
1119}
1120
1121//------------------------------------------------------------------------
1122// Form
1123//------------------------------------------------------------------------
1124
1125Form::Form(XRef *xrefA, Object* acroFormA)
1126{
1127  Object obj1;
1128
1129  xref = xrefA;
1130  acroForm = acroFormA;
1131 
1132  size = 0;
1133  numFields = 0;
1134  rootFields = NULL;
1135
1136  acroForm->dictLookup("NeedAppearances", &obj1);
1137  needAppearances = (obj1.isBool() && obj1.getBool());
1138  obj1.free();
1139
1140  acroForm->dictLookup("Fields", &obj1);
1141  if (obj1.isArray()) {
1142    Array *array = obj1.getArray();
1143    Object obj2;
1144   
1145    for(int i=0; i<array->getLength(); i++) {
1146      Object oref;
1147      array->get(i, &obj2);
1148      array->getNF(i, &oref);
1149      if (!oref.isRef()) {
1150        error(-1, "Direct object in rootFields");
1151        obj2.free();
1152        oref.free();
1153        continue;
1154      }
1155
1156      if (!obj2.isDict()) {
1157        error(-1, "Reference in Fields array to an invalid or non existant object");
1158        obj2.free();
1159        oref.free();
1160        continue;
1161      }
1162
1163      if (numFields >= size) {
1164        size += 16;
1165        rootFields = (FormField**)greallocn(rootFields,size,sizeof(FormField*));
1166      }
1167
1168      rootFields[numFields++] = createFieldFromDict (&obj2, xrefA, oref.getRef());
1169
1170      obj2.free();
1171      oref.free();
1172    }
1173  } else {
1174    error(-1, "Can't get Fields array\n");
1175  }
1176  obj1.free ();
1177}
1178
1179Form::~Form() {
1180  int i;
1181  for(i = 0; i< numFields; ++i)
1182    delete rootFields[i];
1183  gfree (rootFields);
1184}
1185
1186// Look up an inheritable field dictionary entry.
1187Object *Form::fieldLookup(Dict *field, char *key, Object *obj) {
1188  Dict *dict;
1189  Object parent;
1190
1191  dict = field;
1192  if (!dict->lookup(key, obj)->isNull()) {
1193    return obj;
1194  }
1195  obj->free();
1196  if (dict->lookup("Parent", &parent)->isDict()) {
1197    fieldLookup(parent.getDict(), key, obj);
1198  } else {
1199    obj->initNull();
1200  }
1201  parent.free();
1202  return obj;
1203}
1204
1205FormField *Form::createFieldFromDict (Object* obj, XRef *xrefA, const Ref& pref)
1206{
1207    Object obj2;
1208    FormField *field;
1209
1210    if (Form::fieldLookup(obj->getDict (), "FT", &obj2)->isName("Btn")) {
1211      field = new FormFieldButton(xrefA, obj, pref);
1212    } else if (obj2.isName("Tx")) {
1213      field = new FormFieldText(xrefA, obj, pref);
1214    } else if (obj2.isName("Ch")) {
1215      field = new FormFieldChoice(xrefA, obj, pref);
1216    } else if (obj2.isName("Sig")) {
1217      field = new FormFieldSignature(xrefA, obj, pref);
1218    } else { //we don't have an FT entry => non-terminal field
1219      field = new FormField(xrefA, obj, pref);
1220    }
1221    obj2.free();
1222   
1223    field->loadChildrenDefaults();
1224
1225    return field;
1226}
1227
1228void Form::postWidgetsLoad ()
1229{
1230 for(int i=0; i<numFields; i++) {
1231   rootFields[i]->fillChildrenSiblingsID(); 
1232 }
1233}
1234
1235FormWidget* Form::findWidgetByRef (Ref aref)
1236{
1237  for(int i=0; i<numFields; i++) {
1238    FormWidget *result = rootFields[i]->findWidgetByRef(aref);
1239    if(result) return result;
1240  }
1241  return NULL;
1242}
1243
1244//------------------------------------------------------------------------
1245// FormPageWidgets
1246//------------------------------------------------------------------------
1247
1248FormPageWidgets::FormPageWidgets (XRef *xrefA, Object* annots, unsigned int page, Form *form)
1249{
1250  Object obj1;
1251  numWidgets = 0;
1252  widgets = NULL;
1253  xref = xrefA;
1254  if (annots->isArray() && form) {
1255    size = annots->arrayGetLength();
1256    widgets = (FormWidget**)greallocn(widgets, size, sizeof(FormWidget*));
1257
1258    /* For each entry in the page 'Annots' dict, try to find
1259       a matching form field */
1260    for (int i = 0; i < size; ++i) {
1261      if (!annots->arrayGetNF(i, &obj1)->isRef())  {
1262        /* Since all entry in a form field's kid dict needs to be
1263           indirect references, if this annot isn't indirect, it isn't
1264           related to a form field */
1265        obj1.free();
1266        continue;
1267      }
1268      Ref r = obj1.getRef();
1269
1270      /* Try to find a form field which either has this Annot in its Kids entry
1271          or  is merged with this Annot */
1272      FormWidget* tmp = form->findWidgetByRef(r);
1273      if(tmp) {
1274        // We've found a corresponding form field, link it
1275        tmp->setID(FormWidget::encodeID(page, numWidgets));
1276        widgets[numWidgets++] = tmp;
1277        //create a temporary Annot to get the font size
1278        Object obj2;
1279        if (annots->arrayGet(i, &obj2)->isDict()) {
1280          Annot *ann;
1281         
1282          ann = new Annot(xref, obj2.getDict(), NULL);
1283          tmp->setFontSize(ann->getFontSize());
1284          delete ann;
1285        }
1286        obj2.free();
1287      } 
1288     
1289      obj1.free();
1290    }
1291  } 
1292}
1293
1294FormPageWidgets::~FormPageWidgets()
1295{
1296  gfree (widgets);
1297}
Note: See TracBrowser for help on using the repository browser.