1 // Copyright 2014 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/include/fpdfdoc/fpdf_ap.h"
8 #include "core/include/fpdfdoc/fpdf_doc.h"
9 #include "core/include/fpdfdoc/fpdf_vt.h"
10 #include "doc_utils.h"
11 #include "pdf_vt.h"
12 
FPDF_GenerateAP(CPDF_Document * pDoc,CPDF_Dictionary * pAnnotDict)13 FX_BOOL FPDF_GenerateAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict) {
14   if (!pAnnotDict || pAnnotDict->GetConstString("Subtype") != "Widget") {
15     return FALSE;
16   }
17   CFX_ByteString field_type = FPDF_GetFieldAttr(pAnnotDict, "FT")->GetString();
18   FX_DWORD flags = FPDF_GetFieldAttr(pAnnotDict, "Ff")
19                        ? FPDF_GetFieldAttr(pAnnotDict, "Ff")->GetInteger()
20                        : 0;
21   if (field_type == "Tx") {
22     return CPVT_GenerateAP::GenerateTextFieldAP(pDoc, pAnnotDict);
23   }
24   if (field_type == "Ch") {
25     return (flags & (1 << 17))
26                ? CPVT_GenerateAP::GenerateComboBoxAP(pDoc, pAnnotDict)
27                : CPVT_GenerateAP::GenerateListBoxAP(pDoc, pAnnotDict);
28   }
29   if (field_type == "Btn") {
30     if (!(flags & (1 << 16))) {
31       if (!pAnnotDict->KeyExist("AS")) {
32         if (CPDF_Dictionary* pParentDict = pAnnotDict->GetDict("Parent")) {
33           if (pParentDict->KeyExist("AS")) {
34             pAnnotDict->SetAtString("AS", pParentDict->GetString("AS"));
35           }
36         }
37       }
38     }
39   }
40   return FALSE;
41 }
42 
43 class CPVT_FontMap : public IPVT_FontMap {
44  public:
45   CPVT_FontMap(CPDF_Document* pDoc,
46                CPDF_Dictionary* pResDict,
47                CPDF_Font* pDefFont,
48                const CFX_ByteString& sDefFontAlias);
49   ~CPVT_FontMap() override;
50 
51   // IPVT_FontMap
52   CPDF_Font* GetPDFFont(int32_t nFontIndex) override;
53   CFX_ByteString GetPDFFontAlias(int32_t nFontIndex) override;
54 
55   static void GetAnnotSysPDFFont(CPDF_Document* pDoc,
56                                  CPDF_Dictionary* pResDict,
57                                  CPDF_Font*& pSysFont,
58                                  CFX_ByteString& sSysFontAlias);
59 
60  private:
61   CPDF_Document* m_pDocument;
62   CPDF_Dictionary* m_pResDict;
63   CPDF_Font* m_pDefFont;
64   CFX_ByteString m_sDefFontAlias;
65   CPDF_Font* m_pSysFont;
66   CFX_ByteString m_sSysFontAlias;
67 };
68 
CPVT_FontMap(CPDF_Document * pDoc,CPDF_Dictionary * pResDict,CPDF_Font * pDefFont,const CFX_ByteString & sDefFontAlias)69 CPVT_FontMap::CPVT_FontMap(CPDF_Document* pDoc,
70                            CPDF_Dictionary* pResDict,
71                            CPDF_Font* pDefFont,
72                            const CFX_ByteString& sDefFontAlias)
73     : m_pDocument(pDoc),
74       m_pResDict(pResDict),
75       m_pDefFont(pDefFont),
76       m_sDefFontAlias(sDefFontAlias),
77       m_pSysFont(NULL),
78       m_sSysFontAlias() {}
~CPVT_FontMap()79 CPVT_FontMap::~CPVT_FontMap() {}
GetAnnotSysPDFFont(CPDF_Document * pDoc,CPDF_Dictionary * pResDict,CPDF_Font * & pSysFont,CFX_ByteString & sSysFontAlias)80 void CPVT_FontMap::GetAnnotSysPDFFont(CPDF_Document* pDoc,
81                                       CPDF_Dictionary* pResDict,
82                                       CPDF_Font*& pSysFont,
83                                       CFX_ByteString& sSysFontAlias) {
84   if (pDoc && pResDict) {
85     CFX_ByteString sFontAlias;
86     CPDF_Dictionary* pFormDict = pDoc->GetRoot()->GetDict("AcroForm");
87     if (CPDF_Font* pPDFFont =
88             AddNativeInterFormFont(pFormDict, pDoc, sSysFontAlias)) {
89       if (CPDF_Dictionary* pFontList = pResDict->GetDict("Font")) {
90         if (!pFontList->KeyExist(sSysFontAlias)) {
91           pFontList->SetAtReference(sSysFontAlias, pDoc,
92                                     pPDFFont->GetFontDict());
93         }
94       }
95       pSysFont = pPDFFont;
96     }
97   }
98 }
GetPDFFont(int32_t nFontIndex)99 CPDF_Font* CPVT_FontMap::GetPDFFont(int32_t nFontIndex) {
100   switch (nFontIndex) {
101     case 0:
102       return m_pDefFont;
103     case 1:
104       if (!m_pSysFont) {
105         GetAnnotSysPDFFont(m_pDocument, m_pResDict, m_pSysFont,
106                            m_sSysFontAlias);
107       }
108       return m_pSysFont;
109   }
110   return NULL;
111 }
GetPDFFontAlias(int32_t nFontIndex)112 CFX_ByteString CPVT_FontMap::GetPDFFontAlias(int32_t nFontIndex) {
113   switch (nFontIndex) {
114     case 0:
115       return m_sDefFontAlias;
116     case 1:
117       if (!m_pSysFont) {
118         GetAnnotSysPDFFont(m_pDocument, m_pResDict, m_pSysFont,
119                            m_sSysFontAlias);
120       }
121       return m_sSysFontAlias;
122   }
123   return "";
124 }
CPVT_Provider(IPVT_FontMap * pFontMap)125 CPVT_Provider::CPVT_Provider(IPVT_FontMap* pFontMap) : m_pFontMap(pFontMap) {
126   ASSERT(m_pFontMap);
127 }
~CPVT_Provider()128 CPVT_Provider::~CPVT_Provider() {}
GetCharWidth(int32_t nFontIndex,FX_WORD word,int32_t nWordStyle)129 int32_t CPVT_Provider::GetCharWidth(int32_t nFontIndex,
130                                     FX_WORD word,
131                                     int32_t nWordStyle) {
132   if (CPDF_Font* pPDFFont = m_pFontMap->GetPDFFont(nFontIndex)) {
133     FX_DWORD charcode = pPDFFont->CharCodeFromUnicode(word);
134     if (charcode != CPDF_Font::kInvalidCharCode) {
135       return pPDFFont->GetCharWidthF(charcode);
136     }
137   }
138   return 0;
139 }
GetTypeAscent(int32_t nFontIndex)140 int32_t CPVT_Provider::GetTypeAscent(int32_t nFontIndex) {
141   if (CPDF_Font* pPDFFont = m_pFontMap->GetPDFFont(nFontIndex)) {
142     return pPDFFont->GetTypeAscent();
143   }
144   return 0;
145 }
GetTypeDescent(int32_t nFontIndex)146 int32_t CPVT_Provider::GetTypeDescent(int32_t nFontIndex) {
147   if (CPDF_Font* pPDFFont = m_pFontMap->GetPDFFont(nFontIndex)) {
148     return pPDFFont->GetTypeDescent();
149   }
150   return 0;
151 }
GetWordFontIndex(FX_WORD word,int32_t charset,int32_t nFontIndex)152 int32_t CPVT_Provider::GetWordFontIndex(FX_WORD word,
153                                         int32_t charset,
154                                         int32_t nFontIndex) {
155   if (CPDF_Font* pDefFont = m_pFontMap->GetPDFFont(0)) {
156     if (pDefFont->CharCodeFromUnicode(word) != CPDF_Font::kInvalidCharCode) {
157       return 0;
158     }
159   }
160   if (CPDF_Font* pSysFont = m_pFontMap->GetPDFFont(1)) {
161     if (pSysFont->CharCodeFromUnicode(word) != CPDF_Font::kInvalidCharCode) {
162       return 1;
163     }
164   }
165   return -1;
166 }
IsLatinWord(FX_WORD word)167 FX_BOOL CPVT_Provider::IsLatinWord(FX_WORD word) {
168   if ((word >= 0x61 && word <= 0x7A) || (word >= 0x41 && word <= 0x5A) ||
169       word == 0x2D || word == 0x27) {
170     return TRUE;
171   }
172   return FALSE;
173 }
GetDefaultFontIndex()174 int32_t CPVT_Provider::GetDefaultFontIndex() {
175   return 0;
176 }
177 
GetPDFWordString(IPVT_FontMap * pFontMap,int32_t nFontIndex,FX_WORD Word,FX_WORD SubWord)178 static CFX_ByteString GetPDFWordString(IPVT_FontMap* pFontMap,
179                                        int32_t nFontIndex,
180                                        FX_WORD Word,
181                                        FX_WORD SubWord) {
182   CFX_ByteString sWord;
183   if (SubWord > 0) {
184     sWord.Format("%c", SubWord);
185     return sWord;
186   }
187 
188   if (!pFontMap)
189     return sWord;
190 
191   if (CPDF_Font* pPDFFont = pFontMap->GetPDFFont(nFontIndex)) {
192     if (pPDFFont->GetBaseFont().Compare("Symbol") == 0 ||
193         pPDFFont->GetBaseFont().Compare("ZapfDingbats") == 0) {
194       sWord.Format("%c", Word);
195     } else {
196       FX_DWORD dwCharCode = pPDFFont->CharCodeFromUnicode(Word);
197       if (dwCharCode != CPDF_Font::kInvalidCharCode) {
198         pPDFFont->AppendChar(sWord, dwCharCode);
199       }
200     }
201   }
202   return sWord;
203 }
204 
GetWordRenderString(const CFX_ByteString & strWords)205 static CFX_ByteString GetWordRenderString(const CFX_ByteString& strWords) {
206   if (strWords.GetLength() > 0) {
207     return PDF_EncodeString(strWords) + " Tj\n";
208   }
209   return "";
210 }
GetFontSetString(IPVT_FontMap * pFontMap,int32_t nFontIndex,FX_FLOAT fFontSize)211 static CFX_ByteString GetFontSetString(IPVT_FontMap* pFontMap,
212                                        int32_t nFontIndex,
213                                        FX_FLOAT fFontSize) {
214   CFX_ByteTextBuf sRet;
215   if (pFontMap) {
216     CFX_ByteString sFontAlias = pFontMap->GetPDFFontAlias(nFontIndex);
217     if (sFontAlias.GetLength() > 0 && fFontSize > 0) {
218       sRet << "/" << sFontAlias << " " << fFontSize << " Tf\n";
219     }
220   }
221   return sRet.GetByteString();
222 }
ParseColor(const CFX_ByteString & str)223 static CPVT_Color ParseColor(const CFX_ByteString& str) {
224   CPDF_SimpleParser syntax(str);
225   syntax.SetPos(0);
226   if (syntax.FindTagParam("g", 1)) {
227     return CPVT_Color(CT_GRAY, FX_atof(syntax.GetWord()));
228   }
229   syntax.SetPos(0);
230   if (syntax.FindTagParam("rg", 3)) {
231     FX_FLOAT f1 = FX_atof(syntax.GetWord());
232     FX_FLOAT f2 = FX_atof(syntax.GetWord());
233     FX_FLOAT f3 = FX_atof(syntax.GetWord());
234     return CPVT_Color(CT_RGB, f1, f2, f3);
235   }
236   syntax.SetPos(0);
237   if (syntax.FindTagParam("k", 4)) {
238     FX_FLOAT f1 = FX_atof(syntax.GetWord());
239     FX_FLOAT f2 = FX_atof(syntax.GetWord());
240     FX_FLOAT f3 = FX_atof(syntax.GetWord());
241     FX_FLOAT f4 = FX_atof(syntax.GetWord());
242     return CPVT_Color(CT_CMYK, f1, f2, f3, f4);
243   }
244   return CPVT_Color(CT_TRANSPARENT);
245 }
ParseColor(const CPDF_Array & array)246 static CPVT_Color ParseColor(const CPDF_Array& array) {
247   CPVT_Color rt;
248   switch (array.GetCount()) {
249     case 1:
250       rt = CPVT_Color(CT_GRAY, array.GetFloat(0));
251       break;
252     case 3:
253       rt = CPVT_Color(CT_RGB, array.GetFloat(0), array.GetFloat(1),
254                       array.GetFloat(2));
255       break;
256     case 4:
257       rt = CPVT_Color(CT_CMYK, array.GetFloat(0), array.GetFloat(1),
258                       array.GetFloat(2), array.GetFloat(3));
259       break;
260   }
261   return rt;
262 }
GenerateWidgetAP(CPDF_Document * pDoc,CPDF_Dictionary * pAnnotDict,const int32_t & nWidgetType)263 static FX_BOOL GenerateWidgetAP(CPDF_Document* pDoc,
264                                 CPDF_Dictionary* pAnnotDict,
265                                 const int32_t& nWidgetType) {
266   CPDF_Dictionary* pFormDict = NULL;
267   if (CPDF_Dictionary* pRootDict = pDoc->GetRoot()) {
268     pFormDict = pRootDict->GetDict("AcroForm");
269   }
270   if (!pFormDict) {
271     return FALSE;
272   }
273   CFX_ByteString DA;
274   if (CPDF_Object* pDAObj = FPDF_GetFieldAttr(pAnnotDict, "DA")) {
275     DA = pDAObj->GetString();
276   }
277   if (DA.IsEmpty()) {
278     DA = pFormDict->GetString("DA");
279   }
280   if (DA.IsEmpty()) {
281     return FALSE;
282   }
283   CPDF_SimpleParser syntax(DA);
284   syntax.FindTagParam("Tf", 2);
285   CFX_ByteString sFontName = syntax.GetWord();
286   sFontName = PDF_NameDecode(sFontName);
287   if (sFontName.IsEmpty()) {
288     return FALSE;
289   }
290   FX_FLOAT fFontSize = FX_atof(syntax.GetWord());
291   CPVT_Color crText = ParseColor(DA);
292   FX_BOOL bUseFormRes = FALSE;
293   CPDF_Dictionary* pFontDict = NULL;
294   CPDF_Dictionary* pDRDict = pAnnotDict->GetDict("DR");
295   if (!pDRDict) {
296     pDRDict = pFormDict->GetDict("DR");
297     bUseFormRes = TRUE;
298   }
299   CPDF_Dictionary* pDRFontDict = NULL;
300   if (pDRDict && (pDRFontDict = pDRDict->GetDict("Font"))) {
301     pFontDict = pDRFontDict->GetDict(sFontName.Mid(1));
302     if (!pFontDict && !bUseFormRes) {
303       pDRDict = pFormDict->GetDict("DR");
304       pDRFontDict = pDRDict->GetDict("Font");
305       if (pDRFontDict) {
306         pFontDict = pDRFontDict->GetDict(sFontName.Mid(1));
307       }
308     }
309   }
310   if (!pDRFontDict) {
311     return FALSE;
312   }
313   if (!pFontDict) {
314     pFontDict = new CPDF_Dictionary;
315     pFontDict->SetAtName("Type", "Font");
316     pFontDict->SetAtName("Subtype", "Type1");
317     pFontDict->SetAtName("BaseFont", "Helvetica");
318     pFontDict->SetAtName("Encoding", "WinAnsiEncoding");
319     pDoc->AddIndirectObject(pFontDict);
320     pDRFontDict->SetAtReference(sFontName.Mid(1), pDoc, pFontDict);
321   }
322   CPDF_Font* pDefFont = pDoc->LoadFont(pFontDict);
323   if (!pDefFont) {
324     return FALSE;
325   }
326   CPDF_Rect rcAnnot = pAnnotDict->GetRect("Rect");
327   int32_t nRotate = 0;
328   if (CPDF_Dictionary* pMKDict = pAnnotDict->GetDict("MK")) {
329     nRotate = pMKDict->GetInteger("R");
330   }
331   CPDF_Rect rcBBox;
332   CFX_Matrix matrix;
333   switch (nRotate % 360) {
334     case 0:
335       rcBBox = CPDF_Rect(0, 0, rcAnnot.right - rcAnnot.left,
336                          rcAnnot.top - rcAnnot.bottom);
337       break;
338     case 90:
339       matrix = CFX_Matrix(0, 1, -1, 0, rcAnnot.right - rcAnnot.left, 0);
340       rcBBox = CPDF_Rect(0, 0, rcAnnot.top - rcAnnot.bottom,
341                          rcAnnot.right - rcAnnot.left);
342       break;
343     case 180:
344       matrix = CFX_Matrix(-1, 0, 0, -1, rcAnnot.right - rcAnnot.left,
345                           rcAnnot.top - rcAnnot.bottom);
346       rcBBox = CPDF_Rect(0, 0, rcAnnot.right - rcAnnot.left,
347                          rcAnnot.top - rcAnnot.bottom);
348       break;
349     case 270:
350       matrix = CFX_Matrix(0, -1, 1, 0, 0, rcAnnot.top - rcAnnot.bottom);
351       rcBBox = CPDF_Rect(0, 0, rcAnnot.top - rcAnnot.bottom,
352                          rcAnnot.right - rcAnnot.left);
353       break;
354   }
355   int32_t nBorderStyle = PBS_SOLID;
356   FX_FLOAT fBorderWidth = 1;
357   CPVT_Dash dsBorder(3, 0, 0);
358   CPVT_Color crLeftTop, crRightBottom;
359   if (CPDF_Dictionary* pBSDict = pAnnotDict->GetDict("BS")) {
360     if (pBSDict->KeyExist("W")) {
361       fBorderWidth = pBSDict->GetNumber("W");
362     }
363     if (CPDF_Array* pArray = pBSDict->GetArray("D")) {
364       dsBorder = CPVT_Dash(pArray->GetInteger(0), pArray->GetInteger(1),
365                            pArray->GetInteger(2));
366     }
367     switch (pBSDict->GetString("S").GetAt(0)) {
368       case 'S':
369         nBorderStyle = PBS_SOLID;
370         break;
371       case 'D':
372         nBorderStyle = PBS_DASH;
373         break;
374       case 'B':
375         nBorderStyle = PBS_BEVELED;
376         fBorderWidth *= 2;
377         crLeftTop = CPVT_Color(CT_GRAY, 1);
378         crRightBottom = CPVT_Color(CT_GRAY, 0.5);
379         break;
380       case 'I':
381         nBorderStyle = PBS_INSET;
382         fBorderWidth *= 2;
383         crLeftTop = CPVT_Color(CT_GRAY, 0.5);
384         crRightBottom = CPVT_Color(CT_GRAY, 0.75);
385         break;
386       case 'U':
387         nBorderStyle = PBS_UNDERLINED;
388         break;
389     }
390   }
391   CPVT_Color crBorder, crBG;
392   if (CPDF_Dictionary* pMKDict = pAnnotDict->GetDict("MK")) {
393     if (CPDF_Array* pArray = pMKDict->GetArray("BC")) {
394       crBorder = ParseColor(*pArray);
395     }
396     if (CPDF_Array* pArray = pMKDict->GetArray("BG")) {
397       crBG = ParseColor(*pArray);
398     }
399   }
400   CFX_ByteTextBuf sAppStream;
401   CFX_ByteString sBG = CPVT_GenerateAP::GenerateColorAP(crBG, TRUE);
402   if (sBG.GetLength() > 0) {
403     sAppStream << "q\n" << sBG << rcBBox.left << " " << rcBBox.bottom << " "
404                << rcBBox.Width() << " " << rcBBox.Height() << " re f\n"
405                << "Q\n";
406   }
407   CFX_ByteString sBorderStream = CPVT_GenerateAP::GenerateBorderAP(
408       rcBBox, fBorderWidth, crBorder, crLeftTop, crRightBottom, nBorderStyle,
409       dsBorder);
410   if (sBorderStream.GetLength() > 0) {
411     sAppStream << "q\n" << sBorderStream << "Q\n";
412   }
413   CPDF_Rect rcBody =
414       CPDF_Rect(rcBBox.left + fBorderWidth, rcBBox.bottom + fBorderWidth,
415                 rcBBox.right - fBorderWidth, rcBBox.top - fBorderWidth);
416   rcBody.Normalize();
417   CPDF_Dictionary* pAPDict = pAnnotDict->GetDict("AP");
418   if (!pAPDict) {
419     pAPDict = new CPDF_Dictionary;
420     pAnnotDict->SetAt("AP", pAPDict);
421   }
422   CPDF_Stream* pNormalStream = pAPDict->GetStream("N");
423   if (!pNormalStream) {
424     pNormalStream = new CPDF_Stream(nullptr, 0, nullptr);
425     int32_t objnum = pDoc->AddIndirectObject(pNormalStream);
426     pAnnotDict->GetDict("AP")->SetAtReference("N", pDoc, objnum);
427   }
428   CPDF_Dictionary* pStreamDict = pNormalStream->GetDict();
429   if (pStreamDict) {
430     pStreamDict->SetAtMatrix("Matrix", matrix);
431     pStreamDict->SetAtRect("BBox", rcBBox);
432     CPDF_Dictionary* pStreamResList = pStreamDict->GetDict("Resources");
433     if (pStreamResList) {
434       CPDF_Dictionary* pStreamResFontList = pStreamResList->GetDict("Font");
435       if (!pStreamResFontList) {
436         pStreamResFontList = new CPDF_Dictionary;
437         pStreamResList->SetAt("Font", pStreamResFontList);
438       }
439       if (!pStreamResFontList->KeyExist(sFontName)) {
440         pStreamResFontList->SetAtReference(sFontName, pDoc, pFontDict);
441       }
442     } else {
443       pStreamDict->SetAt("Resources", pFormDict->GetDict("DR")->Clone());
444       pStreamResList = pStreamDict->GetDict("Resources");
445     }
446   }
447   switch (nWidgetType) {
448     case 0: {
449       CFX_WideString swValue =
450           FPDF_GetFieldAttr(pAnnotDict, "V")
451               ? FPDF_GetFieldAttr(pAnnotDict, "V")->GetUnicodeText()
452               : CFX_WideString();
453       int32_t nAlign = FPDF_GetFieldAttr(pAnnotDict, "Q")
454                            ? FPDF_GetFieldAttr(pAnnotDict, "Q")->GetInteger()
455                            : 0;
456       FX_DWORD dwFlags = FPDF_GetFieldAttr(pAnnotDict, "Ff")
457                              ? FPDF_GetFieldAttr(pAnnotDict, "Ff")->GetInteger()
458                              : 0;
459       FX_DWORD dwMaxLen =
460           FPDF_GetFieldAttr(pAnnotDict, "MaxLen")
461               ? FPDF_GetFieldAttr(pAnnotDict, "MaxLen")->GetInteger()
462               : 0;
463       CPVT_FontMap map(pDoc,
464                        pStreamDict ? pStreamDict->GetDict("Resources") : NULL,
465                        pDefFont, sFontName.Right(sFontName.GetLength() - 1));
466       CPVT_Provider prd(&map);
467       CPDF_VariableText vt;
468       vt.SetProvider(&prd);
469       vt.SetPlateRect(rcBody);
470       vt.SetAlignment(nAlign);
471       if (IsFloatZero(fFontSize)) {
472         vt.SetAutoFontSize(TRUE);
473       } else {
474         vt.SetFontSize(fFontSize);
475       }
476       FX_BOOL bMultiLine = (dwFlags >> 12) & 1;
477       if (bMultiLine) {
478         vt.SetMultiLine(TRUE);
479         vt.SetAutoReturn(TRUE);
480       }
481       FX_WORD subWord = 0;
482       if ((dwFlags >> 13) & 1) {
483         subWord = '*';
484         vt.SetPasswordChar(subWord);
485       }
486       FX_BOOL bCharArray = (dwFlags >> 24) & 1;
487       if (bCharArray) {
488         vt.SetCharArray(dwMaxLen);
489       } else {
490         vt.SetLimitChar(dwMaxLen);
491       }
492       vt.Initialize();
493       vt.SetText(swValue.c_str());
494       vt.RearrangeAll();
495       CPDF_Rect rcContent = vt.GetContentRect();
496       CPDF_Point ptOffset(0.0f, 0.0f);
497       if (!bMultiLine) {
498         ptOffset =
499             CPDF_Point(0.0f, (rcContent.Height() - rcBody.Height()) / 2.0f);
500       }
501       CFX_ByteString sBody = CPVT_GenerateAP::GenerateEditAP(
502           &map, vt.GetIterator(), ptOffset, !bCharArray, subWord);
503       if (sBody.GetLength() > 0) {
504         sAppStream << "/Tx BMC\n"
505                    << "q\n";
506         if (rcContent.Width() > rcBody.Width() ||
507             rcContent.Height() > rcBody.Height()) {
508           sAppStream << rcBody.left << " " << rcBody.bottom << " "
509                      << rcBody.Width() << " " << rcBody.Height()
510                      << " re\nW\nn\n";
511         }
512         sAppStream << "BT\n" << CPVT_GenerateAP::GenerateColorAP(crText, TRUE)
513                    << sBody << "ET\n"
514                    << "Q\nEMC\n";
515       }
516     } break;
517     case 1: {
518       CFX_WideString swValue =
519           FPDF_GetFieldAttr(pAnnotDict, "V")
520               ? FPDF_GetFieldAttr(pAnnotDict, "V")->GetUnicodeText()
521               : CFX_WideString();
522       CPVT_FontMap map(pDoc,
523                        pStreamDict ? pStreamDict->GetDict("Resources") : NULL,
524                        pDefFont, sFontName.Right(sFontName.GetLength() - 1));
525       CPVT_Provider prd(&map);
526       CPDF_VariableText vt;
527       vt.SetProvider(&prd);
528       CPDF_Rect rcButton = rcBody;
529       rcButton.left = rcButton.right - 13;
530       rcButton.Normalize();
531       CPDF_Rect rcEdit = rcBody;
532       rcEdit.right = rcButton.left;
533       rcEdit.Normalize();
534       vt.SetPlateRect(rcEdit);
535       if (IsFloatZero(fFontSize)) {
536         vt.SetAutoFontSize(TRUE);
537       } else {
538         vt.SetFontSize(fFontSize);
539       }
540       vt.Initialize();
541       vt.SetText(swValue.c_str());
542       vt.RearrangeAll();
543       CPDF_Rect rcContent = vt.GetContentRect();
544       CPDF_Point ptOffset =
545           CPDF_Point(0.0f, (rcContent.Height() - rcEdit.Height()) / 2.0f);
546       CFX_ByteString sEdit = CPVT_GenerateAP::GenerateEditAP(
547           &map, vt.GetIterator(), ptOffset, TRUE, 0);
548       if (sEdit.GetLength() > 0) {
549         sAppStream << "/Tx BMC\n"
550                    << "q\n";
551         sAppStream << rcEdit.left << " " << rcEdit.bottom << " "
552                    << rcEdit.Width() << " " << rcEdit.Height() << " re\nW\nn\n";
553         sAppStream << "BT\n" << CPVT_GenerateAP::GenerateColorAP(crText, TRUE)
554                    << sEdit << "ET\n"
555                    << "Q\nEMC\n";
556       }
557       CFX_ByteString sButton = CPVT_GenerateAP::GenerateColorAP(
558           CPVT_Color(CT_RGB, 220.0f / 255.0f, 220.0f / 255.0f, 220.0f / 255.0f),
559           TRUE);
560       if (sButton.GetLength() > 0 && !rcButton.IsEmpty()) {
561         sAppStream << "q\n" << sButton;
562         sAppStream << rcButton.left << " " << rcButton.bottom << " "
563                    << rcButton.Width() << " " << rcButton.Height() << " re f\n";
564         sAppStream << "Q\n";
565         CFX_ByteString sButtonBorder = CPVT_GenerateAP::GenerateBorderAP(
566             rcButton, 2, CPVT_Color(CT_GRAY, 0), CPVT_Color(CT_GRAY, 1),
567             CPVT_Color(CT_GRAY, 0.5), PBS_BEVELED, CPVT_Dash(3, 0, 0));
568         if (sButtonBorder.GetLength() > 0) {
569           sAppStream << "q\n" << sButtonBorder << "Q\n";
570         }
571         CPDF_Point ptCenter = CPDF_Point((rcButton.left + rcButton.right) / 2,
572                                          (rcButton.top + rcButton.bottom) / 2);
573         if (IsFloatBigger(rcButton.Width(), 6) &&
574             IsFloatBigger(rcButton.Height(), 6)) {
575           sAppStream << "q\n"
576                      << " 0 g\n";
577           sAppStream << ptCenter.x - 3 << " " << ptCenter.y + 1.5f << " m\n";
578           sAppStream << ptCenter.x + 3 << " " << ptCenter.y + 1.5f << " l\n";
579           sAppStream << ptCenter.x << " " << ptCenter.y - 1.5f << " l\n";
580           sAppStream << ptCenter.x - 3 << " " << ptCenter.y + 1.5f << " l f\n";
581           sAppStream << sButton << "Q\n";
582         }
583       }
584     } break;
585     case 2: {
586       CPVT_FontMap map(pDoc,
587                        pStreamDict ? pStreamDict->GetDict("Resources") : NULL,
588                        pDefFont, sFontName.Right(sFontName.GetLength() - 1));
589       CPVT_Provider prd(&map);
590       CPDF_Array* pOpts = FPDF_GetFieldAttr(pAnnotDict, "Opt")
591                               ? FPDF_GetFieldAttr(pAnnotDict, "Opt")->GetArray()
592                               : NULL;
593       CPDF_Array* pSels = FPDF_GetFieldAttr(pAnnotDict, "I")
594                               ? FPDF_GetFieldAttr(pAnnotDict, "I")->GetArray()
595                               : NULL;
596       int32_t nTop = FPDF_GetFieldAttr(pAnnotDict, "TI")
597                          ? FPDF_GetFieldAttr(pAnnotDict, "TI")->GetInteger()
598                          : 0;
599       CFX_ByteTextBuf sBody;
600       if (pOpts) {
601         FX_FLOAT fy = rcBody.top;
602         for (int32_t i = nTop, sz = pOpts->GetCount(); i < sz; i++) {
603           if (IsFloatSmaller(fy, rcBody.bottom)) {
604             break;
605           }
606           if (CPDF_Object* pOpt = pOpts->GetElementValue(i)) {
607             CFX_WideString swItem;
608             if (pOpt->IsString())
609               swItem = pOpt->GetUnicodeText();
610             else if (CPDF_Array* pArray = pOpt->AsArray())
611               swItem = pArray->GetElementValue(1)->GetUnicodeText();
612 
613             FX_BOOL bSelected = FALSE;
614             if (pSels) {
615               for (FX_DWORD s = 0, ssz = pSels->GetCount(); s < ssz; s++) {
616                 if (i == pSels->GetInteger(s)) {
617                   bSelected = TRUE;
618                   break;
619                 }
620               }
621             }
622             CPDF_VariableText vt;
623             vt.SetProvider(&prd);
624             vt.SetPlateRect(CPDF_Rect(rcBody.left, 0.0f, rcBody.right, 0.0f));
625             if (IsFloatZero(fFontSize)) {
626               vt.SetFontSize(12.0f);
627             } else {
628               vt.SetFontSize(fFontSize);
629             }
630             vt.Initialize();
631             vt.SetText(swItem.c_str());
632             vt.RearrangeAll();
633             FX_FLOAT fItemHeight = vt.GetContentRect().Height();
634             if (bSelected) {
635               CPDF_Rect rcItem =
636                   CPDF_Rect(rcBody.left, fy - fItemHeight, rcBody.right, fy);
637               sBody << "q\n" << CPVT_GenerateAP::GenerateColorAP(
638                                     CPVT_Color(CT_RGB, 0, 51.0f / 255.0f,
639                                                113.0f / 255.0f),
640                                     TRUE)
641                     << rcItem.left << " " << rcItem.bottom << " "
642                     << rcItem.Width() << " " << rcItem.Height() << " re f\n"
643                     << "Q\n";
644               sBody << "BT\n" << CPVT_GenerateAP::GenerateColorAP(
645                                      CPVT_Color(CT_GRAY, 1), TRUE)
646                     << CPVT_GenerateAP::GenerateEditAP(&map, vt.GetIterator(),
647                                                        CPDF_Point(0.0f, fy),
648                                                        TRUE, 0)
649                     << "ET\n";
650             } else {
651               sBody << "BT\n" << CPVT_GenerateAP::GenerateColorAP(crText, TRUE)
652                     << CPVT_GenerateAP::GenerateEditAP(&map, vt.GetIterator(),
653                                                        CPDF_Point(0.0f, fy),
654                                                        TRUE, 0)
655                     << "ET\n";
656             }
657             fy -= fItemHeight;
658           }
659         }
660       }
661       if (sBody.GetSize() > 0) {
662         sAppStream << "/Tx BMC\n"
663                    << "q\n";
664         sAppStream << rcBody.left << " " << rcBody.bottom << " "
665                    << rcBody.Width() << " " << rcBody.Height() << " re\nW\nn\n";
666         sAppStream << sBody.GetByteString() << "Q\nEMC\n";
667       }
668     } break;
669   }
670   if (pNormalStream) {
671     pNormalStream->SetData((uint8_t*)sAppStream.GetBuffer(),
672                            sAppStream.GetSize(), FALSE, FALSE);
673     pStreamDict = pNormalStream->GetDict();
674     if (pStreamDict) {
675       pStreamDict->SetAtMatrix("Matrix", matrix);
676       pStreamDict->SetAtRect("BBox", rcBBox);
677       CPDF_Dictionary* pStreamResList = pStreamDict->GetDict("Resources");
678       if (pStreamResList) {
679         CPDF_Dictionary* pStreamResFontList = pStreamResList->GetDict("Font");
680         if (!pStreamResFontList) {
681           pStreamResFontList = new CPDF_Dictionary;
682           pStreamResList->SetAt("Font", pStreamResFontList);
683         }
684         if (!pStreamResFontList->KeyExist(sFontName)) {
685           pStreamResFontList->SetAtReference(sFontName, pDoc, pFontDict);
686         }
687       } else {
688         pStreamDict->SetAt("Resources", pFormDict->GetDict("DR")->Clone());
689         pStreamResList = pStreamDict->GetDict("Resources");
690       }
691     }
692   }
693   return TRUE;
694 }
GenerateTextFieldAP(CPDF_Document * pDoc,CPDF_Dictionary * pAnnotDict)695 FX_BOOL CPVT_GenerateAP::GenerateTextFieldAP(CPDF_Document* pDoc,
696                                              CPDF_Dictionary* pAnnotDict) {
697   return GenerateWidgetAP(pDoc, pAnnotDict, 0);
698 }
GenerateComboBoxAP(CPDF_Document * pDoc,CPDF_Dictionary * pAnnotDict)699 FX_BOOL CPVT_GenerateAP::GenerateComboBoxAP(CPDF_Document* pDoc,
700                                             CPDF_Dictionary* pAnnotDict) {
701   return GenerateWidgetAP(pDoc, pAnnotDict, 1);
702 }
GenerateListBoxAP(CPDF_Document * pDoc,CPDF_Dictionary * pAnnotDict)703 FX_BOOL CPVT_GenerateAP::GenerateListBoxAP(CPDF_Document* pDoc,
704                                            CPDF_Dictionary* pAnnotDict) {
705   return GenerateWidgetAP(pDoc, pAnnotDict, 2);
706 }
GenerateEditAP(IPVT_FontMap * pFontMap,IPDF_VariableText_Iterator * pIterator,const CPDF_Point & ptOffset,FX_BOOL bContinuous,FX_WORD SubWord,const CPVT_WordRange * pVisible)707 CFX_ByteString CPVT_GenerateAP::GenerateEditAP(
708     IPVT_FontMap* pFontMap,
709     IPDF_VariableText_Iterator* pIterator,
710     const CPDF_Point& ptOffset,
711     FX_BOOL bContinuous,
712     FX_WORD SubWord,
713     const CPVT_WordRange* pVisible) {
714   CFX_ByteTextBuf sEditStream, sLineStream, sWords;
715   CPDF_Point ptOld(0.0f, 0.0f), ptNew(0.0f, 0.0f);
716   int32_t nCurFontIndex = -1;
717   if (pIterator) {
718     if (pVisible) {
719       pIterator->SetAt(pVisible->BeginPos);
720     } else {
721       pIterator->SetAt(0);
722     }
723     CPVT_WordPlace oldplace;
724     while (pIterator->NextWord()) {
725       CPVT_WordPlace place = pIterator->GetAt();
726       if (pVisible && place.WordCmp(pVisible->EndPos) > 0) {
727         break;
728       }
729       if (bContinuous) {
730         if (place.LineCmp(oldplace) != 0) {
731           if (sWords.GetSize() > 0) {
732             sLineStream << GetWordRenderString(sWords.GetByteString());
733             sEditStream << sLineStream;
734             sLineStream.Clear();
735             sWords.Clear();
736           }
737           CPVT_Word word;
738           if (pIterator->GetWord(word)) {
739             ptNew = CPDF_Point(word.ptWord.x + ptOffset.x,
740                                word.ptWord.y + ptOffset.y);
741           } else {
742             CPVT_Line line;
743             pIterator->GetLine(line);
744             ptNew = CPDF_Point(line.ptLine.x + ptOffset.x,
745                                line.ptLine.y + ptOffset.y);
746           }
747           if (ptNew.x != ptOld.x || ptNew.y != ptOld.y) {
748             sLineStream << ptNew.x - ptOld.x << " " << ptNew.y - ptOld.y
749                         << " Td\n";
750             ptOld = ptNew;
751           }
752         }
753         CPVT_Word word;
754         if (pIterator->GetWord(word)) {
755           if (word.nFontIndex != nCurFontIndex) {
756             if (sWords.GetSize() > 0) {
757               sLineStream << GetWordRenderString(sWords.GetByteString());
758               sWords.Clear();
759             }
760             sLineStream << GetFontSetString(pFontMap, word.nFontIndex,
761                                             word.fFontSize);
762             nCurFontIndex = word.nFontIndex;
763           }
764           sWords << GetPDFWordString(pFontMap, nCurFontIndex, word.Word,
765                                      SubWord);
766         }
767         oldplace = place;
768       } else {
769         CPVT_Word word;
770         if (pIterator->GetWord(word)) {
771           ptNew = CPDF_Point(word.ptWord.x + ptOffset.x,
772                              word.ptWord.y + ptOffset.y);
773           if (ptNew.x != ptOld.x || ptNew.y != ptOld.y) {
774             sEditStream << ptNew.x - ptOld.x << " " << ptNew.y - ptOld.y
775                         << " Td\n";
776             ptOld = ptNew;
777           }
778           if (word.nFontIndex != nCurFontIndex) {
779             sEditStream << GetFontSetString(pFontMap, word.nFontIndex,
780                                             word.fFontSize);
781             nCurFontIndex = word.nFontIndex;
782           }
783           sEditStream << GetWordRenderString(
784               GetPDFWordString(pFontMap, nCurFontIndex, word.Word, SubWord));
785         }
786       }
787     }
788     if (sWords.GetSize() > 0) {
789       sLineStream << GetWordRenderString(sWords.GetByteString());
790       sEditStream << sLineStream;
791       sWords.Clear();
792     }
793   }
794   return sEditStream.GetByteString();
795 }
GenerateBorderAP(const CPDF_Rect & rect,FX_FLOAT fWidth,const CPVT_Color & color,const CPVT_Color & crLeftTop,const CPVT_Color & crRightBottom,int32_t nStyle,const CPVT_Dash & dash)796 CFX_ByteString CPVT_GenerateAP::GenerateBorderAP(
797     const CPDF_Rect& rect,
798     FX_FLOAT fWidth,
799     const CPVT_Color& color,
800     const CPVT_Color& crLeftTop,
801     const CPVT_Color& crRightBottom,
802     int32_t nStyle,
803     const CPVT_Dash& dash) {
804   CFX_ByteTextBuf sAppStream;
805   CFX_ByteString sColor;
806   FX_FLOAT fLeft = rect.left;
807   FX_FLOAT fRight = rect.right;
808   FX_FLOAT fTop = rect.top;
809   FX_FLOAT fBottom = rect.bottom;
810   if (fWidth > 0.0f) {
811     FX_FLOAT fHalfWidth = fWidth / 2.0f;
812     switch (nStyle) {
813       default:
814       case PBS_SOLID:
815         sColor = GenerateColorAP(color, TRUE);
816         if (sColor.GetLength() > 0) {
817           sAppStream << sColor;
818           sAppStream << fLeft << " " << fBottom << " " << fRight - fLeft << " "
819                      << fTop - fBottom << " re\n";
820           sAppStream << fLeft + fWidth << " " << fBottom + fWidth << " "
821                      << fRight - fLeft - fWidth * 2 << " "
822                      << fTop - fBottom - fWidth * 2 << " re\n";
823           sAppStream << "f*\n";
824         }
825         break;
826       case PBS_DASH:
827         sColor = GenerateColorAP(color, FALSE);
828         if (sColor.GetLength() > 0) {
829           sAppStream << sColor;
830           sAppStream << fWidth << " w"
831                      << " [" << dash.nDash << " " << dash.nGap << "] "
832                      << dash.nPhase << " d\n";
833           sAppStream << fLeft + fWidth / 2 << " " << fBottom + fWidth / 2
834                      << " m\n";
835           sAppStream << fLeft + fWidth / 2 << " " << fTop - fWidth / 2
836                      << " l\n";
837           sAppStream << fRight - fWidth / 2 << " " << fTop - fWidth / 2
838                      << " l\n";
839           sAppStream << fRight - fWidth / 2 << " " << fBottom + fWidth / 2
840                      << " l\n";
841           sAppStream << fLeft + fWidth / 2 << " " << fBottom + fWidth / 2
842                      << " l S\n";
843         }
844         break;
845       case PBS_BEVELED:
846       case PBS_INSET:
847         sColor = GenerateColorAP(crLeftTop, TRUE);
848         if (sColor.GetLength() > 0) {
849           sAppStream << sColor;
850           sAppStream << fLeft + fHalfWidth << " " << fBottom + fHalfWidth
851                      << " m\n";
852           sAppStream << fLeft + fHalfWidth << " " << fTop - fHalfWidth
853                      << " l\n";
854           sAppStream << fRight - fHalfWidth << " " << fTop - fHalfWidth
855                      << " l\n";
856           sAppStream << fRight - fHalfWidth * 2 << " " << fTop - fHalfWidth * 2
857                      << " l\n";
858           sAppStream << fLeft + fHalfWidth * 2 << " " << fTop - fHalfWidth * 2
859                      << " l\n";
860           sAppStream << fLeft + fHalfWidth * 2 << " "
861                      << fBottom + fHalfWidth * 2 << " l f\n";
862         }
863         sColor = GenerateColorAP(crRightBottom, TRUE);
864         if (sColor.GetLength() > 0) {
865           sAppStream << sColor;
866           sAppStream << fRight - fHalfWidth << " " << fTop - fHalfWidth
867                      << " m\n";
868           sAppStream << fRight - fHalfWidth << " " << fBottom + fHalfWidth
869                      << " l\n";
870           sAppStream << fLeft + fHalfWidth << " " << fBottom + fHalfWidth
871                      << " l\n";
872           sAppStream << fLeft + fHalfWidth * 2 << " "
873                      << fBottom + fHalfWidth * 2 << " l\n";
874           sAppStream << fRight - fHalfWidth * 2 << " "
875                      << fBottom + fHalfWidth * 2 << " l\n";
876           sAppStream << fRight - fHalfWidth * 2 << " " << fTop - fHalfWidth * 2
877                      << " l f\n";
878         }
879         sColor = GenerateColorAP(color, TRUE);
880         if (sColor.GetLength() > 0) {
881           sAppStream << sColor;
882           sAppStream << fLeft << " " << fBottom << " " << fRight - fLeft << " "
883                      << fTop - fBottom << " re\n";
884           sAppStream << fLeft + fHalfWidth << " " << fBottom + fHalfWidth << " "
885                      << fRight - fLeft - fHalfWidth * 2 << " "
886                      << fTop - fBottom - fHalfWidth * 2 << " re f*\n";
887         }
888         break;
889       case PBS_UNDERLINED:
890         sColor = GenerateColorAP(color, FALSE);
891         if (sColor.GetLength() > 0) {
892           sAppStream << sColor;
893           sAppStream << fWidth << " w\n";
894           sAppStream << fLeft << " " << fBottom + fWidth / 2 << " m\n";
895           sAppStream << fRight << " " << fBottom + fWidth / 2 << " l S\n";
896         }
897         break;
898     }
899   }
900   return sAppStream.GetByteString();
901 }
GenerateColorAP(const CPVT_Color & color,const FX_BOOL & bFillOrStroke)902 CFX_ByteString CPVT_GenerateAP::GenerateColorAP(const CPVT_Color& color,
903                                                 const FX_BOOL& bFillOrStroke) {
904   CFX_ByteTextBuf sColorStream;
905   switch (color.nColorType) {
906     case CT_RGB:
907       sColorStream << color.fColor1 << " " << color.fColor2 << " "
908                    << color.fColor3 << " " << (bFillOrStroke ? "rg" : "RG")
909                    << "\n";
910       break;
911     case CT_GRAY:
912       sColorStream << color.fColor1 << " " << (bFillOrStroke ? "g" : "G")
913                    << "\n";
914       break;
915     case CT_CMYK:
916       sColorStream << color.fColor1 << " " << color.fColor2 << " "
917                    << color.fColor3 << " " << color.fColor4 << " "
918                    << (bFillOrStroke ? "k" : "K") << "\n";
919       break;
920   }
921   return sColorStream.GetByteString();
922 }
923