1 // Copyright 2016 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6 
7 #include "core/fpdfdoc/cpvt_generateap.h"
8 
9 #include <algorithm>
10 #include <memory>
11 #include <utility>
12 
13 #include "core/fpdfapi/font/cpdf_font.h"
14 #include "core/fpdfapi/parser/cpdf_boolean.h"
15 #include "core/fpdfapi/parser/cpdf_dictionary.h"
16 #include "core/fpdfapi/parser/cpdf_document.h"
17 #include "core/fpdfapi/parser/cpdf_name.h"
18 #include "core/fpdfapi/parser/cpdf_number.h"
19 #include "core/fpdfapi/parser/cpdf_reference.h"
20 #include "core/fpdfapi/parser/cpdf_simple_parser.h"
21 #include "core/fpdfapi/parser/cpdf_stream.h"
22 #include "core/fpdfapi/parser/cpdf_string.h"
23 #include "core/fpdfapi/parser/fpdf_parser_decode.h"
24 #include "core/fpdfdoc/cpdf_annot.h"
25 #include "core/fpdfdoc/cpdf_formfield.h"
26 #include "core/fpdfdoc/cpvt_color.h"
27 #include "core/fpdfdoc/cpvt_fontmap.h"
28 #include "core/fpdfdoc/cpvt_word.h"
29 #include "third_party/base/ptr_util.h"
30 
31 namespace {
32 
GenerateWidgetAP(CPDF_Document * pDoc,CPDF_Dictionary * pAnnotDict,const int32_t & nWidgetType)33 bool GenerateWidgetAP(CPDF_Document* pDoc,
34                       CPDF_Dictionary* pAnnotDict,
35                       const int32_t& nWidgetType) {
36   CPDF_Dictionary* pFormDict = nullptr;
37   if (CPDF_Dictionary* pRootDict = pDoc->GetRoot())
38     pFormDict = pRootDict->GetDictFor("AcroForm");
39   if (!pFormDict)
40     return false;
41 
42   CFX_ByteString DA;
43   if (CPDF_Object* pDAObj = FPDF_GetFieldAttr(pAnnotDict, "DA"))
44     DA = pDAObj->GetString();
45   if (DA.IsEmpty())
46     DA = pFormDict->GetStringFor("DA");
47   if (DA.IsEmpty())
48     return false;
49 
50   CPDF_SimpleParser syntax(DA.AsStringC());
51   syntax.FindTagParamFromStart("Tf", 2);
52   CFX_ByteString sFontName(syntax.GetWord());
53   sFontName = PDF_NameDecode(sFontName);
54   if (sFontName.IsEmpty())
55     return false;
56 
57   FX_FLOAT fFontSize = FX_atof(syntax.GetWord());
58   CPVT_Color crText = CPVT_Color::ParseColor(DA);
59   CPDF_Dictionary* pDRDict = pFormDict->GetDictFor("DR");
60   if (!pDRDict)
61     return false;
62 
63   CPDF_Dictionary* pDRFontDict = pDRDict->GetDictFor("Font");
64   if (!pDRFontDict)
65     return false;
66 
67   CPDF_Dictionary* pFontDict = pDRFontDict->GetDictFor(sFontName.Mid(1));
68   if (!pFontDict) {
69     pFontDict = pDoc->NewIndirect<CPDF_Dictionary>();
70     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());
76   }
77   CPDF_Font* pDefFont = pDoc->LoadFont(pFontDict);
78   if (!pDefFont)
79     return false;
80 
81   CFX_FloatRect rcAnnot = pAnnotDict->GetRectFor("Rect");
82   int32_t nRotate = 0;
83   if (CPDF_Dictionary* pMKDict = pAnnotDict->GetDictFor("MK"))
84     nRotate = pMKDict->GetIntegerFor("R");
85 
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   }
110 
111   BorderStyle nBorderStyle = BorderStyle::SOLID;
112   FX_FLOAT fBorderWidth = 1;
113   CPVT_Dash dsBorder(3, 0, 0);
114   CPVT_Color crLeftTop, crRightBottom;
115   if (CPDF_Dictionary* pBSDict = pAnnotDict->GetDictFor("BS")) {
116     if (pBSDict->KeyExist("W"))
117       fBorderWidth = pBSDict->GetNumberFor("W");
118 
119     if (CPDF_Array* pArray = pBSDict->GetArrayFor("D")) {
120       dsBorder = CPVT_Dash(pArray->GetIntegerAt(0), pArray->GetIntegerAt(1),
121                            pArray->GetIntegerAt(2));
122     }
123     switch (pBSDict->GetStringFor("S").GetAt(0)) {
124       case 'S':
125         nBorderStyle = BorderStyle::SOLID;
126         break;
127       case 'D':
128         nBorderStyle = BorderStyle::DASH;
129         break;
130       case 'B':
131         nBorderStyle = BorderStyle::BEVELED;
132         fBorderWidth *= 2;
133         crLeftTop = CPVT_Color(CPVT_Color::kGray, 1);
134         crRightBottom = CPVT_Color(CPVT_Color::kGray, 0.5);
135         break;
136       case 'I':
137         nBorderStyle = BorderStyle::INSET;
138         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':
143         nBorderStyle = BorderStyle::UNDERLINE;
144         break;
145     }
146   }
147   CPVT_Color crBorder, crBG;
148   if (CPDF_Dictionary* pMKDict = pAnnotDict->GetDictFor("MK")) {
149     if (CPDF_Array* pArray = pMKDict->GetArrayFor("BC"))
150       crBorder = CPVT_Color::ParseColor(*pArray);
151     if (CPDF_Array* pArray = pMKDict->GetArrayFor("BG"))
152       crBG = CPVT_Color::ParseColor(*pArray);
153   }
154   CFX_ByteTextBuf sAppStream;
155   CFX_ByteString sBG =
156       CPVT_GenerateAP::GenerateColorAP(crBG, PaintOperation::FILL);
157   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();
172 
173   CPDF_Dictionary* pAPDict = pAnnotDict->GetDictFor("AP");
174   if (!pAPDict)
175     pAPDict = pAnnotDict->SetNewFor<CPDF_Dictionary>("AP");
176 
177   CPDF_Stream* pNormalStream = pAPDict->GetStreamFor("N");
178   if (!pNormalStream) {
179     pNormalStream = pDoc->NewIndirect<CPDF_Stream>();
180     pAPDict->SetNewFor<CPDF_Reference>("N", pDoc, pNormalStream->GetObjNum());
181   }
182   CPDF_Dictionary* pStreamDict = pNormalStream->GetDict();
183   if (pStreamDict) {
184     pStreamDict->SetMatrixFor("Matrix", matrix);
185     pStreamDict->SetRectFor("BBox", rcBBox);
186     CPDF_Dictionary* pStreamResList = pStreamDict->GetDictFor("Resources");
187     if (pStreamResList) {
188       CPDF_Dictionary* pStreamResFontList = pStreamResList->GetDictFor("Font");
189       if (!pStreamResFontList)
190         pStreamResFontList = pStreamResList->SetNewFor<CPDF_Dictionary>("Font");
191       if (!pStreamResFontList->KeyExist(sFontName)) {
192         pStreamResFontList->SetNewFor<CPDF_Reference>(sFontName, pDoc,
193                                                       pFontDict->GetObjNum());
194       }
195     } else {
196       pStreamDict->SetFor("Resources", pFormDict->GetDictFor("DR")->Clone());
197       pStreamResList = pStreamDict->GetDictFor("Resources");
198     }
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(
217           pDoc, pStreamDict ? pStreamDict->GetDictFor("Resources") : nullptr,
218           pDefFont, sFontName.Right(sFontName.GetLength() - 1));
219       CPDF_VariableText::Provider prd(&map);
220       CPDF_VariableText vt;
221       vt.SetProvider(&prd);
222       vt.SetPlateRect(rcBody);
223       vt.SetAlignment(nAlign);
224       if (IsFloatZero(fFontSize))
225         vt.SetAutoFontSize(true);
226       else
227         vt.SetFontSize(fFontSize);
228 
229       bool bMultiLine = (dwFlags >> 12) & 1;
230       if (bMultiLine) {
231         vt.SetMultiLine(true);
232         vt.SetAutoReturn(true);
233       }
234       uint16_t subWord = 0;
235       if ((dwFlags >> 13) & 1) {
236         subWord = '*';
237         vt.SetPasswordChar(subWord);
238       }
239       bool bCharArray = (dwFlags >> 24) & 1;
240       if (bCharArray)
241         vt.SetCharArray(dwMaxLen);
242       else
243         vt.SetLimitChar(dwMaxLen);
244 
245       vt.Initialize();
246       vt.SetText(swValue);
247       vt.RearrangeAll();
248       CFX_FloatRect rcContent = vt.GetContentRect();
249       CFX_PointF ptOffset;
250       if (!bMultiLine) {
251         ptOffset =
252             CFX_PointF(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         }
265         sAppStream << "BT\n"
266                    << CPVT_GenerateAP::GenerateColorAP(crText,
267                                                        PaintOperation::FILL)
268                    << 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(
278           pDoc, pStreamDict ? pStreamDict->GetDictFor("Resources") : nullptr,
279           pDefFont, sFontName.Right(sFontName.GetLength() - 1));
280       CPDF_VariableText::Provider prd(&map);
281       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))
291         vt.SetAutoFontSize(true);
292       else
293         vt.SetFontSize(fFontSize);
294 
295       vt.Initialize();
296       vt.SetText(swValue);
297       vt.RearrangeAll();
298       CFX_FloatRect rcContent = vt.GetContentRect();
299       CFX_PointF ptOffset =
300           CFX_PointF(0.0f, (rcContent.Height() - rcEdit.Height()) / 2.0f);
301       CFX_ByteString sEdit = CPVT_GenerateAP::GenerateEditAP(
302           &map, vt.GetIterator(), ptOffset, true, 0);
303       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";
308         sAppStream << "BT\n"
309                    << CPVT_GenerateAP::GenerateColorAP(crText,
310                                                        PaintOperation::FILL)
311                    << 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),
317           PaintOperation::FILL);
318       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),
326             CPVT_Color(CPVT_Color::kGray, 0.5), BorderStyle::BEVELED,
327             CPVT_Dash(3, 0, 0));
328         if (sButtonBorder.GetLength() > 0)
329           sAppStream << "q\n" << sButtonBorder << "Q\n";
330 
331         CFX_PointF ptCenter = CFX_PointF((rcButton.left + rcButton.right) / 2,
332                                          (rcButton.top + rcButton.bottom) / 2);
333         if (IsFloatBigger(rcButton.Width(), 6) &&
334             IsFloatBigger(rcButton.Height(), 6)) {
335           sAppStream << "q\n"
336                      << " 0 g\n";
337           sAppStream << ptCenter.x - 3 << " " << ptCenter.y + 1.5f << " m\n";
338           sAppStream << ptCenter.x + 3 << " " << ptCenter.y + 1.5f << " l\n";
339           sAppStream << ptCenter.x << " " << ptCenter.y - 1.5f << " l\n";
340           sAppStream << ptCenter.x - 3 << " " << ptCenter.y + 1.5f << " l f\n";
341           sAppStream << sButton << "Q\n";
342         }
343       }
344     } break;
345     case 2: {
346       CPVT_FontMap map(
347           pDoc, pStreamDict ? pStreamDict->GetDictFor("Resources") : nullptr,
348           pDefFont, sFontName.Right(sFontName.GetLength() - 1));
349       CPDF_VariableText::Provider prd(&map);
350       CPDF_Array* pOpts = ToArray(FPDF_GetFieldAttr(pAnnotDict, "Opt"));
351       CPDF_Array* pSels = ToArray(FPDF_GetFieldAttr(pAnnotDict, "I"));
352       CPDF_Object* pTi = FPDF_GetFieldAttr(pAnnotDict, "TI");
353       int32_t nTop = pTi ? pTi->GetInteger() : 0;
354       CFX_ByteTextBuf sBody;
355       if (pOpts) {
356         FX_FLOAT fy = rcBody.top;
357         for (size_t i = nTop, sz = pOpts->GetCount(); i < sz; i++) {
358           if (IsFloatSmaller(fy, rcBody.bottom))
359             break;
360 
361           if (CPDF_Object* pOpt = pOpts->GetDirectObjectAt(i)) {
362             CFX_WideString swItem;
363             if (pOpt->IsString())
364               swItem = pOpt->GetUnicodeText();
365             else if (CPDF_Array* pArray = pOpt->AsArray())
366               swItem = pArray->GetDirectObjectAt(1)->GetUnicodeText();
367 
368             bool bSelected = false;
369             if (pSels) {
370               for (size_t s = 0, ssz = pSels->GetCount(); s < ssz; s++) {
371                 int value = pSels->GetIntegerAt(s);
372                 if (value >= 0 && i == static_cast<size_t>(value)) {
373                   bSelected = true;
374                   break;
375                 }
376               }
377             }
378             CPDF_VariableText vt;
379             vt.SetProvider(&prd);
380             vt.SetPlateRect(
381                 CFX_FloatRect(rcBody.left, 0.0f, rcBody.right, 0.0f));
382             vt.SetFontSize(IsFloatZero(fFontSize) ? 12.0f : fFontSize);
383 
384             vt.Initialize();
385             vt.SetText(swItem);
386             vt.RearrangeAll();
387             FX_FLOAT fItemHeight = vt.GetContentRect().Height();
388             if (bSelected) {
389               CFX_FloatRect rcItem = CFX_FloatRect(
390                   rcBody.left, fy - fItemHeight, rcBody.right, fy);
391               sBody << "q\n"
392                     << CPVT_GenerateAP::GenerateColorAP(
393                            CPVT_Color(CPVT_Color::kRGB, 0, 51.0f / 255.0f,
394                                       113.0f / 255.0f),
395                            PaintOperation::FILL)
396                     << rcItem.left << " " << rcItem.bottom << " "
397                     << rcItem.Width() << " " << rcItem.Height() << " re f\n"
398                     << "Q\n";
399               sBody << "BT\n"
400                     << CPVT_GenerateAP::GenerateColorAP(
401                            CPVT_Color(CPVT_Color::kGray, 1),
402                            PaintOperation::FILL)
403                     << CPVT_GenerateAP::GenerateEditAP(&map, vt.GetIterator(),
404                                                        CFX_PointF(0.0f, fy),
405                                                        true, 0)
406                     << "ET\n";
407             } else {
408               sBody << "BT\n"
409                     << CPVT_GenerateAP::GenerateColorAP(crText,
410                                                         PaintOperation::FILL)
411                     << CPVT_GenerateAP::GenerateEditAP(&map, vt.GetIterator(),
412                                                        CFX_PointF(0.0f, fy),
413                                                        true, 0)
414                     << "ET\n";
415             }
416             fy -= fItemHeight;
417           }
418         }
419       }
420       if (sBody.GetSize() > 0) {
421         sAppStream << "/Tx BMC\nq\n"
422                    << rcBody.left << " " << rcBody.bottom << " "
423                    << rcBody.Width() << " " << rcBody.Height() << " re\nW\nn\n"
424                    << sBody.AsStringC() << "Q\nEMC\n";
425       }
426     } break;
427   }
428   if (pNormalStream) {
429     pNormalStream->SetData(sAppStream.GetBuffer(), sAppStream.GetSize());
430     pStreamDict = pNormalStream->GetDict();
431     if (pStreamDict) {
432       pStreamDict->SetMatrixFor("Matrix", matrix);
433       pStreamDict->SetRectFor("BBox", rcBBox);
434       CPDF_Dictionary* pStreamResList = pStreamDict->GetDictFor("Resources");
435       if (pStreamResList) {
436         CPDF_Dictionary* pStreamResFontList =
437             pStreamResList->GetDictFor("Font");
438         if (!pStreamResFontList) {
439           pStreamResFontList =
440               pStreamResList->SetNewFor<CPDF_Dictionary>("Font");
441         }
442         if (!pStreamResFontList->KeyExist(sFontName)) {
443           pStreamResFontList->SetNewFor<CPDF_Reference>(sFontName, pDoc,
444                                                         pFontDict->GetObjNum());
445         }
446       } else {
447         pStreamDict->SetFor("Resources", pFormDict->GetDictFor("DR")->Clone());
448         pStreamResList = pStreamDict->GetDictFor("Resources");
449       }
450     }
451   }
452   return true;
453 }
454 
GetColorStringWithDefault(CPDF_Array * pColor,const CPVT_Color & crDefaultColor,PaintOperation nOperation)455 CFX_ByteString GetColorStringWithDefault(CPDF_Array* pColor,
456                                          const CPVT_Color& crDefaultColor,
457                                          PaintOperation nOperation) {
458   if (pColor) {
459     CPVT_Color color = CPVT_Color::ParseColor(*pColor);
460     return CPVT_GenerateAP::GenerateColorAP(color, nOperation);
461   }
462 
463   return CPVT_GenerateAP::GenerateColorAP(crDefaultColor, nOperation);
464 }
465 
GetBorderWidth(const CPDF_Dictionary & pAnnotDict)466 FX_FLOAT GetBorderWidth(const CPDF_Dictionary& pAnnotDict) {
467   if (CPDF_Dictionary* pBorderStyleDict = pAnnotDict.GetDictFor("BS")) {
468     if (pBorderStyleDict->KeyExist("W"))
469       return pBorderStyleDict->GetNumberFor("W");
470   }
471 
472   if (CPDF_Array* pBorderArray = pAnnotDict.GetArrayFor("Border")) {
473     if (pBorderArray->GetCount() > 2)
474       return pBorderArray->GetNumberAt(2);
475   }
476 
477   return 1;
478 }
479 
GetDashArray(const CPDF_Dictionary & pAnnotDict)480 CPDF_Array* GetDashArray(const CPDF_Dictionary& pAnnotDict) {
481   if (CPDF_Dictionary* pBorderStyleDict = pAnnotDict.GetDictFor("BS")) {
482     if (pBorderStyleDict->GetStringFor("S") == "D")
483       return pBorderStyleDict->GetArrayFor("D");
484   }
485 
486   if (CPDF_Array* pBorderArray = pAnnotDict.GetArrayFor("Border")) {
487     if (pBorderArray->GetCount() == 4)
488       return pBorderArray->GetArrayAt(3);
489   }
490 
491   return nullptr;
492 }
493 
GetDashPatternString(const CPDF_Dictionary & pAnnotDict)494 CFX_ByteString GetDashPatternString(const CPDF_Dictionary& pAnnotDict) {
495   CPDF_Array* pDashArray = GetDashArray(pAnnotDict);
496   if (!pDashArray || pDashArray->IsEmpty())
497     return CFX_ByteString();
498 
499   // Support maximum of ten elements in the dash array.
500   size_t pDashArrayCount = std::min<size_t>(pDashArray->GetCount(), 10);
501   CFX_ByteTextBuf sDashStream;
502 
503   sDashStream << "[";
504   for (size_t i = 0; i < pDashArrayCount; ++i)
505     sDashStream << pDashArray->GetNumberAt(i) << " ";
506   sDashStream << "] 0 d\n";
507 
508   return sDashStream.MakeString();
509 }
510 
GetPopupContentsString(CPDF_Document * pDoc,const CPDF_Dictionary & pAnnotDict,CPDF_Font * pDefFont,const CFX_ByteString & sFontName)511 CFX_ByteString GetPopupContentsString(CPDF_Document* pDoc,
512                                       const CPDF_Dictionary& pAnnotDict,
513                                       CPDF_Font* pDefFont,
514                                       const CFX_ByteString& sFontName) {
515   CFX_WideString swValue(pAnnotDict.GetUnicodeTextFor("T"));
516   swValue += L'\n';
517   swValue += pAnnotDict.GetUnicodeTextFor("Contents");
518   CPVT_FontMap map(pDoc, nullptr, pDefFont, sFontName);
519 
520   CPDF_VariableText::Provider prd(&map);
521   CPDF_VariableText vt;
522   vt.SetProvider(&prd);
523   vt.SetPlateRect(pAnnotDict.GetRectFor("Rect"));
524   vt.SetFontSize(12);
525   vt.SetAutoReturn(true);
526   vt.SetMultiLine(true);
527 
528   vt.Initialize();
529   vt.SetText(swValue);
530   vt.RearrangeAll();
531   CFX_PointF ptOffset(3.0f, -3.0f);
532   CFX_ByteString sContent = CPVT_GenerateAP::GenerateEditAP(
533       &map, vt.GetIterator(), ptOffset, false, 0);
534 
535   if (sContent.IsEmpty())
536     return CFX_ByteString();
537 
538   CFX_ByteTextBuf sAppStream;
539   sAppStream << "BT\n"
540              << CPVT_GenerateAP::GenerateColorAP(
541                     CPVT_Color(CPVT_Color::kRGB, 0, 0, 0), PaintOperation::FILL)
542              << sContent << "ET\n"
543              << "Q\n";
544   return sAppStream.MakeString();
545 }
546 
GenerateExtGStateDict(const CPDF_Dictionary & pAnnotDict,const CFX_ByteString & sExtGSDictName,const CFX_ByteString & sBlendMode)547 std::unique_ptr<CPDF_Dictionary> GenerateExtGStateDict(
548     const CPDF_Dictionary& pAnnotDict,
549     const CFX_ByteString& sExtGSDictName,
550     const CFX_ByteString& sBlendMode) {
551   auto pGSDict =
552       pdfium::MakeUnique<CPDF_Dictionary>(pAnnotDict.GetByteStringPool());
553   pGSDict->SetNewFor<CPDF_String>("Type", "ExtGState", false);
554 
555   FX_FLOAT fOpacity =
556       pAnnotDict.KeyExist("CA") ? pAnnotDict.GetNumberFor("CA") : 1;
557   pGSDict->SetNewFor<CPDF_Number>("CA", fOpacity);
558   pGSDict->SetNewFor<CPDF_Number>("ca", fOpacity);
559   pGSDict->SetNewFor<CPDF_Boolean>("AIS", false);
560   pGSDict->SetNewFor<CPDF_String>("BM", sBlendMode, false);
561 
562   auto pExtGStateDict =
563       pdfium::MakeUnique<CPDF_Dictionary>(pAnnotDict.GetByteStringPool());
564   pExtGStateDict->SetFor(sExtGSDictName, std::move(pGSDict));
565   return pExtGStateDict;
566 }
567 
GenerateResourceFontDict(CPDF_Document * pDoc,const CFX_ByteString & sFontDictName)568 std::unique_ptr<CPDF_Dictionary> GenerateResourceFontDict(
569     CPDF_Document* pDoc,
570     const CFX_ByteString& sFontDictName) {
571   CPDF_Dictionary* pFontDict = pDoc->NewIndirect<CPDF_Dictionary>();
572   pFontDict->SetNewFor<CPDF_Name>("Type", "Font");
573   pFontDict->SetNewFor<CPDF_Name>("Subtype", "Type1");
574   pFontDict->SetNewFor<CPDF_Name>("BaseFont", "Helvetica");
575   pFontDict->SetNewFor<CPDF_Name>("Encoding", "WinAnsiEncoding");
576 
577   auto pResourceFontDict =
578       pdfium::MakeUnique<CPDF_Dictionary>(pDoc->GetByteStringPool());
579   pResourceFontDict->SetNewFor<CPDF_Reference>(sFontDictName, pDoc,
580                                                pFontDict->GetObjNum());
581   return pResourceFontDict;
582 }
583 
GenerateResourceDict(CPDF_Document * pDoc,std::unique_ptr<CPDF_Dictionary> pExtGStateDict,std::unique_ptr<CPDF_Dictionary> pResourceFontDict)584 std::unique_ptr<CPDF_Dictionary> GenerateResourceDict(
585     CPDF_Document* pDoc,
586     std::unique_ptr<CPDF_Dictionary> pExtGStateDict,
587     std::unique_ptr<CPDF_Dictionary> pResourceFontDict) {
588   auto pResourceDict =
589       pdfium::MakeUnique<CPDF_Dictionary>(pDoc->GetByteStringPool());
590   if (pExtGStateDict)
591     pResourceDict->SetFor("ExtGState", std::move(pExtGStateDict));
592   if (pResourceFontDict)
593     pResourceDict->SetFor("Font", std::move(pResourceFontDict));
594   return pResourceDict;
595 }
596 
GenerateAndSetAPDict(CPDF_Document * pDoc,CPDF_Dictionary * pAnnotDict,const CFX_ByteTextBuf & sAppStream,std::unique_ptr<CPDF_Dictionary> pResourceDict,bool bIsTextMarkupAnnotation)597 void GenerateAndSetAPDict(CPDF_Document* pDoc,
598                           CPDF_Dictionary* pAnnotDict,
599                           const CFX_ByteTextBuf& sAppStream,
600                           std::unique_ptr<CPDF_Dictionary> pResourceDict,
601                           bool bIsTextMarkupAnnotation) {
602   CPDF_Stream* pNormalStream = pDoc->NewIndirect<CPDF_Stream>();
603   pNormalStream->SetData(sAppStream.GetBuffer(), sAppStream.GetSize());
604 
605   CPDF_Dictionary* pAPDict = pAnnotDict->SetNewFor<CPDF_Dictionary>("AP");
606   pAPDict->SetNewFor<CPDF_Reference>("N", pDoc, pNormalStream->GetObjNum());
607 
608   CPDF_Dictionary* pStreamDict = pNormalStream->GetDict();
609   pStreamDict->SetNewFor<CPDF_Number>("FormType", 1);
610   pStreamDict->SetNewFor<CPDF_String>("Subtype", "Form", false);
611   pStreamDict->SetMatrixFor("Matrix", CFX_Matrix());
612 
613   CFX_FloatRect rect = bIsTextMarkupAnnotation
614                            ? CPDF_Annot::RectFromQuadPoints(pAnnotDict)
615                            : pAnnotDict->GetRectFor("Rect");
616   pStreamDict->SetRectFor("BBox", rect);
617   pStreamDict->SetFor("Resources", std::move(pResourceDict));
618 }
619 
GetPaintOperatorString(bool bIsStrokeRect,bool bIsFillRect)620 CFX_ByteString GetPaintOperatorString(bool bIsStrokeRect, bool bIsFillRect) {
621   if (bIsStrokeRect)
622     return bIsFillRect ? "b" : "s";
623   return bIsFillRect ? "f" : "n";
624 }
625 
GenerateTextSymbolAP(const CFX_FloatRect & rect)626 CFX_ByteString GenerateTextSymbolAP(const CFX_FloatRect& rect) {
627   CFX_ByteTextBuf sAppStream;
628   sAppStream << CPVT_GenerateAP::GenerateColorAP(
629       CPVT_Color(CPVT_Color::kRGB, 1, 1, 0), PaintOperation::FILL);
630   sAppStream << CPVT_GenerateAP::GenerateColorAP(
631       CPVT_Color(CPVT_Color::kRGB, 0, 0, 0), PaintOperation::STROKE);
632 
633   const FX_FLOAT fBorderWidth = 1;
634   sAppStream << fBorderWidth << " w\n";
635 
636   const FX_FLOAT fHalfWidth = fBorderWidth / 2;
637   const FX_FLOAT fTipDelta = 4;
638 
639   CFX_FloatRect outerRect1 = rect;
640   outerRect1.Deflate(fHalfWidth, fHalfWidth);
641   outerRect1.bottom += fTipDelta;
642 
643   CFX_FloatRect outerRect2 = outerRect1;
644   outerRect2.left += fTipDelta;
645   outerRect2.right = outerRect2.left + fTipDelta;
646   outerRect2.top = outerRect2.bottom - fTipDelta;
647   FX_FLOAT outerRect2Middle = (outerRect2.left + outerRect2.right) / 2;
648 
649   // Draw outer boxes.
650   sAppStream << outerRect1.left << " " << outerRect1.bottom << " m\n"
651              << outerRect1.left << " " << outerRect1.top << " l\n"
652              << outerRect1.right << " " << outerRect1.top << " l\n"
653              << outerRect1.right << " " << outerRect1.bottom << " l\n"
654              << outerRect2.right << " " << outerRect2.bottom << " l\n"
655              << outerRect2Middle << " " << outerRect2.top << " l\n"
656              << outerRect2.left << " " << outerRect2.bottom << " l\n"
657              << outerRect1.left << " " << outerRect1.bottom << " l\n";
658 
659   // Draw inner lines.
660   CFX_FloatRect lineRect = outerRect1;
661   const FX_FLOAT fXDelta = 2;
662   const FX_FLOAT fYDelta = (lineRect.top - lineRect.bottom) / 4;
663 
664   lineRect.left += fXDelta;
665   lineRect.right -= fXDelta;
666   for (int i = 0; i < 3; ++i) {
667     lineRect.top -= fYDelta;
668     sAppStream << lineRect.left << " " << lineRect.top << " m\n"
669                << lineRect.right << " " << lineRect.top << " l\n";
670   }
671   sAppStream << "B*\n";
672 
673   return sAppStream.MakeString();
674 }
675 
676 }  // namespace
677 
FPDF_GenerateAP(CPDF_Document * pDoc,CPDF_Dictionary * pAnnotDict)678 bool FPDF_GenerateAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict) {
679   if (!pAnnotDict || pAnnotDict->GetStringFor("Subtype") != "Widget")
680     return false;
681 
682   CPDF_Object* pFieldTypeObj = FPDF_GetFieldAttr(pAnnotDict, "FT");
683   if (!pFieldTypeObj)
684     return false;
685 
686   CFX_ByteString field_type = pFieldTypeObj->GetString();
687   if (field_type == "Tx")
688     return CPVT_GenerateAP::GenerateTextFieldAP(pDoc, pAnnotDict);
689 
690   CPDF_Object* pFieldFlagsObj = FPDF_GetFieldAttr(pAnnotDict, "Ff");
691   uint32_t flags = pFieldFlagsObj ? pFieldFlagsObj->GetInteger() : 0;
692   if (field_type == "Ch") {
693     return (flags & (1 << 17))
694                ? CPVT_GenerateAP::GenerateComboBoxAP(pDoc, pAnnotDict)
695                : CPVT_GenerateAP::GenerateListBoxAP(pDoc, pAnnotDict);
696   }
697 
698   if (field_type == "Btn") {
699     if (!(flags & (1 << 16))) {
700       if (!pAnnotDict->KeyExist("AS")) {
701         if (CPDF_Dictionary* pParentDict = pAnnotDict->GetDictFor("Parent")) {
702           if (pParentDict->KeyExist("AS")) {
703             pAnnotDict->SetNewFor<CPDF_String>(
704                 "AS", pParentDict->GetStringFor("AS"), false);
705           }
706         }
707       }
708     }
709   }
710 
711   return false;
712 }
713 
714 // Static.
GenerateComboBoxAP(CPDF_Document * pDoc,CPDF_Dictionary * pAnnotDict)715 bool CPVT_GenerateAP::GenerateComboBoxAP(CPDF_Document* pDoc,
716                                          CPDF_Dictionary* pAnnotDict) {
717   return GenerateWidgetAP(pDoc, pAnnotDict, 1);
718 }
719 
720 // Static.
GenerateListBoxAP(CPDF_Document * pDoc,CPDF_Dictionary * pAnnotDict)721 bool CPVT_GenerateAP::GenerateListBoxAP(CPDF_Document* pDoc,
722                                         CPDF_Dictionary* pAnnotDict) {
723   return GenerateWidgetAP(pDoc, pAnnotDict, 2);
724 }
725 
726 // Static.
GenerateTextFieldAP(CPDF_Document * pDoc,CPDF_Dictionary * pAnnotDict)727 bool CPVT_GenerateAP::GenerateTextFieldAP(CPDF_Document* pDoc,
728                                           CPDF_Dictionary* pAnnotDict) {
729   return GenerateWidgetAP(pDoc, pAnnotDict, 0);
730 }
731 
GenerateCircleAP(CPDF_Document * pDoc,CPDF_Dictionary * pAnnotDict)732 bool CPVT_GenerateAP::GenerateCircleAP(CPDF_Document* pDoc,
733                                        CPDF_Dictionary* pAnnotDict) {
734   CFX_ByteTextBuf sAppStream;
735   CFX_ByteString sExtGSDictName = "GS";
736   sAppStream << "/" << sExtGSDictName << " gs ";
737 
738   CPDF_Array* pInteriorColor = pAnnotDict->GetArrayFor("IC");
739   sAppStream << GetColorStringWithDefault(pInteriorColor,
740                                           CPVT_Color(CPVT_Color::kTransparent),
741                                           PaintOperation::FILL);
742 
743   sAppStream << GetColorStringWithDefault(pAnnotDict->GetArrayFor("C"),
744                                           CPVT_Color(CPVT_Color::kRGB, 0, 0, 0),
745                                           PaintOperation::STROKE);
746 
747   FX_FLOAT fBorderWidth = GetBorderWidth(*pAnnotDict);
748   bool bIsStrokeRect = fBorderWidth > 0;
749 
750   if (bIsStrokeRect) {
751     sAppStream << fBorderWidth << " w ";
752     sAppStream << GetDashPatternString(*pAnnotDict);
753   }
754 
755   CFX_FloatRect rect = pAnnotDict->GetRectFor("Rect");
756   rect.Normalize();
757 
758   if (bIsStrokeRect) {
759     // Deflating rect because stroking a path entails painting all points whose
760     // perpendicular distance from the path in user space is less than or equal
761     // to half the line width.
762     rect.Deflate(fBorderWidth / 2, fBorderWidth / 2);
763   }
764 
765   const FX_FLOAT fMiddleX = (rect.left + rect.right) / 2;
766   const FX_FLOAT fMiddleY = (rect.top + rect.bottom) / 2;
767 
768   // |fL| is precalculated approximate value of 4 * tan((3.14 / 2) / 4) / 3,
769   // where |fL| * radius is a good approximation of control points for
770   // arc with 90 degrees.
771   const FX_FLOAT fL = 0.5523f;
772   const FX_FLOAT fDeltaX = fL * rect.Width() / 2.0;
773   const FX_FLOAT fDeltaY = fL * rect.Height() / 2.0;
774 
775   // Starting point
776   sAppStream << fMiddleX << " " << rect.top << " m\n";
777   // First Bezier Curve
778   sAppStream << fMiddleX + fDeltaX << " " << rect.top << " " << rect.right
779              << " " << fMiddleY + fDeltaY << " " << rect.right << " "
780              << fMiddleY << " c\n";
781   // Second Bezier Curve
782   sAppStream << rect.right << " " << fMiddleY - fDeltaY << " "
783              << fMiddleX + fDeltaX << " " << rect.bottom << " " << fMiddleX
784              << " " << rect.bottom << " c\n";
785   // Third Bezier Curve
786   sAppStream << fMiddleX - fDeltaX << " " << rect.bottom << " " << rect.left
787              << " " << fMiddleY - fDeltaY << " " << rect.left << " " << fMiddleY
788              << " c\n";
789   // Fourth Bezier Curve
790   sAppStream << rect.left << " " << fMiddleY + fDeltaY << " "
791              << fMiddleX - fDeltaX << " " << rect.top << " " << fMiddleX << " "
792              << rect.top << " c\n";
793 
794   bool bIsFillRect = pInteriorColor && !pInteriorColor->IsEmpty();
795   sAppStream << GetPaintOperatorString(bIsStrokeRect, bIsFillRect) << "\n";
796 
797   auto pExtGStateDict =
798       GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal");
799   auto pResourceDict =
800       GenerateResourceDict(pDoc, std::move(pExtGStateDict), nullptr);
801   GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, std::move(pResourceDict),
802                        false /*IsTextMarkupAnnotation*/);
803   return true;
804 }
805 
GenerateHighlightAP(CPDF_Document * pDoc,CPDF_Dictionary * pAnnotDict)806 bool CPVT_GenerateAP::GenerateHighlightAP(CPDF_Document* pDoc,
807                                           CPDF_Dictionary* pAnnotDict) {
808   CFX_ByteTextBuf sAppStream;
809   CFX_ByteString sExtGSDictName = "GS";
810   sAppStream << "/" << sExtGSDictName << " gs ";
811 
812   sAppStream << GetColorStringWithDefault(pAnnotDict->GetArrayFor("C"),
813                                           CPVT_Color(CPVT_Color::kRGB, 1, 1, 0),
814                                           PaintOperation::FILL);
815 
816   CFX_FloatRect rect = CPDF_Annot::RectFromQuadPoints(pAnnotDict);
817   rect.Normalize();
818 
819   sAppStream << rect.left << " " << rect.top << " m " << rect.right << " "
820              << rect.top << " l " << rect.right << " " << rect.bottom << " l "
821              << rect.left << " " << rect.bottom << " l "
822              << "h f\n";
823 
824   auto pExtGStateDict =
825       GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Multiply");
826   auto pResourceDict =
827       GenerateResourceDict(pDoc, std::move(pExtGStateDict), nullptr);
828   GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, std::move(pResourceDict),
829                        true /*IsTextMarkupAnnotation*/);
830 
831   return true;
832 }
833 
GenerateInkAP(CPDF_Document * pDoc,CPDF_Dictionary * pAnnotDict)834 bool CPVT_GenerateAP::GenerateInkAP(CPDF_Document* pDoc,
835                                     CPDF_Dictionary* pAnnotDict) {
836   FX_FLOAT fBorderWidth = GetBorderWidth(*pAnnotDict);
837   bool bIsStroke = fBorderWidth > 0;
838 
839   if (!bIsStroke)
840     return false;
841 
842   CPDF_Array* pInkList = pAnnotDict->GetArrayFor("InkList");
843   if (!pInkList || pInkList->IsEmpty())
844     return false;
845 
846   CFX_ByteTextBuf sAppStream;
847   CFX_ByteString sExtGSDictName = "GS";
848   sAppStream << "/" << sExtGSDictName << " gs ";
849 
850   sAppStream << GetColorStringWithDefault(pAnnotDict->GetArrayFor("C"),
851                                           CPVT_Color(CPVT_Color::kRGB, 0, 0, 0),
852                                           PaintOperation::STROKE);
853 
854   sAppStream << fBorderWidth << " w ";
855   sAppStream << GetDashPatternString(*pAnnotDict);
856 
857   // Set inflated rect as a new rect because paths near the border with large
858   // width should not be clipped to the original rect.
859   CFX_FloatRect rect = pAnnotDict->GetRectFor("Rect");
860   rect.Inflate(fBorderWidth / 2, fBorderWidth / 2);
861   pAnnotDict->SetRectFor("Rect", rect);
862 
863   for (size_t i = 0; i < pInkList->GetCount(); i++) {
864     CPDF_Array* pInkCoordList = pInkList->GetArrayAt(i);
865     if (!pInkCoordList || pInkCoordList->GetCount() < 2)
866       continue;
867 
868     sAppStream << pInkCoordList->GetNumberAt(0) << " "
869                << pInkCoordList->GetNumberAt(1) << " m ";
870 
871     for (size_t j = 0; j < pInkCoordList->GetCount() - 1; j += 2) {
872       sAppStream << pInkCoordList->GetNumberAt(j) << " "
873                  << pInkCoordList->GetNumberAt(j + 1) << " l ";
874     }
875 
876     sAppStream << "S\n";
877   }
878 
879   auto pExtGStateDict =
880       GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal");
881   auto pResourceDict =
882       GenerateResourceDict(pDoc, std::move(pExtGStateDict), nullptr);
883   GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, std::move(pResourceDict),
884                        false /*IsTextMarkupAnnotation*/);
885   return true;
886 }
887 
GenerateTextAP(CPDF_Document * pDoc,CPDF_Dictionary * pAnnotDict)888 bool CPVT_GenerateAP::GenerateTextAP(CPDF_Document* pDoc,
889                                      CPDF_Dictionary* pAnnotDict) {
890   CFX_ByteTextBuf sAppStream;
891   CFX_ByteString sExtGSDictName = "GS";
892   sAppStream << "/" << sExtGSDictName << " gs ";
893 
894   CFX_FloatRect rect = pAnnotDict->GetRectFor("Rect");
895   const FX_FLOAT fNoteLength = 20;
896   CFX_FloatRect noteRect(rect.left, rect.bottom, rect.left + fNoteLength,
897                          rect.bottom + fNoteLength);
898   pAnnotDict->SetRectFor("Rect", noteRect);
899 
900   sAppStream << GenerateTextSymbolAP(noteRect);
901 
902   auto pExtGStateDict =
903       GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal");
904   auto pResourceDict =
905       GenerateResourceDict(pDoc, std::move(pExtGStateDict), nullptr);
906   GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, std::move(pResourceDict),
907                        false /*IsTextMarkupAnnotation*/);
908   return true;
909 }
910 
GenerateUnderlineAP(CPDF_Document * pDoc,CPDF_Dictionary * pAnnotDict)911 bool CPVT_GenerateAP::GenerateUnderlineAP(CPDF_Document* pDoc,
912                                           CPDF_Dictionary* pAnnotDict) {
913   CFX_ByteTextBuf sAppStream;
914   CFX_ByteString sExtGSDictName = "GS";
915   sAppStream << "/" << sExtGSDictName << " gs ";
916 
917   sAppStream << GetColorStringWithDefault(pAnnotDict->GetArrayFor("C"),
918                                           CPVT_Color(CPVT_Color::kRGB, 0, 0, 0),
919                                           PaintOperation::STROKE);
920 
921   CFX_FloatRect rect = CPDF_Annot::RectFromQuadPoints(pAnnotDict);
922   rect.Normalize();
923 
924   FX_FLOAT fLineWidth = 1.0;
925   sAppStream << fLineWidth << " w " << rect.left << " "
926              << rect.bottom + fLineWidth << " m " << rect.right << " "
927              << rect.bottom + fLineWidth << " l S\n";
928 
929   auto pExtGStateDict =
930       GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal");
931   auto pResourceDict =
932       GenerateResourceDict(pDoc, std::move(pExtGStateDict), nullptr);
933   GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, std::move(pResourceDict),
934                        true /*IsTextMarkupAnnotation*/);
935   return true;
936 }
937 
GeneratePopupAP(CPDF_Document * pDoc,CPDF_Dictionary * pAnnotDict)938 bool CPVT_GenerateAP::GeneratePopupAP(CPDF_Document* pDoc,
939                                       CPDF_Dictionary* pAnnotDict) {
940   CFX_ByteTextBuf sAppStream;
941   CFX_ByteString sExtGSDictName = "GS";
942   sAppStream << "/" << sExtGSDictName << " gs\n";
943 
944   sAppStream << GenerateColorAP(CPVT_Color(CPVT_Color::kRGB, 1, 1, 0),
945                                 PaintOperation::FILL);
946   sAppStream << GenerateColorAP(CPVT_Color(CPVT_Color::kRGB, 0, 0, 0),
947                                 PaintOperation::STROKE);
948 
949   const FX_FLOAT fBorderWidth = 1;
950   sAppStream << fBorderWidth << " w\n";
951 
952   CFX_FloatRect rect = pAnnotDict->GetRectFor("Rect");
953   rect.Normalize();
954   rect.Deflate(fBorderWidth / 2, fBorderWidth / 2);
955 
956   sAppStream << rect.left << " " << rect.bottom << " " << rect.Width() << " "
957              << rect.Height() << " re b\n";
958 
959   CFX_ByteString sFontName = "FONT";
960   auto pResourceFontDict = GenerateResourceFontDict(pDoc, sFontName);
961   CPDF_Font* pDefFont = pDoc->LoadFont(pResourceFontDict.get());
962   if (!pDefFont)
963     return false;
964 
965   auto pExtGStateDict =
966       GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal");
967   auto pResourceDict = GenerateResourceDict(pDoc, std::move(pResourceFontDict),
968                                             std::move(pExtGStateDict));
969 
970   sAppStream << GetPopupContentsString(pDoc, *pAnnotDict, pDefFont, sFontName);
971   GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, std::move(pResourceDict),
972                        false /*IsTextMarkupAnnotation*/);
973   return true;
974 }
975 
GenerateSquareAP(CPDF_Document * pDoc,CPDF_Dictionary * pAnnotDict)976 bool CPVT_GenerateAP::GenerateSquareAP(CPDF_Document* pDoc,
977                                        CPDF_Dictionary* pAnnotDict) {
978   CFX_ByteTextBuf sAppStream;
979   CFX_ByteString sExtGSDictName = "GS";
980   sAppStream << "/" << sExtGSDictName << " gs ";
981 
982   CPDF_Array* pInteriorColor = pAnnotDict->GetArrayFor("IC");
983   sAppStream << GetColorStringWithDefault(pInteriorColor,
984                                           CPVT_Color(CPVT_Color::kTransparent),
985                                           PaintOperation::FILL);
986 
987   sAppStream << GetColorStringWithDefault(pAnnotDict->GetArrayFor("C"),
988                                           CPVT_Color(CPVT_Color::kRGB, 0, 0, 0),
989                                           PaintOperation::STROKE);
990 
991   FX_FLOAT fBorderWidth = GetBorderWidth(*pAnnotDict);
992   bool bIsStrokeRect = fBorderWidth > 0;
993 
994   if (bIsStrokeRect) {
995     sAppStream << fBorderWidth << " w ";
996     sAppStream << GetDashPatternString(*pAnnotDict);
997   }
998 
999   CFX_FloatRect rect = pAnnotDict->GetRectFor("Rect");
1000   rect.Normalize();
1001 
1002   if (bIsStrokeRect) {
1003     // Deflating rect because stroking a path entails painting all points whose
1004     // perpendicular distance from the path in user space is less than or equal
1005     // to half the line width.
1006     rect.Deflate(fBorderWidth / 2, fBorderWidth / 2);
1007   }
1008 
1009   bool bIsFillRect = pInteriorColor && (pInteriorColor->GetCount() > 0);
1010 
1011   sAppStream << rect.left << " " << rect.bottom << " " << rect.Width() << " "
1012              << rect.Height() << " re "
1013              << GetPaintOperatorString(bIsStrokeRect, bIsFillRect) << "\n";
1014 
1015   auto pExtGStateDict =
1016       GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal");
1017   auto pResourceDict =
1018       GenerateResourceDict(pDoc, std::move(pExtGStateDict), nullptr);
1019   GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, std::move(pResourceDict),
1020                        false /*IsTextMarkupAnnotation*/);
1021   return true;
1022 }
1023 
GenerateSquigglyAP(CPDF_Document * pDoc,CPDF_Dictionary * pAnnotDict)1024 bool CPVT_GenerateAP::GenerateSquigglyAP(CPDF_Document* pDoc,
1025                                          CPDF_Dictionary* pAnnotDict) {
1026   CFX_ByteTextBuf sAppStream;
1027   CFX_ByteString sExtGSDictName = "GS";
1028   sAppStream << "/" << sExtGSDictName << " gs ";
1029 
1030   sAppStream << GetColorStringWithDefault(pAnnotDict->GetArrayFor("C"),
1031                                           CPVT_Color(CPVT_Color::kRGB, 0, 0, 0),
1032                                           PaintOperation::STROKE);
1033 
1034   CFX_FloatRect rect = CPDF_Annot::RectFromQuadPoints(pAnnotDict);
1035   rect.Normalize();
1036 
1037   FX_FLOAT fLineWidth = 1.0;
1038   sAppStream << fLineWidth << " w ";
1039 
1040   const FX_FLOAT fDelta = 2.0;
1041   const FX_FLOAT fTop = rect.bottom + fDelta;
1042   const FX_FLOAT fBottom = rect.bottom;
1043 
1044   sAppStream << rect.left << " " << fTop << " m ";
1045 
1046   FX_FLOAT fX = rect.left + fDelta;
1047   bool isUpwards = false;
1048 
1049   while (fX < rect.right) {
1050     sAppStream << fX << " " << (isUpwards ? fTop : fBottom) << " l ";
1051 
1052     fX += fDelta;
1053     isUpwards = !isUpwards;
1054   }
1055 
1056   FX_FLOAT fRemainder = rect.right - (fX - fDelta);
1057   if (isUpwards)
1058     sAppStream << rect.right << " " << fBottom + fRemainder << " l ";
1059   else
1060     sAppStream << rect.right << " " << fTop - fRemainder << " l ";
1061 
1062   sAppStream << "S\n";
1063 
1064   auto pExtGStateDict =
1065       GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal");
1066   auto pResourceDict =
1067       GenerateResourceDict(pDoc, std::move(pExtGStateDict), nullptr);
1068   GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, std::move(pResourceDict),
1069                        true /*IsTextMarkupAnnotation*/);
1070   return true;
1071 }
1072 
GenerateStrikeOutAP(CPDF_Document * pDoc,CPDF_Dictionary * pAnnotDict)1073 bool CPVT_GenerateAP::GenerateStrikeOutAP(CPDF_Document* pDoc,
1074                                           CPDF_Dictionary* pAnnotDict) {
1075   CFX_ByteTextBuf sAppStream;
1076   CFX_ByteString sExtGSDictName = "GS";
1077   sAppStream << "/" << sExtGSDictName << " gs ";
1078 
1079   sAppStream << GetColorStringWithDefault(pAnnotDict->GetArrayFor("C"),
1080                                           CPVT_Color(CPVT_Color::kRGB, 0, 0, 0),
1081                                           PaintOperation::STROKE);
1082 
1083   CFX_FloatRect rect = CPDF_Annot::RectFromQuadPoints(pAnnotDict);
1084   rect.Normalize();
1085 
1086   FX_FLOAT fLineWidth = 1.0;
1087   FX_FLOAT fY = (rect.top + rect.bottom) / 2;
1088   sAppStream << fLineWidth << " w " << rect.left << " " << fY << " m "
1089              << rect.right << " " << fY << " l S\n";
1090 
1091   auto pExtGStateDict =
1092       GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal");
1093   auto pResourceDict =
1094       GenerateResourceDict(pDoc, std::move(pExtGStateDict), nullptr);
1095   GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, std::move(pResourceDict),
1096                        true /*IsTextMarkupAnnotation*/);
1097   return true;
1098 }
1099 
1100 // Static.
GenerateEditAP(IPVT_FontMap * pFontMap,CPDF_VariableText::Iterator * pIterator,const CFX_PointF & ptOffset,bool bContinuous,uint16_t SubWord)1101 CFX_ByteString CPVT_GenerateAP::GenerateEditAP(
1102     IPVT_FontMap* pFontMap,
1103     CPDF_VariableText::Iterator* pIterator,
1104     const CFX_PointF& ptOffset,
1105     bool bContinuous,
1106     uint16_t SubWord) {
1107   CFX_ByteTextBuf sEditStream;
1108   CFX_ByteTextBuf sLineStream;
1109   CFX_ByteTextBuf sWords;
1110   CFX_PointF ptOld;
1111   CFX_PointF ptNew;
1112   int32_t nCurFontIndex = -1;
1113   CPVT_WordPlace oldplace;
1114 
1115   pIterator->SetAt(0);
1116   while (pIterator->NextWord()) {
1117     CPVT_WordPlace place = pIterator->GetAt();
1118     if (bContinuous) {
1119       if (place.LineCmp(oldplace) != 0) {
1120         if (sWords.GetSize() > 0) {
1121           sLineStream << GetWordRenderString(sWords.MakeString());
1122           sEditStream << sLineStream;
1123           sLineStream.Clear();
1124           sWords.Clear();
1125         }
1126         CPVT_Word word;
1127         if (pIterator->GetWord(word)) {
1128           ptNew = CFX_PointF(word.ptWord.x + ptOffset.x,
1129                              word.ptWord.y + ptOffset.y);
1130         } else {
1131           CPVT_Line line;
1132           pIterator->GetLine(line);
1133           ptNew = CFX_PointF(line.ptLine.x + ptOffset.x,
1134                              line.ptLine.y + ptOffset.y);
1135         }
1136         if (ptNew != ptOld) {
1137           sLineStream << ptNew.x - ptOld.x << " " << ptNew.y - ptOld.y
1138                       << " Td\n";
1139           ptOld = ptNew;
1140         }
1141       }
1142       CPVT_Word word;
1143       if (pIterator->GetWord(word)) {
1144         if (word.nFontIndex != nCurFontIndex) {
1145           if (sWords.GetSize() > 0) {
1146             sLineStream << GetWordRenderString(sWords.MakeString());
1147             sWords.Clear();
1148           }
1149           sLineStream << GetFontSetString(pFontMap, word.nFontIndex,
1150                                           word.fFontSize);
1151           nCurFontIndex = word.nFontIndex;
1152         }
1153         sWords << GetPDFWordString(pFontMap, nCurFontIndex, word.Word, SubWord);
1154       }
1155       oldplace = place;
1156     } else {
1157       CPVT_Word word;
1158       if (pIterator->GetWord(word)) {
1159         ptNew =
1160             CFX_PointF(word.ptWord.x + ptOffset.x, word.ptWord.y + ptOffset.y);
1161         if (ptNew != ptOld) {
1162           sEditStream << ptNew.x - ptOld.x << " " << ptNew.y - ptOld.y
1163                       << " Td\n";
1164           ptOld = ptNew;
1165         }
1166         if (word.nFontIndex != nCurFontIndex) {
1167           sEditStream << GetFontSetString(pFontMap, word.nFontIndex,
1168                                           word.fFontSize);
1169           nCurFontIndex = word.nFontIndex;
1170         }
1171         sEditStream << GetWordRenderString(
1172             GetPDFWordString(pFontMap, nCurFontIndex, word.Word, SubWord));
1173       }
1174     }
1175   }
1176   if (sWords.GetSize() > 0) {
1177     sLineStream << GetWordRenderString(sWords.MakeString());
1178     sEditStream << sLineStream;
1179     sWords.Clear();
1180   }
1181   return sEditStream.MakeString();
1182 }
1183 
1184 // Static.
GenerateBorderAP(const CFX_FloatRect & rect,FX_FLOAT fWidth,const CPVT_Color & color,const CPVT_Color & crLeftTop,const CPVT_Color & crRightBottom,BorderStyle nStyle,const CPVT_Dash & dash)1185 CFX_ByteString CPVT_GenerateAP::GenerateBorderAP(
1186     const CFX_FloatRect& rect,
1187     FX_FLOAT fWidth,
1188     const CPVT_Color& color,
1189     const CPVT_Color& crLeftTop,
1190     const CPVT_Color& crRightBottom,
1191     BorderStyle nStyle,
1192     const CPVT_Dash& dash) {
1193   CFX_ByteTextBuf sAppStream;
1194   CFX_ByteString sColor;
1195   FX_FLOAT fLeft = rect.left;
1196   FX_FLOAT fRight = rect.right;
1197   FX_FLOAT fTop = rect.top;
1198   FX_FLOAT fBottom = rect.bottom;
1199   if (fWidth > 0.0f) {
1200     FX_FLOAT fHalfWidth = fWidth / 2.0f;
1201     switch (nStyle) {
1202       default:
1203       case BorderStyle::SOLID:
1204         sColor = GenerateColorAP(color, PaintOperation::FILL);
1205         if (sColor.GetLength() > 0) {
1206           sAppStream << sColor;
1207           sAppStream << fLeft << " " << fBottom << " " << fRight - fLeft << " "
1208                      << fTop - fBottom << " re\n";
1209           sAppStream << fLeft + fWidth << " " << fBottom + fWidth << " "
1210                      << fRight - fLeft - fWidth * 2 << " "
1211                      << fTop - fBottom - fWidth * 2 << " re\n";
1212           sAppStream << "f*\n";
1213         }
1214         break;
1215       case BorderStyle::DASH:
1216         sColor = GenerateColorAP(color, PaintOperation::STROKE);
1217         if (sColor.GetLength() > 0) {
1218           sAppStream << sColor;
1219           sAppStream << fWidth << " w"
1220                      << " [" << dash.nDash << " " << dash.nGap << "] "
1221                      << dash.nPhase << " d\n";
1222           sAppStream << fLeft + fWidth / 2 << " " << fBottom + fWidth / 2
1223                      << " m\n";
1224           sAppStream << fLeft + fWidth / 2 << " " << fTop - fWidth / 2
1225                      << " l\n";
1226           sAppStream << fRight - fWidth / 2 << " " << fTop - fWidth / 2
1227                      << " l\n";
1228           sAppStream << fRight - fWidth / 2 << " " << fBottom + fWidth / 2
1229                      << " l\n";
1230           sAppStream << fLeft + fWidth / 2 << " " << fBottom + fWidth / 2
1231                      << " l S\n";
1232         }
1233         break;
1234       case BorderStyle::BEVELED:
1235       case BorderStyle::INSET:
1236         sColor = GenerateColorAP(crLeftTop, PaintOperation::FILL);
1237         if (sColor.GetLength() > 0) {
1238           sAppStream << sColor;
1239           sAppStream << fLeft + fHalfWidth << " " << fBottom + fHalfWidth
1240                      << " m\n";
1241           sAppStream << fLeft + fHalfWidth << " " << fTop - fHalfWidth
1242                      << " l\n";
1243           sAppStream << fRight - fHalfWidth << " " << fTop - fHalfWidth
1244                      << " l\n";
1245           sAppStream << fRight - fHalfWidth * 2 << " " << fTop - fHalfWidth * 2
1246                      << " l\n";
1247           sAppStream << fLeft + fHalfWidth * 2 << " " << fTop - fHalfWidth * 2
1248                      << " l\n";
1249           sAppStream << fLeft + fHalfWidth * 2 << " "
1250                      << fBottom + fHalfWidth * 2 << " l f\n";
1251         }
1252         sColor = GenerateColorAP(crRightBottom, PaintOperation::FILL);
1253         if (sColor.GetLength() > 0) {
1254           sAppStream << sColor;
1255           sAppStream << fRight - fHalfWidth << " " << fTop - fHalfWidth
1256                      << " m\n";
1257           sAppStream << fRight - fHalfWidth << " " << fBottom + fHalfWidth
1258                      << " l\n";
1259           sAppStream << fLeft + fHalfWidth << " " << fBottom + fHalfWidth
1260                      << " l\n";
1261           sAppStream << fLeft + fHalfWidth * 2 << " "
1262                      << fBottom + fHalfWidth * 2 << " l\n";
1263           sAppStream << fRight - fHalfWidth * 2 << " "
1264                      << fBottom + fHalfWidth * 2 << " l\n";
1265           sAppStream << fRight - fHalfWidth * 2 << " " << fTop - fHalfWidth * 2
1266                      << " l f\n";
1267         }
1268         sColor = GenerateColorAP(color, PaintOperation::FILL);
1269         if (sColor.GetLength() > 0) {
1270           sAppStream << sColor;
1271           sAppStream << fLeft << " " << fBottom << " " << fRight - fLeft << " "
1272                      << fTop - fBottom << " re\n";
1273           sAppStream << fLeft + fHalfWidth << " " << fBottom + fHalfWidth << " "
1274                      << fRight - fLeft - fHalfWidth * 2 << " "
1275                      << fTop - fBottom - fHalfWidth * 2 << " re f*\n";
1276         }
1277         break;
1278       case BorderStyle::UNDERLINE:
1279         sColor = GenerateColorAP(color, PaintOperation::STROKE);
1280         if (sColor.GetLength() > 0) {
1281           sAppStream << sColor;
1282           sAppStream << fWidth << " w\n";
1283           sAppStream << fLeft << " " << fBottom + fWidth / 2 << " m\n";
1284           sAppStream << fRight << " " << fBottom + fWidth / 2 << " l S\n";
1285         }
1286         break;
1287     }
1288   }
1289   return sAppStream.MakeString();
1290 }
1291 
1292 // Static.
GenerateColorAP(const CPVT_Color & color,PaintOperation nOperation)1293 CFX_ByteString CPVT_GenerateAP::GenerateColorAP(const CPVT_Color& color,
1294                                                 PaintOperation nOperation) {
1295   CFX_ByteTextBuf sColorStream;
1296   switch (color.nColorType) {
1297     case CPVT_Color::kRGB:
1298       sColorStream << color.fColor1 << " " << color.fColor2 << " "
1299                    << color.fColor3 << " "
1300                    << (nOperation == PaintOperation::STROKE ? "RG" : "rg")
1301                    << "\n";
1302       break;
1303     case CPVT_Color::kGray:
1304       sColorStream << color.fColor1 << " "
1305                    << (nOperation == PaintOperation::STROKE ? "G" : "g")
1306                    << "\n";
1307       break;
1308     case CPVT_Color::kCMYK:
1309       sColorStream << color.fColor1 << " " << color.fColor2 << " "
1310                    << color.fColor3 << " " << color.fColor4 << " "
1311                    << (nOperation == PaintOperation::STROKE ? "K" : "k")
1312                    << "\n";
1313       break;
1314     case CPVT_Color::kTransparent:
1315       break;
1316   }
1317   return sColorStream.MakeString();
1318 }
1319 
1320 // Static.
GetPDFWordString(IPVT_FontMap * pFontMap,int32_t nFontIndex,uint16_t Word,uint16_t SubWord)1321 CFX_ByteString CPVT_GenerateAP::GetPDFWordString(IPVT_FontMap* pFontMap,
1322                                                  int32_t nFontIndex,
1323                                                  uint16_t Word,
1324                                                  uint16_t SubWord) {
1325   CFX_ByteString sWord;
1326   if (SubWord > 0) {
1327     sWord.Format("%c", SubWord);
1328     return sWord;
1329   }
1330 
1331   if (!pFontMap)
1332     return sWord;
1333 
1334   if (CPDF_Font* pPDFFont = pFontMap->GetPDFFont(nFontIndex)) {
1335     if (pPDFFont->GetBaseFont().Compare("Symbol") == 0 ||
1336         pPDFFont->GetBaseFont().Compare("ZapfDingbats") == 0) {
1337       sWord.Format("%c", Word);
1338     } else {
1339       uint32_t dwCharCode = pPDFFont->CharCodeFromUnicode(Word);
1340       if (dwCharCode != CPDF_Font::kInvalidCharCode)
1341         pPDFFont->AppendChar(sWord, dwCharCode);
1342     }
1343   }
1344   return sWord;
1345 }
1346 
1347 // Static.
GetWordRenderString(const CFX_ByteString & strWords)1348 CFX_ByteString CPVT_GenerateAP::GetWordRenderString(
1349     const CFX_ByteString& strWords) {
1350   if (strWords.GetLength() > 0)
1351     return PDF_EncodeString(strWords) + " Tj\n";
1352   return "";
1353 }
1354 
1355 // Static.
GetFontSetString(IPVT_FontMap * pFontMap,int32_t nFontIndex,FX_FLOAT fFontSize)1356 CFX_ByteString CPVT_GenerateAP::GetFontSetString(IPVT_FontMap* pFontMap,
1357                                                  int32_t nFontIndex,
1358                                                  FX_FLOAT fFontSize) {
1359   CFX_ByteTextBuf sRet;
1360   if (pFontMap) {
1361     CFX_ByteString sFontAlias = pFontMap->GetPDFFontAlias(nFontIndex);
1362     if (sFontAlias.GetLength() > 0 && fFontSize > 0)
1363       sRet << "/" << sFontAlias << " " << fFontSize << " Tf\n";
1364   }
1365   return sRet.MakeString();
1366 }
1367