7#include "core/fpdfdoc/cpdf_generateap.h"
13#include "constants/annotation_common.h"
14#include "constants/appearance.h"
15#include "constants/font_encodings.h"
16#include "constants/form_fields.h"
17#include "core/fpdfapi/font/cpdf_font.h"
18#include "core/fpdfapi/page/cpdf_docpagedata.h"
19#include "core/fpdfapi/parser/cpdf_array.h"
20#include "core/fpdfapi/parser/cpdf_boolean.h"
21#include "core/fpdfapi/parser/cpdf_dictionary.h"
22#include "core/fpdfapi/parser/cpdf_document.h"
23#include "core/fpdfapi/parser/cpdf_name.h"
24#include "core/fpdfapi/parser/cpdf_number.h"
25#include "core/fpdfapi/parser/cpdf_reference.h"
26#include "core/fpdfapi/parser/cpdf_stream.h"
27#include "core/fpdfapi/parser/cpdf_string.h"
28#include "core/fpdfapi/parser/fpdf_parser_decode.h"
29#include "core/fpdfapi/parser/fpdf_parser_utility.h"
30#include "core/fpdfdoc/cpdf_annot.h"
31#include "core/fpdfdoc/cpdf_color_utils.h"
32#include "core/fpdfdoc/cpdf_defaultappearance.h"
33#include "core/fpdfdoc/cpdf_formfield.h"
34#include "core/fpdfdoc/cpvt_fontmap.h"
35#include "core/fpdfdoc/cpvt_variabletext.h"
36#include "core/fpdfdoc/cpvt_word.h"
37#include "core/fxcrt/fx_string_wrappers.h"
38#include "core/fxge/cfx_renderdevice.h"
43 CPVT_Dash(int32_t dash, int32_t gap, int32_t phase)
44 : nDash(dash), nGap(gap), nPhase(phase) {}
51enum class PaintOperation { kStroke, kFill };
67 if (pPDFFont->GetBaseFontName() ==
"Symbol" ||
68 pPDFFont->GetBaseFontName() ==
"ZapfDingbats") {
73 uint32_t dwCharCode = pPDFFont->CharCodeFromUnicode(Word);
75 pPDFFont->AppendChar(&sWord, dwCharCode);
80ByteString GetWordRenderString(ByteStringView strWords) {
81 if (strWords.IsEmpty())
83 return PDF_EncodeString(strWords) +
" Tj\n";
89 fxcrt::ostringstream sRet;
92 if (sFontAlias.GetLength() > 0 && fFontSize > 0)
93 sRet <<
"/" << sFontAlias <<
" " << fFontSize <<
" Tf\n";
95 return ByteString(sRet);
100 const CFX_PointF& ptOffset,
103 fxcrt::ostringstream sEditStream;
104 fxcrt::ostringstream sLineStream;
107 int32_t nCurFontIndex = -1;
116 sLineStream << GetWordRenderString(sWords.AsStringView());
117 sEditStream << sLineStream.str();
123 ptNew = CFX_PointF(word.ptWord.x + ptOffset.x,
124 word.ptWord.y + ptOffset.y);
128 ptNew = CFX_PointF(line.ptLine.x + ptOffset.x,
129 line.ptLine.y + ptOffset.y);
131 if (ptNew != ptOld) {
132 sLineStream << ptNew.x - ptOld.x <<
" " << ptNew.y - ptOld.y
141 sLineStream << GetWordRenderString(sWords.AsStringView());
144 sLineStream << GetFontSetString(pFontMap, word
.nFontIndex,
148 sWords
+= GetPDFWordString(pFontMap, nCurFontIndex, word
.Word, SubWord);
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
162 sEditStream << GetFontSetString(pFontMap, word
.nFontIndex,
166 sEditStream << GetWordRenderString(
167 GetPDFWordString(pFontMap, nCurFontIndex, word
.Word, SubWord)
173 sLineStream << GetWordRenderString(sWords.AsStringView());
174 sEditStream << sLineStream.str();
176 return ByteString(sEditStream);
179ByteString GenerateColorAP(
const CFX_Color& color, PaintOperation nOperation) {
180 fxcrt::ostringstream sColorStream;
185 << (nOperation == PaintOperation::kStroke ?
"RG" :
"rg")
189 sColorStream << color
.fColor1 <<
" "
190 << (nOperation == PaintOperation::kStroke ?
"G" :
"g")
196 << (nOperation == PaintOperation::kStroke ?
"K" :
"k")
202 return ByteString(sColorStream);
211 const CPVT_Dash& dash) {
212 fxcrt::ostringstream sAppStream;
214 float fLeft = rect
.left;
215 float fRight = rect
.right;
216 float fTop = rect
.top;
219 float fHalfWidth = fWidth / 2.0f;
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";
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
242 sAppStream << fLeft + fWidth / 2 <<
" " << fTop - fWidth / 2
244 sAppStream << fRight - fWidth / 2 <<
" " << fTop - fWidth / 2
246 sAppStream << fRight - fWidth / 2 <<
" " << fBottom + fWidth / 2
248 sAppStream << fLeft + fWidth / 2 <<
" " << fBottom + fWidth / 2
254 sColor
= GenerateColorAP(crLeftTop, PaintOperation::kFill);
255 if (sColor.GetLength() > 0) {
256 sAppStream << sColor;
257 sAppStream << fLeft + fHalfWidth <<
" " << fBottom + fHalfWidth
259 sAppStream << fLeft + fHalfWidth <<
" " << fTop - fHalfWidth
261 sAppStream << fRight - fHalfWidth <<
" " << fTop - fHalfWidth
263 sAppStream << fRight - fHalfWidth * 2 <<
" " << fTop - fHalfWidth * 2
265 sAppStream << fLeft + fHalfWidth * 2 <<
" " << fTop - fHalfWidth * 2
267 sAppStream << fLeft + fHalfWidth * 2 <<
" "
268 << fBottom + fHalfWidth * 2 <<
" l f\n";
270 sColor
= GenerateColorAP(crRightBottom, PaintOperation::kFill);
271 if (sColor.GetLength() > 0) {
272 sAppStream << sColor;
273 sAppStream << fRight - fHalfWidth <<
" " << fTop - fHalfWidth
275 sAppStream << fRight - fHalfWidth <<
" " << fBottom + fHalfWidth
277 sAppStream << fLeft + fHalfWidth <<
" " << fBottom + fHalfWidth
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
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";
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";
307 return ByteString(sAppStream);
310ByteString GetColorStringWithDefault(
const CPDF_Array* pColor,
312 PaintOperation nOperation) {
315 return GenerateColorAP(color, nOperation);
318 return GenerateColorAP(crDefaultColor, nOperation);
321float GetBorderWidth(
const CPDF_Dictionary* pDict) {
322 RetainPtr<
const CPDF_Dictionary> pBorderStyleDict = pDict->GetDictFor(
"BS");
323 if (pBorderStyleDict && pBorderStyleDict->KeyExist(
"W"))
324 return pBorderStyleDict->GetFloatFor(
"W");
327 if (pBorderArray && pBorderArray->size() > 2)
328 return pBorderArray->GetFloatAt(2);
333RetainPtr<
const CPDF_Array> GetDashArray(
const CPDF_Dictionary* pDict) {
334 RetainPtr<
const CPDF_Dictionary> pBorderStyleDict = pDict->GetDictFor(
"BS");
335 if (pBorderStyleDict && pBorderStyleDict->GetByteStringFor(
"S") ==
"D")
336 return pBorderStyleDict->GetArrayFor(
"D");
338 RetainPtr<
const CPDF_Array> pBorderArray =
339 pDict->GetArrayFor(pdfium::annotation::kBorder);
340 if (pBorderArray && pBorderArray->size() == 4)
341 return pBorderArray->GetArrayAt(3);
346ByteString GetDashPatternString(
const CPDF_Dictionary* pDict) {
347 RetainPtr<
const CPDF_Array> pDashArray = GetDashArray(pDict);
348 if (!pDashArray || pDashArray->IsEmpty())
352 size_t pDashArrayCount = std::min<size_t>(pDashArray->size(), 10);
353 fxcrt::ostringstream sDashStream;
356 for (size_t i = 0; i < pDashArrayCount; ++i)
357 sDashStream << pDashArray->GetFloatAt(i) <<
" ";
358 sDashStream <<
"] 0 d\n";
360 return ByteString(sDashStream);
364 const CPDF_Dictionary& pAnnotDict,
366 const ByteString& sFontName) {
371 CPVT_FontMap map(pDoc,
nullptr,
std::move(pDefFont), sFontName);
382 CFX_PointF ptOffset(3.0f, -3.0f);
383 ByteString sContent =
389 ByteString sColorAP = GenerateColorAP(
392 return ByteString{
"BT\n", sColorAP.AsStringView(), sContent.AsStringView(),
397 auto font_dict = doc->NewIndirect<CPDF_Dictionary>();
398 font_dict->SetNewFor<CPDF_Name>(
"Type",
"Font");
399 font_dict->SetNewFor<CPDF_Name>(
"Subtype",
"Type1");
401 font_dict->SetNewFor<CPDF_Name>(
"Encoding",
406RetainPtr<CPDF_Dictionary> GenerateResourceFontDict(
408 const ByteString& font_name,
409 uint32_t font_dict_obj_num) {
410 auto resource_font_dict = doc->New<CPDF_Dictionary>();
411 resource_font_dict->SetNewFor<CPDF_Reference>(font_name, doc,
413 return resource_font_dict;
416ByteString GetPaintOperatorString(
bool bIsStrokeRect,
bool bIsFillRect) {
418 return bIsFillRect ?
"b" :
"s";
419 return bIsFillRect ?
"f" :
"n";
423 fxcrt::ostringstream sAppStream;
425 PaintOperation::kFill);
427 PaintOperation::kStroke);
429 const float fBorderWidth = 1;
430 sAppStream << fBorderWidth <<
" w\n";
432 const float fHalfWidth = fBorderWidth / 2;
433 const float fTipDelta = 4;
437 outerRect1
.bottom += fTipDelta;
440 outerRect2
.left += fTipDelta;
443 float outerRect2Middle = (outerRect2
.left + outerRect2
.right) / 2;
446 sAppStream << outerRect1
.left <<
" " << outerRect1
.bottom <<
" m\n"
447 << outerRect1
.left <<
" " << outerRect1
.top <<
" l\n"
448 << outerRect1
.right <<
" " << outerRect1
.top <<
" l\n"
451 << outerRect2Middle <<
" " << outerRect2
.top <<
" l\n"
452 << outerRect2
.left <<
" " << outerRect2
.bottom <<
" l\n"
453 << outerRect1
.left <<
" " << outerRect1
.bottom <<
" l\n";
457 const float fXDelta = 2;
458 const float fYDelta = (lineRect
.top - lineRect
.bottom) / 4;
460 lineRect
.left += fXDelta;
461 lineRect
.right -= fXDelta;
462 for (
int i = 0; i < 3; ++i) {
463 lineRect
.top -= fYDelta;
464 sAppStream << lineRect
.left <<
" " << lineRect
.top <<
" m\n"
465 << lineRect
.right <<
" " << lineRect
.top <<
" l\n";
467 sAppStream <<
"B*\n";
469 return ByteString(sAppStream);
472RetainPtr<CPDF_Dictionary> GenerateExtGStateDict(
473 const CPDF_Dictionary& pAnnotDict,
474 const ByteString& sExtGSDictName,
475 const ByteString& sBlendMode) {
477 pdfium::MakeRetain<CPDF_Dictionary>(pAnnotDict.GetByteStringPool());
478 pGSDict->SetNewFor<CPDF_Name>(
"Type",
"ExtGState");
481 pGSDict->SetNewFor<CPDF_Number>(
"CA", fOpacity);
482 pGSDict->SetNewFor<CPDF_Number>(
"ca", fOpacity);
483 pGSDict->SetNewFor<CPDF_Boolean>(
"AIS",
false);
484 pGSDict->SetNewFor<CPDF_Name>(
"BM", sBlendMode);
486 auto pExtGStateDict =
487 pdfium::MakeRetain<CPDF_Dictionary>(pAnnotDict.GetByteStringPool());
488 pExtGStateDict->SetFor(sExtGSDictName, pGSDict);
489 return pExtGStateDict;
492RetainPtr<CPDF_Dictionary> GenerateResourceDict(
494 RetainPtr<CPDF_Dictionary> pExtGStateDict,
495 RetainPtr<CPDF_Dictionary> pResourceFontDict) {
496 auto pResourceDict = pDoc->New<CPDF_Dictionary>();
498 pResourceDict->SetFor(
"ExtGState", pExtGStateDict);
499 if (pResourceFontDict)
500 pResourceDict->SetFor(
"Font", pResourceFontDict);
501 return pResourceDict;
505 CPDF_Dictionary* pAnnotDict,
506 fxcrt::ostringstream* psAppStream,
507 RetainPtr<CPDF_Dictionary> pResourceDict,
508 bool bIsTextMarkupAnnotation) {
509 auto pNormalStream = pDoc->NewIndirect<CPDF_Stream>();
510 pNormalStream->SetDataFromStringstream(psAppStream);
513 pAnnotDict->GetOrCreateDictFor(pdfium::annotation::kAP);
514 pAPDict->SetNewFor<CPDF_Reference>(
"N", pDoc, pNormalStream->GetObjNum());
516 RetainPtr<CPDF_Dictionary> pStreamDict = pNormalStream->GetMutableDict();
517 pStreamDict->SetNewFor<CPDF_Number>(
"FormType", 1);
518 pStreamDict->SetNewFor<CPDF_Name>(
"Type",
"XObject");
519 pStreamDict->SetNewFor<CPDF_Name>(
"Subtype",
"Form");
525 pStreamDict->SetRectFor(
"BBox", rect);
526 pStreamDict->SetFor(
"Resources", pResourceDict);
529bool GenerateCircleAP(
CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict) {
530 fxcrt::ostringstream sAppStream;
531 ByteString sExtGSDictName =
"GS";
532 sAppStream <<
"/" << sExtGSDictName <<
" gs ";
534 RetainPtr<
const CPDF_Array> pInteriorColor = pAnnotDict->GetArrayFor(
"IC");
535 sAppStream << GetColorStringWithDefault(
537 PaintOperation::kFill);
539 sAppStream << GetColorStringWithDefault(
543 float fBorderWidth = GetBorderWidth(pAnnotDict);
544 bool bIsStrokeRect = fBorderWidth > 0;
547 sAppStream << fBorderWidth <<
" w ";
548 sAppStream << GetDashPatternString(pAnnotDict);
561 const float fMiddleX = (rect
.left + rect
.right) / 2;
562 const float fMiddleY = (rect
.top + rect
.bottom) / 2;
567 const float fL = 0.5523f;
568 const float fDeltaX = fL * rect
.Width() / 2.0;
569 const float fDeltaY = fL * rect
.Height() / 2.0;
572 sAppStream << fMiddleX <<
" " << rect
.top <<
" m\n";
574 sAppStream << fMiddleX + fDeltaX <<
" " << rect
.top <<
" " << rect
.right
575 <<
" " << fMiddleY + fDeltaY <<
" " << rect
.right <<
" "
576 << fMiddleY <<
" c\n";
578 sAppStream << rect
.right <<
" " << fMiddleY - fDeltaY <<
" "
579 << fMiddleX + fDeltaX <<
" " << rect
.bottom <<
" " << fMiddleX
580 <<
" " << rect
.bottom <<
" c\n";
582 sAppStream << fMiddleX - fDeltaX <<
" " << rect
.bottom <<
" " << rect
.left
583 <<
" " << fMiddleY - fDeltaY <<
" " << rect
.left <<
" " << fMiddleY
586 sAppStream << rect
.left <<
" " << fMiddleY + fDeltaY <<
" "
587 << fMiddleX - fDeltaX <<
" " << rect
.top <<
" " << fMiddleX <<
" "
588 << rect
.top <<
" c\n";
590 bool bIsFillRect = pInteriorColor && !pInteriorColor->IsEmpty();
591 sAppStream << GetPaintOperatorString(bIsStrokeRect, bIsFillRect) <<
"\n";
593 auto pExtGStateDict =
594 GenerateExtGStateDict(*pAnnotDict, sExtGSDictName,
"Normal");
596 GenerateResourceDict(pDoc, std::move(pExtGStateDict),
nullptr);
597 GenerateAndSetAPDict(pDoc, pAnnotDict, &sAppStream,
std::move(pResourceDict),
602bool GenerateHighlightAP(
CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict) {
603 fxcrt::ostringstream sAppStream;
604 ByteString sExtGSDictName =
"GS";
605 sAppStream <<
"/" << sExtGSDictName <<
" gs ";
607 sAppStream << GetColorStringWithDefault(
611 RetainPtr<
const CPDF_Array> pArray = pAnnotDict->GetArrayFor(
"QuadPoints");
613 size_t nQuadPointCount = CPDF_Annot::QuadPointCount(pArray.Get());
614 for (size_t i = 0; i < nQuadPointCount; ++i) {
615 CFX_FloatRect rect = CPDF_Annot::RectFromQuadPoints(pAnnotDict, i);
618 sAppStream << rect
.left <<
" " << rect
.top <<
" m " << rect
.right <<
" "
620 <<
" l " << rect
.left <<
" " << rect
.bottom <<
" l h f\n";
624 auto pExtGStateDict =
625 GenerateExtGStateDict(*pAnnotDict, sExtGSDictName,
"Multiply");
627 GenerateResourceDict(pDoc, std::move(pExtGStateDict),
nullptr);
628 GenerateAndSetAPDict(pDoc, pAnnotDict, &sAppStream,
std::move(pResourceDict),
634bool GenerateInkAP(
CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict) {
635 RetainPtr<
const CPDF_Array> pInkList = pAnnotDict->GetArrayFor(
"InkList");
636 if (!pInkList || pInkList->IsEmpty())
639 float fBorderWidth = GetBorderWidth(pAnnotDict);
640 const bool bIsStroke = fBorderWidth > 0;
644 ByteString sExtGSDictName =
"GS";
645 fxcrt::ostringstream sAppStream;
646 sAppStream <<
"/" << sExtGSDictName <<
" gs ";
647 sAppStream << GetColorStringWithDefault(
651 sAppStream << fBorderWidth <<
" w ";
652 sAppStream << GetDashPatternString(pAnnotDict);
660 for (size_t i = 0; i < pInkList->size(); i++) {
661 RetainPtr<
const CPDF_Array> pInkCoordList = pInkList->GetArrayAt(i);
662 if (!pInkCoordList || pInkCoordList->size() < 2)
665 sAppStream << pInkCoordList->GetFloatAt(0) <<
" "
666 << pInkCoordList->GetFloatAt(1) <<
" m ";
668 for (size_t j = 0; j < pInkCoordList->size() - 1; j += 2) {
669 sAppStream << pInkCoordList->GetFloatAt(j) <<
" "
670 << pInkCoordList->GetFloatAt(j + 1) <<
" l ";
676 auto pExtGStateDict =
677 GenerateExtGStateDict(*pAnnotDict, sExtGSDictName,
"Normal");
679 GenerateResourceDict(pDoc, std::move(pExtGStateDict),
nullptr);
680 GenerateAndSetAPDict(pDoc, pAnnotDict, &sAppStream,
std::move(pResourceDict),
685bool GenerateTextAP(
CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict) {
686 fxcrt::ostringstream sAppStream;
687 ByteString sExtGSDictName =
"GS";
688 sAppStream <<
"/" << sExtGSDictName <<
" gs ";
691 const float fNoteLength = 20;
696 sAppStream << GenerateTextSymbolAP(noteRect);
698 auto pExtGStateDict =
699 GenerateExtGStateDict(*pAnnotDict, sExtGSDictName,
"Normal");
701 GenerateResourceDict(pDoc, std::move(pExtGStateDict),
nullptr);
702 GenerateAndSetAPDict(pDoc, pAnnotDict, &sAppStream,
std::move(pResourceDict),
707bool GenerateUnderlineAP(
CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict) {
708 fxcrt::ostringstream sAppStream;
709 ByteString sExtGSDictName =
"GS";
710 sAppStream <<
"/" << sExtGSDictName <<
" gs ";
712 sAppStream << GetColorStringWithDefault(
716 RetainPtr<
const CPDF_Array> pArray = pAnnotDict->GetArrayFor(
"QuadPoints");
718 static constexpr float kLineWidth = 1.0f;
719 sAppStream << kLineWidth <<
" w ";
720 size_t nQuadPointCount = CPDF_Annot::QuadPointCount(pArray.Get());
721 for (size_t i = 0; i < nQuadPointCount; ++i) {
722 CFX_FloatRect rect = CPDF_Annot::RectFromQuadPoints(pAnnotDict, i);
724 sAppStream << rect
.left <<
" " << rect
.bottom + kLineWidth <<
" m "
725 << rect
.right <<
" " << rect
.bottom + kLineWidth <<
" l S\n";
729 auto pExtGStateDict =
730 GenerateExtGStateDict(*pAnnotDict, sExtGSDictName,
"Normal");
732 GenerateResourceDict(pDoc, std::move(pExtGStateDict),
nullptr);
733 GenerateAndSetAPDict(pDoc, pAnnotDict, &sAppStream,
std::move(pResourceDict),
738bool GeneratePopupAP(
CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict) {
739 fxcrt::ostringstream sAppStream;
740 ByteString sExtGSDictName =
"GS";
741 sAppStream <<
"/" << sExtGSDictName <<
" gs\n";
744 PaintOperation::kFill);
746 PaintOperation::kStroke);
748 const float fBorderWidth = 1;
749 sAppStream << fBorderWidth <<
" w\n";
758 RetainPtr<CPDF_Dictionary> font_dict = GenerateFallbackFontDict(pDoc);
764 const ByteString font_name =
"FONT";
765 RetainPtr<CPDF_Dictionary> resource_font_dict =
766 GenerateResourceFontDict(pDoc, font_name, font_dict->GetObjNum());
767 RetainPtr<CPDF_Dictionary> pExtGStateDict =
768 GenerateExtGStateDict(*pAnnotDict, sExtGSDictName,
"Normal");
769 RetainPtr<CPDF_Dictionary> pResourceDict = GenerateResourceDict(
770 pDoc, std::move(pExtGStateDict), std::move(resource_font_dict));
772 sAppStream << GetPopupContentsString(pDoc, *pAnnotDict,
std::move(pDefFont),
774 GenerateAndSetAPDict(pDoc, pAnnotDict, &sAppStream,
std::move(pResourceDict),
779bool GenerateSquareAP(
CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict) {
780 const ByteString sExtGSDictName =
"GS";
781 fxcrt::ostringstream sAppStream;
782 sAppStream <<
"/" << sExtGSDictName <<
" gs ";
784 RetainPtr<
const CPDF_Array> pInteriorColor = pAnnotDict->GetArrayFor(
"IC");
785 sAppStream << GetColorStringWithDefault(
787 PaintOperation::kFill);
789 sAppStream << GetColorStringWithDefault(
793 float fBorderWidth = GetBorderWidth(pAnnotDict);
794 const bool bIsStrokeRect = fBorderWidth > 0;
796 sAppStream << fBorderWidth <<
" w ";
797 sAppStream << GetDashPatternString(pAnnotDict);
810 const bool bIsFillRect = pInteriorColor && (pInteriorColor->size() > 0);
813 << GetPaintOperatorString(bIsStrokeRect, bIsFillRect) <<
"\n";
815 auto pExtGStateDict =
816 GenerateExtGStateDict(*pAnnotDict, sExtGSDictName,
"Normal");
818 GenerateResourceDict(pDoc, std::move(pExtGStateDict),
nullptr);
819 GenerateAndSetAPDict(pDoc, pAnnotDict, &sAppStream,
std::move(pResourceDict),
824bool GenerateSquigglyAP(
CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict) {
825 fxcrt::ostringstream sAppStream;
826 ByteString sExtGSDictName =
"GS";
827 sAppStream <<
"/" << sExtGSDictName <<
" gs ";
829 sAppStream << GetColorStringWithDefault(
833 RetainPtr<
const CPDF_Array> pArray = pAnnotDict->GetArrayFor(
"QuadPoints");
835 static constexpr float kLineWidth = 1.0f;
836 static constexpr float kDelta = 2.0f;
837 sAppStream << kLineWidth <<
" w ";
838 size_t nQuadPointCount = CPDF_Annot::QuadPointCount(pArray.Get());
839 for (size_t i = 0; i < nQuadPointCount; ++i) {
840 CFX_FloatRect rect = CPDF_Annot::RectFromQuadPoints(pAnnotDict, i);
843 const float fTop = rect
.bottom + kDelta;
844 const float fBottom = rect
.bottom;
845 sAppStream << rect
.left <<
" " << fTop <<
" m ";
847 float fX = rect
.left + kDelta;
848 bool isUpwards =
false;
850 sAppStream << fX <<
" " << (isUpwards ? fTop : fBottom) <<
" l ";
852 isUpwards = !isUpwards;
855 float fRemainder = rect
.right - (fX - kDelta);
857 sAppStream << rect
.right <<
" " << fBottom + fRemainder <<
" l ";
859 sAppStream << rect
.right <<
" " << fTop - fRemainder <<
" l ";
865 auto pExtGStateDict =
866 GenerateExtGStateDict(*pAnnotDict, sExtGSDictName,
"Normal");
868 GenerateResourceDict(pDoc, std::move(pExtGStateDict),
nullptr);
869 GenerateAndSetAPDict(pDoc, pAnnotDict, &sAppStream,
std::move(pResourceDict),
874bool GenerateStrikeOutAP(
CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict) {
875 fxcrt::ostringstream sAppStream;
876 ByteString sExtGSDictName =
"GS";
877 sAppStream <<
"/" << sExtGSDictName <<
" gs ";
879 sAppStream << GetColorStringWithDefault(
883 RetainPtr<
const CPDF_Array> pArray = pAnnotDict->GetArrayFor(
"QuadPoints");
885 static constexpr float kLineWidth = 1.0f;
886 size_t nQuadPointCount = CPDF_Annot::QuadPointCount(pArray.Get());
887 for (size_t i = 0; i < nQuadPointCount; ++i) {
888 CFX_FloatRect rect = CPDF_Annot::RectFromQuadPoints(pAnnotDict, i);
892 sAppStream << kLineWidth <<
" w " << rect
.left <<
" " << fY <<
" m "
893 << rect
.right <<
" " << fY <<
" l S\n";
897 auto pExtGStateDict =
898 GenerateExtGStateDict(*pAnnotDict, sExtGSDictName,
"Normal");
900 GenerateResourceDict(pDoc, std::move(pExtGStateDict),
nullptr);
901 GenerateAndSetAPDict(pDoc, pAnnotDict, &sAppStream,
std::move(pResourceDict),
910 CPDF_Dictionary* pAnnotDict,
912 RetainPtr<CPDF_Dictionary> pRootDict = pDoc->GetMutableRoot();
917 pRootDict->GetMutableDictFor(
"AcroForm");
923 CPDF_FormField::GetFieldAttrForDict(pAnnotDict,
"DA");
925 DA = pDAObj->GetString();
927 DA = pFormDict->GetByteStringFor(
"DA");
934 absl::optional<ByteString> font = appearance.GetFont(&fFontSize);
935 if (!font.has_value())
938 ByteString font_name = font.value();
941 RetainPtr<CPDF_Dictionary> pDRDict = pFormDict->GetMutableDictFor(
"DR");
945 RetainPtr<CPDF_Dictionary> pDRFontDict = pDRDict->GetMutableDictFor(
"Font");
946 if (!ValidateFontResourceDict(pDRFontDict.Get()))
950 pDRFontDict->GetMutableDictFor(font_name);
952 pFontDict = GenerateFallbackFontDict(pDoc);
953 pDRFontDict->SetNewFor<CPDF_Reference>(font_name, pDoc,
954 pFontDict->GetObjNum());
962 RetainPtr<
const CPDF_Dictionary> pMKDict = pAnnotDict->GetDictFor(
"MK");
968 switch (nRotate % 360) {
992 float fBorderWidth = 1;
993 CPVT_Dash dsBorder(3, 0, 0);
996 if (RetainPtr<
const CPDF_Dictionary> pBSDict = pAnnotDict->GetDictFor(
"BS")) {
997 if (pBSDict->KeyExist(
"W"))
998 fBorderWidth = pBSDict->GetFloatFor(
"W");
1000 if (RetainPtr<
const CPDF_Array> pArray = pBSDict->GetArrayFor(
"D")) {
1001 dsBorder = CPVT_Dash(pArray->GetIntegerAt(0), pArray->GetIntegerAt(1),
1002 pArray->GetIntegerAt(2));
1004 if (pBSDict->GetByteStringFor(
"S").GetLength()) {
1005 switch (pBSDict->GetByteStringFor(
"S")[0]) {
1034 pMKDict->GetArrayFor(pdfium::appearance::kBC);
1041 fxcrt::ostringstream sAppStream;
1042 ByteString sBG = GenerateColorAP(crBG, PaintOperation::kFill);
1043 if (sBG.GetLength() > 0) {
1049 ByteString sBorderStream =
1050 GenerateBorderAP(rcBBox, fBorderWidth, crBorder, crLeftTop, crRightBottom,
1051 nBorderStyle, dsBorder);
1052 if (sBorderStream.GetLength() > 0)
1053 sAppStream <<
"q\n" << sBorderStream <<
"Q\n";
1057 rcBBox
.right - fBorderWidth
, rcBBox
.top - fBorderWidth
);
1061 pAnnotDict->GetOrCreateDictFor(pdfium::annotation::kAP);
1062 RetainPtr<CPDF_Stream> pNormalStream = pAPDict->GetMutableStreamFor(
"N");
1063 if (!pNormalStream) {
1064 pNormalStream = pDoc->NewIndirect<CPDF_Stream>();
1065 pAPDict->SetNewFor<CPDF_Reference>(
"N", pDoc, pNormalStream->GetObjNum());
1067 RetainPtr<CPDF_Dictionary> pStreamDict = pNormalStream->GetMutableDict();
1069 RetainPtr<CPDF_Dictionary> pStreamResList =
1070 pStreamDict->GetMutableDictFor(
"Resources");
1071 if (pStreamResList) {
1072 RetainPtr<CPDF_Dictionary> pStreamResFontList =
1073 pStreamResList->GetMutableDictFor(
"Font");
1074 if (pStreamResFontList) {
1075 if (!ValidateFontResourceDict(pStreamResFontList.Get()))
1078 pStreamResFontList = pStreamResList->SetNewFor<CPDF_Dictionary>(
"Font");
1080 if (!pStreamResFontList->KeyExist(font_name)) {
1081 pStreamResFontList->SetNewFor<CPDF_Reference>(font_name, pDoc,
1082 pFontDict->GetObjNum());
1085 pStreamDict->SetFor(
"Resources", pFormDict->GetDictFor(
"DR")->Clone());
1087 pStreamDict->SetMatrixFor(
"Matrix", matrix);
1088 pStreamDict->SetRectFor(
"BBox", rcBBox);
1091 pDoc, pStreamDict ? pStreamDict->GetMutableDictFor(
"Resources") :
nullptr,
1092 std::move(pDefFont), font_name);
1098 pAnnotDict, pdfium::form_fields::kV);
1099 WideString swValue = pV ? pV->GetUnicodeText() : WideString
();
1101 CPDF_FormField::GetFieldAttrForDict(pAnnotDict,
"Q");
1102 int32_t nAlign = pQ ? pQ->GetInteger() : 0;
1104 pAnnotDict, pdfium::form_fields::kFf);
1105 uint32_t dwFlags = pFf ? pFf->GetInteger() : 0;
1107 CPDF_FormField::GetFieldAttrForDict(pAnnotDict,
"MaxLen");
1108 uint32_t dwMaxLen = pMaxLen ? pMaxLen->GetInteger() : 0;
1117 bool bMultiLine = (dwFlags >> 12) & 1;
1122 uint16_t subWord = 0;
1123 if ((dwFlags >> 13) & 1) {
1127 bool bCharArray = (dwFlags >> 24) & 1;
1137 CFX_PointF ptOffset;
1142 ByteString sBody = GenerateEditAP(&map, vt
.GetIterator(), ptOffset,
1143 !bCharArray, subWord);
1144 if (sBody.GetLength() > 0) {
1145 sAppStream <<
"/Tx BMC\n"
1149 sAppStream << rcBody
.left <<
" " << rcBody
.bottom <<
" "
1153 sAppStream <<
"BT\n"
1154 << GenerateColorAP(crText, PaintOperation::kFill) << sBody
1162 pAnnotDict, pdfium::form_fields::kV);
1163 WideString swValue = pV ? pV->GetUnicodeText() : WideString
();
1181 CFX_PointF ptOffset =
1182 CFX_PointF(0.0f, (rcContent.Height() - rcEdit.Height()) / 2.0f);
1185 if (sEdit.GetLength() > 0) {
1186 sAppStream <<
"/Tx BMC\n"
1188 sAppStream << rcEdit
.left <<
" " << rcEdit
.bottom <<
" "
1190 sAppStream <<
"BT\n"
1191 << GenerateColorAP(crText, PaintOperation::kFill) << sEdit
1195 ByteString sButton =
1197 220.0f / 255.0f
, 220.0f / 255.0f
),
1198 PaintOperation::kFill);
1199 if (sButton.GetLength() > 0 && !rcButton
.IsEmpty()) {
1200 sAppStream <<
"q\n" << sButton;
1201 sAppStream << rcButton
.left <<
" " << rcButton
.bottom <<
" "
1203 sAppStream <<
"Q\n";
1204 ByteString sButtonBorder =
1209 if (sButtonBorder.GetLength() > 0)
1210 sAppStream <<
"q\n" << sButtonBorder <<
"Q\n";
1212 CFX_PointF ptCenter = CFX_PointF((rcButton.left + rcButton.right) / 2,
1213 (rcButton.top + rcButton.bottom) / 2);
1218 sAppStream << ptCenter.x - 3 <<
" " << ptCenter.y + 1.5f <<
" m\n";
1219 sAppStream << ptCenter.x + 3 <<
" " << ptCenter.y + 1.5f <<
" l\n";
1220 sAppStream << ptCenter.x <<
" " << ptCenter.y - 1.5f <<
" l\n";
1221 sAppStream << ptCenter.x - 3 <<
" " << ptCenter.y + 1.5f <<
" l f\n";
1222 sAppStream << sButton <<
"Q\n";
1229 ToArray(CPDF_FormField::GetFieldAttrForDict(pAnnotDict,
"Opt"));
1231 ToArray(CPDF_FormField::GetFieldAttrForDict(pAnnotDict,
"I"));
1233 CPDF_FormField::GetFieldAttrForDict(pAnnotDict,
"TI");
1234 int32_t nTop = pTi ? pTi->GetInteger() : 0;
1235 fxcrt::ostringstream sBody;
1237 float fy = rcBody
.top;
1238 for (size_t i = nTop, sz = pOpts->size(); i < sz; i++) {
1242 if (RetainPtr<
const CPDF_Object> pOpt = pOpts->GetDirectObjectAt(i)) {
1244 if (pOpt->IsString()) {
1245 swItem = pOpt->GetUnicodeText();
1246 }
else if (
const CPDF_Array* pArray = pOpt->AsArray()) {
1247 RetainPtr<
const CPDF_Object> pDirectObj =
1248 pArray->GetDirectObjectAt(1);
1250 swItem = pDirectObj->GetUnicodeText();
1252 bool bSelected =
false;
1254 for (size_t s = 0, ssz = pSels->size(); s < ssz; s++) {
1255 int value = pSels->GetIntegerAt(s);
1256 if (value >= 0 && i ==
static_cast<size_t>(value)) {
1262 CPVT_VariableText vt(&prd);
1264 CFX_FloatRect(rcBody.left, 0.0f, rcBody.right, 0.0f));
1270 float fItemHeight = vt.GetContentRect().Height();
1272 CFX_FloatRect rcItem = CFX_FloatRect(
1273 rcBody.left, fy - fItemHeight, rcBody.right, fy);
1276 CFX_Color(CFX_Color::Type::kRGB, 0, 51.0f / 255.0f,
1278 PaintOperation::kFill)
1279 << rcItem.left <<
" " << rcItem.bottom <<
" "
1280 << rcItem.Width() <<
" " << rcItem.Height() <<
" re f\n"
1283 << GenerateColorAP(CFX_Color(CFX_Color::Type::kGray, 1),
1284 PaintOperation::kFill)
1285 << GenerateEditAP(&map, vt.GetIterator(),
1286 CFX_PointF(0.0f, fy),
true, 0)
1290 << GenerateColorAP(crText, PaintOperation::kFill)
1291 << GenerateEditAP(&map, vt.GetIterator(),
1292 CFX_PointF(0.0f, fy),
true, 0)
1299 if (sBody.tellp() > 0) {
1300 sAppStream <<
"/Tx BMC\nq\n"
1303 << sBody.str() <<
"Q\nEMC\n";
1312 pNormalStream->SetDataFromStringstreamAndRemoveFilter(&sAppStream);
1313 pStreamDict = pNormalStream->GetMutableDict();
1317 pStreamDict->SetMatrixFor(
"Matrix", matrix);
1318 pStreamDict->SetRectFor(
"BBox", rcBBox);
1319 RetainPtr<CPDF_Dictionary> pStreamResList =
1320 pStreamDict->GetMutableDictFor(
"Resources");
1321 if (!pStreamResList) {
1322 pStreamDict->SetFor(
"Resources", pFormDict->GetDictFor(
"DR")->Clone());
1326 RetainPtr<CPDF_Dictionary> pStreamResFontList =
1327 pStreamResList->GetMutableDictFor(
"Font");
1328 if (pStreamResFontList) {
1329 if (!ValidateFontResourceDict(pStreamResFontList.Get()))
1332 pStreamResFontList = pStreamResList->SetNewFor<CPDF_Dictionary>(
"Font");
1335 if (!pStreamResFontList->KeyExist(font_name)) {
1336 pStreamResFontList->SetNewFor<CPDF_Reference>(font_name, pDoc,
1337 pFontDict->GetObjNum());
1343 CPDF_Dictionary* pAnnotDict) {
1344 auto pExtGStateDict = GenerateExtGStateDict(*pAnnotDict,
"GS",
"Normal");
1345 auto pResourceDict =
1346 GenerateResourceDict(pDoc, std::move(pExtGStateDict),
nullptr);
1348 fxcrt::ostringstream sStream;
1349 GenerateAndSetAPDict(pDoc, pAnnotDict, &sStream,
std::move(pResourceDict),
1355 CPDF_Dictionary* pAnnotDict,
1359 return GenerateCircleAP(pDoc, pAnnotDict);
1361 return GenerateHighlightAP(pDoc, pAnnotDict);
1363 return GenerateInkAP(pDoc, pAnnotDict);
1365 return GeneratePopupAP(pDoc, pAnnotDict);
1367 return GenerateSquareAP(pDoc, pAnnotDict);
1369 return GenerateSquigglyAP(pDoc, pAnnotDict);
1371 return GenerateStrikeOutAP(pDoc, pAnnotDict);
1373 return GenerateTextAP(pDoc, pAnnotDict);
1375 return GenerateUnderlineAP(pDoc, pAnnotDict);
constexpr CFX_FloatRect(float l, float b, float r, float t)
void Inflate(float x, float y)
CFX_FloatRect & operator=(const CFX_FloatRect &that)=default
void Deflate(float x, float y)
static const char kDefaultAnsiFontName[]
CFX_Matrix & operator=(const CFX_Matrix &other)=default
CFX_Matrix(float a1, float b1, float c1, float d1, float e1, float f1)
static CFX_FloatRect BoundingRectFromQuadPoints(const CPDF_Dictionary *pAnnotDict)
CPDF_DefaultAppearance(const ByteString &csDA)
bool KeyExist(const ByteString &key) const
float GetFloatFor(const ByteString &key) const
WideString GetUnicodeTextFor(const ByteString &key) const
void SetRectFor(const ByteString &key, const CFX_FloatRect &rect)
RetainPtr< const CPDF_Array > GetArrayFor(const ByteString &key) const
CFX_FloatRect GetRectFor(const ByteString &key) const
static CPDF_DocPageData * FromDocument(const CPDF_Document *pDoc)
static constexpr uint32_t kInvalidCharCode
static bool GenerateAnnotAP(CPDF_Document *pDoc, CPDF_Dictionary *pAnnotDict, CPDF_Annot::Subtype subtype)
static void GenerateEmptyAP(CPDF_Document *pDoc, CPDF_Dictionary *pAnnotDict)
static void GenerateFormAP(CPDF_Document *pDoc, CPDF_Dictionary *pAnnotDict, FormType type)
void SetAt(int32_t nWordIndex)
bool GetWord(CPVT_Word &word) const
bool GetLine(CPVT_Line &line) const
const CPVT_WordPlace & GetWordPlace() const
void SetPlateRect(const CFX_FloatRect &rect)
void SetLimitChar(int32_t nLimitChar)
CFX_FloatRect GetContentRect() const
CPVT_VariableText(Provider *Provider)
void SetText(const WideString &text)
CPVT_VariableText::Iterator * GetIterator()
void SetCharArray(int32_t nCharArray)
void SetAlignment(int32_t nFormat)
void SetMultiLine(bool bMultiLine)
void SetAutoFontSize(bool bAuto)
void SetFontSize(float fFontSize)
void SetAutoReturn(bool bAuto)
void SetPasswordChar(uint16_t wSubWord)
virtual ByteString GetPDFFontAlias(int32_t nFontIndex)=0
static ByteString Format(const char *pFormat,...)
ByteString & operator+=(const ByteString &str)
ByteString & operator=(ByteString &&that) noexcept
WideString & operator+=(const WideString &str)
WideString & operator+=(wchar_t ch)
#define FXSYS_IsFloatBigger(fa, fb)
#define FXSYS_IsFloatZero(f)
#define FXSYS_IsFloatSmaller(fa, fb)
CFX_Color CFXColorFromArray(const CPDF_Array &array)
CFX_Color CFXColorFromString(const ByteString &str)
const char kWinAnsiEncoding[]
CFX_Color & operator=(const CFX_Color &that)=default
constexpr CFX_Color(Type type=CFX_Color::Type::kTransparent, float color1=0.0f, float color2=0.0f, float color3=0.0f, float color4=0.0f)
int32_t LineCmp(const CPVT_WordPlace &wp) const