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 "fpdfsdk/cpdfsdk_baannot.h" 8 9 #include <algorithm> 10 #include <utility> 11 12 #include "core/fpdfapi/parser/cpdf_array.h" 13 #include "core/fpdfapi/parser/cpdf_document.h" 14 #include "core/fpdfapi/parser/cpdf_name.h" 15 #include "core/fpdfapi/parser/cpdf_number.h" 16 #include "core/fpdfapi/parser/cpdf_reference.h" 17 #include "core/fpdfapi/parser/cpdf_stream.h" 18 #include "core/fpdfapi/parser/cpdf_string.h" 19 #include "core/fpdfapi/parser/fpdf_parser_decode.h" 20 #include "fpdfsdk/cpdfsdk_datetime.h" 21 #include "fpdfsdk/cpdfsdk_pageview.h" 22 23 CPDFSDK_BAAnnot::CPDFSDK_BAAnnot(CPDF_Annot* pAnnot, 24 CPDFSDK_PageView* pPageView) 25 : CPDFSDK_Annot(pPageView), m_pAnnot(pAnnot) {} 26 27 CPDFSDK_BAAnnot::~CPDFSDK_BAAnnot() {} 28 29 CPDF_Annot* CPDFSDK_BAAnnot::GetPDFAnnot() const { 30 return m_pAnnot.Get(); 31 } 32 33 CPDF_Annot* CPDFSDK_BAAnnot::GetPDFPopupAnnot() const { 34 return m_pAnnot->GetPopupAnnot(); 35 } 36 37 CPDF_Dictionary* CPDFSDK_BAAnnot::GetAnnotDict() const { 38 return m_pAnnot->GetAnnotDict(); 39 } 40 41 CPDF_Dictionary* CPDFSDK_BAAnnot::GetAPDict() const { 42 CPDF_Dictionary* pAPDict = m_pAnnot->GetAnnotDict()->GetDictFor("AP"); 43 if (!pAPDict) 44 pAPDict = m_pAnnot->GetAnnotDict()->SetNewFor<CPDF_Dictionary>("AP"); 45 return pAPDict; 46 } 47 48 void CPDFSDK_BAAnnot::SetRect(const CFX_FloatRect& rect) { 49 ASSERT(rect.right - rect.left >= GetMinWidth()); 50 ASSERT(rect.top - rect.bottom >= GetMinHeight()); 51 52 m_pAnnot->GetAnnotDict()->SetRectFor("Rect", rect); 53 } 54 55 CFX_FloatRect CPDFSDK_BAAnnot::GetRect() const { 56 return m_pAnnot->GetRect(); 57 } 58 59 CPDF_Annot::Subtype CPDFSDK_BAAnnot::GetAnnotSubtype() const { 60 return m_pAnnot->GetSubtype(); 61 } 62 63 void CPDFSDK_BAAnnot::DrawAppearance(CFX_RenderDevice* pDevice, 64 const CFX_Matrix& mtUser2Device, 65 CPDF_Annot::AppearanceMode mode, 66 const CPDF_RenderOptions* pOptions) { 67 m_pAnnot->DrawAppearance(m_pPageView->GetPDFPage(), pDevice, mtUser2Device, 68 mode, pOptions); 69 } 70 71 bool CPDFSDK_BAAnnot::IsAppearanceValid() { 72 return !!m_pAnnot->GetAnnotDict()->GetDictFor("AP"); 73 } 74 75 bool CPDFSDK_BAAnnot::IsAppearanceValid(CPDF_Annot::AppearanceMode mode) { 76 CPDF_Dictionary* pAP = m_pAnnot->GetAnnotDict()->GetDictFor("AP"); 77 if (!pAP) 78 return false; 79 80 // Choose the right sub-ap 81 const char* ap_entry = "N"; 82 if (mode == CPDF_Annot::Down) 83 ap_entry = "D"; 84 else if (mode == CPDF_Annot::Rollover) 85 ap_entry = "R"; 86 if (!pAP->KeyExist(ap_entry)) 87 ap_entry = "N"; 88 89 // Get the AP stream or subdirectory 90 CPDF_Object* psub = pAP->GetDirectObjectFor(ap_entry); 91 return !!psub; 92 } 93 94 void CPDFSDK_BAAnnot::DrawBorder(CFX_RenderDevice* pDevice, 95 const CFX_Matrix* pUser2Device, 96 const CPDF_RenderOptions* pOptions) { 97 m_pAnnot->DrawBorder(pDevice, pUser2Device, pOptions); 98 } 99 100 void CPDFSDK_BAAnnot::ClearCachedAP() { 101 m_pAnnot->ClearCachedAP(); 102 } 103 104 void CPDFSDK_BAAnnot::SetContents(const WideString& sContents) { 105 if (sContents.IsEmpty()) { 106 m_pAnnot->GetAnnotDict()->RemoveFor("Contents"); 107 } else { 108 m_pAnnot->GetAnnotDict()->SetNewFor<CPDF_String>( 109 "Contents", PDF_EncodeText(sContents), false); 110 } 111 } 112 113 WideString CPDFSDK_BAAnnot::GetContents() const { 114 return m_pAnnot->GetAnnotDict()->GetUnicodeTextFor("Contents"); 115 } 116 117 void CPDFSDK_BAAnnot::SetAnnotName(const WideString& sName) { 118 if (sName.IsEmpty()) { 119 m_pAnnot->GetAnnotDict()->RemoveFor("NM"); 120 } else { 121 m_pAnnot->GetAnnotDict()->SetNewFor<CPDF_String>( 122 "NM", PDF_EncodeText(sName), false); 123 } 124 } 125 126 WideString CPDFSDK_BAAnnot::GetAnnotName() const { 127 return m_pAnnot->GetAnnotDict()->GetUnicodeTextFor("NM"); 128 } 129 130 void CPDFSDK_BAAnnot::SetModifiedDate(const FX_SYSTEMTIME& st) { 131 CPDFSDK_DateTime dt(st); 132 ByteString str = dt.ToPDFDateTimeString(); 133 if (str.IsEmpty()) 134 m_pAnnot->GetAnnotDict()->RemoveFor("M"); 135 else 136 m_pAnnot->GetAnnotDict()->SetNewFor<CPDF_String>("M", str, false); 137 } 138 139 FX_SYSTEMTIME CPDFSDK_BAAnnot::GetModifiedDate() const { 140 FX_SYSTEMTIME systime; 141 ByteString str = m_pAnnot->GetAnnotDict()->GetStringFor("M"); 142 CPDFSDK_DateTime dt(str); 143 dt.ToSystemTime(systime); 144 return systime; 145 } 146 147 void CPDFSDK_BAAnnot::SetFlags(uint32_t nFlags) { 148 m_pAnnot->GetAnnotDict()->SetNewFor<CPDF_Number>("F", 149 static_cast<int>(nFlags)); 150 } 151 152 uint32_t CPDFSDK_BAAnnot::GetFlags() const { 153 return m_pAnnot->GetAnnotDict()->GetIntegerFor("F"); 154 } 155 156 void CPDFSDK_BAAnnot::SetAppState(const ByteString& str) { 157 if (str.IsEmpty()) 158 m_pAnnot->GetAnnotDict()->RemoveFor("AS"); 159 else 160 m_pAnnot->GetAnnotDict()->SetNewFor<CPDF_String>("AS", str, false); 161 } 162 163 ByteString CPDFSDK_BAAnnot::GetAppState() const { 164 return m_pAnnot->GetAnnotDict()->GetStringFor("AS"); 165 } 166 167 void CPDFSDK_BAAnnot::SetStructParent(int key) { 168 m_pAnnot->GetAnnotDict()->SetNewFor<CPDF_Number>("StructParent", key); 169 } 170 171 int CPDFSDK_BAAnnot::GetStructParent() const { 172 return m_pAnnot->GetAnnotDict()->GetIntegerFor("StructParent"); 173 } 174 175 // border 176 void CPDFSDK_BAAnnot::SetBorderWidth(int nWidth) { 177 CPDF_Array* pBorder = m_pAnnot->GetAnnotDict()->GetArrayFor("Border"); 178 if (pBorder) { 179 pBorder->SetNewAt<CPDF_Number>(2, nWidth); 180 } else { 181 CPDF_Dictionary* pBSDict = m_pAnnot->GetAnnotDict()->GetDictFor("BS"); 182 if (!pBSDict) 183 pBSDict = m_pAnnot->GetAnnotDict()->SetNewFor<CPDF_Dictionary>("BS"); 184 185 pBSDict->SetNewFor<CPDF_Number>("W", nWidth); 186 } 187 } 188 189 int CPDFSDK_BAAnnot::GetBorderWidth() const { 190 if (CPDF_Array* pBorder = m_pAnnot->GetAnnotDict()->GetArrayFor("Border")) 191 return pBorder->GetIntegerAt(2); 192 193 if (CPDF_Dictionary* pBSDict = m_pAnnot->GetAnnotDict()->GetDictFor("BS")) 194 return pBSDict->GetIntegerFor("W", 1); 195 196 return 1; 197 } 198 199 void CPDFSDK_BAAnnot::SetBorderStyle(BorderStyle nStyle) { 200 CPDF_Dictionary* pBSDict = m_pAnnot->GetAnnotDict()->GetDictFor("BS"); 201 if (!pBSDict) 202 pBSDict = m_pAnnot->GetAnnotDict()->SetNewFor<CPDF_Dictionary>("BS"); 203 204 switch (nStyle) { 205 case BorderStyle::SOLID: 206 pBSDict->SetNewFor<CPDF_Name>("S", "S"); 207 break; 208 case BorderStyle::DASH: 209 pBSDict->SetNewFor<CPDF_Name>("S", "D"); 210 break; 211 case BorderStyle::BEVELED: 212 pBSDict->SetNewFor<CPDF_Name>("S", "B"); 213 break; 214 case BorderStyle::INSET: 215 pBSDict->SetNewFor<CPDF_Name>("S", "I"); 216 break; 217 case BorderStyle::UNDERLINE: 218 pBSDict->SetNewFor<CPDF_Name>("S", "U"); 219 break; 220 default: 221 break; 222 } 223 } 224 225 BorderStyle CPDFSDK_BAAnnot::GetBorderStyle() const { 226 CPDF_Dictionary* pBSDict = m_pAnnot->GetAnnotDict()->GetDictFor("BS"); 227 if (pBSDict) { 228 ByteString sBorderStyle = pBSDict->GetStringFor("S", "S"); 229 if (sBorderStyle == "S") 230 return BorderStyle::SOLID; 231 if (sBorderStyle == "D") 232 return BorderStyle::DASH; 233 if (sBorderStyle == "B") 234 return BorderStyle::BEVELED; 235 if (sBorderStyle == "I") 236 return BorderStyle::INSET; 237 if (sBorderStyle == "U") 238 return BorderStyle::UNDERLINE; 239 } 240 241 CPDF_Array* pBorder = m_pAnnot->GetAnnotDict()->GetArrayFor("Border"); 242 if (pBorder) { 243 if (pBorder->GetCount() >= 4) { 244 CPDF_Array* pDP = pBorder->GetArrayAt(3); 245 if (pDP && pDP->GetCount() > 0) 246 return BorderStyle::DASH; 247 } 248 } 249 250 return BorderStyle::SOLID; 251 } 252 253 void CPDFSDK_BAAnnot::SetColor(FX_COLORREF color) { 254 CPDF_Array* pArray = m_pAnnot->GetAnnotDict()->SetNewFor<CPDF_Array>("C"); 255 pArray->AddNew<CPDF_Number>(static_cast<float>(FXSYS_GetRValue(color)) / 256 255.0f); 257 pArray->AddNew<CPDF_Number>(static_cast<float>(FXSYS_GetGValue(color)) / 258 255.0f); 259 pArray->AddNew<CPDF_Number>(static_cast<float>(FXSYS_GetBValue(color)) / 260 255.0f); 261 } 262 263 void CPDFSDK_BAAnnot::RemoveColor() { 264 m_pAnnot->GetAnnotDict()->RemoveFor("C"); 265 } 266 267 bool CPDFSDK_BAAnnot::GetColor(FX_COLORREF& color) const { 268 if (CPDF_Array* pEntry = m_pAnnot->GetAnnotDict()->GetArrayFor("C")) { 269 size_t nCount = pEntry->GetCount(); 270 if (nCount == 1) { 271 float g = pEntry->GetNumberAt(0) * 255; 272 273 color = FXSYS_RGB((int)g, (int)g, (int)g); 274 275 return true; 276 } else if (nCount == 3) { 277 float r = pEntry->GetNumberAt(0) * 255; 278 float g = pEntry->GetNumberAt(1) * 255; 279 float b = pEntry->GetNumberAt(2) * 255; 280 281 color = FXSYS_RGB((int)r, (int)g, (int)b); 282 283 return true; 284 } else if (nCount == 4) { 285 float c = pEntry->GetNumberAt(0); 286 float m = pEntry->GetNumberAt(1); 287 float y = pEntry->GetNumberAt(2); 288 float k = pEntry->GetNumberAt(3); 289 290 float r = 1.0f - std::min(1.0f, c + k); 291 float g = 1.0f - std::min(1.0f, m + k); 292 float b = 1.0f - std::min(1.0f, y + k); 293 294 color = FXSYS_RGB((int)(r * 255), (int)(g * 255), (int)(b * 255)); 295 296 return true; 297 } 298 } 299 300 return false; 301 } 302 303 bool CPDFSDK_BAAnnot::IsVisible() const { 304 uint32_t nFlags = GetFlags(); 305 return !((nFlags & ANNOTFLAG_INVISIBLE) || (nFlags & ANNOTFLAG_HIDDEN) || 306 (nFlags & ANNOTFLAG_NOVIEW)); 307 } 308 309 CPDF_Action CPDFSDK_BAAnnot::GetAction() const { 310 return CPDF_Action(m_pAnnot->GetAnnotDict()->GetDictFor("A")); 311 } 312 313 void CPDFSDK_BAAnnot::SetAction(const CPDF_Action& action) { 314 CPDF_Dictionary* pDict = action.GetDict(); 315 if (pDict != m_pAnnot->GetAnnotDict()->GetDictFor("A")) { 316 CPDF_Document* pDoc = m_pPageView->GetPDFDocument(); 317 if (pDict->IsInline()) 318 pDict = pDoc->AddIndirectObject(pDict->Clone())->AsDictionary(); 319 m_pAnnot->GetAnnotDict()->SetNewFor<CPDF_Reference>("A", pDoc, 320 pDict->GetObjNum()); 321 } 322 } 323 324 void CPDFSDK_BAAnnot::RemoveAction() { 325 m_pAnnot->GetAnnotDict()->RemoveFor("A"); 326 } 327 328 CPDF_AAction CPDFSDK_BAAnnot::GetAAction() const { 329 return CPDF_AAction(m_pAnnot->GetAnnotDict()->GetDictFor("AA")); 330 } 331 332 void CPDFSDK_BAAnnot::SetAAction(const CPDF_AAction& aa) { 333 if (aa.GetDict() != m_pAnnot->GetAnnotDict()->GetDictFor("AA")) 334 m_pAnnot->GetAnnotDict()->SetFor("AA", pdfium::WrapUnique(aa.GetDict())); 335 } 336 337 void CPDFSDK_BAAnnot::RemoveAAction() { 338 m_pAnnot->GetAnnotDict()->RemoveFor("AA"); 339 } 340 341 CPDF_Action CPDFSDK_BAAnnot::GetAAction(CPDF_AAction::AActionType eAAT) { 342 CPDF_AAction AAction = GetAAction(); 343 if (AAction.ActionExist(eAAT)) 344 return AAction.GetAction(eAAT); 345 346 if (eAAT == CPDF_AAction::ButtonUp) 347 return GetAction(); 348 349 return CPDF_Action(nullptr); 350 } 351 352 void CPDFSDK_BAAnnot::SetOpenState(bool bOpenState) { 353 if (CPDF_Annot* pAnnot = m_pAnnot->GetPopupAnnot()) 354 pAnnot->SetOpenState(bOpenState); 355 } 356 357 int CPDFSDK_BAAnnot::GetLayoutOrder() const { 358 if (m_pAnnot->GetSubtype() == CPDF_Annot::Subtype::POPUP) 359 return 1; 360 361 return CPDFSDK_Annot::GetLayoutOrder(); 362 } 363