Commit 74e70386 authored by Albert Astals Cid's avatar Albert Astals Cid
Browse files

2007-02-25 Julien Rebetez <julienr@svn.gnome.org>

            reviewed by: <aacid@kde.org>

        * glib/poppler-document.cc:
        * glib/poppler-document.h:
        * glib/poppler-page.cc:
        * glib/poppler-page.h:
        * glib/poppler-private.h:
        * glib/poppler.h:
        * poppler/Annot.cc:
        * poppler/Annot.h:
        * poppler/Catalog.cc:
        * poppler/Catalog.h:
        * poppler/CharCodeToUnicode.cc:
        * poppler/CharCodeToUnicode.h:
        * poppler/Dict.cc:
        * poppler/Dict.h:
        * poppler/Form.cc:
        * poppler/Form.h:
        * poppler/GfxFont.cc:
        * poppler/GfxFont.h:
        * poppler/Makefile.am:
        * poppler/Object.h:
        * poppler/Page.cc:
        * poppler/Page.h:
        * poppler/XRef.cc:
        * poppler/XRef.h:
                Beginning of Interactive Form support:
                Add a bunch of new classes (FormWidget / FormField) to deal with form
                fields.
                Add support for object modification through XRef::setModifiedObject, as
                well as a function to write the Xref to a file, which will be used
                to implement PDF writing.
                Add some functions to glib wrapper to expose the new form features.
