Home | History | Annotate | Download | only in fpdfdoc
      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