Home | History | Annotate | Download | only in fpdfdoc
      1 // Copyright 2014 PDFium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
      6 
      7 #include "../../include/fpdfdoc/fpdf_doc.h"
      8 #include "../../include/fpdfdoc/fpdf_vt.h"
      9 #include "pdf_vt.h"
     10 #include "../../include/fpdfdoc/fpdf_ap.h"
     11 FX_BOOL FPDF_GenerateAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict)
     12 {
     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 };
     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 }
     67 CPVT_FontMap::~CPVT_FontMap()
     68 {
     69 }
     70 extern CPDF_Font*		AddNativeInterFormFont(CPDF_Dictionary*& pFormDict, CPDF_Document* pDocument, CFX_ByteString& csNameTag);
     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 }
     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 }
    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 }
    113 CPVT_Provider::CPVT_Provider(IPVT_FontMap * pFontMap) : m_pFontMap(pFontMap)
    114 {
    115     ASSERT (m_pFontMap != NULL);
    116 }
    117 CPVT_Provider::~CPVT_Provider()
    118 {
    119 }
    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 }
    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 }
    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 }
    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 }
    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 }
    164 FX_INT32 CPVT_Provider::GetDefaultFontIndex()
    165 {
    166     return 0;
    167 }
    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 }
    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 }
    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 }
    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 }
    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 }
    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 }
    625 FX_BOOL CPVT_GenerateAP::GenerateTextFieldAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict)
    626 {
    627     return GenerateWidgetAP(pDoc, pAnnotDict, 0);
    628 }
    629 FX_BOOL CPVT_GenerateAP::GenerateComboBoxAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict)
    630 {
    631     return GenerateWidgetAP(pDoc, pAnnotDict, 1);
    632 }
    633 FX_BOOL CPVT_GenerateAP::GenerateListBoxAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict)
    634 {
    635     return GenerateWidgetAP(pDoc, pAnnotDict, 2);
    636 }
    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 }
    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 }
    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