source: trunk/poppler/mypoppler/poppler/OptionalContent.cc @ 261

Last change on this file since 261 was 261, checked in by Eugene Romanenko, 13 years ago

PDF plugin: Poppler library updated to version 0.10.2

File size: 8.3 KB
Line 
1//========================================================================
2//
3// OptionalContent.cc
4//
5// Copyright 2007 Brad Hards <bradh@kde.org>
6// Copyright 2008 Pino Toscano <pino@kde.org>
7// Copyright 2008 Carlos Garcia Campos <carlosgc@gnome.org>
8// Copyright 2008 Albert Astals Cid <aacid@kde.org>
9// Copyright 2008 Mark Kaplan <mkaplan@finjan.com>
10//
11// Released under the GPL (version 2, or later, at your option)
12//
13//========================================================================
14
15#include <config.h>
16
17#ifdef USE_GCC_PRAGMAS
18#pragma implementation
19#endif
20
21#include "goo/gmem.h"
22#include "goo/GooString.h"
23#include "goo/GooList.h"
24#include "Error.h"
25// #include "PDFDocEncoding.h"
26#include "OptionalContent.h"
27
28//------------------------------------------------------------------------
29
30OCGs::OCGs(Object *ocgObject, XRef *xref) :
31  m_xref(xref)
32{
33  // we need to parse the dictionary here, and build optionalContentGroups
34  ok = gTrue;
35  optionalContentGroups = new GooList();
36
37  Object ocgList;
38  ocgObject->dictLookup("OCGs", &ocgList);
39  if (!ocgList.isArray()) {
40    error(-1, "Expected the optional content group list, but wasn't able to find it, or it isn't an Array");
41    ocgList.free();
42    ok = gFalse;
43    return;
44  }
45
46  // we now enumerate over the ocgList, and build up the optionalContentGroups list.
47  for(int i = 0; i < ocgList.arrayGetLength(); ++i) {
48    Object ocg;
49    ocgList.arrayGet(i, &ocg);
50    if (!ocg.isDict()) {
51      ocg.free();
52      break;
53    }
54    OptionalContentGroup *thisOptionalContentGroup = new OptionalContentGroup(ocg.getDict());
55    ocg.free();
56    ocgList.arrayGetNF(i, &ocg);
57    // TODO: we should create a lookup map from Ref to the OptionalContentGroup
58    thisOptionalContentGroup->setRef( ocg.getRef() );
59    ocg.free();
60    // the default is ON - we change state later, depending on BaseState, ON and OFF
61    thisOptionalContentGroup->setState(OptionalContentGroup::On);
62    optionalContentGroups->append(thisOptionalContentGroup);
63  }
64
65  Object defaultOcgConfig;
66  ocgObject->dictLookup("D", &defaultOcgConfig);
67  if (!defaultOcgConfig.isDict()) {
68    error(-1, "Expected the default config, but wasn't able to find it, or it isn't a Dictionary");
69    defaultOcgConfig.free();
70    ocgList.free();
71    ok = gFalse;
72    return;
73  }
74#if 0
75  // this is untested - we need an example showing BaseState
76  Object baseState;
77  defaultOcgConfig.dictLookup("BaseState", &baseState);
78  if (baseState.isString()) {
79    // read the value, and set each OptionalContentGroup entry appropriately
80  }
81  baseState.free();
82#endif
83  Object on;
84  defaultOcgConfig.dictLookup("ON", &on);
85  if (on.isArray()) {
86    // ON is an optional element
87    for (int i = 0; i < on.arrayGetLength(); ++i) {
88      Object reference;
89      on.arrayGetNF(i, &reference);
90      if (!reference.isRef()) {
91        // there can be null entries
92        reference.free();
93        break;
94      }
95      OptionalContentGroup *group = findOcgByRef( reference.getRef() );
96      reference.free();
97      if (!group) {
98        error(-1, "Couldn't find group for reference");
99        break;
100      }
101      group->setState(OptionalContentGroup::On);
102    }
103  }
104  on.free();
105
106  Object off;
107  defaultOcgConfig.dictLookup("OFF", &off);
108  if (off.isArray()) {
109    // OFF is an optional element
110    for (int i = 0; i < off.arrayGetLength(); ++i) {
111      Object reference;
112      off.arrayGetNF(i, &reference);
113      if (!reference.isRef()) {
114        // there can be null entries
115        reference.free();
116        break;
117      }
118      OptionalContentGroup *group = findOcgByRef( reference.getRef() );
119      reference.free();
120      if (!group) {
121        error(-1, "Couldn't find group for reference to set OFF");
122        break;
123      }
124      group->setState(OptionalContentGroup::Off);
125    }
126  }
127  off.free();
128
129  defaultOcgConfig.dictLookup("Order", &order);
130  defaultOcgConfig.dictLookup("RBGroups", &rbgroups);
131
132  ocgList.free();
133  defaultOcgConfig.free();
134}
135
136OCGs::~OCGs()
137{
138  deleteGooList(optionalContentGroups, OptionalContentGroup);
139  order.free();
140  rbgroups.free();
141}
142
143
144bool OCGs::hasOCGs()
145{
146  return ( optionalContentGroups->getLength() > 0 );
147}
148
149OptionalContentGroup* OCGs::findOcgByRef( const Ref &ref)
150{
151  //TODO: make this more efficient
152  OptionalContentGroup *ocg = NULL;
153  for (int i=0; i < optionalContentGroups->getLength(); ++i) {
154    ocg = (OptionalContentGroup*)optionalContentGroups->get(i);
155    if ( (ocg->getRef().num == ref.num) && (ocg->getRef().gen == ref.gen) ) {
156      return ocg;
157    }
158  }
159
160  error(-1, "Could not find a OCG with Ref (%d:%d)", ref.num, ref.gen);
161
162  // not found
163  return NULL;
164}
165
166bool OCGs::optContentIsVisible( Object *dictRef )
167{
168  Object dictObj;
169  Dict *dict;
170  Object dictType;
171  Object ocg;
172  Object policy;
173  bool result = true;
174  dictRef->fetch( m_xref, &dictObj );
175  if ( ! dictObj.isDict() ) {
176    error(-1, "Unexpected oc reference target: %i", dictObj.getType() );
177    dictObj.free();
178    return result;
179  }
180  dict = dictObj.getDict();
181  // printf("checking if optContent is visible\n");
182  dict->lookup("Type", &dictType);
183  if (dictType.isName("OCMD")) {
184    // If we supported Visibility Expressions, we'd check
185    // for a VE entry, and then call out to the parser here...
186    // printf("found OCMD dict\n");
187    dict->lookup("P", &policy);
188    dict->lookupNF("OCGs", &ocg);
189    if (ocg.isArray()) {
190      if (policy.isName("AllOn")) {
191        result = allOn( ocg.getArray() );
192      } else if (policy.isName("AllOff")) {
193        result = allOff( ocg.getArray() );
194      } else if (policy.isName("AnyOff")) {
195        result = anyOff( ocg.getArray() );
196      } else if ( (!policy.isName()) || (policy.isName("AnyOn") ) ) {
197        // this is the default
198        result = anyOn( ocg.getArray() );
199      }
200    } else if (ocg.isRef()) {
201      OptionalContentGroup* oc = findOcgByRef( ocg.getRef() );     
202      if ( !oc || oc->getState() == OptionalContentGroup::Off ) {
203        result = false;
204      } else {
205        result = true ;
206      }
207    }
208    ocg.free();
209    policy.free();
210  } else if ( dictType.isName("OCG") ) {
211    OptionalContentGroup* oc = findOcgByRef( dictRef->getRef() );
212    if ( !oc || oc->getState() == OptionalContentGroup::Off ) {
213      result=false;
214    }
215  }
216  dictType.free();
217  dictObj.free();
218  // printf("visibility: %s\n", result? "on" : "off");
219  return result;
220}
221
222bool OCGs::allOn( Array *ocgArray )
223{
224  for (int i = 0; i < ocgArray->getLength(); ++i) {
225    Object ocgItem;
226    ocgArray->getNF(i, &ocgItem);
227    if (ocgItem.isRef()) {
228      OptionalContentGroup* oc = findOcgByRef( ocgItem.getRef() );     
229      if ( oc && oc->getState() == OptionalContentGroup::Off ) {
230        return false;
231      }
232    }
233  }
234  return true;
235}
236
237bool OCGs::allOff( Array *ocgArray )
238{
239  for (int i = 0; i < ocgArray->getLength(); ++i) {
240    Object ocgItem;
241    ocgArray->getNF(i, &ocgItem);
242    if (ocgItem.isRef()) {
243      OptionalContentGroup* oc = findOcgByRef( ocgItem.getRef() );     
244      if ( oc && oc->getState() == OptionalContentGroup::On ) {
245        return false;
246      }
247    }
248  }
249  return true;
250}
251
252bool OCGs::anyOn( Array *ocgArray )
253{
254  for (int i = 0; i < ocgArray->getLength(); ++i) {
255    Object ocgItem;
256    ocgArray->getNF(i, &ocgItem);
257    if (ocgItem.isRef()) {
258      OptionalContentGroup* oc = findOcgByRef( ocgItem.getRef() );     
259      if ( oc && oc->getState() == OptionalContentGroup::On ) {
260        return true;
261      }
262    }
263  }
264  return false;
265}
266
267bool OCGs::anyOff( Array *ocgArray )
268{
269  for (int i = 0; i < ocgArray->getLength(); ++i) {
270    Object ocgItem;
271    ocgArray->getNF(i, &ocgItem);
272    if (ocgItem.isRef()) {
273      OptionalContentGroup* oc = findOcgByRef( ocgItem.getRef() );     
274      if ( oc && oc->getState() == OptionalContentGroup::Off ) {
275        return true;
276      }
277    }
278  }
279  return false;
280}
281
282//------------------------------------------------------------------------
283
284OptionalContentGroup::OptionalContentGroup(Dict *ocgDict) : m_name(NULL)
285{
286  Object ocgName;
287  ocgDict->lookup("Name", &ocgName);
288  if (!ocgName.isString()) {
289    error(-1, "Expected the name of the OCG, but wasn't able to find it, or it isn't a String");
290  } else {
291    m_name = new GooString( ocgName.getString() );
292  }
293  ocgName.free();
294}
295
296OptionalContentGroup::OptionalContentGroup(GooString *label)
297{
298  m_name = label;
299  m_state = On;
300}
301
302GooString* OptionalContentGroup::getName() const
303{
304  return m_name;
305}
306
307void OptionalContentGroup::setRef(const Ref ref)
308{
309  m_ref = ref;
310}
311
312Ref OptionalContentGroup::getRef() const
313{
314  return m_ref;
315}
316
317OptionalContentGroup::~OptionalContentGroup()
318{
319  delete m_name;
320}
321
Note: See TracBrowser for help on using the repository browser.