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