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