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
CreatePopupAnnot(CPDF_Annot * pAnnot,CPDF_Document * pDocument,CPDF_Page * pPage)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
GenerateAP(CPDF_Document * pDoc,CPDF_Dictionary * pAnnotDict)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
CPDF_AnnotList(CPDF_Page * pPage)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
~CPDF_AnnotList()160 CPDF_AnnotList::~CPDF_AnnotList() {}
161
DisplayPass(CPDF_Page * pPage,CFX_RenderDevice * pDevice,CPDF_RenderContext * pContext,bool bPrinting,const CFX_Matrix * pMatrix,bool bWidgetPass,CPDF_RenderOptions * pOptions,FX_RECT * clip_rect)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
DisplayAnnots(CPDF_Page * pPage,CFX_RenderDevice * pDevice,CPDF_RenderContext * pContext,bool bPrinting,const CFX_Matrix * pUser2Device,uint32_t dwAnnotFlags,CPDF_RenderOptions * pOptions,FX_RECT * pClipRect)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
DisplayAnnots(CPDF_Page * pPage,CPDF_RenderContext * pContext,bool bPrinting,const CFX_Matrix * pMatrix,bool bShowWidget,CPDF_RenderOptions * pOptions)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