Commit 664865a2 authored by Carlos Garcia Campos's avatar Carlos Garcia Campos

Merge Link and AnnotLink code

Annotations now belong to the Page and are created only once on demand.
Annots are now ref counted and Links is a list of AnnotLink objects,
Link object has been removed. The AnnotLink API is mostly the same than
Link and frontends APIs are not affected.
Qt4 changes made by Pino Toscano.
parent 1f6573e9
......@@ -2493,7 +2493,7 @@ poppler_document_get_form_field (PopplerDocument *document,
if (!page)
return NULL;
widgets = page->getPageWidgets ();
widgets = page->getFormWidgets (document->doc->getCatalog ());
if (!widgets)
return NULL;
......
......@@ -76,8 +76,6 @@ poppler_page_finalize (GObject *object)
g_object_unref (page->document);
page->document = NULL;
if (page->annots != NULL)
delete page->annots;
if (page->text != NULL)
page->text->decRefCnt();
/* page->page is owned by the document */
......@@ -1139,15 +1137,12 @@ poppler_page_get_link_mapping (PopplerPage *page)
GList *map_list = NULL;
gint i;
Links *links;
Object obj;
double width, height;
g_return_val_if_fail (POPPLER_IS_PAGE (page), NULL);
links = new Links (page->page->getAnnots (&obj),
page->document->doc->getCatalog ()->getBaseURI ());
obj.free ();
links = new Links (page->page->getAnnots (page->document->doc->getCatalog ()));
if (links == NULL)
return NULL;
......@@ -1158,7 +1153,7 @@ poppler_page_get_link_mapping (PopplerPage *page)
PopplerLinkMapping *mapping;
PopplerRectangle rect;
LinkAction *link_action;
Link *link;
AnnotLink *link;
link = links->getLink (i);
link_action = link->getAction ();
......@@ -1250,7 +1245,8 @@ poppler_page_get_form_field_mapping (PopplerPage *page)
g_return_val_if_fail (POPPLER_IS_PAGE (page), NULL);
forms = page->page->getPageWidgets ();
forms = page->page->getFormWidgets (page->document->doc->getCatalog ());
if (forms == NULL)
return NULL;
......@@ -1273,6 +1269,8 @@ poppler_page_get_form_field_mapping (PopplerPage *page)
map_list = g_list_prepend (map_list, mapping);
}
delete forms;
return map_list;
}
......@@ -1310,25 +1308,24 @@ poppler_page_get_annot_mapping (PopplerPage *page)
GList *map_list = NULL;
double width, height;
gint i;
Annots *annots;
g_return_val_if_fail (POPPLER_IS_PAGE (page), NULL);
if (!page->annots)
page->annots = page->page->getAnnots (page->document->doc->getCatalog ());
if (!page->annots)
annots = page->page->getAnnots (page->document->doc->getCatalog ());
if (!annots)
return NULL;
poppler_page_get_size (page, &width, &height);
for (i = 0; i < page->annots->getNumAnnots (); i++) {
for (i = 0; i < annots->getNumAnnots (); i++) {
PopplerAnnotMapping *mapping;
PopplerRectangle rect;
Annot *annot;
PDFRectangle *annot_rect;
gint rotation = 0;
annot = page->annots->getAnnot (i);
annot = annots->getAnnot (i);
/* Create the mapping */
mapping = poppler_annot_mapping_new ();
......@@ -1432,7 +1429,7 @@ poppler_page_add_annot (PopplerPage *page,
g_return_if_fail (POPPLER_IS_PAGE (page));
g_return_if_fail (POPPLER_IS_ANNOT (annot));
page->page->addAnnot (annot->annot);
page->page->addAnnot (annot->annot, page->document->doc->getCatalog ());
}
/* PopplerRectangle type */
......
......@@ -60,7 +60,6 @@ struct _PopplerPage
Page *page;
int index;
TextPage *text;
Annots *annots;
};
struct _PopplerFormField
......
......@@ -46,13 +46,13 @@
#include "Catalog.h"
#include "Gfx.h"
#include "Lexer.h"
#include "Page.h"
#include "Annot.h"
#include "GfxFont.h"
#include "CharCodeToUnicode.h"
#include "PDFDocEncoding.h"
#include "Form.h"
#include "Error.h"
#include "Page.h"
#include "XRef.h"
#include "Movie.h"
#include "OptionalContent.h"
......@@ -853,6 +853,7 @@ AnnotAppearanceCharacs::~AnnotAppearanceCharacs() {
Annot::Annot(XRef *xrefA, PDFRectangle *rectA, Catalog *catalog) {
Object obj1;
refCnt = 1;
flags = flagUnknown;
type = typeUnknown;
......@@ -875,6 +876,7 @@ Annot::Annot(XRef *xrefA, PDFRectangle *rectA, Catalog *catalog) {
}
Annot::Annot(XRef *xrefA, Dict *dict, Catalog* catalog) {
refCnt = 1;
hasRef = false;
flags = flagUnknown;
type = typeUnknown;
......@@ -883,6 +885,7 @@ Annot::Annot(XRef *xrefA, Dict *dict, Catalog* catalog) {
}
Annot::Annot(XRef *xrefA, Dict *dict, Catalog* catalog, Object *obj) {
refCnt = 1;
if (obj->isRef()) {
hasRef = gTrue;
ref = obj->getRef();
......@@ -1048,6 +1051,17 @@ void Annot::initialize(XRef *xrefA, Dict *dict, Catalog *catalog) {
}
}
void Annot::getRect(double *x1, double *y1, double *x2, double *y2) const {
*x1 = rect->x1;
*y1 = rect->y1;
*x2 = rect->x2;
*y2 = rect->y2;
}
GBool Annot::inRect(double x, double y) const {
return rect->contains(x, y);
}
void Annot::update(const char *key, Object *value) {
/* Set M to current time */
delete modified;
......@@ -1128,6 +1142,15 @@ void Annot::readArrayNum(Object *pdfArray, int key, double *value) {
valueObject.free();
}
void Annot::incRefCnt() {
refCnt++;
}
void Annot::decRefCnt() {
if (--refCnt == 0)
delete this;
}
Annot::~Annot() {
annotObj.free();
......@@ -1999,11 +2022,7 @@ AnnotLink::AnnotLink(XRef *xrefA, Dict *dict, Catalog *catalog, Object *obj) :
}
AnnotLink::~AnnotLink() {
/*
if (actionDict)
delete actionDict;
*/
dest.free();
delete action;
/*
if (uriAction)
delete uriAction;
......@@ -2014,15 +2033,21 @@ AnnotLink::~AnnotLink() {
void AnnotLink::initialize(XRef *xrefA, Catalog *catalog, Dict *dict) {
Object obj1;
/*
if (dict->lookup("A", &obj1)->isDict()) {
actionDict = NULL;
action = NULL;
// look for destination
if (!dict->lookup("Dest", &obj1)->isNull()) {
action = LinkAction::parseDest(&obj1);
// look for action
} else {
actionDict = NULL;
obj1.free();
if (dict->lookup("A", &obj1)->isDict()) {
action = LinkAction::parseAction(&obj1, catalog->getBaseURI());
}
}
obj1.free();
*/
dict->lookup("Dest", &dest);
if (dict->lookup("H", &obj1)->isName()) {
GooString *effect = new GooString(obj1.getName());
......@@ -2750,10 +2775,9 @@ void AnnotWidget::initialize(XRef *xrefA, Catalog *catalog, Dict *dict) {
}
obj1.free();
action = NULL;
if(dict->lookup("A", &obj1)->isDict()) {
action = NULL;
} else {
action = NULL;
action = LinkAction::parseAction(&obj1, catalog->getBaseURI());
}
obj1.free();
......@@ -5235,7 +5259,6 @@ Annot3D::Activation::Activation(Dict *dict) {
Annots::Annots(XRef *xref, Catalog *catalog, Object *annotsObj) {
Annot *annot;
Object obj1;
int size;
int i;
annots = NULL;
......@@ -5251,15 +5274,8 @@ Annots::Annots(XRef *xref, Catalog *catalog, Object *annotsObj) {
if (annotsObj->arrayGet(i, &obj1)->isDict()) {
annotsObj->arrayGetNF(i, &obj2);
annot = createAnnot (xref, obj1.getDict(), catalog, &obj2);
if (annot && annot->isOk()) {
if (nAnnots >= size) {
size += 16;
annots = (Annot **)greallocn(annots, size, sizeof(Annot *));
}
annots[nAnnots++] = annot;
} else {
delete annot;
}
appendAnnot(annot);
annot->decRefCnt();
}
obj2.free();
obj1.free();
......@@ -5267,6 +5283,17 @@ Annots::Annots(XRef *xref, Catalog *catalog, Object *annotsObj) {
}
}
void Annots::appendAnnot(Annot *annot) {
if (annot && annot->isOk()) {
if (nAnnots >= size) {
size += 16;
annots = (Annot **)greallocn(annots, size, sizeof(Annot *));
}
annots[nAnnots++] = annot;
annot->incRefCnt();
}
}
Annot *Annots::createAnnot(XRef *xref, Dict* dict, Catalog *catalog, Object *obj) {
Annot *annot;
Object obj1;
......@@ -5364,7 +5391,7 @@ Annots::~Annots() {
int i;
for (i = 0; i < nAnnots; ++i) {
delete annots[i];
annots[i]->decRefCnt();
}
gfree(annots);
}
......@@ -486,9 +486,11 @@ public:
Annot(XRef *xrefA, PDFRectangle *rectA, Catalog *catalog);
Annot(XRef *xrefA, Dict *dict, Catalog *catalog);
Annot(XRef *xrefA, Dict *dict, Catalog *catalog, Object *obj);
virtual ~Annot();
GBool isOk() { return ok; }
void incRefCnt();
void decRefCnt();
virtual void draw(Gfx *gfx, GBool printing);
// Get appearance object.
Object *getAppearance(Object *obj) { return appearance.fetch(xref, obj); }
......@@ -513,9 +515,11 @@ public:
// getters
XRef *getXRef() const { return xref; }
GBool getHasRef() const { return hasRef; }
Ref getRef() const { return ref; }
AnnotSubtype getType() const { return type; }
PDFRectangle *getRect() const { return rect; }
void getRect(double *x1, double *y1, double *x2, double *y2) const;
GooString *getContents() const { return contents; }
int getPageNum() const { return page; }
GooString *getName() const { return name; }
......@@ -529,6 +533,9 @@ public:
int getId() { return ref.num; }
// Check if point is inside the annot rectangle.
GBool inRect(double x, double y) const;
private:
void readArrayNum(Object *pdfArray, int key, double *value);
// write vStr[i:j[ in appearBuf
......@@ -537,6 +544,7 @@ private:
protected:
virtual ~Annot();
void setColor(AnnotColor *color, GBool fill);
void drawCircle(double cx, double cy, double r, GBool fill);
void drawCircleTopLeft(double cx, double cy, double r);
......@@ -550,6 +558,8 @@ protected:
// and sets M to the current time
void update(const char *key, Object *value);
int refCnt;
Object annotObj;
// required data
......@@ -774,8 +784,7 @@ public:
virtual void draw(Gfx *gfx, GBool printing);
// getters
Dict *getActionDict() const { return actionDict; }
Object *getDest() { return &dest; }
LinkAction *getAction() const { return action; }
AnnotLinkEffect getLinkEffect() const { return linkEffect; }
Dict *getUriAction() const { return uriAction; }
AnnotQuadrilaterals *getQuadrilaterals() const { return quadrilaterals; }
......@@ -784,8 +793,7 @@ protected:
void initialize(XRef *xrefA, Catalog *catalog, Dict *dict);
Dict *actionDict; // A
Object dest; // Dest
LinkAction *action; // A, Dest
AnnotLinkEffect linkEffect; // H (Default I)
Dict *uriAction; // PA
......@@ -1161,7 +1169,7 @@ public:
AnnotWidgetHighlightMode getMode() { return mode; }
AnnotAppearanceCharacs *getAppearCharacs() { return appearCharacs; }
Dict *getAction() { return action; }
LinkAction *getAction() { return action; }
Dict *getAdditionActions() { return additionActions; }
Dict *getParent() { return parent; }
......@@ -1185,7 +1193,7 @@ private:
FormWidget *widget; // FormWidget object for this annotation
AnnotWidgetHighlightMode mode; // H (Default I)
AnnotAppearanceCharacs *appearCharacs; // MK
Dict *action; // A
LinkAction *action; // A
Dict *additionActions; // AA
// inherited from Annot
// AnnotBorderBS border; // BS
......@@ -1268,6 +1276,7 @@ public:
// Iterate through list of annotations.
int getNumAnnots() { return nAnnots; }
Annot *getAnnot(int i) { return annots[i]; }
void appendAnnot(Annot *annot);
private:
Annot* createAnnot(XRef *xref, Dict* dict, Catalog *catalog, Object *obj);
......@@ -1275,6 +1284,7 @@ private:
Annot **annots;
int nAnnots;
int size;
};
#endif
......@@ -140,10 +140,6 @@ void ArthurOutputDev::startPage(int pageNum, GfxState *state)
void ArthurOutputDev::endPage() {
}
void ArthurOutputDev::drawLink(Link *link, Catalog *catalog)
{
}
void ArthurOutputDev::saveState(GfxState *state)
{
m_painter->save();
......
......@@ -91,9 +91,6 @@ public:
// End a page.
virtual void endPage();
//----- link borders
virtual void drawLink(Link *link, Catalog *catalog);
//----- save/restore graphics state
virtual void saveState(GfxState *state);
virtual void restoreState(GfxState *state);
......
......@@ -242,9 +242,6 @@ void CairoOutputDev::endPage() {
}
}
void CairoOutputDev::drawLink(Link *link, Catalog *catalog) {
}
void CairoOutputDev::saveState(GfxState *state) {
LOG(printf ("save\n"));
cairo_save (cairo);
......
......@@ -128,9 +128,6 @@ public:
// End a page.
virtual void endPage();
//----- link borders
virtual void drawLink(Link *link, Catalog *catalog);
//----- save/restore graphics state
virtual void saveState(GfxState *state);
virtual void restoreState(GfxState *state);
......@@ -386,9 +383,6 @@ public:
// Does this device need non-text content?
virtual GBool needNonText() { return gTrue; }
//----- link borders
virtual void drawLink(Link *link, Catalog *catalog) { }
//----- save/restore graphics state
virtual void saveState(GfxState *state) { }
virtual void restoreState(GfxState *state) { }
......
......@@ -73,8 +73,7 @@ GooList *FontInfoScanner::scan(int nPages) {
if ((resDict = page->getResourceDict())) {
scanFonts(resDict, result);
}
annots = new Annots(doc->getXRef(), doc->getCatalog(), page->getAnnots(&obj1));
obj1.free();
annots = page->getAnnots(doc->getCatalog());
for (int i = 0; i < annots->getNumAnnots(); ++i) {
if (annots->getAnnot(i)->getAppearance(&obj1)->isStream()) {
obj1.streamGetDict()->lookup("Resources", &obj2);
......@@ -85,7 +84,6 @@ GooList *FontInfoScanner::scan(int nPages) {
}
obj1.free();
}
delete annots;
}
currentPage = lastPage;
......
......@@ -1360,50 +1360,40 @@ FormWidget* Form::findWidgetByRef (Ref aref)
// FormPageWidgets
//------------------------------------------------------------------------
FormPageWidgets::FormPageWidgets (XRef *xrefA, Object* annots, unsigned int page, Form *form)
FormPageWidgets::FormPageWidgets (Annots *annots, unsigned int page, Form *form)
{
Object obj1;
numWidgets = 0;
widgets = NULL;
xref = xrefA;
if (annots->isArray() && form) {
size = annots->arrayGetLength();
if (annots && annots->getNumAnnots() > 0 && form) {
size = annots->getNumAnnots();
widgets = (FormWidget**)greallocn(widgets, size, sizeof(FormWidget*));
/* For each entry in the page 'Annots' dict, try to find
a matching form field */
for (int i = 0; i < size; ++i) {
if (!annots->arrayGetNF(i, &obj1)->isRef()) {
Annot *annot = annots->getAnnot(i);
if (!annot->getHasRef()) {
/* Since all entry in a form field's kid dict needs to be
indirect references, if this annot isn't indirect, it isn't
related to a form field */
obj1.free();
continue;
}
Ref r = obj1.getRef();
Ref r = annot->getRef();
/* Try to find a form field which either has this Annot in its Kids entry
or is merged with this Annot */
FormWidget* tmp = form->findWidgetByRef(r);
if(tmp) {
if (tmp) {
// We've found a corresponding form field, link it
tmp->setID(FormWidget::encodeID(page, numWidgets));
tmp->setFontSize(annot->getFontSize());
widgets[numWidgets++] = tmp;
//create a temporary Annot to get the font size
Object obj2;
if (annots->arrayGet(i, &obj2)->isDict()) {
Annot *ann;
ann = new Annot(xref, obj2.getDict(), NULL);
tmp->setFontSize(ann->getFontSize());
delete ann;
}
obj2.free();
}
obj1.free();
}
}
}
}
}
FormPageWidgets::~FormPageWidgets()
......
......@@ -26,6 +26,7 @@ class GooString;
class Array;
class Dict;
class Annot;
class Annots;
class Catalog;
class LinkAction;
......@@ -477,7 +478,7 @@ private:
class FormPageWidgets {
public:
FormPageWidgets (XRef *xrefA, Object* annots, unsigned int page, Form *form);
FormPageWidgets (Annots* annots, unsigned int page, Form *form);
~FormPageWidgets();
int getNumWidgets() const { return numWidgets; }
......@@ -487,8 +488,6 @@ private:
FormWidget** widgets;
int numWidgets;
int size;
unsigned pageNum;
XRef* xref;
};
#endif
......
......@@ -44,6 +44,7 @@
#include "Sound.h"
#include "FileSpec.h"
#include "Rendition.h"
#include "Annot.h"
//------------------------------------------------------------------------
// LinkAction
......@@ -859,97 +860,11 @@ LinkUnknown::~LinkUnknown() {
delete action;
}
//------------------------------------------------------------------------
// Link
//------------------------------------------------------------------------
Link::Link(Dict *dict, GooString *baseURI) {
Object obj1, obj2;
double t;
action = NULL;
ok = gFalse;
// get rectangle
if (!dict->lookup("Rect", &obj1)->isArray()) {
error(-1, "Annotation rectangle is wrong type");
goto err2;
}
if (!obj1.arrayGet(0, &obj2)->isNum()) {
error(-1, "Bad annotation rectangle");
goto err1;
}
x1 = obj2.getNum();
obj2.free();
if (!obj1.arrayGet(1, &obj2)->isNum()) {
error(-1, "Bad annotation rectangle");
goto err1;
}
y1 = obj2.getNum();
obj2.free();
if (!obj1.arrayGet(2, &obj2)->isNum()) {
error(-1, "Bad annotation rectangle");
goto err1;
}
x2 = obj2.getNum();
obj2.free();
if (!obj1.arrayGet(3, &obj2)->isNum()) {
error(-1, "Bad annotation rectangle");
goto err1;
}
y2 = obj2.getNum();
obj2.free();
obj1.free();
if (x1 > x2) {
t = x1;
x1 = x2;
x2 = t;
}
if (y1 > y2) {
t = y1;
y1 = y2;
y2 = t;
}
// look for destination
if (!dict->lookup("Dest", &obj1)->isNull()) {
action = LinkAction::parseDest(&obj1);
// look for action
} else {
obj1.free();
if (dict->lookup("A", &obj1)->isDict()) {
action = LinkAction::parseAction(&obj1, baseURI);
}
}
obj1.free();
// check for bad action
if (action) {
ok = gTrue;
}
return;
err1:
obj2.free();
err2:
obj1.free();
}
Link::~Link() {
if (action) {
delete action;
}
}
//------------------------------------------------------------------------
// Links
//------------------------------------------------------------------------
Links::Links(Object *annots, GooString *baseURI) {
Link *link;
Object obj1, obj2;
Links::Links(Annots *annots) {
int size;
int i;
......@@ -957,25 +872,21 @@ Links::Links(Object *annots, GooString *baseURI) {
size = 0;
numLinks = 0;
if (annots->isArray()) {
for (i = 0; i < annots->arrayGetLength(); ++i) {
if (annots->arrayGet(i, &obj1)->isDict()) {
if (obj1.dictLookup("Subtype", &obj2)->isName("Link")) {
link = new Link(obj1.getDict(), baseURI);
if (link->isOk()) {
if (numLinks >= size) {
size += 16;
links = (Link **)greallocn(links, size, sizeof(Link *));
}
links[numLinks++] = link;
} else {
delete link;
}
}
obj2.free();
}
obj1.free();
if (!annots)
return;
for (i = 0; i < annots->getNumAnnots(); ++i) {
Annot *annot = annots->getAnnot(i);
if (annot->getType() != Annot::typeLink)
continue;
if (numLinks >= size) {
size += 16;
links = (AnnotLink **)greallocn(links, size, sizeof(AnnotLink *));
}
annot->incRefCnt();
links[numLinks++] = static_cast<AnnotLink *>(annot);
}
}
......@@ -983,7 +894,8 @@ Links::~Links() {
int i;
for (i = 0; i < numLinks; ++i)
delete links[i];
links[i]->decRefCnt();
gfree(links);
}
......
......@@ -37,6 +37,8 @@ class Array;
class Dict;
class Sound;
class MediaRendition;
class AnnotLink;
class Annots;
//------------------------------------------------------------------------
// LinkAction
......@@ -453,41 +455,6 @@ private:
GooString *action; // action subtype
};
//------------------------------------------------------------------------
// Link
//------------------------------------------------------------------------
class Link {
public:
// Construct a link, given its dictionary.
Link(Dict *dict, GooString *baseURI);
// Destructor.
~Link();
// Was the link created successfully?
GBool isOk() { return ok; }
// Check if point is inside the link rectangle.
GBool inRect(double x, double y)
{ return x1 <= x && x <= x2 && y1 <= y && y <= y2; }
// Get action.
LinkAction *getAction() { return action; }
</