parent 5c4ea446
2007-02-25 Julien Rebetez <julienr@svn.gnome.org>
reviewed by: <aacid@kde.org>
* glib/poppler-document.cc:
* glib/poppler-document.h:
* glib/poppler-page.cc:
* glib/poppler-page.h:
* glib/poppler-private.h:
* glib/poppler.h:
* poppler/Annot.cc:
* poppler/Annot.h:
* poppler/Catalog.cc:
* poppler/Catalog.h:
* poppler/CharCodeToUnicode.cc:
* poppler/CharCodeToUnicode.h:
* poppler/Dict.cc:
* poppler/Dict.h:
* poppler/Form.cc:
* poppler/Form.h:
* poppler/GfxFont.cc:
* poppler/GfxFont.h:
* poppler/Makefile.am:
* poppler/Object.h:
* poppler/Page.cc:
* poppler/Page.h:
* poppler/XRef.cc:
* poppler/XRef.h:
Beginning of Interactive Form support:
Add a bunch of new classes (FormWidget / FormField) to deal with form
fields.
Add support for object modification through XRef::setModifiedObject, as
well as a function to write the Xref to a file, which will be used
to implement PDF writing.
Add some functions to glib wrapper to expose the new form features.
2007-02-18 Albert Astals Cid <aacid@kde.org>
* configure.ac: Change {datadir}/poppler to {datarootdir}/poppler so
......
......@@ -1399,3 +1399,195 @@ poppler_ps_file_free (PopplerPSFile *ps_file)
g_return_if_fail (ps_file != NULL);
g_object_unref (ps_file);
}
FormWidget *
_get_form_widget_by_id (PopplerDocument *document, unsigned id)
{
Catalog *catalog = document->doc->getCatalog();
unsigned pageNum;
unsigned fieldNum;
FormWidget::decodeID(id, &pageNum, &fieldNum);
FormWidget *field = catalog->getPage(pageNum)->getPageWidgets()->getWidget(fieldNum);
if (field != NULL) {
return field;
} else
return NULL;
}
void
poppler_document_set_form_field_button_state (PopplerDocument *document, unsigned id, gboolean state)
{
FormWidget *field = _get_form_widget_by_id(document, id);
if (field && field->getType() == formButton) {
static_cast<FormWidgetButton*>(field)->setState((GBool)state);
} else {
g_warning("poppler_document_set_form_field_button_state, unknown id: %i", id);
}
}
gboolean
poppler_document_get_form_field_button_state (PopplerDocument *document, unsigned id)
{
FormWidget *field = _get_form_widget_by_id(document, id);
if (field && field->getType() == formButton) {
return static_cast<FormWidgetButton*>(field)->getState();
} else {
g_warning("poppler_document_get_form_field_button_state, unknown id: %i", id);
}
return FALSE;
}
void
poppler_document_set_form_field_text_content (PopplerDocument *document, unsigned id, char *content, int length)
{
FormWidget *field = _get_form_widget_by_id(document, id);
if (field && field->getType() == formText) {
GooString *tmp = new GooString(content, length);
static_cast<FormWidgetText*>(field)->setContent(tmp);
delete tmp;
} else {
g_warning("poppler_document_set_form_field_text_content, unknown id: %i", id);
}
}
gchar *
poppler_document_get_form_field_text_content (PopplerDocument *document, unsigned id, int* length)
{
FormWidget *field = _get_form_widget_by_id(document, id);
if (field && field->getType() == formText) {
FormWidgetText *wid = static_cast<FormWidgetText*>(field);
if (wid->getContent()) {
*length = wid->getContent()->getLength();
return wid->getContent()->getCString();
} else {
*length = 0;
return NULL;
}
} else {
g_warning("poppler_document_get_form_field_choice_content, unknown id: %i", id);
*length = 0;
return NULL;
}
}
gchar *
poppler_document_get_form_field_choice_content (PopplerDocument *document, unsigned id, int index, int *length)
{
FormWidget *field = _get_form_widget_by_id(document, id);
if (field && field->getType() == formChoice) {
*length = static_cast<FormWidgetChoice*>(field)->getChoice(index)->getLength();
return static_cast<FormWidgetChoice*>(field)->getChoice(index)->getCString();
} else {
g_warning("poppler_document_get_form_field_choice_content, unknown id: %i", id);
return NULL;
}
}
int
poppler_document_form_field_choice_is_selected (PopplerDocument* document, unsigned id, int index)
{
FormWidget *field = _get_form_widget_by_id(document, id);
if (field && field->getType() == formChoice) {
return static_cast<FormWidgetChoice*>(field)->isSelected(index);
} else {
g_warning("poppler_document_is_form_field_choice_selected, unknown id: %i", id);
return -1;
}
}
int
poppler_document_get_form_field_choice_num_choices (PopplerDocument *document, unsigned id)
{
FormWidget *field = _get_form_widget_by_id(document, id);
if (field && field->getType() == formChoice) {
return static_cast<FormWidgetChoice*>(field)->getNumChoices();
} else {
g_warning("poppler_document_get_form_field_choice_content, unknown id: %i", id);
return -1;
}
}
void
poppler_document_form_field_choice_select (PopplerDocument* document, unsigned id, int index)
{
FormWidget *field = _get_form_widget_by_id(document, id);
if (field && field->getType() == formChoice) {
static_cast<FormWidgetChoice*>(field)->select(index);
} else {
g_warning("poppler_document_set_form_field_choice_select, unknown id: %i", id);
}
}
void
poppler_document_form_field_choice_toggle (PopplerDocument* document, unsigned id, int index)
{
FormWidget *field = _get_form_widget_by_id(document, id);
if (field && field->getType() == formChoice) {
static_cast<FormWidgetChoice*>(field)->toggle(index);
} else {
g_warning("poppler_document_form_field_choice_toggle, unknown id: %i", id);
}
}
void
poppler_document_form_field_choice_deselect_all (PopplerDocument* document, unsigned id)
{
FormWidget *field = _get_form_widget_by_id(document, id);
if (field && field->getType() == formChoice) {
static_cast<FormWidgetChoice*>(field)->deselectAll();
} else {
g_warning("poppler_document_form_field_choice_deselect_all, unknown id: %i", id);
}
}
void
poppler_document_set_form_field_choice_edit (PopplerDocument* document,
unsigned id,
char *content,
int length)
{
FormWidget *field = _get_form_widget_by_id(document, id);
if (field && field->getType() == formChoice) {
GooString *tmp = new GooString(content, length);
static_cast<FormWidgetChoice*>(field)->setEditChoice(tmp);
delete tmp;
} else {
g_warning("poppler_document_form_field_choice_set_edit, unknown id: %i", id);
}
}
gchar *
poppler_document_get_form_field_choice_edit (PopplerDocument* document,
unsigned id,
int *length)
{
FormWidget *field = _get_form_widget_by_id(document, id);
if (field && field->getType() == formChoice) {
FormWidgetChoice *choice = static_cast<FormWidgetChoice*>(field);
if (choice->getEditChoice()) {
*length = choice->getEditChoice()->getLength();
return choice->getEditChoice()->getCString();
} else
return NULL;
} else {
g_warning("poppler_document_get_form_field_choice_edit, unknown id: %i", id);
return NULL;
}
}
PopplerFormField *
poppler_document_find_form_field_by_id (PopplerDocument *document, unsigned id)
{
FormWidget *field = _get_form_widget_by_id(document, id);
if (field != NULL) {
PopplerFormField *poppler_field = _form_field_new_from_widget (field);
return poppler_field;
} else
return NULL;
}
......@@ -112,6 +112,61 @@ GList *poppler_document_get_attachments (PopplerDocument *document)
PopplerDest *poppler_document_find_dest (PopplerDocument *document,
const gchar *link_name);
/* Form */
void poppler_document_set_form_field_text_content (PopplerDocument *document,
unsigned id,
char *content,
int length);
PopplerFormField *poppler_document_find_form_field_by_id (PopplerDocument *document,
unsigned id);
void poppler_document_set_form_field_button_state (PopplerDocument *document,
unsigned id,
gboolean state);
gboolean poppler_document_get_form_field_button_state (PopplerDocument *document,
unsigned id);
gchar *
poppler_document_get_form_field_text_content (PopplerDocument *document,
unsigned id,
int *length);
int
poppler_document_get_form_field_choice_num_choices (PopplerDocument *document,
unsigned id);
gchar *
poppler_document_get_form_field_choice_content (PopplerDocument *document,
unsigned id,
int index,
int *length);
int
poppler_document_form_field_choice_is_selected (PopplerDocument* document,
unsigned id,
int index);
void
poppler_document_form_field_choice_select (PopplerDocument* document,
unsigned id,
int index);
void
poppler_document_form_field_choice_toggle (PopplerDocument* document,
unsigned id,
int index);
void
poppler_document_form_field_choice_deselect_all (PopplerDocument* document,
unsigned id);
void
poppler_document_set_form_field_choice_edit (PopplerDocument* document,
unsigned id,
char *content,
int length);
gchar *
poppler_document_get_form_field_choice_edit (PopplerDocument* document,
unsigned id,
int *length);
/* Interface for getting the Index of a poppler_document */
#define POPPLER_TYPE_INDEX_ITER (poppler_index_iter_get_type ())
GType poppler_index_iter_get_type (void) G_GNUC_CONST;
......
......@@ -1038,3 +1038,123 @@ poppler_link_mapping_free (PopplerLinkMapping *mapping)
g_free (mapping);
}
/* Form Type */
GType
poppler_form_field_get_type (void)
{
static GType our_type = 0;
if (our_type == 0)
our_type = g_boxed_type_register_static("PopplerFormField",
(GBoxedCopyFunc) poppler_form_field_copy,
(GBoxedFreeFunc) poppler_form_field_free);
return our_type;
}
PopplerFormField*
poppler_form_field_new (void)
{
return (PopplerFormField *) g_new0 (PopplerFormField, 1);
}
PopplerFormField*
poppler_form_field_copy (PopplerFormField* field)
{
PopplerFormField* new_field;
new_field = poppler_form_field_new();
new_field = field;
return new_field;
}
void
poppler_form_field_free (PopplerFormField* field)
{
g_free (field);
}
PopplerFormField *
_form_field_new_from_widget (FormWidget* field)
{
PopplerFormField *poppler_field = g_new(PopplerFormField, 1);
field->getRect (&(poppler_field->area.x1), &(poppler_field->area.y1),
&(poppler_field->area.x2), &(poppler_field->area.y2));
poppler_field->type = (PopplerFormFieldType)field->getType();
poppler_field->id = field->getID();
poppler_field->font_size = field->getFontSize();
if (poppler_field->type == POPPLER_FORM_FIELD_TEXT) {
FormWidgetText* wid = static_cast<FormWidgetText*>(field);
GooString *tmp = wid->getContentCopy();
poppler_field->text.content = (tmp)?tmp->getCString():NULL;
poppler_field->text.length = (tmp)?tmp->getLength():0;
poppler_field->text.multiline = wid->isMultiline();
poppler_field->text.password = wid->isPassword();
poppler_field->text.fileselect = wid->isFileSelect();
poppler_field->text.do_not_spell_check = wid->noSpellCheck();
poppler_field->text.do_not_scroll = wid->noScroll();
poppler_field->text.rich_text = wid->isRichText();
} else if (poppler_field->type == POPPLER_FORM_FIELD_BUTTON) {
poppler_field->button.state = (gboolean)static_cast<FormWidgetButton*>(field)->getState();
} else if (poppler_field->type == POPPLER_FORM_FIELD_CHOICE) {
FormWidgetChoice* wid = static_cast<FormWidgetChoice*>(field);
poppler_field->choice.combo = wid->isCombo();
poppler_field->choice.edit = wid->hasEdit();
poppler_field->choice.multi_select = wid->isMultiSelect();
poppler_field->choice.do_not_spell_check = wid->noSpellCheck();
}
return poppler_field;
}
/**
* poppler_page_get_form_fields
**/
GList*
poppler_page_get_form_fields (PopplerPage *page)
{
GList *field_list = NULL;
FormPageWidgets *form;
gint i;
Object obj;
g_return_val_if_fail (POPPLER_IS_PAGE (page), NULL);
form = page->page->getPageWidgets();
obj.free ();
if(form == NULL)
return NULL;
for(i = 0; i < form->getNumWidgets(); i++) {
PopplerFormField *poppler_field;
FormWidget *field;
field = form->getWidget(i);
poppler_field = _form_field_new_from_widget (field);
field_list = g_list_prepend(field_list,poppler_field);
}
return field_list;
}
void
poppler_page_free_form_fields (GList *list)
{
if (list == NULL)
return;
g_list_foreach (list, (GFunc) (poppler_form_field_free), NULL);
g_list_free (list);
}
void
poppler_page_get_crop_box (PopplerPage *page, PopplerRectangle *rect)
{
PDFRectangle* cropBox = page->page->getCropBox();
rect->x1 = cropBox->x1;
rect->x2 = cropBox->x2;
rect->y1 = cropBox->y1;
rect->y2 = cropBox->y2;
}
......@@ -81,6 +81,11 @@ void poppler_page_render_selection (PopplerPage *page,
PopplerRectangle *old_selection,
GdkColor *glyph_color,
GdkColor *background_color);
GList *poppler_page_get_form_fields (PopplerPage *page);
void poppler_page_free_form_fields (GList *list);
void poppler_page_get_crop_box (PopplerPage *page,
PopplerRectangle *rect);
/* A rectangle on a page, with coordinates in PDF points. */
......@@ -113,6 +118,56 @@ PopplerLinkMapping *poppler_link_mapping_new (void);
PopplerLinkMapping *poppler_link_mapping_copy (PopplerLinkMapping *mapping);
void poppler_link_mapping_free (PopplerLinkMapping *mapping);
/* FormField */
#define POPPLER_TYPE_FORM_FIELD (poppler_form_field_get_type ())
struct _PopplerTextField
{
//flags
char multiline:1;
char password:1;
char fileselect:1;
char do_not_spell_check:1;
char do_not_scroll:1;
char comb:1;
char rich_text:1;
//content
gchar *content;
int length;
};
struct _PopplerButtonField
{
//content
gboolean state;
};
struct _PopplerChoiceField
{
char combo:1;
char edit:1;
char multi_select:1;
char do_not_spell_check:1;
char commit_on_sel_change:1;
};
struct _PopplerFormField
{
PopplerRectangle area;
PopplerFormFieldType type;
int id;
double font_size;
union {
PopplerTextField text;
PopplerButtonField button;
PopplerChoiceField choice;
};
};
GType poppler_form_field_get_type (void) G_GNUC_CONST;
PopplerFormField *poppler_form_field_new (void);
PopplerFormField *poppler_form_field_copy (PopplerFormField *field);
void poppler_form_field_free (PopplerFormField *field);
G_END_DECLS
#endif /* __POPPLER_PAGE_H__ */
......@@ -5,6 +5,7 @@
#include <PDFDoc.h>
#include <PSOutputDev.h>
#include <Link.h>
#include <Form.h>
#include <Gfx.h>
#include <FontInfo.h>
#include <TextOutputDev.h>
......@@ -60,6 +61,9 @@ struct _PopplerPage
Gfx *gfx;
};
PopplerFormField *_form_field_new_from_widget (FormWidget* field);
PopplerPage *_poppler_page_new (PopplerDocument *document,
Page *page,
int index);
......
......@@ -42,17 +42,30 @@ typedef enum
POPPLER_ORIENTATION_SEASCAPE
} PopplerOrientation;
/* MUST be the same than poppler/Form.h fieldType */
typedef enum
{
POPPLER_FORM_FIELD_BUTTON,
POPPLER_FORM_FIELD_TEXT,
POPPLER_FORM_FIELD_CHOICE,
POPPLER_FORM_FIELD_SIGNATURE,
} PopplerFormFieldType;
typedef struct _PopplerDocument PopplerDocument;
typedef struct _PopplerIndexIter PopplerIndexIter;
typedef struct _PopplerFontsIter PopplerFontsIter;
typedef struct _PopplerRectangle PopplerRectangle;
typedef struct _PopplerLinkMapping PopplerLinkMapping;
typedef struct _PopplerFormField PopplerFormField;
typedef struct _PopplerPage PopplerPage;
typedef struct _PopplerFontInfo PopplerFontInfo;
typedef struct _PopplerPSFile PopplerPSFile;
typedef union _PopplerAction PopplerAction;
typedef struct _PopplerDest PopplerDest;
typedef struct _PopplerTextField PopplerTextField;
typedef struct _PopplerButtonField PopplerButtonField;
typedef struct _PopplerChoiceField PopplerChoiceField;
typedef enum
{
......
......@@ -20,19 +20,30 @@
#include "Lexer.h"
#include "UGooString.h"
#include "Annot.h"
#include "GfxFont.h"
#include "CharCodeToUnicode.h"
#include "Form.h"
#include "Error.h"
//------------------------------------------------------------------------
// Annot
//------------------------------------------------------------------------
Annot::Annot(XRef *xrefA, Dict *acroForm, Dict *dict) {
Annot::Annot(XRef *xrefA, Dict *acroForm, Dict *dict, Ref* aref, Catalog* catalog) {
Object apObj, asObj, obj1, obj2;
GBool regen, isTextField;
double t;
ok = gTrue;
xref = xrefA;
appearBuf = NULL;
fontSize = 0;
widget = NULL;
if (aref) {
hasRef = true;
ref = *aref;
} else
hasRef = false;
if (dict->lookup("Rect", &obj1)->isArray() &&
obj1.arrayGetLength() == 4) {
......@@ -59,6 +70,16 @@ Annot::Annot(XRef *xrefA, Dict *acroForm, Dict *dict) {
}
obj1.free();
//check for hidden annot
hidden = false;
Object obj3;
if (dict->lookup("F", &obj3)->isInt()) {
int flags = obj3.getInt();
if (flags & 0x2)
hidden = true;
}
obj3.free();
// check if field apperances need to be regenerated
regen = gFalse;
if (acroForm) {
......@@ -68,16 +89,38 @@ Annot::Annot(XRef *xrefA, Dict *acroForm, Dict *dict) {
}
obj1.free();
}
regen = gTrue;
// check for a text-type field
isTextField = dict->lookup("FT", &obj1)->isName("Tx");
obj1.free();
/*TODO: appearance generation isn't complete :
non-comprehensive list of missings things by Leonard Rosenthol :
* Doesn't support walking up the parents of the field for /DA information
* Doesn't support field attributes
border style (width, color, etc.)
background color
flags (password, comb, etc.)
etc.
* Only works for text fields, basic support for combos
*/
//try to find the corresponding FormWidget
if (hasRef && catalog->getForm()) {