summaryrefslogtreecommitdiff
path: root/core/fpdfdoc/cpdf_occontext.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'core/fpdfdoc/cpdf_occontext.cpp')
-rw-r--r--core/fpdfdoc/cpdf_occontext.cpp281
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);
+}