Home | History | Annotate | Download | only in fpdfdoc
      1 // Copyright 2016 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/fpdfdoc/cpvt_generateap.h"
      8 
      9 #include <algorithm>
     10 #include <memory>
     11 #include <utility>
     12 
     13 #include "core/fpdfapi/font/cpdf_font.h"
     14 #include "core/fpdfapi/parser/cpdf_boolean.h"
     15 #include "core/fpdfapi/parser/cpdf_dictionary.h"
     16 #include "core/fpdfapi/parser/cpdf_document.h"
     17 #include "core/fpdfapi/parser/cpdf_name.h"
     18 #include "core/fpdfapi/parser/cpdf_number.h"
     19 #include "core/fpdfapi/parser/cpdf_reference.h"
     20 #include "core/fpdfapi/parser/cpdf_simple_parser.h"
     21 #include "core/fpdfapi/parser/cpdf_stream.h"
     22 #include "core/fpdfapi/parser/cpdf_string.h"
     23 #include "core/fpdfapi/parser/fpdf_parser_decode.h"
     24 #include "core/fpdfdoc/cpdf_annot.h"
     25 #include "core/fpdfdoc/cpdf_formfield.h"
     26 #include "core/fpdfdoc/cpvt_color.h"
     27 #include "core/fpdfdoc/cpvt_fontmap.h"
     28 #include "core/fpdfdoc/cpvt_word.h"
     29 #include "third_party/base/ptr_util.h"
     30 
     31 namespace {
     32 
     33 bool GenerateWidgetAP(CPDF_Document* pDoc,
     34                       CPDF_Dictionary* pAnnotDict,
     35                       const int32_t& nWidgetType) {
     36   CPDF_Dictionary* pFormDict = nullptr;
     37   if (CPDF_Dictionary* pRootDict = pDoc->GetRoot())
     38     pFormDict = pRootDict->GetDictFor("AcroForm");
     39   if (!pFormDict)
     40     return false;
     41 
     42   CFX_ByteString DA;
     43   if (CPDF_Object* pDAObj = FPDF_GetFieldAttr(pAnnotDict, "DA"))
     44     DA = pDAObj->GetString();
     45   if (DA.IsEmpty())
     46     DA = pFormDict->GetStringFor("DA");
     47   if (DA.IsEmpty())
     48     return false;
     49 
     50   CPDF_SimpleParser syntax(DA.AsStringC());
     51   syntax.FindTagParamFromStart("Tf", 2);
     52   CFX_ByteString sFontName(syntax.GetWord());
     53   sFontName = PDF_NameDecode(sFontName);
     54   if (sFontName.IsEmpty())
     55     return false;
     56 
     57   FX_FLOAT fFontSize = FX_atof(syntax.GetWord());
     58   CPVT_Color crText = CPVT_Color::ParseColor(DA);
     59   CPDF_Dictionary* pDRDict = pFormDict->GetDictFor("DR");
     60   if (!pDRDict)
     61     return false;
     62 
     63   CPDF_Dictionary* pDRFontDict = pDRDict->GetDictFor("Font");
     64   if (!pDRFontDict)
     65     return false;
     66 
     67   CPDF_Dictionary* pFontDict = pDRFontDict->GetDictFor(sFontName.Mid(1));
     68   if (!pFontDict) {
     69     pFontDict = pDoc->NewIndirect<CPDF_Dictionary>();
     70     pFontDict->SetNewFor<CPDF_Name>("Type", "Font");
     71     pFontDict->SetNewFor<CPDF_Name>("Subtype", "Type1");
     72     pFontDict->SetNewFor<CPDF_Name>("BaseFont", "Helvetica");
     73     pFontDict->SetNewFor<CPDF_Name>("Encoding", "WinAnsiEncoding");
     74     pDRFontDict->SetNewFor<CPDF_Reference>(sFontName.Mid(1), pDoc,
     75                                            pFontDict->GetObjNum());
     76   }
     77   CPDF_Font* pDefFont = pDoc->LoadFont(pFontDict);
     78   if (!pDefFont)
     79     return false;
     80 
     81   CFX_FloatRect rcAnnot = pAnnotDict->GetRectFor("Rect");
     82   int32_t nRotate = 0;
     83   if (CPDF_Dictionary* pMKDict = pAnnotDict->GetDictFor("MK"))
     84     nRotate = pMKDict->GetIntegerFor("R");
     85 
     86   CFX_FloatRect rcBBox;
     87   CFX_Matrix matrix;
     88   switch (nRotate % 360) {
     89     case 0:
     90       rcBBox = CFX_FloatRect(0, 0, rcAnnot.right - rcAnnot.left,
     91                              rcAnnot.top - rcAnnot.bottom);
     92       break;
     93     case 90:
     94       matrix = CFX_Matrix(0, 1, -1, 0, rcAnnot.right - rcAnnot.left, 0);
     95       rcBBox = CFX_FloatRect(0, 0, rcAnnot.top - rcAnnot.bottom,
     96                              rcAnnot.right - rcAnnot.left);
     97       break;
     98     case 180:
     99       matrix = CFX_Matrix(-1, 0, 0, -1, rcAnnot.right - rcAnnot.left,
    100                           rcAnnot.top - rcAnnot.bottom);
    101       rcBBox = CFX_FloatRect(0, 0, rcAnnot.right - rcAnnot.left,
    102                              rcAnnot.top - rcAnnot.bottom);
    103       break;
    104     case 270:
    105       matrix = CFX_Matrix(0, -1, 1, 0, 0, rcAnnot.top - rcAnnot.bottom);
    106       rcBBox = CFX_FloatRect(0, 0, rcAnnot.top - rcAnnot.bottom,
    107                              rcAnnot.right - rcAnnot.left);
    108       break;
    109   }
    110 
    111   BorderStyle nBorderStyle = BorderStyle::SOLID;
    112   FX_FLOAT fBorderWidth = 1;
    113   CPVT_Dash dsBorder(3, 0, 0);
    114   CPVT_Color crLeftTop, crRightBottom;
    115   if (CPDF_Dictionary* pBSDict = pAnnotDict->GetDictFor("BS")) {
    116     if (pBSDict->KeyExist("W"))
    117       fBorderWidth = pBSDict->GetNumberFor("W");
    118 
    119     if (CPDF_Array* pArray = pBSDict->GetArrayFor("D")) {
    120       dsBorder = CPVT_Dash(pArray->GetIntegerAt(0), pArray->GetIntegerAt(1),
    121                            pArray->GetIntegerAt(2));
    122     }
    123     switch (pBSDict->GetStringFor("S").GetAt(0)) {
    124       case 'S':
    125         nBorderStyle = BorderStyle::SOLID;
    126         break;
    127       case 'D':
    128         nBorderStyle = BorderStyle::DASH;
    129         break;
    130       case 'B':
    131         nBorderStyle = BorderStyle::BEVELED;
    132         fBorderWidth *= 2;
    133         crLeftTop = CPVT_Color(CPVT_Color::kGray, 1);
    134         crRightBottom = CPVT_Color(CPVT_Color::kGray, 0.5);
    135         break;
    136       case 'I':
    137         nBorderStyle = BorderStyle::INSET;
    138         fBorderWidth *= 2;
    139         crLeftTop = CPVT_Color(CPVT_Color::kGray, 0.5);
    140         crRightBottom = CPVT_Color(CPVT_Color::kGray, 0.75);
    141         break;
    142       case 'U':
    143         nBorderStyle = BorderStyle::UNDERLINE;
    144         break;
    145     }
    146   }
    147   CPVT_Color crBorder, crBG;
    148   if (CPDF_Dictionary* pMKDict = pAnnotDict->GetDictFor("MK")) {
    149     if (CPDF_Array* pArray = pMKDict->GetArrayFor("BC"))
    150       crBorder = CPVT_Color::ParseColor(*pArray);
    151     if (CPDF_Array* pArray = pMKDict->GetArrayFor("BG"))
    152       crBG = CPVT_Color::ParseColor(*pArray);
    153   }
    154   CFX_ByteTextBuf sAppStream;
    155   CFX_ByteString sBG =
    156       CPVT_GenerateAP::GenerateColorAP(crBG, PaintOperation::FILL);
    157   if (sBG.GetLength() > 0) {
    158     sAppStream << "q\n" << sBG << rcBBox.left << " " << rcBBox.bottom << " "
    159                << rcBBox.Width() << " " << rcBBox.Height() << " re f\n"
    160                << "Q\n";
    161   }
    162   CFX_ByteString sBorderStream = CPVT_GenerateAP::GenerateBorderAP(
    163       rcBBox, fBorderWidth, crBorder, crLeftTop, crRightBottom, nBorderStyle,
    164       dsBorder);
    165   if (sBorderStream.GetLength() > 0)
    166     sAppStream << "q\n" << sBorderStream << "Q\n";
    167 
    168   CFX_FloatRect rcBody =
    169       CFX_FloatRect(rcBBox.left + fBorderWidth, rcBBox.bottom + fBorderWidth,
    170                     rcBBox.right - fBorderWidth, rcBBox.top - fBorderWidth);
    171   rcBody.Normalize();
    172 
    173   CPDF_Dictionary* pAPDict = pAnnotDict->GetDictFor("AP");
    174   if (!pAPDict)
    175     pAPDict = pAnnotDict->SetNewFor<CPDF_Dictionary>("AP");
    176 
    177   CPDF_Stream* pNormalStream = pAPDict->GetStreamFor("N");
    178   if (!pNormalStream) {
    179     pNormalStream = pDoc->NewIndirect<CPDF_Stream>();
    180     pAPDict->SetNewFor<CPDF_Reference>("N", pDoc, pNormalStream->GetObjNum());
    181   }
    182   CPDF_Dictionary* pStreamDict = pNormalStream->GetDict();
    183   if (pStreamDict) {
    184     pStreamDict->SetMatrixFor("Matrix", matrix);
    185     pStreamDict->SetRectFor("BBox", rcBBox);
    186     CPDF_Dictionary* pStreamResList = pStreamDict->GetDictFor("Resources");
    187     if (pStreamResList) {
    188       CPDF_Dictionary* pStreamResFontList = pStreamResList->GetDictFor("Font");
    189       if (!pStreamResFontList)
    190         pStreamResFontList = pStreamResList->SetNewFor<CPDF_Dictionary>("Font");
    191       if (!pStreamResFontList->KeyExist(sFontName)) {
    192         pStreamResFontList->SetNewFor<CPDF_Reference>(sFontName, pDoc,
    193                                                       pFontDict->GetObjNum());
    194       }
    195     } else {
    196       pStreamDict->SetFor("Resources", pFormDict->GetDictFor("DR")->Clone());
    197       pStreamResList = pStreamDict->GetDictFor("Resources");
    198     }
    199   }
    200   switch (nWidgetType) {
    201     case 0: {
    202       CFX_WideString swValue =
    203           FPDF_GetFieldAttr(pAnnotDict, "V")
    204               ? FPDF_GetFieldAttr(pAnnotDict, "V")->GetUnicodeText()
    205               : CFX_WideString();
    206       int32_t nAlign = FPDF_GetFieldAttr(pAnnotDict, "Q")
    207                            ? FPDF_GetFieldAttr(pAnnotDict, "Q")->GetInteger()
    208                            : 0;
    209       uint32_t dwFlags = FPDF_GetFieldAttr(pAnnotDict, "Ff")
    210                              ? FPDF_GetFieldAttr(pAnnotDict, "Ff")->GetInteger()
    211                              : 0;
    212       uint32_t dwMaxLen =
    213           FPDF_GetFieldAttr(pAnnotDict, "MaxLen")
    214               ? FPDF_GetFieldAttr(pAnnotDict, "MaxLen")->GetInteger()
    215               : 0;
    216       CPVT_FontMap map(
    217           pDoc, pStreamDict ? pStreamDict->GetDictFor("Resources") : nullptr,
    218           pDefFont, sFontName.Right(sFontName.GetLength() - 1));
    219       CPDF_VariableText::Provider prd(&map);
    220       CPDF_VariableText vt;
    221       vt.SetProvider(&prd);
    222       vt.SetPlateRect(rcBody);
    223       vt.SetAlignment(nAlign);
    224       if (IsFloatZero(fFontSize))
    225         vt.SetAutoFontSize(true);
    226       else
    227         vt.SetFontSize(fFontSize);
    228 
    229       bool bMultiLine = (dwFlags >> 12) & 1;
    230       if (bMultiLine) {
    231         vt.SetMultiLine(true);
    232         vt.SetAutoReturn(true);
    233       }
    234       uint16_t subWord = 0;
    235       if ((dwFlags >> 13) & 1) {
    236         subWord = '*';
    237         vt.SetPasswordChar(subWord);
    238       }
    239       bool bCharArray = (dwFlags >> 24) & 1;
    240       if (bCharArray)
    241         vt.SetCharArray(dwMaxLen);
    242       else
    243         vt.SetLimitChar(dwMaxLen);
    244 
    245       vt.Initialize();
    246       vt.SetText(swValue);
    247       vt.RearrangeAll();
    248       CFX_FloatRect rcContent = vt.GetContentRect();
    249       CFX_PointF ptOffset;
    250       if (!bMultiLine) {
    251         ptOffset =
    252             CFX_PointF(0.0f, (rcContent.Height() - rcBody.Height()) / 2.0f);
    253       }
    254       CFX_ByteString sBody = CPVT_GenerateAP::GenerateEditAP(
    255           &map, vt.GetIterator(), ptOffset, !bCharArray, subWord);
    256       if (sBody.GetLength() > 0) {
    257         sAppStream << "/Tx BMC\n"
    258                    << "q\n";
    259         if (rcContent.Width() > rcBody.Width() ||
    260             rcContent.Height() > rcBody.Height()) {
    261           sAppStream << rcBody.left << " " << rcBody.bottom << " "
    262                      << rcBody.Width() << " " << rcBody.Height()
    263                      << " re\nW\nn\n";
    264         }
    265         sAppStream << "BT\n"
    266                    << CPVT_GenerateAP::GenerateColorAP(crText,
    267                                                        PaintOperation::FILL)
    268                    << sBody << "ET\n"
    269                    << "Q\nEMC\n";
    270       }
    271     } break;
    272     case 1: {
    273       CFX_WideString swValue =
    274           FPDF_GetFieldAttr(pAnnotDict, "V")
    275               ? FPDF_GetFieldAttr(pAnnotDict, "V")->GetUnicodeText()
    276               : CFX_WideString();
    277       CPVT_FontMap map(
    278           pDoc, pStreamDict ? pStreamDict->GetDictFor("Resources") : nullptr,
    279           pDefFont, sFontName.Right(sFontName.GetLength() - 1));
    280       CPDF_VariableText::Provider prd(&map);
    281       CPDF_VariableText vt;
    282       vt.SetProvider(&prd);
    283       CFX_FloatRect rcButton = rcBody;
    284       rcButton.left = rcButton.right - 13;
    285       rcButton.Normalize();
    286       CFX_FloatRect rcEdit = rcBody;
    287       rcEdit.right = rcButton.left;
    288       rcEdit.Normalize();
    289       vt.SetPlateRect(rcEdit);
    290       if (IsFloatZero(fFontSize))
    291         vt.SetAutoFontSize(true);
    292       else
    293         vt.SetFontSize(fFontSize);
    294 
    295       vt.Initialize();
    296       vt.SetText(swValue);
    297       vt.RearrangeAll();
    298       CFX_FloatRect rcContent = vt.GetContentRect();
    299       CFX_PointF ptOffset =
    300           CFX_PointF(0.0f, (rcContent.Height() - rcEdit.Height()) / 2.0f);
    301       CFX_ByteString sEdit = CPVT_GenerateAP::GenerateEditAP(
    302           &map, vt.GetIterator(), ptOffset, true, 0);
    303       if (sEdit.GetLength() > 0) {
    304         sAppStream << "/Tx BMC\n"
    305                    << "q\n";
    306         sAppStream << rcEdit.left << " " << rcEdit.bottom << " "
    307                    << rcEdit.Width() << " " << rcEdit.Height() << " re\nW\nn\n";
    308         sAppStream << "BT\n"
    309                    << CPVT_GenerateAP::GenerateColorAP(crText,
    310                                                        PaintOperation::FILL)
    311                    << sEdit << "ET\n"
    312                    << "Q\nEMC\n";
    313       }
    314       CFX_ByteString sButton = CPVT_GenerateAP::GenerateColorAP(
    315           CPVT_Color(CPVT_Color::kRGB, 220.0f / 255.0f, 220.0f / 255.0f,
    316                      220.0f / 255.0f),
    317           PaintOperation::FILL);
    318       if (sButton.GetLength() > 0 && !rcButton.IsEmpty()) {
    319         sAppStream << "q\n" << sButton;
    320         sAppStream << rcButton.left << " " << rcButton.bottom << " "
    321                    << rcButton.Width() << " " << rcButton.Height() << " re f\n";
    322         sAppStream << "Q\n";
    323         CFX_ByteString sButtonBorder = CPVT_GenerateAP::GenerateBorderAP(
    324             rcButton, 2, CPVT_Color(CPVT_Color::kGray, 0),
    325             CPVT_Color(CPVT_Color::kGray, 1),
    326             CPVT_Color(CPVT_Color::kGray, 0.5), BorderStyle::BEVELED,
    327             CPVT_Dash(3, 0, 0));
    328         if (sButtonBorder.GetLength() > 0)
    329           sAppStream << "q\n" << sButtonBorder << "Q\n";
    330 
    331         CFX_PointF ptCenter = CFX_PointF((rcButton.left + rcButton.right) / 2,
    332                                          (rcButton.top + rcButton.bottom) / 2);
    333         if (IsFloatBigger(rcButton.Width(), 6) &&
    334             IsFloatBigger(rcButton.Height(), 6)) {
    335           sAppStream << "q\n"
    336                      << " 0 g\n";
    337           sAppStream << ptCenter.x - 3 << " " << ptCenter.y + 1.5f << " m\n";
    338           sAppStream << ptCenter.x + 3 << " " << ptCenter.y + 1.5f << " l\n";
    339           sAppStream << ptCenter.x << " " << ptCenter.y - 1.5f << " l\n";
    340           sAppStream << ptCenter.x - 3 << " " << ptCenter.y + 1.5f << " l f\n";
    341           sAppStream << sButton << "Q\n";
    342         }
    343       }
    344     } break;
    345     case 2: {
    346       CPVT_FontMap map(
    347           pDoc, pStreamDict ? pStreamDict->GetDictFor("Resources") : nullptr,
    348           pDefFont, sFontName.Right(sFontName.GetLength() - 1));
    349       CPDF_VariableText::Provider prd(&map);
    350       CPDF_Array* pOpts = ToArray(FPDF_GetFieldAttr(pAnnotDict, "Opt"));
    351       CPDF_Array* pSels = ToArray(FPDF_GetFieldAttr(pAnnotDict, "I"));
    352       CPDF_Object* pTi = FPDF_GetFieldAttr(pAnnotDict, "TI");
    353       int32_t nTop = pTi ? pTi->GetInteger() : 0;
    354       CFX_ByteTextBuf sBody;
    355       if (pOpts) {
    356         FX_FLOAT fy = rcBody.top;
    357         for (size_t i = nTop, sz = pOpts->GetCount(); i < sz; i++) {
    358           if (IsFloatSmaller(fy, rcBody.bottom))
    359             break;
    360 
    361           if (CPDF_Object* pOpt = pOpts->GetDirectObjectAt(i)) {
    362             CFX_WideString swItem;
    363             if (pOpt->IsString())
    364               swItem = pOpt->GetUnicodeText();
    365             else if (CPDF_Array* pArray = pOpt->AsArray())
    366               swItem = pArray->GetDirectObjectAt(1)->GetUnicodeText();
    367 
    368             bool bSelected = false;
    369             if (pSels) {
    370               for (size_t s = 0, ssz = pSels->GetCount(); s < ssz; s++) {
    371                 int value = pSels->GetIntegerAt(s);
    372                 if (value >= 0 && i == static_cast<size_t>(value)) {
    373                   bSelected = true;
    374                   break;
    375                 }
    376               }
    377             }
    378             CPDF_VariableText vt;
    379             vt.SetProvider(&prd);
    380             vt.SetPlateRect(
    381                 CFX_FloatRect(rcBody.left, 0.0f, rcBody.right, 0.0f));
    382             vt.SetFontSize(IsFloatZero(fFontSize) ? 12.0f : fFontSize);
    383 
    384             vt.Initialize();
    385             vt.SetText(swItem);
    386             vt.RearrangeAll();
    387             FX_FLOAT fItemHeight = vt.GetContentRect().Height();
    388             if (bSelected) {
    389               CFX_FloatRect rcItem = CFX_FloatRect(
    390                   rcBody.left, fy - fItemHeight, rcBody.right, fy);
    391               sBody << "q\n"
    392                     << CPVT_GenerateAP::GenerateColorAP(
    393                            CPVT_Color(CPVT_Color::kRGB, 0, 51.0f / 255.0f,
    394                                       113.0f / 255.0f),
    395                            PaintOperation::FILL)
    396                     << rcItem.left << " " << rcItem.bottom << " "
    397                     << rcItem.Width() << " " << rcItem.Height() << " re f\n"
    398                     << "Q\n";
    399               sBody << "BT\n"
    400                     << CPVT_GenerateAP::GenerateColorAP(
    401                            CPVT_Color(CPVT_Color::kGray, 1),
    402                            PaintOperation::FILL)
    403                     << CPVT_GenerateAP::GenerateEditAP(&map, vt.GetIterator(),
    404                                                        CFX_PointF(0.0f, fy),
    405                                                        true, 0)
    406                     << "ET\n";
    407             } else {
    408               sBody << "BT\n"
    409                     << CPVT_GenerateAP::GenerateColorAP(crText,
    410                                                         PaintOperation::FILL)
    411                     << CPVT_GenerateAP::GenerateEditAP(&map, vt.GetIterator(),
    412                                                        CFX_PointF(0.0f, fy),
    413                                                        true, 0)
    414                     << "ET\n";
    415             }
    416             fy -= fItemHeight;
    417           }
    418         }
    419       }
    420       if (sBody.GetSize() > 0) {
    421         sAppStream << "/Tx BMC\nq\n"
    422                    << rcBody.left << " " << rcBody.bottom << " "
    423                    << rcBody.Width() << " " << rcBody.Height() << " re\nW\nn\n"
    424                    << sBody.AsStringC() << "Q\nEMC\n";
    425       }
    426     } break;
    427   }
    428   if (pNormalStream) {
    429     pNormalStream->SetData(sAppStream.GetBuffer(), sAppStream.GetSize());
    430     pStreamDict = pNormalStream->GetDict();
    431     if (pStreamDict) {
    432       pStreamDict->SetMatrixFor("Matrix", matrix);
    433       pStreamDict->SetRectFor("BBox", rcBBox);
    434       CPDF_Dictionary* pStreamResList = pStreamDict->GetDictFor("Resources");
    435       if (pStreamResList) {
    436         CPDF_Dictionary* pStreamResFontList =
    437             pStreamResList->GetDictFor("Font");
    438         if (!pStreamResFontList) {
    439           pStreamResFontList =
    440               pStreamResList->SetNewFor<CPDF_Dictionary>("Font");
    441         }
    442         if (!pStreamResFontList->KeyExist(sFontName)) {
    443           pStreamResFontList->SetNewFor<CPDF_Reference>(sFontName, pDoc,
    444                                                         pFontDict->GetObjNum());
    445         }
    446       } else {
    447         pStreamDict->SetFor("Resources", pFormDict->GetDictFor("DR")->Clone());
    448         pStreamResList = pStreamDict->GetDictFor("Resources");
    449       }
    450     }
    451   }
    452   return true;
    453 }
    454 
    455 CFX_ByteString GetColorStringWithDefault(CPDF_Array* pColor,
    456                                          const CPVT_Color& crDefaultColor,
    457                                          PaintOperation nOperation) {
    458   if (pColor) {
    459     CPVT_Color color = CPVT_Color::ParseColor(*pColor);
    460     return CPVT_GenerateAP::GenerateColorAP(color, nOperation);
    461   }
    462 
    463   return CPVT_GenerateAP::GenerateColorAP(crDefaultColor, nOperation);
    464 }
    465 
    466 FX_FLOAT GetBorderWidth(const CPDF_Dictionary& pAnnotDict) {
    467   if (CPDF_Dictionary* pBorderStyleDict = pAnnotDict.GetDictFor("BS")) {
    468     if (pBorderStyleDict->KeyExist("W"))
    469       return pBorderStyleDict->GetNumberFor("W");
    470   }
    471 
    472   if (CPDF_Array* pBorderArray = pAnnotDict.GetArrayFor("Border")) {
    473     if (pBorderArray->GetCount() > 2)
    474       return pBorderArray->GetNumberAt(2);
    475   }
    476 
    477   return 1;
    478 }
    479 
    480 CPDF_Array* GetDashArray(const CPDF_Dictionary& pAnnotDict) {
    481   if (CPDF_Dictionary* pBorderStyleDict = pAnnotDict.GetDictFor("BS")) {
    482     if (pBorderStyleDict->GetStringFor("S") == "D")
    483       return pBorderStyleDict->GetArrayFor("D");
    484   }
    485 
    486   if (CPDF_Array* pBorderArray = pAnnotDict.GetArrayFor("Border")) {
    487     if (pBorderArray->GetCount() == 4)
    488       return pBorderArray->GetArrayAt(3);
    489   }
    490 
    491   return nullptr;
    492 }
    493 
    494 CFX_ByteString GetDashPatternString(const CPDF_Dictionary& pAnnotDict) {
    495   CPDF_Array* pDashArray = GetDashArray(pAnnotDict);
    496   if (!pDashArray || pDashArray->IsEmpty())
    497     return CFX_ByteString();
    498 
    499   // Support maximum of ten elements in the dash array.
    500   size_t pDashArrayCount = std::min<size_t>(pDashArray->GetCount(), 10);
    501   CFX_ByteTextBuf sDashStream;
    502 
    503   sDashStream << "[";
    504   for (size_t i = 0; i < pDashArrayCount; ++i)
    505     sDashStream << pDashArray->GetNumberAt(i) << " ";
    506   sDashStream << "] 0 d\n";
    507 
    508   return sDashStream.MakeString();
    509 }
    510 
    511 CFX_ByteString GetPopupContentsString(CPDF_Document* pDoc,
    512                                       const CPDF_Dictionary& pAnnotDict,
    513                                       CPDF_Font* pDefFont,
    514                                       const CFX_ByteString& sFontName) {
    515   CFX_WideString swValue(pAnnotDict.GetUnicodeTextFor("T"));
    516   swValue += L'\n';
    517   swValue += pAnnotDict.GetUnicodeTextFor("Contents");
    518   CPVT_FontMap map(pDoc, nullptr, pDefFont, sFontName);
    519 
    520   CPDF_VariableText::Provider prd(&map);
    521   CPDF_VariableText vt;
    522   vt.SetProvider(&prd);
    523   vt.SetPlateRect(pAnnotDict.GetRectFor("Rect"));
    524   vt.SetFontSize(12);
    525   vt.SetAutoReturn(true);
    526   vt.SetMultiLine(true);
    527 
    528   vt.Initialize();
    529   vt.SetText(swValue);
    530   vt.RearrangeAll();
    531   CFX_PointF ptOffset(3.0f, -3.0f);
    532   CFX_ByteString sContent = CPVT_GenerateAP::GenerateEditAP(
    533       &map, vt.GetIterator(), ptOffset, false, 0);
    534 
    535   if (sContent.IsEmpty())
    536     return CFX_ByteString();
    537 
    538   CFX_ByteTextBuf sAppStream;
    539   sAppStream << "BT\n"
    540              << CPVT_GenerateAP::GenerateColorAP(
    541                     CPVT_Color(CPVT_Color::kRGB, 0, 0, 0), PaintOperation::FILL)
    542              << sContent << "ET\n"
    543              << "Q\n";
    544   return sAppStream.MakeString();
    545 }
    546 
    547 std::unique_ptr<CPDF_Dictionary> GenerateExtGStateDict(
    548     const CPDF_Dictionary& pAnnotDict,
    549     const CFX_ByteString& sExtGSDictName,
    550     const CFX_ByteString& sBlendMode) {
    551   auto pGSDict =
    552       pdfium::MakeUnique<CPDF_Dictionary>(pAnnotDict.GetByteStringPool());
    553   pGSDict->SetNewFor<CPDF_String>("Type", "ExtGState", false);
    554 
    555   FX_FLOAT fOpacity =
    556       pAnnotDict.KeyExist("CA") ? pAnnotDict.GetNumberFor("CA") : 1;
    557   pGSDict->SetNewFor<CPDF_Number>("CA", fOpacity);
    558   pGSDict->SetNewFor<CPDF_Number>("ca", fOpacity);
    559   pGSDict->SetNewFor<CPDF_Boolean>("AIS", false);
    560   pGSDict->SetNewFor<CPDF_String>("BM", sBlendMode, false);
    561 
    562   auto pExtGStateDict =
    563       pdfium::MakeUnique<CPDF_Dictionary>(pAnnotDict.GetByteStringPool());
    564   pExtGStateDict->SetFor(sExtGSDictName, std::move(pGSDict));
    565   return pExtGStateDict;
    566 }
    567 
    568 std::unique_ptr<CPDF_Dictionary> GenerateResourceFontDict(
    569     CPDF_Document* pDoc,
    570     const CFX_ByteString& sFontDictName) {
    571   CPDF_Dictionary* pFontDict = pDoc->NewIndirect<CPDF_Dictionary>();
    572   pFontDict->SetNewFor<CPDF_Name>("Type", "Font");
    573   pFontDict->SetNewFor<CPDF_Name>("Subtype", "Type1");
    574   pFontDict->SetNewFor<CPDF_Name>("BaseFont", "Helvetica");
    575   pFontDict->SetNewFor<CPDF_Name>("Encoding", "WinAnsiEncoding");
    576 
    577   auto pResourceFontDict =
    578       pdfium::MakeUnique<CPDF_Dictionary>(pDoc->GetByteStringPool());
    579   pResourceFontDict->SetNewFor<CPDF_Reference>(sFontDictName, pDoc,
    580                                                pFontDict->GetObjNum());
    581   return pResourceFontDict;
    582 }
    583 
    584 std::unique_ptr<CPDF_Dictionary> GenerateResourceDict(
    585     CPDF_Document* pDoc,
    586     std::unique_ptr<CPDF_Dictionary> pExtGStateDict,
    587     std::unique_ptr<CPDF_Dictionary> pResourceFontDict) {
    588   auto pResourceDict =
    589       pdfium::MakeUnique<CPDF_Dictionary>(pDoc->GetByteStringPool());
    590   if (pExtGStateDict)
    591     pResourceDict->SetFor("ExtGState", std::move(pExtGStateDict));
    592   if (pResourceFontDict)
    593     pResourceDict->SetFor("Font", std::move(pResourceFontDict));
    594   return pResourceDict;
    595 }
    596 
    597 void GenerateAndSetAPDict(CPDF_Document* pDoc,
    598                           CPDF_Dictionary* pAnnotDict,
    599                           const CFX_ByteTextBuf& sAppStream,
    600                           std::unique_ptr<CPDF_Dictionary> pResourceDict,
    601                           bool bIsTextMarkupAnnotation) {
    602   CPDF_Stream* pNormalStream = pDoc->NewIndirect<CPDF_Stream>();
    603   pNormalStream->SetData(sAppStream.GetBuffer(), sAppStream.GetSize());
    604 
    605   CPDF_Dictionary* pAPDict = pAnnotDict->SetNewFor<CPDF_Dictionary>("AP");
    606   pAPDict->SetNewFor<CPDF_Reference>("N", pDoc, pNormalStream->GetObjNum());
    607 
    608   CPDF_Dictionary* pStreamDict = pNormalStream->GetDict();
    609   pStreamDict->SetNewFor<CPDF_Number>("FormType", 1);
    610   pStreamDict->SetNewFor<CPDF_String>("Subtype", "Form", false);
    611   pStreamDict->SetMatrixFor("Matrix", CFX_Matrix());
    612 
    613   CFX_FloatRect rect = bIsTextMarkupAnnotation
    614                            ? CPDF_Annot::RectFromQuadPoints(pAnnotDict)
    615                            : pAnnotDict->GetRectFor("Rect");
    616   pStreamDict->SetRectFor("BBox", rect);
    617   pStreamDict->SetFor("Resources", std::move(pResourceDict));
    618 }
    619 
    620 CFX_ByteString GetPaintOperatorString(bool bIsStrokeRect, bool bIsFillRect) {
    621   if (bIsStrokeRect)
    622     return bIsFillRect ? "b" : "s";
    623   return bIsFillRect ? "f" : "n";
    624 }
    625 
    626 CFX_ByteString GenerateTextSymbolAP(const CFX_FloatRect& rect) {
    627   CFX_ByteTextBuf sAppStream;
    628   sAppStream << CPVT_GenerateAP::GenerateColorAP(
    629       CPVT_Color(CPVT_Color::kRGB, 1, 1, 0), PaintOperation::FILL);
    630   sAppStream << CPVT_GenerateAP::GenerateColorAP(
    631       CPVT_Color(CPVT_Color::kRGB, 0, 0, 0), PaintOperation::STROKE);
    632 
    633   const FX_FLOAT fBorderWidth = 1;
    634   sAppStream << fBorderWidth << " w\n";
    635 
    636   const FX_FLOAT fHalfWidth = fBorderWidth / 2;
    637   const FX_FLOAT fTipDelta = 4;
    638 
    639   CFX_FloatRect outerRect1 = rect;
    640   outerRect1.Deflate(fHalfWidth, fHalfWidth);
    641   outerRect1.bottom += fTipDelta;
    642 
    643   CFX_FloatRect outerRect2 = outerRect1;
    644   outerRect2.left += fTipDelta;
    645   outerRect2.right = outerRect2.left + fTipDelta;
    646   outerRect2.top = outerRect2.bottom - fTipDelta;
    647   FX_FLOAT outerRect2Middle = (outerRect2.left + outerRect2.right) / 2;
    648 
    649   // Draw outer boxes.
    650   sAppStream << outerRect1.left << " " << outerRect1.bottom << " m\n"
    651              << outerRect1.left << " " << outerRect1.top << " l\n"
    652              << outerRect1.right << " " << outerRect1.top << " l\n"
    653              << outerRect1.right << " " << outerRect1.bottom << " l\n"
    654              << outerRect2.right << " " << outerRect2.bottom << " l\n"
    655              << outerRect2Middle << " " << outerRect2.top << " l\n"
    656              << outerRect2.left << " " << outerRect2.bottom << " l\n"
    657              << outerRect1.left << " " << outerRect1.bottom << " l\n";
    658 
    659   // Draw inner lines.
    660   CFX_FloatRect lineRect = outerRect1;
    661   const FX_FLOAT fXDelta = 2;
    662   const FX_FLOAT fYDelta = (lineRect.top - lineRect.bottom) / 4;
    663 
    664   lineRect.left += fXDelta;
    665   lineRect.right -= fXDelta;
    666   for (int i = 0; i < 3; ++i) {
    667     lineRect.top -= fYDelta;
    668     sAppStream << lineRect.left << " " << lineRect.top << " m\n"
    669                << lineRect.right << " " << lineRect.top << " l\n";
    670   }
    671   sAppStream << "B*\n";
    672 
    673   return sAppStream.MakeString();
    674 }
    675 
    676 }  // namespace
    677 
    678 bool FPDF_GenerateAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict) {
    679   if (!pAnnotDict || pAnnotDict->GetStringFor("Subtype") != "Widget")
    680     return false;
    681 
    682   CPDF_Object* pFieldTypeObj = FPDF_GetFieldAttr(pAnnotDict, "FT");
    683   if (!pFieldTypeObj)
    684     return false;
    685 
    686   CFX_ByteString field_type = pFieldTypeObj->GetString();
    687   if (field_type == "Tx")
    688     return CPVT_GenerateAP::GenerateTextFieldAP(pDoc, pAnnotDict);
    689 
    690   CPDF_Object* pFieldFlagsObj = FPDF_GetFieldAttr(pAnnotDict, "Ff");
    691   uint32_t flags = pFieldFlagsObj ? pFieldFlagsObj->GetInteger() : 0;
    692   if (field_type == "Ch") {
    693     return (flags & (1 << 17))
    694                ? CPVT_GenerateAP::GenerateComboBoxAP(pDoc, pAnnotDict)
    695                : CPVT_GenerateAP::GenerateListBoxAP(pDoc, pAnnotDict);
    696   }
    697 
    698   if (field_type == "Btn") {
    699     if (!(flags & (1 << 16))) {
    700       if (!pAnnotDict->KeyExist("AS")) {
    701         if (CPDF_Dictionary* pParentDict = pAnnotDict->GetDictFor("Parent")) {
    702           if (pParentDict->KeyExist("AS")) {
    703             pAnnotDict->SetNewFor<CPDF_String>(
    704                 "AS", pParentDict->GetStringFor("AS"), false);
    705           }
    706         }
    707       }
    708     }
    709   }
    710 
    711   return false;
    712 }
    713 
    714 // Static.
    715 bool CPVT_GenerateAP::GenerateComboBoxAP(CPDF_Document* pDoc,
    716                                          CPDF_Dictionary* pAnnotDict) {
    717   return GenerateWidgetAP(pDoc, pAnnotDict, 1);
    718 }
    719 
    720 // Static.
    721 bool CPVT_GenerateAP::GenerateListBoxAP(CPDF_Document* pDoc,
    722                                         CPDF_Dictionary* pAnnotDict) {
    723   return GenerateWidgetAP(pDoc, pAnnotDict, 2);
    724 }
    725 
    726 // Static.
    727 bool CPVT_GenerateAP::GenerateTextFieldAP(CPDF_Document* pDoc,
    728                                           CPDF_Dictionary* pAnnotDict) {
    729   return GenerateWidgetAP(pDoc, pAnnotDict, 0);
    730 }
    731 
    732 bool CPVT_GenerateAP::GenerateCircleAP(CPDF_Document* pDoc,
    733                                        CPDF_Dictionary* pAnnotDict) {
    734   CFX_ByteTextBuf sAppStream;
    735   CFX_ByteString sExtGSDictName = "GS";
    736   sAppStream << "/" << sExtGSDictName << " gs ";
    737 
    738   CPDF_Array* pInteriorColor = pAnnotDict->GetArrayFor("IC");
    739   sAppStream << GetColorStringWithDefault(pInteriorColor,
    740                                           CPVT_Color(CPVT_Color::kTransparent),
    741                                           PaintOperation::FILL);
    742 
    743   sAppStream << GetColorStringWithDefault(pAnnotDict->GetArrayFor("C"),
    744                                           CPVT_Color(CPVT_Color::kRGB, 0, 0, 0),
    745                                           PaintOperation::STROKE);
    746 
    747   FX_FLOAT fBorderWidth = GetBorderWidth(*pAnnotDict);
    748   bool bIsStrokeRect = fBorderWidth > 0;
    749 
    750   if (bIsStrokeRect) {
    751     sAppStream << fBorderWidth << " w ";
    752     sAppStream << GetDashPatternString(*pAnnotDict);
    753   }
    754 
    755   CFX_FloatRect rect = pAnnotDict->GetRectFor("Rect");
    756   rect.Normalize();
    757 
    758   if (bIsStrokeRect) {
    759     // Deflating rect because stroking a path entails painting all points whose
    760     // perpendicular distance from the path in user space is less than or equal
    761     // to half the line width.
    762     rect.Deflate(fBorderWidth / 2, fBorderWidth / 2);
    763   }
    764 
    765   const FX_FLOAT fMiddleX = (rect.left + rect.right) / 2;
    766   const FX_FLOAT fMiddleY = (rect.top + rect.bottom) / 2;
    767 
    768   // |fL| is precalculated approximate value of 4 * tan((3.14 / 2) / 4) / 3,
    769   // where |fL| * radius is a good approximation of control points for
    770   // arc with 90 degrees.
    771   const FX_FLOAT fL = 0.5523f;
    772   const FX_FLOAT fDeltaX = fL * rect.Width() / 2.0;
    773   const FX_FLOAT fDeltaY = fL * rect.Height() / 2.0;
    774 
    775   // Starting point
    776   sAppStream << fMiddleX << " " << rect.top << " m\n";
    777   // First Bezier Curve
    778   sAppStream << fMiddleX + fDeltaX << " " << rect.top << " " << rect.right
    779              << " " << fMiddleY + fDeltaY << " " << rect.right << " "
    780              << fMiddleY << " c\n";
    781   // Second Bezier Curve
    782   sAppStream << rect.right << " " << fMiddleY - fDeltaY << " "
    783              << fMiddleX + fDeltaX << " " << rect.bottom << " " << fMiddleX
    784              << " " << rect.bottom << " c\n";
    785   // Third Bezier Curve
    786   sAppStream << fMiddleX - fDeltaX << " " << rect.bottom << " " << rect.left
    787              << " " << fMiddleY - fDeltaY << " " << rect.left << " " << fMiddleY
    788              << " c\n";
    789   // Fourth Bezier Curve
    790   sAppStream << rect.left << " " << fMiddleY + fDeltaY << " "
    791              << fMiddleX - fDeltaX << " " << rect.top << " " << fMiddleX << " "
    792              << rect.top << " c\n";
    793 
    794   bool bIsFillRect = pInteriorColor && !pInteriorColor->IsEmpty();
    795   sAppStream << GetPaintOperatorString(bIsStrokeRect, bIsFillRect) << "\n";
    796 
    797   auto pExtGStateDict =
    798       GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal");
    799   auto pResourceDict =
    800       GenerateResourceDict(pDoc, std::move(pExtGStateDict), nullptr);
    801   GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, std::move(pResourceDict),
    802                        false /*IsTextMarkupAnnotation*/);
    803   return true;
    804 }
    805 
    806 bool CPVT_GenerateAP::GenerateHighlightAP(CPDF_Document* pDoc,
    807                                           CPDF_Dictionary* pAnnotDict) {
    808   CFX_ByteTextBuf sAppStream;
    809   CFX_ByteString sExtGSDictName = "GS";
    810   sAppStream << "/" << sExtGSDictName << " gs ";
    811 
    812   sAppStream << GetColorStringWithDefault(pAnnotDict->GetArrayFor("C"),
    813                                           CPVT_Color(CPVT_Color::kRGB, 1, 1, 0),
    814                                           PaintOperation::FILL);
    815 
    816   CFX_FloatRect rect = CPDF_Annot::RectFromQuadPoints(pAnnotDict);
    817   rect.Normalize();
    818 
    819   sAppStream << rect.left << " " << rect.top << " m " << rect.right << " "
    820              << rect.top << " l " << rect.right << " " << rect.bottom << " l "
    821              << rect.left << " " << rect.bottom << " l "
    822              << "h f\n";
    823 
    824   auto pExtGStateDict =
    825       GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Multiply");
    826   auto pResourceDict =
    827       GenerateResourceDict(pDoc, std::move(pExtGStateDict), nullptr);
    828   GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, std::move(pResourceDict),
    829                        true /*IsTextMarkupAnnotation*/);
    830 
    831   return true;
    832 }
    833 
    834 bool CPVT_GenerateAP::GenerateInkAP(CPDF_Document* pDoc,
    835                                     CPDF_Dictionary* pAnnotDict) {
    836   FX_FLOAT fBorderWidth = GetBorderWidth(*pAnnotDict);
    837   bool bIsStroke = fBorderWidth > 0;
    838 
    839   if (!bIsStroke)
    840     return false;
    841 
    842   CPDF_Array* pInkList = pAnnotDict->GetArrayFor("InkList");
    843   if (!pInkList || pInkList->IsEmpty())
    844     return false;
    845 
    846   CFX_ByteTextBuf sAppStream;
    847   CFX_ByteString sExtGSDictName = "GS";
    848   sAppStream << "/" << sExtGSDictName << " gs ";
    849 
    850   sAppStream << GetColorStringWithDefault(pAnnotDict->GetArrayFor("C"),
    851                                           CPVT_Color(CPVT_Color::kRGB, 0, 0, 0),
    852                                           PaintOperation::STROKE);
    853 
    854   sAppStream << fBorderWidth << " w ";
    855   sAppStream << GetDashPatternString(*pAnnotDict);
    856 
    857   // Set inflated rect as a new rect because paths near the border with large
    858   // width should not be clipped to the original rect.
    859   CFX_FloatRect rect = pAnnotDict->GetRectFor("Rect");
    860   rect.Inflate(fBorderWidth / 2, fBorderWidth / 2);
    861   pAnnotDict->SetRectFor("Rect", rect);
    862 
    863   for (size_t i = 0; i < pInkList->GetCount(); i++) {
    864     CPDF_Array* pInkCoordList = pInkList->GetArrayAt(i);
    865     if (!pInkCoordList || pInkCoordList->GetCount() < 2)
    866       continue;
    867 
    868     sAppStream << pInkCoordList->GetNumberAt(0) << " "
    869                << pInkCoordList->GetNumberAt(1) << " m ";
    870 
    871     for (size_t j = 0; j < pInkCoordList->GetCount() - 1; j += 2) {
    872       sAppStream << pInkCoordList->GetNumberAt(j) << " "
    873                  << pInkCoordList->GetNumberAt(j + 1) << " l ";
    874     }
    875 
    876     sAppStream << "S\n";
    877   }
    878 
    879   auto pExtGStateDict =
    880       GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal");
    881   auto pResourceDict =
    882       GenerateResourceDict(pDoc, std::move(pExtGStateDict), nullptr);
    883   GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, std::move(pResourceDict),
    884                        false /*IsTextMarkupAnnotation*/);
    885   return true;
    886 }
    887 
    888 bool CPVT_GenerateAP::GenerateTextAP(CPDF_Document* pDoc,
    889                                      CPDF_Dictionary* pAnnotDict) {
    890   CFX_ByteTextBuf sAppStream;
    891   CFX_ByteString sExtGSDictName = "GS";
    892   sAppStream << "/" << sExtGSDictName << " gs ";
    893 
    894   CFX_FloatRect rect = pAnnotDict->GetRectFor("Rect");
    895   const FX_FLOAT fNoteLength = 20;
    896   CFX_FloatRect noteRect(rect.left, rect.bottom, rect.left + fNoteLength,
    897                          rect.bottom + fNoteLength);
    898   pAnnotDict->SetRectFor("Rect", noteRect);
    899 
    900   sAppStream << GenerateTextSymbolAP(noteRect);
    901 
    902   auto pExtGStateDict =
    903       GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal");
    904   auto pResourceDict =
    905       GenerateResourceDict(pDoc, std::move(pExtGStateDict), nullptr);
    906   GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, std::move(pResourceDict),
    907                        false /*IsTextMarkupAnnotation*/);
    908   return true;
    909 }
    910 
    911 bool CPVT_GenerateAP::GenerateUnderlineAP(CPDF_Document* pDoc,
    912                                           CPDF_Dictionary* pAnnotDict) {
    913   CFX_ByteTextBuf sAppStream;
    914   CFX_ByteString sExtGSDictName = "GS";
    915   sAppStream << "/" << sExtGSDictName << " gs ";
    916 
    917   sAppStream << GetColorStringWithDefault(pAnnotDict->GetArrayFor("C"),
    918                                           CPVT_Color(CPVT_Color::kRGB, 0, 0, 0),
    919                                           PaintOperation::STROKE);
    920 
    921   CFX_FloatRect rect = CPDF_Annot::RectFromQuadPoints(pAnnotDict);
    922   rect.Normalize();
    923 
    924   FX_FLOAT fLineWidth = 1.0;
    925   sAppStream << fLineWidth << " w " << rect.left << " "
    926              << rect.bottom + fLineWidth << " m " << rect.right << " "
    927              << rect.bottom + fLineWidth << " l S\n";
    928 
    929   auto pExtGStateDict =
    930       GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal");
    931   auto pResourceDict =
    932       GenerateResourceDict(pDoc, std::move(pExtGStateDict), nullptr);
    933   GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, std::move(pResourceDict),
    934                        true /*IsTextMarkupAnnotation*/);
    935   return true;
    936 }
    937 
    938 bool CPVT_GenerateAP::GeneratePopupAP(CPDF_Document* pDoc,
    939                                       CPDF_Dictionary* pAnnotDict) {
    940   CFX_ByteTextBuf sAppStream;
    941   CFX_ByteString sExtGSDictName = "GS";
    942   sAppStream << "/" << sExtGSDictName << " gs\n";
    943 
    944   sAppStream << GenerateColorAP(CPVT_Color(CPVT_Color::kRGB, 1, 1, 0),
    945                                 PaintOperation::FILL);
    946   sAppStream << GenerateColorAP(CPVT_Color(CPVT_Color::kRGB, 0, 0, 0),
    947                                 PaintOperation::STROKE);
    948 
    949   const FX_FLOAT fBorderWidth = 1;
    950   sAppStream << fBorderWidth << " w\n";
    951 
    952   CFX_FloatRect rect = pAnnotDict->GetRectFor("Rect");
    953   rect.Normalize();
    954   rect.Deflate(fBorderWidth / 2, fBorderWidth / 2);
    955 
    956   sAppStream << rect.left << " " << rect.bottom << " " << rect.Width() << " "
    957              << rect.Height() << " re b\n";
    958 
    959   CFX_ByteString sFontName = "FONT";
    960   auto pResourceFontDict = GenerateResourceFontDict(pDoc, sFontName);
    961   CPDF_Font* pDefFont = pDoc->LoadFont(pResourceFontDict.get());
    962   if (!pDefFont)
    963     return false;
    964 
    965   auto pExtGStateDict =
    966       GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal");
    967   auto pResourceDict = GenerateResourceDict(pDoc, std::move(pResourceFontDict),
    968                                             std::move(pExtGStateDict));
    969 
    970   sAppStream << GetPopupContentsString(pDoc, *pAnnotDict, pDefFont, sFontName);
    971   GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, std::move(pResourceDict),
    972                        false /*IsTextMarkupAnnotation*/);
    973   return true;
    974 }
    975 
    976 bool CPVT_GenerateAP::GenerateSquareAP(CPDF_Document* pDoc,
    977                                        CPDF_Dictionary* pAnnotDict) {
    978   CFX_ByteTextBuf sAppStream;
    979   CFX_ByteString sExtGSDictName = "GS";
    980   sAppStream << "/" << sExtGSDictName << " gs ";
    981 
    982   CPDF_Array* pInteriorColor = pAnnotDict->GetArrayFor("IC");
    983   sAppStream << GetColorStringWithDefault(pInteriorColor,
    984                                           CPVT_Color(CPVT_Color::kTransparent),
    985                                           PaintOperation::FILL);
    986 
    987   sAppStream << GetColorStringWithDefault(pAnnotDict->GetArrayFor("C"),
    988                                           CPVT_Color(CPVT_Color::kRGB, 0, 0, 0),
    989                                           PaintOperation::STROKE);
    990 
    991   FX_FLOAT fBorderWidth = GetBorderWidth(*pAnnotDict);
    992   bool bIsStrokeRect = fBorderWidth > 0;
    993 
    994   if (bIsStrokeRect) {
    995     sAppStream << fBorderWidth << " w ";
    996     sAppStream << GetDashPatternString(*pAnnotDict);
    997   }
    998 
    999   CFX_FloatRect rect = pAnnotDict->GetRectFor("Rect");
   1000   rect.Normalize();
   1001 
   1002   if (bIsStrokeRect) {
   1003     // Deflating rect because stroking a path entails painting all points whose
   1004     // perpendicular distance from the path in user space is less than or equal
   1005     // to half the line width.
   1006     rect.Deflate(fBorderWidth / 2, fBorderWidth / 2);
   1007   }
   1008 
   1009   bool bIsFillRect = pInteriorColor && (pInteriorColor->GetCount() > 0);
   1010 
   1011   sAppStream << rect.left << " " << rect.bottom << " " << rect.Width() << " "
   1012              << rect.Height() << " re "
   1013              << GetPaintOperatorString(bIsStrokeRect, bIsFillRect) << "\n";
   1014 
   1015   auto pExtGStateDict =
   1016       GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal");
   1017   auto pResourceDict =
   1018       GenerateResourceDict(pDoc, std::move(pExtGStateDict), nullptr);
   1019   GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, std::move(pResourceDict),
   1020                        false /*IsTextMarkupAnnotation*/);
   1021   return true;
   1022 }
   1023 
   1024 bool CPVT_GenerateAP::GenerateSquigglyAP(CPDF_Document* pDoc,
   1025                                          CPDF_Dictionary* pAnnotDict) {
   1026   CFX_ByteTextBuf sAppStream;
   1027   CFX_ByteString sExtGSDictName = "GS";
   1028   sAppStream << "/" << sExtGSDictName << " gs ";
   1029 
   1030   sAppStream << GetColorStringWithDefault(pAnnotDict->GetArrayFor("C"),
   1031                                           CPVT_Color(CPVT_Color::kRGB, 0, 0, 0),
   1032                                           PaintOperation::STROKE);
   1033 
   1034   CFX_FloatRect rect = CPDF_Annot::RectFromQuadPoints(pAnnotDict);
   1035   rect.Normalize();
   1036 
   1037   FX_FLOAT fLineWidth = 1.0;
   1038   sAppStream << fLineWidth << " w ";
   1039 
   1040   const FX_FLOAT fDelta = 2.0;
   1041   const FX_FLOAT fTop = rect.bottom + fDelta;
   1042   const FX_FLOAT fBottom = rect.bottom;
   1043 
   1044   sAppStream << rect.left << " " << fTop << " m ";
   1045 
   1046   FX_FLOAT fX = rect.left + fDelta;
   1047   bool isUpwards = false;
   1048 
   1049   while (fX < rect.right) {
   1050     sAppStream << fX << " " << (isUpwards ? fTop : fBottom) << " l ";
   1051 
   1052     fX += fDelta;
   1053     isUpwards = !isUpwards;
   1054   }
   1055 
   1056   FX_FLOAT fRemainder = rect.right - (fX - fDelta);
   1057   if (isUpwards)
   1058     sAppStream << rect.right << " " << fBottom + fRemainder << " l ";
   1059   else
   1060     sAppStream << rect.right << " " << fTop - fRemainder << " l ";
   1061 
   1062   sAppStream << "S\n";
   1063 
   1064   auto pExtGStateDict =
   1065       GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal");
   1066   auto pResourceDict =
   1067       GenerateResourceDict(pDoc, std::move(pExtGStateDict), nullptr);
   1068   GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, std::move(pResourceDict),
   1069                        true /*IsTextMarkupAnnotation*/);
   1070   return true;
   1071 }
   1072 
   1073 bool CPVT_GenerateAP::GenerateStrikeOutAP(CPDF_Document* pDoc,
   1074                                           CPDF_Dictionary* pAnnotDict) {
   1075   CFX_ByteTextBuf sAppStream;
   1076   CFX_ByteString sExtGSDictName = "GS";
   1077   sAppStream << "/" << sExtGSDictName << " gs ";
   1078 
   1079   sAppStream << GetColorStringWithDefault(pAnnotDict->GetArrayFor("C"),
   1080                                           CPVT_Color(CPVT_Color::kRGB, 0, 0, 0),
   1081                                           PaintOperation::STROKE);
   1082 
   1083   CFX_FloatRect rect = CPDF_Annot::RectFromQuadPoints(pAnnotDict);
   1084   rect.Normalize();
   1085 
   1086   FX_FLOAT fLineWidth = 1.0;
   1087   FX_FLOAT fY = (rect.top + rect.bottom) / 2;
   1088   sAppStream << fLineWidth << " w " << rect.left << " " << fY << " m "
   1089              << rect.right << " " << fY << " l S\n";
   1090 
   1091   auto pExtGStateDict =
   1092       GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal");
   1093   auto pResourceDict =
   1094       GenerateResourceDict(pDoc, std::move(pExtGStateDict), nullptr);
   1095   GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, std::move(pResourceDict),
   1096                        true /*IsTextMarkupAnnotation*/);
   1097   return true;
   1098 }
   1099 
   1100 // Static.
   1101 CFX_ByteString CPVT_GenerateAP::GenerateEditAP(
   1102     IPVT_FontMap* pFontMap,
   1103     CPDF_VariableText::Iterator* pIterator,
   1104     const CFX_PointF& ptOffset,
   1105     bool bContinuous,
   1106     uint16_t SubWord) {
   1107   CFX_ByteTextBuf sEditStream;
   1108   CFX_ByteTextBuf sLineStream;
   1109   CFX_ByteTextBuf sWords;
   1110   CFX_PointF ptOld;
   1111   CFX_PointF ptNew;
   1112   int32_t nCurFontIndex = -1;
   1113   CPVT_WordPlace oldplace;
   1114 
   1115   pIterator->SetAt(0);
   1116   while (pIterator->NextWord()) {
   1117     CPVT_WordPlace place = pIterator->GetAt();
   1118     if (bContinuous) {
   1119       if (place.LineCmp(oldplace) != 0) {
   1120         if (sWords.GetSize() > 0) {
   1121           sLineStream << GetWordRenderString(sWords.MakeString());
   1122           sEditStream << sLineStream;
   1123           sLineStream.Clear();
   1124           sWords.Clear();
   1125         }
   1126         CPVT_Word word;
   1127         if (pIterator->GetWord(word)) {
   1128           ptNew = CFX_PointF(word.ptWord.x + ptOffset.x,
   1129                              word.ptWord.y + ptOffset.y);
   1130         } else {
   1131           CPVT_Line line;
   1132           pIterator->GetLine(line);
   1133           ptNew = CFX_PointF(line.ptLine.x + ptOffset.x,
   1134                              line.ptLine.y + ptOffset.y);
   1135         }
   1136         if (ptNew != ptOld) {
   1137           sLineStream << ptNew.x - ptOld.x << " " << ptNew.y - ptOld.y
   1138                       << " Td\n";
   1139           ptOld = ptNew;
   1140         }
   1141       }
   1142       CPVT_Word word;
   1143       if (pIterator->GetWord(word)) {
   1144         if (word.nFontIndex != nCurFontIndex) {
   1145           if (sWords.GetSize() > 0) {
   1146             sLineStream << GetWordRenderString(sWords.MakeString());
   1147             sWords.Clear();
   1148           }
   1149           sLineStream << GetFontSetString(pFontMap, word.nFontIndex,
   1150                                           word.fFontSize);
   1151           nCurFontIndex = word.nFontIndex;
   1152         }
   1153         sWords << GetPDFWordString(pFontMap, nCurFontIndex, word.Word, SubWord);
   1154       }
   1155       oldplace = place;
   1156     } else {
   1157       CPVT_Word word;
   1158       if (pIterator->GetWord(word)) {
   1159         ptNew =
   1160             CFX_PointF(word.ptWord.x + ptOffset.x, word.ptWord.y + ptOffset.y);
   1161         if (ptNew != ptOld) {
   1162           sEditStream << ptNew.x - ptOld.x << " " << ptNew.y - ptOld.y
   1163                       << " Td\n";
   1164           ptOld = ptNew;
   1165         }
   1166         if (word.nFontIndex != nCurFontIndex) {
   1167           sEditStream << GetFontSetString(pFontMap, word.nFontIndex,
   1168                                           word.fFontSize);
   1169           nCurFontIndex = word.nFontIndex;
   1170         }
   1171         sEditStream << GetWordRenderString(
   1172             GetPDFWordString(pFontMap, nCurFontIndex, word.Word, SubWord));
   1173       }
   1174     }
   1175   }
   1176   if (sWords.GetSize() > 0) {
   1177     sLineStream << GetWordRenderString(sWords.MakeString());
   1178     sEditStream << sLineStream;
   1179     sWords.Clear();
   1180   }
   1181   return sEditStream.MakeString();
   1182 }
   1183 
   1184 // Static.
   1185 CFX_ByteString CPVT_GenerateAP::GenerateBorderAP(
   1186     const CFX_FloatRect& rect,
   1187     FX_FLOAT fWidth,
   1188     const CPVT_Color& color,
   1189     const CPVT_Color& crLeftTop,
   1190     const CPVT_Color& crRightBottom,
   1191     BorderStyle nStyle,
   1192     const CPVT_Dash& dash) {
   1193   CFX_ByteTextBuf sAppStream;
   1194   CFX_ByteString sColor;
   1195   FX_FLOAT fLeft = rect.left;
   1196   FX_FLOAT fRight = rect.right;
   1197   FX_FLOAT fTop = rect.top;
   1198   FX_FLOAT fBottom = rect.bottom;
   1199   if (fWidth > 0.0f) {
   1200     FX_FLOAT fHalfWidth = fWidth / 2.0f;
   1201     switch (nStyle) {
   1202       default:
   1203       case BorderStyle::SOLID:
   1204         sColor = GenerateColorAP(color, PaintOperation::FILL);
   1205         if (sColor.GetLength() > 0) {
   1206           sAppStream << sColor;
   1207           sAppStream << fLeft << " " << fBottom << " " << fRight - fLeft << " "
   1208                      << fTop - fBottom << " re\n";
   1209           sAppStream << fLeft + fWidth << " " << fBottom + fWidth << " "
   1210                      << fRight - fLeft - fWidth * 2 << " "
   1211                      << fTop - fBottom - fWidth * 2 << " re\n";
   1212           sAppStream << "f*\n";
   1213         }
   1214         break;
   1215       case BorderStyle::DASH:
   1216         sColor = GenerateColorAP(color, PaintOperation::STROKE);
   1217         if (sColor.GetLength() > 0) {
   1218           sAppStream << sColor;
   1219           sAppStream << fWidth << " w"
   1220                      << " [" << dash.nDash << " " << dash.nGap << "] "
   1221                      << dash.nPhase << " d\n";
   1222           sAppStream << fLeft + fWidth / 2 << " " << fBottom + fWidth / 2
   1223                      << " m\n";
   1224           sAppStream << fLeft + fWidth / 2 << " " << fTop - fWidth / 2
   1225                      << " l\n";
   1226           sAppStream << fRight - fWidth / 2 << " " << fTop - fWidth / 2
   1227                      << " l\n";
   1228           sAppStream << fRight - fWidth / 2 << " " << fBottom + fWidth / 2
   1229                      << " l\n";
   1230           sAppStream << fLeft + fWidth / 2 << " " << fBottom + fWidth / 2
   1231                      << " l S\n";
   1232         }
   1233         break;
   1234       case BorderStyle::BEVELED:
   1235       case BorderStyle::INSET:
   1236         sColor = GenerateColorAP(crLeftTop, PaintOperation::FILL);
   1237         if (sColor.GetLength() > 0) {
   1238           sAppStream << sColor;
   1239           sAppStream << fLeft + fHalfWidth << " " << fBottom + fHalfWidth
   1240                      << " m\n";
   1241           sAppStream << fLeft + fHalfWidth << " " << fTop - fHalfWidth
   1242                      << " l\n";
   1243           sAppStream << fRight - fHalfWidth << " " << fTop - fHalfWidth
   1244                      << " l\n";
   1245           sAppStream << fRight - fHalfWidth * 2 << " " << fTop - fHalfWidth * 2
   1246                      << " l\n";
   1247           sAppStream << fLeft + fHalfWidth * 2 << " " << fTop - fHalfWidth * 2
   1248                      << " l\n";
   1249           sAppStream << fLeft + fHalfWidth * 2 << " "
   1250                      << fBottom + fHalfWidth * 2 << " l f\n";
   1251         }
   1252         sColor = GenerateColorAP(crRightBottom, PaintOperation::FILL);
   1253         if (sColor.GetLength() > 0) {
   1254           sAppStream << sColor;
   1255           sAppStream << fRight - fHalfWidth << " " << fTop - fHalfWidth
   1256                      << " m\n";
   1257           sAppStream << fRight - fHalfWidth << " " << fBottom + fHalfWidth
   1258                      << " l\n";
   1259           sAppStream << fLeft + fHalfWidth << " " << fBottom + fHalfWidth
   1260                      << " l\n";
   1261           sAppStream << fLeft + fHalfWidth * 2 << " "
   1262                      << fBottom + fHalfWidth * 2 << " l\n";
   1263           sAppStream << fRight - fHalfWidth * 2 << " "
   1264                      << fBottom + fHalfWidth * 2 << " l\n";
   1265           sAppStream << fRight - fHalfWidth * 2 << " " << fTop - fHalfWidth * 2
   1266                      << " l f\n";
   1267         }
   1268         sColor = GenerateColorAP(color, PaintOperation::FILL);
   1269         if (sColor.GetLength() > 0) {
   1270           sAppStream << sColor;
   1271           sAppStream << fLeft << " " << fBottom << " " << fRight - fLeft << " "
   1272                      << fTop - fBottom << " re\n";
   1273           sAppStream << fLeft + fHalfWidth << " " << fBottom + fHalfWidth << " "
   1274                      << fRight - fLeft - fHalfWidth * 2 << " "
   1275                      << fTop - fBottom - fHalfWidth * 2 << " re f*\n";
   1276         }
   1277         break;
   1278       case BorderStyle::UNDERLINE:
   1279         sColor = GenerateColorAP(color, PaintOperation::STROKE);
   1280         if (sColor.GetLength() > 0) {
   1281           sAppStream << sColor;
   1282           sAppStream << fWidth << " w\n";
   1283           sAppStream << fLeft << " " << fBottom + fWidth / 2 << " m\n";
   1284           sAppStream << fRight << " " << fBottom + fWidth / 2 << " l S\n";
   1285         }
   1286         break;
   1287     }
   1288   }
   1289   return sAppStream.MakeString();
   1290 }
   1291 
   1292 // Static.
   1293 CFX_ByteString CPVT_GenerateAP::GenerateColorAP(const CPVT_Color& color,
   1294                                                 PaintOperation nOperation) {
   1295   CFX_ByteTextBuf sColorStream;
   1296   switch (color.nColorType) {
   1297     case CPVT_Color::kRGB:
   1298       sColorStream << color.fColor1 << " " << color.fColor2 << " "
   1299                    << color.fColor3 << " "
   1300                    << (nOperation == PaintOperation::STROKE ? "RG" : "rg")
   1301                    << "\n";
   1302       break;
   1303     case CPVT_Color::kGray:
   1304       sColorStream << color.fColor1 << " "
   1305                    << (nOperation == PaintOperation::STROKE ? "G" : "g")
   1306                    << "\n";
   1307       break;
   1308     case CPVT_Color::kCMYK:
   1309       sColorStream << color.fColor1 << " " << color.fColor2 << " "
   1310                    << color.fColor3 << " " << color.fColor4 << " "
   1311                    << (nOperation == PaintOperation::STROKE ? "K" : "k")
   1312                    << "\n";
   1313       break;
   1314     case CPVT_Color::kTransparent:
   1315       break;
   1316   }
   1317   return sColorStream.MakeString();
   1318 }
   1319 
   1320 // Static.
   1321 CFX_ByteString CPVT_GenerateAP::GetPDFWordString(IPVT_FontMap* pFontMap,
   1322                                                  int32_t nFontIndex,
   1323                                                  uint16_t Word,
   1324                                                  uint16_t SubWord) {
   1325   CFX_ByteString sWord;
   1326   if (SubWord > 0) {
   1327     sWord.Format("%c", SubWord);
   1328     return sWord;
   1329   }
   1330 
   1331   if (!pFontMap)
   1332     return sWord;
   1333 
   1334   if (CPDF_Font* pPDFFont = pFontMap->GetPDFFont(nFontIndex)) {
   1335     if (pPDFFont->GetBaseFont().Compare("Symbol") == 0 ||
   1336         pPDFFont->GetBaseFont().Compare("ZapfDingbats") == 0) {
   1337       sWord.Format("%c", Word);
   1338     } else {
   1339       uint32_t dwCharCode = pPDFFont->CharCodeFromUnicode(Word);
   1340       if (dwCharCode != CPDF_Font::kInvalidCharCode)
   1341         pPDFFont->AppendChar(sWord, dwCharCode);
   1342     }
   1343   }
   1344   return sWord;
   1345 }
   1346 
   1347 // Static.
   1348 CFX_ByteString CPVT_GenerateAP::GetWordRenderString(
   1349     const CFX_ByteString& strWords) {
   1350   if (strWords.GetLength() > 0)
   1351     return PDF_EncodeString(strWords) + " Tj\n";
   1352   return "";
   1353 }
   1354 
   1355 // Static.
   1356 CFX_ByteString CPVT_GenerateAP::GetFontSetString(IPVT_FontMap* pFontMap,
   1357                                                  int32_t nFontIndex,
   1358                                                  FX_FLOAT fFontSize) {
   1359   CFX_ByteTextBuf sRet;
   1360   if (pFontMap) {
   1361     CFX_ByteString sFontAlias = pFontMap->GetPDFFontAlias(nFontIndex);
   1362     if (sFontAlias.GetLength() > 0 && fFontSize > 0)
   1363       sRet << "/" << sFontAlias << " " << fFontSize << " Tf\n";
   1364   }
   1365   return sRet.MakeString();
   1366 }
   1367