OLD | NEW |
| (Empty) |
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 "core/fpdfdoc/include/cpdf_occontext.h" | |
8 | |
9 #include "core/fpdfapi/fpdf_page/cpdf_contentmarkdata.h" | |
10 #include "core/fpdfapi/fpdf_page/include/cpdf_pageobject.h" | |
11 #include "core/fpdfapi/fpdf_parser/include/cpdf_array.h" | |
12 #include "core/fpdfapi/fpdf_parser/include/cpdf_document.h" | |
13 | |
14 namespace { | |
15 | |
16 int32_t FPDFDOC_OCG_FindGroup(const CPDF_Array* pArray, | |
17 const CPDF_Dictionary* pGroupDict) { | |
18 if (!pArray || !pGroupDict) | |
19 return -1; | |
20 | |
21 for (size_t i = 0; i < pArray->GetCount(); i++) { | |
22 if (pArray->GetDictAt(i) == pGroupDict) | |
23 return i; | |
24 } | |
25 return -1; | |
26 } | |
27 | |
28 bool FPDFDOC_OCG_HasIntent(const CPDF_Dictionary* pDict, | |
29 const CFX_ByteStringC& csElement, | |
30 const CFX_ByteStringC& csDef) { | |
31 CPDF_Object* pIntent = pDict->GetDirectObjectBy("Intent"); | |
32 if (!pIntent) | |
33 return csElement == csDef; | |
34 | |
35 CFX_ByteString bsIntent; | |
36 if (CPDF_Array* pArray = pIntent->AsArray()) { | |
37 for (size_t i = 0; i < pArray->GetCount(); i++) { | |
38 bsIntent = pArray->GetStringAt(i); | |
39 if (bsIntent == "All" || bsIntent == csElement) | |
40 return true; | |
41 } | |
42 return false; | |
43 } | |
44 bsIntent = pIntent->GetString(); | |
45 return bsIntent == "All" || bsIntent == csElement; | |
46 } | |
47 | |
48 CPDF_Dictionary* FPDFDOC_OCG_GetConfig(CPDF_Document* pDoc, | |
49 const CPDF_Dictionary* pOCGDict) { | |
50 ASSERT(pOCGDict); | |
51 CPDF_Dictionary* pOCProperties = pDoc->GetRoot()->GetDictBy("OCProperties"); | |
52 if (!pOCProperties) | |
53 return nullptr; | |
54 | |
55 CPDF_Array* pOCGs = pOCProperties->GetArrayBy("OCGs"); | |
56 if (!pOCGs) | |
57 return nullptr; | |
58 | |
59 if (FPDFDOC_OCG_FindGroup(pOCGs, pOCGDict) < 0) | |
60 return nullptr; | |
61 | |
62 CPDF_Dictionary* pConfig = pOCProperties->GetDictBy("D"); | |
63 CPDF_Array* pConfigs = pOCProperties->GetArrayBy("Configs"); | |
64 if (!pConfigs) | |
65 return pConfig; | |
66 | |
67 for (size_t i = 0; i < pConfigs->GetCount(); i++) { | |
68 CPDF_Dictionary* pFind = pConfigs->GetDictAt(i); | |
69 if (pFind && FPDFDOC_OCG_HasIntent(pFind, "View", "View")) | |
70 return pFind; | |
71 } | |
72 return pConfig; | |
73 } | |
74 | |
75 CFX_ByteString FPDFDOC_OCG_GetUsageTypeString(CPDF_OCContext::UsageType eType) { | |
76 CFX_ByteString csState; | |
77 switch (eType) { | |
78 case CPDF_OCContext::Design: | |
79 csState = "Design"; | |
80 break; | |
81 case CPDF_OCContext::Print: | |
82 csState = "Print"; | |
83 break; | |
84 case CPDF_OCContext::Export: | |
85 csState = "Export"; | |
86 break; | |
87 default: | |
88 csState = "View"; | |
89 break; | |
90 } | |
91 return csState; | |
92 } | |
93 | |
94 } // namespace | |
95 | |
96 CPDF_OCContext::CPDF_OCContext(CPDF_Document* pDoc, UsageType eUsageType) | |
97 : m_pDocument(pDoc), m_eUsageType(eUsageType) { | |
98 ASSERT(pDoc); | |
99 } | |
100 | |
101 CPDF_OCContext::~CPDF_OCContext() { | |
102 } | |
103 | |
104 bool CPDF_OCContext::LoadOCGStateFromConfig( | |
105 const CFX_ByteString& csConfig, | |
106 const CPDF_Dictionary* pOCGDict) const { | |
107 CPDF_Dictionary* pConfig = FPDFDOC_OCG_GetConfig(m_pDocument, pOCGDict); | |
108 if (!pConfig) | |
109 return true; | |
110 | |
111 bool bState = pConfig->GetStringBy("BaseState", "ON") != "OFF"; | |
112 CPDF_Array* pArray = pConfig->GetArrayBy("ON"); | |
113 if (pArray) { | |
114 if (FPDFDOC_OCG_FindGroup(pArray, pOCGDict) >= 0) | |
115 bState = true; | |
116 } | |
117 pArray = pConfig->GetArrayBy("OFF"); | |
118 if (pArray) { | |
119 if (FPDFDOC_OCG_FindGroup(pArray, pOCGDict) >= 0) | |
120 bState = false; | |
121 } | |
122 pArray = pConfig->GetArrayBy("AS"); | |
123 if (!pArray) | |
124 return bState; | |
125 | |
126 CFX_ByteString csFind = csConfig + "State"; | |
127 for (size_t i = 0; i < pArray->GetCount(); i++) { | |
128 CPDF_Dictionary* pUsage = pArray->GetDictAt(i); | |
129 if (!pUsage) | |
130 continue; | |
131 | |
132 if (pUsage->GetStringBy("Event", "View") != csConfig) | |
133 continue; | |
134 | |
135 CPDF_Array* pOCGs = pUsage->GetArrayBy("OCGs"); | |
136 if (!pOCGs) | |
137 continue; | |
138 | |
139 if (FPDFDOC_OCG_FindGroup(pOCGs, pOCGDict) < 0) | |
140 continue; | |
141 | |
142 CPDF_Dictionary* pState = pUsage->GetDictBy(csConfig); | |
143 if (!pState) | |
144 continue; | |
145 | |
146 bState = pState->GetStringBy(csFind) != "OFF"; | |
147 } | |
148 return bState; | |
149 } | |
150 | |
151 bool CPDF_OCContext::LoadOCGState(const CPDF_Dictionary* pOCGDict) const { | |
152 if (!FPDFDOC_OCG_HasIntent(pOCGDict, "View", "View")) | |
153 return true; | |
154 | |
155 CFX_ByteString csState = FPDFDOC_OCG_GetUsageTypeString(m_eUsageType); | |
156 CPDF_Dictionary* pUsage = pOCGDict->GetDictBy("Usage"); | |
157 if (pUsage) { | |
158 CPDF_Dictionary* pState = pUsage->GetDictBy(csState); | |
159 if (pState) { | |
160 CFX_ByteString csFind = csState + "State"; | |
161 if (pState->KeyExist(csFind)) { | |
162 return pState->GetStringBy(csFind) != "OFF"; | |
163 } | |
164 } | |
165 if (csState != "View") { | |
166 pState = pUsage->GetDictBy("View"); | |
167 if (pState && pState->KeyExist("ViewState")) { | |
168 return pState->GetStringBy("ViewState") != "OFF"; | |
169 } | |
170 } | |
171 } | |
172 return LoadOCGStateFromConfig(csState, pOCGDict); | |
173 } | |
174 | |
175 bool CPDF_OCContext::GetOCGVisible(const CPDF_Dictionary* pOCGDict) { | |
176 if (!pOCGDict) | |
177 return false; | |
178 | |
179 const auto it = m_OCGStates.find(pOCGDict); | |
180 if (it != m_OCGStates.end()) | |
181 return it->second; | |
182 | |
183 bool bState = LoadOCGState(pOCGDict); | |
184 m_OCGStates[pOCGDict] = bState; | |
185 return bState; | |
186 } | |
187 | |
188 bool CPDF_OCContext::CheckObjectVisible(const CPDF_PageObject* pObj) { | |
189 const CPDF_ContentMarkData* pData = pObj->m_ContentMark.GetObject(); | |
190 for (int i = 0; i < pData->CountItems(); i++) { | |
191 const CPDF_ContentMarkItem& item = pData->GetItem(i); | |
192 if (item.GetName() == "OC" && | |
193 item.GetParamType() == CPDF_ContentMarkItem::PropertiesDict && | |
194 !CheckOCGVisible(item.GetParam())) { | |
195 return false; | |
196 } | |
197 } | |
198 return true; | |
199 } | |
200 | |
201 bool CPDF_OCContext::GetOCGVE(CPDF_Array* pExpression, int nLevel) { | |
202 if (nLevel > 32 || !pExpression) | |
203 return false; | |
204 | |
205 CFX_ByteString csOperator = pExpression->GetStringAt(0); | |
206 if (csOperator == "Not") { | |
207 CPDF_Object* pOCGObj = pExpression->GetDirectObjectAt(1); | |
208 if (!pOCGObj) | |
209 return false; | |
210 if (CPDF_Dictionary* pDict = pOCGObj->AsDictionary()) | |
211 return !GetOCGVisible(pDict); | |
212 if (CPDF_Array* pArray = pOCGObj->AsArray()) | |
213 return !GetOCGVE(pArray, nLevel + 1); | |
214 return false; | |
215 } | |
216 | |
217 if (csOperator != "Or" && csOperator != "And") | |
218 return false; | |
219 | |
220 bool bValue = false; | |
221 for (size_t i = 1; i < pExpression->GetCount(); i++) { | |
222 CPDF_Object* pOCGObj = pExpression->GetDirectObjectAt(1); | |
223 if (!pOCGObj) | |
224 continue; | |
225 | |
226 bool bItem = false; | |
227 if (CPDF_Dictionary* pDict = pOCGObj->AsDictionary()) | |
228 bItem = GetOCGVisible(pDict); | |
229 else if (CPDF_Array* pArray = pOCGObj->AsArray()) | |
230 bItem = GetOCGVE(pArray, nLevel + 1); | |
231 | |
232 if (i == 1) { | |
233 bValue = bItem; | |
234 } else { | |
235 if (csOperator == "Or") { | |
236 bValue = bValue || bItem; | |
237 } else { | |
238 bValue = bValue && bItem; | |
239 } | |
240 } | |
241 } | |
242 return bValue; | |
243 } | |
244 | |
245 bool CPDF_OCContext::LoadOCMDState(const CPDF_Dictionary* pOCMDDict) { | |
246 CPDF_Array* pVE = pOCMDDict->GetArrayBy("VE"); | |
247 if (pVE) | |
248 return GetOCGVE(pVE, 0); | |
249 | |
250 CFX_ByteString csP = pOCMDDict->GetStringBy("P", "AnyOn"); | |
251 CPDF_Object* pOCGObj = pOCMDDict->GetDirectObjectBy("OCGs"); | |
252 if (!pOCGObj) | |
253 return true; | |
254 | |
255 if (const CPDF_Dictionary* pDict = pOCGObj->AsDictionary()) | |
256 return GetOCGVisible(pDict); | |
257 | |
258 CPDF_Array* pArray = pOCGObj->AsArray(); | |
259 if (!pArray) | |
260 return true; | |
261 | |
262 bool bState = (csP == "AllOn" || csP == "AllOff"); | |
263 for (size_t i = 0; i < pArray->GetCount(); i++) { | |
264 bool bItem = true; | |
265 CPDF_Dictionary* pItemDict = pArray->GetDictAt(i); | |
266 if (pItemDict) | |
267 bItem = GetOCGVisible(pItemDict); | |
268 | |
269 if ((csP == "AnyOn" && bItem) || (csP == "AnyOff" && !bItem)) | |
270 return true; | |
271 if ((csP == "AllOn" && !bItem) || (csP == "AllOff" && bItem)) | |
272 return false; | |
273 } | |
274 return bState; | |
275 } | |
276 | |
277 bool CPDF_OCContext::CheckOCGVisible(const CPDF_Dictionary* pOCGDict) { | |
278 if (!pOCGDict) | |
279 return true; | |
280 | |
281 CFX_ByteString csType = pOCGDict->GetStringBy("Type", "OCG"); | |
282 if (csType == "OCG") | |
283 return GetOCGVisible(pOCGDict); | |
284 return LoadOCMDState(pOCGDict); | |
285 } | |
OLD | NEW |