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; 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 void CPDFSDK_BAAnnot::SetRect(const CFX_FloatRect& rect) { 42 ASSERT(rect.right - rect.left >= GetMinWidth()); 43 ASSERT(rect.top - rect.bottom >= GetMinHeight()); 44 45 m_pAnnot->GetAnnotDict()->SetRectFor("Rect", rect); 46 } 47 48 CFX_FloatRect CPDFSDK_BAAnnot::GetRect() const { 49 return m_pAnnot->GetRect(); 50 } 51 52 CPDF_Annot::Subtype CPDFSDK_BAAnnot::GetAnnotSubtype() const { 53 return m_pAnnot->GetSubtype(); 54 } 55 56 void CPDFSDK_BAAnnot::DrawAppearance(CFX_RenderDevice* pDevice, 57 const CFX_Matrix* pUser2Device, 58 CPDF_Annot::AppearanceMode mode, 59 const CPDF_RenderOptions* pOptions) { 60 m_pAnnot->DrawAppearance(m_pPageView->GetPDFPage(), pDevice, pUser2Device, 61 mode, pOptions); 62 } 63 64 bool CPDFSDK_BAAnnot::IsAppearanceValid() { 65 return !!m_pAnnot->GetAnnotDict()->GetDictFor("AP"); 66 } 67 68 bool CPDFSDK_BAAnnot::IsAppearanceValid(CPDF_Annot::AppearanceMode mode) { 69 CPDF_Dictionary* pAP = m_pAnnot->GetAnnotDict()->GetDictFor("AP"); 70 if (!pAP) 71 return false; 72 73 // Choose the right sub-ap 74 const FX_CHAR* ap_entry = "N"; 75 if (mode == CPDF_Annot::Down) 76 ap_entry = "D"; 77 else if (mode == CPDF_Annot::Rollover) 78 ap_entry = "R"; 79 if (!pAP->KeyExist(ap_entry)) 80 ap_entry = "N"; 81 82 // Get the AP stream or subdirectory 83 CPDF_Object* psub = pAP->GetDirectObjectFor(ap_entry); 84 return !!psub; 85 } 86 87 void CPDFSDK_BAAnnot::DrawBorder(CFX_RenderDevice* pDevice, 88 const CFX_Matrix* pUser2Device, 89 const CPDF_RenderOptions* pOptions) { 90 m_pAnnot->DrawBorder(pDevice, pUser2Device, pOptions); 91 } 92 93 void CPDFSDK_BAAnnot::ClearCachedAP() { 94 m_pAnnot->ClearCachedAP(); 95 } 96 97 void CPDFSDK_BAAnnot::SetContents(const CFX_WideString& sContents) { 98 if (sContents.IsEmpty()) { 99 m_pAnnot->GetAnnotDict()->RemoveFor("Contents"); 100 } else { 101 m_pAnnot->GetAnnotDict()->SetNewFor<CPDF_String>( 102 "Contents", PDF_EncodeText(sContents), false); 103 } 104 } 105 106 CFX_WideString CPDFSDK_BAAnnot::GetContents() const { 107 return m_pAnnot->GetAnnotDict()->GetUnicodeTextFor("Contents"); 108 } 109 110 void CPDFSDK_BAAnnot::SetAnnotName(const CFX_WideString& sName) { 111 if (sName.IsEmpty()) { 112 m_pAnnot->GetAnnotDict()->RemoveFor("NM"); 113 } else { 114 m_pAnnot->GetAnnotDict()->SetNewFor<CPDF_String>( 115 "NM", PDF_EncodeText(sName), false); 116 } 117 } 118 119 CFX_WideString CPDFSDK_BAAnnot::GetAnnotName() const { 120 return m_pAnnot->GetAnnotDict()->GetUnicodeTextFor("NM"); 121 } 122 123 void CPDFSDK_BAAnnot::SetModifiedDate(const FX_SYSTEMTIME& st) { 124 CPDFSDK_DateTime dt(st); 125 CFX_ByteString str = dt.ToPDFDateTimeString(); 126 if (str.IsEmpty()) 127 m_pAnnot->GetAnnotDict()->RemoveFor("M"); 128 else 129 m_pAnnot->GetAnnotDict()->SetNewFor<CPDF_String>("M", str, false); 130 } 131 132 FX_SYSTEMTIME CPDFSDK_BAAnnot::GetModifiedDate() const { 133 FX_SYSTEMTIME systime; 134 CFX_ByteString str = m_pAnnot->GetAnnotDict()->GetStringFor("M"); 135 CPDFSDK_DateTime dt(str); 136 dt.ToSystemTime(systime); 137 return systime; 138 } 139 140 void CPDFSDK_BAAnnot::SetFlags(uint32_t nFlags) { 141 m_pAnnot->GetAnnotDict()->SetNewFor<CPDF_Number>("F", 142 static_cast<int>(nFlags)); 143 } 144 145 uint32_t CPDFSDK_BAAnnot::GetFlags() const { 146 return m_pAnnot->GetAnnotDict()->GetIntegerFor("F"); 147 } 148 149 void CPDFSDK_BAAnnot::SetAppState(const CFX_ByteString& str) { 150 if (str.IsEmpty()) 151 m_pAnnot->GetAnnotDict()->RemoveFor("AS"); 152 else 153 m_pAnnot->GetAnnotDict()->SetNewFor<CPDF_String>("AS", str, false); 154 } 155 156 CFX_ByteString CPDFSDK_BAAnnot::GetAppState() const { 157 return m_pAnnot->GetAnnotDict()->GetStringFor("AS"); 158 } 159 160 void CPDFSDK_BAAnnot::SetStructParent(int key) { 161 m_pAnnot->GetAnnotDict()->SetNewFor<CPDF_Number>("StructParent", key); 162 } 163 164 int CPDFSDK_BAAnnot::GetStructParent() const { 165 return m_pAnnot->GetAnnotDict()->GetIntegerFor("StructParent"); 166 } 167 168 // border 169 void CPDFSDK_BAAnnot::SetBorderWidth(int nWidth) { 170 CPDF_Array* pBorder = m_pAnnot->GetAnnotDict()->GetArrayFor("Border"); 171 if (pBorder) { 172 pBorder->SetNewAt<CPDF_Number>(2, nWidth); 173 } else { 174 CPDF_Dictionary* pBSDict = m_pAnnot->GetAnnotDict()->GetDictFor("BS"); 175 if (!pBSDict) 176 pBSDict = m_pAnnot->GetAnnotDict()->SetNewFor<CPDF_Dictionary>("BS"); 177 178 pBSDict->SetNewFor<CPDF_Number>("W", nWidth); 179 } 180 } 181 182 int CPDFSDK_BAAnnot::GetBorderWidth() const { 183 if (CPDF_Array* pBorder = m_pAnnot->GetAnnotDict()->GetArrayFor("Border")) 184 return pBorder->GetIntegerAt(2); 185 186 if (CPDF_Dictionary* pBSDict = m_pAnnot->GetAnnotDict()->GetDictFor("BS")) 187 return pBSDict->GetIntegerFor("W", 1); 188 189 return 1; 190 } 191 192 void CPDFSDK_BAAnnot::SetBorderStyle(BorderStyle nStyle) { 193 CPDF_Dictionary* pBSDict = m_pAnnot->GetAnnotDict()->GetDictFor("BS"); 194 if (!pBSDict) 195 pBSDict = m_pAnnot->GetAnnotDict()->SetNewFor<CPDF_Dictionary>("BS"); 196 197 switch (nStyle) { 198 case BorderStyle::SOLID: 199 pBSDict->SetNewFor<CPDF_Name>("S", "S"); 200 break; 201 case BorderStyle::DASH: 202 pBSDict->SetNewFor<CPDF_Name>("S", "D"); 203 break; 204 case BorderStyle::BEVELED: 205 pBSDict->SetNewFor<CPDF_Name>("S", "B"); 206 break; 207 case BorderStyle::INSET: 208 pBSDict->SetNewFor<CPDF_Name>("S", "I"); 209 break; 210 case BorderStyle::UNDERLINE: 211 pBSDict->SetNewFor<CPDF_Name>("S", "U"); 212 break; 213 default: 214 break; 215 } 216 } 217 218 BorderStyle CPDFSDK_BAAnnot::GetBorderStyle() const { 219 CPDF_Dictionary* pBSDict = m_pAnnot->GetAnnotDict()->GetDictFor("BS"); 220 if (pBSDict) { 221 CFX_ByteString sBorderStyle = pBSDict->GetStringFor("S", "S"); 222 if (sBorderStyle == "S") 223 return BorderStyle::SOLID; 224 if (sBorderStyle == "D") 225 return BorderStyle::DASH; 226 if (sBorderStyle == "B") 227 return BorderStyle::BEVELED; 228 if (sBorderStyle == "I") 229 return BorderStyle::INSET; 230 if (sBorderStyle == "U") 231 return BorderStyle::UNDERLINE; 232 } 233 234 CPDF_Array* pBorder = m_pAnnot->GetAnnotDict()->GetArrayFor("Border"); 235 if (pBorder) { 236 if (pBorder->GetCount() >= 4) { 237 CPDF_Array* pDP = pBorder->GetArrayAt(3); 238 if (pDP && pDP->GetCount() > 0) 239 return BorderStyle::DASH; 240 } 241 } 242 243 return BorderStyle::SOLID; 244 } 245 246 void CPDFSDK_BAAnnot::SetColor(FX_COLORREF color) { 247 CPDF_Array* pArray = m_pAnnot->GetAnnotDict()->SetNewFor<CPDF_Array>("C"); 248 pArray->AddNew<CPDF_Number>(static_cast<FX_FLOAT>(FXSYS_GetRValue(color)) / 249 255.0f); 250 pArray->AddNew<CPDF_Number>(static_cast<FX_FLOAT>(FXSYS_GetGValue(color)) / 251 255.0f); 252 pArray->AddNew<CPDF_Number>(static_cast<FX_FLOAT>(FXSYS_GetBValue(color)) / 253 255.0f); 254 } 255 256 void CPDFSDK_BAAnnot::RemoveColor() { 257 m_pAnnot->GetAnnotDict()->RemoveFor("C"); 258 } 259 260 bool CPDFSDK_BAAnnot::GetColor(FX_COLORREF& color) const { 261 if (CPDF_Array* pEntry = m_pAnnot->GetAnnotDict()->GetArrayFor("C")) { 262 size_t nCount = pEntry->GetCount(); 263 if (nCount == 1) { 264 FX_FLOAT g = pEntry->GetNumberAt(0) * 255; 265 266 color = FXSYS_RGB((int)g, (int)g, (int)g); 267 268 return true; 269 } else if (nCount == 3) { 270 FX_FLOAT r = pEntry->GetNumberAt(0) * 255; 271 FX_FLOAT g = pEntry->GetNumberAt(1) * 255; 272 FX_FLOAT b = pEntry->GetNumberAt(2) * 255; 273 274 color = FXSYS_RGB((int)r, (int)g, (int)b); 275 276 return true; 277 } else if (nCount == 4) { 278 FX_FLOAT c = pEntry->GetNumberAt(0); 279 FX_FLOAT m = pEntry->GetNumberAt(1); 280 FX_FLOAT y = pEntry->GetNumberAt(2); 281 FX_FLOAT k = pEntry->GetNumberAt(3); 282 283 FX_FLOAT r = 1.0f - std::min(1.0f, c + k); 284 FX_FLOAT g = 1.0f - std::min(1.0f, m + k); 285 FX_FLOAT b = 1.0f - std::min(1.0f, y + k); 286 287 color = FXSYS_RGB((int)(r * 255), (int)(g * 255), (int)(b * 255)); 288 289 return true; 290 } 291 } 292 293 return false; 294 } 295 296 void CPDFSDK_BAAnnot::WriteAppearance(const CFX_ByteString& sAPType, 297 const CFX_FloatRect& rcBBox, 298 const CFX_Matrix& matrix, 299 const CFX_ByteString& sContents, 300 const CFX_ByteString& sAPState) { 301 CPDF_Dictionary* pAPDict = m_pAnnot->GetAnnotDict()->GetDictFor("AP"); 302 if (!pAPDict) 303 pAPDict = m_pAnnot->GetAnnotDict()->SetNewFor<CPDF_Dictionary>("AP"); 304 305 CPDF_Stream* pStream = nullptr; 306 CPDF_Dictionary* pParentDict = nullptr; 307 if (sAPState.IsEmpty()) { 308 pParentDict = pAPDict; 309 pStream = pAPDict->GetStreamFor(sAPType); 310 } else { 311 CPDF_Dictionary* pAPTypeDict = pAPDict->GetDictFor(sAPType); 312 if (!pAPTypeDict) 313 pAPTypeDict = pAPDict->SetNewFor<CPDF_Dictionary>(sAPType); 314 315 pParentDict = pAPTypeDict; 316 pStream = pAPTypeDict->GetStreamFor(sAPState); 317 } 318 319 if (!pStream) { 320 CPDF_Document* pDoc = m_pPageView->GetPDFDocument(); 321 pStream = pDoc->NewIndirect<CPDF_Stream>(); 322 pParentDict->SetNewFor<CPDF_Reference>(sAPType, pDoc, pStream->GetObjNum()); 323 } 324 325 CPDF_Dictionary* pStreamDict = pStream->GetDict(); 326 if (!pStreamDict) { 327 auto pNewDict = pdfium::MakeUnique<CPDF_Dictionary>( 328 m_pAnnot->GetDocument()->GetByteStringPool()); 329 pStreamDict = pNewDict.get(); 330 pStreamDict->SetNewFor<CPDF_Name>("Type", "XObject"); 331 pStreamDict->SetNewFor<CPDF_Name>("Subtype", "Form"); 332 pStreamDict->SetNewFor<CPDF_Number>("FormType", 1); 333 pStream->InitStream(nullptr, 0, std::move(pNewDict)); 334 } 335 pStreamDict->SetMatrixFor("Matrix", matrix); 336 pStreamDict->SetRectFor("BBox", rcBBox); 337 pStream->SetData((uint8_t*)sContents.c_str(), sContents.GetLength()); 338 } 339 340 bool CPDFSDK_BAAnnot::IsVisible() const { 341 uint32_t nFlags = GetFlags(); 342 return !((nFlags & ANNOTFLAG_INVISIBLE) || (nFlags & ANNOTFLAG_HIDDEN) || 343 (nFlags & ANNOTFLAG_NOVIEW)); 344 } 345 346 CPDF_Action CPDFSDK_BAAnnot::GetAction() const { 347 return CPDF_Action(m_pAnnot->GetAnnotDict()->GetDictFor("A")); 348 } 349 350 void CPDFSDK_BAAnnot::SetAction(const CPDF_Action& action) { 351 CPDF_Dictionary* pDict = action.GetDict(); 352 if (pDict != m_pAnnot->GetAnnotDict()->GetDictFor("A")) { 353 CPDF_Document* pDoc = m_pPageView->GetPDFDocument(); 354 if (pDict->IsInline()) 355 pDict = pDoc->AddIndirectObject(pDict->Clone())->AsDictionary(); 356 m_pAnnot->GetAnnotDict()->SetNewFor<CPDF_Reference>("A", pDoc, 357 pDict->GetObjNum()); 358 } 359 } 360 361 void CPDFSDK_BAAnnot::RemoveAction() { 362 m_pAnnot->GetAnnotDict()->RemoveFor("A"); 363 } 364 365 CPDF_AAction CPDFSDK_BAAnnot::GetAAction() const { 366 return CPDF_AAction(m_pAnnot->GetAnnotDict()->GetDictFor("AA")); 367 } 368 369 void CPDFSDK_BAAnnot::SetAAction(const CPDF_AAction& aa) { 370 if (aa.GetDict() != m_pAnnot->GetAnnotDict()->GetDictFor("AA")) 371 m_pAnnot->GetAnnotDict()->SetFor("AA", pdfium::WrapUnique(aa.GetDict())); 372 } 373 374 void CPDFSDK_BAAnnot::RemoveAAction() { 375 m_pAnnot->GetAnnotDict()->RemoveFor("AA"); 376 } 377 378 CPDF_Action CPDFSDK_BAAnnot::GetAAction(CPDF_AAction::AActionType eAAT) { 379 CPDF_AAction AAction = GetAAction(); 380 if (AAction.ActionExist(eAAT)) 381 return AAction.GetAction(eAAT); 382 383 if (eAAT == CPDF_AAction::ButtonUp) 384 return GetAction(); 385 386 return CPDF_Action(); 387 } 388 389 void CPDFSDK_BAAnnot::Annot_OnDraw(CFX_RenderDevice* pDevice, 390 CFX_Matrix* pUser2Device, 391 CPDF_RenderOptions* pOptions) { 392 m_pAnnot->GetAPForm(m_pPageView->GetPDFPage(), CPDF_Annot::Normal); 393 m_pAnnot->DrawAppearance(m_pPageView->GetPDFPage(), pDevice, pUser2Device, 394 CPDF_Annot::Normal, nullptr); 395 } 396 397 void CPDFSDK_BAAnnot::SetOpenState(bool bOpenState) { 398 if (CPDF_Annot* pAnnot = m_pAnnot->GetPopupAnnot()) 399 pAnnot->SetOpenState(bOpenState); 400 } 401