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"
11FX_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}
39class CPVT_FontMap : public IPVT_FontMap
40{
41public:
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);
49private:
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};
57CPVT_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}
67CPVT_FontMap::~CPVT_FontMap()
68{
69}
70extern CPDF_Font*		AddNativeInterFormFont(CPDF_Dictionary*& pFormDict, CPDF_Document* pDocument, CFX_ByteString& csNameTag);
71void 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}
87CPDF_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}
100CFX_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}
113CPVT_Provider::CPVT_Provider(IPVT_FontMap * pFontMap) : m_pFontMap(pFontMap)
114{
115    ASSERT (m_pFontMap != NULL);
116}
117CPVT_Provider::~CPVT_Provider()
118{
119}
120FX_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}
130FX_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}
137FX_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}
144FX_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}
157FX_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}
164FX_INT32 CPVT_Provider::GetDefaultFontIndex()
165{
166    return 0;
167}
168static 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}
189static CFX_ByteString GetWordRenderString(const CFX_ByteString & strWords)
190{
191    if (strWords.GetLength() > 0) {
192        return PDF_EncodeString(strWords) + " Tj\n";
193    }
194    return "";
195}
196static 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}
207static 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}
231static 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}
247static 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}
625FX_BOOL CPVT_GenerateAP::GenerateTextFieldAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict)
626{
627    return GenerateWidgetAP(pDoc, pAnnotDict, 0);
628}
629FX_BOOL CPVT_GenerateAP::GenerateComboBoxAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict)
630{
631    return GenerateWidgetAP(pDoc, pAnnotDict, 1);
632}
633FX_BOOL CPVT_GenerateAP::GenerateListBoxAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict)
634{
635    return GenerateWidgetAP(pDoc, pAnnotDict, 2);
636}
637CFX_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}
712CFX_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}
791CFX_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