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

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

PDF plugin: Poppler library updated to version 0.10.0

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