[poppler] 7 commits - CMakeLists.txt cpp/CMakeLists.txt poppler/GfxState.cc poppler/Link.cc poppler/Link.h qt5/src

Adam Reichold adam.reichold at t-online.de
Mon Apr 16 18:36:37 UTC 2018


Hello again,

Am 16.04.2018 um 20:22 schrieb Albert Astals Cid:
> El dilluns, 16 d’abril de 2018, a les 19:05:25 CEST, Adam Reichold va 
> escriure:
>> Hello,
>>
>> concerning df8a4ee51e18a39f85568c4122e5edd8c03d61df, I think there is a
>> problem in the "isArray" branch where a moved-from value
>> "seenNextActions" is used if the array contains more than one dict. I
>> think this is generally undefined behavior (even though it is probably
>> fine in this case since a moved-from std::unique_ptr is probably just
>> empty, but the only guarantee is that it can be destructed safely).
>>
>> But I also think that it is not how the function is supposed to work
>> since every call to parseActions should start we the same prefix of
>> already-seen actions, hence needs to start with the same value of
>> seenNextActions modifying its private copy if actual branching takes
>> place, so that the copies probably cannot be elided in that part of the
>> function.
> 
> You're right, good catch!
> 
>> Also if this is about performance, I think this could be a bit lazier by
>> initializing the set the first when it will really be used, it could use
>> std::unordered_set since we only check membership and a single lookup
>> should suffice since it returns whether insertion actually took place.
>>
>> But also since an empty instance of std::set does not allocate any
>> nodes, wouldn't it be even simpler to just pass that set by value moving
>> the set and not the pointer to it where that is possible? (It is
>> basically the size of two pointers instead of one, but also looses one
>> indirection.)
> 
> But your patch does exactly what i want to avoid, you're copying the set in
> 
> auto seenNextActionsAux = seenNextActions;
> 
> This other patch I'm attaching should fix the problem too with less copying, 
> right?

It does not copy, but it is not functionally equivalent to the original
implementation which would not share the already-seen actions between
the branches in the array (as this does not imply circular connections).

Also std::shared_ptr uses atomic reference counts behind the scenes and
is hence a rather heavy weight abstraction w.r.t performance.

So if any repetitions and not just circular paths are forbidden, the
easiest option would probably be to have parseAction just become

static LinkAction* doParseAction(const Object*, const GooString*, const
std::std<int>&);

with an additional helper

static LinkAction parseAction(const Object* obj, const GooString* baseURI) {
std::set<int> seenNextActions;
return doParseAction(obj, baseURI, seenNextActions);
}

To keep the original semantics one must copy if I understand things
correctly.

> Cheers,
>   Albert

Best regards, Adam.

