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