[PATCH 1/7] Yet new setters to AnnotFreeText
 poppler/Annot.cc |   45 +++++++++++++++++++++++++++++++++++++++++++++
 poppler/Annot.h  |    2 ++
 2 files changed, 47 insertions(+), 0 deletions(-)


[PATCH 2/7] Basic Annot border editing support
 poppler/Annot.cc |   23 +++++++++++++++++++++++
 poppler/Annot.h  |    9 +++++++++
 2 files changed, 32 insertions(+), 0 deletions(-)


[PATCH 3/7] Fix in AnnotMarkup's popup window handling
 poppler/Annot.cc |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)


[PATCH 4/7] Added XRef::removeIndirectObject
 poppler/PDFDoc.cc |   15 ++++++++++-----
 poppler/XRef.cc   |   15 +++++++++++++++
 poppler/XRef.h    |    2 ++
 3 files changed, 27 insertions(+), 5 deletions(-)


[PATCH 5/7] Added Array::remove (and Object::arrayRemove)
 poppler/Array.cc |   12 ++++++++++++
 poppler/Array.h  |    4 ++++
 poppler/Object.h |    5 +++++
 3 files changed, 21 insertions(+), 0 deletions(-)


[PATCH 6/7] Basic support for Annot appearance stream removal and invalidation
 poppler/Annot.cc |  172 ++++++++++++++++++++++++++++++++++++++----------------
 poppler/Annot.h  |   26 +++++++-
 2 files changed, 145 insertions(+), 53 deletions(-)


[PATCH 7/7] Annotation removal
 poppler/Annot.cc |   16 ++++++++++++++++
 poppler/Annot.h  |    1 +
 poppler/Page.cc  |   35 +++++++++++++++++++++++++++++++++++
 poppler/Page.h   |    2 ++
 4 files changed, 54 insertions(+), 0 deletions(-)

                                          
From 3df6d03bbdf1f98a921983f571b4ffdd010af350 Mon Sep 17 00:00:00 2001
From: Fabio D'Urso <[email protected]>
Date: Fri, 16 Mar 2012 21:47:02 +0100
Subject: [PATCH 1/7] Yet new setters to AnnotFreeText

---
 poppler/Annot.cc |   45 +++++++++++++++++++++++++++++++++++++++++++++
 poppler/Annot.h  |    2 ++
 2 files changed, 47 insertions(+), 0 deletions(-)

diff --git a/poppler/Annot.cc b/poppler/Annot.cc
index f6eacbb..208c43d 100644
--- a/poppler/Annot.cc
+++ b/poppler/Annot.cc
@@ -2346,6 +2346,20 @@ void AnnotFreeText::initialize(PDFDoc *docA, Dict *dict) {
   obj1.free();
 }
 
