1 // Copyright 2016 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/cpdf_dest.h" 8 9 #include <algorithm> 10 11 #include "core/fpdfapi/parser/cpdf_array.h" 12 #include "core/fpdfapi/parser/cpdf_document.h" 13 #include "core/fpdfapi/parser/cpdf_name.h" 14 #include "core/fpdfapi/parser/cpdf_number.h" 15 16 namespace { 17 18 // These arrays are indexed by the PDFDEST_VIEW_* constants. 19 20 // Last element is a sentinel. 21 const char* const g_sZoomModes[] = {"Unknown", "XYZ", "Fit", "FitH", 22 "FitV", "FitR", "FitB", "FitBH", 23 "FitBV", nullptr}; 24 25 const uint8_t g_sZoomModeMaxParamCount[] = {0, 3, 0, 1, 1, 4, 0, 1, 1, 0}; 26 27 static_assert(FX_ArraySize(g_sZoomModes) == 28 FX_ArraySize(g_sZoomModeMaxParamCount), 29 "Zoom mode count Mismatch"); 30 31 } // namespace 32 33 CPDF_Dest::CPDF_Dest() {} 34 35 CPDF_Dest::CPDF_Dest(const CPDF_Dest& pObj) = default; 36 37 CPDF_Dest::CPDF_Dest(CPDF_Object* pObj) : m_pObj(pObj) {} 38 39 CPDF_Dest::~CPDF_Dest() {} 40 41 int CPDF_Dest::GetPageIndex(CPDF_Document* pDoc) const { 42 CPDF_Array* pArray = ToArray(m_pObj.Get()); 43 if (!pArray) 44 return 0; 45 46 CPDF_Object* pPage = pArray->GetDirectObjectAt(0); 47 if (!pPage) 48 return 0; 49 if (pPage->IsNumber()) 50 return pPage->GetInteger(); 51 if (!pPage->IsDictionary()) 52 return 0; 53 return pDoc->GetPageIndex(pPage->GetObjNum()); 54 } 55 56 uint32_t CPDF_Dest::GetPageObjNum() const { 57 CPDF_Array* pArray = ToArray(m_pObj.Get()); 58 if (!pArray) 59 return 0; 60 61 CPDF_Object* pPage = pArray->GetDirectObjectAt(0); 62 if (!pPage) 63 return 0; 64 if (pPage->IsNumber()) 65 return pPage->GetInteger(); 66 if (pPage->IsDictionary()) 67 return pPage->GetObjNum(); 68 return 0; 69 } 70 71 int CPDF_Dest::GetZoomMode() const { 72 CPDF_Array* pArray = ToArray(m_pObj.Get()); 73 if (!pArray) 74 return 0; 75 76 CPDF_Object* pObj = pArray->GetDirectObjectAt(1); 77 if (!pObj) 78 return 0; 79 80 ByteString mode = pObj->GetString(); 81 for (int i = 1; g_sZoomModes[i]; ++i) { 82 if (mode == g_sZoomModes[i]) 83 return i; 84 } 85 86 return 0; 87 } 88 89 bool CPDF_Dest::GetXYZ(bool* pHasX, 90 bool* pHasY, 91 bool* pHasZoom, 92 float* pX, 93 float* pY, 94 float* pZoom) const { 95 *pHasX = false; 96 *pHasY = false; 97 *pHasZoom = false; 98 99 CPDF_Array* pArray = ToArray(m_pObj.Get()); 100 if (!pArray) 101 return false; 102 103 if (pArray->GetCount() < 5) 104 return false; 105 106 const CPDF_Name* xyz = ToName(pArray->GetDirectObjectAt(1)); 107 if (!xyz || xyz->GetString() != "XYZ") 108 return false; 109 110 const CPDF_Number* numX = ToNumber(pArray->GetDirectObjectAt(2)); 111 const CPDF_Number* numY = ToNumber(pArray->GetDirectObjectAt(3)); 112 const CPDF_Number* numZoom = ToNumber(pArray->GetDirectObjectAt(4)); 113 114 // If the value is a CPDF_Null then ToNumber will return nullptr. 115 *pHasX = !!numX; 116 *pHasY = !!numY; 117 *pHasZoom = !!numZoom; 118 119 if (numX) 120 *pX = numX->GetNumber(); 121 if (numY) 122 *pY = numY->GetNumber(); 123 124 // A zoom value of 0 is equivalent to a null value, so treat it as a null. 125 if (numZoom) { 126 float num = numZoom->GetNumber(); 127 if (num == 0.0) 128 *pHasZoom = false; 129 else 130 *pZoom = num; 131 } 132 133 return true; 134 } 135 136 unsigned long CPDF_Dest::GetNumParams() const { 137 CPDF_Array* pArray = ToArray(m_pObj.Get()); 138 if (!pArray || pArray->GetCount() < 2) 139 return 0; 140 141 unsigned long maxParamsForFitType = g_sZoomModeMaxParamCount[GetZoomMode()]; 142 unsigned long numParamsInArray = pArray->GetCount() - 2; 143 return std::min(maxParamsForFitType, numParamsInArray); 144 } 145 146 float CPDF_Dest::GetParam(int index) const { 147 CPDF_Array* pArray = ToArray(m_pObj.Get()); 148 return pArray ? pArray->GetNumberAt(2 + index) : 0; 149 } 150 151 ByteString CPDF_Dest::GetRemoteName() const { 152 return m_pObj ? m_pObj->GetString() : ByteString(); 153 } 154