diff options
Diffstat (limited to 'core/fpdfdoc/cpdf_occontext.cpp')
-rw-r--r-- | core/fpdfdoc/cpdf_occontext.cpp | 281 |
1 files changed, 281 insertions, 0 deletions
diff --git a/core/fpdfdoc/cpdf_occontext.cpp b/core/fpdfdoc/cpdf_occontext.cpp new file mode 100644 index 0000000000..9206b97e6f --- /dev/null +++ b/core/fpdfdoc/cpdf_occontext.cpp @@ -0,0 +1,281 @@ +// Copyright 2016 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/fpdfdoc/include/cpdf_occontext.h" + +#include "core/fpdfapi/fpdf_page/cpdf_contentmarkdata.h" +#include "core/fpdfapi/fpdf_page/include/cpdf_pageobject.h" +#include "core/fpdfapi/fpdf_parser/include/cpdf_array.h" +#include "core/fpdfapi/fpdf_parser/include/cpdf_document.h" + +namespace { + +int32_t FindGroup(const CPDF_Array* pArray, const CPDF_Dictionary* pGroupDict) { + if (!pArray || !pGroupDict) + return -1; + + for (size_t i = 0; i < pArray->GetCount(); i++) { + if (pArray->GetDictAt(i) == pGroupDict) + return i; + } + return -1; +} + +bool HasIntent(const CPDF_Dictionary* pDict, + const CFX_ByteStringC& csElement, + const CFX_ByteStringC& csDef) { + CPDF_Object* pIntent = pDict->GetDirectObjectBy("Intent"); + if (!pIntent) + return csElement == csDef; + + CFX_ByteString bsIntent; + if (CPDF_Array* pArray = pIntent->AsArray()) { + for (size_t i = 0; i < pArray->GetCount(); i++) { + bsIntent = pArray->GetStringAt(i); + if (bsIntent == "All" || bsIntent == csElement) + return true; + } + return false; + } + bsIntent = pIntent->GetString(); + return bsIntent == "All" || bsIntent == csElement; +} + +CPDF_Dictionary* GetConfig(CPDF_Document* pDoc, + const CPDF_Dictionary* pOCGDict) { + ASSERT(pOCGDict); + CPDF_Dictionary* pOCProperties = pDoc->GetRoot()->GetDictBy("OCProperties"); + if (!pOCProperties) + return nullptr; + + CPDF_Array* pOCGs = pOCProperties->GetArrayBy("OCGs"); + if (!pOCGs) + return nullptr; + + if (FindGroup(pOCGs, pOCGDict) < 0) + return nullptr; + + CPDF_Dictionary* pConfig = pOCProperties->GetDictBy("D"); + CPDF_Array* pConfigs = pOCProperties->GetArrayBy("Configs"); + if (!pConfigs) + return pConfig; + + for (size_t i = 0; i < pConfigs->GetCount(); i++) { + CPDF_Dictionary* pFind = pConfigs->GetDictAt(i); + if (pFind && HasIntent(pFind, "View", "View")) + return pFind; + } + return pConfig; +} + +CFX_ByteString GetUsageTypeString(CPDF_OCContext::UsageType eType) { + CFX_ByteString csState; + switch (eType) { + case CPDF_OCContext::Design: + csState = "Design"; + break; + case CPDF_OCContext::Print: + csState = "Print"; + break; + case CPDF_OCContext::Export: + csState = "Export"; + break; + default: + csState = "View"; + break; + } + return csState; +} + +} // namespace + +CPDF_OCContext::CPDF_OCContext(CPDF_Document* pDoc, UsageType eUsageType) + : m_pDocument(pDoc), m_eUsageType(eUsageType) { + ASSERT(pDoc); +} + +CPDF_OCContext::~CPDF_OCContext() {} + +bool CPDF_OCContext::LoadOCGStateFromConfig( + const CFX_ByteString& csConfig, + const CPDF_Dictionary* pOCGDict) const { + CPDF_Dictionary* pConfig = GetConfig(m_pDocument, pOCGDict); + if (!pConfig) + return true; + + bool bState = pConfig->GetStringBy("BaseState", "ON") != "OFF"; + CPDF_Array* pArray = pConfig->GetArrayBy("ON"); + if (pArray) { + if (FindGroup(pArray, pOCGDict) >= 0) + bState = true; + } + pArray = pConfig->GetArrayBy("OFF"); + if (pArray) { + if (FindGroup(pArray, pOCGDict) >= 0) + bState = false; + } + pArray = pConfig->GetArrayBy("AS"); + if (!pArray) + return bState; + + CFX_ByteString csFind = csConfig + "State"; + for (size_t i = 0; i < pArray->GetCount(); i++) { + CPDF_Dictionary* pUsage = pArray->GetDictAt(i); + if (!pUsage) + continue; + + if (pUsage->GetStringBy("Event", "View") != csConfig) + continue; + + CPDF_Array* pOCGs = pUsage->GetArrayBy("OCGs"); + if (!pOCGs) + continue; + + if (FindGroup(pOCGs, pOCGDict) < 0) + continue; + + CPDF_Dictionary* pState = pUsage->GetDictBy(csConfig); + if (!pState) + continue; + + bState = pState->GetStringBy(csFind) != "OFF"; + } + return bState; +} + +bool CPDF_OCContext::LoadOCGState(const CPDF_Dictionary* pOCGDict) const { + if (!HasIntent(pOCGDict, "View", "View")) + return true; + + CFX_ByteString csState = GetUsageTypeString(m_eUsageType); + CPDF_Dictionary* pUsage = pOCGDict->GetDictBy("Usage"); + if (pUsage) { + CPDF_Dictionary* pState = pUsage->GetDictBy(csState); + if (pState) { + CFX_ByteString csFind = csState + "State"; + if (pState->KeyExist(csFind)) + return pState->GetStringBy(csFind) != "OFF"; + } + if (csState != "View") { + pState = pUsage->GetDictBy("View"); + if (pState && pState->KeyExist("ViewState")) + return pState->GetStringBy("ViewState") != "OFF"; + } + } + return LoadOCGStateFromConfig(csState, pOCGDict); +} + +bool CPDF_OCContext::GetOCGVisible(const CPDF_Dictionary* pOCGDict) { + if (!pOCGDict) + return false; + + const auto it = m_OCGStates.find(pOCGDict); + if (it != m_OCGStates.end()) + return it->second; + + bool bState = LoadOCGState(pOCGDict); + m_OCGStates[pOCGDict] = bState; + return bState; +} + +bool CPDF_OCContext::CheckObjectVisible(const CPDF_PageObject* pObj) { + const CPDF_ContentMarkData* pData = pObj->m_ContentMark.GetObject(); + for (int i = 0; i < pData->CountItems(); i++) { + const CPDF_ContentMarkItem& item = pData->GetItem(i); + if (item.GetName() == "OC" && + item.GetParamType() == CPDF_ContentMarkItem::PropertiesDict && + !CheckOCGVisible(item.GetParam())) { + return false; + } + } + return true; +} + +bool CPDF_OCContext::GetOCGVE(CPDF_Array* pExpression, int nLevel) { + if (nLevel > 32 || !pExpression) + return false; + + CFX_ByteString csOperator = pExpression->GetStringAt(0); + if (csOperator == "Not") { + CPDF_Object* pOCGObj = pExpression->GetDirectObjectAt(1); + if (!pOCGObj) + return false; + if (CPDF_Dictionary* pDict = pOCGObj->AsDictionary()) + return !GetOCGVisible(pDict); + if (CPDF_Array* pArray = pOCGObj->AsArray()) + return !GetOCGVE(pArray, nLevel + 1); + return false; + } + + if (csOperator != "Or" && csOperator != "And") + return false; + + bool bValue = false; + for (size_t i = 1; i < pExpression->GetCount(); i++) { + CPDF_Object* pOCGObj = pExpression->GetDirectObjectAt(1); + if (!pOCGObj) + continue; + + bool bItem = false; + if (CPDF_Dictionary* pDict = pOCGObj->AsDictionary()) + bItem = GetOCGVisible(pDict); + else if (CPDF_Array* pArray = pOCGObj->AsArray()) + bItem = GetOCGVE(pArray, nLevel + 1); + + if (i == 1) { + bValue = bItem; + } else { + if (csOperator == "Or") { + bValue = bValue || bItem; + } else { + bValue = bValue && bItem; + } + } + } + return bValue; +} + +bool CPDF_OCContext::LoadOCMDState(const CPDF_Dictionary* pOCMDDict) { + CPDF_Array* pVE = pOCMDDict->GetArrayBy("VE"); + if (pVE) + return GetOCGVE(pVE, 0); + + CFX_ByteString csP = pOCMDDict->GetStringBy("P", "AnyOn"); + CPDF_Object* pOCGObj = pOCMDDict->GetDirectObjectBy("OCGs"); + if (!pOCGObj) + return true; + + if (const CPDF_Dictionary* pDict = pOCGObj->AsDictionary()) + return GetOCGVisible(pDict); + + CPDF_Array* pArray = pOCGObj->AsArray(); + if (!pArray) + return true; + + bool bState = (csP == "AllOn" || csP == "AllOff"); + for (size_t i = 0; i < pArray->GetCount(); i++) { + bool bItem = true; + CPDF_Dictionary* pItemDict = pArray->GetDictAt(i); + if (pItemDict) + bItem = GetOCGVisible(pItemDict); + + if ((csP == "AnyOn" && bItem) || (csP == "AnyOff" && !bItem)) + return true; + if ((csP == "AllOn" && !bItem) || (csP == "AllOff" && bItem)) + return false; + } + return bState; +} + +bool CPDF_OCContext::CheckOCGVisible(const CPDF_Dictionary* pOCGDict) { + if (!pOCGDict) + return true; + + CFX_ByteString csType = pOCGDict->GetStringBy("Type", "OCG"); + if (csType == "OCG") + return GetOCGVisible(pOCGDict); + return LoadOCMDState(pOCGDict); +} |