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