+void AnnotFreeText::setAppearanceString(GooString *new_string) {
+  delete appearanceString;
+
+  if (new_string) {
+    appearanceString = new GooString(new_string);
+  } else {
+    appearanceString = new GooString();
+  }
+
+  Object obj1;
+  obj1.initString(appearanceString->copy());
+  update ("DA", &obj1);
+}
+
 void AnnotFreeText::setQuadding(AnnotFreeTextQuadding new_quadding) {
   Object obj1;
   quadding = new_quadding;
@@ -2372,6 +2386,37 @@ void AnnotFreeText::setStyleString(GooString *new_string) {
   update ("DS", &obj1);
 }
 
+void AnnotFreeText::setCalloutLine(AnnotCalloutLine *line) {
+  delete calloutLine;
+
+  Object obj1;
+  if (line == NULL) {
+    obj1.initNull();
+    calloutLine = NULL;
+  } else {
+    double x1 = line->getX1(), y1 = line->getY1();
+    double x2 = line->getX2(), y2 = line->getY2();
+    Object obj2;
+    obj1.initArray(xref);
+    obj1.arrayAdd( obj2.initReal(x1) );
+    obj1.arrayAdd( obj2.initReal(y1) );
+    obj1.arrayAdd( obj2.initReal(x2) );
+    obj1.arrayAdd( obj2.initReal(y2) );
+
+    AnnotCalloutMultiLine *mline = dynamic_cast<AnnotCalloutMultiLine*>(line);
+    if (mline) {
+      double x3 = mline->getX3(), y3 = mline->getY3();
+      obj1.arrayAdd( obj2.initReal(x3) );
+      obj1.arrayAdd( obj2.initReal(y3) );
+      calloutLine = new AnnotCalloutMultiLine(x1, y1, x2, y2, x3, y3);
+    } else {
+      calloutLine = new AnnotCalloutLine(x1, y1, x2, y2);
+    }
+  }
+
+  update("CL", &obj1);
+}
+
 void AnnotFreeText::setIntent(AnnotFreeTextIntent new_intent) {
   Object obj1;
 
diff --git a/poppler/Annot.h b/poppler/Annot.h
index 5a2a7bc..611974c 100644
--- a/poppler/Annot.h
+++ b/poppler/Annot.h
@@ -807,8 +807,10 @@ public:
   AnnotFreeText(PDFDoc *docA, Dict *dict, Object *obj);
   ~AnnotFreeText();
 
+  void setAppearanceString(GooString *new_string);
   void setQuadding(AnnotFreeTextQuadding new_quadding);
   void setStyleString(GooString *new_string);
+  void setCalloutLine(AnnotCalloutLine *line);
   void setIntent(AnnotFreeTextIntent new_intent);
 
   // getters
-- 
1.7.6.5

From c48c78e041001295df57c559f9389ca75fdc425a Mon Sep 17 00:00:00 2001
From: Fabio D'Urso <[email protected]>
Date: Mon, 19 Mar 2012 20:56:45 +0100
Subject: [PATCH 2/7] Basic Annot border editing support

---
 poppler/Annot.cc |   23 +++++++++++++++++++++++
 poppler/Annot.h  |    9 +++++++++
 2 files changed, 32 insertions(+), 0 deletions(-)

diff --git a/poppler/Annot.cc b/poppler/Annot.cc
index 208c43d..9b1c710 100644
--- a/poppler/Annot.cc
+++ b/poppler/Annot.cc
@@ -557,6 +557,16 @@ AnnotBorderArray::AnnotBorderArray(Array *array) {
   }
 }
 
+void AnnotBorderArray::writeToObject(XRef *xref, Object *obj1) const {
+  Object obj2;
+
+  obj1->initArray(xref);
+  obj1->arrayAdd(obj2.initReal( horizontalCorner ));
+  obj1->arrayAdd(obj2.initReal( verticalCorner ));
+  obj1->arrayAdd(obj2.initReal( width ));
+  // TODO: Dash array
+}
+
 //------------------------------------------------------------------------
 // AnnotBorderBS
 //------------------------------------------------------------------------
@@ -1169,6 +1179,19 @@ void Annot::setFlags(Guint new_flags) {
   update ("F", &obj1);
 }
 
+void Annot::setBorder(AnnotBorderArray *new_border) {
+  delete border;
+
+  if (new_border) {
+    Object obj1;
+    new_border->writeToObject(xref, &obj1);
+    update ("Border", &obj1);
+    border = new_border;
+  } else {
+    border = NULL;
+  }
+}
+
 void Annot::setColor(AnnotColor *new_color) {
   delete color;
 
diff --git a/poppler/Annot.h b/poppler/Annot.h
index 611974c..8d40a8a 100644
--- a/poppler/Annot.h
+++ b/poppler/Annot.h
@@ -228,6 +228,8 @@ public:
   AnnotBorder();
   virtual ~AnnotBorder();
 
+  virtual void setWidth(double new_width) { width = new_width; }
+
   virtual AnnotBorderType getType() const { return type; }
   virtual double getWidth() const { return width; }
   virtual int getDashLength() const { return dashLength; }
@@ -254,6 +256,11 @@ public:
   AnnotBorderArray();
   AnnotBorderArray(Array *array);
 
+  void writeToObject(XRef *xref, Object *dest) const;
+
+  void setHorizontalCorner(double hc) { horizontalCorner = hc; }
+  void setVerticalCorner(double vc) { verticalCorner = vc; }
+
   double getHorizontalCorner() const { return horizontalCorner; }
   double getVerticalCorner() const { return verticalCorner; }
 
@@ -487,6 +494,8 @@ public:
   void setModified(GooString *new_date);
   void setFlags(Guint new_flags);
 
+  void setBorder(AnnotBorderArray *new_border); // Takes ownership
+
   // The annotation takes the ownership of
   // new_color. 
   void setColor(AnnotColor *new_color);
-- 
1.7.6.5

From 4dbc32a83fa90f5fd097eadf8630137a61722c3f Mon Sep 17 00:00:00 2001
From: Fabio D'Urso <[email protected]>
Date: Mon, 19 Mar 2012 19:17:09 +0100
Subject: [PATCH 3/7] Fix in AnnotMarkup's popup window handling

AnnotPopup's ref was previously set to the *parent* annot, now it's correctly
set to the *popup* annot's own.
---
 poppler/Annot.cc |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/poppler/Annot.cc b/poppler/Annot.cc
index 9b1c710..405f5f6 100644
--- a/poppler/Annot.cc
+++ b/poppler/Annot.cc
@@ -1573,7 +1573,7 @@ AnnotMarkup::~AnnotMarkup() {
 }
 
 void AnnotMarkup::initialize(PDFDoc *docA, Dict *dict, Object *obj) {
-  Object obj1;
+  Object obj1, obj2;
 
   if (dict->lookup("T", &obj1)->isString()) {
     label = obj1.getString()->copy();
@@ -1582,8 +1582,8 @@ void AnnotMarkup::initialize(PDFDoc *docA, Dict *dict, Object *obj) {
   }
   obj1.free();
 
-  if (dict->lookup("Popup", &obj1)->isDict()) {
-    popup = new AnnotPopup(docA, obj1.getDict(), obj);
+  if (dict->lookup("Popup", &obj1)->isDict() && dict->lookupNF("Popup", &obj2)->isRef()) {
+    popup = new AnnotPopup(docA, obj1.getDict(), &obj2);
   } else {
     popup = NULL;
   }
-- 
1.7.6.5

From a8830499ed56fe345112b34bee7cfe29e0b7bd1f Mon Sep 17 00:00:00 2001
From: Fabio D'Urso <[email protected]>
Date: Sun, 18 Mar 2012 23:58:05 +0100
Subject: [PATCH 4/7] Added XRef::removeIndirectObject

---
 poppler/PDFDoc.cc |   15 ++++++++++-----
 poppler/XRef.cc   |   15 +++++++++++++++
 poppler/XRef.h    |    2 ++
 3 files changed, 27 insertions(+), 5 deletions(-)

diff --git a/poppler/PDFDoc.cc b/poppler/PDFDoc.cc
index ecc5980..898bcbb 100644
--- a/poppler/PDFDoc.cc
+++ b/poppler/PDFDoc.cc
@@ -27,6 +27,7 @@
 // Copyright (C) 2010 Srinivas Adicherla <[email protected]>
 // Copyright (C) 2010 Philip Lorenz <[email protected]>
 // Copyright (C) 2011, 2012 Thomas Freitag <[email protected]>
+// Copyright (C) 2012 Fabio D'Urso <[email protected]>
 //
 // To see a description of the changes please see the Changelog file that
 // came with your tarball or type make ChangeLog if you are building from git
@@ -841,14 +842,18 @@ void PDFDoc::saveIncrementalUpdate (OutStream* outStr)
       continue;
 
     if (xref->getEntry(i)->updated) { //we have an updated object
-      Object obj1;
       Ref ref;
       ref.num = i;
       ref.gen = xref->getEntry(i)->type == xrefEntryCompressed ? 0 : xref->getEntry(i)->gen;
-      xref->fetch(ref.num, ref.gen, &obj1);
-      Guint offset = writeObject(&obj1, &ref, outStr);
-      uxref->add(ref.num, ref.gen, offset, gTrue);
-      obj1.free();
+      if (xref->getEntry(i)->type != xrefEntryFree) {
+        Object obj1;
+        xref->fetch(ref.num, ref.gen, &obj1);
+        Guint offset = writeObject(&obj1, &ref, outStr);
+        uxref->add(ref.num, ref.gen, offset, gTrue);
+        obj1.free();
+      } else {
+        uxref->add(ref.num, ref.gen, 0, gFalse);
+      }
     }
   }
   if (uxref->getNumObjects() == 0) { //we have nothing to update
diff --git a/poppler/XRef.cc b/poppler/XRef.cc
index 699eb6b..60c2f9d 100644
--- a/poppler/XRef.cc
+++ b/poppler/XRef.cc
@@ -21,6 +21,7 @@
 // Copyright (C) 2009, 2010 Ilya Gorenbein <[email protected]>
 // Copyright (C) 2010 Hib Eris <[email protected]>
 // Copyright (C) 2012 Thomas Freitag <[email protected]>
+// Copyright (C) 2012 Fabio D'Urso <[email protected]>
 //
 // To see a description of the changes please see the Changelog file that
 // came with your tarball or type make ChangeLog if you are building from git
@@ -1222,6 +1223,20 @@ Ref XRef::addIndirectObject (Object* o) {
   return r;
 }
 
+void XRef::removeIndirectObject(Ref r) {
+  if (r.num < 0 || r.num >= size) {
+    error(errInternal, -1,"XRef::removeIndirectObject on unknown ref: {0:d}, {1:d}\n", r.num, r.gen);
+    return;
+  }
+  XRefEntry *e = getEntry(r.num);
+  if (e->type == xrefEntryFree)
+    return;
+  e->obj.free();
+  e->type = xrefEntryFree;
+  e->gen++;
+  e->updated = true;
+}
+
 void XRef::writeToFile(OutStream* outStr, GBool writeAllEntries) {
   //create free entries linked-list
   if (getEntry(0)->gen != 65535) {
diff --git a/poppler/XRef.h b/poppler/XRef.h
index c7b20bd..ea2c1b4 100644
--- a/poppler/XRef.h
+++ b/poppler/XRef.h
@@ -20,6 +20,7 @@
 // Copyright (C) 2010 Ilya Gorenbein <[email protected]>
 // Copyright (C) 2010 Hib Eris <[email protected]>
 // Copyright (C) 2012 Thomas Freitag <[email protected]>
+// Copyright (C) 2012 Fabio D'Urso <[email protected]>
 //
 // To see a description of the changes please see the Changelog file that
 // came with your tarball or type make ChangeLog if you are building from git
@@ -132,6 +133,7 @@ public:
   // Write access
   void setModifiedObject(Object* o, Ref r);
   Ref addIndirectObject (Object* o);
+  void removeIndirectObject(Ref r);
   void add(int num, int gen,  Guint offs, GBool used);
   void writeToFile(OutStream* outStr, GBool writeAllEntries);
 
-- 
1.7.6.5

From 655815bf49cf4bf1c95ea53c6a21f1c7a812aabd Mon Sep 17 00:00:00 2001
From: Fabio D'Urso <[email protected]>
Date: Mon, 19 Mar 2012 00:05:49 +0100
Subject: [PATCH 5/7] Added Array::remove (and Object::arrayRemove)

---
 poppler/Array.cc |   12 ++++++++++++
 poppler/Array.h  |    4 ++++
 poppler/Object.h |    5 +++++
 3 files changed, 21 insertions(+), 0 deletions(-)

diff --git a/poppler/Array.cc b/poppler/Array.cc
index e7ec4e7..732009c 100644
--- a/poppler/Array.cc
+++ b/poppler/Array.cc
@@ -14,6 +14,7 @@
 // under GPL version 2 or later
 //
 // Copyright (C) 2005 Kristian Høgsberg <[email protected]>
+// Copyright (C) 2012 Fabio D'Urso <[email protected]>
 //
 // To see a description of the changes please see the Changelog file that
 // came with your tarball or type make ChangeLog if you are building from git
@@ -64,6 +65,17 @@ void Array::add(Object *elem) {
   ++length;
 }
 
+void Array::remove(int i) {
+  if (i < 0 || i >= length) {
+#ifdef DEBUG_MEM
+    abort();
+#endif
+  }
+  --length;
+  for (; i < length; ++i) // Shift subsequent elements left
+    elems[i] = elems[i+1];
+}
+
 Object *Array::get(int i, Object *obj) {
   if (i < 0 || i >= length) {
 #ifdef DEBUG_MEM
diff --git a/poppler/Array.h b/poppler/Array.h
index a6aca26..666a409 100644
--- a/poppler/Array.h
+++ b/poppler/Array.h
@@ -14,6 +14,7 @@
 // under GPL version 2 or later
 //
 // Copyright (C) 2005 Kristian Høgsberg <[email protected]>
+// Copyright (C) 2012 Fabio D'Urso <[email protected]>
 //
 // To see a description of the changes please see the Changelog file that
 // came with your tarball or type make ChangeLog if you are building from git
@@ -54,6 +55,9 @@ public:
   // Add an element.
   void add(Object *elem);
 
+  // Remove an element by position
+  void remove(int i);
+
   // Accessors.
   Object *get(int i, Object *obj);
   Object *getNF(int i, Object *obj);
diff --git a/poppler/Object.h b/poppler/Object.h
index a67b403..c885d73 100644
--- a/poppler/Object.h
+++ b/poppler/Object.h
@@ -17,6 +17,7 @@
 // Copyright (C) 2008 Kees Cook <[email protected]>
 // Copyright (C) 2008, 2010 Albert Astals Cid <[email protected]>
 // Copyright (C) 2009 Jakub Wilk <[email protected]>
+// Copyright (C) 2012 Fabio D'Urso <[email protected]>
 //
 // To see a description of the changes please see the Changelog file that
 // came with your tarball or type make ChangeLog if you are building from git
@@ -205,6 +206,7 @@ public:
   // Array accessors.
   int arrayGetLength();
   void arrayAdd(Object *elem);
+  void arrayRemove(int i);
   Object *arrayGet(int i, Object *obj);
   Object *arrayGetNF(int i, Object *obj);
 
@@ -273,6 +275,9 @@ inline int Object::arrayGetLength()
 inline void Object::arrayAdd(Object *elem)
   { OBJECT_TYPE_CHECK(objArray); array->add(elem); }
 
+inline void Object::arrayRemove(int i)
+  { OBJECT_TYPE_CHECK(objArray); array->remove(i); }
+
 inline Object *Object::arrayGet(int i, Object *obj)
   { OBJECT_TYPE_CHECK(objArray); return array->get(i, obj); }
 
-- 
1.7.6.5

From ee615da9fc9fd993198bdb6a4027994a59f05fff Mon Sep 17 00:00:00 2001
From: Fabio D'Urso <[email protected]>
Date: Mon, 19 Mar 2012 19:10:20 +0100
Subject: [PATCH 6/7] Basic support for Annot appearance stream removal and
 invalidation

---
 poppler/Annot.cc |  172 ++++++++++++++++++++++++++++++++++++++----------------
 poppler/Annot.h  |   26 +++++++-
 2 files changed, 145 insertions(+), 53 deletions(-)

diff --git a/poppler/Annot.cc b/poppler/Annot.cc
index 405f5f6..6231354 100644
--- a/poppler/Annot.cc
+++ b/poppler/Annot.cc
@@ -776,6 +776,93 @@ AnnotIconFit::AnnotIconFit(Dict* dict) {
 }
 
 //------------------------------------------------------------------------
+// AnnotAppearance
+//------------------------------------------------------------------------
+
+AnnotAppearance::AnnotAppearance(PDFDoc *docA, Dict *dict) {
+  xref = docA->getXRef();
+  appearDict = new Dict(dict);
+}
+
+void AnnotAppearance::getAppearanceStream(AnnotAppearance::AnnotAppearanceType type, const char *state, Object *dest) {
+  Object apData;
+  // Obtain dictionary or stream associated to appearance type
+  if (type == appearRollover && appearDict->hasKey("R"))
+    appearDict->lookupNF("R", &apData);
+  else if (type == appearDown && appearDict->hasKey("D"))
+    appearDict->lookupNF("D", &apData);
+  else
+    appearDict->lookupNF("N", &apData); // Normal appearance
+
+  // Search state if it's a subdictionary
+  if (apData.isDict() && state) {
+    Object obj1;
+    apData.dictLookupNF(state, &obj1);
+    apData.free();
+    obj1.copy(&apData);
+    obj1.free();
+  }
+
+  if (apData.isRef())
+    apData.copy(dest); // Return reference to stream
+  else
+    dest->initNull();
+
+  apData.free();
+}
+
+GooString * AnnotAppearance::getStateKey(int i) {
+  Object obj1;
+  GooString * res = NULL;
+  appearDict->lookupNF("N", &obj1);
+  if (obj1.isDict())
+    res = new GooString(obj1.dictGetKey(i));
+  obj1.free();
+  return res;
+}
+
+int AnnotAppearance::getNumStates() {
+  Object obj1;
+  int res = 0;
+  appearDict->lookupNF("N", &obj1);
+  if (obj1.isDict())
+    res = obj1.dictGetLength();
+  obj1.free();
+  return res;
+}
+
+// Removes stream if obj is a Ref, or removes pointed streams if obj is a Dict
+void AnnotAppearance::removeStateStreams(Object *obj1) {
+  // TODO: Remove XObject resources, check for XObjects shared by multiple
+  //       annotations, delete streams from name table (if any)
+  if (obj1->isRef()) {
+    xref->removeIndirectObject(obj1->getRef());
+  } else if (obj1->isDict()) {
+    const int size = obj1->dictGetLength();
+    for (int i = 0; i < size; ++i) {
+      Object obj2;
+      obj1->dictGetValNF(i, &obj2);
+      if (obj2.isRef())
+        xref->removeIndirectObject(obj2.getRef());
+      obj2.free();
+    }
+  }
+}
+
+void AnnotAppearance::removeAllStreams() {
+  Object obj1;
+  appearDict->lookupNF("N", &obj1);
+  removeStateStreams(&obj1);
+  obj1.free();
+  appearDict->lookupNF("R", &obj1);
+  removeStateStreams(&obj1);
+  obj1.free();
+  appearDict->lookupNF("D", &obj1);
+  removeStateStreams(&obj1);
+  obj1.free();
+}
+
+//------------------------------------------------------------------------
 // AnnotAppearanceCharacs
 //------------------------------------------------------------------------
 
@@ -912,13 +999,12 @@ Annot::Annot(PDFDoc *docA, Dict *dict, Object *obj) {
 }
 
 void Annot::initialize(PDFDoc *docA, Dict *dict) {
-  Object apObj, asObj, obj1, obj2, obj3;
+  Object apObj, asObj, obj1, obj2;
 
-  appRef.num = 0;
-  appRef.gen = 65535;
   ok = gTrue;
   doc = docA;
   xref = doc->getXRef();
+  appearDict = NULL;
   appearState = NULL;
   appearBuf = NULL;
   fontSize = 0;
@@ -995,22 +1081,23 @@ void Annot::initialize(PDFDoc *docA, Dict *dict) {
   }
   obj1.free();
 
-  //----- get the appearance state
-
+  //----- get the annotation appearance dictionary
   dict->lookup("AP", &apObj);
+  if (apObj.isDict())
+    appearDict = new AnnotAppearance(doc, apObj.getDict());
+  apObj.free();
+
+  //----- get the appearance state
   dict->lookup("AS", &asObj);
   if (asObj.isName()) {
     appearState = new GooString(asObj.getName());
-  } else if (apObj.isDict()) {
-    if (apObj.dictLookup("N", &obj1)->isDict()) {
-      error (errSyntaxError, -1, "Invalid or missing AS value in annotation containing one or more appearance subdictionaries");
-      // AS value is required in this case, but if the
-      // N dictionary contains only one entry
-      // take it as default appearance.
-      if (obj1.dictGetLength() == 1)
-        appearState = new GooString(obj1.dictGetKey(0));
-    }
-    obj1.free();
+  } else if (appearDict && appearDict->getNumStates() != 0) {
+    error (errSyntaxError, -1, "Invalid or missing AS value in annotation containing one or more appearance subdictionaries");
+    // AS value is required in this case, but if the
+    // N dictionary contains only one entry
+    // take it as default appearance.
+    if (appearDict->getNumStates() == 1)
+      appearState = appearDict->getStateKey(0);
   }
   if (!appearState) {
     appearState = new GooString("Off");
@@ -1018,22 +1105,8 @@ void Annot::initialize(PDFDoc *docA, Dict *dict) {
   asObj.free();
 
   //----- get the annotation appearance
-
-  if (apObj.isDict()) {
-    apObj.dictLookup("N", &obj1);
-    apObj.dictLookupNF("N", &obj2);
-    if (obj1.isDict()) {
-      if (obj1.dictLookupNF(appearState->getCString(), &obj3)->isRef()) {
-	obj3.copy(&appearance);
-      }
-      obj3.free();
-    } else if (obj2.isRef()) {
-      obj2.copy(&appearance);
-    }
-    obj1.free();
-    obj2.free();
-  }
-  apObj.free();
+  if (appearDict)
+    appearDict->getAppearanceStream(AnnotAppearance::appearNormal, appearState->getCString(), &appearance);
 
   //----- parse the border style
   if (dict->lookup("BS", &obj1)->isDict()) {
@@ -1218,9 +1291,6 @@ void Annot::setAppearanceState(const char *state) {
   if (!state)
     return;
 
-  if (appearState && appearState->cmp(state) == 0)
-    return;
-
   delete appearState;
   appearState = new GooString(state);
 
@@ -1229,23 +1299,23 @@ void Annot::setAppearanceState(const char *state) {
   update ("AS", &obj1);
 
   // The appearance state determines the current appearance stream
-  Object obj2;
-  if (annotObj.dictLookup("AP", &obj2)->isDict()) {
-    Object obj3;
-
-    if (obj2.dictLookup("N", &obj3)->isDict()) {
-      Object obj4;
+  appearance.free();
+  if (appearDict)
+    appearDict->getAppearanceStream(AnnotAppearance::appearNormal, appearState->getCString(), &appearance);
+  else
+    appearance.initNull();
+}
 
-      appearance.free();
-      if (obj3.dictLookupNF(state, &obj4)->isRef())
-        obj4.copy(&appearance);
-      else
-        appearance.initNull();
-      obj4.free();
-    }
-    obj3.free();
-  }
-  obj2.free();
+void Annot::invalidateAppearance() {
+  if (appearDict)
+    appearDict->removeAllStreams(); // Remove streams
+  delete appearDict;
+  appearDict = NULL;
+  Object obj1;
+  obj1.initNull();
+  update ("AP", &obj1); // Removes AP
+  update ("AS", &obj1); // Removes AS
+  setAppearanceState("Off"); // Default value
 }
 
 double Annot::getXMin() {
@@ -1292,6 +1362,8 @@ Annot::~Annot() {
   if (modified)
     delete modified;
 
+  delete appearDict;
+
   appearance.free();
 
   if (appearState)
diff --git a/poppler/Annot.h b/poppler/Annot.h
index 8d40a8a..9e2754a 100644
--- a/poppler/Annot.h
+++ b/poppler/Annot.h
@@ -368,7 +368,25 @@ public:
     appearDown
   };
 
-  AnnotAppearance(Dict *dict);
+  AnnotAppearance(PDFDoc *docA, Dict *dict);
+
+  // State is ignored if no subdictionary is present
+  void getAppearanceStream(AnnotAppearanceType type, const char *state, Object *dest);
+
+  // Access keys in normal appearance subdictionary (N)
+  GooString * getStateKey(int i);
+  int getNumStates();
+
+  // Removes all associated streams in the xref table. Caller is required to
+  // reset parent annotation's AP and AS after this call.
+  void removeAllStreams();
+
+private:
+  void removeStateStreams(Object *state);
+
+protected:
+  XRef *xref;                   // the xref table for this PDF file
+  Dict *appearDict;             // Annotation's AP
 };
 
 //------------------------------------------------------------------------
@@ -504,6 +522,9 @@ public:
 
   void setAppearanceState(const char *state);
 
+  // Delete appearance stream and reset appearance state
+  void invalidateAppearance();
+
   // getters
   PDFDoc *getDoc() const { return doc; }
   XRef *getXRef() const { return xref; }
@@ -564,8 +585,7 @@ protected:
   GooString *name;                  // NM
   GooString *modified;              // M
   Guint flags;                      // F (must be a 32 bit unsigned int)
-  //Dict *appearDict;                 // AP (should be correctly parsed)
-  Ref appRef;                       //the reference to the indirect appearance object in XRef 
+  AnnotAppearance *appearDict;      // AP
   Object appearance;     // a reference to the Form XObject stream
                          //   for the normal appearance
   GooString *appearState;           // AS
-- 
1.7.6.5

From f5f5b1fd9e6c39ce68aebfec5b4e6c0a5eafa354 Mon Sep 17 00:00:00 2001
From: Fabio D'Urso <[email protected]>
Date: Tue, 20 Mar 2012 00:56:50 +0100
Subject: [PATCH 7/7] Annotation removal

---
 poppler/Annot.cc |   16 ++++++++++++++++
 poppler/Annot.h  |    1 +
 poppler/Page.cc  |   35 +++++++++++++++++++++++++++++++++++
 poppler/Page.h   |    2 ++
 4 files changed, 54 insertions(+), 0 deletions(-)

diff --git a/poppler/Annot.cc b/poppler/Annot.cc
index 6231354..594aae6 100644
--- a/poppler/Annot.cc
+++ b/poppler/Annot.cc
@@ -5702,6 +5702,22 @@ void Annots::appendAnnot(Annot *annot) {
   }
 }
 
+GBool Annots::removeAnnot(Annot *annot) {
+  int idx = -1;
+  // Search annot and remove it by swapping with last element
+  for (int i = 0; idx == -1 && i < nAnnots; i++) {
+    if (annots[i] == annot)
+      idx = i;
+  }
+  if (idx == -1) {
+    return gFalse;
+  } else {
+    annots[idx] = annots[--nAnnots];
+    annot->decRefCnt();
+    return gTrue;
+  }
+}
+
 Annot *Annots::createAnnot(Dict* dict, Object *obj) {
   Annot *annot = NULL;
   Object obj1;
diff --git a/poppler/Annot.h b/poppler/Annot.h
index 9e2754a..534c00e 100644
--- a/poppler/Annot.h
+++ b/poppler/Annot.h
@@ -1329,6 +1329,7 @@ public:
   int getNumAnnots() { return nAnnots; }
   Annot *getAnnot(int i) { return annots[i]; }
   void appendAnnot(Annot *annot);
+  GBool removeAnnot(Annot *annot);
 
 private:
   Annot* createAnnot(Dict* dict, Object *obj);
diff --git a/poppler/Page.cc b/poppler/Page.cc
index 48ed647..570101a 100644
--- a/poppler/Page.cc
+++ b/poppler/Page.cc
@@ -394,6 +394,41 @@ void Page::addAnnot(Annot *annot) {
   annot->setPage(&pageRef, num);
 }
 
+// Note: Caller is responsible for deleting popup and appearance streams too
+void Page::removeAnnot(Annot *annot) {
+  Ref annotRef = annot->getRef();
+  Object annArray;
+  getAnnots(&annArray);
+
+  if (annArray.isArray()) {
+    int idx = -1;
+    // Get annotation position
+    for (int i = 0; idx == -1 && i < annArray.arrayGetLength(); ++i) {
+      Object tmp;
+      Ref currAnnot = annArray.arrayGetNF(i, &tmp)->getRef();
+      tmp.free();
+      if (currAnnot.num == annotRef.num && currAnnot.gen == annotRef.gen)
+        idx = i;
+    }
+
+    if (idx == -1) {
+      error(errInternal, -1, "Annotation doesn't belong to this page");
+      annArray.free();
+      return;
+    }
+    annots->removeAnnot(annot); // Gracefully fails on popup windows
+    annArray.arrayRemove(idx);
+    xref->removeIndirectObject(annotRef);
+
+    if (annotsObj.isRef())
+      xref->setModifiedObject (&annArray, annotsObj.getRef());
+    else
+      xref->setModifiedObject (&pageObj, pageRef);
+  }
+
+  annArray.free();
+}
+
 Links *Page::getLinks() {
   return new Links(getAnnots());
 }
diff --git a/poppler/Page.h b/poppler/Page.h
index 70141d0..e22353b 100644
--- a/poppler/Page.h
+++ b/poppler/Page.h
@@ -171,6 +171,8 @@ public:
   Object *getAnnots(Object *obj) { return annotsObj.fetch(xref, obj); }
   // Add a new annotation to the page
   void addAnnot(Annot *annot);
+  // Remove an existing annotation from the page
+  void removeAnnot(Annot *annot);
 
   // Return a list of links.
   Links *getLinks();
-- 
1.7.6.5

_______________________________________________
poppler mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/poppler

Reply via email to