• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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->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")->GetInteger();
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 = FPDF_GetFieldAttr(pAnnotDict, "DA")->GetString();
257     if (DA.IsEmpty()) {
258         DA = pFormDict->GetString("DA");
259     }
260     if (DA.IsEmpty()) {
261         return FALSE;
262     }
263     CPDF_SimpleParser syntax(DA);
264     syntax.FindTagParam("Tf", 2);
265     CFX_ByteString sFontName = syntax.GetWord();
266     sFontName = PDF_NameDecode(sFontName);
267     if (sFontName.IsEmpty()) {
268         return FALSE;
269     }
270     FX_FLOAT fFontSize = FX_atof(syntax.GetWord());
271     CPVT_Color crText = ParseColor(DA);
272     FX_BOOL bUseFormRes = FALSE;
273     CPDF_Dictionary * pFontDict = NULL;
274     CPDF_Dictionary* pDRDict = pAnnotDict->GetDict(FX_BSTRC("DR"));
275     if (pDRDict == NULL) {
276         pDRDict = pFormDict->GetDict(FX_BSTRC("DR"));
277         bUseFormRes = TRUE;
278     }
279     CPDF_Dictionary * pDRFontDict = NULL;
280     if ((pDRFontDict = pDRDict->GetDict("Font"))) {
281         pFontDict = pDRFontDict->GetDict(sFontName.Mid(1));
282         if (!pFontDict && !bUseFormRes) {
283             pDRDict = pFormDict->GetDict(FX_BSTRC("DR"));
284             pDRFontDict = pDRDict->GetDict("Font");
285             if (pDRFontDict) {
286                 pFontDict = pDRFontDict->GetDict(sFontName.Mid(1));
287             }
288         }
289     }
290     if (!pDRFontDict) {
291         return FALSE;
292     }
293     if (!pFontDict) {
294         pFontDict = CPDF_Dictionary::Create();
295         if (pFontDict == NULL) {
296             return FALSE;
297         }
298         pFontDict->SetAtName(FX_BSTRC("Type"), "Font");
299         pFontDict->SetAtName(FX_BSTRC("Subtype"), "Type1");
300         pFontDict->SetAtName(FX_BSTRC("BaseFont"), "Helvetica");
301         pFontDict->SetAtName(FX_BSTRC("Encoding"), "WinAnsiEncoding");
302         pDoc->AddIndirectObject(pFontDict);
303         pDRFontDict->SetAtReference(sFontName.Mid(1), pDoc, pFontDict);
304     }
305     CPDF_Font* pDefFont = pDoc->LoadFont(pFontDict);
306     if (!pDefFont) {
307         return FALSE;
308     }
309     CFX_CharMap* pCharMap = pDefFont->GetCharMap();
310     CPDF_Rect rcAnnot = pAnnotDict->GetRect("Rect");
311     FX_INT32 nRotate = 0;
312     if (CPDF_Dictionary * pMKDict = pAnnotDict->GetDict("MK")) {
313         nRotate = pMKDict->GetInteger("R");
314     }
315     CPDF_Rect rcBBox;
316     CPDF_Matrix matrix;
317     switch (nRotate % 360) {
318         case 0:
319             rcBBox = CPDF_Rect(0, 0, rcAnnot.right - rcAnnot.left, rcAnnot.top - rcAnnot.bottom);
320             break;
321         case 90:
322             matrix = CPDF_Matrix(0, 1, -1, 0, rcAnnot.right - rcAnnot.left, 0);
323             rcBBox = CPDF_Rect(0, 0, rcAnnot.top - rcAnnot.bottom, rcAnnot.right - rcAnnot.left);
324             break;
325         case 180:
326             matrix = CPDF_Matrix(-1, 0, 0, -1, rcAnnot.right - rcAnnot.left, rcAnnot.top - rcAnnot.bottom);
327             rcBBox = CPDF_Rect(0, 0, rcAnnot.right - rcAnnot.left, rcAnnot.top - rcAnnot.bottom);
328             break;
329         case 270:
330             matrix = CPDF_Matrix(0, -1, 1, 0, 0, rcAnnot.top - rcAnnot.bottom);
331             rcBBox = CPDF_Rect(0, 0, rcAnnot.top - rcAnnot.bottom, rcAnnot.right - rcAnnot.left);
332             break;
333     }
334     FX_INT32 nBorderStyle = PBS_SOLID;
335     FX_FLOAT fBorderWidth = 1;
336     CPVT_Dash dsBorder(3, 0, 0);
337     CPVT_Color crLeftTop, crRightBottom;
338     if (CPDF_Dictionary * pBSDict = pAnnotDict->GetDict("BS")) {
339         if (pBSDict->KeyExist("W")) {
340             fBorderWidth = pBSDict->GetNumber("W");
341         }
342         if (CPDF_Array * pArray = pBSDict->GetArray("D")) {
343             dsBorder = CPVT_Dash(pArray->GetInteger(0), pArray->GetInteger(1), pArray->GetInteger(2));
344         }
345         switch (pBSDict->GetString("S").GetAt(0)) {
346             case 'S':
347                 nBorderStyle = PBS_SOLID;
348                 break;
349             case 'D':
350                 nBorderStyle = PBS_DASH;
351                 break;
352             case 'B':
353                 nBorderStyle = PBS_BEVELED;
354                 fBorderWidth *= 2;
355                 crLeftTop = CPVT_Color(CT_GRAY, 1);
356                 crRightBottom = CPVT_Color(CT_GRAY, 0.5);
357                 break;
358             case 'I':
359                 nBorderStyle = PBS_INSET;
360                 fBorderWidth *= 2;
361                 crLeftTop = CPVT_Color(CT_GRAY, 0.5);
362                 crRightBottom = CPVT_Color(CT_GRAY, 0.75);
363                 break;
364             case 'U':
365                 nBorderStyle = PBS_UNDERLINED;
366                 break;
367         }
368     }
369     CPVT_Color crBorder, crBG;
370     if (CPDF_Dictionary * pMKDict = pAnnotDict->GetDict("MK")) {
371         if (CPDF_Array * pArray = pMKDict->GetArray("BC")) {
372             crBorder = ParseColor(*pArray);
373         }
374         if (CPDF_Array * pArray = pMKDict->GetArray("BG")) {
375             crBG = ParseColor(*pArray);
376         }
377     }
378     CFX_ByteTextBuf sAppStream;
379     CFX_ByteString sBG = CPVT_GenerateAP::GenerateColorAP(crBG, TRUE);
380     if (sBG.GetLength() > 0) {
381         sAppStream << "q\n" << sBG << rcBBox.left << " " << rcBBox.bottom << " "
382                    << rcBBox.Width() << " " << rcBBox.Height() << " re f\n" << "Q\n";
383     }
384     CFX_ByteString sBorderStream = CPVT_GenerateAP::GenerateBorderAP(rcBBox, fBorderWidth,
385                                    crBorder, crLeftTop, crRightBottom, nBorderStyle, dsBorder);
386     if (sBorderStream.GetLength() > 0) {
387         sAppStream << "q\n" << sBorderStream << "Q\n";
388     }
389     CPDF_Rect rcBody = CPDF_Rect(rcBBox.left + fBorderWidth, rcBBox.bottom + fBorderWidth,
390                                  rcBBox.right - fBorderWidth, rcBBox.top - fBorderWidth);
391     rcBody.Normalize();
392     CPDF_Dictionary* pAPDict = pAnnotDict->GetDict("AP");
393     if (pAPDict == NULL) {
394         pAPDict = CPDF_Dictionary::Create();
395         if (pAPDict == NULL) {
396             return FALSE;
397         }
398         pAnnotDict->SetAt("AP", pAPDict);
399     }
400     CPDF_Stream* pNormalStream = pAPDict->GetStream("N");
401     if (pNormalStream == NULL) {
402         pNormalStream = CPDF_Stream::Create(NULL, 0, NULL);
403         if (pNormalStream == NULL) {
404             return FALSE;
405         }
406         FX_INT32 objnum = pDoc->AddIndirectObject(pNormalStream);
407         pAnnotDict->GetDict("AP")->SetAtReference("N", pDoc, objnum);
408     }
409     CPDF_Dictionary * pStreamDict = pNormalStream->GetDict();
410     if (pStreamDict) {
411         pStreamDict->SetAtMatrix("Matrix", matrix);
412         pStreamDict->SetAtRect("BBox", rcBBox);
413         CPDF_Dictionary* pStreamResList = pStreamDict->GetDict("Resources");
414         if (pStreamResList) {
415             CPDF_Dictionary* pStreamResFontList = pStreamResList->GetDict("Font");
416             if (!pStreamResFontList) {
417                 pStreamResFontList = CPDF_Dictionary::Create();
418                 if (pStreamResFontList == NULL) {
419                     return FALSE;
420                 }
421                 pStreamResList->SetAt("Font", pStreamResFontList);
422             }
423             if (!pStreamResFontList->KeyExist(sFontName)) {
424                 pStreamResFontList->SetAtReference(sFontName, pDoc, pFontDict);
425             }
426         } else {
427             pStreamDict->SetAt("Resources", pFormDict->GetDict("DR")->Clone());
428             pStreamResList = pStreamDict->GetDict("Resources");
429         }
430     }
431     switch (nWidgetType) {
432         case 0: {
433                 CFX_WideString swValue = FPDF_GetFieldAttr(pAnnotDict, "V")->GetUnicodeText();
434                 FX_INT32 nAlign = FPDF_GetFieldAttr(pAnnotDict, "Q")->GetInteger();
435                 FX_DWORD dwFlags = FPDF_GetFieldAttr(pAnnotDict, "Ff")->GetInteger();
436                 FX_DWORD dwMaxLen = FPDF_GetFieldAttr(pAnnotDict, "MaxLen")->GetInteger();
437                 CPVT_FontMap map(pDoc, pStreamDict->GetDict("Resources"), pDefFont, sFontName.Right(sFontName.GetLength() - 1));
438                 CPVT_Provider prd(&map);
439                 CPDF_VariableText vt;
440                 vt.SetProvider(&prd);
441                 vt.SetPlateRect(rcBody);
442                 vt.SetAlignment(nAlign);
443                 if (IsFloatZero(fFontSize)) {
444                     vt.SetAutoFontSize(TRUE);
445                 } else {
446                     vt.SetFontSize(fFontSize);
447                 }
448                 FX_BOOL bMultiLine = (dwFlags >> 12) & 1;
449                 if (bMultiLine) {
450                     vt.SetMultiLine(TRUE);
451                     vt.SetAutoReturn(TRUE);
452                 }
453                 FX_WORD subWord = 0;
454                 if ((dwFlags >> 13) & 1) {
455                     subWord = '*';
456                     vt.SetPasswordChar(subWord);
457                 }
458                 FX_BOOL bCharArray = (dwFlags >> 24) & 1;
459                 if (bCharArray) {
460                     vt.SetCharArray(dwMaxLen);
461                 } else {
462                     vt.SetLimitChar(dwMaxLen);
463                 }
464                 vt.Initialize();
465                 vt.SetText(swValue);
466                 vt.RearrangeAll();
467                 CPDF_Rect rcContent = vt.GetContentRect();
468                 CPDF_Point ptOffset(0.0f, 0.0f);
469                 if (!bMultiLine) {
470                     ptOffset = CPDF_Point(0.0f, (rcContent.Height() - rcBody.Height()) / 2.0f);
471                 }
472                 CFX_ByteString sBody = CPVT_GenerateAP::GenerateEditAP(&map, vt.GetIterator(), ptOffset, !bCharArray, subWord);
473                 if (sBody.GetLength() > 0) {
474                     sAppStream << "/Tx BMC\n" << "q\n";
475                     if (rcContent.Width() > rcBody.Width() ||
476                             rcContent.Height() > rcBody.Height()) {
477                         sAppStream << rcBody.left << " " << rcBody.bottom << " "
478                                    << rcBody.Width() << " " << rcBody.Height() << " re\nW\nn\n";
479                     }
480                     sAppStream << "BT\n" << CPVT_GenerateAP::GenerateColorAP(crText, TRUE) << sBody << "ET\n" << "Q\nEMC\n";
481                 }
482             }
483             break;
484         case 1: {
485                 CFX_WideString swValue = FPDF_GetFieldAttr(pAnnotDict, "V")->GetUnicodeText();
486                 CPVT_FontMap map(pDoc, pStreamDict->GetDict("Resources"), pDefFont, sFontName.Right(sFontName.GetLength() - 1));
487                 CPVT_Provider prd(&map);
488                 CPDF_VariableText vt;
489                 vt.SetProvider(&prd);
490                 CPDF_Rect rcButton = rcBody;
491                 rcButton.left = rcButton.right - 13;
492                 rcButton.Normalize();
493                 CPDF_Rect rcEdit = rcBody;
494                 rcEdit.right = rcButton.left;
495                 rcEdit.Normalize();
496                 vt.SetPlateRect(rcEdit);
497                 if (IsFloatZero(fFontSize)) {
498                     vt.SetAutoFontSize(TRUE);
499                 } else {
500                     vt.SetFontSize(fFontSize);
501                 }
502                 vt.Initialize();
503                 vt.SetText(swValue);
504                 vt.RearrangeAll();
505                 CPDF_Rect rcContent = vt.GetContentRect();
506                 CPDF_Point ptOffset = CPDF_Point(0.0f, (rcContent.Height() - rcEdit.Height()) / 2.0f);
507                 CFX_ByteString sEdit = CPVT_GenerateAP::GenerateEditAP(&map, vt.GetIterator(), ptOffset, TRUE, 0);
508                 if (sEdit.GetLength() > 0) {
509                     sAppStream << "/Tx BMC\n" << "q\n";
510                     sAppStream << rcEdit.left << " " << rcEdit.bottom << " "
511                                << rcEdit.Width() << " " << rcEdit.Height() << " re\nW\nn\n";
512                     sAppStream << "BT\n" << CPVT_GenerateAP::GenerateColorAP(crText, TRUE) << sEdit << "ET\n" << "Q\nEMC\n";
513                 }
514                 CFX_ByteString sButton = CPVT_GenerateAP::GenerateColorAP(CPVT_Color(CT_RGB, 220.0f / 255.0f, 220.0f / 255.0f, 220.0f / 255.0f), TRUE);
515                 if (sButton.GetLength() > 0 && !rcButton.IsEmpty()) {
516                     sAppStream << "q\n" << sButton;
517                     sAppStream << rcButton.left << " " << rcButton.bottom << " "
518                                << rcButton.Width() << " " << rcButton.Height() << " re f\n";
519                     sAppStream << "Q\n";
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));
521                     if (sButtonBorder.GetLength() > 0) {
522                         sAppStream << "q\n" << sButtonBorder << "Q\n";
523                     }
524                     CPDF_Point ptCenter = CPDF_Point((rcButton.left + rcButton.right) / 2, (rcButton.top + rcButton.bottom) / 2);
525                     if (IsFloatBigger(rcButton.Width(), 6) && IsFloatBigger(rcButton.Height(), 6)) {
526                         sAppStream << "q\n" << " 0 g\n";
527                         sAppStream << ptCenter.x - 3 << " " << ptCenter.y + 1.5f << " m\n";
528                         sAppStream << ptCenter.x + 3 << " " << ptCenter.y + 1.5f << " l\n";
529                         sAppStream << ptCenter.x << " " << ptCenter.y - 1.5f << " l\n";
530                         sAppStream << ptCenter.x - 3 << " " << ptCenter.y + 1.5f << " l f\n";
531                         sAppStream << sButton << "Q\n";
532                     }
533                 }
534             }
535             break;
536         case 2: {
537                 CPVT_FontMap map(pDoc, pStreamDict->GetDict("Resources"), pDefFont, sFontName.Right(sFontName.GetLength() - 1));
538                 CPVT_Provider prd(&map);
539                 CPDF_Array * pOpts = FPDF_GetFieldAttr(pAnnotDict, "Opt")->GetArray();
540                 CPDF_Array * pSels = FPDF_GetFieldAttr(pAnnotDict, "I")->GetArray();
541                 FX_INT32 nTop = FPDF_GetFieldAttr(pAnnotDict, "TI")->GetInteger();
542                 CFX_ByteTextBuf sBody;
543                 if (pOpts) {
544                     FX_FLOAT fy = rcBody.top;
545                     for (FX_INT32 i = nTop, sz = pOpts->GetCount(); i < sz; i++) {
546                         if (IsFloatSmaller(fy, rcBody.bottom)) {
547                             break;
548                         }
549                         if (CPDF_Object* pOpt = pOpts->GetElementValue(i)) {
550                             CFX_WideString swItem;
551                             if (pOpt->GetType() == PDFOBJ_STRING) {
552                                 swItem = pOpt->GetUnicodeText();
553                             } else if (pOpt->GetType() == PDFOBJ_ARRAY) {
554                                 swItem = ((CPDF_Array*)pOpt)->GetElementValue(1)->GetUnicodeText();
555                             }
556                             FX_BOOL bSelected = FALSE;
557                             if (pSels) {
558                                 for (FX_DWORD s = 0, ssz = pSels->GetCount(); s < ssz; s++) {
559                                     if (i == pSels->GetInteger(s)) {
560                                         bSelected = TRUE;
561                                         break;
562                                     }
563                                 }
564                             }
565                             CPDF_VariableText vt;
566                             vt.SetProvider(&prd);
567                             vt.SetPlateRect(CPDF_Rect(rcBody.left, 0.0f, rcBody.right, 0.0f));
568                             if (IsFloatZero(fFontSize)) {
569                                 vt.SetFontSize(12.0f);
570                             } else {
571                                 vt.SetFontSize(fFontSize);
572                             }
573                             vt.Initialize();
574                             vt.SetText(swItem);
575                             vt.RearrangeAll();
576                             FX_FLOAT fItemHeight = vt.GetContentRect().Height();
577                             if (bSelected) {
578                                 CPDF_Rect rcItem = CPDF_Rect(rcBody.left, fy - fItemHeight, rcBody.right, fy);
579                                 sBody << "q\n" << CPVT_GenerateAP::GenerateColorAP(CPVT_Color(CT_RGB, 0, 51.0f / 255.0f, 113.0f / 255.0f), TRUE)
580                                       << rcItem.left << " " << rcItem.bottom << " " << rcItem.Width() << " " << rcItem.Height() << " re f\n" << "Q\n";
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";
582                             } else {
583                                 sBody << "BT\n" << CPVT_GenerateAP::GenerateColorAP(crText, TRUE) << CPVT_GenerateAP::GenerateEditAP(&map, vt.GetIterator(), CPDF_Point(0.0f, fy), TRUE, 0) << "ET\n";
584                             }
585                             fy -= fItemHeight;
586                         }
587                     }
588                 }
589                 if (sBody.GetSize() > 0) {
590                     sAppStream << "/Tx BMC\n" << "q\n";
591                     sAppStream << rcBody.left << " " << rcBody.bottom << " "
592                                << rcBody.Width() << " " << rcBody.Height() << " re\nW\nn\n";
593                     sAppStream << sBody.GetByteString() << "Q\nEMC\n";
594                 }
595             }
596             break;
597     }
598     if (pNormalStream) {
599         pNormalStream->SetData((FX_BYTE*)sAppStream.GetBuffer(), sAppStream.GetSize(), FALSE, FALSE);
600         pStreamDict = pNormalStream->GetDict();
601         if (pStreamDict) {
602             pStreamDict->SetAtMatrix("Matrix", matrix);
603             pStreamDict->SetAtRect("BBox", rcBBox);
604             CPDF_Dictionary* pStreamResList = pStreamDict->GetDict("Resources");
605             if (pStreamResList) {
606                 CPDF_Dictionary* pStreamResFontList = pStreamResList->GetDict("Font");
607                 if (!pStreamResFontList) {
608                     pStreamResFontList = CPDF_Dictionary::Create();
609                     if (pStreamResFontList == NULL) {
610                         return FALSE;
611                     }
612                     pStreamResList->SetAt("Font", pStreamResFontList);
613                 }
614                 if (!pStreamResFontList->KeyExist(sFontName)) {
615                     pStreamResFontList->SetAtReference(sFontName, pDoc, pFontDict);
616                 }
617             } else {
618                 pStreamDict->SetAt("Resources", pFormDict->GetDict("DR")->Clone());
619                 pStreamResList = pStreamDict->GetDict("Resources");
620             }
621         }
622     }
623     return TRUE;
624 }
GenerateTextFieldAP(CPDF_Document * pDoc,CPDF_Dictionary * pAnnotDict)625 FX_BOOL CPVT_GenerateAP::GenerateTextFieldAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict)
626 {
627     return GenerateWidgetAP(pDoc, pAnnotDict, 0);
628 }
GenerateComboBoxAP(CPDF_Document * pDoc,CPDF_Dictionary * pAnnotDict)629 FX_BOOL CPVT_GenerateAP::GenerateComboBoxAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict)
630 {
631     return GenerateWidgetAP(pDoc, pAnnotDict, 1);
632 }
GenerateListBoxAP(CPDF_Document * pDoc,CPDF_Dictionary * pAnnotDict)633 FX_BOOL CPVT_GenerateAP::GenerateListBoxAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict)
634 {
635     return GenerateWidgetAP(pDoc, pAnnotDict, 2);
636 }
GenerateEditAP(IPVT_FontMap * pFontMap,IPDF_VariableText_Iterator * pIterator,const CPDF_Point & ptOffset,FX_BOOL bContinuous,FX_WORD SubWord,const CPVT_WordRange * pVisible)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)
638 {
639     CFX_ByteTextBuf sEditStream, sLineStream, sWords;
640     CPDF_Point ptOld(0.0f, 0.0f), ptNew(0.0f, 0.0f);
641     FX_INT32 nCurFontIndex = -1;
642     if (pIterator) {
643         if (pVisible) {
644             pIterator->SetAt(pVisible->BeginPos);
645         } else {
646             pIterator->SetAt(0);
647         }
648         CPVT_WordPlace oldplace;
649         while (pIterator->NextWord()) {
650             CPVT_WordPlace place = pIterator->GetAt();
651             if (pVisible && place.WordCmp(pVisible->EndPos) > 0) {
652                 break;
653             }
654             if (bContinuous) {
655                 if (place.LineCmp(oldplace) != 0) {
656                     if (sWords.GetSize() > 0) {
657                         sLineStream << GetWordRenderString(sWords.GetByteString());
658                         sEditStream << sLineStream;
659                         sLineStream.Clear();
660                         sWords.Clear();
661                     }
662                     CPVT_Word word;
663                     if (pIterator->GetWord(word)) {
664                         ptNew = CPDF_Point(word.ptWord.x + ptOffset.x, word.ptWord.y + ptOffset.y);
665                     } else {
666                         CPVT_Line line;
667                         pIterator->GetLine(line);
668                         ptNew = CPDF_Point(line.ptLine.x + ptOffset.x, line.ptLine.y + ptOffset.y);
669                     }
670                     if (ptNew.x != ptOld.x || ptNew.y != ptOld.y) {
671                         sLineStream << ptNew.x - ptOld.x << " " << ptNew.y - ptOld.y << " Td\n";
672                         ptOld = ptNew;
673                     }
674                 }
675                 CPVT_Word word;
676                 if (pIterator->GetWord(word)) {
677                     if (word.nFontIndex != nCurFontIndex) {
678                         if (sWords.GetSize() > 0) {
679                             sLineStream << GetWordRenderString(sWords.GetByteString());
680                             sWords.Clear();
681                         }
682                         sLineStream << GetFontSetString(pFontMap, word.nFontIndex, word.fFontSize);
683                         nCurFontIndex = word.nFontIndex;
684                     }
685                     sWords << GetPDFWordString(pFontMap, nCurFontIndex, word.Word, SubWord);
686                 }
687                 oldplace = place;
688             } else {
689                 CPVT_Word word;
690                 if (pIterator->GetWord(word)) {
691                     ptNew = CPDF_Point(word.ptWord.x + ptOffset.x, word.ptWord.y + ptOffset.y);
692                     if (ptNew.x != ptOld.x || ptNew.y != ptOld.y) {
693                         sEditStream << ptNew.x - ptOld.x << " " << ptNew.y - ptOld.y << " Td\n";
694                         ptOld = ptNew;
695                     }
696                     if (word.nFontIndex != nCurFontIndex) {
697                         sEditStream << GetFontSetString(pFontMap, word.nFontIndex, word.fFontSize);
698                         nCurFontIndex = word.nFontIndex;
699                     }
700                     sEditStream << GetWordRenderString(GetPDFWordString(pFontMap, nCurFontIndex, word.Word, SubWord));
701                 }
702             }
703         }
704         if (sWords.GetSize() > 0) {
705             sLineStream << GetWordRenderString(sWords.GetByteString());
706             sEditStream << sLineStream;
707             sWords.Clear();
708         }
709     }
710     return sEditStream.GetByteString();
711 }
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)712 CFX_ByteString CPVT_GenerateAP::GenerateBorderAP(const CPDF_Rect & rect, FX_FLOAT fWidth,
713         const CPVT_Color & color, const CPVT_Color & crLeftTop, const CPVT_Color & crRightBottom,
714         FX_INT32 nStyle, const CPVT_Dash & dash)
715 {
716     CFX_ByteTextBuf sAppStream;
717     CFX_ByteString sColor;
718     FX_FLOAT fLeft = rect.left;
719     FX_FLOAT fRight = rect.right;
720     FX_FLOAT fTop = rect.top;
721     FX_FLOAT fBottom = rect.bottom;
722     if (fWidth > 0.0f) {
723         FX_FLOAT fHalfWidth = fWidth / 2.0f;
724         switch (nStyle) {
725             default:
726             case PBS_SOLID:
727                 sColor = GenerateColorAP(color, TRUE);
728                 if (sColor.GetLength() > 0) {
729                     sAppStream << sColor;
730                     sAppStream << fLeft << " " << fBottom << " " << fRight - fLeft << " " << fTop - fBottom << " re\n";
731                     sAppStream << fLeft + fWidth << " " << fBottom + fWidth << " "
732                                << fRight - fLeft - fWidth * 2 << " " << fTop - fBottom - fWidth * 2 << " re\n";
733                     sAppStream << "f*\n";
734                 }
735                 break;
736             case PBS_DASH:
737                 sColor = GenerateColorAP(color, FALSE);
738                 if (sColor.GetLength() > 0) {
739                     sAppStream << sColor;
740                     sAppStream << fWidth << " w" << " [" << dash.nDash << " " << dash.nGap << "] " << dash.nPhase << " d\n";
741                     sAppStream << fLeft + fWidth / 2 << " " << fBottom + fWidth / 2 << " m\n";
742                     sAppStream << fLeft + fWidth / 2 << " " << fTop - fWidth / 2 << " l\n";
743                     sAppStream << fRight - fWidth / 2 << " " << fTop - fWidth / 2 << " l\n";
744                     sAppStream << fRight - fWidth / 2 << " " << fBottom + fWidth / 2 << " l\n";
745                     sAppStream << fLeft + fWidth / 2 << " " << fBottom + fWidth / 2 << " l S\n";
746                 }
747                 break;
748             case PBS_BEVELED:
749             case PBS_INSET:
750                 sColor = GenerateColorAP(crLeftTop, TRUE);
751                 if (sColor.GetLength() > 0) {
752                     sAppStream << sColor;
753                     sAppStream << fLeft + fHalfWidth << " " << fBottom + fHalfWidth << " m\n";
754                     sAppStream << fLeft + fHalfWidth << " " << fTop - fHalfWidth << " l\n";
755                     sAppStream << fRight - fHalfWidth << " " << fTop - fHalfWidth << " l\n";
756                     sAppStream << fRight - fHalfWidth * 2 << " " << fTop - fHalfWidth * 2 << " l\n";
757                     sAppStream << fLeft + fHalfWidth * 2 << " " << fTop - fHalfWidth * 2 << " l\n";
758                     sAppStream << fLeft + fHalfWidth * 2 << " " << fBottom + fHalfWidth * 2 << " l f\n";
759                 }
760                 sColor = GenerateColorAP(crRightBottom, TRUE);
761                 if (sColor.GetLength() > 0) {
762                     sAppStream << sColor;
763                     sAppStream << fRight - fHalfWidth << " " <<	fTop - fHalfWidth << " m\n";
764                     sAppStream << fRight - fHalfWidth << " " <<	fBottom + fHalfWidth << " l\n";
765                     sAppStream << fLeft + fHalfWidth << " " << 	fBottom + fHalfWidth << " l\n";
766                     sAppStream << fLeft + fHalfWidth * 2 << " " << fBottom + fHalfWidth * 2 << " l\n";
767                     sAppStream << fRight - fHalfWidth * 2 << " " << fBottom + fHalfWidth * 2 << " l\n";
768                     sAppStream << fRight - fHalfWidth * 2 << " " << fTop - fHalfWidth * 2 << " l f\n";
769                 }
770                 sColor = GenerateColorAP(color, TRUE);
771                 if (sColor.GetLength() > 0) {
772                     sAppStream << sColor;
773                     sAppStream << fLeft << " " << fBottom << " " <<	fRight - fLeft << " " << fTop - fBottom << " re\n";
774                     sAppStream << fLeft + fHalfWidth << " " << fBottom + fHalfWidth << " "
775                                << fRight - fLeft - fHalfWidth * 2 << " " << fTop - fBottom - fHalfWidth * 2 << " re f*\n";
776                 }
777                 break;
778             case PBS_UNDERLINED:
779                 sColor = GenerateColorAP(color, FALSE);
780                 if (sColor.GetLength() > 0) {
781                     sAppStream << sColor;
782                     sAppStream << fWidth << " w\n";
783                     sAppStream << fLeft << " " << fBottom + fWidth / 2 << " m\n";
784                     sAppStream << fRight << " " << fBottom + fWidth / 2 << " l S\n";
785                 }
786                 break;
787         }
788     }
789     return sAppStream.GetByteString();
790 }
GenerateColorAP(const CPVT_Color & color,const FX_BOOL & bFillOrStroke)791 CFX_ByteString CPVT_GenerateAP::GenerateColorAP(const CPVT_Color & color, const FX_BOOL & bFillOrStroke)
792 {
793     CFX_ByteTextBuf sColorStream;
794     switch (color.nColorType) {
795         case CT_RGB:
796             sColorStream << color.fColor1 << " " << color.fColor2 << " " << color.fColor3 << " "
797                          << (bFillOrStroke ? "rg" : "RG") << "\n";
798             break;
799         case CT_GRAY:
800             sColorStream << color.fColor1 << " " << (bFillOrStroke ? "g" : "G") << "\n";
801             break;
802         case CT_CMYK:
803             sColorStream << color.fColor1 << " " << color.fColor2 << " " << color.fColor3 << " " << color.fColor4 << " "
804                          << (bFillOrStroke ? "k" : "K") << "\n";
805             break;
806     }
807     return sColorStream.GetByteString();
808 }
809