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