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