blob: 4bb244f29e65bfe7f07d04655f8d54ed9f628205 [file] [log] [blame]
dsinclair777b3332016-03-31 20:03:08 -07001// 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/cpvt_generateap.h"
8
thestig717d1332016-09-20 05:58:19 -07009#include <algorithm>
thestig69bbfa82016-11-10 10:39:01 -080010#include <memory>
11#include <utility>
thestig717d1332016-09-20 05:58:19 -070012
dsinclairbc5e6d22016-10-04 11:08:49 -070013#include "core/fpdfapi/font/cpdf_font.h"
tsepez0e606b52016-11-18 16:22:41 -080014#include "core/fpdfapi/parser/cpdf_boolean.h"
dsinclair488b7ad2016-10-04 11:55:50 -070015#include "core/fpdfapi/parser/cpdf_dictionary.h"
16#include "core/fpdfapi/parser/cpdf_document.h"
tsepez0e606b52016-11-18 16:22:41 -080017#include "core/fpdfapi/parser/cpdf_name.h"
18#include "core/fpdfapi/parser/cpdf_number.h"
19#include "core/fpdfapi/parser/cpdf_reference.h"
dsinclair488b7ad2016-10-04 11:55:50 -070020#include "core/fpdfapi/parser/cpdf_simple_parser.h"
21#include "core/fpdfapi/parser/cpdf_stream.h"
tsepez0e606b52016-11-18 16:22:41 -080022#include "core/fpdfapi/parser/cpdf_string.h"
dsinclair488b7ad2016-10-04 11:55:50 -070023#include "core/fpdfapi/parser/fpdf_parser_decode.h"
dsinclair1727aee2016-09-29 13:12:56 -070024#include "core/fpdfdoc/cpdf_annot.h"
25#include "core/fpdfdoc/cpdf_formfield.h"
dsinclair777b3332016-03-31 20:03:08 -070026#include "core/fpdfdoc/cpvt_color.h"
27#include "core/fpdfdoc/cpvt_fontmap.h"
dsinclair1727aee2016-09-29 13:12:56 -070028#include "core/fpdfdoc/cpvt_word.h"
thestig69bbfa82016-11-10 10:39:01 -080029#include "third_party/base/ptr_util.h"
dsinclair777b3332016-03-31 20:03:08 -070030
31namespace {
32
jaepark9c987e92016-07-29 18:17:44 -070033bool GenerateWidgetAP(CPDF_Document* pDoc,
34 CPDF_Dictionary* pAnnotDict,
35 const int32_t& nWidgetType) {
dsinclair777b3332016-03-31 20:03:08 -070036 CPDF_Dictionary* pFormDict = nullptr;
37 if (CPDF_Dictionary* pRootDict = pDoc->GetRoot())
dsinclair38fd8442016-09-15 10:15:32 -070038 pFormDict = pRootDict->GetDictFor("AcroForm");
dsinclair777b3332016-03-31 20:03:08 -070039 if (!pFormDict)
jaepark9c987e92016-07-29 18:17:44 -070040 return false;
dsinclair777b3332016-03-31 20:03:08 -070041
42 CFX_ByteString DA;
43 if (CPDF_Object* pDAObj = FPDF_GetFieldAttr(pAnnotDict, "DA"))
44 DA = pDAObj->GetString();
45 if (DA.IsEmpty())
dsinclair38fd8442016-09-15 10:15:32 -070046 DA = pFormDict->GetStringFor("DA");
dsinclair777b3332016-03-31 20:03:08 -070047 if (DA.IsEmpty())
jaepark9c987e92016-07-29 18:17:44 -070048 return false;
dsinclair777b3332016-03-31 20:03:08 -070049
tsepez4c3debb2016-04-08 12:20:38 -070050 CPDF_SimpleParser syntax(DA.AsStringC());
dsinclair777b3332016-03-31 20:03:08 -070051 syntax.FindTagParamFromStart("Tf", 2);
tsepez71a452f2016-05-13 17:51:27 -070052 CFX_ByteString sFontName(syntax.GetWord());
dsinclair777b3332016-03-31 20:03:08 -070053 sFontName = PDF_NameDecode(sFontName);
54 if (sFontName.IsEmpty())
jaepark9c987e92016-07-29 18:17:44 -070055 return false;
dsinclair777b3332016-03-31 20:03:08 -070056
57 FX_FLOAT fFontSize = FX_atof(syntax.GetWord());
58 CPVT_Color crText = CPVT_Color::ParseColor(DA);
dsinclair38fd8442016-09-15 10:15:32 -070059 CPDF_Dictionary* pDRDict = pFormDict->GetDictFor("DR");
npm860a2d02016-09-12 15:02:28 -070060 if (!pDRDict)
61 return false;
62
dsinclair38fd8442016-09-15 10:15:32 -070063 CPDF_Dictionary* pDRFontDict = pDRDict->GetDictFor("Font");
dsinclair777b3332016-03-31 20:03:08 -070064 if (!pDRFontDict)
jaepark9c987e92016-07-29 18:17:44 -070065 return false;
dsinclair777b3332016-03-31 20:03:08 -070066
dsinclair38fd8442016-09-15 10:15:32 -070067 CPDF_Dictionary* pFontDict = pDRFontDict->GetDictFor(sFontName.Mid(1));
dsinclair777b3332016-03-31 20:03:08 -070068 if (!pFontDict) {
tsepez5913a6c2016-11-16 17:31:18 -080069 pFontDict = pDoc->NewIndirect<CPDF_Dictionary>();
tsepez0e606b52016-11-18 16:22:41 -080070 pFontDict->SetNewFor<CPDF_Name>("Type", "Font");
71 pFontDict->SetNewFor<CPDF_Name>("Subtype", "Type1");
72 pFontDict->SetNewFor<CPDF_Name>("BaseFont", "Helvetica");
73 pFontDict->SetNewFor<CPDF_Name>("Encoding", "WinAnsiEncoding");
74 pDRFontDict->SetNewFor<CPDF_Reference>(sFontName.Mid(1), pDoc,
75 pFontDict->GetObjNum());
dsinclair777b3332016-03-31 20:03:08 -070076 }
77 CPDF_Font* pDefFont = pDoc->LoadFont(pFontDict);
78 if (!pDefFont)
jaepark9c987e92016-07-29 18:17:44 -070079 return false;
dsinclair777b3332016-03-31 20:03:08 -070080
dsinclair38fd8442016-09-15 10:15:32 -070081 CFX_FloatRect rcAnnot = pAnnotDict->GetRectFor("Rect");
dsinclair777b3332016-03-31 20:03:08 -070082 int32_t nRotate = 0;
dsinclair38fd8442016-09-15 10:15:32 -070083 if (CPDF_Dictionary* pMKDict = pAnnotDict->GetDictFor("MK"))
84 nRotate = pMKDict->GetIntegerFor("R");
dsinclair777b3332016-03-31 20:03:08 -070085
86 CFX_FloatRect rcBBox;
87 CFX_Matrix matrix;
88 switch (nRotate % 360) {
89 case 0:
90 rcBBox = CFX_FloatRect(0, 0, rcAnnot.right - rcAnnot.left,
91 rcAnnot.top - rcAnnot.bottom);
92 break;
93 case 90:
94 matrix = CFX_Matrix(0, 1, -1, 0, rcAnnot.right - rcAnnot.left, 0);
95 rcBBox = CFX_FloatRect(0, 0, rcAnnot.top - rcAnnot.bottom,
96 rcAnnot.right - rcAnnot.left);
97 break;
98 case 180:
99 matrix = CFX_Matrix(-1, 0, 0, -1, rcAnnot.right - rcAnnot.left,
100 rcAnnot.top - rcAnnot.bottom);
101 rcBBox = CFX_FloatRect(0, 0, rcAnnot.right - rcAnnot.left,
102 rcAnnot.top - rcAnnot.bottom);
103 break;
104 case 270:
105 matrix = CFX_Matrix(0, -1, 1, 0, 0, rcAnnot.top - rcAnnot.bottom);
106 rcBBox = CFX_FloatRect(0, 0, rcAnnot.top - rcAnnot.bottom,
107 rcAnnot.right - rcAnnot.left);
108 break;
109 }
dsinclair92cb5e52016-05-16 11:38:28 -0700110
111 BorderStyle nBorderStyle = BorderStyle::SOLID;
dsinclair777b3332016-03-31 20:03:08 -0700112 FX_FLOAT fBorderWidth = 1;
113 CPVT_Dash dsBorder(3, 0, 0);
114 CPVT_Color crLeftTop, crRightBottom;
dsinclair38fd8442016-09-15 10:15:32 -0700115 if (CPDF_Dictionary* pBSDict = pAnnotDict->GetDictFor("BS")) {
dsinclair777b3332016-03-31 20:03:08 -0700116 if (pBSDict->KeyExist("W"))
dsinclair38fd8442016-09-15 10:15:32 -0700117 fBorderWidth = pBSDict->GetNumberFor("W");
dsinclair777b3332016-03-31 20:03:08 -0700118
dsinclair38fd8442016-09-15 10:15:32 -0700119 if (CPDF_Array* pArray = pBSDict->GetArrayFor("D")) {
dsinclair777b3332016-03-31 20:03:08 -0700120 dsBorder = CPVT_Dash(pArray->GetIntegerAt(0), pArray->GetIntegerAt(1),
121 pArray->GetIntegerAt(2));
122 }
dsinclair38fd8442016-09-15 10:15:32 -0700123 switch (pBSDict->GetStringFor("S").GetAt(0)) {
dsinclair777b3332016-03-31 20:03:08 -0700124 case 'S':
dsinclair92cb5e52016-05-16 11:38:28 -0700125 nBorderStyle = BorderStyle::SOLID;
dsinclair777b3332016-03-31 20:03:08 -0700126 break;
127 case 'D':
dsinclair92cb5e52016-05-16 11:38:28 -0700128 nBorderStyle = BorderStyle::DASH;
dsinclair777b3332016-03-31 20:03:08 -0700129 break;
130 case 'B':
dsinclair92cb5e52016-05-16 11:38:28 -0700131 nBorderStyle = BorderStyle::BEVELED;
dsinclair777b3332016-03-31 20:03:08 -0700132 fBorderWidth *= 2;
133 crLeftTop = CPVT_Color(CPVT_Color::kGray, 1);
134 crRightBottom = CPVT_Color(CPVT_Color::kGray, 0.5);
135 break;
136 case 'I':
dsinclair92cb5e52016-05-16 11:38:28 -0700137 nBorderStyle = BorderStyle::INSET;
dsinclair777b3332016-03-31 20:03:08 -0700138 fBorderWidth *= 2;
139 crLeftTop = CPVT_Color(CPVT_Color::kGray, 0.5);
140 crRightBottom = CPVT_Color(CPVT_Color::kGray, 0.75);
141 break;
142 case 'U':
dsinclair92cb5e52016-05-16 11:38:28 -0700143 nBorderStyle = BorderStyle::UNDERLINE;
dsinclair777b3332016-03-31 20:03:08 -0700144 break;
145 }
146 }
147 CPVT_Color crBorder, crBG;
dsinclair38fd8442016-09-15 10:15:32 -0700148 if (CPDF_Dictionary* pMKDict = pAnnotDict->GetDictFor("MK")) {
149 if (CPDF_Array* pArray = pMKDict->GetArrayFor("BC"))
dsinclair777b3332016-03-31 20:03:08 -0700150 crBorder = CPVT_Color::ParseColor(*pArray);
dsinclair38fd8442016-09-15 10:15:32 -0700151 if (CPDF_Array* pArray = pMKDict->GetArrayFor("BG"))
dsinclair777b3332016-03-31 20:03:08 -0700152 crBG = CPVT_Color::ParseColor(*pArray);
153 }
154 CFX_ByteTextBuf sAppStream;
jaeparkb2e63372016-08-02 12:25:15 -0700155 CFX_ByteString sBG =
156 CPVT_GenerateAP::GenerateColorAP(crBG, PaintOperation::FILL);
dsinclair777b3332016-03-31 20:03:08 -0700157 if (sBG.GetLength() > 0) {
158 sAppStream << "q\n" << sBG << rcBBox.left << " " << rcBBox.bottom << " "
159 << rcBBox.Width() << " " << rcBBox.Height() << " re f\n"
160 << "Q\n";
161 }
162 CFX_ByteString sBorderStream = CPVT_GenerateAP::GenerateBorderAP(
163 rcBBox, fBorderWidth, crBorder, crLeftTop, crRightBottom, nBorderStyle,
164 dsBorder);
165 if (sBorderStream.GetLength() > 0)
166 sAppStream << "q\n" << sBorderStream << "Q\n";
167
168 CFX_FloatRect rcBody =
169 CFX_FloatRect(rcBBox.left + fBorderWidth, rcBBox.bottom + fBorderWidth,
170 rcBBox.right - fBorderWidth, rcBBox.top - fBorderWidth);
171 rcBody.Normalize();
tsepez0e606b52016-11-18 16:22:41 -0800172
dsinclair38fd8442016-09-15 10:15:32 -0700173 CPDF_Dictionary* pAPDict = pAnnotDict->GetDictFor("AP");
tsepez0e606b52016-11-18 16:22:41 -0800174 if (!pAPDict)
175 pAPDict = pAnnotDict->SetNewFor<CPDF_Dictionary>("AP");
176
dsinclair38fd8442016-09-15 10:15:32 -0700177 CPDF_Stream* pNormalStream = pAPDict->GetStreamFor("N");
dsinclair777b3332016-03-31 20:03:08 -0700178 if (!pNormalStream) {
tsepez70c4afd2016-11-15 11:33:44 -0800179 pNormalStream = pDoc->NewIndirect<CPDF_Stream>();
tsepez0e606b52016-11-18 16:22:41 -0800180 pAPDict->SetNewFor<CPDF_Reference>("N", pDoc, pNormalStream->GetObjNum());
dsinclair777b3332016-03-31 20:03:08 -0700181 }
182 CPDF_Dictionary* pStreamDict = pNormalStream->GetDict();
183 if (pStreamDict) {
dsinclair38fd8442016-09-15 10:15:32 -0700184 pStreamDict->SetMatrixFor("Matrix", matrix);
185 pStreamDict->SetRectFor("BBox", rcBBox);
186 CPDF_Dictionary* pStreamResList = pStreamDict->GetDictFor("Resources");
dsinclair777b3332016-03-31 20:03:08 -0700187 if (pStreamResList) {
dsinclair38fd8442016-09-15 10:15:32 -0700188 CPDF_Dictionary* pStreamResFontList = pStreamResList->GetDictFor("Font");
tsepez0e606b52016-11-18 16:22:41 -0800189 if (!pStreamResFontList)
190 pStreamResFontList = pStreamResList->SetNewFor<CPDF_Dictionary>("Font");
191 if (!pStreamResFontList->KeyExist(sFontName)) {
192 pStreamResFontList->SetNewFor<CPDF_Reference>(sFontName, pDoc,
193 pFontDict->GetObjNum());
dsinclair777b3332016-03-31 20:03:08 -0700194 }
dsinclair777b3332016-03-31 20:03:08 -0700195 } else {
tsepez0e606b52016-11-18 16:22:41 -0800196 pStreamDict->SetFor("Resources", pFormDict->GetDictFor("DR")->Clone());
dsinclair38fd8442016-09-15 10:15:32 -0700197 pStreamResList = pStreamDict->GetDictFor("Resources");
dsinclair777b3332016-03-31 20:03:08 -0700198 }
199 }
200 switch (nWidgetType) {
201 case 0: {
202 CFX_WideString swValue =
203 FPDF_GetFieldAttr(pAnnotDict, "V")
204 ? FPDF_GetFieldAttr(pAnnotDict, "V")->GetUnicodeText()
205 : CFX_WideString();
206 int32_t nAlign = FPDF_GetFieldAttr(pAnnotDict, "Q")
207 ? FPDF_GetFieldAttr(pAnnotDict, "Q")->GetInteger()
208 : 0;
209 uint32_t dwFlags = FPDF_GetFieldAttr(pAnnotDict, "Ff")
210 ? FPDF_GetFieldAttr(pAnnotDict, "Ff")->GetInteger()
211 : 0;
212 uint32_t dwMaxLen =
213 FPDF_GetFieldAttr(pAnnotDict, "MaxLen")
214 ? FPDF_GetFieldAttr(pAnnotDict, "MaxLen")->GetInteger()
215 : 0;
216 CPVT_FontMap map(
dsinclair38fd8442016-09-15 10:15:32 -0700217 pDoc, pStreamDict ? pStreamDict->GetDictFor("Resources") : nullptr,
dsinclair777b3332016-03-31 20:03:08 -0700218 pDefFont, sFontName.Right(sFontName.GetLength() - 1));
dsinclairc7a73492016-04-05 12:01:42 -0700219 CPDF_VariableText::Provider prd(&map);
dsinclair777b3332016-03-31 20:03:08 -0700220 CPDF_VariableText vt;
221 vt.SetProvider(&prd);
222 vt.SetPlateRect(rcBody);
223 vt.SetAlignment(nAlign);
224 if (IsFloatZero(fFontSize))
tsepez12f3e4a2016-11-02 15:17:29 -0700225 vt.SetAutoFontSize(true);
dsinclair777b3332016-03-31 20:03:08 -0700226 else
227 vt.SetFontSize(fFontSize);
228
tsepez12f3e4a2016-11-02 15:17:29 -0700229 bool bMultiLine = (dwFlags >> 12) & 1;
dsinclair777b3332016-03-31 20:03:08 -0700230 if (bMultiLine) {
tsepez12f3e4a2016-11-02 15:17:29 -0700231 vt.SetMultiLine(true);
232 vt.SetAutoReturn(true);
dsinclair777b3332016-03-31 20:03:08 -0700233 }
234 uint16_t subWord = 0;
235 if ((dwFlags >> 13) & 1) {
236 subWord = '*';
237 vt.SetPasswordChar(subWord);
238 }
tsepez12f3e4a2016-11-02 15:17:29 -0700239 bool bCharArray = (dwFlags >> 24) & 1;
dsinclair777b3332016-03-31 20:03:08 -0700240 if (bCharArray)
241 vt.SetCharArray(dwMaxLen);
242 else
243 vt.SetLimitChar(dwMaxLen);
244
245 vt.Initialize();
tsepez067990c2016-09-13 06:46:40 -0700246 vt.SetText(swValue);
dsinclair777b3332016-03-31 20:03:08 -0700247 vt.RearrangeAll();
248 CFX_FloatRect rcContent = vt.GetContentRect();
tsepez63f545c2016-09-13 16:08:49 -0700249 CFX_FloatPoint ptOffset;
dsinclair777b3332016-03-31 20:03:08 -0700250 if (!bMultiLine) {
251 ptOffset =
252 CFX_FloatPoint(0.0f, (rcContent.Height() - rcBody.Height()) / 2.0f);
253 }
254 CFX_ByteString sBody = CPVT_GenerateAP::GenerateEditAP(
255 &map, vt.GetIterator(), ptOffset, !bCharArray, subWord);
256 if (sBody.GetLength() > 0) {
257 sAppStream << "/Tx BMC\n"
258 << "q\n";
259 if (rcContent.Width() > rcBody.Width() ||
260 rcContent.Height() > rcBody.Height()) {
261 sAppStream << rcBody.left << " " << rcBody.bottom << " "
262 << rcBody.Width() << " " << rcBody.Height()
263 << " re\nW\nn\n";
264 }
jaeparkb2e63372016-08-02 12:25:15 -0700265 sAppStream << "BT\n"
266 << CPVT_GenerateAP::GenerateColorAP(crText,
267 PaintOperation::FILL)
dsinclair777b3332016-03-31 20:03:08 -0700268 << sBody << "ET\n"
269 << "Q\nEMC\n";
270 }
271 } break;
272 case 1: {
273 CFX_WideString swValue =
274 FPDF_GetFieldAttr(pAnnotDict, "V")
275 ? FPDF_GetFieldAttr(pAnnotDict, "V")->GetUnicodeText()
276 : CFX_WideString();
277 CPVT_FontMap map(
dsinclair38fd8442016-09-15 10:15:32 -0700278 pDoc, pStreamDict ? pStreamDict->GetDictFor("Resources") : nullptr,
dsinclair777b3332016-03-31 20:03:08 -0700279 pDefFont, sFontName.Right(sFontName.GetLength() - 1));
dsinclairc7a73492016-04-05 12:01:42 -0700280 CPDF_VariableText::Provider prd(&map);
dsinclair777b3332016-03-31 20:03:08 -0700281 CPDF_VariableText vt;
282 vt.SetProvider(&prd);
283 CFX_FloatRect rcButton = rcBody;
284 rcButton.left = rcButton.right - 13;
285 rcButton.Normalize();
286 CFX_FloatRect rcEdit = rcBody;
287 rcEdit.right = rcButton.left;
288 rcEdit.Normalize();
289 vt.SetPlateRect(rcEdit);
290 if (IsFloatZero(fFontSize))
tsepez12f3e4a2016-11-02 15:17:29 -0700291 vt.SetAutoFontSize(true);
dsinclair777b3332016-03-31 20:03:08 -0700292 else
293 vt.SetFontSize(fFontSize);
294
295 vt.Initialize();
tsepez067990c2016-09-13 06:46:40 -0700296 vt.SetText(swValue);
dsinclair777b3332016-03-31 20:03:08 -0700297 vt.RearrangeAll();
298 CFX_FloatRect rcContent = vt.GetContentRect();
299 CFX_FloatPoint ptOffset =
300 CFX_FloatPoint(0.0f, (rcContent.Height() - rcEdit.Height()) / 2.0f);
301 CFX_ByteString sEdit = CPVT_GenerateAP::GenerateEditAP(
tsepez12f3e4a2016-11-02 15:17:29 -0700302 &map, vt.GetIterator(), ptOffset, true, 0);
dsinclair777b3332016-03-31 20:03:08 -0700303 if (sEdit.GetLength() > 0) {
304 sAppStream << "/Tx BMC\n"
305 << "q\n";
306 sAppStream << rcEdit.left << " " << rcEdit.bottom << " "
307 << rcEdit.Width() << " " << rcEdit.Height() << " re\nW\nn\n";
jaeparkb2e63372016-08-02 12:25:15 -0700308 sAppStream << "BT\n"
309 << CPVT_GenerateAP::GenerateColorAP(crText,
310 PaintOperation::FILL)
dsinclair777b3332016-03-31 20:03:08 -0700311 << sEdit << "ET\n"
312 << "Q\nEMC\n";
313 }
314 CFX_ByteString sButton = CPVT_GenerateAP::GenerateColorAP(
315 CPVT_Color(CPVT_Color::kRGB, 220.0f / 255.0f, 220.0f / 255.0f,
316 220.0f / 255.0f),
jaeparkb2e63372016-08-02 12:25:15 -0700317 PaintOperation::FILL);
dsinclair777b3332016-03-31 20:03:08 -0700318 if (sButton.GetLength() > 0 && !rcButton.IsEmpty()) {
319 sAppStream << "q\n" << sButton;
320 sAppStream << rcButton.left << " " << rcButton.bottom << " "
321 << rcButton.Width() << " " << rcButton.Height() << " re f\n";
322 sAppStream << "Q\n";
323 CFX_ByteString sButtonBorder = CPVT_GenerateAP::GenerateBorderAP(
324 rcButton, 2, CPVT_Color(CPVT_Color::kGray, 0),
325 CPVT_Color(CPVT_Color::kGray, 1),
dsinclair92cb5e52016-05-16 11:38:28 -0700326 CPVT_Color(CPVT_Color::kGray, 0.5), BorderStyle::BEVELED,
dsinclair777b3332016-03-31 20:03:08 -0700327 CPVT_Dash(3, 0, 0));
328 if (sButtonBorder.GetLength() > 0)
329 sAppStream << "q\n" << sButtonBorder << "Q\n";
330
331 CFX_FloatPoint ptCenter =
332 CFX_FloatPoint((rcButton.left + rcButton.right) / 2,
333 (rcButton.top + rcButton.bottom) / 2);
334 if (IsFloatBigger(rcButton.Width(), 6) &&
335 IsFloatBigger(rcButton.Height(), 6)) {
336 sAppStream << "q\n"
337 << " 0 g\n";
338 sAppStream << ptCenter.x - 3 << " " << ptCenter.y + 1.5f << " m\n";
339 sAppStream << ptCenter.x + 3 << " " << ptCenter.y + 1.5f << " l\n";
340 sAppStream << ptCenter.x << " " << ptCenter.y - 1.5f << " l\n";
341 sAppStream << ptCenter.x - 3 << " " << ptCenter.y + 1.5f << " l f\n";
342 sAppStream << sButton << "Q\n";
343 }
344 }
345 } break;
346 case 2: {
347 CPVT_FontMap map(
dsinclair38fd8442016-09-15 10:15:32 -0700348 pDoc, pStreamDict ? pStreamDict->GetDictFor("Resources") : nullptr,
dsinclair777b3332016-03-31 20:03:08 -0700349 pDefFont, sFontName.Right(sFontName.GetLength() - 1));
dsinclairc7a73492016-04-05 12:01:42 -0700350 CPDF_VariableText::Provider prd(&map);
thestigb8bf55f2016-05-21 21:08:05 -0700351 CPDF_Array* pOpts = ToArray(FPDF_GetFieldAttr(pAnnotDict, "Opt"));
352 CPDF_Array* pSels = ToArray(FPDF_GetFieldAttr(pAnnotDict, "I"));
353 CPDF_Object* pTi = FPDF_GetFieldAttr(pAnnotDict, "TI");
354 int32_t nTop = pTi ? pTi->GetInteger() : 0;
dsinclair777b3332016-03-31 20:03:08 -0700355 CFX_ByteTextBuf sBody;
356 if (pOpts) {
357 FX_FLOAT fy = rcBody.top;
Wei Lie1aebd42016-04-11 10:02:09 -0700358 for (size_t i = nTop, sz = pOpts->GetCount(); i < sz; i++) {
dsinclair777b3332016-03-31 20:03:08 -0700359 if (IsFloatSmaller(fy, rcBody.bottom))
360 break;
361
362 if (CPDF_Object* pOpt = pOpts->GetDirectObjectAt(i)) {
363 CFX_WideString swItem;
364 if (pOpt->IsString())
365 swItem = pOpt->GetUnicodeText();
366 else if (CPDF_Array* pArray = pOpt->AsArray())
367 swItem = pArray->GetDirectObjectAt(1)->GetUnicodeText();
368
tsepez12f3e4a2016-11-02 15:17:29 -0700369 bool bSelected = false;
dsinclair777b3332016-03-31 20:03:08 -0700370 if (pSels) {
Wei Lie1aebd42016-04-11 10:02:09 -0700371 for (size_t s = 0, ssz = pSels->GetCount(); s < ssz; s++) {
ochang6b19ec62016-04-12 11:53:23 -0700372 int value = pSels->GetIntegerAt(s);
373 if (value >= 0 && i == static_cast<size_t>(value)) {
tsepez12f3e4a2016-11-02 15:17:29 -0700374 bSelected = true;
dsinclair777b3332016-03-31 20:03:08 -0700375 break;
376 }
377 }
378 }
379 CPDF_VariableText vt;
380 vt.SetProvider(&prd);
381 vt.SetPlateRect(
382 CFX_FloatRect(rcBody.left, 0.0f, rcBody.right, 0.0f));
383 vt.SetFontSize(IsFloatZero(fFontSize) ? 12.0f : fFontSize);
384
385 vt.Initialize();
tsepez067990c2016-09-13 06:46:40 -0700386 vt.SetText(swItem);
dsinclair777b3332016-03-31 20:03:08 -0700387 vt.RearrangeAll();
388 FX_FLOAT fItemHeight = vt.GetContentRect().Height();
389 if (bSelected) {
390 CFX_FloatRect rcItem = CFX_FloatRect(
391 rcBody.left, fy - fItemHeight, rcBody.right, fy);
jaeparkb2e63372016-08-02 12:25:15 -0700392 sBody << "q\n"
393 << CPVT_GenerateAP::GenerateColorAP(
394 CPVT_Color(CPVT_Color::kRGB, 0, 51.0f / 255.0f,
395 113.0f / 255.0f),
396 PaintOperation::FILL)
dsinclair777b3332016-03-31 20:03:08 -0700397 << rcItem.left << " " << rcItem.bottom << " "
398 << rcItem.Width() << " " << rcItem.Height() << " re f\n"
399 << "Q\n";
jaeparkb2e63372016-08-02 12:25:15 -0700400 sBody << "BT\n"
401 << CPVT_GenerateAP::GenerateColorAP(
402 CPVT_Color(CPVT_Color::kGray, 1),
403 PaintOperation::FILL)
dsinclair777b3332016-03-31 20:03:08 -0700404 << CPVT_GenerateAP::GenerateEditAP(&map, vt.GetIterator(),
405 CFX_FloatPoint(0.0f, fy),
tsepez12f3e4a2016-11-02 15:17:29 -0700406 true, 0)
dsinclair777b3332016-03-31 20:03:08 -0700407 << "ET\n";
408 } else {
jaeparkb2e63372016-08-02 12:25:15 -0700409 sBody << "BT\n"
410 << CPVT_GenerateAP::GenerateColorAP(crText,
411 PaintOperation::FILL)
dsinclair777b3332016-03-31 20:03:08 -0700412 << CPVT_GenerateAP::GenerateEditAP(&map, vt.GetIterator(),
413 CFX_FloatPoint(0.0f, fy),
tsepez12f3e4a2016-11-02 15:17:29 -0700414 true, 0)
dsinclair777b3332016-03-31 20:03:08 -0700415 << "ET\n";
416 }
417 fy -= fItemHeight;
418 }
419 }
420 }
421 if (sBody.GetSize() > 0) {
thestigb8bf55f2016-05-21 21:08:05 -0700422 sAppStream << "/Tx BMC\nq\n"
423 << rcBody.left << " " << rcBody.bottom << " "
424 << rcBody.Width() << " " << rcBody.Height() << " re\nW\nn\n"
425 << sBody.AsStringC() << "Q\nEMC\n";
dsinclair777b3332016-03-31 20:03:08 -0700426 }
427 } break;
428 }
429 if (pNormalStream) {
tsepeze6db16e2016-09-19 10:45:09 -0700430 pNormalStream->SetData(sAppStream.GetBuffer(), sAppStream.GetSize());
dsinclair777b3332016-03-31 20:03:08 -0700431 pStreamDict = pNormalStream->GetDict();
432 if (pStreamDict) {
dsinclair38fd8442016-09-15 10:15:32 -0700433 pStreamDict->SetMatrixFor("Matrix", matrix);
434 pStreamDict->SetRectFor("BBox", rcBBox);
435 CPDF_Dictionary* pStreamResList = pStreamDict->GetDictFor("Resources");
dsinclair777b3332016-03-31 20:03:08 -0700436 if (pStreamResList) {
dsinclair38fd8442016-09-15 10:15:32 -0700437 CPDF_Dictionary* pStreamResFontList =
438 pStreamResList->GetDictFor("Font");
dsinclair777b3332016-03-31 20:03:08 -0700439 if (!pStreamResFontList) {
tsepez0e606b52016-11-18 16:22:41 -0800440 pStreamResFontList =
441 pStreamResList->SetNewFor<CPDF_Dictionary>("Font");
dsinclair777b3332016-03-31 20:03:08 -0700442 }
tsepez0e606b52016-11-18 16:22:41 -0800443 if (!pStreamResFontList->KeyExist(sFontName)) {
444 pStreamResFontList->SetNewFor<CPDF_Reference>(sFontName, pDoc,
445 pFontDict->GetObjNum());
446 }
dsinclair777b3332016-03-31 20:03:08 -0700447 } else {
tsepez0e606b52016-11-18 16:22:41 -0800448 pStreamDict->SetFor("Resources", pFormDict->GetDictFor("DR")->Clone());
dsinclair38fd8442016-09-15 10:15:32 -0700449 pStreamResList = pStreamDict->GetDictFor("Resources");
dsinclair777b3332016-03-31 20:03:08 -0700450 }
451 }
452 }
jaepark9c987e92016-07-29 18:17:44 -0700453 return true;
dsinclair777b3332016-03-31 20:03:08 -0700454}
455
jaeparkaf7ab332016-08-09 10:23:14 -0700456CFX_ByteString GetColorStringWithDefault(CPDF_Array* pColor,
jaepark33e9b262016-08-02 16:22:52 -0700457 const CPVT_Color& crDefaultColor,
458 PaintOperation nOperation) {
jaeparkaf7ab332016-08-09 10:23:14 -0700459 if (pColor) {
jaepark33e9b262016-08-02 16:22:52 -0700460 CPVT_Color color = CPVT_Color::ParseColor(*pColor);
461 return CPVT_GenerateAP::GenerateColorAP(color, nOperation);
462 }
463
464 return CPVT_GenerateAP::GenerateColorAP(crDefaultColor, nOperation);
465}
466
jaeparkaf7ab332016-08-09 10:23:14 -0700467FX_FLOAT GetBorderWidth(const CPDF_Dictionary& pAnnotDict) {
dsinclair38fd8442016-09-15 10:15:32 -0700468 if (CPDF_Dictionary* pBorderStyleDict = pAnnotDict.GetDictFor("BS")) {
jaeparkaf7ab332016-08-09 10:23:14 -0700469 if (pBorderStyleDict->KeyExist("W"))
dsinclair38fd8442016-09-15 10:15:32 -0700470 return pBorderStyleDict->GetNumberFor("W");
jaeparkaf7ab332016-08-09 10:23:14 -0700471 }
472
dsinclair38fd8442016-09-15 10:15:32 -0700473 if (CPDF_Array* pBorderArray = pAnnotDict.GetArrayFor("Border")) {
jaeparkaf7ab332016-08-09 10:23:14 -0700474 if (pBorderArray->GetCount() > 2)
475 return pBorderArray->GetNumberAt(2);
476 }
477
478 return 1;
479}
480
481CPDF_Array* GetDashArray(const CPDF_Dictionary& pAnnotDict) {
dsinclair38fd8442016-09-15 10:15:32 -0700482 if (CPDF_Dictionary* pBorderStyleDict = pAnnotDict.GetDictFor("BS")) {
483 if (pBorderStyleDict->GetStringFor("S") == "D")
484 return pBorderStyleDict->GetArrayFor("D");
jaeparkaf7ab332016-08-09 10:23:14 -0700485 }
486
dsinclair38fd8442016-09-15 10:15:32 -0700487 if (CPDF_Array* pBorderArray = pAnnotDict.GetArrayFor("Border")) {
jaeparkaf7ab332016-08-09 10:23:14 -0700488 if (pBorderArray->GetCount() == 4)
489 return pBorderArray->GetArrayAt(3);
490 }
491
492 return nullptr;
493}
494
495CFX_ByteString GetDashPatternString(const CPDF_Dictionary& pAnnotDict) {
496 CPDF_Array* pDashArray = GetDashArray(pAnnotDict);
497 if (!pDashArray || pDashArray->IsEmpty())
498 return CFX_ByteString();
499
500 // Support maximum of ten elements in the dash array.
501 size_t pDashArrayCount = std::min<size_t>(pDashArray->GetCount(), 10);
502 CFX_ByteTextBuf sDashStream;
503
504 sDashStream << "[";
505 for (size_t i = 0; i < pDashArrayCount; ++i)
506 sDashStream << pDashArray->GetNumberAt(i) << " ";
507 sDashStream << "] 0 d\n";
508
509 return sDashStream.MakeString();
510}
511
jaepark35512aa2016-08-29 17:15:08 -0700512CFX_ByteString GetPopupContentsString(CPDF_Document* pDoc,
513 const CPDF_Dictionary& pAnnotDict,
514 CPDF_Font* pDefFont,
515 const CFX_ByteString& sFontName) {
dsinclair38fd8442016-09-15 10:15:32 -0700516 CFX_WideString swValue(pAnnotDict.GetUnicodeTextFor("T"));
jaepark35512aa2016-08-29 17:15:08 -0700517 swValue += L'\n';
dsinclair38fd8442016-09-15 10:15:32 -0700518 swValue += pAnnotDict.GetUnicodeTextFor("Contents");
jaepark35512aa2016-08-29 17:15:08 -0700519 CPVT_FontMap map(pDoc, nullptr, pDefFont, sFontName);
520
521 CPDF_VariableText::Provider prd(&map);
522 CPDF_VariableText vt;
523 vt.SetProvider(&prd);
dsinclair38fd8442016-09-15 10:15:32 -0700524 vt.SetPlateRect(pAnnotDict.GetRectFor("Rect"));
jaepark35512aa2016-08-29 17:15:08 -0700525 vt.SetFontSize(12);
tsepez12f3e4a2016-11-02 15:17:29 -0700526 vt.SetAutoReturn(true);
527 vt.SetMultiLine(true);
jaepark35512aa2016-08-29 17:15:08 -0700528
529 vt.Initialize();
tsepez067990c2016-09-13 06:46:40 -0700530 vt.SetText(swValue);
jaepark35512aa2016-08-29 17:15:08 -0700531 vt.RearrangeAll();
532 CFX_FloatPoint ptOffset(3.0f, -3.0f);
533 CFX_ByteString sContent = CPVT_GenerateAP::GenerateEditAP(
tsepez12f3e4a2016-11-02 15:17:29 -0700534 &map, vt.GetIterator(), ptOffset, false, 0);
jaepark35512aa2016-08-29 17:15:08 -0700535
536 if (sContent.IsEmpty())
537 return CFX_ByteString();
538
539 CFX_ByteTextBuf sAppStream;
540 sAppStream << "BT\n"
541 << CPVT_GenerateAP::GenerateColorAP(
542 CPVT_Color(CPVT_Color::kRGB, 0, 0, 0), PaintOperation::FILL)
543 << sContent << "ET\n"
544 << "Q\n";
545 return sAppStream.MakeString();
546}
547
thestig69bbfa82016-11-10 10:39:01 -0800548std::unique_ptr<CPDF_Dictionary> GenerateExtGStateDict(
549 const CPDF_Dictionary& pAnnotDict,
550 const CFX_ByteString& sExtGSDictName,
551 const CFX_ByteString& sBlendMode) {
552 auto pGSDict =
553 pdfium::MakeUnique<CPDF_Dictionary>(pAnnotDict.GetByteStringPool());
tsepez0e606b52016-11-18 16:22:41 -0800554 pGSDict->SetNewFor<CPDF_String>("Type", "ExtGState", false);
jaepark33e9b262016-08-02 16:22:52 -0700555
556 FX_FLOAT fOpacity =
dsinclair38fd8442016-09-15 10:15:32 -0700557 pAnnotDict.KeyExist("CA") ? pAnnotDict.GetNumberFor("CA") : 1;
tsepez0e606b52016-11-18 16:22:41 -0800558 pGSDict->SetNewFor<CPDF_Number>("CA", fOpacity);
559 pGSDict->SetNewFor<CPDF_Number>("ca", fOpacity);
560 pGSDict->SetNewFor<CPDF_Boolean>("AIS", false);
561 pGSDict->SetNewFor<CPDF_String>("BM", sBlendMode, false);
jaepark33e9b262016-08-02 16:22:52 -0700562
thestig69bbfa82016-11-10 10:39:01 -0800563 auto pExtGStateDict =
564 pdfium::MakeUnique<CPDF_Dictionary>(pAnnotDict.GetByteStringPool());
tsepez0e606b52016-11-18 16:22:41 -0800565 pExtGStateDict->SetFor(sExtGSDictName, std::move(pGSDict));
jaepark33e9b262016-08-02 16:22:52 -0700566 return pExtGStateDict;
567}
568
thestig69bbfa82016-11-10 10:39:01 -0800569std::unique_ptr<CPDF_Dictionary> GenerateResourceFontDict(
570 CPDF_Document* pDoc,
571 const CFX_ByteString& sFontDictName) {
tsepez5913a6c2016-11-16 17:31:18 -0800572 CPDF_Dictionary* pFontDict = pDoc->NewIndirect<CPDF_Dictionary>();
tsepez0e606b52016-11-18 16:22:41 -0800573 pFontDict->SetNewFor<CPDF_Name>("Type", "Font");
574 pFontDict->SetNewFor<CPDF_Name>("Subtype", "Type1");
575 pFontDict->SetNewFor<CPDF_Name>("BaseFont", "Helvetica");
576 pFontDict->SetNewFor<CPDF_Name>("Encoding", "WinAnsiEncoding");
jaepark35512aa2016-08-29 17:15:08 -0700577
thestig69bbfa82016-11-10 10:39:01 -0800578 auto pResourceFontDict =
579 pdfium::MakeUnique<CPDF_Dictionary>(pDoc->GetByteStringPool());
tsepez0e606b52016-11-18 16:22:41 -0800580 pResourceFontDict->SetNewFor<CPDF_Reference>(sFontDictName, pDoc,
581 pFontDict->GetObjNum());
jaepark35512aa2016-08-29 17:15:08 -0700582 return pResourceFontDict;
583}
584
thestig69bbfa82016-11-10 10:39:01 -0800585std::unique_ptr<CPDF_Dictionary> GenerateResourceDict(
586 CPDF_Document* pDoc,
587 std::unique_ptr<CPDF_Dictionary> pExtGStateDict,
588 std::unique_ptr<CPDF_Dictionary> pResourceFontDict) {
589 auto pResourceDict =
590 pdfium::MakeUnique<CPDF_Dictionary>(pDoc->GetByteStringPool());
jaepark35512aa2016-08-29 17:15:08 -0700591 if (pExtGStateDict)
tsepez0e606b52016-11-18 16:22:41 -0800592 pResourceDict->SetFor("ExtGState", std::move(pExtGStateDict));
jaepark35512aa2016-08-29 17:15:08 -0700593 if (pResourceFontDict)
tsepez0e606b52016-11-18 16:22:41 -0800594 pResourceDict->SetFor("Font", std::move(pResourceFontDict));
jaepark35512aa2016-08-29 17:15:08 -0700595 return pResourceDict;
596}
597
jaepark33e9b262016-08-02 16:22:52 -0700598void GenerateAndSetAPDict(CPDF_Document* pDoc,
599 CPDF_Dictionary* pAnnotDict,
600 const CFX_ByteTextBuf& sAppStream,
thestig69bbfa82016-11-10 10:39:01 -0800601 std::unique_ptr<CPDF_Dictionary> pResourceDict,
tonikitoo0a17faf2016-09-15 13:50:50 -0700602 bool bIsTextMarkupAnnotation) {
tsepez70c4afd2016-11-15 11:33:44 -0800603 CPDF_Stream* pNormalStream = pDoc->NewIndirect<CPDF_Stream>();
tsepeze6db16e2016-09-19 10:45:09 -0700604 pNormalStream->SetData(sAppStream.GetBuffer(), sAppStream.GetSize());
thestig69bbfa82016-11-10 10:39:01 -0800605
tsepez0e606b52016-11-18 16:22:41 -0800606 CPDF_Dictionary* pAPDict = pAnnotDict->SetNewFor<CPDF_Dictionary>("AP");
607 pAPDict->SetNewFor<CPDF_Reference>("N", pDoc, pNormalStream->GetObjNum());
thestig69bbfa82016-11-10 10:39:01 -0800608
tsepez70c4afd2016-11-15 11:33:44 -0800609 CPDF_Dictionary* pStreamDict = pNormalStream->GetDict();
tsepez0e606b52016-11-18 16:22:41 -0800610 pStreamDict->SetNewFor<CPDF_Number>("FormType", 1);
611 pStreamDict->SetNewFor<CPDF_String>("Subtype", "Form", false);
dsinclair38fd8442016-09-15 10:15:32 -0700612 pStreamDict->SetMatrixFor("Matrix", CFX_Matrix());
jaepark33e9b262016-08-02 16:22:52 -0700613
tonikitoo0a17faf2016-09-15 13:50:50 -0700614 CFX_FloatRect rect = bIsTextMarkupAnnotation
615 ? CPDF_Annot::RectFromQuadPoints(pAnnotDict)
616 : pAnnotDict->GetRectFor("Rect");
dsinclair38fd8442016-09-15 10:15:32 -0700617 pStreamDict->SetRectFor("BBox", rect);
tsepez0e606b52016-11-18 16:22:41 -0800618 pStreamDict->SetFor("Resources", std::move(pResourceDict));
jaepark33e9b262016-08-02 16:22:52 -0700619}
620
jaeparkaf7ab332016-08-09 10:23:14 -0700621CFX_ByteString GetPaintOperatorString(bool bIsStrokeRect, bool bIsFillRect) {
622 if (bIsStrokeRect)
623 return bIsFillRect ? "b" : "s";
624 return bIsFillRect ? "f" : "n";
625}
626
jaeparkc38de112016-08-22 17:54:56 -0700627CFX_ByteString GenerateTextSymbolAP(const CFX_FloatRect& rect) {
628 CFX_ByteTextBuf sAppStream;
629 sAppStream << CPVT_GenerateAP::GenerateColorAP(
630 CPVT_Color(CPVT_Color::kRGB, 1, 1, 0), PaintOperation::FILL);
631 sAppStream << CPVT_GenerateAP::GenerateColorAP(
632 CPVT_Color(CPVT_Color::kRGB, 0, 0, 0), PaintOperation::STROKE);
633
634 const FX_FLOAT fBorderWidth = 1;
635 sAppStream << fBorderWidth << " w\n";
636
637 const FX_FLOAT fHalfWidth = fBorderWidth / 2;
638 const FX_FLOAT fTipDelta = 4;
639
640 CFX_FloatRect outerRect1 = rect;
641 outerRect1.Deflate(fHalfWidth, fHalfWidth);
642 outerRect1.bottom += fTipDelta;
643
644 CFX_FloatRect outerRect2 = outerRect1;
645 outerRect2.left += fTipDelta;
646 outerRect2.right = outerRect2.left + fTipDelta;
647 outerRect2.top = outerRect2.bottom - fTipDelta;
648 FX_FLOAT outerRect2Middle = (outerRect2.left + outerRect2.right) / 2;
649
650 // Draw outer boxes.
651 sAppStream << outerRect1.left << " " << outerRect1.bottom << " m\n"
652 << outerRect1.left << " " << outerRect1.top << " l\n"
653 << outerRect1.right << " " << outerRect1.top << " l\n"
654 << outerRect1.right << " " << outerRect1.bottom << " l\n"
655 << outerRect2.right << " " << outerRect2.bottom << " l\n"
656 << outerRect2Middle << " " << outerRect2.top << " l\n"
657 << outerRect2.left << " " << outerRect2.bottom << " l\n"
658 << outerRect1.left << " " << outerRect1.bottom << " l\n";
659
660 // Draw inner lines.
661 CFX_FloatRect lineRect = outerRect1;
662 const FX_FLOAT fXDelta = 2;
663 const FX_FLOAT fYDelta = (lineRect.top - lineRect.bottom) / 4;
664
665 lineRect.left += fXDelta;
666 lineRect.right -= fXDelta;
667 for (int i = 0; i < 3; ++i) {
668 lineRect.top -= fYDelta;
669 sAppStream << lineRect.left << " " << lineRect.top << " m\n"
670 << lineRect.right << " " << lineRect.top << " l\n";
671 }
672 sAppStream << "B*\n";
673
674 return sAppStream.MakeString();
675}
676
dsinclair777b3332016-03-31 20:03:08 -0700677} // namespace
678
jaepark9c987e92016-07-29 18:17:44 -0700679bool FPDF_GenerateAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict) {
dsinclair38fd8442016-09-15 10:15:32 -0700680 if (!pAnnotDict || pAnnotDict->GetStringFor("Subtype") != "Widget")
jaepark9c987e92016-07-29 18:17:44 -0700681 return false;
682
thestig717d1332016-09-20 05:58:19 -0700683 CPDF_Object* pFieldTypeObj = FPDF_GetFieldAttr(pAnnotDict, "FT");
684 if (!pFieldTypeObj)
685 return false;
686
687 CFX_ByteString field_type = pFieldTypeObj->GetString();
688 if (field_type == "Tx")
dsinclair777b3332016-03-31 20:03:08 -0700689 return CPVT_GenerateAP::GenerateTextFieldAP(pDoc, pAnnotDict);
thestig717d1332016-09-20 05:58:19 -0700690
691 CPDF_Object* pFieldFlagsObj = FPDF_GetFieldAttr(pAnnotDict, "Ff");
692 uint32_t flags = pFieldFlagsObj ? pFieldFlagsObj->GetInteger() : 0;
dsinclair777b3332016-03-31 20:03:08 -0700693 if (field_type == "Ch") {
694 return (flags & (1 << 17))
695 ? CPVT_GenerateAP::GenerateComboBoxAP(pDoc, pAnnotDict)
696 : CPVT_GenerateAP::GenerateListBoxAP(pDoc, pAnnotDict);
697 }
thestig717d1332016-09-20 05:58:19 -0700698
dsinclair777b3332016-03-31 20:03:08 -0700699 if (field_type == "Btn") {
700 if (!(flags & (1 << 16))) {
701 if (!pAnnotDict->KeyExist("AS")) {
dsinclair38fd8442016-09-15 10:15:32 -0700702 if (CPDF_Dictionary* pParentDict = pAnnotDict->GetDictFor("Parent")) {
dsinclair777b3332016-03-31 20:03:08 -0700703 if (pParentDict->KeyExist("AS")) {
tsepez0e606b52016-11-18 16:22:41 -0800704 pAnnotDict->SetNewFor<CPDF_String>(
705 "AS", pParentDict->GetStringFor("AS"), false);
dsinclair777b3332016-03-31 20:03:08 -0700706 }
707 }
708 }
709 }
710 }
thestig717d1332016-09-20 05:58:19 -0700711
jaepark9c987e92016-07-29 18:17:44 -0700712 return false;
dsinclair777b3332016-03-31 20:03:08 -0700713}
714
715// Static.
jaepark9c987e92016-07-29 18:17:44 -0700716bool CPVT_GenerateAP::GenerateComboBoxAP(CPDF_Document* pDoc,
717 CPDF_Dictionary* pAnnotDict) {
dsinclair777b3332016-03-31 20:03:08 -0700718 return GenerateWidgetAP(pDoc, pAnnotDict, 1);
719}
720
721// Static.
jaepark9c987e92016-07-29 18:17:44 -0700722bool CPVT_GenerateAP::GenerateListBoxAP(CPDF_Document* pDoc,
723 CPDF_Dictionary* pAnnotDict) {
dsinclair777b3332016-03-31 20:03:08 -0700724 return GenerateWidgetAP(pDoc, pAnnotDict, 2);
725}
726
727// Static.
jaepark9c987e92016-07-29 18:17:44 -0700728bool CPVT_GenerateAP::GenerateTextFieldAP(CPDF_Document* pDoc,
729 CPDF_Dictionary* pAnnotDict) {
730 return GenerateWidgetAP(pDoc, pAnnotDict, 0);
731}
732
jaeparke7107f42016-08-09 11:40:58 -0700733bool CPVT_GenerateAP::GenerateCircleAP(CPDF_Document* pDoc,
734 CPDF_Dictionary* pAnnotDict) {
jaeparke7107f42016-08-09 11:40:58 -0700735 CFX_ByteTextBuf sAppStream;
736 CFX_ByteString sExtGSDictName = "GS";
737 sAppStream << "/" << sExtGSDictName << " gs ";
738
dsinclair38fd8442016-09-15 10:15:32 -0700739 CPDF_Array* pInteriorColor = pAnnotDict->GetArrayFor("IC");
jaeparke7107f42016-08-09 11:40:58 -0700740 sAppStream << GetColorStringWithDefault(pInteriorColor,
741 CPVT_Color(CPVT_Color::kTransparent),
742 PaintOperation::FILL);
743
dsinclair38fd8442016-09-15 10:15:32 -0700744 sAppStream << GetColorStringWithDefault(pAnnotDict->GetArrayFor("C"),
jaeparke7107f42016-08-09 11:40:58 -0700745 CPVT_Color(CPVT_Color::kRGB, 0, 0, 0),
746 PaintOperation::STROKE);
747
748 FX_FLOAT fBorderWidth = GetBorderWidth(*pAnnotDict);
749 bool bIsStrokeRect = fBorderWidth > 0;
750
751 if (bIsStrokeRect) {
752 sAppStream << fBorderWidth << " w ";
753 sAppStream << GetDashPatternString(*pAnnotDict);
754 }
755
dsinclair38fd8442016-09-15 10:15:32 -0700756 CFX_FloatRect rect = pAnnotDict->GetRectFor("Rect");
jaeparke7107f42016-08-09 11:40:58 -0700757 rect.Normalize();
758
759 if (bIsStrokeRect) {
760 // Deflating rect because stroking a path entails painting all points whose
761 // perpendicular distance from the path in user space is less than or equal
762 // to half the line width.
763 rect.Deflate(fBorderWidth / 2, fBorderWidth / 2);
764 }
765
766 const FX_FLOAT fMiddleX = (rect.left + rect.right) / 2;
767 const FX_FLOAT fMiddleY = (rect.top + rect.bottom) / 2;
768
769 // |fL| is precalculated approximate value of 4 * tan((3.14 / 2) / 4) / 3,
770 // where |fL| * radius is a good approximation of control points for
771 // arc with 90 degrees.
772 const FX_FLOAT fL = 0.5523f;
773 const FX_FLOAT fDeltaX = fL * rect.Width() / 2.0;
774 const FX_FLOAT fDeltaY = fL * rect.Height() / 2.0;
775
776 // Starting point
777 sAppStream << fMiddleX << " " << rect.top << " m\n";
778 // First Bezier Curve
779 sAppStream << fMiddleX + fDeltaX << " " << rect.top << " " << rect.right
780 << " " << fMiddleY + fDeltaY << " " << rect.right << " "
781 << fMiddleY << " c\n";
782 // Second Bezier Curve
783 sAppStream << rect.right << " " << fMiddleY - fDeltaY << " "
784 << fMiddleX + fDeltaX << " " << rect.bottom << " " << fMiddleX
785 << " " << rect.bottom << " c\n";
786 // Third Bezier Curve
787 sAppStream << fMiddleX - fDeltaX << " " << rect.bottom << " " << rect.left
788 << " " << fMiddleY - fDeltaY << " " << rect.left << " " << fMiddleY
789 << " c\n";
790 // Fourth Bezier Curve
791 sAppStream << rect.left << " " << fMiddleY + fDeltaY << " "
792 << fMiddleX - fDeltaX << " " << rect.top << " " << fMiddleX << " "
793 << rect.top << " c\n";
794
795 bool bIsFillRect = pInteriorColor && !pInteriorColor->IsEmpty();
796 sAppStream << GetPaintOperatorString(bIsStrokeRect, bIsFillRect) << "\n";
797
thestig69bbfa82016-11-10 10:39:01 -0800798 auto pExtGStateDict =
jaeparke7107f42016-08-09 11:40:58 -0700799 GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal");
thestig69bbfa82016-11-10 10:39:01 -0800800 auto pResourceDict =
801 GenerateResourceDict(pDoc, std::move(pExtGStateDict), nullptr);
802 GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, std::move(pResourceDict),
tonikitoo0a17faf2016-09-15 13:50:50 -0700803 false /*IsTextMarkupAnnotation*/);
jaeparke7107f42016-08-09 11:40:58 -0700804 return true;
805}
806
jaeparkab47ace2016-07-29 19:53:40 -0700807bool CPVT_GenerateAP::GenerateHighlightAP(CPDF_Document* pDoc,
808 CPDF_Dictionary* pAnnotDict) {
jaeparkab47ace2016-07-29 19:53:40 -0700809 CFX_ByteTextBuf sAppStream;
jaepark33e9b262016-08-02 16:22:52 -0700810 CFX_ByteString sExtGSDictName = "GS";
811 sAppStream << "/" << sExtGSDictName << " gs ";
jaeparkab47ace2016-07-29 19:53:40 -0700812
dsinclair38fd8442016-09-15 10:15:32 -0700813 sAppStream << GetColorStringWithDefault(pAnnotDict->GetArrayFor("C"),
jaeparkaf7ab332016-08-09 10:23:14 -0700814 CPVT_Color(CPVT_Color::kRGB, 1, 1, 0),
815 PaintOperation::FILL);
jaeparkab47ace2016-07-29 19:53:40 -0700816
tonikitoo0a17faf2016-09-15 13:50:50 -0700817 CFX_FloatRect rect = CPDF_Annot::RectFromQuadPoints(pAnnotDict);
jaeparkab47ace2016-07-29 19:53:40 -0700818 rect.Normalize();
819
820 sAppStream << rect.left << " " << rect.top << " m " << rect.right << " "
821 << rect.top << " l " << rect.right << " " << rect.bottom << " l "
822 << rect.left << " " << rect.bottom << " l "
823 << "h f\n";
824
thestig69bbfa82016-11-10 10:39:01 -0800825 auto pExtGStateDict =
jaepark33e9b262016-08-02 16:22:52 -0700826 GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Multiply");
thestig69bbfa82016-11-10 10:39:01 -0800827 auto pResourceDict =
828 GenerateResourceDict(pDoc, std::move(pExtGStateDict), nullptr);
829 GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, std::move(pResourceDict),
tonikitoo0a17faf2016-09-15 13:50:50 -0700830 true /*IsTextMarkupAnnotation*/);
jaeparkab47ace2016-07-29 19:53:40 -0700831
jaepark33e9b262016-08-02 16:22:52 -0700832 return true;
833}
jaeparkab47ace2016-07-29 19:53:40 -0700834
jaepark39ba18a2016-08-09 15:19:35 -0700835bool CPVT_GenerateAP::GenerateInkAP(CPDF_Document* pDoc,
836 CPDF_Dictionary* pAnnotDict) {
jaepark39ba18a2016-08-09 15:19:35 -0700837 FX_FLOAT fBorderWidth = GetBorderWidth(*pAnnotDict);
838 bool bIsStroke = fBorderWidth > 0;
839
840 if (!bIsStroke)
841 return false;
842
dsinclair38fd8442016-09-15 10:15:32 -0700843 CPDF_Array* pInkList = pAnnotDict->GetArrayFor("InkList");
jaepark39ba18a2016-08-09 15:19:35 -0700844 if (!pInkList || pInkList->IsEmpty())
845 return false;
846
847 CFX_ByteTextBuf sAppStream;
848 CFX_ByteString sExtGSDictName = "GS";
849 sAppStream << "/" << sExtGSDictName << " gs ";
850
dsinclair38fd8442016-09-15 10:15:32 -0700851 sAppStream << GetColorStringWithDefault(pAnnotDict->GetArrayFor("C"),
jaepark39ba18a2016-08-09 15:19:35 -0700852 CPVT_Color(CPVT_Color::kRGB, 0, 0, 0),
853 PaintOperation::STROKE);
854
855 sAppStream << fBorderWidth << " w ";
856 sAppStream << GetDashPatternString(*pAnnotDict);
857
858 // Set inflated rect as a new rect because paths near the border with large
859 // width should not be clipped to the original rect.
dsinclair38fd8442016-09-15 10:15:32 -0700860 CFX_FloatRect rect = pAnnotDict->GetRectFor("Rect");
jaepark39ba18a2016-08-09 15:19:35 -0700861 rect.Inflate(fBorderWidth / 2, fBorderWidth / 2);
dsinclair38fd8442016-09-15 10:15:32 -0700862 pAnnotDict->SetRectFor("Rect", rect);
jaepark39ba18a2016-08-09 15:19:35 -0700863
864 for (size_t i = 0; i < pInkList->GetCount(); i++) {
865 CPDF_Array* pInkCoordList = pInkList->GetArrayAt(i);
866 if (!pInkCoordList || pInkCoordList->GetCount() < 2)
867 continue;
868
869 sAppStream << pInkCoordList->GetNumberAt(0) << " "
870 << pInkCoordList->GetNumberAt(1) << " m ";
871
872 for (size_t j = 0; j < pInkCoordList->GetCount() - 1; j += 2) {
873 sAppStream << pInkCoordList->GetNumberAt(j) << " "
874 << pInkCoordList->GetNumberAt(j + 1) << " l ";
875 }
876
877 sAppStream << "S\n";
878 }
879
thestig69bbfa82016-11-10 10:39:01 -0800880 auto pExtGStateDict =
jaepark39ba18a2016-08-09 15:19:35 -0700881 GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal");
thestig69bbfa82016-11-10 10:39:01 -0800882 auto pResourceDict =
883 GenerateResourceDict(pDoc, std::move(pExtGStateDict), nullptr);
884 GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, std::move(pResourceDict),
tonikitoo0a17faf2016-09-15 13:50:50 -0700885 false /*IsTextMarkupAnnotation*/);
jaepark39ba18a2016-08-09 15:19:35 -0700886 return true;
887}
888
jaeparkc38de112016-08-22 17:54:56 -0700889bool CPVT_GenerateAP::GenerateTextAP(CPDF_Document* pDoc,
890 CPDF_Dictionary* pAnnotDict) {
jaeparkc38de112016-08-22 17:54:56 -0700891 CFX_ByteTextBuf sAppStream;
892 CFX_ByteString sExtGSDictName = "GS";
893 sAppStream << "/" << sExtGSDictName << " gs ";
894
dsinclair38fd8442016-09-15 10:15:32 -0700895 CFX_FloatRect rect = pAnnotDict->GetRectFor("Rect");
jaeparkc38de112016-08-22 17:54:56 -0700896 const FX_FLOAT fNoteLength = 20;
897 CFX_FloatRect noteRect(rect.left, rect.bottom, rect.left + fNoteLength,
898 rect.bottom + fNoteLength);
dsinclair38fd8442016-09-15 10:15:32 -0700899 pAnnotDict->SetRectFor("Rect", noteRect);
jaeparkc38de112016-08-22 17:54:56 -0700900
901 sAppStream << GenerateTextSymbolAP(noteRect);
902
thestig69bbfa82016-11-10 10:39:01 -0800903 auto pExtGStateDict =
jaeparkc38de112016-08-22 17:54:56 -0700904 GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal");
thestig69bbfa82016-11-10 10:39:01 -0800905 auto pResourceDict =
906 GenerateResourceDict(pDoc, std::move(pExtGStateDict), nullptr);
907 GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, std::move(pResourceDict),
tonikitoo0a17faf2016-09-15 13:50:50 -0700908 false /*IsTextMarkupAnnotation*/);
jaeparkc38de112016-08-22 17:54:56 -0700909 return true;
910}
911
jaepark33e9b262016-08-02 16:22:52 -0700912bool CPVT_GenerateAP::GenerateUnderlineAP(CPDF_Document* pDoc,
913 CPDF_Dictionary* pAnnotDict) {
jaepark33e9b262016-08-02 16:22:52 -0700914 CFX_ByteTextBuf sAppStream;
915 CFX_ByteString sExtGSDictName = "GS";
916 sAppStream << "/" << sExtGSDictName << " gs ";
jaeparkab47ace2016-07-29 19:53:40 -0700917
dsinclair38fd8442016-09-15 10:15:32 -0700918 sAppStream << GetColorStringWithDefault(pAnnotDict->GetArrayFor("C"),
jaepark33e9b262016-08-02 16:22:52 -0700919 CPVT_Color(CPVT_Color::kRGB, 0, 0, 0),
920 PaintOperation::STROKE);
jaepark2d7ab182016-08-01 18:07:21 -0700921
tonikitoo0a17faf2016-09-15 13:50:50 -0700922 CFX_FloatRect rect = CPDF_Annot::RectFromQuadPoints(pAnnotDict);
jaepark33e9b262016-08-02 16:22:52 -0700923 rect.Normalize();
jaeparkab47ace2016-07-29 19:53:40 -0700924
jaepark33e9b262016-08-02 16:22:52 -0700925 FX_FLOAT fLineWidth = 1.0;
926 sAppStream << fLineWidth << " w " << rect.left << " "
927 << rect.bottom + fLineWidth << " m " << rect.right << " "
928 << rect.bottom + fLineWidth << " l S\n";
jaeparkab47ace2016-07-29 19:53:40 -0700929
thestig69bbfa82016-11-10 10:39:01 -0800930 auto pExtGStateDict =
jaepark33e9b262016-08-02 16:22:52 -0700931 GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal");
thestig69bbfa82016-11-10 10:39:01 -0800932 auto pResourceDict =
933 GenerateResourceDict(pDoc, std::move(pExtGStateDict), nullptr);
934 GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, std::move(pResourceDict),
tonikitoo0a17faf2016-09-15 13:50:50 -0700935 true /*IsTextMarkupAnnotation*/);
jaepark35512aa2016-08-29 17:15:08 -0700936 return true;
937}
938
939bool CPVT_GenerateAP::GeneratePopupAP(CPDF_Document* pDoc,
940 CPDF_Dictionary* pAnnotDict) {
941 CFX_ByteTextBuf sAppStream;
942 CFX_ByteString sExtGSDictName = "GS";
943 sAppStream << "/" << sExtGSDictName << " gs\n";
944
945 sAppStream << GenerateColorAP(CPVT_Color(CPVT_Color::kRGB, 1, 1, 0),
946 PaintOperation::FILL);
947 sAppStream << GenerateColorAP(CPVT_Color(CPVT_Color::kRGB, 0, 0, 0),
948 PaintOperation::STROKE);
949
950 const FX_FLOAT fBorderWidth = 1;
951 sAppStream << fBorderWidth << " w\n";
952
dsinclair38fd8442016-09-15 10:15:32 -0700953 CFX_FloatRect rect = pAnnotDict->GetRectFor("Rect");
jaepark35512aa2016-08-29 17:15:08 -0700954 rect.Normalize();
955 rect.Deflate(fBorderWidth / 2, fBorderWidth / 2);
956
957 sAppStream << rect.left << " " << rect.bottom << " " << rect.Width() << " "
958 << rect.Height() << " re b\n";
959
960 CFX_ByteString sFontName = "FONT";
thestig69bbfa82016-11-10 10:39:01 -0800961 auto pResourceFontDict = GenerateResourceFontDict(pDoc, sFontName);
962 CPDF_Font* pDefFont = pDoc->LoadFont(pResourceFontDict.get());
jaepark35512aa2016-08-29 17:15:08 -0700963 if (!pDefFont)
964 return false;
965
thestig69bbfa82016-11-10 10:39:01 -0800966 auto pExtGStateDict =
967 GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal");
968 auto pResourceDict = GenerateResourceDict(pDoc, std::move(pResourceFontDict),
969 std::move(pExtGStateDict));
970
jaepark35512aa2016-08-29 17:15:08 -0700971 sAppStream << GetPopupContentsString(pDoc, *pAnnotDict, pDefFont, sFontName);
thestig69bbfa82016-11-10 10:39:01 -0800972 GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, std::move(pResourceDict),
tonikitoo0a17faf2016-09-15 13:50:50 -0700973 false /*IsTextMarkupAnnotation*/);
jaeparkab47ace2016-07-29 19:53:40 -0700974 return true;
975}
976
jaeparkaf7ab332016-08-09 10:23:14 -0700977bool CPVT_GenerateAP::GenerateSquareAP(CPDF_Document* pDoc,
978 CPDF_Dictionary* pAnnotDict) {
jaeparkaf7ab332016-08-09 10:23:14 -0700979 CFX_ByteTextBuf sAppStream;
980 CFX_ByteString sExtGSDictName = "GS";
981 sAppStream << "/" << sExtGSDictName << " gs ";
982
dsinclair38fd8442016-09-15 10:15:32 -0700983 CPDF_Array* pInteriorColor = pAnnotDict->GetArrayFor("IC");
jaeparkaf7ab332016-08-09 10:23:14 -0700984 sAppStream << GetColorStringWithDefault(pInteriorColor,
985 CPVT_Color(CPVT_Color::kTransparent),
986 PaintOperation::FILL);
987
dsinclair38fd8442016-09-15 10:15:32 -0700988 sAppStream << GetColorStringWithDefault(pAnnotDict->GetArrayFor("C"),
jaeparkaf7ab332016-08-09 10:23:14 -0700989 CPVT_Color(CPVT_Color::kRGB, 0, 0, 0),
990 PaintOperation::STROKE);
991
992 FX_FLOAT fBorderWidth = GetBorderWidth(*pAnnotDict);
993 bool bIsStrokeRect = fBorderWidth > 0;
994
995 if (bIsStrokeRect) {
996 sAppStream << fBorderWidth << " w ";
997 sAppStream << GetDashPatternString(*pAnnotDict);
998 }
999
dsinclair38fd8442016-09-15 10:15:32 -07001000 CFX_FloatRect rect = pAnnotDict->GetRectFor("Rect");
jaeparkaf7ab332016-08-09 10:23:14 -07001001 rect.Normalize();
1002
1003 if (bIsStrokeRect) {
1004 // Deflating rect because stroking a path entails painting all points whose
1005 // perpendicular distance from the path in user space is less than or equal
1006 // to half the line width.
1007 rect.Deflate(fBorderWidth / 2, fBorderWidth / 2);
1008 }
1009
1010 bool bIsFillRect = pInteriorColor && (pInteriorColor->GetCount() > 0);
1011
1012 sAppStream << rect.left << " " << rect.bottom << " " << rect.Width() << " "
1013 << rect.Height() << " re "
1014 << GetPaintOperatorString(bIsStrokeRect, bIsFillRect) << "\n";
1015
thestig69bbfa82016-11-10 10:39:01 -08001016 auto pExtGStateDict =
jaeparkaf7ab332016-08-09 10:23:14 -07001017 GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal");
thestig69bbfa82016-11-10 10:39:01 -08001018 auto pResourceDict =
1019 GenerateResourceDict(pDoc, std::move(pExtGStateDict), nullptr);
1020 GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, std::move(pResourceDict),
tonikitoo0a17faf2016-09-15 13:50:50 -07001021 false /*IsTextMarkupAnnotation*/);
jaeparkaf7ab332016-08-09 10:23:14 -07001022 return true;
1023}
1024
jaepark96a07862016-08-03 14:17:02 -07001025bool CPVT_GenerateAP::GenerateSquigglyAP(CPDF_Document* pDoc,
1026 CPDF_Dictionary* pAnnotDict) {
jaepark96a07862016-08-03 14:17:02 -07001027 CFX_ByteTextBuf sAppStream;
1028 CFX_ByteString sExtGSDictName = "GS";
1029 sAppStream << "/" << sExtGSDictName << " gs ";
1030
dsinclair38fd8442016-09-15 10:15:32 -07001031 sAppStream << GetColorStringWithDefault(pAnnotDict->GetArrayFor("C"),
jaepark96a07862016-08-03 14:17:02 -07001032 CPVT_Color(CPVT_Color::kRGB, 0, 0, 0),
1033 PaintOperation::STROKE);
1034
tonikitoo0a17faf2016-09-15 13:50:50 -07001035 CFX_FloatRect rect = CPDF_Annot::RectFromQuadPoints(pAnnotDict);
jaepark96a07862016-08-03 14:17:02 -07001036 rect.Normalize();
1037
1038 FX_FLOAT fLineWidth = 1.0;
1039 sAppStream << fLineWidth << " w ";
1040
1041 const FX_FLOAT fDelta = 2.0;
1042 const FX_FLOAT fTop = rect.bottom + fDelta;
1043 const FX_FLOAT fBottom = rect.bottom;
1044
1045 sAppStream << rect.left << " " << fTop << " m ";
1046
1047 FX_FLOAT fX = rect.left + fDelta;
1048 bool isUpwards = false;
1049
1050 while (fX < rect.right) {
1051 sAppStream << fX << " " << (isUpwards ? fTop : fBottom) << " l ";
1052
1053 fX += fDelta;
1054 isUpwards = !isUpwards;
1055 }
1056
1057 FX_FLOAT fRemainder = rect.right - (fX - fDelta);
1058 if (isUpwards)
1059 sAppStream << rect.right << " " << fBottom + fRemainder << " l ";
1060 else
1061 sAppStream << rect.right << " " << fTop - fRemainder << " l ";
1062
1063 sAppStream << "S\n";
1064
thestig69bbfa82016-11-10 10:39:01 -08001065 auto pExtGStateDict =
jaepark96a07862016-08-03 14:17:02 -07001066 GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal");
thestig69bbfa82016-11-10 10:39:01 -08001067 auto pResourceDict =
1068 GenerateResourceDict(pDoc, std::move(pExtGStateDict), nullptr);
1069 GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, std::move(pResourceDict),
tonikitoo0a17faf2016-09-15 13:50:50 -07001070 true /*IsTextMarkupAnnotation*/);
jaepark96a07862016-08-03 14:17:02 -07001071 return true;
1072}
1073
jaepark0d8c2d12016-08-02 17:32:23 -07001074bool CPVT_GenerateAP::GenerateStrikeOutAP(CPDF_Document* pDoc,
1075 CPDF_Dictionary* pAnnotDict) {
jaepark0d8c2d12016-08-02 17:32:23 -07001076 CFX_ByteTextBuf sAppStream;
1077 CFX_ByteString sExtGSDictName = "GS";
1078 sAppStream << "/" << sExtGSDictName << " gs ";
1079
dsinclair38fd8442016-09-15 10:15:32 -07001080 sAppStream << GetColorStringWithDefault(pAnnotDict->GetArrayFor("C"),
jaepark0d8c2d12016-08-02 17:32:23 -07001081 CPVT_Color(CPVT_Color::kRGB, 0, 0, 0),
1082 PaintOperation::STROKE);
1083
tonikitoo0a17faf2016-09-15 13:50:50 -07001084 CFX_FloatRect rect = CPDF_Annot::RectFromQuadPoints(pAnnotDict);
jaepark0d8c2d12016-08-02 17:32:23 -07001085 rect.Normalize();
1086
1087 FX_FLOAT fLineWidth = 1.0;
1088 FX_FLOAT fY = (rect.top + rect.bottom) / 2;
1089 sAppStream << fLineWidth << " w " << rect.left << " " << fY << " m "
1090 << rect.right << " " << fY << " l S\n";
1091
thestig69bbfa82016-11-10 10:39:01 -08001092 auto pExtGStateDict =
jaepark0d8c2d12016-08-02 17:32:23 -07001093 GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal");
thestig69bbfa82016-11-10 10:39:01 -08001094 auto pResourceDict =
1095 GenerateResourceDict(pDoc, std::move(pExtGStateDict), nullptr);
1096 GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, std::move(pResourceDict),
tonikitoo0a17faf2016-09-15 13:50:50 -07001097 true /*IsTextMarkupAnnotation*/);
jaepark0d8c2d12016-08-02 17:32:23 -07001098 return true;
1099}
1100
jaepark9c987e92016-07-29 18:17:44 -07001101// Static.
dsinclair777b3332016-03-31 20:03:08 -07001102CFX_ByteString CPVT_GenerateAP::GenerateEditAP(
1103 IPVT_FontMap* pFontMap,
dsinclairc7a73492016-04-05 12:01:42 -07001104 CPDF_VariableText::Iterator* pIterator,
dsinclair777b3332016-03-31 20:03:08 -07001105 const CFX_FloatPoint& ptOffset,
tsepez12f3e4a2016-11-02 15:17:29 -07001106 bool bContinuous,
thestig2c3a16a2016-05-10 13:24:16 -07001107 uint16_t SubWord) {
thestig594b20b2016-05-12 21:56:43 -07001108 CFX_ByteTextBuf sEditStream;
1109 CFX_ByteTextBuf sLineStream;
1110 CFX_ByteTextBuf sWords;
tsepez63f545c2016-09-13 16:08:49 -07001111 CFX_FloatPoint ptOld;
1112 CFX_FloatPoint ptNew;
dsinclair777b3332016-03-31 20:03:08 -07001113 int32_t nCurFontIndex = -1;
tsepez63f545c2016-09-13 16:08:49 -07001114 CPVT_WordPlace oldplace;
thestig594b20b2016-05-12 21:56:43 -07001115
thestig821d59e2016-05-11 12:59:22 -07001116 pIterator->SetAt(0);
thestig821d59e2016-05-11 12:59:22 -07001117 while (pIterator->NextWord()) {
1118 CPVT_WordPlace place = pIterator->GetAt();
1119 if (bContinuous) {
1120 if (place.LineCmp(oldplace) != 0) {
1121 if (sWords.GetSize() > 0) {
tsepez71a452f2016-05-13 17:51:27 -07001122 sLineStream << GetWordRenderString(sWords.MakeString());
thestig821d59e2016-05-11 12:59:22 -07001123 sEditStream << sLineStream;
1124 sLineStream.Clear();
1125 sWords.Clear();
dsinclair777b3332016-03-31 20:03:08 -07001126 }
1127 CPVT_Word word;
1128 if (pIterator->GetWord(word)) {
dsinclair777b3332016-03-31 20:03:08 -07001129 ptNew = CFX_FloatPoint(word.ptWord.x + ptOffset.x,
1130 word.ptWord.y + ptOffset.y);
thestig821d59e2016-05-11 12:59:22 -07001131 } else {
1132 CPVT_Line line;
1133 pIterator->GetLine(line);
1134 ptNew = CFX_FloatPoint(line.ptLine.x + ptOffset.x,
1135 line.ptLine.y + ptOffset.y);
1136 }
tsepez63f545c2016-09-13 16:08:49 -07001137 if (ptNew != ptOld) {
thestig821d59e2016-05-11 12:59:22 -07001138 sLineStream << ptNew.x - ptOld.x << " " << ptNew.y - ptOld.y
1139 << " Td\n";
1140 ptOld = ptNew;
dsinclair777b3332016-03-31 20:03:08 -07001141 }
1142 }
thestig821d59e2016-05-11 12:59:22 -07001143 CPVT_Word word;
1144 if (pIterator->GetWord(word)) {
1145 if (word.nFontIndex != nCurFontIndex) {
1146 if (sWords.GetSize() > 0) {
tsepez71a452f2016-05-13 17:51:27 -07001147 sLineStream << GetWordRenderString(sWords.MakeString());
thestig821d59e2016-05-11 12:59:22 -07001148 sWords.Clear();
1149 }
1150 sLineStream << GetFontSetString(pFontMap, word.nFontIndex,
1151 word.fFontSize);
1152 nCurFontIndex = word.nFontIndex;
1153 }
1154 sWords << GetPDFWordString(pFontMap, nCurFontIndex, word.Word, SubWord);
1155 }
1156 oldplace = place;
1157 } else {
1158 CPVT_Word word;
1159 if (pIterator->GetWord(word)) {
1160 ptNew = CFX_FloatPoint(word.ptWord.x + ptOffset.x,
1161 word.ptWord.y + ptOffset.y);
tsepez63f545c2016-09-13 16:08:49 -07001162 if (ptNew != ptOld) {
thestig821d59e2016-05-11 12:59:22 -07001163 sEditStream << ptNew.x - ptOld.x << " " << ptNew.y - ptOld.y
1164 << " Td\n";
1165 ptOld = ptNew;
1166 }
1167 if (word.nFontIndex != nCurFontIndex) {
1168 sEditStream << GetFontSetString(pFontMap, word.nFontIndex,
1169 word.fFontSize);
1170 nCurFontIndex = word.nFontIndex;
1171 }
1172 sEditStream << GetWordRenderString(
1173 GetPDFWordString(pFontMap, nCurFontIndex, word.Word, SubWord));
1174 }
dsinclair777b3332016-03-31 20:03:08 -07001175 }
thestig821d59e2016-05-11 12:59:22 -07001176 }
1177 if (sWords.GetSize() > 0) {
tsepez71a452f2016-05-13 17:51:27 -07001178 sLineStream << GetWordRenderString(sWords.MakeString());
thestig821d59e2016-05-11 12:59:22 -07001179 sEditStream << sLineStream;
1180 sWords.Clear();
dsinclair777b3332016-03-31 20:03:08 -07001181 }
tsepez71a452f2016-05-13 17:51:27 -07001182 return sEditStream.MakeString();
dsinclair777b3332016-03-31 20:03:08 -07001183}
1184
1185// Static.
1186CFX_ByteString CPVT_GenerateAP::GenerateBorderAP(
1187 const CFX_FloatRect& rect,
1188 FX_FLOAT fWidth,
1189 const CPVT_Color& color,
1190 const CPVT_Color& crLeftTop,
1191 const CPVT_Color& crRightBottom,
dsinclair92cb5e52016-05-16 11:38:28 -07001192 BorderStyle nStyle,
dsinclair777b3332016-03-31 20:03:08 -07001193 const CPVT_Dash& dash) {
1194 CFX_ByteTextBuf sAppStream;
1195 CFX_ByteString sColor;
1196 FX_FLOAT fLeft = rect.left;
1197 FX_FLOAT fRight = rect.right;
1198 FX_FLOAT fTop = rect.top;
1199 FX_FLOAT fBottom = rect.bottom;
1200 if (fWidth > 0.0f) {
1201 FX_FLOAT fHalfWidth = fWidth / 2.0f;
1202 switch (nStyle) {
1203 default:
dsinclair92cb5e52016-05-16 11:38:28 -07001204 case BorderStyle::SOLID:
jaeparkb2e63372016-08-02 12:25:15 -07001205 sColor = GenerateColorAP(color, PaintOperation::FILL);
dsinclair777b3332016-03-31 20:03:08 -07001206 if (sColor.GetLength() > 0) {
1207 sAppStream << sColor;
1208 sAppStream << fLeft << " " << fBottom << " " << fRight - fLeft << " "
1209 << fTop - fBottom << " re\n";
1210 sAppStream << fLeft + fWidth << " " << fBottom + fWidth << " "
1211 << fRight - fLeft - fWidth * 2 << " "
1212 << fTop - fBottom - fWidth * 2 << " re\n";
1213 sAppStream << "f*\n";
1214 }
1215 break;
dsinclair92cb5e52016-05-16 11:38:28 -07001216 case BorderStyle::DASH:
jaeparkb2e63372016-08-02 12:25:15 -07001217 sColor = GenerateColorAP(color, PaintOperation::STROKE);
dsinclair777b3332016-03-31 20:03:08 -07001218 if (sColor.GetLength() > 0) {
1219 sAppStream << sColor;
1220 sAppStream << fWidth << " w"
1221 << " [" << dash.nDash << " " << dash.nGap << "] "
1222 << dash.nPhase << " d\n";
1223 sAppStream << fLeft + fWidth / 2 << " " << fBottom + fWidth / 2
1224 << " m\n";
1225 sAppStream << fLeft + fWidth / 2 << " " << fTop - fWidth / 2
1226 << " l\n";
1227 sAppStream << fRight - fWidth / 2 << " " << fTop - fWidth / 2
1228 << " l\n";
1229 sAppStream << fRight - fWidth / 2 << " " << fBottom + fWidth / 2
1230 << " l\n";
1231 sAppStream << fLeft + fWidth / 2 << " " << fBottom + fWidth / 2
1232 << " l S\n";
1233 }
1234 break;
dsinclair92cb5e52016-05-16 11:38:28 -07001235 case BorderStyle::BEVELED:
1236 case BorderStyle::INSET:
jaeparkb2e63372016-08-02 12:25:15 -07001237 sColor = GenerateColorAP(crLeftTop, PaintOperation::FILL);
dsinclair777b3332016-03-31 20:03:08 -07001238 if (sColor.GetLength() > 0) {
1239 sAppStream << sColor;
1240 sAppStream << fLeft + fHalfWidth << " " << fBottom + fHalfWidth
1241 << " m\n";
1242 sAppStream << fLeft + fHalfWidth << " " << fTop - fHalfWidth
1243 << " l\n";
1244 sAppStream << fRight - fHalfWidth << " " << fTop - fHalfWidth
1245 << " l\n";
1246 sAppStream << fRight - fHalfWidth * 2 << " " << fTop - fHalfWidth * 2
1247 << " l\n";
1248 sAppStream << fLeft + fHalfWidth * 2 << " " << fTop - fHalfWidth * 2
1249 << " l\n";
1250 sAppStream << fLeft + fHalfWidth * 2 << " "
1251 << fBottom + fHalfWidth * 2 << " l f\n";
1252 }
jaeparkb2e63372016-08-02 12:25:15 -07001253 sColor = GenerateColorAP(crRightBottom, PaintOperation::FILL);
dsinclair777b3332016-03-31 20:03:08 -07001254 if (sColor.GetLength() > 0) {
1255 sAppStream << sColor;
1256 sAppStream << fRight - fHalfWidth << " " << fTop - fHalfWidth
1257 << " m\n";
1258 sAppStream << fRight - fHalfWidth << " " << fBottom + fHalfWidth
1259 << " l\n";
1260 sAppStream << fLeft + fHalfWidth << " " << fBottom + fHalfWidth
1261 << " l\n";
1262 sAppStream << fLeft + fHalfWidth * 2 << " "
1263 << fBottom + fHalfWidth * 2 << " l\n";
1264 sAppStream << fRight - fHalfWidth * 2 << " "
1265 << fBottom + fHalfWidth * 2 << " l\n";
1266 sAppStream << fRight - fHalfWidth * 2 << " " << fTop - fHalfWidth * 2
1267 << " l f\n";
1268 }
jaeparkb2e63372016-08-02 12:25:15 -07001269 sColor = GenerateColorAP(color, PaintOperation::FILL);
dsinclair777b3332016-03-31 20:03:08 -07001270 if (sColor.GetLength() > 0) {
1271 sAppStream << sColor;
1272 sAppStream << fLeft << " " << fBottom << " " << fRight - fLeft << " "
1273 << fTop - fBottom << " re\n";
1274 sAppStream << fLeft + fHalfWidth << " " << fBottom + fHalfWidth << " "
1275 << fRight - fLeft - fHalfWidth * 2 << " "
1276 << fTop - fBottom - fHalfWidth * 2 << " re f*\n";
1277 }
1278 break;
dsinclair92cb5e52016-05-16 11:38:28 -07001279 case BorderStyle::UNDERLINE:
jaeparkb2e63372016-08-02 12:25:15 -07001280 sColor = GenerateColorAP(color, PaintOperation::STROKE);
dsinclair777b3332016-03-31 20:03:08 -07001281 if (sColor.GetLength() > 0) {
1282 sAppStream << sColor;
1283 sAppStream << fWidth << " w\n";
1284 sAppStream << fLeft << " " << fBottom + fWidth / 2 << " m\n";
1285 sAppStream << fRight << " " << fBottom + fWidth / 2 << " l S\n";
1286 }
1287 break;
1288 }
1289 }
tsepez71a452f2016-05-13 17:51:27 -07001290 return sAppStream.MakeString();
dsinclair777b3332016-03-31 20:03:08 -07001291}
1292
1293// Static.
1294CFX_ByteString CPVT_GenerateAP::GenerateColorAP(const CPVT_Color& color,
jaeparkb2e63372016-08-02 12:25:15 -07001295 PaintOperation nOperation) {
dsinclair777b3332016-03-31 20:03:08 -07001296 CFX_ByteTextBuf sColorStream;
1297 switch (color.nColorType) {
1298 case CPVT_Color::kRGB:
1299 sColorStream << color.fColor1 << " " << color.fColor2 << " "
jaeparkb2e63372016-08-02 12:25:15 -07001300 << color.fColor3 << " "
1301 << (nOperation == PaintOperation::STROKE ? "RG" : "rg")
dsinclair777b3332016-03-31 20:03:08 -07001302 << "\n";
1303 break;
1304 case CPVT_Color::kGray:
jaeparkb2e63372016-08-02 12:25:15 -07001305 sColorStream << color.fColor1 << " "
1306 << (nOperation == PaintOperation::STROKE ? "G" : "g")
dsinclair777b3332016-03-31 20:03:08 -07001307 << "\n";
1308 break;
1309 case CPVT_Color::kCMYK:
1310 sColorStream << color.fColor1 << " " << color.fColor2 << " "
1311 << color.fColor3 << " " << color.fColor4 << " "
jaeparkb2e63372016-08-02 12:25:15 -07001312 << (nOperation == PaintOperation::STROKE ? "K" : "k")
1313 << "\n";
dsinclair777b3332016-03-31 20:03:08 -07001314 break;
1315 case CPVT_Color::kTransparent:
1316 break;
1317 }
tsepez71a452f2016-05-13 17:51:27 -07001318 return sColorStream.MakeString();
dsinclair777b3332016-03-31 20:03:08 -07001319}
1320
1321// Static.
1322CFX_ByteString CPVT_GenerateAP::GetPDFWordString(IPVT_FontMap* pFontMap,
1323 int32_t nFontIndex,
1324 uint16_t Word,
1325 uint16_t SubWord) {
1326 CFX_ByteString sWord;
1327 if (SubWord > 0) {
1328 sWord.Format("%c", SubWord);
1329 return sWord;
1330 }
1331
1332 if (!pFontMap)
1333 return sWord;
1334
1335 if (CPDF_Font* pPDFFont = pFontMap->GetPDFFont(nFontIndex)) {
1336 if (pPDFFont->GetBaseFont().Compare("Symbol") == 0 ||
1337 pPDFFont->GetBaseFont().Compare("ZapfDingbats") == 0) {
1338 sWord.Format("%c", Word);
1339 } else {
1340 uint32_t dwCharCode = pPDFFont->CharCodeFromUnicode(Word);
1341 if (dwCharCode != CPDF_Font::kInvalidCharCode)
1342 pPDFFont->AppendChar(sWord, dwCharCode);
1343 }
1344 }
1345 return sWord;
1346}
1347
1348// Static.
1349CFX_ByteString CPVT_GenerateAP::GetWordRenderString(
1350 const CFX_ByteString& strWords) {
1351 if (strWords.GetLength() > 0)
1352 return PDF_EncodeString(strWords) + " Tj\n";
1353 return "";
1354}
1355
1356// Static.
1357CFX_ByteString CPVT_GenerateAP::GetFontSetString(IPVT_FontMap* pFontMap,
1358 int32_t nFontIndex,
1359 FX_FLOAT fFontSize) {
1360 CFX_ByteTextBuf sRet;
1361 if (pFontMap) {
1362 CFX_ByteString sFontAlias = pFontMap->GetPDFFontAlias(nFontIndex);
1363 if (sFontAlias.GetLength() > 0 && fFontSize > 0)
1364 sRet << "/" << sFontAlias << " " << fFontSize << " Tf\n";
1365 }
tsepez71a452f2016-05-13 17:51:27 -07001366 return sRet.MakeString();
dsinclair777b3332016-03-31 20:03:08 -07001367}