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_annotlist.h" 8 9 #include <algorithm> 10 #include <memory> 11 #include <utility> 12 13 #include "core/fpdfapi/page/cpdf_page.h" 14 #include "core/fpdfapi/parser/cpdf_array.h" 15 #include "core/fpdfapi/parser/cpdf_document.h" 16 #include "core/fpdfapi/parser/cpdf_name.h" 17 #include "core/fpdfapi/parser/cpdf_number.h" 18 #include "core/fpdfapi/parser/cpdf_reference.h" 19 #include "core/fpdfapi/parser/cpdf_string.h" 20 #include "core/fpdfapi/render/cpdf_renderoptions.h" 21 #include "core/fpdfdoc/cpdf_annot.h" 22 #include "core/fpdfdoc/cpdf_interform.h" 23 #include "core/fpdfdoc/cpdf_occontext.h" 24 #include "core/fpdfdoc/cpvt_generateap.h" 25 #include "core/fxge/cfx_renderdevice.h" 26 #include "third_party/base/ptr_util.h" 27 28 namespace { 29 30 std::unique_ptr<CPDF_Annot> CreatePopupAnnot(CPDF_Annot* pAnnot, 31 CPDF_Document* pDocument, 32 CPDF_Page* pPage) { 33 CPDF_Dictionary* pParentDict = pAnnot->GetAnnotDict(); 34 if (!pParentDict) 35 return nullptr; 36 37 // TODO(jaepark): We shouldn't strip BOM for some strings and not for others. 38 // See pdfium:593. 39 WideString sContents = pParentDict->GetUnicodeTextFor("Contents"); 40 if (sContents.IsEmpty()) 41 return nullptr; 42 43 auto pAnnotDict = 44 pdfium::MakeUnique<CPDF_Dictionary>(pDocument->GetByteStringPool()); 45 pAnnotDict->SetNewFor<CPDF_Name>("Type", "Annot"); 46 pAnnotDict->SetNewFor<CPDF_Name>("Subtype", "Popup"); 47 pAnnotDict->SetNewFor<CPDF_String>("T", pParentDict->GetStringFor("T"), 48 false); 49 pAnnotDict->SetNewFor<CPDF_String>("Contents", sContents.UTF8Encode(), false); 50 51 CFX_FloatRect rect = pParentDict->GetRectFor("Rect"); 52 rect.Normalize(); 53 CFX_FloatRect popupRect(0, 0, 200, 200); 54 // Note that if the popup can set its own dimensions, then we will need to 55 // make sure that it isn't larger than the page size. 56 if (rect.left + popupRect.Width() > pPage->GetPageWidth() && 57 rect.bottom - popupRect.Height() < 0) { 58 // If the annotation is on the bottom-right corner of the page, then place 59 // the popup above and to the left of the annotation. 60 popupRect.Translate(rect.right - popupRect.Width(), rect.top); 61 } else { 62 // Place the popup below and to the right of the annotation without getting 63 // clipped by page edges. 64 popupRect.Translate( 65 std::min(rect.left, pPage->GetPageWidth() - popupRect.Width()), 66 std::max(rect.bottom - popupRect.Height(), 0.f)); 67 } 68 69 pAnnotDict->SetRectFor("Rect", popupRect); 70 pAnnotDict->SetNewFor<CPDF_Number>("F", 0); 71 72 auto pPopupAnnot = 73 pdfium::MakeUnique<CPDF_Annot>(std::move(pAnnotDict), pDocument); 74 pAnnot->SetPopupAnnot(pPopupAnnot.get()); 75 return pPopupAnnot; 76 } 77 78 void GenerateAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict) { 79 if (!pAnnotDict || pAnnotDict->GetStringFor("Subtype") != "Widget") 80 return; 81 82 CPDF_Object* pFieldTypeObj = FPDF_GetFieldAttr(pAnnotDict, "FT"); 83 if (!pFieldTypeObj) 84 return; 85 86 ByteString field_type = pFieldTypeObj->GetString(); 87 if (field_type == "Tx") { 88 CPVT_GenerateAP::GenerateFormAP(CPVT_GenerateAP::kTextField, pDoc, 89 pAnnotDict); 90 return; 91 } 92 93 CPDF_Object* pFieldFlagsObj = FPDF_GetFieldAttr(pAnnotDict, "Ff"); 94 uint32_t flags = pFieldFlagsObj ? pFieldFlagsObj->GetInteger() : 0; 95 if (field_type == "Ch") { 96 CPVT_GenerateAP::GenerateFormAP((flags & (1 << 17)) 97 ? CPVT_GenerateAP::kComboBox 98 : CPVT_GenerateAP::kListBox, 99 pDoc, pAnnotDict); 100 return; 101 } 102 103 if (field_type != "Btn") 104 return; 105 if (flags & (1 << 16)) 106 return; 107 if (pAnnotDict->KeyExist("AS")) 108 return; 109 110 CPDF_Dictionary* pParentDict = pAnnotDict->GetDictFor("Parent"); 111 if (!pParentDict || !pParentDict->KeyExist("AS")) 112 return; 113 114 pAnnotDict->SetNewFor<CPDF_String>("AS", pParentDict->GetStringFor("AS"), 115 false); 116 return; 117 } 118 119 } // namespace 120 121 CPDF_AnnotList::CPDF_AnnotList(CPDF_Page* pPage) 122 : m_pDocument(pPage->m_pDocument.Get()) { 123 if (!pPage->m_pFormDict) 124 return; 125 126 CPDF_Array* pAnnots = pPage->m_pFormDict->GetArrayFor("Annots"); 127 if (!pAnnots) 128 return; 129 130 const CPDF_Dictionary* pRoot = m_pDocument->GetRoot(); 131 CPDF_Dictionary* pAcroForm = pRoot->GetDictFor("AcroForm"); 132 bool bRegenerateAP = pAcroForm && pAcroForm->GetBooleanFor("NeedAppearances"); 133 for (size_t i = 0; i < pAnnots->GetCount(); ++i) { 134 CPDF_Dictionary* pDict = ToDictionary(pAnnots->GetDirectObjectAt(i)); 135 if (!pDict) 136 continue; 137 const ByteString subtype = pDict->GetStringFor("Subtype"); 138 if (subtype == "Popup") { 139 // Skip creating Popup annotations in the PDF document since PDFium 140 // provides its own Popup annotations. 141 continue; 142 } 143 pAnnots->ConvertToIndirectObjectAt(i, m_pDocument); 144 m_AnnotList.push_back(pdfium::MakeUnique<CPDF_Annot>(pDict, m_pDocument)); 145 if (bRegenerateAP && subtype == "Widget" && 146 CPDF_InterForm::IsUpdateAPEnabled() && !pDict->GetDictFor("AP")) { 147 GenerateAP(m_pDocument, pDict); 148 } 149 } 150 151 size_t nAnnotListSize = m_AnnotList.size(); 152 for (size_t i = 0; i < nAnnotListSize; ++i) { 153 std::unique_ptr<CPDF_Annot> pPopupAnnot( 154 CreatePopupAnnot(m_AnnotList[i].get(), m_pDocument, pPage)); 155 if (pPopupAnnot) 156 m_AnnotList.push_back(std::move(pPopupAnnot)); 157 } 158 } 159 160 CPDF_AnnotList::~CPDF_AnnotList() {} 161 162 void CPDF_AnnotList::DisplayPass(CPDF_Page* pPage, 163 CFX_RenderDevice* pDevice, 164 CPDF_RenderContext* pContext, 165 bool bPrinting, 166 const CFX_Matrix* pMatrix, 167 bool bWidgetPass, 168 CPDF_RenderOptions* pOptions, 169 FX_RECT* clip_rect) { 170 for (const auto& pAnnot : m_AnnotList) { 171 bool bWidget = pAnnot->GetSubtype() == CPDF_Annot::Subtype::WIDGET; 172 if ((bWidgetPass && !bWidget) || (!bWidgetPass && bWidget)) 173 continue; 174 175 uint32_t annot_flags = pAnnot->GetFlags(); 176 if (annot_flags & ANNOTFLAG_HIDDEN) 177 continue; 178 179 if (bPrinting && (annot_flags & ANNOTFLAG_PRINT) == 0) 180 continue; 181 182 if (!bPrinting && (annot_flags & ANNOTFLAG_NOVIEW)) 183 continue; 184 185 if (pOptions) { 186 CPDF_Dictionary* pAnnotDict = pAnnot->GetAnnotDict(); 187 if (pOptions->GetOCContext() && pAnnotDict && 188 !pOptions->GetOCContext()->CheckOCGVisible( 189 pAnnotDict->GetDictFor("OC"))) { 190 continue; 191 } 192 } 193 194 CFX_Matrix matrix = *pMatrix; 195 if (clip_rect) { 196 FX_RECT annot_rect = 197 matrix.TransformRect(pAnnot->GetRect()).GetOuterRect(); 198 annot_rect.Intersect(*clip_rect); 199 if (annot_rect.IsEmpty()) 200 continue; 201 } 202 if (pContext) { 203 pAnnot->DrawInContext(pPage, pContext, &matrix, CPDF_Annot::Normal); 204 } else if (!pAnnot->DrawAppearance(pPage, pDevice, matrix, 205 CPDF_Annot::Normal, pOptions)) { 206 pAnnot->DrawBorder(pDevice, &matrix, pOptions); 207 } 208 } 209 } 210 211 void CPDF_AnnotList::DisplayAnnots(CPDF_Page* pPage, 212 CFX_RenderDevice* pDevice, 213 CPDF_RenderContext* pContext, 214 bool bPrinting, 215 const CFX_Matrix* pUser2Device, 216 uint32_t dwAnnotFlags, 217 CPDF_RenderOptions* pOptions, 218 FX_RECT* pClipRect) { 219 if (dwAnnotFlags & ANNOTFLAG_INVISIBLE) { 220 DisplayPass(pPage, pDevice, pContext, bPrinting, pUser2Device, false, 221 pOptions, pClipRect); 222 } 223 if (dwAnnotFlags & ANNOTFLAG_HIDDEN) { 224 DisplayPass(pPage, pDevice, pContext, bPrinting, pUser2Device, true, 225 pOptions, pClipRect); 226 } 227 } 228 229 void CPDF_AnnotList::DisplayAnnots(CPDF_Page* pPage, 230 CPDF_RenderContext* pContext, 231 bool bPrinting, 232 const CFX_Matrix* pMatrix, 233 bool bShowWidget, 234 CPDF_RenderOptions* pOptions) { 235 uint32_t dwAnnotFlags = bShowWidget ? ANNOTFLAG_INVISIBLE | ANNOTFLAG_HIDDEN 236 : ANNOTFLAG_INVISIBLE; 237 DisplayAnnots(pPage, nullptr, pContext, bPrinting, pMatrix, dwAnnotFlags, 238 pOptions, nullptr); 239 } 240