blob: 31d22422356697839f2132f77d2e7f1a1010e164 [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"
dsinclair488b7ad2016-10-04 11:55:50 -070014#include "core/fpdfapi/parser/cpdf_dictionary.h"
15#include "core/fpdfapi/parser/cpdf_document.h"
16#include "core/fpdfapi/parser/cpdf_simple_parser.h"
17#include "core/fpdfapi/parser/cpdf_stream.h"
18#include "core/fpdfapi/parser/fpdf_parser_decode.h"
dsinclair1727aee2016-09-29 13:12:56 -070019#include "core/fpdfdoc/cpdf_annot.h"
20#include "core/fpdfdoc/cpdf_formfield.h"
dsinclair777b3332016-03-31 20:03:08 -070021#include "core/fpdfdoc/cpvt_color.h"
22#include "core/fpdfdoc/cpvt_fontmap.h"
dsinclair1727aee2016-09-29 13:12:56 -070023#include "core/fpdfdoc/cpvt_word.h"
thestig69bbfa82016-11-10 10:39:01 -080024#include "third_party/base/ptr_util.h"
dsinclair777b3332016-03-31 20:03:08 -070025
26namespace {
27
jaepark9c987e92016-07-29 18:17:44 -070028bool GenerateWidgetAP(CPDF_Document* pDoc,
29 CPDF_Dictionary* pAnnotDict,
30 const int32_t& nWidgetType) {
dsinclair777b3332016-03-31 20:03:08 -070031 CPDF_Dictionary* pFormDict = nullptr;
32 if (CPDF_Dictionary* pRootDict = pDoc->GetRoot())
dsinclair38fd8442016-09-15 10:15:32 -070033 pFormDict = pRootDict->GetDictFor("AcroForm");
dsinclair777b3332016-03-31 20:03:08 -070034 if (!pFormDict)
jaepark9c987e92016-07-29 18:17:44 -070035 return false;
dsinclair777b3332016-03-31 20:03:08 -070036
37 CFX_ByteString DA;
38 if (CPDF_Object* pDAObj = FPDF_GetFieldAttr(pAnnotDict, "DA"))
39 DA = pDAObj->GetString();
40 if (DA.IsEmpty())
dsinclair38fd8442016-09-15 10:15:32 -070041 DA = pFormDict->GetStringFor("DA");
dsinclair777b3332016-03-31 20:03:08 -070042 if (DA.IsEmpty())
jaepark9c987e92016-07-29 18:17:44 -070043 return false;
dsinclair777b3332016-03-31 20:03:08 -070044
tsepez4c3debb2016-04-08 12:20:38 -070045 CPDF_SimpleParser syntax(DA.AsStringC());
dsinclair777b3332016-03-31 20:03:08 -070046 syntax.FindTagParamFromStart("Tf", 2);
tsepez71a452f2016-05-13 17:51:27 -070047 CFX_ByteString sFontName(syntax.GetWord());
dsinclair777b3332016-03-31 20:03:08 -070048 sFontName = PDF_NameDecode(sFontName);
49 if (sFontName.IsEmpty())
jaepark9c987e92016-07-29 18:17:44 -070050 return false;
dsinclair777b3332016-03-31 20:03:08 -070051
52 FX_FLOAT fFontSize = FX_atof(syntax.GetWord());
53 CPVT_Color crText = CPVT_Color::ParseColor(DA);
dsinclair38fd8442016-09-15 10:15:32 -070054 CPDF_Dictionary* pDRDict = pFormDict->GetDictFor("DR");
npm860a2d02016-09-12 15:02:28 -070055 if (!pDRDict)
56 return false;
57
dsinclair38fd8442016-09-15 10:15:32 -070058 CPDF_Dictionary* pDRFontDict = pDRDict->GetDictFor("Font");
dsinclair777b3332016-03-31 20:03:08 -070059 if (!pDRFontDict)
jaepark9c987e92016-07-29 18:17:44 -070060 return false;
dsinclair777b3332016-03-31 20:03:08 -070061
dsinclair38fd8442016-09-15 10:15:32 -070062 CPDF_Dictionary* pFontDict = pDRFontDict->GetDictFor(sFontName.Mid(1));
dsinclair777b3332016-03-31 20:03:08 -070063 if (!pFontDict) {
tsepez5913a6c2016-11-16 17:31:18 -080064 pFontDict = pDoc->NewIndirect<CPDF_Dictionary>();
tsepez70c4afd2016-11-15 11:33:44 -080065 pFontDict->SetNameFor("Type", "Font");
66 pFontDict->SetNameFor("Subtype", "Type1");
67 pFontDict->SetNameFor("BaseFont", "Helvetica");
68 pFontDict->SetNameFor("Encoding", "WinAnsiEncoding");
69 pDRFontDict->SetReferenceFor(sFontName.Mid(1), pDoc, pFontDict);
dsinclair777b3332016-03-31 20:03:08 -070070 }
71 CPDF_Font* pDefFont = pDoc->LoadFont(pFontDict);
72 if (!pDefFont)
jaepark9c987e92016-07-29 18:17:44 -070073 return false;
dsinclair777b3332016-03-31 20:03:08 -070074
dsinclair38fd8442016-09-15 10:15:32 -070075 CFX_FloatRect rcAnnot = pAnnotDict->GetRectFor("Rect");
dsinclair777b3332016-03-31 20:03:08 -070076 int32_t nRotate = 0;
dsinclair38fd8442016-09-15 10:15:32 -070077 if (CPDF_Dictionary* pMKDict = pAnnotDict->GetDictFor("MK"))
78 nRotate = pMKDict->GetIntegerFor("R");
dsinclair777b3332016-03-31 20:03:08 -070079
80 CFX_FloatRect rcBBox;
81 CFX_Matrix matrix;
82 switch (nRotate % 360) {
83 case 0:
84 rcBBox = CFX_FloatRect(0, 0, rcAnnot.right - rcAnnot.left,
85 rcAnnot.top - rcAnnot.bottom);
86 break;
87 case 90:
88 matrix = CFX_Matrix(0, 1, -1, 0, rcAnnot.right - rcAnnot.left, 0);
89 rcBBox = CFX_FloatRect(0, 0, rcAnnot.top - rcAnnot.bottom,
90 rcAnnot.right - rcAnnot.left);
91 break;
92 case 180:
93 matrix = CFX_Matrix(-1, 0, 0, -1, rcAnnot.right - rcAnnot.left,
94 rcAnnot.top - rcAnnot.bottom);
95 rcBBox = CFX_FloatRect(0, 0, rcAnnot.right - rcAnnot.left,
96 rcAnnot.top - rcAnnot.bottom);
97 break;
98 case 270:
99 matrix = CFX_Matrix(0, -1, 1, 0, 0, rcAnnot.top - rcAnnot.bottom);
100 rcBBox = CFX_FloatRect(0, 0, rcAnnot.top - rcAnnot.bottom,
101 rcAnnot.right - rcAnnot.left);
102 break;
103 }
dsinclair92cb5e52016-05-16 11:38:28 -0700104
105 BorderStyle nBorderStyle = BorderStyle::SOLID;
dsinclair777b3332016-03-31 20:03:08 -0700106 FX_FLOAT fBorderWidth = 1;
107 CPVT_Dash dsBorder(3, 0, 0);
108 CPVT_Color crLeftTop, crRightBottom;
dsinclair38fd8442016-09-15 10:15:32 -0700109 if (CPDF_Dictionary* pBSDict = pAnnotDict->GetDictFor("BS")) {
dsinclair777b3332016-03-31 20:03:08 -0700110 if (pBSDict->KeyExist("W"))
dsinclair38fd8442016-09-15 10:15:32 -0700111 fBorderWidth = pBSDict->GetNumberFor("W");
dsinclair777b3332016-03-31 20:03:08 -0700112
dsinclair38fd8442016-09-15 10:15:32 -0700113 if (CPDF_Array* pArray = pBSDict->GetArrayFor("D")) {
dsinclair777b3332016-03-31 20:03:08 -0700114 dsBorder = CPVT_Dash(pArray->GetIntegerAt(0), pArray->GetIntegerAt(1),
115 pArray->GetIntegerAt(2));
116 }
dsinclair38fd8442016-09-15 10:15:32 -0700117 switch (pBSDict->GetStringFor("S").GetAt(0)) {
dsinclair777b3332016-03-31 20:03:08 -0700118 case 'S':
dsinclair92cb5e52016-05-16 11:38:28 -0700119 nBorderStyle = BorderStyle::SOLID;
dsinclair777b3332016-03-31 20:03:08 -0700120 break;
121 case 'D':
dsinclair92cb5e52016-05-16 11:38:28 -0700122 nBorderStyle = BorderStyle::DASH;
dsinclair777b3332016-03-31 20:03:08 -0700123 break;
124 case 'B':
dsinclair92cb5e52016-05-16 11:38:28 -0700125 nBorderStyle = BorderStyle::BEVELED;
dsinclair777b3332016-03-31 20:03:08 -0700126 fBorderWidth *= 2;
127 crLeftTop = CPVT_Color(CPVT_Color::kGray, 1);
128 crRightBottom = CPVT_Color(CPVT_Color::kGray, 0.5);
129 break;
130 case 'I':
dsinclair92cb5e52016-05-16 11:38:28 -0700131 nBorderStyle = BorderStyle::INSET;
dsinclair777b3332016-03-31 20:03:08 -0700132 fBorderWidth *= 2;
133 crLeftTop = CPVT_Color(CPVT_Color::kGray, 0.5);
134 crRightBottom = CPVT_Color(CPVT_Color::kGray, 0.75);
135 break;
136 case 'U':
dsinclair92cb5e52016-05-16 11:38:28 -0700137 nBorderStyle = BorderStyle::UNDERLINE;
dsinclair777b3332016-03-31 20:03:08 -0700138 break;
139 }
140 }
141 CPVT_Color crBorder, crBG;
dsinclair38fd8442016-09-15 10:15:32 -0700142 if (CPDF_Dictionary* pMKDict = pAnnotDict->GetDictFor("MK")) {
143 if (CPDF_Array* pArray = pMKDict->GetArrayFor("BC"))
dsinclair777b3332016-03-31 20:03:08 -0700144 crBorder = CPVT_Color::ParseColor(*pArray);
dsinclair38fd8442016-09-15 10:15:32 -0700145 if (CPDF_Array* pArray = pMKDict->GetArrayFor("BG"))
dsinclair777b3332016-03-31 20:03:08 -0700146 crBG = CPVT_Color::ParseColor(*pArray);
147 }
148 CFX_ByteTextBuf sAppStream;
jaeparkb2e63372016-08-02 12:25:15 -0700149 CFX_ByteString sBG =
150 CPVT_GenerateAP::GenerateColorAP(crBG, PaintOperation::FILL);
dsinclair777b3332016-03-31 20:03:08 -0700151 if (sBG.GetLength() > 0) {
152 sAppStream << "q\n" << sBG << rcBBox.left << " " << rcBBox.bottom << " "
153 << rcBBox.Width() << " " << rcBBox.Height() << " re f\n"
154 << "Q\n";
155 }
156 CFX_ByteString sBorderStream = CPVT_GenerateAP::GenerateBorderAP(
157 rcBBox, fBorderWidth, crBorder, crLeftTop, crRightBottom, nBorderStyle,
158 dsBorder);
159 if (sBorderStream.GetLength() > 0)
160 sAppStream << "q\n" << sBorderStream << "Q\n";
161
162 CFX_FloatRect rcBody =
163 CFX_FloatRect(rcBBox.left + fBorderWidth, rcBBox.bottom + fBorderWidth,
164 rcBBox.right - fBorderWidth, rcBBox.top - fBorderWidth);
165 rcBody.Normalize();
dsinclair38fd8442016-09-15 10:15:32 -0700166 CPDF_Dictionary* pAPDict = pAnnotDict->GetDictFor("AP");
dsinclair777b3332016-03-31 20:03:08 -0700167 if (!pAPDict) {
thestig69bbfa82016-11-10 10:39:01 -0800168 auto pNewAPDict =
169 pdfium::MakeUnique<CPDF_Dictionary>(pDoc->GetByteStringPool());
170 // Ownership passes to |pAnnotDict|.
171 pAPDict = pNewAPDict.release();
dsinclair38fd8442016-09-15 10:15:32 -0700172 pAnnotDict->SetFor("AP", pAPDict);
dsinclair777b3332016-03-31 20:03:08 -0700173 }
dsinclair38fd8442016-09-15 10:15:32 -0700174 CPDF_Stream* pNormalStream = pAPDict->GetStreamFor("N");
dsinclair777b3332016-03-31 20:03:08 -0700175 if (!pNormalStream) {
tsepez70c4afd2016-11-15 11:33:44 -0800176 pNormalStream = pDoc->NewIndirect<CPDF_Stream>();
177 pAPDict->SetReferenceFor("N", pDoc, pNormalStream);
dsinclair777b3332016-03-31 20:03:08 -0700178 }
179 CPDF_Dictionary* pStreamDict = pNormalStream->GetDict();
180 if (pStreamDict) {
dsinclair38fd8442016-09-15 10:15:32 -0700181 pStreamDict->SetMatrixFor("Matrix", matrix);
182 pStreamDict->SetRectFor("BBox", rcBBox);
183 CPDF_Dictionary* pStreamResList = pStreamDict->GetDictFor("Resources");
dsinclair777b3332016-03-31 20:03:08 -0700184 if (pStreamResList) {
dsinclair38fd8442016-09-15 10:15:32 -0700185 CPDF_Dictionary* pStreamResFontList = pStreamResList->GetDictFor("Font");
dsinclair777b3332016-03-31 20:03:08 -0700186 if (!pStreamResFontList) {
thestig69bbfa82016-11-10 10:39:01 -0800187 auto pNewStreamResFontList =
188 pdfium::MakeUnique<CPDF_Dictionary>(pDoc->GetByteStringPool());
189 // Ownership passes to |pStreamResList|.
190 pStreamResFontList = pNewStreamResFontList.release();
dsinclair38fd8442016-09-15 10:15:32 -0700191 pStreamResList->SetFor("Font", pStreamResFontList);
dsinclair777b3332016-03-31 20:03:08 -0700192 }
tsepez7b1ccf92016-04-14 11:04:57 -0700193 if (!pStreamResFontList->KeyExist(sFontName))
tsepez70c4afd2016-11-15 11:33:44 -0800194 pStreamResFontList->SetReferenceFor(sFontName, pDoc, pFontDict);
dsinclair777b3332016-03-31 20:03:08 -0700195 } else {
tsepez335cf092016-11-09 13:28:26 -0800196 pStreamDict->SetFor("Resources",
197 pFormDict->GetDictFor("DR")->Clone().release());
dsinclair38fd8442016-09-15 10:15:32 -0700198 pStreamResList = pStreamDict->GetDictFor("Resources");
dsinclair777b3332016-03-31 20:03:08 -0700199 }
200 }
201 switch (nWidgetType) {
202 case 0: {
203 CFX_WideString swValue =
204 FPDF_GetFieldAttr(pAnnotDict, "V")
205 ? FPDF_GetFieldAttr(pAnnotDict, "V")->GetUnicodeText()
206 : CFX_WideString();
207 int32_t nAlign = FPDF_GetFieldAttr(pAnnotDict, "Q")
208 ? FPDF_GetFieldAttr(pAnnotDict, "Q")->GetInteger()
209 : 0;
210 uint32_t dwFlags = FPDF_GetFieldAttr(pAnnotDict, "Ff")
211 ? FPDF_GetFieldAttr(pAnnotDict, "Ff")->GetInteger()
212 : 0;
213 uint32_t dwMaxLen =
214 FPDF_GetFieldAttr(pAnnotDict, "MaxLen")
215 ? FPDF_GetFieldAttr(pAnnotDict, "MaxLen")->GetInteger()
216 : 0;
217 CPVT_FontMap map(
dsinclair38fd8442016-09-15 10:15:32 -0700218 pDoc, pStreamDict ? pStreamDict->GetDictFor("Resources") : nullptr,
dsinclair777b3332016-03-31 20:03:08 -0700219 pDefFont, sFontName.Right(sFontName.GetLength() - 1));
dsinclairc7a73492016-04-05 12:01:42 -0700220 CPDF_VariableText::Provider prd(&map);
dsinclair777b3332016-03-31 20:03:08 -0700221 CPDF_VariableText vt;
222 vt.SetProvider(&prd);
223 vt.SetPlateRect(rcBody);
224 vt.SetAlignment(nAlign);
225 if (IsFloatZero(fFontSize))
tsepez12f3e4a2016-11-02 15:17:29 -0700226 vt.SetAutoFontSize(true);
dsinclair777b3332016-03-31 20:03:08 -0700227 else
228 vt.SetFontSize(fFontSize);
229
tsepez12f3e4a2016-11-02 15:17:29 -0700230 bool bMultiLine = (dwFlags >> 12) & 1;
dsinclair777b3332016-03-31 20:03:08 -0700231 if (bMultiLine) {
tsepez12f3e4a2016-11-02 15:17:29 -0700232 vt.SetMultiLine(true);
233 vt.SetAutoReturn(true);
dsinclair777b3332016-03-31 20:03:08 -0700234 }
235 uint16_t subWord = 0;
236 if ((dwFlags >> 13) & 1) {
237 subWord = '*';
238 vt.SetPasswordChar(subWord);
239 }
tsepez12f3e4a2016-11-02 15:17:29 -0700240 bool bCharArray = (dwFlags >> 24) & 1;
dsinclair777b3332016-03-31 20:03:08 -0700241 if (bCharArray)
242 vt.SetCharArray(dwMaxLen);
243 else
244 vt.SetLimitChar(dwMaxLen);
245
246 vt.Initialize();
tsepez067990c2016-09-13 06:46:40 -0700247 vt.SetText(swValue);
dsinclair777b3332016-03-31 20:03:08 -0700248 vt.RearrangeAll();
249 CFX_FloatRect rcContent = vt.GetContentRect();
tsepez63f545c2016-09-13 16:08:49 -0700250 CFX_FloatPoint ptOffset;
dsinclair777b3332016-03-31 20:03:08 -0700251 if (!bMultiLine) {
252 ptOffset =
253 CFX_FloatPoint(0.0f, (rcContent.Height() - rcBody.Height()) / 2.0f);
254 }
255 CFX_ByteString sBody = CPVT_GenerateAP::GenerateEditAP(
256 &map, vt.GetIterator(), ptOffset, !bCharArray, subWord);
257 if (sBody.GetLength() > 0) {
258 sAppStream << "/Tx BMC\n"
259 << "q\n";
260 if (rcContent.Width() > rcBody.Width() ||
261 rcContent.Height() > rcBody.Height()) {
262 sAppStream << rcBody.left << " " << rcBody.bottom << " "
263 << rcBody.Width() << " " << rcBody.Height()
264 << " re\nW\nn\n";
265 }
jaeparkb2e63372016-08-02 12:25:15 -0700266 sAppStream << "BT\n"
267 << CPVT_GenerateAP::GenerateColorAP(crText,
268 PaintOperation::FILL)
dsinclair777b3332016-03-31 20:03:08 -0700269 << sBody << "ET\n"
270 << "Q\nEMC\n";
271 }
272 } break;
273 case 1: {
274 CFX_WideString swValue =
275 FPDF_GetFieldAttr(pAnnotDict, "V")
276 ? FPDF_GetFieldAttr(pAnnotDict, "V")->GetUnicodeText()
277 : CFX_WideString();
278 CPVT_FontMap map(
dsinclair38fd8442016-09-15 10:15:32 -0700279 pDoc, pStreamDict ? pStreamDict->GetDictFor("Resources") : nullptr,
dsinclair777b3332016-03-31 20:03:08 -0700280 pDefFont, sFontName.Right(sFontName.GetLength() - 1));
dsinclairc7a73492016-04-05 12:01:42 -0700281 CPDF_VariableText::Provider prd(&map);
dsinclair777b3332016-03-31 20:03:08 -0700282 CPDF_VariableText vt;
283 vt.SetProvider(&prd);
284 CFX_FloatRect rcButton = rcBody;
285 rcButton.left = rcButton.right - 13;
286 rcButton.Normalize();
287 CFX_FloatRect rcEdit = rcBody;
288 rcEdit.right = rcButton.left;
289 rcEdit.Normalize();
290 vt.SetPlateRect(rcEdit);
291 if (IsFloatZero(fFontSize))
tsepez12f3e4a2016-11-02 15:17:29 -0700292 vt.SetAutoFontSize(true);
dsinclair777b3332016-03-31 20:03:08 -0700293 else
294 vt.SetFontSize(fFontSize);
295
296 vt.Initialize();
tsepez067990c2016-09-13 06:46:40 -0700297 vt.SetText(swValue);
dsinclair777b3332016-03-31 20:03:08 -0700298 vt.RearrangeAll();
299 CFX_FloatRect rcContent = vt.GetContentRect();
300 CFX_FloatPoint ptOffset =
301 CFX_FloatPoint(0.0f, (rcContent.Height() - rcEdit.Height()) / 2.0f);
302 CFX_ByteString sEdit = CPVT_GenerateAP::GenerateEditAP(
tsepez12f3e4a2016-11-02 15:17:29 -0700303 &map, vt.GetIterator(), ptOffset, true, 0);
dsinclair777b3332016-03-31 20:03:08 -0700304 if (sEdit.GetLength() > 0) {
305 sAppStream << "/Tx BMC\n"
306 << "q\n";
307 sAppStream << rcEdit.left << " " << rcEdit.bottom << " "
308 << rcEdit.Width() << " " << rcEdit.Height() << " re\nW\nn\n";
jaeparkb2e63372016-08-02 12:25:15 -0700309 sAppStream << "BT\n"
310 << CPVT_GenerateAP::GenerateColorAP(crText,
311 PaintOperation::FILL)
dsinclair777b3332016-03-31 20:03:08 -0700312 << sEdit << "ET\n"
313 << "Q\nEMC\n";
314 }
315 CFX_ByteString sButton = CPVT_GenerateAP::GenerateColorAP(
316 CPVT_Color(CPVT_Color::kRGB, 220.0f / 255.0f, 220.0f / 255.0f,
317 220.0f / 255.0f),
jaeparkb2e63372016-08-02 12:25:15 -0700318 PaintOperation::FILL);
dsinclair777b3332016-03-31 20:03:08 -0700319 if (sButton.GetLength() > 0 && !rcButton.IsEmpty()) {
320 sAppStream << "q\n" << sButton;
321 sAppStream << rcButton.left << " " << rcButton.bottom << " "
322 << rcButton.Width() << " " << rcButton.Height() << " re f\n";
323 sAppStream << "Q\n";
324 CFX_ByteString sButtonBorder = CPVT_GenerateAP::GenerateBorderAP(
325 rcButton, 2, CPVT_Color(CPVT_Color::kGray, 0),
326 CPVT_Color(CPVT_Color::kGray, 1),
dsinclair92cb5e52016-05-16 11:38:28 -0700327 CPVT_Color(CPVT_Color::kGray, 0.5), BorderStyle::BEVELED,
dsinclair777b3332016-03-31 20:03:08 -0700328 CPVT_Dash(3, 0, 0));
329 if (sButtonBorder.GetLength() > 0)
330 sAppStream << "q\n" << sButtonBorder << "Q\n";
331
332 CFX_FloatPoint ptCenter =
333 CFX_FloatPoint((rcButton.left + rcButton.right) / 2,
334 (rcButton.top + rcButton.bottom) / 2);
335 if (IsFloatBigger(rcButton.Width(), 6) &&
336 IsFloatBigger(rcButton.Height(), 6)) {
337 sAppStream << "q\n"
338 << " 0 g\n";
339 sAppStream << ptCenter.x - 3 << " " << ptCenter.y + 1.5f << " m\n";
340 sAppStream << ptCenter.x + 3 << " " << ptCenter.y + 1.5f << " l\n";
341 sAppStream << ptCenter.x << " " << ptCenter.y - 1.5f << " l\n";
342 sAppStream << ptCenter.x - 3 << " " << ptCenter.y + 1.5f << " l f\n";
343 sAppStream << sButton << "Q\n";
344 }
345 }
346 } break;
347 case 2: {
348 CPVT_FontMap map(
dsinclair38fd8442016-09-15 10:15:32 -0700349 pDoc, pStreamDict ? pStreamDict->GetDictFor("Resources") : nullptr,
dsinclair777b3332016-03-31 20:03:08 -0700350 pDefFont, sFontName.Right(sFontName.GetLength() - 1));
dsinclairc7a73492016-04-05 12:01:42 -0700351 CPDF_VariableText::Provider prd(&map);
thestigb8bf55f2016-05-21 21:08:05 -0700352 CPDF_Array* pOpts = ToArray(FPDF_GetFieldAttr(pAnnotDict, "Opt"));
353 CPDF_Array* pSels = ToArray(FPDF_GetFieldAttr(pAnnotDict, "I"));
354 CPDF_Object* pTi = FPDF_GetFieldAttr(pAnnotDict, "TI");
355 int32_t nTop = pTi ? pTi->GetInteger() : 0;
dsinclair777b3332016-03-31 20:03:08 -0700356 CFX_ByteTextBuf sBody;
357 if (pOpts) {
358 FX_FLOAT fy = rcBody.top;
Wei Lie1aebd42016-04-11 10:02:09 -0700359 for (size_t i = nTop, sz = pOpts->GetCount(); i < sz; i++) {
dsinclair777b3332016-03-31 20:03:08 -0700360 if (IsFloatSmaller(fy, rcBody.bottom))
361 break;
362
363 if (CPDF_Object* pOpt = pOpts->GetDirectObjectAt(i)) {
364 CFX_WideString swItem;
365 if (pOpt->IsString())
366 swItem = pOpt->GetUnicodeText();
367 else if (CPDF_Array* pArray = pOpt->AsArray())
368 swItem = pArray->GetDirectObjectAt(1)->GetUnicodeText();
369
tsepez12f3e4a2016-11-02 15:17:29 -0700370 bool bSelected = false;
dsinclair777b3332016-03-31 20:03:08 -0700371 if (pSels) {
Wei Lie1aebd42016-04-11 10:02:09 -0700372 for (size_t s = 0, ssz = pSels->GetCount(); s < ssz; s++) {
ochang6b19ec62016-04-12 11:53:23 -0700373 int value = pSels->GetIntegerAt(s);
374 if (value >= 0 && i == static_cast<size_t>(value)) {
tsepez12f3e4a2016-11-02 15:17:29 -0700375 bSelected = true;
dsinclair777b3332016-03-31 20:03:08 -0700376 break;
377 }
378 }
379 }
380 CPDF_VariableText vt;
381 vt.SetProvider(&prd);
382 vt.SetPlateRect(
383 CFX_FloatRect(rcBody.left, 0.0f, rcBody.right, 0.0f));
384 vt.SetFontSize(IsFloatZero(fFontSize) ? 12.0f : fFontSize);
385
386 vt.Initialize();
tsepez067990c2016-09-13 06:46:40 -0700387 vt.SetText(swItem);
dsinclair777b3332016-03-31 20:03:08 -0700388 vt.RearrangeAll();
389 FX_FLOAT fItemHeight = vt.GetContentRect().Height();
390 if (bSelected) {
391 CFX_FloatRect rcItem = CFX_FloatRect(
392 rcBody.left, fy - fItemHeight, rcBody.right, fy);
jaeparkb2e63372016-08-02 12:25:15 -0700393 sBody << "q\n"
394 << CPVT_GenerateAP::GenerateColorAP(
395 CPVT_Color(CPVT_Color::kRGB, 0, 51.0f / 255.0f,
396 113.0f / 255.0f),
397 PaintOperation::FILL)
dsinclair777b3332016-03-31 20:03:08 -0700398 << rcItem.left << " " << rcItem.bottom << " "
399 << rcItem.Width() << " " << rcItem.Height() << " re f\n"
400 << "Q\n";
jaeparkb2e63372016-08-02 12:25:15 -0700401 sBody << "BT\n"
402 << CPVT_GenerateAP::GenerateColorAP(
403 CPVT_Color(CPVT_Color::kGray, 1),
404 PaintOperation::FILL)
dsinclair777b3332016-03-31 20:03:08 -0700405 << CPVT_GenerateAP::GenerateEditAP(&map, vt.GetIterator(),
406 CFX_FloatPoint(0.0f, fy),
tsepez12f3e4a2016-11-02 15:17:29 -0700407 true, 0)
dsinclair777b3332016-03-31 20:03:08 -0700408 << "ET\n";
409 } else {
jaeparkb2e63372016-08-02 12:25:15 -0700410 sBody << "BT\n"
411 << CPVT_GenerateAP::GenerateColorAP(crText,
412 PaintOperation::FILL)
dsinclair777b3332016-03-31 20:03:08 -0700413 << CPVT_GenerateAP::GenerateEditAP(&map, vt.GetIterator(),
414 CFX_FloatPoint(0.0f, fy),
tsepez12f3e4a2016-11-02 15:17:29 -0700415 true, 0)
dsinclair777b3332016-03-31 20:03:08 -0700416 << "ET\n";
417 }
418 fy -= fItemHeight;
419 }
420 }
421 }
422 if (sBody.GetSize() > 0) {
thestigb8bf55f2016-05-21 21:08:05 -0700423 sAppStream << "/Tx BMC\nq\n"
424 << rcBody.left << " " << rcBody.bottom << " "
425 << rcBody.Width() << " " << rcBody.Height() << " re\nW\nn\n"
426 << sBody.AsStringC() << "Q\nEMC\n";
dsinclair777b3332016-03-31 20:03:08 -0700427 }
428 } break;
429 }
430 if (pNormalStream) {
tsepeze6db16e2016-09-19 10:45:09 -0700431 pNormalStream->SetData(sAppStream.GetBuffer(), sAppStream.GetSize());
dsinclair777b3332016-03-31 20:03:08 -0700432 pStreamDict = pNormalStream->GetDict();
433 if (pStreamDict) {
dsinclair38fd8442016-09-15 10:15:32 -0700434 pStreamDict->SetMatrixFor("Matrix", matrix);
435 pStreamDict->SetRectFor("BBox", rcBBox);
436 CPDF_Dictionary* pStreamResList = pStreamDict->GetDictFor("Resources");
dsinclair777b3332016-03-31 20:03:08 -0700437 if (pStreamResList) {
dsinclair38fd8442016-09-15 10:15:32 -0700438 CPDF_Dictionary* pStreamResFontList =
439 pStreamResList->GetDictFor("Font");
dsinclair777b3332016-03-31 20:03:08 -0700440 if (!pStreamResFontList) {
thestig69bbfa82016-11-10 10:39:01 -0800441 auto pNewStreamResFontList =
442 pdfium::MakeUnique<CPDF_Dictionary>(pDoc->GetByteStringPool());
443 // Ownership passes to |pStreamResList|.
444 pStreamResFontList = pNewStreamResFontList.release();
dsinclair38fd8442016-09-15 10:15:32 -0700445 pStreamResList->SetFor("Font", pStreamResFontList);
dsinclair777b3332016-03-31 20:03:08 -0700446 }
tsepez7b1ccf92016-04-14 11:04:57 -0700447 if (!pStreamResFontList->KeyExist(sFontName))
tsepez70c4afd2016-11-15 11:33:44 -0800448 pStreamResFontList->SetReferenceFor(sFontName, pDoc, pFontDict);
dsinclair777b3332016-03-31 20:03:08 -0700449 } else {
tsepez335cf092016-11-09 13:28:26 -0800450 pStreamDict->SetFor("Resources",
451 pFormDict->GetDictFor("DR")->Clone().release());
dsinclair38fd8442016-09-15 10:15:32 -0700452 pStreamResList = pStreamDict->GetDictFor("Resources");
dsinclair777b3332016-03-31 20:03:08 -0700453 }
454 }
455 }
jaepark9c987e92016-07-29 18:17:44 -0700456 return true;
dsinclair777b3332016-03-31 20:03:08 -0700457}
458
jaeparkaf7ab332016-08-09 10:23:14 -0700459CFX_ByteString GetColorStringWithDefault(CPDF_Array* pColor,
jaepark33e9b262016-08-02 16:22:52 -0700460 const CPVT_Color& crDefaultColor,
461 PaintOperation nOperation) {
jaeparkaf7ab332016-08-09 10:23:14 -0700462 if (pColor) {
jaepark33e9b262016-08-02 16:22:52 -0700463 CPVT_Color color = CPVT_Color::ParseColor(*pColor);
464 return CPVT_GenerateAP::GenerateColorAP(color, nOperation);
465 }
466
467 return CPVT_GenerateAP::GenerateColorAP(crDefaultColor, nOperation);
468}
469
jaeparkaf7ab332016-08-09 10:23:14 -0700470FX_FLOAT GetBorderWidth(const CPDF_Dictionary& pAnnotDict) {
dsinclair38fd8442016-09-15 10:15:32 -0700471 if (CPDF_Dictionary* pBorderStyleDict = pAnnotDict.GetDictFor("BS")) {
jaeparkaf7ab332016-08-09 10:23:14 -0700472 if (pBorderStyleDict->KeyExist("W"))
dsinclair38fd8442016-09-15 10:15:32 -0700473 return pBorderStyleDict->GetNumberFor("W");
jaeparkaf7ab332016-08-09 10:23:14 -0700474 }
475
dsinclair38fd8442016-09-15 10:15:32 -0700476 if (CPDF_Array* pBorderArray = pAnnotDict.GetArrayFor("Border")) {
jaeparkaf7ab332016-08-09 10:23:14 -0700477 if (pBorderArray->GetCount() > 2)
478 return pBorderArray->GetNumberAt(2);
479 }
480
481 return 1;
482}
483
484CPDF_Array* GetDashArray(const CPDF_Dictionary& pAnnotDict) {
dsinclair38fd8442016-09-15 10:15:32 -0700485 if (CPDF_Dictionary* pBorderStyleDict = pAnnotDict.GetDictFor("BS")) {
486 if (pBorderStyleDict->GetStringFor("S") == "D")
487 return pBorderStyleDict->GetArrayFor("D");
jaeparkaf7ab332016-08-09 10:23:14 -0700488 }
489
dsinclair38fd8442016-09-15 10:15:32 -0700490 if (CPDF_Array* pBorderArray = pAnnotDict.GetArrayFor("Border")) {
jaeparkaf7ab332016-08-09 10:23:14 -0700491 if (pBorderArray->GetCount() == 4)
492 return pBorderArray->GetArrayAt(3);
493 }
494
495 return nullptr;
496}
497
498CFX_ByteString GetDashPatternString(const CPDF_Dictionary& pAnnotDict) {
499 CPDF_Array* pDashArray = GetDashArray(pAnnotDict);
500 if (!pDashArray || pDashArray->IsEmpty())
501 return CFX_ByteString();
502
503 // Support maximum of ten elements in the dash array.
504 size_t pDashArrayCount = std::min<size_t>(pDashArray->GetCount(), 10);
505 CFX_ByteTextBuf sDashStream;
506
507 sDashStream << "[";
508 for (size_t i = 0; i < pDashArrayCount; ++i)
509 sDashStream << pDashArray->GetNumberAt(i) << " ";
510 sDashStream << "] 0 d\n";
511
512 return sDashStream.MakeString();
513}
514
jaepark35512aa2016-08-29 17:15:08 -0700515CFX_ByteString GetPopupContentsString(CPDF_Document* pDoc,
516 const CPDF_Dictionary& pAnnotDict,
517 CPDF_Font* pDefFont,
518 const CFX_ByteString& sFontName) {
dsinclair38fd8442016-09-15 10:15:32 -0700519 CFX_WideString swValue(pAnnotDict.GetUnicodeTextFor("T"));
jaepark35512aa2016-08-29 17:15:08 -0700520 swValue += L'\n';
dsinclair38fd8442016-09-15 10:15:32 -0700521 swValue += pAnnotDict.GetUnicodeTextFor("Contents");
jaepark35512aa2016-08-29 17:15:08 -0700522 CPVT_FontMap map(pDoc, nullptr, pDefFont, sFontName);
523
524 CPDF_VariableText::Provider prd(&map);
525 CPDF_VariableText vt;
526 vt.SetProvider(&prd);
dsinclair38fd8442016-09-15 10:15:32 -0700527 vt.SetPlateRect(pAnnotDict.GetRectFor("Rect"));
jaepark35512aa2016-08-29 17:15:08 -0700528 vt.SetFontSize(12);
tsepez12f3e4a2016-11-02 15:17:29 -0700529 vt.SetAutoReturn(true);
530 vt.SetMultiLine(true);
jaepark35512aa2016-08-29 17:15:08 -0700531
532 vt.Initialize();
tsepez067990c2016-09-13 06:46:40 -0700533 vt.SetText(swValue);
jaepark35512aa2016-08-29 17:15:08 -0700534 vt.RearrangeAll();
535 CFX_FloatPoint ptOffset(3.0f, -3.0f);
536 CFX_ByteString sContent = CPVT_GenerateAP::GenerateEditAP(
tsepez12f3e4a2016-11-02 15:17:29 -0700537 &map, vt.GetIterator(), ptOffset, false, 0);
jaepark35512aa2016-08-29 17:15:08 -0700538
539 if (sContent.IsEmpty())
540 return CFX_ByteString();
541
542 CFX_ByteTextBuf sAppStream;
543 sAppStream << "BT\n"
544 << CPVT_GenerateAP::GenerateColorAP(
545 CPVT_Color(CPVT_Color::kRGB, 0, 0, 0), PaintOperation::FILL)
546 << sContent << "ET\n"
547 << "Q\n";
548 return sAppStream.MakeString();
549}
550
thestig69bbfa82016-11-10 10:39:01 -0800551std::unique_ptr<CPDF_Dictionary> GenerateExtGStateDict(
552 const CPDF_Dictionary& pAnnotDict,
553 const CFX_ByteString& sExtGSDictName,
554 const CFX_ByteString& sBlendMode) {
555 auto pGSDict =
556 pdfium::MakeUnique<CPDF_Dictionary>(pAnnotDict.GetByteStringPool());
dsinclair38fd8442016-09-15 10:15:32 -0700557 pGSDict->SetStringFor("Type", "ExtGState");
jaepark33e9b262016-08-02 16:22:52 -0700558
559 FX_FLOAT fOpacity =
dsinclair38fd8442016-09-15 10:15:32 -0700560 pAnnotDict.KeyExist("CA") ? pAnnotDict.GetNumberFor("CA") : 1;
561 pGSDict->SetNumberFor("CA", fOpacity);
562 pGSDict->SetNumberFor("ca", fOpacity);
563 pGSDict->SetBooleanFor("AIS", false);
564 pGSDict->SetStringFor("BM", sBlendMode);
jaepark33e9b262016-08-02 16:22:52 -0700565
thestig69bbfa82016-11-10 10:39:01 -0800566 auto pExtGStateDict =
567 pdfium::MakeUnique<CPDF_Dictionary>(pAnnotDict.GetByteStringPool());
568 pExtGStateDict->SetFor(sExtGSDictName, pGSDict.release());
jaepark33e9b262016-08-02 16:22:52 -0700569 return pExtGStateDict;
570}
571
thestig69bbfa82016-11-10 10:39:01 -0800572std::unique_ptr<CPDF_Dictionary> GenerateResourceFontDict(
573 CPDF_Document* pDoc,
574 const CFX_ByteString& sFontDictName) {
tsepez5913a6c2016-11-16 17:31:18 -0800575 CPDF_Dictionary* pFontDict = pDoc->NewIndirect<CPDF_Dictionary>();
dsinclair38fd8442016-09-15 10:15:32 -0700576 pFontDict->SetNameFor("Type", "Font");
577 pFontDict->SetNameFor("Subtype", "Type1");
578 pFontDict->SetNameFor("BaseFont", "Helvetica");
579 pFontDict->SetNameFor("Encoding", "WinAnsiEncoding");
jaepark35512aa2016-08-29 17:15:08 -0700580
thestig69bbfa82016-11-10 10:39:01 -0800581 auto pResourceFontDict =
582 pdfium::MakeUnique<CPDF_Dictionary>(pDoc->GetByteStringPool());
tsepez70c4afd2016-11-15 11:33:44 -0800583 pResourceFontDict->SetReferenceFor(sFontDictName, pDoc, pFontDict);
jaepark35512aa2016-08-29 17:15:08 -0700584 return pResourceFontDict;
585}
586
thestig69bbfa82016-11-10 10:39:01 -0800587std::unique_ptr<CPDF_Dictionary> GenerateResourceDict(
588 CPDF_Document* pDoc,
589 std::unique_ptr<CPDF_Dictionary> pExtGStateDict,
590 std::unique_ptr<CPDF_Dictionary> pResourceFontDict) {
591 auto pResourceDict =
592 pdfium::MakeUnique<CPDF_Dictionary>(pDoc->GetByteStringPool());
jaepark35512aa2016-08-29 17:15:08 -0700593 if (pExtGStateDict)
thestig69bbfa82016-11-10 10:39:01 -0800594 pResourceDict->SetFor("ExtGState", pExtGStateDict.release());
jaepark35512aa2016-08-29 17:15:08 -0700595 if (pResourceFontDict)
thestig69bbfa82016-11-10 10:39:01 -0800596 pResourceDict->SetFor("Font", pResourceFontDict.release());
jaepark35512aa2016-08-29 17:15:08 -0700597 return pResourceDict;
598}
599
jaepark33e9b262016-08-02 16:22:52 -0700600void GenerateAndSetAPDict(CPDF_Document* pDoc,
601 CPDF_Dictionary* pAnnotDict,
602 const CFX_ByteTextBuf& sAppStream,
thestig69bbfa82016-11-10 10:39:01 -0800603 std::unique_ptr<CPDF_Dictionary> pResourceDict,
tonikitoo0a17faf2016-09-15 13:50:50 -0700604 bool bIsTextMarkupAnnotation) {
tsepez70c4afd2016-11-15 11:33:44 -0800605 CPDF_Stream* pNormalStream = pDoc->NewIndirect<CPDF_Stream>();
tsepeze6db16e2016-09-19 10:45:09 -0700606 pNormalStream->SetData(sAppStream.GetBuffer(), sAppStream.GetSize());
thestig69bbfa82016-11-10 10:39:01 -0800607
608 auto pAPDict = pdfium::MakeUnique<CPDF_Dictionary>(pDoc->GetByteStringPool());
tsepez70c4afd2016-11-15 11:33:44 -0800609 pAPDict->SetReferenceFor("N", pDoc, pNormalStream);
thestig69bbfa82016-11-10 10:39:01 -0800610 pAnnotDict->SetFor("AP", pAPDict.release());
611
tsepez70c4afd2016-11-15 11:33:44 -0800612 CPDF_Dictionary* pStreamDict = pNormalStream->GetDict();
dsinclair38fd8442016-09-15 10:15:32 -0700613 pStreamDict->SetIntegerFor("FormType", 1);
614 pStreamDict->SetStringFor("Subtype", "Form");
615 pStreamDict->SetMatrixFor("Matrix", CFX_Matrix());
jaepark33e9b262016-08-02 16:22:52 -0700616
tonikitoo0a17faf2016-09-15 13:50:50 -0700617 CFX_FloatRect rect = bIsTextMarkupAnnotation
618 ? CPDF_Annot::RectFromQuadPoints(pAnnotDict)
619 : pAnnotDict->GetRectFor("Rect");
dsinclair38fd8442016-09-15 10:15:32 -0700620 pStreamDict->SetRectFor("BBox", rect);
thestig69bbfa82016-11-10 10:39:01 -0800621 pStreamDict->SetFor("Resources", pResourceDict.release());
jaepark33e9b262016-08-02 16:22:52 -0700622}
623
jaeparkaf7ab332016-08-09 10:23:14 -0700624CFX_ByteString GetPaintOperatorString(bool bIsStrokeRect, bool bIsFillRect) {
625 if (bIsStrokeRect)
626 return bIsFillRect ? "b" : "s";
627 return bIsFillRect ? "f" : "n";
628}
629
jaeparkc38de112016-08-22 17:54:56 -0700630CFX_ByteString GenerateTextSymbolAP(const CFX_FloatRect& rect) {
631 CFX_ByteTextBuf sAppStream;
632 sAppStream << CPVT_GenerateAP::GenerateColorAP(
633 CPVT_Color(CPVT_Color::kRGB, 1, 1, 0), PaintOperation::FILL);
634 sAppStream << CPVT_GenerateAP::GenerateColorAP(
635 CPVT_Color(CPVT_Color::kRGB, 0, 0, 0), PaintOperation::STROKE);
636
637 const FX_FLOAT fBorderWidth = 1;
638 sAppStream << fBorderWidth << " w\n";
639
640 const FX_FLOAT fHalfWidth = fBorderWidth / 2;
641 const FX_FLOAT fTipDelta = 4;
642
643 CFX_FloatRect outerRect1 = rect;
644 outerRect1.Deflate(fHalfWidth, fHalfWidth);
645 outerRect1.bottom += fTipDelta;
646
647 CFX_FloatRect outerRect2 = outerRect1;
648 outerRect2.left += fTipDelta;
649 outerRect2.right = outerRect2.left + fTipDelta;
650 outerRect2.top = outerRect2.bottom - fTipDelta;
651 FX_FLOAT outerRect2Middle = (outerRect2.left + outerRect2.right) / 2;
652
653 // Draw outer boxes.
654 sAppStream << outerRect1.left << " " << outerRect1.bottom << " m\n"
655 << outerRect1.left << " " << outerRect1.top << " l\n"
656 << outerRect1.right << " " << outerRect1.top << " l\n"
657 << outerRect1.right << " " << outerRect1.bottom << " l\n"
658 << outerRect2.right << " " << outerRect2.bottom << " l\n"
659 << outerRect2Middle << " " << outerRect2.top << " l\n"
660 << outerRect2.left << " " << outerRect2.bottom << " l\n"
661 << outerRect1.left << " " << outerRect1.bottom << " l\n";
662
663 // Draw inner lines.
664 CFX_FloatRect lineRect = outerRect1;
665 const FX_FLOAT fXDelta = 2;
666 const FX_FLOAT fYDelta = (lineRect.top - lineRect.bottom) / 4;
667
668 lineRect.left += fXDelta;
669 lineRect.right -= fXDelta;
670 for (int i = 0; i < 3; ++i) {
671 lineRect.top -= fYDelta;
672 sAppStream << lineRect.left << " " << lineRect.top << " m\n"
673 << lineRect.right << " " << lineRect.top << " l\n";
674 }
675 sAppStream << "B*\n";
676
677 return sAppStream.MakeString();
678}
679
dsinclair777b3332016-03-31 20:03:08 -0700680} // namespace
681
jaepark9c987e92016-07-29 18:17:44 -0700682bool FPDF_GenerateAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict) {
dsinclair38fd8442016-09-15 10:15:32 -0700683 if (!pAnnotDict || pAnnotDict->GetStringFor("Subtype") != "Widget")
jaepark9c987e92016-07-29 18:17:44 -0700684 return false;
685
thestig717d1332016-09-20 05:58:19 -0700686 CPDF_Object* pFieldTypeObj = FPDF_GetFieldAttr(pAnnotDict, "FT");
687 if (!pFieldTypeObj)
688 return false;
689
690 CFX_ByteString field_type = pFieldTypeObj->GetString();
691 if (field_type == "Tx")
dsinclair777b3332016-03-31 20:03:08 -0700692 return CPVT_GenerateAP::GenerateTextFieldAP(pDoc, pAnnotDict);
thestig717d1332016-09-20 05:58:19 -0700693
694 CPDF_Object* pFieldFlagsObj = FPDF_GetFieldAttr(pAnnotDict, "Ff");
695 uint32_t flags = pFieldFlagsObj ? pFieldFlagsObj->GetInteger() : 0;
696
dsinclair777b3332016-03-31 20:03:08 -0700697 if (field_type == "Ch") {
698 return (flags & (1 << 17))
699 ? CPVT_GenerateAP::GenerateComboBoxAP(pDoc, pAnnotDict)
700 : CPVT_GenerateAP::GenerateListBoxAP(pDoc, pAnnotDict);
701 }
thestig717d1332016-09-20 05:58:19 -0700702
dsinclair777b3332016-03-31 20:03:08 -0700703 if (field_type == "Btn") {
704 if (!(flags & (1 << 16))) {
705 if (!pAnnotDict->KeyExist("AS")) {
dsinclair38fd8442016-09-15 10:15:32 -0700706 if (CPDF_Dictionary* pParentDict = pAnnotDict->GetDictFor("Parent")) {
dsinclair777b3332016-03-31 20:03:08 -0700707 if (pParentDict->KeyExist("AS")) {
dsinclair38fd8442016-09-15 10:15:32 -0700708 pAnnotDict->SetStringFor("AS", pParentDict->GetStringFor("AS"));
dsinclair777b3332016-03-31 20:03:08 -0700709 }
710 }
711 }
712 }
713 }
thestig717d1332016-09-20 05:58:19 -0700714
jaepark9c987e92016-07-29 18:17:44 -0700715 return false;
dsinclair777b3332016-03-31 20:03:08 -0700716}
717
718// Static.
jaepark9c987e92016-07-29 18:17:44 -0700719bool CPVT_GenerateAP::GenerateComboBoxAP(CPDF_Document* pDoc,
720 CPDF_Dictionary* pAnnotDict) {
dsinclair777b3332016-03-31 20:03:08 -0700721 return GenerateWidgetAP(pDoc, pAnnotDict, 1);
722}
723
724// Static.
jaepark9c987e92016-07-29 18:17:44 -0700725bool CPVT_GenerateAP::GenerateListBoxAP(CPDF_Document* pDoc,
726 CPDF_Dictionary* pAnnotDict) {
dsinclair777b3332016-03-31 20:03:08 -0700727 return GenerateWidgetAP(pDoc, pAnnotDict, 2);
728}
729
730// Static.
jaepark9c987e92016-07-29 18:17:44 -0700731bool CPVT_GenerateAP::GenerateTextFieldAP(CPDF_Document* pDoc,
732 CPDF_Dictionary* pAnnotDict) {
733 return GenerateWidgetAP(pDoc, pAnnotDict, 0);
734}
735
jaeparke7107f42016-08-09 11:40:58 -0700736bool CPVT_GenerateAP::GenerateCircleAP(CPDF_Document* pDoc,
737 CPDF_Dictionary* pAnnotDict) {
jaeparke7107f42016-08-09 11:40:58 -0700738 CFX_ByteTextBuf sAppStream;
739 CFX_ByteString sExtGSDictName = "GS";
740 sAppStream << "/" << sExtGSDictName << " gs ";
741
dsinclair38fd8442016-09-15 10:15:32 -0700742 CPDF_Array* pInteriorColor = pAnnotDict->GetArrayFor("IC");
jaeparke7107f42016-08-09 11:40:58 -0700743 sAppStream << GetColorStringWithDefault(pInteriorColor,
744 CPVT_Color(CPVT_Color::kTransparent),
745 PaintOperation::FILL);
746
dsinclair38fd8442016-09-15 10:15:32 -0700747 sAppStream << GetColorStringWithDefault(pAnnotDict->GetArrayFor("C"),
jaeparke7107f42016-08-09 11:40:58 -0700748 CPVT_Color(CPVT_Color::kRGB, 0, 0, 0),
749 PaintOperation::STROKE);
750
751 FX_FLOAT fBorderWidth = GetBorderWidth(*pAnnotDict);
752 bool bIsStrokeRect = fBorderWidth > 0;
753
754 if (bIsStrokeRect) {
755 sAppStream << fBorderWidth << " w ";
756 sAppStream << GetDashPatternString(*pAnnotDict);
757 }
758
dsinclair38fd8442016-09-15 10:15:32 -0700759 CFX_FloatRect rect = pAnnotDict->GetRectFor("Rect");
jaeparke7107f42016-08-09 11:40:58 -0700760 rect.Normalize();
761
762 if (bIsStrokeRect) {
763 // Deflating rect because stroking a path entails painting all points whose
764 // perpendicular distance from the path in user space is less than or equal
765 // to half the line width.
766 rect.Deflate(fBorderWidth / 2, fBorderWidth / 2);
767 }
768
769 const FX_FLOAT fMiddleX = (rect.left + rect.right) / 2;
770 const FX_FLOAT fMiddleY = (rect.top + rect.bottom) / 2;
771
772 // |fL| is precalculated approximate value of 4 * tan((3.14 / 2) / 4) / 3,
773 // where |fL| * radius is a good approximation of control points for
774 // arc with 90 degrees.
775 const FX_FLOAT fL = 0.5523f;
776 const FX_FLOAT fDeltaX = fL * rect.Width() / 2.0;
777 const FX_FLOAT fDeltaY = fL * rect.Height() / 2.0;
778
779 // Starting point
780 sAppStream << fMiddleX << " " << rect.top << " m\n";
781 // First Bezier Curve
782 sAppStream << fMiddleX + fDeltaX << " " << rect.top << " " << rect.right
783 << " " << fMiddleY + fDeltaY << " " << rect.right << " "
784 << fMiddleY << " c\n";
785 // Second Bezier Curve
786 sAppStream << rect.right << " " << fMiddleY - fDeltaY << " "
787 << fMiddleX + fDeltaX << " " << rect.bottom << " " << fMiddleX
788 << " " << rect.bottom << " c\n";
789 // Third Bezier Curve
790 sAppStream << fMiddleX - fDeltaX << " " << rect.bottom << " " << rect.left
791 << " " << fMiddleY - fDeltaY << " " << rect.left << " " << fMiddleY
792 << " c\n";
793 // Fourth Bezier Curve
794 sAppStream << rect.left << " " << fMiddleY + fDeltaY << " "
795 << fMiddleX - fDeltaX << " " << rect.top << " " << fMiddleX << " "
796 << rect.top << " c\n";
797
798 bool bIsFillRect = pInteriorColor && !pInteriorColor->IsEmpty();
799 sAppStream << GetPaintOperatorString(bIsStrokeRect, bIsFillRect) << "\n";
800
thestig69bbfa82016-11-10 10:39:01 -0800801 auto pExtGStateDict =
jaeparke7107f42016-08-09 11:40:58 -0700802 GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal");
thestig69bbfa82016-11-10 10:39:01 -0800803 auto pResourceDict =
804 GenerateResourceDict(pDoc, std::move(pExtGStateDict), nullptr);
805 GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, std::move(pResourceDict),
tonikitoo0a17faf2016-09-15 13:50:50 -0700806 false /*IsTextMarkupAnnotation*/);
jaeparke7107f42016-08-09 11:40:58 -0700807 return true;
808}
809
jaeparkab47ace2016-07-29 19:53:40 -0700810bool CPVT_GenerateAP::GenerateHighlightAP(CPDF_Document* pDoc,
811 CPDF_Dictionary* pAnnotDict) {
jaeparkab47ace2016-07-29 19:53:40 -0700812 CFX_ByteTextBuf sAppStream;
jaepark33e9b262016-08-02 16:22:52 -0700813 CFX_ByteString sExtGSDictName = "GS";
814 sAppStream << "/" << sExtGSDictName << " gs ";
jaeparkab47ace2016-07-29 19:53:40 -0700815
dsinclair38fd8442016-09-15 10:15:32 -0700816 sAppStream << GetColorStringWithDefault(pAnnotDict->GetArrayFor("C"),
jaeparkaf7ab332016-08-09 10:23:14 -0700817 CPVT_Color(CPVT_Color::kRGB, 1, 1, 0),
818 PaintOperation::FILL);
jaeparkab47ace2016-07-29 19:53:40 -0700819
tonikitoo0a17faf2016-09-15 13:50:50 -0700820 CFX_FloatRect rect = CPDF_Annot::RectFromQuadPoints(pAnnotDict);
jaeparkab47ace2016-07-29 19:53:40 -0700821 rect.Normalize();
822
823 sAppStream << rect.left << " " << rect.top << " m " << rect.right << " "
824 << rect.top << " l " << rect.right << " " << rect.bottom << " l "
825 << rect.left << " " << rect.bottom << " l "
826 << "h f\n";
827
thestig69bbfa82016-11-10 10:39:01 -0800828 auto pExtGStateDict =
jaepark33e9b262016-08-02 16:22:52 -0700829 GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Multiply");
thestig69bbfa82016-11-10 10:39:01 -0800830 auto pResourceDict =
831 GenerateResourceDict(pDoc, std::move(pExtGStateDict), nullptr);
832 GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, std::move(pResourceDict),
tonikitoo0a17faf2016-09-15 13:50:50 -0700833 true /*IsTextMarkupAnnotation*/);
jaeparkab47ace2016-07-29 19:53:40 -0700834
jaepark33e9b262016-08-02 16:22:52 -0700835 return true;
836}
jaeparkab47ace2016-07-29 19:53:40 -0700837
jaepark39ba18a2016-08-09 15:19:35 -0700838bool CPVT_GenerateAP::GenerateInkAP(CPDF_Document* pDoc,
839 CPDF_Dictionary* pAnnotDict) {
jaepark39ba18a2016-08-09 15:19:35 -0700840 FX_FLOAT fBorderWidth = GetBorderWidth(*pAnnotDict);
841 bool bIsStroke = fBorderWidth > 0;
842
843 if (!bIsStroke)
844 return false;
845
dsinclair38fd8442016-09-15 10:15:32 -0700846 CPDF_Array* pInkList = pAnnotDict->GetArrayFor("InkList");
jaepark39ba18a2016-08-09 15:19:35 -0700847 if (!pInkList || pInkList->IsEmpty())
848 return false;
849
850 CFX_ByteTextBuf sAppStream;
851 CFX_ByteString sExtGSDictName = "GS";
852 sAppStream << "/" << sExtGSDictName << " gs ";
853
dsinclair38fd8442016-09-15 10:15:32 -0700854 sAppStream << GetColorStringWithDefault(pAnnotDict->GetArrayFor("C"),
jaepark39ba18a2016-08-09 15:19:35 -0700855 CPVT_Color(CPVT_Color::kRGB, 0, 0, 0),
856 PaintOperation::STROKE);
857
858 sAppStream << fBorderWidth << " w ";
859 sAppStream << GetDashPatternString(*pAnnotDict);
860
861 // Set inflated rect as a new rect because paths near the border with large
862 // width should not be clipped to the original rect.
dsinclair38fd8442016-09-15 10:15:32 -0700863 CFX_FloatRect rect = pAnnotDict->GetRectFor("Rect");
jaepark39ba18a2016-08-09 15:19:35 -0700864 rect.Inflate(fBorderWidth / 2, fBorderWidth / 2);
dsinclair38fd8442016-09-15 10:15:32 -0700865 pAnnotDict->SetRectFor("Rect", rect);
jaepark39ba18a2016-08-09 15:19:35 -0700866
867 for (size_t i = 0; i < pInkList->GetCount(); i++) {
868 CPDF_Array* pInkCoordList = pInkList->GetArrayAt(i);
869 if (!pInkCoordList || pInkCoordList->GetCount() < 2)
870 continue;
871
872 sAppStream << pInkCoordList->GetNumberAt(0) << " "
873 << pInkCoordList->GetNumberAt(1) << " m ";
874
875 for (size_t j = 0; j < pInkCoordList->GetCount() - 1; j += 2) {
876 sAppStream << pInkCoordList->GetNumberAt(j) << " "
877 << pInkCoordList->GetNumberAt(j + 1) << " l ";
878 }
879
880 sAppStream << "S\n";
881 }
882
thestig69bbfa82016-11-10 10:39:01 -0800883 auto pExtGStateDict =
jaepark39ba18a2016-08-09 15:19:35 -0700884 GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal");
thestig69bbfa82016-11-10 10:39:01 -0800885 auto pResourceDict =
886 GenerateResourceDict(pDoc, std::move(pExtGStateDict), nullptr);
887 GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, std::move(pResourceDict),
tonikitoo0a17faf2016-09-15 13:50:50 -0700888 false /*IsTextMarkupAnnotation*/);
jaepark39ba18a2016-08-09 15:19:35 -0700889 return true;
890}
891
jaeparkc38de112016-08-22 17:54:56 -0700892bool CPVT_GenerateAP::GenerateTextAP(CPDF_Document* pDoc,
893 CPDF_Dictionary* pAnnotDict) {
jaeparkc38de112016-08-22 17:54:56 -0700894 CFX_ByteTextBuf sAppStream;
895 CFX_ByteString sExtGSDictName = "GS";
896 sAppStream << "/" << sExtGSDictName << " gs ";
897
dsinclair38fd8442016-09-15 10:15:32 -0700898 CFX_FloatRect rect = pAnnotDict->GetRectFor("Rect");
jaeparkc38de112016-08-22 17:54:56 -0700899 const FX_FLOAT fNoteLength = 20;
900 CFX_FloatRect noteRect(rect.left, rect.bottom, rect.left + fNoteLength,
901 rect.bottom + fNoteLength);
dsinclair38fd8442016-09-15 10:15:32 -0700902 pAnnotDict->SetRectFor("Rect", noteRect);
jaeparkc38de112016-08-22 17:54:56 -0700903
904 sAppStream << GenerateTextSymbolAP(noteRect);
905
thestig69bbfa82016-11-10 10:39:01 -0800906 auto pExtGStateDict =
jaeparkc38de112016-08-22 17:54:56 -0700907 GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal");
thestig69bbfa82016-11-10 10:39:01 -0800908 auto pResourceDict =
909 GenerateResourceDict(pDoc, std::move(pExtGStateDict), nullptr);
910 GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, std::move(pResourceDict),
tonikitoo0a17faf2016-09-15 13:50:50 -0700911 false /*IsTextMarkupAnnotation*/);
jaeparkc38de112016-08-22 17:54:56 -0700912 return true;
913}
914
jaepark33e9b262016-08-02 16:22:52 -0700915bool CPVT_GenerateAP::GenerateUnderlineAP(CPDF_Document* pDoc,
916 CPDF_Dictionary* pAnnotDict) {
jaepark33e9b262016-08-02 16:22:52 -0700917 CFX_ByteTextBuf sAppStream;
918 CFX_ByteString sExtGSDictName = "GS";
919 sAppStream << "/" << sExtGSDictName << " gs ";
jaeparkab47ace2016-07-29 19:53:40 -0700920
dsinclair38fd8442016-09-15 10:15:32 -0700921 sAppStream << GetColorStringWithDefault(pAnnotDict->GetArrayFor("C"),
jaepark33e9b262016-08-02 16:22:52 -0700922 CPVT_Color(CPVT_Color::kRGB, 0, 0, 0),
923 PaintOperation::STROKE);
jaepark2d7ab182016-08-01 18:07:21 -0700924
tonikitoo0a17faf2016-09-15 13:50:50 -0700925 CFX_FloatRect rect = CPDF_Annot::RectFromQuadPoints(pAnnotDict);
jaepark33e9b262016-08-02 16:22:52 -0700926 rect.Normalize();
jaeparkab47ace2016-07-29 19:53:40 -0700927
jaepark33e9b262016-08-02 16:22:52 -0700928 FX_FLOAT fLineWidth = 1.0;
929 sAppStream << fLineWidth << " w " << rect.left << " "
930 << rect.bottom + fLineWidth << " m " << rect.right << " "
931 << rect.bottom + fLineWidth << " l S\n";
jaeparkab47ace2016-07-29 19:53:40 -0700932
thestig69bbfa82016-11-10 10:39:01 -0800933 auto pExtGStateDict =
jaepark33e9b262016-08-02 16:22:52 -0700934 GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal");
thestig69bbfa82016-11-10 10:39:01 -0800935 auto pResourceDict =
936 GenerateResourceDict(pDoc, std::move(pExtGStateDict), nullptr);
937 GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, std::move(pResourceDict),
tonikitoo0a17faf2016-09-15 13:50:50 -0700938 true /*IsTextMarkupAnnotation*/);
jaepark35512aa2016-08-29 17:15:08 -0700939 return true;
940}
941
942bool CPVT_GenerateAP::GeneratePopupAP(CPDF_Document* pDoc,
943 CPDF_Dictionary* pAnnotDict) {
944 CFX_ByteTextBuf sAppStream;
945 CFX_ByteString sExtGSDictName = "GS";
946 sAppStream << "/" << sExtGSDictName << " gs\n";
947
948 sAppStream << GenerateColorAP(CPVT_Color(CPVT_Color::kRGB, 1, 1, 0),
949 PaintOperation::FILL);
950 sAppStream << GenerateColorAP(CPVT_Color(CPVT_Color::kRGB, 0, 0, 0),
951 PaintOperation::STROKE);
952
953 const FX_FLOAT fBorderWidth = 1;
954 sAppStream << fBorderWidth << " w\n";
955
dsinclair38fd8442016-09-15 10:15:32 -0700956 CFX_FloatRect rect = pAnnotDict->GetRectFor("Rect");
jaepark35512aa2016-08-29 17:15:08 -0700957 rect.Normalize();
958 rect.Deflate(fBorderWidth / 2, fBorderWidth / 2);
959
960 sAppStream << rect.left << " " << rect.bottom << " " << rect.Width() << " "
961 << rect.Height() << " re b\n";
962
963 CFX_ByteString sFontName = "FONT";
thestig69bbfa82016-11-10 10:39:01 -0800964 auto pResourceFontDict = GenerateResourceFontDict(pDoc, sFontName);
965 CPDF_Font* pDefFont = pDoc->LoadFont(pResourceFontDict.get());
jaepark35512aa2016-08-29 17:15:08 -0700966 if (!pDefFont)
967 return false;
968
thestig69bbfa82016-11-10 10:39:01 -0800969 auto pExtGStateDict =
970 GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal");
971 auto pResourceDict = GenerateResourceDict(pDoc, std::move(pResourceFontDict),
972 std::move(pExtGStateDict));
973
jaepark35512aa2016-08-29 17:15:08 -0700974 sAppStream << GetPopupContentsString(pDoc, *pAnnotDict, pDefFont, sFontName);
thestig69bbfa82016-11-10 10:39:01 -0800975 GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, std::move(pResourceDict),
tonikitoo0a17faf2016-09-15 13:50:50 -0700976 false /*IsTextMarkupAnnotation*/);
jaeparkab47ace2016-07-29 19:53:40 -0700977 return true;
978}
979
jaeparkaf7ab332016-08-09 10:23:14 -0700980bool CPVT_GenerateAP::GenerateSquareAP(CPDF_Document* pDoc,
981 CPDF_Dictionary* pAnnotDict) {
jaeparkaf7ab332016-08-09 10:23:14 -0700982 CFX_ByteTextBuf sAppStream;
983 CFX_ByteString sExtGSDictName = "GS";
984 sAppStream << "/" << sExtGSDictName << " gs ";
985
dsinclair38fd8442016-09-15 10:15:32 -0700986 CPDF_Array* pInteriorColor = pAnnotDict->GetArrayFor("IC");
jaeparkaf7ab332016-08-09 10:23:14 -0700987 sAppStream << GetColorStringWithDefault(pInteriorColor,
988 CPVT_Color(CPVT_Color::kTransparent),
989 PaintOperation::FILL);
990
dsinclair38fd8442016-09-15 10:15:32 -0700991 sAppStream << GetColorStringWithDefault(pAnnotDict->GetArrayFor("C"),
jaeparkaf7ab332016-08-09 10:23:14 -0700992 CPVT_Color(CPVT_Color::kRGB, 0, 0, 0),
993 PaintOperation::STROKE);
994
995 FX_FLOAT fBorderWidth = GetBorderWidth(*pAnnotDict);
996 bool bIsStrokeRect = fBorderWidth > 0;
997
998 if (bIsStrokeRect) {
999 sAppStream << fBorderWidth << " w ";
1000 sAppStream << GetDashPatternString(*pAnnotDict);
1001 }
1002
dsinclair38fd8442016-09-15 10:15:32 -07001003 CFX_FloatRect rect = pAnnotDict->GetRectFor("Rect");
jaeparkaf7ab332016-08-09 10:23:14 -07001004 rect.Normalize();
1005
1006 if (bIsStrokeRect) {
1007 // Deflating rect because stroking a path entails painting all points whose
1008 // perpendicular distance from the path in user space is less than or equal
1009 // to half the line width.
1010 rect.Deflate(fBorderWidth / 2, fBorderWidth / 2);
1011 }
1012
1013 bool bIsFillRect = pInteriorColor && (pInteriorColor->GetCount() > 0);
1014
1015 sAppStream << rect.left << " " << rect.bottom << " " << rect.Width() << " "
1016 << rect.Height() << " re "
1017 << GetPaintOperatorString(bIsStrokeRect, bIsFillRect) << "\n";
1018
thestig69bbfa82016-11-10 10:39:01 -08001019 auto pExtGStateDict =
jaeparkaf7ab332016-08-09 10:23:14 -07001020 GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal");
thestig69bbfa82016-11-10 10:39:01 -08001021 auto pResourceDict =
1022 GenerateResourceDict(pDoc, std::move(pExtGStateDict), nullptr);
1023 GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, std::move(pResourceDict),
tonikitoo0a17faf2016-09-15 13:50:50 -07001024 false /*IsTextMarkupAnnotation*/);
jaeparkaf7ab332016-08-09 10:23:14 -07001025 return true;
1026}
1027
jaepark96a07862016-08-03 14:17:02 -07001028bool CPVT_GenerateAP::GenerateSquigglyAP(CPDF_Document* pDoc,
1029 CPDF_Dictionary* pAnnotDict) {
jaepark96a07862016-08-03 14:17:02 -07001030 CFX_ByteTextBuf sAppStream;
1031 CFX_ByteString sExtGSDictName = "GS";
1032 sAppStream << "/" << sExtGSDictName << " gs ";
1033
dsinclair38fd8442016-09-15 10:15:32 -07001034 sAppStream << GetColorStringWithDefault(pAnnotDict->GetArrayFor("C"),
jaepark96a07862016-08-03 14:17:02 -07001035 CPVT_Color(CPVT_Color::kRGB, 0, 0, 0),
1036 PaintOperation::STROKE);
1037
tonikitoo0a17faf2016-09-15 13:50:50 -07001038 CFX_FloatRect rect = CPDF_Annot::RectFromQuadPoints(pAnnotDict);
jaepark96a07862016-08-03 14:17:02 -07001039 rect.Normalize();
1040
1041 FX_FLOAT fLineWidth = 1.0;
1042 sAppStream << fLineWidth << " w ";
1043
1044 const FX_FLOAT fDelta = 2.0;
1045 const FX_FLOAT fTop = rect.bottom + fDelta;
1046 const FX_FLOAT fBottom = rect.bottom;
1047
1048 sAppStream << rect.left << " " << fTop << " m ";
1049
1050 FX_FLOAT fX = rect.left + fDelta;
1051 bool isUpwards = false;
1052
1053 while (fX < rect.right) {
1054 sAppStream << fX << " " << (isUpwards ? fTop : fBottom) << " l ";
1055
1056 fX += fDelta;
1057 isUpwards = !isUpwards;
1058 }
1059
1060 FX_FLOAT fRemainder = rect.right - (fX - fDelta);
1061 if (isUpwards)
1062 sAppStream << rect.right << " " << fBottom + fRemainder << " l ";
1063 else
1064 sAppStream << rect.right << " " << fTop - fRemainder << " l ";
1065
1066 sAppStream << "S\n";
1067
thestig69bbfa82016-11-10 10:39:01 -08001068 auto pExtGStateDict =
jaepark96a07862016-08-03 14:17:02 -07001069 GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal");
thestig69bbfa82016-11-10 10:39:01 -08001070 auto pResourceDict =
1071 GenerateResourceDict(pDoc, std::move(pExtGStateDict), nullptr);
1072 GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, std::move(pResourceDict),
tonikitoo0a17faf2016-09-15 13:50:50 -07001073 true /*IsTextMarkupAnnotation*/);
jaepark96a07862016-08-03 14:17:02 -07001074 return true;
1075}
1076
jaepark0d8c2d12016-08-02 17:32:23 -07001077bool CPVT_GenerateAP::GenerateStrikeOutAP(CPDF_Document* pDoc,
1078 CPDF_Dictionary* pAnnotDict) {
jaepark0d8c2d12016-08-02 17:32:23 -07001079 CFX_ByteTextBuf sAppStream;
1080 CFX_ByteString sExtGSDictName = "GS";
1081 sAppStream << "/" << sExtGSDictName << " gs ";
1082
dsinclair38fd8442016-09-15 10:15:32 -07001083 sAppStream << GetColorStringWithDefault(pAnnotDict->GetArrayFor("C"),
jaepark0d8c2d12016-08-02 17:32:23 -07001084 CPVT_Color(CPVT_Color::kRGB, 0, 0, 0),
1085 PaintOperation::STROKE);
1086
tonikitoo0a17faf2016-09-15 13:50:50 -07001087 CFX_FloatRect rect = CPDF_Annot::RectFromQuadPoints(pAnnotDict);
jaepark0d8c2d12016-08-02 17:32:23 -07001088 rect.Normalize();
1089
1090 FX_FLOAT fLineWidth = 1.0;
1091 FX_FLOAT fY = (rect.top + rect.bottom) / 2;
1092 sAppStream << fLineWidth << " w " << rect.left << " " << fY << " m "
1093 << rect.right << " " << fY << " l S\n";
1094
thestig69bbfa82016-11-10 10:39:01 -08001095 auto pExtGStateDict =
jaepark0d8c2d12016-08-02 17:32:23 -07001096 GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal");
thestig69bbfa82016-11-10 10:39:01 -08001097 auto pResourceDict =
1098 GenerateResourceDict(pDoc, std::move(pExtGStateDict), nullptr);
1099 GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, std::move(pResourceDict),
tonikitoo0a17faf2016-09-15 13:50:50 -07001100 true /*IsTextMarkupAnnotation*/);
jaepark0d8c2d12016-08-02 17:32:23 -07001101 return true;
1102}
1103
jaepark9c987e92016-07-29 18:17:44 -07001104// Static.
dsinclair777b3332016-03-31 20:03:08 -07001105CFX_ByteString CPVT_GenerateAP::GenerateEditAP(
1106 IPVT_FontMap* pFontMap,
dsinclairc7a73492016-04-05 12:01:42 -07001107 CPDF_VariableText::Iterator* pIterator,
dsinclair777b3332016-03-31 20:03:08 -07001108 const CFX_FloatPoint& ptOffset,
tsepez12f3e4a2016-11-02 15:17:29 -07001109 bool bContinuous,
thestig2c3a16a2016-05-10 13:24:16 -07001110 uint16_t SubWord) {
thestig594b20b2016-05-12 21:56:43 -07001111 CFX_ByteTextBuf sEditStream;
1112 CFX_ByteTextBuf sLineStream;
1113 CFX_ByteTextBuf sWords;
tsepez63f545c2016-09-13 16:08:49 -07001114 CFX_FloatPoint ptOld;
1115 CFX_FloatPoint ptNew;
dsinclair777b3332016-03-31 20:03:08 -07001116 int32_t nCurFontIndex = -1;
tsepez63f545c2016-09-13 16:08:49 -07001117 CPVT_WordPlace oldplace;
thestig594b20b2016-05-12 21:56:43 -07001118
thestig821d59e2016-05-11 12:59:22 -07001119 pIterator->SetAt(0);
thestig821d59e2016-05-11 12:59:22 -07001120 while (pIterator->NextWord()) {
1121 CPVT_WordPlace place = pIterator->GetAt();
1122 if (bContinuous) {
1123 if (place.LineCmp(oldplace) != 0) {
1124 if (sWords.GetSize() > 0) {
tsepez71a452f2016-05-13 17:51:27 -07001125 sLineStream << GetWordRenderString(sWords.MakeString());
thestig821d59e2016-05-11 12:59:22 -07001126 sEditStream << sLineStream;
1127 sLineStream.Clear();
1128 sWords.Clear();
dsinclair777b3332016-03-31 20:03:08 -07001129 }
1130 CPVT_Word word;
1131 if (pIterator->GetWord(word)) {
dsinclair777b3332016-03-31 20:03:08 -07001132 ptNew = CFX_FloatPoint(word.ptWord.x + ptOffset.x,
1133 word.ptWord.y + ptOffset.y);
thestig821d59e2016-05-11 12:59:22 -07001134 } else {
1135 CPVT_Line line;
1136 pIterator->GetLine(line);
1137 ptNew = CFX_FloatPoint(line.ptLine.x + ptOffset.x,
1138 line.ptLine.y + ptOffset.y);
1139 }
tsepez63f545c2016-09-13 16:08:49 -07001140 if (ptNew != ptOld) {
thestig821d59e2016-05-11 12:59:22 -07001141 sLineStream << ptNew.x - ptOld.x << " " << ptNew.y - ptOld.y
1142 << " Td\n";
1143 ptOld = ptNew;
dsinclair777b3332016-03-31 20:03:08 -07001144 }
1145 }
thestig821d59e2016-05-11 12:59:22 -07001146 CPVT_Word word;
1147 if (pIterator->GetWord(word)) {
1148 if (word.nFontIndex != nCurFontIndex) {
1149 if (sWords.GetSize() > 0) {
tsepez71a452f2016-05-13 17:51:27 -07001150 sLineStream << GetWordRenderString(sWords.MakeString());
thestig821d59e2016-05-11 12:59:22 -07001151 sWords.Clear();
1152 }
1153 sLineStream << GetFontSetString(pFontMap, word.nFontIndex,
1154 word.fFontSize);
1155 nCurFontIndex = word.nFontIndex;
1156 }
1157 sWords << GetPDFWordString(pFontMap, nCurFontIndex, word.Word, SubWord);
1158 }
1159 oldplace = place;
1160 } else {
1161 CPVT_Word word;
1162 if (pIterator->GetWord(word)) {
1163 ptNew = CFX_FloatPoint(word.ptWord.x + ptOffset.x,
1164 word.ptWord.y + ptOffset.y);
tsepez63f545c2016-09-13 16:08:49 -07001165 if (ptNew != ptOld) {
thestig821d59e2016-05-11 12:59:22 -07001166 sEditStream << ptNew.x - ptOld.x << " " << ptNew.y - ptOld.y
1167 << " Td\n";
1168 ptOld = ptNew;
1169 }
1170 if (word.nFontIndex != nCurFontIndex) {
1171 sEditStream << GetFontSetString(pFontMap, word.nFontIndex,
1172 word.fFontSize);
1173 nCurFontIndex = word.nFontIndex;
1174 }
1175 sEditStream << GetWordRenderString(
1176 GetPDFWordString(pFontMap, nCurFontIndex, word.Word, SubWord));
1177 }
dsinclair777b3332016-03-31 20:03:08 -07001178 }
thestig821d59e2016-05-11 12:59:22 -07001179 }
1180 if (sWords.GetSize() > 0) {
tsepez71a452f2016-05-13 17:51:27 -07001181 sLineStream << GetWordRenderString(sWords.MakeString());
thestig821d59e2016-05-11 12:59:22 -07001182 sEditStream << sLineStream;
1183 sWords.Clear();
dsinclair777b3332016-03-31 20:03:08 -07001184 }
tsepez71a452f2016-05-13 17:51:27 -07001185 return sEditStream.MakeString();
dsinclair777b3332016-03-31 20:03:08 -07001186}
1187
1188// Static.
1189CFX_ByteString CPVT_GenerateAP::GenerateBorderAP(
1190 const CFX_FloatRect& rect,
1191 FX_FLOAT fWidth,
1192 const CPVT_Color& color,
1193 const CPVT_Color& crLeftTop,
1194 const CPVT_Color& crRightBottom,
dsinclair92cb5e52016-05-16 11:38:28 -07001195 BorderStyle nStyle,
dsinclair777b3332016-03-31 20:03:08 -07001196 const CPVT_Dash& dash) {
1197 CFX_ByteTextBuf sAppStream;
1198 CFX_ByteString sColor;
1199 FX_FLOAT fLeft = rect.left;
1200 FX_FLOAT fRight = rect.right;
1201 FX_FLOAT fTop = rect.top;
1202 FX_FLOAT fBottom = rect.bottom;
1203 if (fWidth > 0.0f) {
1204 FX_FLOAT fHalfWidth = fWidth / 2.0f;
1205 switch (nStyle) {
1206 default:
dsinclair92cb5e52016-05-16 11:38:28 -07001207 case BorderStyle::SOLID:
jaeparkb2e63372016-08-02 12:25:15 -07001208 sColor = GenerateColorAP(color, PaintOperation::FILL);
dsinclair777b3332016-03-31 20:03:08 -07001209 if (sColor.GetLength() > 0) {
1210 sAppStream << sColor;
1211 sAppStream << fLeft << " " << fBottom << " " << fRight - fLeft << " "
1212 << fTop - fBottom << " re\n";
1213 sAppStream << fLeft + fWidth << " " << fBottom + fWidth << " "
1214 << fRight - fLeft - fWidth * 2 << " "
1215 << fTop - fBottom - fWidth * 2 << " re\n";
1216 sAppStream << "f*\n";
1217 }
1218 break;
dsinclair92cb5e52016-05-16 11:38:28 -07001219 case BorderStyle::DASH:
jaeparkb2e63372016-08-02 12:25:15 -07001220 sColor = GenerateColorAP(color, PaintOperation::STROKE);
dsinclair777b3332016-03-31 20:03:08 -07001221 if (sColor.GetLength() > 0) {
1222 sAppStream << sColor;
1223 sAppStream << fWidth << " w"
1224 << " [" << dash.nDash << " " << dash.nGap << "] "
1225 << dash.nPhase << " d\n";
1226 sAppStream << fLeft + fWidth / 2 << " " << fBottom + fWidth / 2
1227 << " m\n";
1228 sAppStream << fLeft + fWidth / 2 << " " << fTop - fWidth / 2
1229 << " l\n";
1230 sAppStream << fRight - fWidth / 2 << " " << fTop - fWidth / 2
1231 << " l\n";
1232 sAppStream << fRight - fWidth / 2 << " " << fBottom + fWidth / 2
1233 << " l\n";
1234 sAppStream << fLeft + fWidth / 2 << " " << fBottom + fWidth / 2
1235 << " l S\n";
1236 }
1237 break;
dsinclair92cb5e52016-05-16 11:38:28 -07001238 case BorderStyle::BEVELED:
1239 case BorderStyle::INSET:
jaeparkb2e63372016-08-02 12:25:15 -07001240 sColor = GenerateColorAP(crLeftTop, PaintOperation::FILL);
dsinclair777b3332016-03-31 20:03:08 -07001241 if (sColor.GetLength() > 0) {
1242 sAppStream << sColor;
1243 sAppStream << fLeft + fHalfWidth << " " << fBottom + fHalfWidth
1244 << " m\n";
1245 sAppStream << fLeft + fHalfWidth << " " << fTop - fHalfWidth
1246 << " l\n";
1247 sAppStream << fRight - fHalfWidth << " " << fTop - fHalfWidth
1248 << " l\n";
1249 sAppStream << fRight - fHalfWidth * 2 << " " << fTop - fHalfWidth * 2
1250 << " l\n";
1251 sAppStream << fLeft + fHalfWidth * 2 << " " << fTop - fHalfWidth * 2
1252 << " l\n";
1253 sAppStream << fLeft + fHalfWidth * 2 << " "
1254 << fBottom + fHalfWidth * 2 << " l f\n";
1255 }
jaeparkb2e63372016-08-02 12:25:15 -07001256 sColor = GenerateColorAP(crRightBottom, PaintOperation::FILL);
dsinclair777b3332016-03-31 20:03:08 -07001257 if (sColor.GetLength() > 0) {
1258 sAppStream << sColor;
1259 sAppStream << fRight - fHalfWidth << " " << fTop - fHalfWidth
1260 << " m\n";
1261 sAppStream << fRight - fHalfWidth << " " << fBottom + fHalfWidth
1262 << " l\n";
1263 sAppStream << fLeft + fHalfWidth << " " << fBottom + fHalfWidth
1264 << " l\n";
1265 sAppStream << fLeft + fHalfWidth * 2 << " "
1266 << fBottom + fHalfWidth * 2 << " l\n";
1267 sAppStream << fRight - fHalfWidth * 2 << " "
1268 << fBottom + fHalfWidth * 2 << " l\n";
1269 sAppStream << fRight - fHalfWidth * 2 << " " << fTop - fHalfWidth * 2
1270 << " l f\n";
1271 }
jaeparkb2e63372016-08-02 12:25:15 -07001272 sColor = GenerateColorAP(color, PaintOperation::FILL);
dsinclair777b3332016-03-31 20:03:08 -07001273 if (sColor.GetLength() > 0) {
1274 sAppStream << sColor;
1275 sAppStream << fLeft << " " << fBottom << " " << fRight - fLeft << " "
1276 << fTop - fBottom << " re\n";
1277 sAppStream << fLeft + fHalfWidth << " " << fBottom + fHalfWidth << " "
1278 << fRight - fLeft - fHalfWidth * 2 << " "
1279 << fTop - fBottom - fHalfWidth * 2 << " re f*\n";
1280 }
1281 break;
dsinclair92cb5e52016-05-16 11:38:28 -07001282 case BorderStyle::UNDERLINE:
jaeparkb2e63372016-08-02 12:25:15 -07001283 sColor = GenerateColorAP(color, PaintOperation::STROKE);
dsinclair777b3332016-03-31 20:03:08 -07001284 if (sColor.GetLength() > 0) {
1285 sAppStream << sColor;
1286 sAppStream << fWidth << " w\n";
1287 sAppStream << fLeft << " " << fBottom + fWidth / 2 << " m\n";
1288 sAppStream << fRight << " " << fBottom + fWidth / 2 << " l S\n";
1289 }
1290 break;
1291 }
1292 }
tsepez71a452f2016-05-13 17:51:27 -07001293 return sAppStream.MakeString();
dsinclair777b3332016-03-31 20:03:08 -07001294}
1295
1296// Static.
1297CFX_ByteString CPVT_GenerateAP::GenerateColorAP(const CPVT_Color& color,
jaeparkb2e63372016-08-02 12:25:15 -07001298 PaintOperation nOperation) {
dsinclair777b3332016-03-31 20:03:08 -07001299 CFX_ByteTextBuf sColorStream;
1300 switch (color.nColorType) {
1301 case CPVT_Color::kRGB:
1302 sColorStream << color.fColor1 << " " << color.fColor2 << " "
jaeparkb2e63372016-08-02 12:25:15 -07001303 << color.fColor3 << " "
1304 << (nOperation == PaintOperation::STROKE ? "RG" : "rg")
dsinclair777b3332016-03-31 20:03:08 -07001305 << "\n";
1306 break;
1307 case CPVT_Color::kGray:
jaeparkb2e63372016-08-02 12:25:15 -07001308 sColorStream << color.fColor1 << " "
1309 << (nOperation == PaintOperation::STROKE ? "G" : "g")
dsinclair777b3332016-03-31 20:03:08 -07001310 << "\n";
1311 break;
1312 case CPVT_Color::kCMYK:
1313 sColorStream << color.fColor1 << " " << color.fColor2 << " "
1314 << color.fColor3 << " " << color.fColor4 << " "
jaeparkb2e63372016-08-02 12:25:15 -07001315 << (nOperation == PaintOperation::STROKE ? "K" : "k")
1316 << "\n";
dsinclair777b3332016-03-31 20:03:08 -07001317 break;
1318 case CPVT_Color::kTransparent:
1319 break;
1320 }
tsepez71a452f2016-05-13 17:51:27 -07001321 return sColorStream.MakeString();
dsinclair777b3332016-03-31 20:03:08 -07001322}
1323
1324// Static.
1325CFX_ByteString CPVT_GenerateAP::GetPDFWordString(IPVT_FontMap* pFontMap,
1326 int32_t nFontIndex,
1327 uint16_t Word,
1328 uint16_t SubWord) {
1329 CFX_ByteString sWord;
1330 if (SubWord > 0) {
1331 sWord.Format("%c", SubWord);
1332 return sWord;
1333 }
1334
1335 if (!pFontMap)
1336 return sWord;
1337
1338 if (CPDF_Font* pPDFFont = pFontMap->GetPDFFont(nFontIndex)) {
1339 if (pPDFFont->GetBaseFont().Compare("Symbol") == 0 ||
1340 pPDFFont->GetBaseFont().Compare("ZapfDingbats") == 0) {
1341 sWord.Format("%c", Word);
1342 } else {
1343 uint32_t dwCharCode = pPDFFont->CharCodeFromUnicode(Word);
1344 if (dwCharCode != CPDF_Font::kInvalidCharCode)
1345 pPDFFont->AppendChar(sWord, dwCharCode);
1346 }
1347 }
1348 return sWord;
1349}
1350
1351// Static.
1352CFX_ByteString CPVT_GenerateAP::GetWordRenderString(
1353 const CFX_ByteString& strWords) {
1354 if (strWords.GetLength() > 0)
1355 return PDF_EncodeString(strWords) + " Tj\n";
1356 return "";
1357}
1358
1359// Static.
1360CFX_ByteString CPVT_GenerateAP::GetFontSetString(IPVT_FontMap* pFontMap,
1361 int32_t nFontIndex,
1362 FX_FLOAT fFontSize) {
1363 CFX_ByteTextBuf sRet;
1364 if (pFontMap) {
1365 CFX_ByteString sFontAlias = pFontMap->GetPDFFontAlias(nFontIndex);
1366 if (sFontAlias.GetLength() > 0 && fFontSize > 0)
1367 sRet << "/" << sFontAlias << " " << fFontSize << " Tf\n";
1368 }
tsepez71a452f2016-05-13 17:51:27 -07001369 return sRet.MakeString();
dsinclair777b3332016-03-31 20:03:08 -07001370}