Remove default argument from CPDF_Dictionary::SetAt().
[pdfium.git] / core / src / fpdfdoc / doc_ocg.cpp
1 // Copyright 2014 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7 #include "../../include/fpdfdoc/fpdf_doc.h"
8 static int32_t FPDFDOC_OCG_FindGroup(const CPDF_Object* pObject,
9                                      const CPDF_Dictionary* pGroupDict) {
10   if (!pObject || !pGroupDict)
11     return -1;
12
13   if (const CPDF_Array* pArray = pObject->AsArray()) {
14     FX_DWORD dwCount = pArray->GetCount();
15     for (FX_DWORD i = 0; i < dwCount; i++) {
16       if (pArray->GetDict(i) == pGroupDict)
17         return i;
18     }
19     return -1;
20   }
21   return pObject->GetDict() == pGroupDict ? 0 : -1;
22 }
23 static FX_BOOL FPDFDOC_OCG_HasIntent(
24     const CPDF_Dictionary* pDict,
25     const CFX_ByteStringC& csElement,
26     const CFX_ByteStringC& csDef = FX_BSTRC("")) {
27   FXSYS_assert(pDict != NULL);
28   CPDF_Object* pIntent = pDict->GetElementValue(FX_BSTRC("Intent"));
29   if (pIntent == NULL) {
30     return csElement == csDef;
31   }
32   CFX_ByteString bsIntent;
33   if (CPDF_Array* pArray = pIntent->AsArray()) {
34     FX_DWORD dwCount = pArray->GetCount();
35     for (FX_DWORD i = 0; i < dwCount; i++) {
36       bsIntent = pArray->GetString(i);
37       if (bsIntent == FX_BSTRC("All") || bsIntent == csElement)
38         return TRUE;
39     }
40     return FALSE;
41   }
42   bsIntent = pIntent->GetString();
43   return bsIntent == FX_BSTRC("All") || bsIntent == csElement;
44 }
45 static CPDF_Dictionary* FPDFDOC_OCG_GetConfig(CPDF_Document* pDoc,
46                                               const CPDF_Dictionary* pOCGDict,
47                                               const CFX_ByteStringC& bsState) {
48   FXSYS_assert(pDoc && pOCGDict);
49   CPDF_Dictionary* pOCProperties =
50       pDoc->GetRoot()->GetDict(FX_BSTRC("OCProperties"));
51   if (!pOCProperties) {
52     return NULL;
53   }
54   CPDF_Array* pOCGs = pOCProperties->GetArray(FX_BSTRC("OCGs"));
55   if (!pOCGs) {
56     return NULL;
57   }
58   if (FPDFDOC_OCG_FindGroup(pOCGs, pOCGDict) < 0) {
59     return NULL;
60   }
61   CPDF_Dictionary* pConfig = pOCProperties->GetDict(FX_BSTRC("D"));
62   CPDF_Array* pConfigs = pOCProperties->GetArray(FX_BSTRC("Configs"));
63   if (pConfigs) {
64     CPDF_Dictionary* pFind;
65     int32_t iCount = pConfigs->GetCount();
66     for (int32_t i = 0; i < iCount; i++) {
67       pFind = pConfigs->GetDict(i);
68       if (!pFind) {
69         continue;
70       }
71       if (!FPDFDOC_OCG_HasIntent(pFind, FX_BSTRC("View"), FX_BSTRC("View"))) {
72         continue;
73       }
74       pConfig = pFind;
75       break;
76     }
77   }
78   return pConfig;
79 }
80 static CFX_ByteString FPDFDOC_OCG_GetUsageTypeString(
81     CPDF_OCContext::UsageType eType) {
82   CFX_ByteString csState = FX_BSTRC("View");
83   if (eType == CPDF_OCContext::Design) {
84     csState = FX_BSTRC("Design");
85   } else if (eType == CPDF_OCContext::Print) {
86     csState = FX_BSTRC("Print");
87   } else if (eType == CPDF_OCContext::Export) {
88     csState = FX_BSTRC("Export");
89   }
90   return csState;
91 }
92 CPDF_OCContext::CPDF_OCContext(CPDF_Document* pDoc, UsageType eUsageType) {
93   FXSYS_assert(pDoc != NULL);
94   m_pDocument = pDoc;
95   m_eUsageType = eUsageType;
96 }
97 CPDF_OCContext::~CPDF_OCContext() {
98   m_OCGStates.clear();
99 }
100 FX_BOOL CPDF_OCContext::LoadOCGStateFromConfig(const CFX_ByteStringC& csConfig,
101                                                const CPDF_Dictionary* pOCGDict,
102                                                FX_BOOL& bValidConfig) const {
103   CPDF_Dictionary* pConfig =
104       FPDFDOC_OCG_GetConfig(m_pDocument, pOCGDict, csConfig);
105   if (!pConfig) {
106     return TRUE;
107   }
108   bValidConfig = TRUE;
109   FX_BOOL bState = pConfig->GetString(FX_BSTRC("BaseState"), FX_BSTRC("ON")) !=
110                    FX_BSTRC("OFF");
111   CPDF_Array* pArray = pConfig->GetArray(FX_BSTRC("ON"));
112   if (pArray) {
113     if (FPDFDOC_OCG_FindGroup(pArray, pOCGDict) >= 0) {
114       bState = TRUE;
115     }
116   }
117   pArray = pConfig->GetArray(FX_BSTRC("OFF"));
118   if (pArray) {
119     if (FPDFDOC_OCG_FindGroup(pArray, pOCGDict) >= 0) {
120       bState = FALSE;
121     }
122   }
123   pArray = pConfig->GetArray(FX_BSTRC("AS"));
124   if (pArray) {
125     CFX_ByteString csFind = csConfig + FX_BSTRC("State");
126     int32_t iCount = pArray->GetCount();
127     for (int32_t i = 0; i < iCount; i++) {
128       CPDF_Dictionary* pUsage = pArray->GetDict(i);
129       if (!pUsage) {
130         continue;
131       }
132       if (pUsage->GetString(FX_BSTRC("Event"), FX_BSTRC("View")) != csConfig) {
133         continue;
134       }
135       CPDF_Array* pOCGs = pUsage->GetArray(FX_BSTRC("OCGs"));
136       if (!pOCGs) {
137         continue;
138       }
139       if (FPDFDOC_OCG_FindGroup(pOCGs, pOCGDict) < 0) {
140         continue;
141       }
142       CPDF_Dictionary* pState = pUsage->GetDict(csConfig);
143       if (!pState) {
144         continue;
145       }
146       bState = pState->GetString(csFind) != FX_BSTRC("OFF");
147     }
148   }
149   return bState;
150 }
151 FX_BOOL CPDF_OCContext::LoadOCGState(const CPDF_Dictionary* pOCGDict) const {
152   if (!FPDFDOC_OCG_HasIntent(pOCGDict, FX_BSTRC("View"), FX_BSTRC("View"))) {
153     return TRUE;
154   }
155   CFX_ByteString csState = FPDFDOC_OCG_GetUsageTypeString(m_eUsageType);
156   CPDF_Dictionary* pUsage = pOCGDict->GetDict(FX_BSTRC("Usage"));
157   if (pUsage) {
158     CPDF_Dictionary* pState = pUsage->GetDict(csState);
159     if (pState) {
160       CFX_ByteString csFind = csState + FX_BSTRC("State");
161       if (pState->KeyExist(csFind)) {
162         return pState->GetString(csFind) != FX_BSTRC("OFF");
163       }
164     }
165     if (csState != FX_BSTRC("View")) {
166       pState = pUsage->GetDict(FX_BSTRC("View"));
167       if (pState && pState->KeyExist(FX_BSTRC("ViewState"))) {
168         return pState->GetString(FX_BSTRC("ViewState")) != FX_BSTRC("OFF");
169       }
170     }
171   }
172   FX_BOOL bDefValid = FALSE;
173   return LoadOCGStateFromConfig(csState, pOCGDict, bDefValid);
174 }
175
176 FX_BOOL CPDF_OCContext::GetOCGVisible(const CPDF_Dictionary* pOCGDict) {
177   if (!pOCGDict)
178     return FALSE;
179
180   const auto it = m_OCGStates.find(pOCGDict);
181   if (it != m_OCGStates.end())
182     return it->second;
183
184   FX_BOOL bState = LoadOCGState(pOCGDict);
185   m_OCGStates[pOCGDict] = bState;
186   return bState;
187 }
188
189 FX_BOOL CPDF_OCContext::GetOCGVE(CPDF_Array* pExpression,
190                                  FX_BOOL bFromConfig,
191                                  int nLevel) {
192   if (nLevel > 32) {
193     return FALSE;
194   }
195   if (pExpression == NULL) {
196     return FALSE;
197   }
198   int32_t iCount = pExpression->GetCount();
199   CPDF_Object* pOCGObj;
200   CFX_ByteString csOperator = pExpression->GetString(0);
201   if (csOperator == FX_BSTRC("Not")) {
202     pOCGObj = pExpression->GetElementValue(1);
203     if (!pOCGObj)
204       return FALSE;
205     if (CPDF_Dictionary* pDict = pOCGObj->AsDictionary())
206       return !(bFromConfig ? LoadOCGState(pDict) : GetOCGVisible(pDict));
207     if (CPDF_Array* pArray = pOCGObj->AsArray())
208       return !GetOCGVE(pArray, bFromConfig, nLevel + 1);
209     return FALSE;
210   }
211   if (csOperator == FX_BSTRC("Or") || csOperator == FX_BSTRC("And")) {
212     FX_BOOL bValue = FALSE;
213     for (int32_t i = 1; i < iCount; i++) {
214       pOCGObj = pExpression->GetElementValue(1);
215       if (pOCGObj == NULL) {
216         continue;
217       }
218       FX_BOOL bItem = FALSE;
219       if (CPDF_Dictionary* pDict = pOCGObj->AsDictionary())
220         bItem = bFromConfig ? LoadOCGState(pDict) : GetOCGVisible(pDict);
221       else if (CPDF_Array* pArray = pOCGObj->AsArray())
222         bItem = GetOCGVE(pArray, bFromConfig, nLevel + 1);
223
224       if (i == 1) {
225         bValue = bItem;
226       } else {
227         if (csOperator == FX_BSTRC("Or")) {
228           bValue = bValue || bItem;
229         } else {
230           bValue = bValue && bItem;
231         }
232       }
233     }
234     return bValue;
235   }
236   return FALSE;
237 }
238 FX_BOOL CPDF_OCContext::LoadOCMDState(const CPDF_Dictionary* pOCMDDict,
239                                       FX_BOOL bFromConfig) {
240   FXSYS_assert(pOCMDDict != NULL);
241   CPDF_Array* pVE = pOCMDDict->GetArray(FX_BSTRC("VE"));
242   if (pVE != NULL) {
243     return GetOCGVE(pVE, bFromConfig);
244   }
245   CFX_ByteString csP = pOCMDDict->GetString(FX_BSTRC("P"), FX_BSTRC("AnyOn"));
246   CPDF_Object* pOCGObj = pOCMDDict->GetElementValue(FX_BSTRC("OCGs"));
247   if (!pOCGObj)
248     return TRUE;
249   if (const CPDF_Dictionary* pDict = pOCGObj->AsDictionary())
250     return bFromConfig ? LoadOCGState(pDict) : GetOCGVisible(pDict);
251
252   CPDF_Array* pArray = pOCGObj->AsArray();
253   if (!pArray)
254     return TRUE;
255
256   FX_BOOL bState = FALSE;
257   if (csP == FX_BSTRC("AllOn") || csP == FX_BSTRC("AllOff")) {
258     bState = TRUE;
259   }
260   int32_t iCount = pArray->GetCount();
261   for (int32_t i = 0; i < iCount; i++) {
262     FX_BOOL bItem = TRUE;
263     CPDF_Dictionary* pItemDict = pArray->GetDict(i);
264     if (pItemDict)
265       bItem = bFromConfig ? LoadOCGState(pItemDict) : GetOCGVisible(pItemDict);
266
267     if ((csP == FX_BSTRC("AnyOn") && bItem) ||
268         (csP == FX_BSTRC("AnyOff") && !bItem))
269       return TRUE;
270     if ((csP == FX_BSTRC("AllOn") && !bItem) ||
271         (csP == FX_BSTRC("AllOff") && bItem))
272       return FALSE;
273   }
274   return bState;
275 }
276 FX_BOOL CPDF_OCContext::CheckOCGVisible(const CPDF_Dictionary* pOCGDict) {
277   if (!pOCGDict) {
278     return TRUE;
279   }
280   CFX_ByteString csType =
281       pOCGDict->GetString(FX_BSTRC("Type"), FX_BSTRC("OCG"));
282   if (csType == FX_BSTRC("OCG")) {
283     return GetOCGVisible(pOCGDict);
284   }
285   return LoadOCMDState(pOCGDict, FALSE);
286 }
287 void CPDF_OCContext::ResetOCContext() {
288   m_OCGStates.clear();
289 }