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