[poppler] 7 commits - poppler/Annot.cc poppler/Annot.h poppler/Form.cc poppler/Link.cc poppler/SignatureInfo.cc poppler/SignatureInfo.h qt5/src qt5/tests

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Sun Sep 2 10:59:19 UTC 2018


 poppler/Annot.cc                    |  159 ++++++++++++++++++++++--------------
 poppler/Annot.h                     |   38 +++++++-
 poppler/Form.cc                     |    6 -
 poppler/Link.cc                     |    3 
 poppler/SignatureInfo.cc            |    8 -
 poppler/SignatureInfo.h             |    4 
 qt5/src/poppler-annotation-helper.h |    3 
 qt5/src/poppler-annotation.cc       |  122 ++++++++++++++++++---------
 qt5/src/poppler-annotation.h        |    5 +
 qt5/tests/CMakeLists.txt            |    1 
 qt5/tests/check_annotations.cpp     |  105 +++++++++++++++++++++++
 11 files changed, 341 insertions(+), 113 deletions(-)

New commits:
commit 042d2483c04652036ab921983b4967851f3bb8cf
Author: Albert Astals Cid <aacid at kde.org>
Date:   Sun Sep 2 12:39:09 2018 +0200

    Add missing (C)
    
    And minor style change by Albert

diff --git a/poppler/Annot.cc b/poppler/Annot.cc
index 9a481ae6..1ea14b43 100644
--- a/poppler/Annot.cc
+++ b/poppler/Annot.cc
@@ -39,6 +39,8 @@
 // Copyright (C) 2018 Klarälvdalens Datakonsult AB, a KDAB Group company, <info at kdab.com>. Work sponsored by the LiMux project of the city of Munich
 // Copyright 2018 Andre Heinecke <aheinecke at intevation.de>
 // Copyright (C) 2018 Adam Reichold <adam.reichold at t-online.de>
+// Copyright (C) 2018 Dileep Sankhla <sankhla.dileep96 at gmail.com>
+// Copyright (C) 2018 Tobias Deiminger <haxtibal at posteo.de>
 //
 // 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
