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