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