@@ -796,8 +798,8 @@ Object AnnotColor::writeToObject(XRef *xref) const {
 // DefaultAppearance
 //------------------------------------------------------------------------
 
-DefaultAppearance::DefaultAppearance(Object &&fontName, double fontPtSize, std::unique_ptr<AnnotColor> fontColor) :
-    fontName(std::move(fontName)), fontPtSize(fontPtSize), fontColor(std::move(fontColor)) {
+DefaultAppearance::DefaultAppearance(Object &&fontNameA, double fontPtSizeA, std::unique_ptr<AnnotColor> fontColorA) :
+    fontName(std::move(fontNameA)), fontPtSize(fontPtSizeA), fontColor(std::move(fontColorA)) {
 }
 
 DefaultAppearance::DefaultAppearance(GooString *da) {
diff --git a/poppler/Annot.h b/poppler/Annot.h
index 2e73e607..d564c413 100644
--- a/poppler/Annot.h
+++ b/poppler/Annot.h
@@ -27,6 +27,8 @@
 // Copyright (C) 2013 Thomas Freitag <Thomas.Freitag at alfa.de>
 // Copyright (C) 2013, 2017 Adrian Johnson <ajohnson at redneon.com>
 // Copyright (C) 2018 Klarälvdalens Datakonsult AB, a KDAB Group company, <info at kdab.com>. Work sponsored by the LiMux project of the city of Munich
+// Copyright (C) 2018 Dileep Sankhla <sankhla.dileep96 at gmail.com>
+// Copyright (C) 2018 Tobias Deiminger <haxtibal at posteo.de>
 //
 // 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
@@ -355,7 +357,7 @@ private:
 class DefaultAppearance {
 public:
 
-  DefaultAppearance(Object &&fontName, double fontPtSize, std::unique_ptr<AnnotColor> fontColor);
+  DefaultAppearance(Object &&fontNameA, double fontPtSizeA, std::unique_ptr<AnnotColor> fontColorA);
   DefaultAppearance(GooString *da);
   void setFontName(Object &&fontNameA);
   const Object &getFontName() const { return fontName; }
@@ -365,7 +367,7 @@ public:
   const AnnotColor *getFontColor() const { return fontColor.get(); }
   GooString *toAppearanceString() const;
 
-  DefaultAppearance(DefaultAppearance &) = delete;
+  DefaultAppearance(const DefaultAppearance &) = delete;
   DefaultAppearance& operator=(const DefaultAppearance&) = delete;
 
 private:
diff --git a/qt5/src/poppler-annotation-helper.h b/qt5/src/poppler-annotation-helper.h
index 669b98ee..1c8ab8c9 100644
--- a/qt5/src/poppler-annotation-helper.h
+++ b/qt5/src/poppler-annotation-helper.h
@@ -2,6 +2,7 @@
  * Copyright (C) 2006, 2008, 2017, Albert Astals Cid <aacid at kde.org>
  * Copyright (C) 2008, Pino Toscano <pino at kde.org>
  * Copyright (C) 2012, Fabio D'Urso <fabiodurso at hotmail.it>
+ * Copyright (C) 2018, Dileep Sankhla <sankhla.dileep96 at gmail.com>
  * Adapting code from
  *   Copyright (C) 2004 by Enrico Ros <eros.kde at email.it>
  *
diff --git a/qt5/src/poppler-annotation.cc b/qt5/src/poppler-annotation.cc
index ba8f15db..a2a20fa1 100644
--- a/qt5/src/poppler-annotation.cc
+++ b/qt5/src/poppler-annotation.cc
@@ -7,6 +7,8 @@
  * Copyright (C) 2018 Adam Reichold <adam.reichold at t-online.de>
  * Copyright (C) 2018 Klarälvdalens Datakonsult AB, a KDAB Group company, <info at kdab.com>. Work sponsored by the LiMux project of the city of Munich
  * Copyright (C) 2018 Intevation GmbH <intevation at intevation.de>
+ * Copyright (C) 2018 Dileep Sankhla <sankhla.dileep96 at gmail.com>
+ * Copyright (C) 2018 Tobias Deiminger <haxtibal at posteo.de>
  * Adapting code from
  *   Copyright (C) 2004 by Enrico Ros <eros.kde at email.it>
  *
diff --git a/qt5/src/poppler-annotation.h b/qt5/src/poppler-annotation.h
index 477629ef..dee0874b 100644
--- a/qt5/src/poppler-annotation.h
+++ b/qt5/src/poppler-annotation.h
@@ -7,6 +7,7 @@
  * Copyright (C) 2012, Guillermo A. Amaral B. <gamaral at kde.org>
  * Copyright (C) 2012, 2013 Fabio D'Urso <fabiodurso at hotmail.it>
  * Copyright (C) 2013, Anthony Granger <grangeranthony at gmail.com>
+ * Copyright (C) 2018, Dileep Sankhla <sankhla.dileep96 at gmail.com>
  * Adapting code from
  *   Copyright (C) 2004 by Enrico Ros <eros.kde at email.it>
  *
commit d4b4be23c8b55a118f7b9194a93a8e9da38793c1
Author: Tobias Deiminger <haxtibal at posteo.de>
Date:   Sat Aug 25 23:08:39 2018 +0200

    More review fixes
    
    Text color is indicated by nonstroking color in graphics state
            Assumption: Text rendering mode is 'fill'.
    
    Increase color precision for lossless roundtrip of 16 bit integers
            Our API takes QColor from user. We want to support a lossless roundtrip
            of QColor (16 bit per channel internally) through document save and
            load, and empirically found .5f is best match.
    
    Check only .5f case of color channel roundtrip. Include 65535.
            We check if precision == 5 is sufficient, and fail if not. We know that
            precision < 5 will never work, because target set contains less numbers
            than uint16 range.
    
    Use smart pointer in textFont and textColor
    
    Add test for CMYK QColor roundtrip
    
    Support QColor::Cmyk to AnnotColor::colorCMYK conversion
    
    Add simple test for font size. Fix actual/expected args.
    
    Model font name as class Object, type objName
            Take into account that ISO 32000 says Tf operand is always an object of
            PDF type "name". Further benefit: class Object introduces ownership
            semantcis.
    
    Use more std::unique_ptr and fix some coding syle
            Some places assumed ownership implicitely. Make it more explicit.
    
    Move parse/constructAppearanceString into DefaultAppearance
            We gain cohesion and automatic memory management.
    
    Fix minor styling issues
    
    Use std::make_unique from C++14

diff --git a/poppler/Annot.cc b/poppler/Annot.cc
index e8c9f95a..9a481ae6 100644
--- a/poppler/Annot.cc
+++ b/poppler/Annot.cc
@@ -796,17 +796,69 @@ Object AnnotColor::writeToObject(XRef *xref) const {
 // DefaultAppearance
 //------------------------------------------------------------------------
 
-DefaultAppearance::DefaultAppearance(const GooString &fontTag, int fontPtSize, AnnotColor *fontColor)
- : fontPtSize(fontPtSize), fontColor(fontColor) {
-  DefaultAppearance::fontTag = fontTag.copy();
+DefaultAppearance::DefaultAppearance(Object &&fontName, double fontPtSize, std::unique_ptr<AnnotColor> fontColor) :
+    fontName(std::move(fontName)), fontPtSize(fontPtSize), fontColor(std::move(fontColor)) {
 }
 
-DefaultAppearance::~DefaultAppearance() {
-  delete fontTag;
+DefaultAppearance::DefaultAppearance(GooString *da) {
+  fontPtSize = -1;
+
+  if (da) {
+    GooList * daToks = new GooList();
+    int i = FormFieldText::tokenizeDA(da, daToks, "Tf");
+
+    if (i >= 1) {
+      fontPtSize = gatof(( (GooString *)daToks->get(i-1) )->getCString());
+    }
+    if (i >= 2) {
+      // We are expecting a name, therefore the first letter should be '/'.
+      if (((const char*)daToks->get(i-2)) && ((const char*)daToks->get(i-2))[0] == '/') {
+        // The +1 is here to skip the leading '/'.
+        fontName = Object(objName, ((const char*)daToks->get(i-2))+1);
+      }
+    }
+    // Scan backwards: we are looking for the last set value
+    for (i = daToks->getLength()-1; i >= 0; --i) {
+      if (!fontColor) {
+        if (!((GooString *)daToks->get(i))->cmp("g") && i >= 1) {
+          fontColor = std::make_unique<AnnotColor>(gatof(( (GooString *)daToks->get(i-1) )->getCString()));
+        } else if (!((GooString *)daToks->get(i))->cmp("rg") && i >= 3) {
+          fontColor = std::make_unique<AnnotColor>(gatof(( (GooString *)daToks->get(i-3) )->getCString()),
+                                                   gatof(( (GooString *)daToks->get(i-2) )->getCString()),
+                                                   gatof(( (GooString *)daToks->get(i-1) )->getCString()));
+        } else if (!((GooString *)daToks->get(i))->cmp("k") && i >= 4) {
+          fontColor = std::make_unique<AnnotColor>(gatof(( (GooString *)daToks->get(i-4) )->getCString()),
+                                                   gatof(( (GooString *)daToks->get(i-3) )->getCString()),
+                                                   gatof(( (GooString *)daToks->get(i-2) )->getCString()),
+                                                   gatof(( (GooString *)daToks->get(i-1) )->getCString()));
+        }
+      }
+    }
+    deleteGooList(daToks, GooString);
+  }
+}
+
+void DefaultAppearance::setFontName(Object &&fontNameA) {
+  fontName = std::move(fontNameA);
+}
+
+void DefaultAppearance::setFontPtSize(double fontPtSizeA) {
+  fontPtSize = fontPtSizeA;
+}
+
+void DefaultAppearance::setFontColor(std::unique_ptr<AnnotColor> fontColorA) {
+  fontColor = std::move(fontColorA);
+}
+
+GooString *DefaultAppearance::toAppearanceString() const {
+  AnnotAppearanceBuilder appearBuilder;
   if (fontColor) {
-    delete fontColor;
+    appearBuilder.setDrawColor(fontColor.get(), gTrue);
   }
+  appearBuilder.setTextFont(fontName, fontPtSize);
+  return appearBuilder.buffer()->copy();
 }
+
 //------------------------------------------------------------------------
 // AnnotIconFit
 //------------------------------------------------------------------------
@@ -1632,17 +1684,17 @@ void AnnotAppearanceBuilder::setDrawColor(const AnnotColor *drawColor, GBool fil
 
   switch (drawColor->getSpace()) {
   case AnnotColor::colorCMYK:
-    appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:c}\n",
+    appearBuf->appendf("{0:.5f} {1:.5f} {2:.5f} {3:.5f} {4:c}\n",
 		       values[0], values[1], values[2], values[3],
 		       fill ? 'k' : 'K');
     break;
   case AnnotColor::colorRGB:
-    appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:s}\n",
+    appearBuf->appendf("{0:.5f} {1:.5f} {2:.5f} {3:s}\n",
 		       values[0], values[1], values[2],
 		       fill ? "rg" : "RG");
     break;
   case AnnotColor::colorGray:
-    appearBuf->appendf("{0:.2f} {1:c}\n",
+    appearBuf->appendf("{0:.5f} {1:c}\n",
 		       values[0],
 		       fill ? 'g' : 'G');
     break;
@@ -1652,9 +1704,9 @@ void AnnotAppearanceBuilder::setDrawColor(const AnnotColor *drawColor, GBool fil
   }
 }
 
-void AnnotAppearanceBuilder::setTextFont(const GooString &fontTag, double fontSize) {
-  if (fontTag.getLength() > 0)
-    appearBuf->appendf("/{0:s} {1:.2f} Tf", &fontTag, fontSize);
+void AnnotAppearanceBuilder::setTextFont(const Object &fontName, double fontSize) {
+  if (fontName.isName() && strlen(fontName.getName()) > 0)
+    appearBuf->appendf("/{0:s} {1:.2f} Tf", fontName.getName(), fontSize);
 }
 
 void AnnotAppearanceBuilder::setLineStyleForBorder(const AnnotBorder *border) {
@@ -2618,7 +2670,7 @@ AnnotFreeText::AnnotFreeText(PDFDoc *docA, PDFRectangle *rect, const DefaultAppe
     AnnotMarkup(docA, rect) {
   type = typeFreeText;
 
-  GooString *daStr = constructAppearanceString(da.getFontTag(), da.getFontPtSize(), da.getFontColor());
+  GooString *daStr = da.toAppearanceString();
   annotObj.dictSet ("Subtype", Object(objName, "FreeText"));
   annotObj.dictSet("DA", Object(daStr));
 
@@ -2751,7 +2803,7 @@ void AnnotFreeText::setContents(GooString *new_content) {
 void AnnotFreeText::setDefaultAppearance(const DefaultAppearance &da) {
   delete appearanceString;
 
-  appearanceString = constructAppearanceString(da.getFontTag(), da.getFontPtSize(), da.getFontColor());
+  appearanceString = da.toAppearanceString();
 
   update ("DA", Object(appearanceString->copy()));
   invalidateAppearance();
@@ -2823,14 +2875,8 @@ void AnnotFreeText::setIntent(AnnotFreeTextIntent new_intent) {
   update ("IT", Object(objName, intentName));
 }
 
-DefaultAppearance *AnnotFreeText::getDefaultAppearance() const {
-  double fontSize;
-  AnnotColor *fontColor;
-  GooString *fontTag;
-  parseAppearanceString(appearanceString, fontSize, fontColor, &fontTag);
-  DefaultAppearance *da = new DefaultAppearance(*fontTag, fontSize, fontColor);
-  delete fontTag;
-  return da;
+std::unique_ptr<DefaultAppearance> AnnotFreeText::getDefaultAppearance() const {
+  return std::make_unique<DefaultAppearance>(appearanceString);
 }
 
 static GfxFont *createAnnotDrawFont(XRef * xref, Dict *fontResDict)
@@ -2850,51 +2896,6 @@ static GfxFont *createAnnotDrawFont(XRef * xref, Dict *fontResDict)
   return GfxFont::makeFont(xref, "AnnotDrawFont", dummyRef, fontDict);
 }
 
-GooString *AnnotFreeText::constructAppearanceString(const GooString &fontTag, double fontSize, const AnnotColor *fontColor) {
-  AnnotAppearanceBuilder appearBuilder;
-  if (fontColor) {
-    appearBuilder.setDrawColor(fontColor, gFalse);
-  }
-  appearBuilder.setTextFont(fontTag, fontSize);
-  return appearBuilder.buffer()->copy();
-}
-
-void AnnotFreeText::parseAppearanceString(GooString *da, double &fontsize, AnnotColor* &fontcolor, GooString **fontTag) {
-  fontsize = -1;
-  fontcolor = nullptr;
-  if (fontTag)
-    *fontTag = nullptr;
-  if (da) {
-    GooList * daToks = new GooList();
-    int i = FormFieldText::tokenizeDA(da, daToks, "Tf");
-
-    if (i >= 1) {
-      fontsize = gatof(( (GooString *)daToks->get(i-1) )->getCString());
-    }
-    if (fontTag && i >= 2) {
-      *fontTag = new GooString(( (GooString *)daToks->get(i-2) )->getCString());
-    }
-    // Scan backwards: we are looking for the last set value
-    for (i = daToks->getLength()-1; i >= 0; --i) {
-      if (fontcolor == nullptr) {
-        if (!((GooString *)daToks->get(i))->cmp("g") && i >= 1) {
-          fontcolor = new AnnotColor(gatof(( (GooString *)daToks->get(i-1) )->getCString()));
-        } else if (!((GooString *)daToks->get(i))->cmp("rg") && i >= 3) {
-          fontcolor = new AnnotColor(gatof(( (GooString *)daToks->get(i-3) )->getCString()),
-                                     gatof(( (GooString *)daToks->get(i-2) )->getCString()),
-                                     gatof(( (GooString *)daToks->get(i-1) )->getCString()));
-        } else if (!((GooString *)daToks->get(i))->cmp("k") && i >= 4) {
-          fontcolor = new AnnotColor(gatof(( (GooString *)daToks->get(i-4) )->getCString()),
-                                     gatof(( (GooString *)daToks->get(i-3) )->getCString()),
-                                     gatof(( (GooString *)daToks->get(i-2) )->getCString()),
-                                     gatof(( (GooString *)daToks->get(i-1) )->getCString()));
-        }
-      }
-    }
-    deleteGooList(daToks, GooString);
-  }
-}
-
 void AnnotFreeText::generateFreeTextAppearance()
 {
   double borderWidth, ca = opacity;
@@ -2911,14 +2912,13 @@ void AnnotFreeText::generateFreeTextAppearance()
   const double height = rect->y2 - rect->y1;
 
   // Parse some properties from the appearance string
-  double fontsize;
-  AnnotColor *fontcolor;
-  parseAppearanceString(appearanceString, fontsize, fontcolor, nullptr);
+  DefaultAppearance da{appearanceString};
+
   // Default values
-  if (fontsize <= 0)
-    fontsize = 10;
-  if (fontcolor == nullptr)
-    fontcolor = new AnnotColor(0, 0, 0); // Black
+  if (da.getFontPtSize() <= 0)
+    da.setFontPtSize(10);
+  if (!da.getFontColor())
+    da.setFontColor(std::make_unique<AnnotColor>(0, 0, 0));
   if (!contents)
     contents = new GooString ();
 
@@ -2927,7 +2927,7 @@ void AnnotFreeText::generateFreeTextAppearance()
   GBool doStroke = (borderWidth != 0);
   if (doFill || doStroke) {
     if (doStroke) {
-      appearBuilder.setDrawColor(fontcolor, gFalse); // Border color: same as font color
+      appearBuilder.setDrawColor(da.getFontColor(), gFalse); // Border color: same as font color
     }
     appearBuilder.appendf ("{0:.2f} {0:.2f} {1:.2f} {2:.2f} re\n", borderWidth/2, width-borderWidth, height-borderWidth);
     if (doFill) {
@@ -2947,17 +2947,17 @@ void AnnotFreeText::generateFreeTextAppearance()
   GfxFont *font = createAnnotDrawFont(xref, fontResDict);
 
   // Set font state
-  appearBuilder.setDrawColor(fontcolor, gTrue);
-  appearBuilder.appendf ("BT 1 0 0 1 {0:.2f} {1:.2f} Tm\n", textmargin, height - textmargin - fontsize * font->getDescent());
-  appearBuilder.appendf ("/AnnotDrawFont {0:.2f} Tf\n", fontsize);
+  appearBuilder.setDrawColor(da.getFontColor(), gTrue);
+  appearBuilder.appendf ("BT 1 0 0 1 {0:.2f} {1:.2f} Tm\n", textmargin, height - textmargin - da.getFontPtSize() * font->getDescent());
+  appearBuilder.appendf ("/AnnotDrawFont {0:.2f} Tf\n", da.getFontPtSize());
 
   int i = 0;
   double xposPrev = 0;
   while (i < contents->getLength()) {
     GooString out;
     double linewidth, xpos;
-    layoutText(contents, &out, &i, font, &linewidth, textwidth/fontsize, nullptr, gFalse);
-    linewidth *= fontsize;
+    layoutText(contents, &out, &i, font, &linewidth, textwidth/da.getFontPtSize(), nullptr, gFalse);
+    linewidth *= da.getFontPtSize();
     switch (quadding) {
     case quaddingCentered:
       xpos = (textwidth - linewidth) / 2;
@@ -2969,14 +2969,13 @@ void AnnotFreeText::generateFreeTextAppearance()
       xpos = 0;
       break;
     }
-    appearBuilder.appendf("{0:.2f} {1:.2f} Td\n", xpos - xposPrev, -fontsize);
+    appearBuilder.appendf("{0:.2f} {1:.2f} Td\n", xpos - xposPrev, -da.getFontPtSize());
     appearBuilder.writeString(out);
     appearBuilder.append("Tj\n");
     xposPrev = xpos;
   }
 
   font->decRefCnt();
-  delete fontcolor;
   appearBuilder.append ("ET Q\n");
 
   double bbox[4];
diff --git a/poppler/Annot.h b/poppler/Annot.h
index af35d226..2e73e607 100644
--- a/poppler/Annot.h
+++ b/poppler/Annot.h
@@ -40,6 +40,7 @@
 #pragma interface
 #endif
 
+#include <memory>
 #include "Object.h"
 
 class XRef;
@@ -354,18 +355,24 @@ private:
 class DefaultAppearance {
 public:
 
-  DefaultAppearance(const GooString &fontTag, int fontPtSize, AnnotColor *fontColor = nullptr);
-  const GooString &getFontTag() const { return *fontTag; }
-  int getFontPtSize() const { return fontPtSize; }
-  const AnnotColor *getFontColor() const { return fontColor; }
-  ~DefaultAppearance();
+  DefaultAppearance(Object &&fontName, double fontPtSize, std::unique_ptr<AnnotColor> fontColor);
+  DefaultAppearance(GooString *da);
+  void setFontName(Object &&fontNameA);
+  const Object &getFontName() const { return fontName; }
+  void setFontPtSize(double fontPtSizeA);
+  double getFontPtSize() const { return fontPtSize; }
+  void setFontColor(std::unique_ptr<AnnotColor> fontColorA);
+  const AnnotColor *getFontColor() const { return fontColor.get(); }
+  GooString *toAppearanceString() const;
+
   DefaultAppearance(DefaultAppearance &) = delete;
   DefaultAppearance& operator=(const DefaultAppearance&) = delete;
+
 private:
 
-  GooString *fontTag;
-  int fontPtSize;
-  AnnotColor *fontColor;
+  Object fontName;
+  double fontPtSize;
+  std::unique_ptr<AnnotColor> fontColor;
 };
 
 //------------------------------------------------------------------------
@@ -532,7 +539,7 @@ public:
 
   void setDrawColor(const AnnotColor *color, GBool fill);
   void setLineStyleForBorder(const AnnotBorder *border);
-  void setTextFont(const GooString &fontTag, double fontSize);
+  void setTextFont(const Object &fontName, double fontSize);
   void drawCircle(double cx, double cy, double r, GBool fill);
   void drawCircleTopLeft(double cx, double cy, double r);
   void drawCircleBottomRight(double cx, double cy, double r);
@@ -1006,7 +1013,7 @@ public:
   void setIntent(AnnotFreeTextIntent new_intent);
 
   // getters
-  DefaultAppearance *getDefaultAppearance() const;
+  std::unique_ptr<DefaultAppearance> getDefaultAppearance() const;
   AnnotFreeTextQuadding getQuadding() const { return quadding; }
   // return rc
   const GooString *getStyleString() const { return styleString; }
@@ -1019,8 +1026,6 @@ public:
 protected:
 
   void initialize(PDFDoc *docA, Dict *dict);
-  static GooString *constructAppearanceString(const GooString &fontTag, double fontSize, const AnnotColor *fontColor);
-  static void parseAppearanceString(GooString *da, double &fontSize, AnnotColor* &fontColor, GooString **fontTag);
   void generateFreeTextAppearance();
 
   // required
diff --git a/qt5/src/poppler-annotation.cc b/qt5/src/poppler-annotation.cc
index 46dcc93c..ba8f15db 100644
--- a/qt5/src/poppler-annotation.cc
+++ b/qt5/src/poppler-annotation.cc
@@ -1817,7 +1817,7 @@ class TextAnnotationPrivate : public AnnotationPrivate
         Annotation * makeAlias() override;
         Annot* createNativeAnnot(::Page *destPage, DocumentData *doc) override;
         void setDefaultAppearanceToNative();
-        DefaultAppearance *getDefaultAppearanceFromNative() const;
+        std::unique_ptr<DefaultAppearance> getDefaultAppearanceFromNative() const;
 
         // data fields
         TextAnnotation::TextType textType;
@@ -1852,11 +1852,14 @@ Annot* TextAnnotationPrivate::createNativeAnnot(::Page *destPage, DocumentData *
 
     // Set pdfAnnot
     PDFRectangle rect = boundaryToPdfRectangle(boundary, flags);
-    if (textType == TextAnnotation::Linked) {
-      pdfAnnot = new AnnotText(destPage->getDoc(), &rect);
-    } else {
-      DefaultAppearance da(GooString("Invalid_font"), textFont.pointSize(), convertQColor(textColor));
-      pdfAnnot = new AnnotFreeText(destPage->getDoc(), &rect, da);
+    if (textType == TextAnnotation::Linked)
+    {
+        pdfAnnot = new AnnotText{ destPage->getDoc(), &rect };
+    }
+    else
+    {
+        DefaultAppearance da{ { objName, "Invalid_font" }, static_cast<double>( textFont.pointSize() ), std::unique_ptr<AnnotColor>{ convertQColor( textColor ) } };
+        pdfAnnot = new AnnotFreeText{ destPage->getDoc(), &rect, da };
     }
 
     // Set properties
@@ -1875,21 +1878,24 @@ Annot* TextAnnotationPrivate::createNativeAnnot(::Page *destPage, DocumentData *
 
 void TextAnnotationPrivate::setDefaultAppearanceToNative()
 {
-    if (pdfAnnot && pdfAnnot->getType() == Annot::typeFreeText) {
-        AnnotFreeText * ftextann = static_cast<AnnotFreeText*>(pdfAnnot);
-        AnnotColor *color = convertQColor(textColor);
-        DefaultAppearance da(GooString("Invalid_font"), textFont.pointSize(), color);
-        ftextann->setDefaultAppearance(da);
+    if ( pdfAnnot && pdfAnnot->getType() == Annot::typeFreeText )
+    {
+        AnnotFreeText * ftextann = static_cast<AnnotFreeText*>( pdfAnnot );
+        DefaultAppearance da{ { objName, "Invalid_font" }, static_cast<double>( textFont.pointSize() ), std::unique_ptr<AnnotColor>{ convertQColor( textColor ) } };
+        ftextann->setDefaultAppearance( da );
     }
 }
 
-DefaultAppearance *TextAnnotationPrivate::getDefaultAppearanceFromNative() const
+std::unique_ptr<DefaultAppearance> TextAnnotationPrivate::getDefaultAppearanceFromNative() const
 {
-    if (pdfAnnot && pdfAnnot->getType() == Annot::typeFreeText) {
-        AnnotFreeText * ftextann = static_cast<AnnotFreeText*>(pdfAnnot);
+    if ( pdfAnnot && pdfAnnot->getType() == Annot::typeFreeText )
+    {
+        AnnotFreeText * ftextann = static_cast<AnnotFreeText*>( pdfAnnot );
         return ftextann->getDefaultAppearance();
-    } else {
-        return nullptr;
+    }
+    else
+    {
+        return {};
     }
 }
 
@@ -2082,17 +2088,16 @@ QFont TextAnnotation::textFont() const
 {
     Q_D( const TextAnnotation );
 
-    if (!d->pdfAnnot)
+    if ( !d->pdfAnnot )
         return d->textFont;
 
     QFont font;
-
-    if (d->pdfAnnot->getType() == Annot::typeFreeText)
+    if ( d->pdfAnnot->getType() == Annot::typeFreeText )
     {
-        DefaultAppearance *da = d->getDefaultAppearanceFromNative();
-        if (da)
+        if ( std::unique_ptr<DefaultAppearance> da{ d->getDefaultAppearanceFromNative() } )
+        {
             font.setPointSize( da->getFontPtSize() );
-        delete da;
+        }
     }
 
     return font;
@@ -2111,15 +2116,15 @@ QColor TextAnnotation::textColor() const
 {
     Q_D( const TextAnnotation );
 
-    if (!d->pdfAnnot)
+    if ( !d->pdfAnnot )
         return d->textColor;
 
-    QColor color;
-    DefaultAppearance *da = d->getDefaultAppearanceFromNative();
-    if (da)
-        color = convertAnnotColor(da->getFontColor());
-    delete da;
-    return color;
+    if ( std::unique_ptr<DefaultAppearance> da{ d->getDefaultAppearanceFromNative() } )
+    {
+        return convertAnnotColor( da->getFontColor() );
+    }
+
+    return {};
 }
 
 void TextAnnotation::setTextColor( const QColor &color )
@@ -5103,10 +5108,26 @@ QColor convertAnnotColor( const AnnotColor *color )
 
 AnnotColor* convertQColor( const QColor &c )
 {
-    if (!c.isValid() || c.alpha() == 0)
+    if ( c.alpha() == 0 )
         return new AnnotColor(); // Transparent
-    else
-        return new AnnotColor(c.redF(), c.greenF(), c.blueF());
+
+    AnnotColor *newcolor;
+    switch ( c.spec() )
+    {
+        case QColor::Rgb:
+        case QColor::Hsl:
+        case QColor::Hsv:
+            newcolor = new AnnotColor( c.redF(), c.greenF(), c.blueF() );
+            break;
+        case QColor::Cmyk:
+            newcolor = new AnnotColor( c.cyanF(), c.magentaF(), c.yellowF(), c.blackF() );
+            break;
+        case QColor::Invalid:
+        default:
+            newcolor = new AnnotColor();
+            break;
+    }
+    return newcolor;
 }
 //END utility annotation functions
 
diff --git a/qt5/tests/check_annotations.cpp b/qt5/tests/check_annotations.cpp
index 022c4911..f53ec513 100644
--- a/qt5/tests/check_annotations.cpp
+++ b/qt5/tests/check_annotations.cpp
@@ -1,21 +1,45 @@
+#include <cmath>
 #include <memory>
+#include <sstream>
 
 #include <QtTest/QtTest>
 #include <QTemporaryFile>
 
 #include <poppler-qt5.h>
 
+#include "goo/GooString.h"
+#include "goo/gstrtod.h"
+
 class TestAnnotations : public QObject
 {
   Q_OBJECT
 private slots:
-  void checkFontColor();
+  void checkQColorPrecision();
+  void checkFontSizeAndColor();
 };
 
-void TestAnnotations::checkFontColor()
+/* Is .5f sufficient for 16 bit color channel roundtrip trough save and load on all architectures? */
+void TestAnnotations::checkQColorPrecision() {
+  bool precisionOk = true;
+  for (int i = std::numeric_limits<uint16_t>::min(); i <= std::numeric_limits<uint16_t>::max(); i++) {
+    double normalized = static_cast<uint16_t>(i) / static_cast<double>(std::numeric_limits<uint16_t>::max());
+    GooString* serialized = GooString::format("{0:.5f}", normalized);
+    double deserialized = gatof( serialized->getCString() );
+    uint16_t denormalized = std::round(deserialized * std::numeric_limits<uint16_t>::max());
+    if (static_cast<uint16_t>(i) != denormalized) {
+      precisionOk = false;
+      break;
+    }
+  }
+  QVERIFY(precisionOk);
+}
+
+void TestAnnotations::checkFontSizeAndColor()
 {
   const QString contents{"foobar"};
-  const QColor textColor{0xAB, 0xCD, 0xEF};
+  const std::vector<QColor> testColors{QColor::fromRgb(0xAB, 0xCD, 0xEF),
+                                       QColor::fromCmyk(0xAB, 0xBC, 0xCD, 0xDE)};
+  const QFont testFont("Helvetica", 20);
 
   QTemporaryFile tempFile;
   QVERIFY(tempFile.open());
@@ -32,15 +56,14 @@ void TestAnnotations::checkFontColor()
     };
     QVERIFY(page);
 
-    std::unique_ptr<Poppler::TextAnnotation> annot{
-      new Poppler::TextAnnotation{Poppler::TextAnnotation::InPlace}
-    };
-
-    annot->setBoundary(QRectF(0.0, 0.0, 1.0, 1.0));
-    annot->setContents(contents);
-    annot->setTextColor(textColor);
-
-    page->addAnnotation(annot.get());
+    for (const auto& color : testColors) {
+      auto annot = std::make_unique<Poppler::TextAnnotation>(Poppler::TextAnnotation::InPlace);
+      annot->setBoundary(QRectF(0.0, 0.0, 1.0, 1.0));
+      annot->setContents(contents);
+      annot->setTextFont(testFont);
+      annot->setTextColor(color);
+      page->addAnnotation(annot.get());
+    }
 
     std::unique_ptr<Poppler::PDFConverter> conv(doc->pdfConverter());
     QVERIFY(conv);
@@ -61,12 +84,19 @@ void TestAnnotations::checkFontColor()
     QVERIFY(page);
 
     auto annots = page->annotations();
-    QCOMPARE(1, annots.size());
-    QCOMPARE(Poppler::Annotation::AText, annots.constFirst()->subType());
-
-    auto annot = static_cast<Poppler::TextAnnotation*>(annots.constFirst());
-    QCOMPARE(contents, annot->contents());
-    QCOMPARE(textColor, annot->textColor());
+    QCOMPARE(annots.size(), static_cast<int>(testColors.size()));
+
+    auto &&annot = annots.constBegin();
+    for (const auto& color : testColors) {
+      QCOMPARE((*annot)->subType(), Poppler::Annotation::AText);
+      auto textAnnot = static_cast<Poppler::TextAnnotation*>(*annot);
+      QCOMPARE(textAnnot->contents(), contents);
+      QCOMPARE(textAnnot->textFont().pointSize(), testFont.pointSize());
+      QCOMPARE(static_cast<int>(textAnnot->textColor().spec()), static_cast<int>(color.spec()));
+      QCOMPARE(textAnnot->textColor(), color);
+      if (annot != annots.end())
+          ++annot;
+    }
   }
 }
 
commit b67e7ab708a0606298fd3707347bed935390d062
Author: Adam Reichold <adam.reichold at t-online.de>
Date:   Fri Aug 24 20:14:14 2018 +0200

    Add a roundtrip consistency test for the text color properties of annotations.

diff --git a/qt5/tests/CMakeLists.txt b/qt5/tests/CMakeLists.txt
index 1e67e6ec..e808f181 100644
--- a/qt5/tests/CMakeLists.txt
+++ b/qt5/tests/CMakeLists.txt
@@ -58,6 +58,7 @@ qt5_add_qtest(check_qt5_attachments check_attachments.cpp)
 qt5_add_qtest(check_qt5_dateConversion check_dateConversion.cpp)
 qt5_add_qtest(check_qt5_fonts check_fonts.cpp)
 qt5_add_qtest(check_qt5_links check_links.cpp)
+qt5_add_qtest(check_qt5_annotations check_annotations.cpp)
 qt5_add_qtest(check_qt5_metadata check_metadata.cpp)
 qt5_add_qtest(check_qt5_optcontent check_optcontent.cpp)
 qt5_add_qtest(check_qt5_pagelayout check_pagelayout.cpp)
diff --git a/qt5/tests/check_annotations.cpp b/qt5/tests/check_annotations.cpp
new file mode 100644
index 00000000..022c4911
--- /dev/null
+++ b/qt5/tests/check_annotations.cpp
@@ -0,0 +1,75 @@
+#include <memory>
+
+#include <QtTest/QtTest>
+#include <QTemporaryFile>
+
+#include <poppler-qt5.h>
+
+class TestAnnotations : public QObject
+{
+  Q_OBJECT
+private slots:
+  void checkFontColor();
+};
+
+void TestAnnotations::checkFontColor()
+{
+  const QString contents{"foobar"};
+  const QColor textColor{0xAB, 0xCD, 0xEF};
+
+  QTemporaryFile tempFile;
+  QVERIFY(tempFile.open());
+  tempFile.close();
+
+  {
+    std::unique_ptr<Poppler::Document> doc{
+      Poppler::Document::load(TESTDATADIR "/unittestcases/UseNone.pdf")
+    };
+    QVERIFY(doc);
+
+    std::unique_ptr<Poppler::Page> page{
+      doc->page(0)
+    };
+    QVERIFY(page);
+
+    std::unique_ptr<Poppler::TextAnnotation> annot{
+      new Poppler::TextAnnotation{Poppler::TextAnnotation::InPlace}
+    };
+
+    annot->setBoundary(QRectF(0.0, 0.0, 1.0, 1.0));
+    annot->setContents(contents);
+    annot->setTextColor(textColor);
+
+    page->addAnnotation(annot.get());
+
+    std::unique_ptr<Poppler::PDFConverter> conv(doc->pdfConverter());
+    QVERIFY(conv);
+    conv->setOutputFileName(tempFile.fileName());
+    conv->setPDFOptions(Poppler::PDFConverter::WithChanges);
+    QVERIFY(conv->convert());
+  }
+
+  {
+    std::unique_ptr<Poppler::Document> doc{
+      Poppler::Document::load(tempFile.fileName())
+    };
+    QVERIFY(doc);
+
+    std::unique_ptr<Poppler::Page> page{
+      doc->page(0)
+    };
+    QVERIFY(page);
+
+    auto annots = page->annotations();
+    QCOMPARE(1, annots.size());
+    QCOMPARE(Poppler::Annotation::AText, annots.constFirst()->subType());
+
+    auto annot = static_cast<Poppler::TextAnnotation*>(annots.constFirst());
+    QCOMPARE(contents, annot->contents());
+    QCOMPARE(textColor, annot->textColor());
+  }
+}
+
+QTEST_GUILESS_MAIN(TestAnnotations)
+
+#include "check_annotations.moc"
commit db0451ab16060509d13415162a95db269ca0d4f3
Author: Tobias Deiminger <haxtibal at posteo.de>
Date:   Sat Aug 25 19:57:13 2018 +0200

    Fix open review comments from #50
    
    Make fontTag optional for AnnotFreeText::parseAppearanceString.
    Handle fontColor == nullptr in AnnotFreeText::constructAppearanceString.
    Use AnnotAppearanceBuilder in AnnotFreeText::constructAppearanceString.
    Delete copy assignment operator for DefaultAppearance.
    Rename setAppearanceString to setDefaultAppearance.

diff --git a/poppler/Annot.cc b/poppler/Annot.cc
index c2bc85d7..e8c9f95a 100644
--- a/poppler/Annot.cc
+++ b/poppler/Annot.cc
@@ -1652,6 +1652,11 @@ void AnnotAppearanceBuilder::setDrawColor(const AnnotColor *drawColor, GBool fil
   }
 }
 
+void AnnotAppearanceBuilder::setTextFont(const GooString &fontTag, double fontSize) {
+  if (fontTag.getLength() > 0)
+    appearBuf->appendf("/{0:s} {1:.2f} Tf", &fontTag, fontSize);
+}
+
 void AnnotAppearanceBuilder::setLineStyleForBorder(const AnnotBorder *border) {
   int i, dashLength;
   double *dash;
@@ -2743,7 +2748,7 @@ void AnnotFreeText::setContents(GooString *new_content) {
   invalidateAppearance();
 }
 
-void AnnotFreeText::setAppearanceString(const DefaultAppearance &da) {
+void AnnotFreeText::setDefaultAppearance(const DefaultAppearance &da) {
   delete appearanceString;
 
   appearanceString = constructAppearanceString(da.getFontTag(), da.getFontPtSize(), da.getFontColor());
@@ -2822,7 +2827,7 @@ DefaultAppearance *AnnotFreeText::getDefaultAppearance() const {
   double fontSize;
   AnnotColor *fontColor;
   GooString *fontTag;
-  parseAppearanceString(appearanceString, fontSize, fontColor, fontTag);
+  parseAppearanceString(appearanceString, fontSize, fontColor, &fontTag);
   DefaultAppearance *da = new DefaultAppearance(*fontTag, fontSize, fontColor);
   delete fontTag;
   return da;
@@ -2846,31 +2851,19 @@ static GfxFont *createAnnotDrawFont(XRef * xref, Dict *fontResDict)
 }
 
 GooString *AnnotFreeText::constructAppearanceString(const GooString &fontTag, double fontSize, const AnnotColor *fontColor) {
-  const double *colorData = fontColor->getValues();
-  GooString * cstr = nullptr;
-  switch(fontColor->getSpace())
-  {
-    case AnnotColor::AnnotColorSpace::colorTransparent: // =0
-      cstr = new GooString();
-      break;
-    case AnnotColor::AnnotColorSpace::colorGray: //=1
-      cstr = GooString::format("{0:.2f} g ", colorData[0]);
-      break;
-    case AnnotColor::AnnotColorSpace::colorRGB: //=3
-      cstr = GooString::format("{0:.2f} {1:.2f} {2:.2f} rg ", colorData[0], colorData[1], colorData[2]);
-      break;
-    case AnnotColor::AnnotColorSpace::colorCMYK: //=4
-      cstr = GooString::format("{0:.2f} {1:.2f} {2:.2f} {3:.2f} k ", colorData[0], colorData[1], colorData[2], colorData[3]);
-      break;
+  AnnotAppearanceBuilder appearBuilder;
+  if (fontColor) {
+    appearBuilder.setDrawColor(fontColor, gFalse);
   }
-  const GooString * str = GooString::format("/{0:s} {1:.2f} Tf", &fontTag, fontSize);
-  return cstr->append( str );
+  appearBuilder.setTextFont(fontTag, fontSize);
+  return appearBuilder.buffer()->copy();
 }
 
-void AnnotFreeText::parseAppearanceString(GooString *da, double &fontsize, AnnotColor* &fontcolor, GooString* &fontTag) {
+void AnnotFreeText::parseAppearanceString(GooString *da, double &fontsize, AnnotColor* &fontcolor, GooString **fontTag) {
   fontsize = -1;
   fontcolor = nullptr;
-  fontTag = nullptr;
+  if (fontTag)
+    *fontTag = nullptr;
   if (da) {
     GooList * daToks = new GooList();
     int i = FormFieldText::tokenizeDA(da, daToks, "Tf");
@@ -2878,8 +2871,8 @@ void AnnotFreeText::parseAppearanceString(GooString *da, double &fontsize, Annot
     if (i >= 1) {
       fontsize = gatof(( (GooString *)daToks->get(i-1) )->getCString());
     }
-    if (i >= 2) {
-      fontTag = new GooString(( (GooString *)daToks->get(i-2) )->getCString());
+    if (fontTag && i >= 2) {
+      *fontTag = new GooString(( (GooString *)daToks->get(i-2) )->getCString());
     }
     // Scan backwards: we are looking for the last set value
     for (i = daToks->getLength()-1; i >= 0; --i) {
@@ -2920,9 +2913,7 @@ void AnnotFreeText::generateFreeTextAppearance()
   // Parse some properties from the appearance string
   double fontsize;
   AnnotColor *fontcolor;
-  GooString *fontTag = nullptr;
-  parseAppearanceString(appearanceString, fontsize, fontcolor, fontTag);
-  delete fontTag;
+  parseAppearanceString(appearanceString, fontsize, fontcolor, nullptr);
   // Default values
   if (fontsize <= 0)
     fontsize = 10;
diff --git a/poppler/Annot.h b/poppler/Annot.h
index 359b5d0d..af35d226 100644
--- a/poppler/Annot.h
+++ b/poppler/Annot.h
@@ -359,7 +359,8 @@ public:
   int getFontPtSize() const { return fontPtSize; }
   const AnnotColor *getFontColor() const { return fontColor; }
   ~DefaultAppearance();
-  DefaultAppearance(DefaultAppearance &ger) = delete;
+  DefaultAppearance(DefaultAppearance &) = delete;
+  DefaultAppearance& operator=(const DefaultAppearance&) = delete;
 private:
 
   GooString *fontTag;
@@ -531,6 +532,7 @@ public:
 
   void setDrawColor(const AnnotColor *color, GBool fill);
   void setLineStyleForBorder(const AnnotBorder *border);
+  void setTextFont(const GooString &fontTag, double fontSize);
   void drawCircle(double cx, double cy, double r, GBool fill);
   void drawCircleTopLeft(double cx, double cy, double r);
   void drawCircleBottomRight(double cx, double cy, double r);
@@ -997,7 +999,7 @@ public:
   Object getAppearanceResDict() override;
   void setContents(GooString *new_content) override;
 
-  void setAppearanceString(const DefaultAppearance &da);
+  void setDefaultAppearance(const DefaultAppearance &da);
   void setQuadding(AnnotFreeTextQuadding new_quadding);
   void setStyleString(GooString *new_string);
   void setCalloutLine(AnnotCalloutLine *line);
@@ -1018,7 +1020,7 @@ protected:
 
   void initialize(PDFDoc *docA, Dict *dict);
   static GooString *constructAppearanceString(const GooString &fontTag, double fontSize, const AnnotColor *fontColor);
-  static void parseAppearanceString(GooString *da, double &fontSize, AnnotColor* &fontColor, GooString* &fontTag);
+  static void parseAppearanceString(GooString *da, double &fontSize, AnnotColor* &fontColor, GooString **fontTag);
   void generateFreeTextAppearance();
 
   // required
diff --git a/qt5/src/poppler-annotation.cc b/qt5/src/poppler-annotation.cc
index 301b4f48..46dcc93c 100644
--- a/qt5/src/poppler-annotation.cc
+++ b/qt5/src/poppler-annotation.cc
@@ -1879,7 +1879,7 @@ void TextAnnotationPrivate::setDefaultAppearanceToNative()
         AnnotFreeText * ftextann = static_cast<AnnotFreeText*>(pdfAnnot);
         AnnotColor *color = convertQColor(textColor);
         DefaultAppearance da(GooString("Invalid_font"), textFont.pointSize(), color);
-        ftextann->setAppearanceString(da);
+        ftextann->setDefaultAppearance(da);
     }
 }
 
commit 64531344de3dc663a4429e94381d68cc198d0425
Author: Dileep Sankhla <sankhla.dileep96 at gmail.com>
Date:   Thu Aug 23 17:48:39 2018 +0200

    Add annotation font color

diff --git a/poppler/Annot.cc b/poppler/Annot.cc
index e6efd2f3..c2bc85d7 100644
--- a/poppler/Annot.cc
+++ b/poppler/Annot.cc
@@ -793,6 +793,21 @@ Object AnnotColor::writeToObject(XRef *xref) const {
 }
 
 //------------------------------------------------------------------------
+// DefaultAppearance
+//------------------------------------------------------------------------
+
+DefaultAppearance::DefaultAppearance(const GooString &fontTag, int fontPtSize, AnnotColor *fontColor)
+ : fontPtSize(fontPtSize), fontColor(fontColor) {
+  DefaultAppearance::fontTag = fontTag.copy();
+}
+
+DefaultAppearance::~DefaultAppearance() {
+  delete fontTag;
+  if (fontColor) {
+    delete fontColor;
+  }
+}
+//------------------------------------------------------------------------
 // AnnotIconFit
 //------------------------------------------------------------------------
 
@@ -2594,12 +2609,13 @@ void AnnotLink::draw(Gfx *gfx, GBool printing) {
 //------------------------------------------------------------------------
 // AnnotFreeText
 //------------------------------------------------------------------------
-AnnotFreeText::AnnotFreeText(PDFDoc *docA, PDFRectangle *rect, GooString *da) :
+AnnotFreeText::AnnotFreeText(PDFDoc *docA, PDFRectangle *rect, const DefaultAppearance &da) :
     AnnotMarkup(docA, rect) {
   type = typeFreeText;
 
+  GooString *daStr = constructAppearanceString(da.getFontTag(), da.getFontPtSize(), da.getFontColor());
   annotObj.dictSet ("Subtype", Object(objName, "FreeText"));
-  annotObj.dictSet("DA", Object(da->copy()));
+  annotObj.dictSet("DA", Object(daStr));
 
   initialize (docA, annotObj.getDict());
 }
@@ -2727,14 +2743,10 @@ void AnnotFreeText::setContents(GooString *new_content) {
   invalidateAppearance();
 }
 
-void AnnotFreeText::setAppearanceString(GooString *new_string) {
+void AnnotFreeText::setAppearanceString(const DefaultAppearance &da) {
   delete appearanceString;
 
-  if (new_string) {
-    appearanceString = new GooString(new_string);
-  } else {
-    appearanceString = new GooString();
-  }
+  appearanceString = constructAppearanceString(da.getFontTag(), da.getFontPtSize(), da.getFontColor());
 
   update ("DA", Object(appearanceString->copy()));
   invalidateAppearance();
@@ -2806,7 +2818,17 @@ void AnnotFreeText::setIntent(AnnotFreeTextIntent new_intent) {
   update ("IT", Object(objName, intentName));
 }
 
-static GfxFont * createAnnotDrawFont(XRef * xref, Dict *fontResDict)
+DefaultAppearance *AnnotFreeText::getDefaultAppearance() const {
+  double fontSize;
+  AnnotColor *fontColor;
+  GooString *fontTag;
+  parseAppearanceString(appearanceString, fontSize, fontColor, fontTag);
+  DefaultAppearance *da = new DefaultAppearance(*fontTag, fontSize, fontColor);
+  delete fontTag;
+  return da;
+}
+
+static GfxFont *createAnnotDrawFont(XRef * xref, Dict *fontResDict)
 {
   const Ref dummyRef = { -1, -1 };
 
@@ -2823,16 +2845,41 @@ static GfxFont * createAnnotDrawFont(XRef * xref, Dict *fontResDict)
   return GfxFont::makeFont(xref, "AnnotDrawFont", dummyRef, fontDict);
 }
 
-void AnnotFreeText::parseAppearanceString(GooString *da, double &fontsize, AnnotColor* &fontcolor) {
+GooString *AnnotFreeText::constructAppearanceString(const GooString &fontTag, double fontSize, const AnnotColor *fontColor) {
+  const double *colorData = fontColor->getValues();
+  GooString * cstr = nullptr;
+  switch(fontColor->getSpace())
+  {
+    case AnnotColor::AnnotColorSpace::colorTransparent: // =0
+      cstr = new GooString();
+      break;
+    case AnnotColor::AnnotColorSpace::colorGray: //=1
+      cstr = GooString::format("{0:.2f} g ", colorData[0]);
+      break;
+    case AnnotColor::AnnotColorSpace::colorRGB: //=3
+      cstr = GooString::format("{0:.2f} {1:.2f} {2:.2f} rg ", colorData[0], colorData[1], colorData[2]);
+      break;
+    case AnnotColor::AnnotColorSpace::colorCMYK: //=4
+      cstr = GooString::format("{0:.2f} {1:.2f} {2:.2f} {3:.2f} k ", colorData[0], colorData[1], colorData[2], colorData[3]);
+      break;
+  }
+  const GooString * str = GooString::format("/{0:s} {1:.2f} Tf", &fontTag, fontSize);
+  return cstr->append( str );
+}
+
+void AnnotFreeText::parseAppearanceString(GooString *da, double &fontsize, AnnotColor* &fontcolor, GooString* &fontTag) {
   fontsize = -1;
   fontcolor = nullptr;
+  fontTag = nullptr;
   if (da) {
     GooList * daToks = new GooList();
     int i = FormFieldText::tokenizeDA(da, daToks, "Tf");
 
     if (i >= 1) {
       fontsize = gatof(( (GooString *)daToks->get(i-1) )->getCString());
-      // TODO: Font name
+    }
+    if (i >= 2) {
+      fontTag = new GooString(( (GooString *)daToks->get(i-2) )->getCString());
     }
     // Scan backwards: we are looking for the last set value
     for (i = daToks->getLength()-1; i >= 0; --i) {
@@ -2873,7 +2920,9 @@ void AnnotFreeText::generateFreeTextAppearance()
   // Parse some properties from the appearance string
   double fontsize;
   AnnotColor *fontcolor;
-  parseAppearanceString(appearanceString, fontsize, fontcolor);
+  GooString *fontTag = nullptr;
+  parseAppearanceString(appearanceString, fontsize, fontcolor, fontTag);
+  delete fontTag;
   // Default values
   if (fontsize <= 0)
     fontsize = 10;
diff --git a/poppler/Annot.h b/poppler/Annot.h
index 83c10b39..359b5d0d 100644
--- a/poppler/Annot.h
+++ b/poppler/Annot.h
@@ -348,6 +348,26 @@ private:
 };
 
 //------------------------------------------------------------------------
+// DefaultAppearance
+//------------------------------------------------------------------------
+
+class DefaultAppearance {
+public:
+
+  DefaultAppearance(const GooString &fontTag, int fontPtSize, AnnotColor *fontColor = nullptr);
+  const GooString &getFontTag() const { return *fontTag; }
+  int getFontPtSize() const { return fontPtSize; }
+  const AnnotColor *getFontColor() const { return fontColor; }
+  ~DefaultAppearance();
+  DefaultAppearance(DefaultAppearance &ger) = delete;
+private:
+
+  GooString *fontTag;
+  int fontPtSize;
+  AnnotColor *fontColor;
+};
+
+//------------------------------------------------------------------------
 // AnnotIconFit
 //------------------------------------------------------------------------
 
@@ -969,7 +989,7 @@ public:
     intentFreeTextTypeWriter  // FreeTextTypeWriter
   };
 
-  AnnotFreeText(PDFDoc *docA, PDFRectangle *rect, GooString *da);
+  AnnotFreeText(PDFDoc *docA, PDFRectangle *rect, const DefaultAppearance &da);
   AnnotFreeText(PDFDoc *docA, Object *dictObject, Object *obj);
   ~AnnotFreeText();
 
@@ -977,14 +997,14 @@ public:
   Object getAppearanceResDict() override;
   void setContents(GooString *new_content) override;
 
-  void setAppearanceString(GooString *new_string);
+  void setAppearanceString(const DefaultAppearance &da);
   void setQuadding(AnnotFreeTextQuadding new_quadding);
   void setStyleString(GooString *new_string);
   void setCalloutLine(AnnotCalloutLine *line);
   void setIntent(AnnotFreeTextIntent new_intent);
 
   // getters
-  const GooString *getAppearanceString() const { return appearanceString; }
+  DefaultAppearance *getDefaultAppearance() const;
   AnnotFreeTextQuadding getQuadding() const { return quadding; }
   // return rc
   const GooString *getStyleString() const { return styleString; }
@@ -997,7 +1017,8 @@ public:
 protected:
 
   void initialize(PDFDoc *docA, Dict *dict);
-  static void parseAppearanceString(GooString *da, double &fontsize, AnnotColor* &fontcolor);
+  static GooString *constructAppearanceString(const GooString &fontTag, double fontSize, const AnnotColor *fontColor);
+  static void parseAppearanceString(GooString *da, double &fontSize, AnnotColor* &fontColor, GooString* &fontTag);
   void generateFreeTextAppearance();
 
   // required
diff --git a/qt5/src/poppler-annotation-helper.h b/qt5/src/poppler-annotation-helper.h
index 3150569c..669b98ee 100644
--- a/qt5/src/poppler-annotation-helper.h
+++ b/qt5/src/poppler-annotation-helper.h
@@ -175,7 +175,7 @@ void XPDFReader::invTransform( double * M, const QPointF &p, double &x, double &
     y = invM[1] * xt + invM[3] * yt;
 }
 
-QColor convertAnnotColor( AnnotColor *color );
+QColor convertAnnotColor( const AnnotColor *color );
 AnnotColor* convertQColor( const QColor &color );
 
 }
diff --git a/qt5/src/poppler-annotation.cc b/qt5/src/poppler-annotation.cc
index 5550efcd..301b4f48 100644
--- a/qt5/src/poppler-annotation.cc
+++ b/qt5/src/poppler-annotation.cc
@@ -1816,17 +1816,17 @@ class TextAnnotationPrivate : public AnnotationPrivate
         TextAnnotationPrivate();
         Annotation * makeAlias() override;
         Annot* createNativeAnnot(::Page *destPage, DocumentData *doc) override;
+        void setDefaultAppearanceToNative();
+        DefaultAppearance *getDefaultAppearanceFromNative() const;
 
         // data fields
         TextAnnotation::TextType textType;
         QString textIcon;
         QFont textFont;
+        QColor textColor;
         int inplaceAlign; // 0:left, 1:center, 2:right
         QVector<QPointF> inplaceCallout;
         TextAnnotation::InplaceIntent inplaceIntent;
-
-        // Helper
-        static GooString * toAppearanceString(const QFont &font);
 };
 
 TextAnnotationPrivate::TextAnnotationPrivate()
@@ -1841,13 +1841,6 @@ Annotation * TextAnnotationPrivate::makeAlias()
     return new TextAnnotation(*this);
 }
 
-GooString * TextAnnotationPrivate::toAppearanceString(const QFont &font)
-{
-    GooString * s = GooString::format("/Invalid_font {0:d} Tf", font.pointSize());
-    // TODO: Font family, style (bold, italic, ...) and pointSize as float
-    return s;
-}
-
 Annot* TextAnnotationPrivate::createNativeAnnot(::Page *destPage, DocumentData *doc)
 {
     // Setters are defined in the public class
@@ -1859,15 +1852,11 @@ Annot* TextAnnotationPrivate::createNativeAnnot(::Page *destPage, DocumentData *
 
     // Set pdfAnnot
     PDFRectangle rect = boundaryToPdfRectangle(boundary, flags);
-    if (textType == TextAnnotation::Linked)
-    {
-        pdfAnnot = new AnnotText(destPage->getDoc(), &rect);
-    }
-    else
-    {
-        GooString * da = toAppearanceString(textFont);
-        pdfAnnot = new AnnotFreeText(destPage->getDoc(), &rect, da);
-        delete da;
+    if (textType == TextAnnotation::Linked) {
+      pdfAnnot = new AnnotText(destPage->getDoc(), &rect);
+    } else {
+      DefaultAppearance da(GooString("Invalid_font"), textFont.pointSize(), convertQColor(textColor));
+      pdfAnnot = new AnnotFreeText(destPage->getDoc(), &rect, da);
     }
 
     // Set properties
@@ -1884,6 +1873,26 @@ Annot* TextAnnotationPrivate::createNativeAnnot(::Page *destPage, DocumentData *
     return pdfAnnot;
 }
 
+void TextAnnotationPrivate::setDefaultAppearanceToNative()
+{
+    if (pdfAnnot && pdfAnnot->getType() == Annot::typeFreeText) {
+        AnnotFreeText * ftextann = static_cast<AnnotFreeText*>(pdfAnnot);
+        AnnotColor *color = convertQColor(textColor);
+        DefaultAppearance da(GooString("Invalid_font"), textFont.pointSize(), color);
+        ftextann->setAppearanceString(da);
+    }
+}
+
+DefaultAppearance *TextAnnotationPrivate::getDefaultAppearanceFromNative() const
+{
+    if (pdfAnnot && pdfAnnot->getType() == Annot::typeFreeText) {
+        AnnotFreeText * ftextann = static_cast<AnnotFreeText*>(pdfAnnot);
+        return ftextann->getDefaultAppearance();
+    } else {
+        return nullptr;
+    }
+}
+
 TextAnnotation::TextAnnotation( TextAnnotation::TextType type )
     : Annotation( *new TextAnnotationPrivate() )
 {
@@ -1916,6 +1925,11 @@ TextAnnotation::TextAnnotation( const QDomNode & node )
             QFont font;
             font.fromString( e.attribute( QStringLiteral("font") ) );
             setTextFont(font);
+            if ( e.hasAttribute( QStringLiteral("fontColor") ) )
+            {
+                const QColor color = QColor(e.attribute( QStringLiteral("fontColor") ) );
+                setTextColor(color);
+            }
         }
         if ( e.hasAttribute( QStringLiteral("align") ) )
             setInplaceAlign(e.attribute( QStringLiteral("align") ).toInt());
@@ -1975,6 +1989,7 @@ void TextAnnotation::store( QDomNode & node, QDomDocument & document ) const
         textElement.setAttribute( QStringLiteral("intent"), (int)inplaceIntent() );
 
     textElement.setAttribute( QStringLiteral("font"), textFont().toString() );
+    textElement.setAttribute( QStringLiteral("fontColor"), textColor().name() );
 
     // Sub-Node-1 - escapedText
     if ( !contents().isEmpty() )
@@ -2074,17 +2089,10 @@ QFont TextAnnotation::textFont() const
 
     if (d->pdfAnnot->getType() == Annot::typeFreeText)
     {
-        const AnnotFreeText * ftextann = static_cast<const AnnotFreeText*>(d->pdfAnnot);
-        const GooString * da = ftextann->getAppearanceString();
+        DefaultAppearance *da = d->getDefaultAppearanceFromNative();
         if (da)
-        {
-            // At the moment, only font size is parsed
-            QString style = QString::fromLatin1( da->getCString() );
-            QRegExp rx(QStringLiteral("(\\d+)(\\.\\d*)? Tf"));
-            if (rx.indexIn(style) != -1)
-                font.setPointSize( rx.cap(1).toInt() );
-            // TODO: Other properties
-        }
+            font.setPointSize( da->getFontPtSize() );
+        delete da;
     }
 
     return font;
@@ -2093,20 +2101,33 @@ QFont TextAnnotation::textFont() const
 void TextAnnotation::setTextFont( const QFont &font )
 {
     Q_D( TextAnnotation );
+    d->textFont = font;
+    d->textColor = Qt::black;
 
-    if (!d->pdfAnnot)
-    {
-        d->textFont = font;
-        return;
-    }
+    d->setDefaultAppearanceToNative();
+}
 
-    if (d->pdfAnnot->getType() != Annot::typeFreeText)
-        return;
+QColor TextAnnotation::textColor() const
+{
+    Q_D( const TextAnnotation );
 
-    AnnotFreeText * ftextann = static_cast<AnnotFreeText*>(d->pdfAnnot);
-    GooString * da = TextAnnotationPrivate::toAppearanceString(font);
-    ftextann->setAppearanceString(da);
+    if (!d->pdfAnnot)
+        return d->textColor;
+
+    QColor color;
+    DefaultAppearance *da = d->getDefaultAppearanceFromNative();
+    if (da)
+        color = convertAnnotColor(da->getFontColor());
     delete da;
+    return color;
+}
+
+void TextAnnotation::setTextColor( const QColor &color )
+{
+    Q_D( TextAnnotation );
+    d->textColor = color;
+
+    d->setDefaultAppearanceToNative();
 }
 
 int TextAnnotation::inplaceAlign() const
@@ -5055,7 +5076,7 @@ RichMediaAnnotation::Content* RichMediaAnnotation::content() const
 
 
 //BEGIN utility annotation functions
-QColor convertAnnotColor( AnnotColor *color )
+QColor convertAnnotColor( const AnnotColor *color )
 {
     if ( !color )
         return QColor();
diff --git a/qt5/src/poppler-annotation.h b/qt5/src/poppler-annotation.h
index a70cbe4f..477629ef 100644
--- a/qt5/src/poppler-annotation.h
+++ b/qt5/src/poppler-annotation.h
@@ -484,6 +484,10 @@ class POPPLER_QT5_EXPORT TextAnnotation : public Annotation
 
     QFont textFont() const;
     void setTextFont( const QFont &font );
+    /// \since 0.69
+    QColor textColor() const;
+    /// \since 0.69
+    void setTextColor( const QColor &color );
 
     int inplaceAlign() const;
     void setInplaceAlign( int align );
commit f506b8bc52efd0781a933a44bb58d02fb000c78d
Author: Albert Astals Cid <aacid at kde.org>
Date:   Sat Sep 1 23:54:26 2018 +0200

    Fix handling of Signature Info Location and Reason
    
    We can't call GooString->getCString and just store that char *
    as it belonged to us since it may very well be the inner array
    of the GooString and be invalid once the GooString goes away

diff --git a/poppler/Form.cc b/poppler/Form.cc
index 95336875..2ff4aafa 100644
--- a/poppler/Form.cc
+++ b/poppler/Form.cc
@@ -5,7 +5,7 @@
 // This file is licensed under the GPLv2 or later
 //
 // Copyright 2006-2008 Julien Rebetez <julienr at svn.gnome.org>
-// Copyright 2007-2012, 2015-2017 Albert Astals Cid <aacid at kde.org>
+// Copyright 2007-2012, 2015-2018 Albert Astals Cid <aacid at kde.org>
 // Copyright 2007-2008, 2011 Carlos Garcia Campos <carlosgc at gnome.org>
 // Copyright 2007, 2013, 2016 Adrian Johnson <ajohnson at redneon.com>
 // Copyright 2007 Iñigo Martínez <inigomartinez at gmail.com>
@@ -1638,12 +1638,12 @@ void FormFieldSignature::parseInfo()
 
   const Object location_obj = sig_dict.dictLookup("Location");
   if (location_obj.isString()) {
-    signature_info->setLocation(location_obj.getString()->copy()->getCString());
+    signature_info->setLocation(location_obj.getString()->getCString());
   }
 
   const Object reason_obj = sig_dict.dictLookup("Reason");
   if (reason_obj.isString()) {
-    signature_info->setReason(reason_obj.getString()->copy()->getCString());
+    signature_info->setReason(reason_obj.getString()->getCString());
   }
 
   // retrieve SigningTime
diff --git a/poppler/SignatureInfo.cc b/poppler/SignatureInfo.cc
index 76a54c0c..11e47e5b 100644
--- a/poppler/SignatureInfo.cc
+++ b/poppler/SignatureInfo.cc
@@ -127,16 +127,16 @@ void SignatureInfo::setSubjectDN(const char *subjectDN)
   subject_dn = strdup(subjectDN);
 }
 
-void SignatureInfo::setLocation(char *loc)
+void SignatureInfo::setLocation(const char *loc)
 {
   free(location);
-  location = loc;
+  location = strdup(loc);
 }
 
-void SignatureInfo::setReason(char *signingReason)
+void SignatureInfo::setReason(const char *signingReason)
 {
   free(reason);
-  reason = signingReason;
+  reason = strdup(signingReason);
 }
 
 void SignatureInfo::setHashAlgorithm(int type)
diff --git a/poppler/SignatureInfo.h b/poppler/SignatureInfo.h
index 1e9f5f9d..f4554c60 100644
--- a/poppler/SignatureInfo.h
+++ b/poppler/SignatureInfo.h
@@ -61,8 +61,8 @@ public:
   void setCertificateValStatus(enum CertificateValidationStatus );
   void setSignerName(char *);
   void setSubjectDN(const char *);
-  void setLocation(char *);
-  void setReason(char *);
+  void setLocation(const char *);
+  void setReason(const char *);
   void setHashAlgorithm(int);
   void setSigningTime(time_t);
   void setSubFilterSupport(bool isSupported) { sig_subfilter_supported = isSupported; }
commit 7418616dbfc9c4e5b05b7a57f4fabed3bf9fdcb0
Author: Albert Astals Cid <aacid at kde.org>
Date:   Sat Sep 1 23:51:48 2018 +0200

    Link: Fix memory leak regarding next actions

diff --git a/poppler/Link.cc b/poppler/Link.cc
index 4a20752c..f88183f9 100644
--- a/poppler/Link.cc
+++ b/poppler/Link.cc
@@ -56,7 +56,8 @@ LinkAction::LinkAction() : nextActionList(nullptr) {
 }
 
 LinkAction::~LinkAction() {
-  delete nextActionList;
+  if (nextActionList)
+    deleteGooList(nextActionList, LinkAction);
 }
 
 LinkAction *LinkAction::parseDest(const Object *obj) {


More information about the poppler mailing list