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