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

Last change on this file since 277 was 277, checked in by rbri, 12 years ago

PDF plugin: Poppler library updated to version 0.12.3

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