| 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 |