>>
>> Best regards,
>> Adam
>>
>> Am 16.04.2018 um 18:10 schrieb Albert Astals Cid:
>>>  CMakeLists.txt                 |    7 ++
>>>  cpp/CMakeLists.txt             |    1
>>>  poppler/GfxState.cc            |    5 +
>>>  poppler/Link.cc                |  103
>>>  ++++++++++++++++++++++++++++++++++++++++- poppler/Link.h                
>>>  |   54 ++++++++++++++++++++-
>>>  qt5/src/poppler-annotation.cc  |    6 ++
>>>  qt5/src/poppler-link-private.h |   26 ++++++++++
>>>  qt5/src/poppler-link.cc        |   35 +++++++++++++
>>>  qt5/src/poppler-link.h         |   50 +++++++++++++++++++
>>>  qt5/src/poppler-page.cc        |   25 +++++++++
>>>  10 files changed, 303 insertions(+), 9 deletions(-)
>>>
>>> New commits:
>>> commit 88c99f1f6f4faf31faabccd35d9d094958020ebc
>>> Author: Albert Astals Cid <aacid at kde.org>
>>> Date:   Mon Apr 16 17:59:35 2018 +0200
>>>
>>>     Fix crash on malformed documents
>>>     
>>>     In GfxGouraudTriangleShading::parse
>>>     
>>>     Bug #106061
>>>
>>> diff --git a/poppler/GfxState.cc b/poppler/GfxState.cc
>>> index 95699355..5d7cc6ba 100644
>>> --- a/poppler/GfxState.cc
>>> +++ b/poppler/GfxState.cc
>>> @@ -4916,7 +4916,7 @@ GfxGouraudTriangleShading
>>> *GfxGouraudTriangleShading::parse(GfxResources *res, i> 
>>>      }
>>>    
>>>    }
>>>    delete bitBuf;
>>>
>>> -  if (typeA == 5 && nVerticesA > 0) {
>>> +  if (typeA == 5 && nVerticesA > 0 && vertsPerRow > 0) {
>>>
>>>      nRows = nVerticesA / vertsPerRow;
>>>      nTrianglesA = (nRows - 1) * 2 * (vertsPerRow - 1);
>>>      trianglesA = (int (*)[3])gmallocn_checkoverflow(nTrianglesA * 3,
>>>      sizeof(int));> 
>>> commit df8a4ee51e18a39f85568c4122e5edd8c03d61df
>>> Author: Albert Astals Cid <aacid at kde.org>
>>> Date:   Mon Apr 16 17:46:10 2018 +0200
>>>
>>>     Make it so we copy seenNextActions a bit less
>>>
>>> diff --git a/poppler/Link.cc b/poppler/Link.cc
>>> index 2f853125..42bdaf1b 100644
>>> --- a/poppler/Link.cc
>>> +++ b/poppler/Link.cc
>>> @@ -71,7 +71,7 @@ LinkAction *LinkAction::parseDest(const Object *obj) {
>>>
>>>  }
>>>  
>>>  LinkAction *LinkAction::parseAction(const Object *obj, const GooString
>>>  *baseURI,> 
>>> -                                    const std::set<int> *seenNextActions)
>>> { +                                    std::unique_ptr<std::set<int>>
>>> seenNextActions) {> 
>>>    LinkAction *action;
>>>    
>>>    if (!obj->isDict()) {
>>>
>>> @@ -160,18 +160,19 @@ LinkAction *LinkAction::parseAction(const Object
>>> *obj, const GooString *baseURI,> 
>>>      // Prevent circles in the tree by checking the ref against used refs
>>>      in
>>>      // our current tree branch.
>>>      const Object nextRefObj = obj->dictLookupNF("Next");
>>>
>>> -    std::set<int> seenNextActionsAux = seenNextActions ? *seenNextActions
>>> : std::set<int> (); +    if (!seenNextActions)
>>> +        seenNextActions.reset(new std::set<int>);
>>>
>>>      if (nextRefObj.isRef()) {
>>>      
>>>          const Ref ref = nextRefObj.getRef();
>>>
>>> -        if (seenNextActionsAux.find(ref.num) != seenNextActionsAux.end())
>>> { +        if (seenNextActions->find(ref.num) != seenNextActions->end())
>>> {> 
>>>              error(errSyntaxWarning, -1, "parseAction: Circular next
>>>              actions detected."); return action;
>>>          
>>>          }
>>>
>>> -        seenNextActionsAux.insert(ref.num);
>>> +        seenNextActions->insert(ref.num);
>>>
>>>      }
>>>      
>>>      actionList = new GooList(1);
>>>
>>> -    actionList->append(parseAction(&nextObj, nullptr,
>>> &seenNextActionsAux)); +    actionList->append(parseAction(&nextObj,
>>> nullptr, std::move(seenNextActions)));> 
>>>    } else if (nextObj.isArray()) {
>>>    
>>>      const Array *a = nextObj.getArray();
>>>      const int n = a->getLength();
>>>
>>> @@ -184,18 +185,19 @@ LinkAction *LinkAction::parseAction(const Object
>>> *obj, const GooString *baseURI,> 
>>>        }
>>>        
>>>        // Similar circle check as above.
>>>
>>> -      std::set<int> seenNextActionsAux = seenNextActions ?
>>> *seenNextActions : std::set<int> (); +      if (!seenNextActions)
>>> +        seenNextActions.reset(new std::set<int>);
>>>
>>>        const Object obj3Ref = a->getNF(i);
>>>        if (obj3Ref.isRef()) {
>>>        
>>>            const Ref ref = obj3Ref.getRef();
>>>
>>> -          if (seenNextActionsAux.find(ref.num) !=
>>> seenNextActionsAux.end()) { +          if (seenNextActions->find(ref.num)
>>> != seenNextActions->end()) {> 
>>>                error(errSyntaxWarning, -1, "parseAction: Circular next
>>>                actions detected in array."); return action;
>>>            
>>>            }
>>>
>>> -          seenNextActionsAux.insert(ref.num);
>>> +          seenNextActions->insert(ref.num);
>>>
>>>        }
>>>
>>> -      actionList->append(parseAction(&obj3, nullptr,
>>> &seenNextActionsAux)); +      actionList->append(parseAction(&obj3,
>>> nullptr, std::move(seenNextActions)));> 
>>>      }
>>>    
>>>    }
>>>
>>> diff --git a/poppler/Link.h b/poppler/Link.h
>>> index 806e30f6..77d224d9 100644
>>> --- a/poppler/Link.h
>>> +++ b/poppler/Link.h
>>> @@ -34,6 +34,7 @@
>>>
>>>  #endif
>>>  
>>>  #include "Object.h"
>>>
>>> +#include <memory>
>>>
>>>  #include <set>
>>>  
>>>  class GooString;
>>>
>>> @@ -85,7 +86,7 @@ public:
>>>    // Parse an action dictionary.
>>>    static LinkAction *parseAction(const Object *obj, const GooString
>>>    *baseURI = nullptr,> 
>>> -                                 const std::set<int> *seenNextActions =
>>> nullptr); +                                
>>> std::unique_ptr<std::set<int>> seenNextActions = nullptr);> 
>>>    // A List of the next actions to execute in order.
>>>    // The list contains pointer to LinkAction objects.
>>>
>>> commit bd9fb431941916174e1c3b2201bf5f422bcf61bd
>>> Author: Aleix Pol <aleixpol at kde.org>
>>> Date:   Mon Apr 16 16:38:09 2018 +0200
>>>
>>>     Make it possible to build poppler on Android without fontconfig
>>>     
>>>     Didn't manage to make fontconfig build, still nice to have poppler
>>>     available.
>>>
>>> diff --git a/CMakeLists.txt b/CMakeLists.txt
>>> index efa6c3f4..e2ebc44d 100644
>>> --- a/CMakeLists.txt
>>> +++ b/CMakeLists.txt
>>> @@ -89,10 +89,13 @@ endif()
>>>
>>>  if(WIN32)
>>>  
>>>    set(_default_fontconfiguration "win32")
>>>
>>> +elseif(ANDROID)
>>> +  # on android we don't have fontconfig and we don't want window-specific
>>> code +  set(_default_fontconfiguration "generic")
>>>
>>>  else()
>>>  
>>>    set(_default_fontconfiguration "fontconfig")
>>>  
>>>  endif()
>>>
>>> -set(FONT_CONFIGURATION "${_default_fontconfiguration}" CACHE STRING "The
>>> font configuration backend (win32|fontconfig).") +set(FONT_CONFIGURATION
>>> "${_default_fontconfiguration}" CACHE STRING "The font configuration
>>> backend (win32|generic|fontconfig).")> 
>>>  string(TOLOWER "${FONT_CONFIGURATION}" font_configuration)
>>>  set(WITH_FONTCONFIGURATION_WIN32 OFF)
>>>  set(WITH_FONTCONFIGURATION_FONTCONFIG OFF)
>>>
>>> @@ -100,6 +103,8 @@ if(font_configuration STREQUAL "win32")
>>>
>>>    set(WITH_FONTCONFIGURATION_WIN32 ON)
>>>  
>>>  elseif(font_configuration STREQUAL "fontconfig")
>>>  
>>>    set(WITH_FONTCONFIGURATION_FONTCONFIG ON)
>>>
>>> +elseif(font_configuration STREQUAL "generic")
>>> +  message(STATUS "no fontconfig or win32 specific code")
>>>
>>>  else()
>>>  
>>>    message(FATAL_ERROR "Invalid font configuration setting:
>>>    ${FONT_CONFIGURATION}")>  
>>>  endif()
>>>
>>> commit 34a44e5b95230b1ed03bb030e9963d0187b01951
>>> Author: Aleix Pol <aleixpol at kde.org>
>>> Date:   Mon Apr 16 16:35:47 2018 +0200
>>>
>>>     Do not assume that iconv is in /usr/include
>>>     
>>>     We find it explicitly because it may be elsewhere.
>>>
>>> diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt
>>> index ea252088..a08ee263 100644
>>> --- a/cpp/CMakeLists.txt
>>> +++ b/cpp/CMakeLists.txt
>>> @@ -1,6 +1,7 @@
>>>
>>>  include_directories(
>>>  
>>>    ${CMAKE_CURRENT_SOURCE_DIR}
>>>    ${CMAKE_CURRENT_BINARY_DIR}
>>>
>>> +  ${ICONV_INCLUDE_DIR}
>>>
>>>  )
>>>  
>>>  configure_file(poppler-version.h.in
>>>  ${CMAKE_CURRENT_BINARY_DIR}/poppler-version.h @ONLY)> 
>>> commit bdd8db389c7b09cd9042267f36214f809e4c5f60
>>> Author: Andre Heinecke <aheinecke at intevation.de>
>>> Date:   Mon Apr 16 17:13:05 2018 +0200
>>>
>>>     Add support for Next actions following an action
>>>     
>>>     Next actions are action dictionaries or an array
>>>     of action dictonaries. "Next" is an entry in the
>>>     general action dictionary.
>>>     
>>>     These actions are supposed to be performed after each other.
>>>     So that a single button press can for example
>>>     both trigger a Hide action and a JavaScript action.
>>>
>>> diff --git a/poppler/Link.cc b/poppler/Link.cc
>>> index a748d69e..2f853125 100644
>>> --- a/poppler/Link.cc
>>> +++ b/poppler/Link.cc
>>> @@ -52,6 +52,12 @@
>>>
>>>  //-----------------------------------------------------------------------
>>>  -
>>>  // LinkAction
>>>  //-----------------------------------------------------------------------
>>>  -
>>>
>>> +LinkAction::LinkAction() : nextActionList(nullptr) {
>>> +}
>>> +
>>> +LinkAction::~LinkAction() {
>>> +  delete nextActionList;
>>> +}
>>>
>>>  LinkAction *LinkAction::parseDest(const Object *obj) {
>>>  
>>>    LinkAction *action;
>>>
>>> @@ -64,7 +70,8 @@ LinkAction *LinkAction::parseDest(const Object *obj) {
>>>
>>>    return action;
>>>  
>>>  }
>>>
>>> -LinkAction *LinkAction::parseAction(const Object *obj, const GooString
>>> *baseURI) { +LinkAction *LinkAction::parseAction(const Object *obj, const
>>> GooString *baseURI, +                                    const
>>> std::set<int> *seenNextActions) {> 
>>>    LinkAction *action;
>>>    
>>>    if (!obj->isDict()) {
>>>
>>> @@ -140,9 +147,72 @@ LinkAction *LinkAction::parseAction(const Object
>>> *obj, const GooString *baseURI)> 
>>>      delete action;
>>>      return nullptr;
>>>    
>>>    }
>>>
>>> +
>>> +  if (!action) {
>>> +    return nullptr;
>>> +  }
>>> +
>>> +  // parse the next actions
>>> +  const Object nextObj = obj->dictLookup("Next");
>>> +  GooList *actionList = nullptr;
>>> +  if (nextObj.isDict()) {
>>> +
>>> +    // Prevent circles in the tree by checking the ref against used refs
>>> in +    // our current tree branch.
>>> +    const Object nextRefObj = obj->dictLookupNF("Next");
>>> +    std::set<int> seenNextActionsAux = seenNextActions ? *seenNextActions
>>> : std::set<int> (); +    if (nextRefObj.isRef()) {
>>> +        const Ref ref = nextRefObj.getRef();
>>> +        if (seenNextActionsAux.find(ref.num) != seenNextActionsAux.end())
>>> { +            error(errSyntaxWarning, -1, "parseAction: Circular next
>>> actions detected."); +            return action;
>>> +        }
>>> +        seenNextActionsAux.insert(ref.num);
>>> +    }
>>> +
>>> +    actionList = new GooList(1);
>>> +    actionList->append(parseAction(&nextObj, nullptr,
>>> &seenNextActionsAux)); +  } else if (nextObj.isArray()) {
>>> +    const Array *a = nextObj.getArray();
>>> +    const int n = a->getLength();
>>> +    actionList = new GooList(n);
>>> +    for (int i = 0; i < n; ++i) {
>>> +      const Object obj3 = a->get(i);
>>> +      if (!obj3.isDict()) {
>>> +        error(errSyntaxWarning, -1, "parseAction: Next array does not
>>> contain only dicts"); +        continue;
>>> +      }
>>> +
>>> +      // Similar circle check as above.
>>> +      std::set<int> seenNextActionsAux = seenNextActions ?
>>> *seenNextActions : std::set<int> (); +      const Object obj3Ref =
>>> a->getNF(i);
>>> +      if (obj3Ref.isRef()) {
>>> +          const Ref ref = obj3Ref.getRef();
>>> +          if (seenNextActionsAux.find(ref.num) !=
>>> seenNextActionsAux.end()) { +              error(errSyntaxWarning, -1,
>>> "parseAction: Circular next actions detected in array."); +             
>>> return action;
>>> +          }
>>> +          seenNextActionsAux.insert(ref.num);
>>> +      }
>>> +
>>> +      actionList->append(parseAction(&obj3, nullptr,
>>> &seenNextActionsAux)); +    }
>>> +  }
>>> +
>>> +  action->setNextActions(actionList);
>>> +
>>>
>>>    return action;
>>>  
>>>  }
>>>
>>> +const GooList *LinkAction::nextActions() const {
>>> +  return nextActionList;
>>> +}
>>> +
>>> +void LinkAction::setNextActions(GooList *actions) {
>>> +  delete nextActionList;
>>> +  nextActionList = actions;
>>> +}
>>> +
>>>
>>>  //-----------------------------------------------------------------------
>>>  -
>>>  // LinkDest
>>>  //-----------------------------------------------------------------------
>>>  -
>>>
>>> diff --git a/poppler/Link.h b/poppler/Link.h
>>> index 229a8431..806e30f6 100644
>>> --- a/poppler/Link.h
>>> +++ b/poppler/Link.h
>>> @@ -34,6 +34,7 @@
>>>
>>>  #endif
>>>  
>>>  #include "Object.h"
>>>
>>> +#include <set>
>>>
>>>  class GooString;
>>>  class GooList;
>>>
>>> @@ -66,12 +67,12 @@ enum LinkActionKind {
>>>
>>>  class LinkAction {
>>>
>>>  public:
>>> -  LinkAction() = default;
>>> +  LinkAction();
>>>
>>>    LinkAction(const LinkAction &) = delete;
>>>    LinkAction& operator=(const LinkAction &other) = delete;
>>>    
>>>    // Destructor.
>>>
>>> -  virtual ~LinkAction() {}
>>> +  virtual ~LinkAction();
>>>
>>>    // Was the LinkAction created successfully?
>>>    virtual GBool isOk() const = 0;
>>>
>>> @@ -83,7 +84,18 @@ public:
>>>    static LinkAction *parseDest(const Object *obj);
>>>    
>>>    // Parse an action dictionary.
>>>
>>> -  static LinkAction *parseAction(const Object *obj, const GooString
>>> *baseURI = NULL); +  static LinkAction *parseAction(const Object *obj,
>>> const GooString *baseURI = nullptr, +                                
>>> const std::set<int> *seenNextActions = nullptr); +
>>> +  // A List of the next actions to execute in order.
>>> +  // The list contains pointer to LinkAction objects.
>>> +  const GooList *nextActions() const;
>>> +
>>> +  // Sets the next action list. Takes ownership of the actions.
>>> +  void setNextActions(GooList *actions);
>>> +
>>> +private:
>>> +  GooList *nextActionList;
>>>
>>>  };
>>>  
>>>  //-----------------------------------------------------------------------
>>>  -
>>>
>>> diff --git a/qt5/src/poppler-link-private.h
>>> b/qt5/src/poppler-link-private.h index e54c8f86..766f1899 100644
>>> --- a/qt5/src/poppler-link-private.h
>>> +++ b/qt5/src/poppler-link-private.h
>>> @@ -24,6 +24,8 @@ class LinkOCGState;
>>>
>>>  namespace Poppler {
>>>
>>> +class Link;
>>> +
>>>
>>>  class LinkPrivate
>>>  {
>>>
>>>  public:
>>> @@ -34,12 +36,19 @@ public:
>>>      virtual ~LinkPrivate()
>>>      {
>>>
>>> +        qDeleteAll(nextLinks);
>>> +    }
>>> +
>>> +    static LinkPrivate *get( Link *link )
>>> +    {
>>> +        return link->d_ptr;
>>>
>>>      }
>>>      
>>>      LinkPrivate(const LinkPrivate &) = delete;
>>>      LinkPrivate& operator=(const LinkPrivate &) = delete;
>>>      
>>>      QRectF linkArea;
>>>
>>> +    QVector <Link *> nextLinks;
>>>
>>>  };
>>>
>>> diff --git a/qt5/src/poppler-link.cc b/qt5/src/poppler-link.cc
>>> index 1279e0b2..1086afce 100644
>>> --- a/qt5/src/poppler-link.cc
>>> +++ b/qt5/src/poppler-link.cc
>>> @@ -427,7 +427,12 @@ class LinkMoviePrivate : public LinkPrivate
>>>
>>>  		Q_D( const Link );
>>>  		return d->linkArea;
>>>  	
>>>  	}
>>>
>>> -
>>> +
>>> +	QVector< Link * > Link::nextLinks() const
>>> +	{
>>> +		return d_ptr->nextLinks;
>>> +	}
>>> +
>>>
>>>  	// LinkGoto
>>>  	LinkGoto::LinkGoto( const QRectF &linkArea, QString extFileName, 
> const
>>>  	LinkDestination & destination )>  	
>>>  		: Link( *new LinkGotoPrivate( linkArea, destination ) )
>>>
>>> diff --git a/qt5/src/poppler-link.h b/qt5/src/poppler-link.h
>>> index 5a59b6f3..0ce4c0d1 100644
>>> --- a/qt5/src/poppler-link.h
>>> +++ b/qt5/src/poppler-link.h
>>> @@ -29,6 +29,7 @@
>>>
>>>  #include <QtCore/QString>
>>>  #include <QtCore/QRectF>
>>>  #include <QtCore/QSharedDataPointer>
>>>
>>> +#include <QtCore/QVector>
>>>
>>>  #include "poppler-export.h"
>>>  
>>>  struct Ref;
>>>
>>> @@ -177,6 +178,7 @@ class POPPLER_QT5_EXPORT LinkDestination
>>>
>>>  class POPPLER_QT5_EXPORT Link
>>>  {
>>>  
>>>  	friend class OptContentModel;
>>>
>>> +	friend class LinkPrivate;
>>>
>>>  	public:
>>>  		/// \cond PRIVATE
>>>
>>> @@ -220,7 +222,14 @@ class POPPLER_QT5_EXPORT Link
>>>
>>>  		 * a general action. The area is given in 0..1 range
>>>  		 */
>>>  		
>>>  		QRectF linkArea() const;
>>>
>>> -
>>> +
>>> +		/**
>>> +		 * Get the next links to be activiated / executed after this 
> link.
>>> +		 *
>>> +		 * \since 0.64
>>> +		 */
>>> +		QVector<Link *> nextLinks() const;
>>> +
>>>
>>>  	protected:
>>>  		/// \cond PRIVATE
>>>  		Link( LinkPrivate &dd );
>>>
>>> diff --git a/qt5/src/poppler-page.cc b/qt5/src/poppler-page.cc
>>> index 3ed98846..b48ee959 100644
>>> --- a/qt5/src/poppler-page.cc
>>> +++ b/qt5/src/poppler-page.cc
>>> @@ -358,6 +358,20 @@ Link* PageData::convertLinkActionToLink(::LinkAction
>>> * a, DocumentData *parentDo> 
>>>      break;
>>>    
>>>    }
>>>
>>> +  if ( popplerLink )
>>> +  {
>>> +    const GooList *nextActions = a->nextActions();
>>> +    if ( nextActions )
>>> +    {
>>> +      QVector<Link *> links;
>>> +      for ( int i = 0; i < nextActions->getLength(); ++i )
>>> +      {
>>> +        links << convertLinkActionToLink( static_cast< ::LinkAction * >(
>>> nextActions->get( i ) ), parentDoc, linkArea ); +      }
>>> +      LinkPrivate::get(popplerLink)->nextLinks = links;
>>> +    }
>>> +  }
>>> +
>>>
>>>    return popplerLink;
>>>  
>>>  }
>>>
>>> commit ab72205dd14efe9c5c8d12e6b1ae538208bce168
>>> Author: Andre Heinecke <aheinecke at intevation.de>
>>> Date:   Mon Apr 16 16:31:38 2018 +0200
>>>
>>>     Add support for hide action
>>>     
>>>     The hide action can be used to show / hide fields.
>>>
>>> diff --git a/poppler/Link.cc b/poppler/Link.cc
>>> index 9be6a8c1..a748d69e 100644
>>> --- a/poppler/Link.cc
>>> +++ b/poppler/Link.cc
>>> @@ -21,6 +21,7 @@
>>>
>>>  // Copyright (C) 2009 Ilya Gorenbein <igorenbein at finjan.com>
>>>  // Copyright (C) 2012 Tobias Koening <tobias.koenig at kdab.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 Intevation GmbH <intevation at intevation.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> 
>>> @@ -120,6 +121,10 @@ LinkAction *LinkAction::parseAction(const Object
>>> *obj, const GooString *baseURI)> 
>>>    } else if (obj2.isName("SetOCGState")) {
>>>    
>>>      action = new LinkOCGState(obj);
>>>
>>> +  // Hide action
>>> +  } else if (obj2.isName("Hide")) {
>>> +    action = new LinkHide(obj);
>>> +
>>>
>>>    // unknown action
>>>    } else if (obj2.isName()) {
>>>    
>>>      action = new LinkUnknown(obj2.getName());
>>>
>>> @@ -811,6 +816,30 @@ LinkOCGState::StateList::~StateList() {
>>>
>>>  }
>>>  
>>>  //-----------------------------------------------------------------------
>>>  -
>>>
>>> +// LinkHide
>>> +//-----------------------------------------------------------------------
>>> -
>>> +
>>> +LinkHide::LinkHide(const Object *hideObj) {
>>> +  targetName = nullptr;
>>> +  show = false; // Default
>>> +
>>> +  if (hideObj->isDict()) {
>>> +      const Object targetObj = hideObj->dictLookup("T");
>>> +      if (targetObj.isString()) {
>>> +	targetName = targetObj.getString()->copy();
>>> +      }
>>> +      const Object shouldHide = hideObj->dictLookup("H");
>>> +      if (shouldHide.isBool()) {
>>> +	show = !shouldHide.getBool();
>>> +      }
>>> +  }
>>> +}
>>> +
>>> +LinkHide::~LinkHide() {
>>> +  delete targetName;
>>> +}
>>> +
>>> +//-----------------------------------------------------------------------
>>> -
>>>
>>>  // LinkUnknown
>>>  //-----------------------------------------------------------------------
>>>  -
>>>
>>> diff --git a/poppler/Link.h b/poppler/Link.h
>>> index 90496c42..229a8431 100644
>>> --- a/poppler/Link.h
>>> +++ b/poppler/Link.h
>>> @@ -19,6 +19,7 @@
>>>
>>>  // Copyright (C) 2012 Tobias Koening <tobias.koenig at kdab.com>
>>>  // Copyright (C) 2018 Albert Astals Cid <aacid at kde.org>
>>>  // 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>
>>>
>>>  //
>>>  // 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> 
>>> @@ -58,6 +59,7 @@ enum LinkActionKind {
>>>
>>>    actionSound,			// sound action
>>>    actionJavaScript,		// JavaScript action
>>>    actionOCGState,               // Set-OCG-State action
>>>
>>> +  actionHide,			// Hide action
>>>
>>>    actionUnknown			// anything else
>>>  
>>>  };
>>>
>>> @@ -452,6 +454,39 @@ private:
>>>  };
>>>  
>>>  //-----------------------------------------------------------------------
>>>  -
>>>
>>> +// LinkHide
>>> +//-----------------------------------------------------------------------
>>> -
>>> +
>>> +class LinkHide: public LinkAction {
>>> +public:
>>> +  LinkHide(const Object *hideObj);
>>> +
>>> +  ~LinkHide();
>>> +
>>> +  GBool isOk() const override { return targetName != nullptr; }
>>> +  LinkActionKind getKind() const override { return actionHide; }
>>> +
>>> +  // According to spec the target can be either:
>>> +  // a) A text string containing the fully qualified name of the target
>>> +  //    field.
>>> +  // b) An indirect reference to an annotation dictionary.
>>> +  // c) An array of "such dictionaries or text strings".
>>> +  //
>>> +  // While b / c appear to be very uncommon and can't easily be
>>> +  // created with Adobe Acrobat DC. So only support hide
>>> +  // actions with named targets (yet).
>>> +  GBool hasTargetName() const { return targetName != nullptr; }
>>> +  const GooString *getTargetName() const { return targetName; }
>>> +
>>> +  // Should this action show or hide.
>>> +  GBool isShowAction() const { return show; }
>>> +
>>> +private:
>>> +  GooString *targetName;
>>> +  GBool show;
>>> +};
>>> +
>>> +//-----------------------------------------------------------------------
>>> -
>>>
>>>  // LinkUnknown
>>>  //-----------------------------------------------------------------------
>>>  -
>>>
>>> diff --git a/qt5/src/poppler-annotation.cc b/qt5/src/poppler-annotation.cc
>>> index 6a2ec893..2394ffc5 100644
>>> --- a/qt5/src/poppler-annotation.cc
>>> +++ b/qt5/src/poppler-annotation.cc
>>> @@ -6,6 +6,7 @@
>>>
>>>   * Copyright (C) 2012, 2015, Tobias Koenig <tobias.koenig at kdab.com>
>>>   * 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>
>>>
>>>   * Adapting code from
>>>   *   Copyright (C) 2004 by Enrico Ros <eros.kde at email.it>
>>>   *
>>>
>>> @@ -3946,6 +3947,11 @@ void LinkAnnotation::store( QDomNode & node,
>>> QDomDocument & document ) const> 
>>>                  hyperlinkElement.setAttribute( QStringLiteral("type"),
>>>                  QStringLiteral("OCGState") ); break;
>>>              
>>>              }
>>>
>>> +            case Poppler::Link::Hide:
>>> +            {
>>> +                hyperlinkElement.setAttribute( QStringLiteral("type"),
>>> QStringLiteral("Hide") ); +                break;
>>> +            }
>>>
>>>              case Poppler::Link::None:
>>>                  break;
>>>          
>>>          }
>>>
>>> diff --git a/qt5/src/poppler-link-private.h
>>> b/qt5/src/poppler-link-private.h index 6bc5cb9f..e54c8f86 100644
>>> --- a/qt5/src/poppler-link-private.h
>>> +++ b/qt5/src/poppler-link-private.h
>>> @@ -1,5 +1,6 @@
>>>
>>>  /* poppler-link-private.h: qt interface to poppler
>>>  
>>>   * Copyright (C) 2016, 2018, Albert Astals Cid <aacid at kde.org>
>>>
>>> + * Copyright (C) 2018 Intevation GmbH <intevation at intevation.de>
>>>
>>>   *
>>>   * This program is free software; you can redistribute it and/or modify
>>>   * it under the terms of the GNU General Public License as published by
>>>
>>> @@ -55,6 +56,22 @@ public:
>>>      ::LinkOCGState *popplerLinkOCGState;
>>>  
>>>  };
>>>
>>> +
>>> +
>>> +class LinkHidePrivate : public LinkPrivate
>>> +{
>>> +public:
>>> +    LinkHidePrivate( const QRectF &area, const QString &tName, bool show
>>> )
>>> +        : LinkPrivate( area )
>>> +        , targetName( tName )
>>> +        , isShow( show )
>>> +    {
>>> +    }
>>> +
>>> +    QString targetName;
>>> +    bool isShow;
>>> +};
>>> +
>>>
>>>  }
>>>  
>>>  #endif
>>>
>>> diff --git a/qt5/src/poppler-link.cc b/qt5/src/poppler-link.cc
>>> index ffa3e74d..1279e0b2 100644
>>> --- a/qt5/src/poppler-link.cc
>>> +++ b/qt5/src/poppler-link.cc
>>> @@ -4,6 +4,7 @@
>>>
>>>   * Copyright (C) 2010 Hib Eris <hib at hiberis.nl>
>>>   * Copyright (C) 2012, Tobias Koenig <tokoe at kdab.com>
>>>   * Copyright (C) 2012, Guillermo A. Amaral B. <gamaral at kde.org>
>>>
>>> + * Copyright (C) 2018 Intevation GmbH <intevation at intevation.de>
>>>
>>>   * Adapting code from
>>>   *   Copyright (C) 2004 by Enrico Ros <eros.kde at email.it>
>>>   *
>>>
>>> @@ -704,4 +705,31 @@ class LinkMoviePrivate : public LinkPrivate
>>>
>>>  	{
>>>  	
>>>  		return OCGState;
>>>  	
>>>  	}
>>>
>>> +
>>> +	// LinkHide
>>> +	LinkHide::LinkHide( LinkHidePrivate *lhidep )
>>> +		: Link( *lhidep )
>>> +	{
>>> +	}
>>> +
>>> +	LinkHide::~LinkHide()
>>> +	{
>>> +	}
>>> +
>>> +	Link::LinkType LinkHide::linkType() const
>>> +	{
>>> +		return Hide;
>>> +	}
>>> +
>>> +	QVector < QString > LinkHide::targets() const
>>> +	{
>>> +		Q_D( const LinkHide );
>>> +		return QVector< QString >() << d->targetName;
>>> +	}
>>> +
>>> +	bool LinkHide::isShowAction() const
>>> +	{
>>> +		Q_D( const LinkHide );
>>> +		return d->isShow;
>>> +	}
>>>
>>>  }
>>>
>>> diff --git a/qt5/src/poppler-link.h b/qt5/src/poppler-link.h
>>> index 0753ce99..5a59b6f3 100644
>>> --- a/qt5/src/poppler-link.h
>>> +++ b/qt5/src/poppler-link.h
>>> @@ -4,6 +4,7 @@
>>>
>>>   * Copyright (C) 2010, 2012, Guillermo Amaral <gamaral at kdab.com>
>>>   * Copyright (C) 2012, Tobias Koenig <tokoe at kdab.com>
>>>   * Copyright (C) 2013, Anthony Granger <grangeranthony at gmail.com>
>>>
>>> + * Copyright (C) 2018 Intevation GmbH <intevation at intevation.de>
>>>
>>>   * Adapting code from
>>>   *   Copyright (C) 2004 by Enrico Ros <eros.kde at email.it>
>>>   *
>>>
>>> @@ -49,6 +50,7 @@ class LinkDestinationData;
>>>
>>>  class LinkDestinationPrivate;
>>>  class LinkRenditionPrivate;
>>>  class LinkOCGStatePrivate;
>>>
>>> +class LinkHidePrivate;
>>>
>>>  class MediaRendition;
>>>  class SoundObject;
>>>
>>> @@ -197,7 +199,8 @@ class POPPLER_QT5_EXPORT Link
>>>
>>>  		    Movie,    ///< An action to be executed on a movie
>>>  		    Rendition,    ///< A rendition link \since 0.20
>>>  		    JavaScript,   ///< A JavaScript code to be interpreted \since 
> 0.10
>>>
>>> -		    OCGState      ///< An Optional Content Group state change 
> \since
>>> 0.50 +		    OCGState,      ///< An Optional Content Group state 
> change
>>> \since 0.50 +		    Hide,     ///< An action to hide a field \since 0.64
>>>
>>>  		};
>>>  		
>>>  		/**
>>>
>>> @@ -627,6 +630,40 @@ class POPPLER_QT5_EXPORT LinkOCGState : public Link
>>>
>>>  		Q_DISABLE_COPY( LinkOCGState )
>>>  
>>>  };
>>>
>>> +/**
>>> + * Hide: an action to show / hide a field.
>>> + *
>>> + * \since 0.64
>>> + */
>>> +class POPPLER_QT5_EXPORT LinkHide: public Link
>>> +{
>>> +	public:
>>> +		/**
>>> +		 * Create a new Hide link. This is only used by Poppler::Page.
>>> +		 */
>>> +		LinkHide( LinkHidePrivate *lhidep );
>>> +		/**
>>> +		 * Destructor.
>>> +		 */
>>> +		~LinkHide();
>>> +
>>> +		LinkType linkType() const override;
>>> +
>>> +		/**
>>> +		 * The fully qualified target names of the action.
>>> +		 */
>>> +		QVector< QString > targets() const;
>>> +
>>> +		/**
>>> +		 * Should this action change the visibility of the target to 
> true.
>>> +		 */
>>> +		bool isShowAction() const;
>>> +
>>> +	private:
>>> +		Q_DECLARE_PRIVATE( LinkHide )
>>> +		Q_DISABLE_COPY( LinkHide )
>>> +};
>>> +
>>>
>>>  }
>>>  
>>>  #endif
>>>
>>> diff --git a/qt5/src/poppler-page.cc b/qt5/src/poppler-page.cc
>>> index 48dbe8ff..3ed98846 100644
>>> --- a/qt5/src/poppler-page.cc
>>> +++ b/qt5/src/poppler-page.cc
>>> @@ -20,6 +20,7 @@
>>>
>>>   * Copyright (C) 2017, 2018, Oliver Sander <oliver.sander at tu-dresden.de>
>>>   * Copyright (C) 2017 Adrian Johnson <ajohnson at redneon.com>
>>>   * Copyright (C) 2017, 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>
>>>
>>>   *
>>>   * This program is free software; you can redistribute it and/or modify
>>>   * it under the terms of the GNU General Public License as published by
>>>
>>> @@ -342,6 +343,16 @@ Link* PageData::convertLinkActionToLink(::LinkAction
>>> * a, DocumentData *parentDo> 
>>>        LinkOCGStatePrivate *locgp = new LinkOCGStatePrivate( linkArea,
>>>        plocg );
>>>        popplerLink = new LinkOCGState( locgp );
>>>      
>>>      }
>>>
>>> +    break;
>>> +
>>> +    case actionHide:
>>> +    {
>>> +      ::LinkHide *lh = (::LinkHide *)a;
>>> +
>>> +      LinkHidePrivate *lhp = new LinkHidePrivate( linkArea,
>>> lh->hasTargetName() ? UnicodeParsedString( lh->getTargetName() ) :
>>> QString(), lh->isShowAction() ); +      popplerLink = new LinkHide( lhp
>>> );
>>> +    }
>>> +    break;
>>>
>>>      case actionUnknown:
>>>      break;
>>>
>>> commit 022ccd4e1c61f4e89c7ffad83d9a5a896f65dc40
>>> Author: Albert Astals Cid <aacid at kde.org>
>>> Date:   Mon Apr 16 16:22:55 2018 +0200
>>>
>>>     GfxGouraudTriangleShading::parse: Fix memory leak on malformed files
>>>     
>>>     Bug #106059
>>>
>>> diff --git a/poppler/GfxState.cc b/poppler/GfxState.cc
>>> index 3d564138..95699355 100644
>>> --- a/poppler/GfxState.cc
>>> +++ b/poppler/GfxState.cc
>>> @@ -4922,6 +4922,9 @@ GfxGouraudTriangleShading
>>> *GfxGouraudTriangleShading::parse(GfxResources *res, i> 
>>>      trianglesA = (int (*)[3])gmallocn_checkoverflow(nTrianglesA * 3,
>>>      sizeof(int)); if (unlikely(!trianglesA)) {
>>>      
>>>        gfree(verticesA);
>>>
>>> +      for (i = 0; i < nFuncsA; ++i) {
>>> +	delete funcsA[i];
>>> +      }
>>>
>>>        return nullptr;
>>>      
>>>      }
>>>      k = 0;
>>>
>>> _______________________________________________
>>> poppler mailing list
>>> poppler at lists.freedesktop.org
>>> https://lists.freedesktop.org/mailman/listinfo/poppler
> 

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: OpenPGP digital signature
URL: <https://lists.freedesktop.org/archives/poppler/attachments/20180416/d041169a/attachment-0001.sig>


More information about the poppler mailing list