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