summaryrefslogtreecommitdiff
path: root/poppler/OptionalContent.h
blob: c383262c738cc208334ce0bd4f0080ad4ff09f95 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
//========================================================================
//
// OptionalContent.h
//
// Copyright 2007 Brad Hards <bradh@kde.org>
// Copyright 2008 Carlos Garcia Campos <carlosgc@gnome.org>
// Copyright 2013, 2018 Albert Astals Cid <aacid@kde.org>
// Copyright 2018 Adam Reichold <adam.reichold@t-online.de>
//
// Released under the GPL (version 2, or later, at your option)
//
//========================================================================

#ifndef OPTIONALCONTENT_H
#define OPTIONALCONTENT_H

#include "Object.h"
#include "CharTypes.h"
#include <unordered_map>
#include <memory>

class GooString;
class GooList;
class XRef;

class OptionalContentGroup;
class OCDisplayNode;

//------------------------------------------------------------------------

class OCGs {
public:

  OCGs(Object *ocgObject, XRef *xref);

  OCGs(const OCGs &) = delete;
  OCGs& operator=(const OCGs &) = delete;

  // Is OCGS valid?
  bool isOk() const { return ok; }
  
  bool hasOCGs() const;
  const std::unordered_map< Ref, std::unique_ptr< OptionalContentGroup > > &getOCGs() const { return optionalContentGroups; }

  OptionalContentGroup* findOcgByRef( const Ref ref);

  // Get the root node of the optional content group display tree
  // (which does not necessarily include all of the OCGs).
  OCDisplayNode *getDisplayRoot();

  Array* getOrderArray() 
    { return (order.isArray() && order.arrayGetLength() > 0) ? order.getArray() : nullptr; }
  Array* getRBGroupsArray() 
    { return (rbgroups.isArray() && rbgroups.arrayGetLength()) ? rbgroups.getArray() : nullptr; }

  bool optContentIsVisible( Object *dictRef );

private:
  bool ok;

  bool evalOCVisibilityExpr(Object *expr, int recursion);
  bool allOn( Array *ocgArray );
  bool allOff( Array *ocgArray );
  bool anyOn( Array *ocgArray );
  bool anyOff( Array *ocgArray );

  std::unordered_map< Ref, std::unique_ptr< OptionalContentGroup > > optionalContentGroups;

  Object order;
  Object rbgroups;
  XRef *m_xref;
  std::unique_ptr< OCDisplayNode > display; // root node of display tree
};

//------------------------------------------------------------------------

class OptionalContentGroup {
public:
  enum State { On, Off };

  // Values from the optional content usage dictionary.
  enum UsageState {
    ocUsageOn,
    ocUsageOff,
    ocUsageUnset
  };

  OptionalContentGroup(Dict *dict);

  OptionalContentGroup(GooString *label);

  ~OptionalContentGroup();

  OptionalContentGroup(const OptionalContentGroup &) = delete;
  OptionalContentGroup& operator=(const OptionalContentGroup &) = delete;

  const GooString* getName() const;

  Ref getRef() const;
  void setRef(const Ref ref);

  State getState() { return m_state; };
  void setState(State state) { m_state = state; };

  UsageState getViewState() { return viewState; }
  UsageState getPrintState() { return printState; }

private:
  GooString *m_name;
  Ref m_ref;
  State m_state;
  UsageState viewState;	 // suggested state when viewing
  UsageState printState; // suggested state when printing
};

//------------------------------------------------------------------------

class OCDisplayNode {
public:

  static OCDisplayNode *parse(Object *obj, OCGs *oc, XRef *xref, int recursion = 0);
  OCDisplayNode();
  ~OCDisplayNode();

  OCDisplayNode(const OCDisplayNode &) = delete;
  OCDisplayNode& operator=(const OCDisplayNode &) = delete;

  const GooString *getName() const { return name; }
  const OptionalContentGroup *getOCG() const { return ocg; }
  int getNumChildren() const;
  OCDisplayNode *getChild(int idx) const;

private:

  OCDisplayNode(const GooString *nameA);
  OCDisplayNode(OptionalContentGroup *ocgA);
  void addChild(OCDisplayNode *child);
  void addChildren(GooList *childrenA);
  GooList *takeChildren();

  GooString *name;		// display name (may be nullptr)
  OptionalContentGroup *ocg;	// nullptr for display labels
  GooList *children;		// nullptr if there are no children
				//   [OCDisplayNode]
};

#endif