Simplify CPVT_GenerateAP interface
This CL moves the annotation decision inside GenerateAnnotAP and hides
the individual annotation AP generation methods. The form methods are
hidden inside GenerateFormAP and a general GenerateEmptyAP has been
added.
Change-Id: I9e761cb10ceca70681df4e546631a7859f1bfc7c
Reviewed-on: https://pdfium-review.googlesource.com/16130
Reviewed-by: Henrique Nakashima <hnakashima@chromium.org>
Commit-Queue: dsinclair <dsinclair@chromium.org>
diff --git a/core/fpdfdoc/cpdf_annot.cpp b/core/fpdfdoc/cpdf_annot.cpp
index 1ccb890..9f8ab78 100644
--- a/core/fpdfdoc/cpdf_annot.cpp
+++ b/core/fpdfdoc/cpdf_annot.cpp
@@ -87,32 +87,13 @@
void CPDF_Annot::GenerateAPIfNeeded() {
if (!ShouldGenerateAPForAnnotation(m_pAnnotDict.Get()))
return;
-
- CPDF_Dictionary* pDict = m_pAnnotDict.Get();
- bool result = false;
- if (m_nSubtype == CPDF_Annot::Subtype::CIRCLE)
- result = CPVT_GenerateAP::GenerateCircleAP(m_pDocument.Get(), pDict);
- else if (m_nSubtype == CPDF_Annot::Subtype::HIGHLIGHT)
- result = CPVT_GenerateAP::GenerateHighlightAP(m_pDocument.Get(), pDict);
- else if (m_nSubtype == CPDF_Annot::Subtype::INK)
- result = CPVT_GenerateAP::GenerateInkAP(m_pDocument.Get(), pDict);
- else if (m_nSubtype == CPDF_Annot::Subtype::POPUP)
- result = CPVT_GenerateAP::GeneratePopupAP(m_pDocument.Get(), pDict);
- else if (m_nSubtype == CPDF_Annot::Subtype::SQUARE)
- result = CPVT_GenerateAP::GenerateSquareAP(m_pDocument.Get(), pDict);
- else if (m_nSubtype == CPDF_Annot::Subtype::SQUIGGLY)
- result = CPVT_GenerateAP::GenerateSquigglyAP(m_pDocument.Get(), pDict);
- else if (m_nSubtype == CPDF_Annot::Subtype::STRIKEOUT)
- result = CPVT_GenerateAP::GenerateStrikeOutAP(m_pDocument.Get(), pDict);
- else if (m_nSubtype == CPDF_Annot::Subtype::TEXT)
- result = CPVT_GenerateAP::GenerateTextAP(m_pDocument.Get(), pDict);
- else if (m_nSubtype == CPDF_Annot::Subtype::UNDERLINE)
- result = CPVT_GenerateAP::GenerateUnderlineAP(m_pDocument.Get(), pDict);
-
- if (result) {
- m_pAnnotDict->SetNewFor<CPDF_Boolean>(kPDFiumKey_HasGeneratedAP, result);
- m_bHasGeneratedAP = result;
+ if (!CPVT_GenerateAP::GenerateAnnotAP(m_nSubtype, m_pDocument.Get(),
+ m_pAnnotDict.Get())) {
+ return;
}
+
+ m_pAnnotDict->SetNewFor<CPDF_Boolean>(kPDFiumKey_HasGeneratedAP, true);
+ m_bHasGeneratedAP = true;
}
bool CPDF_Annot::ShouldDrawAnnotation() {
diff --git a/core/fpdfdoc/cpdf_annotlist.cpp b/core/fpdfdoc/cpdf_annotlist.cpp
index c7da676..192649d 100644
--- a/core/fpdfdoc/cpdf_annotlist.cpp
+++ b/core/fpdfdoc/cpdf_annotlist.cpp
@@ -85,15 +85,18 @@
ByteString field_type = pFieldTypeObj->GetString();
if (field_type == "Tx") {
- CPVT_GenerateAP::GenerateTextFieldAP(pDoc, pAnnotDict);
+ CPVT_GenerateAP::GenerateFormAP(CPVT_GenerateAP::kTextField, pDoc,
+ pAnnotDict);
return;
}
CPDF_Object* pFieldFlagsObj = FPDF_GetFieldAttr(pAnnotDict, "Ff");
uint32_t flags = pFieldFlagsObj ? pFieldFlagsObj->GetInteger() : 0;
if (field_type == "Ch") {
- (flags & (1 << 17)) ? CPVT_GenerateAP::GenerateComboBoxAP(pDoc, pAnnotDict)
- : CPVT_GenerateAP::GenerateListBoxAP(pDoc, pAnnotDict);
+ CPVT_GenerateAP::GenerateFormAP((flags & (1 << 17))
+ ? CPVT_GenerateAP::kComboBox
+ : CPVT_GenerateAP::kListBox,
+ pDoc, pAnnotDict);
return;
}
diff --git a/core/fpdfdoc/cpvt_generateap.cpp b/core/fpdfdoc/cpvt_generateap.cpp
index 3aea95f..c7b551f 100644
--- a/core/fpdfdoc/cpvt_generateap.cpp
+++ b/core/fpdfdoc/cpvt_generateap.cpp
@@ -298,428 +298,6 @@
return ByteString(sAppStream);
}
-bool GenerateWidgetAP(CPDF_Document* pDoc,
- CPDF_Dictionary* pAnnotDict,
- const int32_t& nWidgetType) {
- const CPDF_Dictionary* pRootDict = pDoc->GetRoot();
- if (!pRootDict)
- return false;
-
- const CPDF_Dictionary* pFormDict = pRootDict->GetDictFor("AcroForm");
- if (!pFormDict)
- return false;
-
- ByteString DA;
- if (CPDF_Object* pDAObj = FPDF_GetFieldAttr(pAnnotDict, "DA"))
- DA = pDAObj->GetString();
- if (DA.IsEmpty())
- DA = pFormDict->GetStringFor("DA");
- if (DA.IsEmpty())
- return false;
-
- CPDF_SimpleParser syntax(DA.AsStringView());
- syntax.FindTagParamFromStart("Tf", 2);
- ByteString sFontName(syntax.GetWord());
- sFontName = PDF_NameDecode(sFontName);
- if (sFontName.IsEmpty())
- return false;
-
- float fFontSize = FX_atof(syntax.GetWord());
- CFX_Color crText = CFX_Color::ParseColor(DA);
- CPDF_Dictionary* pDRDict = pFormDict->GetDictFor("DR");
- if (!pDRDict)
- return false;
-
- CPDF_Dictionary* pDRFontDict = pDRDict->GetDictFor("Font");
- if (!pDRFontDict)
- return false;
-
- CPDF_Dictionary* pFontDict =
- pDRFontDict->GetDictFor(sFontName.Right(sFontName.GetLength() - 1));
- if (!pFontDict) {
- pFontDict = pDoc->NewIndirect<CPDF_Dictionary>();
- pFontDict->SetNewFor<CPDF_Name>("Type", "Font");
- pFontDict->SetNewFor<CPDF_Name>("Subtype", "Type1");
- pFontDict->SetNewFor<CPDF_Name>("BaseFont", "Helvetica");
- pFontDict->SetNewFor<CPDF_Name>("Encoding", "WinAnsiEncoding");
- pDRFontDict->SetNewFor<CPDF_Reference>(
- sFontName.Right(sFontName.GetLength() - 1), pDoc,
- pFontDict->GetObjNum());
- }
- CPDF_Font* pDefFont = pDoc->LoadFont(pFontDict);
- if (!pDefFont)
- return false;
-
- CFX_FloatRect rcAnnot = pAnnotDict->GetRectFor("Rect");
- int32_t nRotate = 0;
- if (CPDF_Dictionary* pMKDict = pAnnotDict->GetDictFor("MK"))
- nRotate = pMKDict->GetIntegerFor("R");
-
- CFX_FloatRect rcBBox;
- CFX_Matrix matrix;
- switch (nRotate % 360) {
- case 0:
- rcBBox = CFX_FloatRect(0, 0, rcAnnot.right - rcAnnot.left,
- rcAnnot.top - rcAnnot.bottom);
- break;
- case 90:
- matrix = CFX_Matrix(0, 1, -1, 0, rcAnnot.right - rcAnnot.left, 0);
- rcBBox = CFX_FloatRect(0, 0, rcAnnot.top - rcAnnot.bottom,
- rcAnnot.right - rcAnnot.left);
- break;
- case 180:
- matrix = CFX_Matrix(-1, 0, 0, -1, rcAnnot.right - rcAnnot.left,
- rcAnnot.top - rcAnnot.bottom);
- rcBBox = CFX_FloatRect(0, 0, rcAnnot.right - rcAnnot.left,
- rcAnnot.top - rcAnnot.bottom);
- break;
- case 270:
- matrix = CFX_Matrix(0, -1, 1, 0, 0, rcAnnot.top - rcAnnot.bottom);
- rcBBox = CFX_FloatRect(0, 0, rcAnnot.top - rcAnnot.bottom,
- rcAnnot.right - rcAnnot.left);
- break;
- }
-
- BorderStyle nBorderStyle = BorderStyle::SOLID;
- float fBorderWidth = 1;
- CPVT_Dash dsBorder(3, 0, 0);
- CFX_Color crLeftTop;
- CFX_Color crRightBottom;
- if (CPDF_Dictionary* pBSDict = pAnnotDict->GetDictFor("BS")) {
- if (pBSDict->KeyExist("W"))
- fBorderWidth = pBSDict->GetNumberFor("W");
-
- if (CPDF_Array* pArray = pBSDict->GetArrayFor("D")) {
- dsBorder = CPVT_Dash(pArray->GetIntegerAt(0), pArray->GetIntegerAt(1),
- pArray->GetIntegerAt(2));
- }
- if (pBSDict->GetStringFor("S").GetLength()) {
- switch (pBSDict->GetStringFor("S")[0]) {
- case 'S':
- nBorderStyle = BorderStyle::SOLID;
- break;
- case 'D':
- nBorderStyle = BorderStyle::DASH;
- break;
- case 'B':
- nBorderStyle = BorderStyle::BEVELED;
- fBorderWidth *= 2;
- crLeftTop = CFX_Color(CFX_Color::kGray, 1);
- crRightBottom = CFX_Color(CFX_Color::kGray, 0.5);
- break;
- case 'I':
- nBorderStyle = BorderStyle::INSET;
- fBorderWidth *= 2;
- crLeftTop = CFX_Color(CFX_Color::kGray, 0.5);
- crRightBottom = CFX_Color(CFX_Color::kGray, 0.75);
- break;
- case 'U':
- nBorderStyle = BorderStyle::UNDERLINE;
- break;
- }
- }
- }
- CFX_Color crBorder;
- CFX_Color crBG;
- if (CPDF_Dictionary* pMKDict = pAnnotDict->GetDictFor("MK")) {
- if (CPDF_Array* pArray = pMKDict->GetArrayFor("BC"))
- crBorder = CFX_Color::ParseColor(*pArray);
- if (CPDF_Array* pArray = pMKDict->GetArrayFor("BG"))
- crBG = CFX_Color::ParseColor(*pArray);
- }
- std::ostringstream sAppStream;
- ByteString sBG = GenerateColorAP(crBG, PaintOperation::FILL);
- if (sBG.GetLength() > 0) {
- sAppStream << "q\n" << sBG << rcBBox.left << " " << rcBBox.bottom << " "
- << rcBBox.Width() << " " << rcBBox.Height() << " re f\n"
- << "Q\n";
- }
- ByteString sBorderStream =
- GenerateBorderAP(rcBBox, fBorderWidth, crBorder, crLeftTop, crRightBottom,
- nBorderStyle, dsBorder);
- if (sBorderStream.GetLength() > 0)
- sAppStream << "q\n" << sBorderStream << "Q\n";
-
- CFX_FloatRect rcBody =
- CFX_FloatRect(rcBBox.left + fBorderWidth, rcBBox.bottom + fBorderWidth,
- rcBBox.right - fBorderWidth, rcBBox.top - fBorderWidth);
- rcBody.Normalize();
-
- CPDF_Dictionary* pAPDict = pAnnotDict->GetDictFor("AP");
- if (!pAPDict)
- pAPDict = pAnnotDict->SetNewFor<CPDF_Dictionary>("AP");
-
- CPDF_Stream* pNormalStream = pAPDict->GetStreamFor("N");
- if (!pNormalStream) {
- pNormalStream = pDoc->NewIndirect<CPDF_Stream>();
- pAPDict->SetNewFor<CPDF_Reference>("N", pDoc, pNormalStream->GetObjNum());
- }
- CPDF_Dictionary* pStreamDict = pNormalStream->GetDict();
- if (pStreamDict) {
- pStreamDict->SetMatrixFor("Matrix", matrix);
- pStreamDict->SetRectFor("BBox", rcBBox);
- CPDF_Dictionary* pStreamResList = pStreamDict->GetDictFor("Resources");
- if (pStreamResList) {
- CPDF_Dictionary* pStreamResFontList = pStreamResList->GetDictFor("Font");
- if (!pStreamResFontList)
- pStreamResFontList = pStreamResList->SetNewFor<CPDF_Dictionary>("Font");
- if (!pStreamResFontList->KeyExist(sFontName)) {
- pStreamResFontList->SetNewFor<CPDF_Reference>(sFontName, pDoc,
- pFontDict->GetObjNum());
- }
- } else {
- pStreamDict->SetFor("Resources", pFormDict->GetDictFor("DR")->Clone());
- pStreamResList = pStreamDict->GetDictFor("Resources");
- }
- }
- switch (nWidgetType) {
- case 0: {
- WideString swValue =
- FPDF_GetFieldAttr(pAnnotDict, "V")
- ? FPDF_GetFieldAttr(pAnnotDict, "V")->GetUnicodeText()
- : WideString();
- int32_t nAlign = FPDF_GetFieldAttr(pAnnotDict, "Q")
- ? FPDF_GetFieldAttr(pAnnotDict, "Q")->GetInteger()
- : 0;
- uint32_t dwFlags = FPDF_GetFieldAttr(pAnnotDict, "Ff")
- ? FPDF_GetFieldAttr(pAnnotDict, "Ff")->GetInteger()
- : 0;
- uint32_t dwMaxLen =
- FPDF_GetFieldAttr(pAnnotDict, "MaxLen")
- ? FPDF_GetFieldAttr(pAnnotDict, "MaxLen")->GetInteger()
- : 0;
- CPVT_FontMap map(
- pDoc, pStreamDict ? pStreamDict->GetDictFor("Resources") : nullptr,
- pDefFont, sFontName.Right(sFontName.GetLength() - 1));
- CPDF_VariableText::Provider prd(&map);
- CPDF_VariableText vt;
- vt.SetProvider(&prd);
- vt.SetPlateRect(rcBody);
- vt.SetAlignment(nAlign);
- if (IsFloatZero(fFontSize))
- vt.SetAutoFontSize(true);
- else
- vt.SetFontSize(fFontSize);
-
- bool bMultiLine = (dwFlags >> 12) & 1;
- if (bMultiLine) {
- vt.SetMultiLine(true);
- vt.SetAutoReturn(true);
- }
- uint16_t subWord = 0;
- if ((dwFlags >> 13) & 1) {
- subWord = '*';
- vt.SetPasswordChar(subWord);
- }
- bool bCharArray = (dwFlags >> 24) & 1;
- if (bCharArray)
- vt.SetCharArray(dwMaxLen);
- else
- vt.SetLimitChar(dwMaxLen);
-
- vt.Initialize();
- vt.SetText(swValue);
- vt.RearrangeAll();
- CFX_FloatRect rcContent = vt.GetContentRect();
- CFX_PointF ptOffset;
- if (!bMultiLine) {
- ptOffset =
- CFX_PointF(0.0f, (rcContent.Height() - rcBody.Height()) / 2.0f);
- }
- ByteString sBody = GenerateEditAP(&map, vt.GetIterator(), ptOffset,
- !bCharArray, subWord);
- if (sBody.GetLength() > 0) {
- sAppStream << "/Tx BMC\n"
- << "q\n";
- if (rcContent.Width() > rcBody.Width() ||
- rcContent.Height() > rcBody.Height()) {
- sAppStream << rcBody.left << " " << rcBody.bottom << " "
- << rcBody.Width() << " " << rcBody.Height()
- << " re\nW\nn\n";
- }
- sAppStream << "BT\n"
- << GenerateColorAP(crText, PaintOperation::FILL) << sBody
- << "ET\n"
- << "Q\nEMC\n";
- }
- } break;
- case 1: {
- WideString swValue =
- FPDF_GetFieldAttr(pAnnotDict, "V")
- ? FPDF_GetFieldAttr(pAnnotDict, "V")->GetUnicodeText()
- : WideString();
- CPVT_FontMap map(
- pDoc, pStreamDict ? pStreamDict->GetDictFor("Resources") : nullptr,
- pDefFont, sFontName.Right(sFontName.GetLength() - 1));
- CPDF_VariableText::Provider prd(&map);
- CPDF_VariableText vt;
- vt.SetProvider(&prd);
- CFX_FloatRect rcButton = rcBody;
- rcButton.left = rcButton.right - 13;
- rcButton.Normalize();
- CFX_FloatRect rcEdit = rcBody;
- rcEdit.right = rcButton.left;
- rcEdit.Normalize();
- vt.SetPlateRect(rcEdit);
- if (IsFloatZero(fFontSize))
- vt.SetAutoFontSize(true);
- else
- vt.SetFontSize(fFontSize);
-
- vt.Initialize();
- vt.SetText(swValue);
- vt.RearrangeAll();
- CFX_FloatRect rcContent = vt.GetContentRect();
- CFX_PointF ptOffset =
- CFX_PointF(0.0f, (rcContent.Height() - rcEdit.Height()) / 2.0f);
- ByteString sEdit =
- GenerateEditAP(&map, vt.GetIterator(), ptOffset, true, 0);
- if (sEdit.GetLength() > 0) {
- sAppStream << "/Tx BMC\n"
- << "q\n";
- sAppStream << rcEdit.left << " " << rcEdit.bottom << " "
- << rcEdit.Width() << " " << rcEdit.Height() << " re\nW\nn\n";
- sAppStream << "BT\n"
- << GenerateColorAP(crText, PaintOperation::FILL) << sEdit
- << "ET\n"
- << "Q\nEMC\n";
- }
- ByteString sButton =
- GenerateColorAP(CFX_Color(CFX_Color::kRGB, 220.0f / 255.0f,
- 220.0f / 255.0f, 220.0f / 255.0f),
- PaintOperation::FILL);
- if (sButton.GetLength() > 0 && !rcButton.IsEmpty()) {
- sAppStream << "q\n" << sButton;
- sAppStream << rcButton.left << " " << rcButton.bottom << " "
- << rcButton.Width() << " " << rcButton.Height() << " re f\n";
- sAppStream << "Q\n";
- ByteString sButtonBorder = GenerateBorderAP(
- rcButton, 2, CFX_Color(CFX_Color::kGray, 0),
- CFX_Color(CFX_Color::kGray, 1), CFX_Color(CFX_Color::kGray, 0.5),
- BorderStyle::BEVELED, CPVT_Dash(3, 0, 0));
- if (sButtonBorder.GetLength() > 0)
- sAppStream << "q\n" << sButtonBorder << "Q\n";
-
- CFX_PointF ptCenter = CFX_PointF((rcButton.left + rcButton.right) / 2,
- (rcButton.top + rcButton.bottom) / 2);
- if (IsFloatBigger(rcButton.Width(), 6) &&
- IsFloatBigger(rcButton.Height(), 6)) {
- sAppStream << "q\n"
- << " 0 g\n";
- sAppStream << ptCenter.x - 3 << " " << ptCenter.y + 1.5f << " m\n";
- sAppStream << ptCenter.x + 3 << " " << ptCenter.y + 1.5f << " l\n";
- sAppStream << ptCenter.x << " " << ptCenter.y - 1.5f << " l\n";
- sAppStream << ptCenter.x - 3 << " " << ptCenter.y + 1.5f << " l f\n";
- sAppStream << sButton << "Q\n";
- }
- }
- } break;
- case 2: {
- CPVT_FontMap map(
- pDoc, pStreamDict ? pStreamDict->GetDictFor("Resources") : nullptr,
- pDefFont, sFontName.Right(sFontName.GetLength() - 1));
- CPDF_VariableText::Provider prd(&map);
- CPDF_Array* pOpts = ToArray(FPDF_GetFieldAttr(pAnnotDict, "Opt"));
- CPDF_Array* pSels = ToArray(FPDF_GetFieldAttr(pAnnotDict, "I"));
- CPDF_Object* pTi = FPDF_GetFieldAttr(pAnnotDict, "TI");
- int32_t nTop = pTi ? pTi->GetInteger() : 0;
- std::ostringstream sBody;
- if (pOpts) {
- float fy = rcBody.top;
- for (size_t i = nTop, sz = pOpts->GetCount(); i < sz; i++) {
- if (IsFloatSmaller(fy, rcBody.bottom))
- break;
-
- if (CPDF_Object* pOpt = pOpts->GetDirectObjectAt(i)) {
- WideString swItem;
- if (pOpt->IsString())
- swItem = pOpt->GetUnicodeText();
- else if (CPDF_Array* pArray = pOpt->AsArray())
- swItem = pArray->GetDirectObjectAt(1)->GetUnicodeText();
-
- bool bSelected = false;
- if (pSels) {
- for (size_t s = 0, ssz = pSels->GetCount(); s < ssz; s++) {
- int value = pSels->GetIntegerAt(s);
- if (value >= 0 && i == static_cast<size_t>(value)) {
- bSelected = true;
- break;
- }
- }
- }
- CPDF_VariableText vt;
- vt.SetProvider(&prd);
- vt.SetPlateRect(
- CFX_FloatRect(rcBody.left, 0.0f, rcBody.right, 0.0f));
- vt.SetFontSize(IsFloatZero(fFontSize) ? 12.0f : fFontSize);
-
- vt.Initialize();
- vt.SetText(swItem);
- vt.RearrangeAll();
- float fItemHeight = vt.GetContentRect().Height();
- if (bSelected) {
- CFX_FloatRect rcItem = CFX_FloatRect(
- rcBody.left, fy - fItemHeight, rcBody.right, fy);
- sBody << "q\n"
- << GenerateColorAP(
- CFX_Color(CFX_Color::kRGB, 0, 51.0f / 255.0f,
- 113.0f / 255.0f),
- PaintOperation::FILL)
- << rcItem.left << " " << rcItem.bottom << " "
- << rcItem.Width() << " " << rcItem.Height() << " re f\n"
- << "Q\n";
- sBody << "BT\n"
- << GenerateColorAP(CFX_Color(CFX_Color::kGray, 1),
- PaintOperation::FILL)
- << GenerateEditAP(&map, vt.GetIterator(),
- CFX_PointF(0.0f, fy), true, 0)
- << "ET\n";
- } else {
- sBody << "BT\n"
- << GenerateColorAP(crText, PaintOperation::FILL)
- << GenerateEditAP(&map, vt.GetIterator(),
- CFX_PointF(0.0f, fy), true, 0)
- << "ET\n";
- }
- fy -= fItemHeight;
- }
- }
- }
- if (sBody.tellp() > 0) {
- sAppStream << "/Tx BMC\nq\n"
- << rcBody.left << " " << rcBody.bottom << " "
- << rcBody.Width() << " " << rcBody.Height() << " re\nW\nn\n"
- << sBody.str() << "Q\nEMC\n";
- }
- } break;
- }
- if (pNormalStream) {
- pNormalStream->SetDataAndRemoveFilter(&sAppStream);
- pStreamDict = pNormalStream->GetDict();
- if (pStreamDict) {
- pStreamDict->SetMatrixFor("Matrix", matrix);
- pStreamDict->SetRectFor("BBox", rcBBox);
- CPDF_Dictionary* pStreamResList = pStreamDict->GetDictFor("Resources");
- if (pStreamResList) {
- CPDF_Dictionary* pStreamResFontList =
- pStreamResList->GetDictFor("Font");
- if (!pStreamResFontList) {
- pStreamResFontList =
- pStreamResList->SetNewFor<CPDF_Dictionary>("Font");
- }
- if (!pStreamResFontList->KeyExist(sFontName)) {
- pStreamResFontList->SetNewFor<CPDF_Reference>(sFontName, pDoc,
- pFontDict->GetObjNum());
- }
- } else {
- pStreamDict->SetFor("Resources", pFormDict->GetDictFor("DR")->Clone());
- pStreamResList = pStreamDict->GetDictFor("Resources");
- }
- }
- }
- return true;
-}
-
ByteString GetColorStringWithDefault(CPDF_Array* pColor,
const CFX_Color& crDefaultColor,
PaintOperation nOperation) {
@@ -884,28 +462,67 @@
return ByteString(sAppStream);
}
-} // namespace
+std::unique_ptr<CPDF_Dictionary> GenerateExtGStateDict(
+ const CPDF_Dictionary& pAnnotDict,
+ const ByteString& sExtGSDictName,
+ const ByteString& sBlendMode) {
+ auto pGSDict =
+ pdfium::MakeUnique<CPDF_Dictionary>(pAnnotDict.GetByteStringPool());
+ pGSDict->SetNewFor<CPDF_String>("Type", "ExtGState", false);
-// Static.
-void CPVT_GenerateAP::GenerateComboBoxAP(CPDF_Document* pDoc,
- CPDF_Dictionary* pAnnotDict) {
- GenerateWidgetAP(pDoc, pAnnotDict, 1);
+ float fOpacity =
+ pAnnotDict.KeyExist("CA") ? pAnnotDict.GetNumberFor("CA") : 1;
+ pGSDict->SetNewFor<CPDF_Number>("CA", fOpacity);
+ pGSDict->SetNewFor<CPDF_Number>("ca", fOpacity);
+ pGSDict->SetNewFor<CPDF_Boolean>("AIS", false);
+ pGSDict->SetNewFor<CPDF_String>("BM", sBlendMode, false);
+
+ auto pExtGStateDict =
+ pdfium::MakeUnique<CPDF_Dictionary>(pAnnotDict.GetByteStringPool());
+ pExtGStateDict->SetFor(sExtGSDictName, std::move(pGSDict));
+ return pExtGStateDict;
}
-// Static.
-void CPVT_GenerateAP::GenerateListBoxAP(CPDF_Document* pDoc,
- CPDF_Dictionary* pAnnotDict) {
- GenerateWidgetAP(pDoc, pAnnotDict, 2);
+std::unique_ptr<CPDF_Dictionary> GenerateResourceDict(
+ CPDF_Document* pDoc,
+ std::unique_ptr<CPDF_Dictionary> pExtGStateDict,
+ std::unique_ptr<CPDF_Dictionary> pResourceFontDict) {
+ auto pResourceDict =
+ pdfium::MakeUnique<CPDF_Dictionary>(pDoc->GetByteStringPool());
+ if (pExtGStateDict)
+ pResourceDict->SetFor("ExtGState", std::move(pExtGStateDict));
+ if (pResourceFontDict)
+ pResourceDict->SetFor("Font", std::move(pResourceFontDict));
+ return pResourceDict;
}
-// Static.
-void CPVT_GenerateAP::GenerateTextFieldAP(CPDF_Document* pDoc,
- CPDF_Dictionary* pAnnotDict) {
- GenerateWidgetAP(pDoc, pAnnotDict, 0);
+void GenerateAndSetAPDict(CPDF_Document* pDoc,
+ CPDF_Dictionary* pAnnotDict,
+ std::ostringstream* psAppStream,
+ std::unique_ptr<CPDF_Dictionary> pResourceDict,
+ bool bIsTextMarkupAnnotation) {
+ CPDF_Stream* pNormalStream = pDoc->NewIndirect<CPDF_Stream>();
+ pNormalStream->SetData(psAppStream);
+
+ CPDF_Dictionary* pAPDict = pAnnotDict->GetDictFor("AP");
+ if (!pAPDict)
+ pAPDict = pAnnotDict->SetNewFor<CPDF_Dictionary>("AP");
+
+ pAPDict->SetNewFor<CPDF_Reference>("N", pDoc, pNormalStream->GetObjNum());
+
+ CPDF_Dictionary* pStreamDict = pNormalStream->GetDict();
+ pStreamDict->SetNewFor<CPDF_Number>("FormType", 1);
+ pStreamDict->SetNewFor<CPDF_String>("Subtype", "Form", false);
+ pStreamDict->SetMatrixFor("Matrix", CFX_Matrix());
+
+ CFX_FloatRect rect = bIsTextMarkupAnnotation
+ ? CPDF_Annot::RectFromQuadPoints(pAnnotDict)
+ : pAnnotDict->GetRectFor("Rect");
+ pStreamDict->SetRectFor("BBox", rect);
+ pStreamDict->SetFor("Resources", std::move(pResourceDict));
}
-bool CPVT_GenerateAP::GenerateCircleAP(CPDF_Document* pDoc,
- CPDF_Dictionary* pAnnotDict) {
+bool GenerateCircleAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict) {
std::ostringstream sAppStream;
ByteString sExtGSDictName = "GS";
sAppStream << "/" << sExtGSDictName << " gs ";
@@ -977,8 +594,7 @@
return true;
}
-bool CPVT_GenerateAP::GenerateHighlightAP(CPDF_Document* pDoc,
- CPDF_Dictionary* pAnnotDict) {
+bool GenerateHighlightAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict) {
std::ostringstream sAppStream;
ByteString sExtGSDictName = "GS";
sAppStream << "/" << sExtGSDictName << " gs ";
@@ -1005,8 +621,7 @@
return true;
}
-bool CPVT_GenerateAP::GenerateInkAP(CPDF_Document* pDoc,
- CPDF_Dictionary* pAnnotDict) {
+bool GenerateInkAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict) {
float fBorderWidth = GetBorderWidth(*pAnnotDict);
bool bIsStroke = fBorderWidth > 0;
@@ -1059,8 +674,7 @@
return true;
}
-bool CPVT_GenerateAP::GenerateTextAP(CPDF_Document* pDoc,
- CPDF_Dictionary* pAnnotDict) {
+bool GenerateTextAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict) {
std::ostringstream sAppStream;
ByteString sExtGSDictName = "GS";
sAppStream << "/" << sExtGSDictName << " gs ";
@@ -1082,8 +696,7 @@
return true;
}
-bool CPVT_GenerateAP::GenerateUnderlineAP(CPDF_Document* pDoc,
- CPDF_Dictionary* pAnnotDict) {
+bool GenerateUnderlineAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict) {
std::ostringstream sAppStream;
ByteString sExtGSDictName = "GS";
sAppStream << "/" << sExtGSDictName << " gs ";
@@ -1109,8 +722,7 @@
return true;
}
-bool CPVT_GenerateAP::GeneratePopupAP(CPDF_Document* pDoc,
- CPDF_Dictionary* pAnnotDict) {
+bool GeneratePopupAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict) {
std::ostringstream sAppStream;
ByteString sExtGSDictName = "GS";
sAppStream << "/" << sExtGSDictName << " gs\n";
@@ -1147,8 +759,7 @@
return true;
}
-bool CPVT_GenerateAP::GenerateSquareAP(CPDF_Document* pDoc,
- CPDF_Dictionary* pAnnotDict) {
+bool GenerateSquareAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict) {
std::ostringstream sAppStream;
ByteString sExtGSDictName = "GS";
sAppStream << "/" << sExtGSDictName << " gs ";
@@ -1194,8 +805,7 @@
return true;
}
-bool CPVT_GenerateAP::GenerateSquigglyAP(CPDF_Document* pDoc,
- CPDF_Dictionary* pAnnotDict) {
+bool GenerateSquigglyAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict) {
std::ostringstream sAppStream;
ByteString sExtGSDictName = "GS";
sAppStream << "/" << sExtGSDictName << " gs ";
@@ -1243,8 +853,7 @@
return true;
}
-bool CPVT_GenerateAP::GenerateStrikeOutAP(CPDF_Document* pDoc,
- CPDF_Dictionary* pAnnotDict) {
+bool GenerateStrikeOutAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict) {
std::ostringstream sAppStream;
ByteString sExtGSDictName = "GS";
sAppStream << "/" << sExtGSDictName << " gs ";
@@ -1270,66 +879,472 @@
return true;
}
-// Static.
-std::unique_ptr<CPDF_Dictionary> CPVT_GenerateAP::GenerateExtGStateDict(
- const CPDF_Dictionary& pAnnotDict,
- const ByteString& sExtGSDictName,
- const ByteString& sBlendMode) {
- auto pGSDict =
- pdfium::MakeUnique<CPDF_Dictionary>(pAnnotDict.GetByteStringPool());
- pGSDict->SetNewFor<CPDF_String>("Type", "ExtGState", false);
+} // namespace
- float fOpacity =
- pAnnotDict.KeyExist("CA") ? pAnnotDict.GetNumberFor("CA") : 1;
- pGSDict->SetNewFor<CPDF_Number>("CA", fOpacity);
- pGSDict->SetNewFor<CPDF_Number>("ca", fOpacity);
- pGSDict->SetNewFor<CPDF_Boolean>("AIS", false);
- pGSDict->SetNewFor<CPDF_String>("BM", sBlendMode, false);
+// static
+void CPVT_GenerateAP::GenerateFormAP(Type type,
+ CPDF_Document* pDoc,
+ CPDF_Dictionary* pAnnotDict) {
+ const CPDF_Dictionary* pRootDict = pDoc->GetRoot();
+ if (!pRootDict)
+ return;
- auto pExtGStateDict =
- pdfium::MakeUnique<CPDF_Dictionary>(pAnnotDict.GetByteStringPool());
- pExtGStateDict->SetFor(sExtGSDictName, std::move(pGSDict));
- return pExtGStateDict;
-}
+ const CPDF_Dictionary* pFormDict = pRootDict->GetDictFor("AcroForm");
+ if (!pFormDict)
+ return;
-// Static.
-std::unique_ptr<CPDF_Dictionary> CPVT_GenerateAP::GenerateResourceDict(
- CPDF_Document* pDoc,
- std::unique_ptr<CPDF_Dictionary> pExtGStateDict,
- std::unique_ptr<CPDF_Dictionary> pResourceFontDict) {
- auto pResourceDict =
- pdfium::MakeUnique<CPDF_Dictionary>(pDoc->GetByteStringPool());
- if (pExtGStateDict)
- pResourceDict->SetFor("ExtGState", std::move(pExtGStateDict));
- if (pResourceFontDict)
- pResourceDict->SetFor("Font", std::move(pResourceFontDict));
- return pResourceDict;
-}
+ ByteString DA;
+ if (CPDF_Object* pDAObj = FPDF_GetFieldAttr(pAnnotDict, "DA"))
+ DA = pDAObj->GetString();
+ if (DA.IsEmpty())
+ DA = pFormDict->GetStringFor("DA");
+ if (DA.IsEmpty())
+ return;
-// Static.
-void CPVT_GenerateAP::GenerateAndSetAPDict(
- CPDF_Document* pDoc,
- CPDF_Dictionary* pAnnotDict,
- std::ostringstream* psAppStream,
- std::unique_ptr<CPDF_Dictionary> pResourceDict,
- bool bIsTextMarkupAnnotation) {
- CPDF_Stream* pNormalStream = pDoc->NewIndirect<CPDF_Stream>();
- pNormalStream->SetData(psAppStream);
+ CPDF_SimpleParser syntax(DA.AsStringView());
+ syntax.FindTagParamFromStart("Tf", 2);
+ ByteString sFontName(syntax.GetWord());
+ sFontName = PDF_NameDecode(sFontName);
+ if (sFontName.IsEmpty())
+ return;
+
+ float fFontSize = FX_atof(syntax.GetWord());
+ CFX_Color crText = CFX_Color::ParseColor(DA);
+ CPDF_Dictionary* pDRDict = pFormDict->GetDictFor("DR");
+ if (!pDRDict)
+ return;
+
+ CPDF_Dictionary* pDRFontDict = pDRDict->GetDictFor("Font");
+ if (!pDRFontDict)
+ return;
+
+ CPDF_Dictionary* pFontDict =
+ pDRFontDict->GetDictFor(sFontName.Right(sFontName.GetLength() - 1));
+ if (!pFontDict) {
+ pFontDict = pDoc->NewIndirect<CPDF_Dictionary>();
+ pFontDict->SetNewFor<CPDF_Name>("Type", "Font");
+ pFontDict->SetNewFor<CPDF_Name>("Subtype", "Type1");
+ pFontDict->SetNewFor<CPDF_Name>("BaseFont", "Helvetica");
+ pFontDict->SetNewFor<CPDF_Name>("Encoding", "WinAnsiEncoding");
+ pDRFontDict->SetNewFor<CPDF_Reference>(
+ sFontName.Right(sFontName.GetLength() - 1), pDoc,
+ pFontDict->GetObjNum());
+ }
+ CPDF_Font* pDefFont = pDoc->LoadFont(pFontDict);
+ if (!pDefFont)
+ return;
+
+ CFX_FloatRect rcAnnot = pAnnotDict->GetRectFor("Rect");
+ int32_t nRotate = 0;
+ if (CPDF_Dictionary* pMKDict = pAnnotDict->GetDictFor("MK"))
+ nRotate = pMKDict->GetIntegerFor("R");
+
+ CFX_FloatRect rcBBox;
+ CFX_Matrix matrix;
+ switch (nRotate % 360) {
+ case 0:
+ rcBBox = CFX_FloatRect(0, 0, rcAnnot.right - rcAnnot.left,
+ rcAnnot.top - rcAnnot.bottom);
+ break;
+ case 90:
+ matrix = CFX_Matrix(0, 1, -1, 0, rcAnnot.right - rcAnnot.left, 0);
+ rcBBox = CFX_FloatRect(0, 0, rcAnnot.top - rcAnnot.bottom,
+ rcAnnot.right - rcAnnot.left);
+ break;
+ case 180:
+ matrix = CFX_Matrix(-1, 0, 0, -1, rcAnnot.right - rcAnnot.left,
+ rcAnnot.top - rcAnnot.bottom);
+ rcBBox = CFX_FloatRect(0, 0, rcAnnot.right - rcAnnot.left,
+ rcAnnot.top - rcAnnot.bottom);
+ break;
+ case 270:
+ matrix = CFX_Matrix(0, -1, 1, 0, 0, rcAnnot.top - rcAnnot.bottom);
+ rcBBox = CFX_FloatRect(0, 0, rcAnnot.top - rcAnnot.bottom,
+ rcAnnot.right - rcAnnot.left);
+ break;
+ }
+
+ BorderStyle nBorderStyle = BorderStyle::SOLID;
+ float fBorderWidth = 1;
+ CPVT_Dash dsBorder(3, 0, 0);
+ CFX_Color crLeftTop;
+ CFX_Color crRightBottom;
+ if (CPDF_Dictionary* pBSDict = pAnnotDict->GetDictFor("BS")) {
+ if (pBSDict->KeyExist("W"))
+ fBorderWidth = pBSDict->GetNumberFor("W");
+
+ if (CPDF_Array* pArray = pBSDict->GetArrayFor("D")) {
+ dsBorder = CPVT_Dash(pArray->GetIntegerAt(0), pArray->GetIntegerAt(1),
+ pArray->GetIntegerAt(2));
+ }
+ if (pBSDict->GetStringFor("S").GetLength()) {
+ switch (pBSDict->GetStringFor("S")[0]) {
+ case 'S':
+ nBorderStyle = BorderStyle::SOLID;
+ break;
+ case 'D':
+ nBorderStyle = BorderStyle::DASH;
+ break;
+ case 'B':
+ nBorderStyle = BorderStyle::BEVELED;
+ fBorderWidth *= 2;
+ crLeftTop = CFX_Color(CFX_Color::kGray, 1);
+ crRightBottom = CFX_Color(CFX_Color::kGray, 0.5);
+ break;
+ case 'I':
+ nBorderStyle = BorderStyle::INSET;
+ fBorderWidth *= 2;
+ crLeftTop = CFX_Color(CFX_Color::kGray, 0.5);
+ crRightBottom = CFX_Color(CFX_Color::kGray, 0.75);
+ break;
+ case 'U':
+ nBorderStyle = BorderStyle::UNDERLINE;
+ break;
+ }
+ }
+ }
+ CFX_Color crBorder;
+ CFX_Color crBG;
+ if (CPDF_Dictionary* pMKDict = pAnnotDict->GetDictFor("MK")) {
+ if (CPDF_Array* pArray = pMKDict->GetArrayFor("BC"))
+ crBorder = CFX_Color::ParseColor(*pArray);
+ if (CPDF_Array* pArray = pMKDict->GetArrayFor("BG"))
+ crBG = CFX_Color::ParseColor(*pArray);
+ }
+ std::ostringstream sAppStream;
+ ByteString sBG = GenerateColorAP(crBG, PaintOperation::FILL);
+ if (sBG.GetLength() > 0) {
+ sAppStream << "q\n"
+ << sBG << rcBBox.left << " " << rcBBox.bottom << " "
+ << rcBBox.Width() << " " << rcBBox.Height() << " re f\n"
+ << "Q\n";
+ }
+ ByteString sBorderStream =
+ GenerateBorderAP(rcBBox, fBorderWidth, crBorder, crLeftTop, crRightBottom,
+ nBorderStyle, dsBorder);
+ if (sBorderStream.GetLength() > 0)
+ sAppStream << "q\n" << sBorderStream << "Q\n";
+
+ CFX_FloatRect rcBody =
+ CFX_FloatRect(rcBBox.left + fBorderWidth, rcBBox.bottom + fBorderWidth,
+ rcBBox.right - fBorderWidth, rcBBox.top - fBorderWidth);
+ rcBody.Normalize();
CPDF_Dictionary* pAPDict = pAnnotDict->GetDictFor("AP");
if (!pAPDict)
pAPDict = pAnnotDict->SetNewFor<CPDF_Dictionary>("AP");
- pAPDict->SetNewFor<CPDF_Reference>("N", pDoc, pNormalStream->GetObjNum());
-
+ CPDF_Stream* pNormalStream = pAPDict->GetStreamFor("N");
+ if (!pNormalStream) {
+ pNormalStream = pDoc->NewIndirect<CPDF_Stream>();
+ pAPDict->SetNewFor<CPDF_Reference>("N", pDoc, pNormalStream->GetObjNum());
+ }
CPDF_Dictionary* pStreamDict = pNormalStream->GetDict();
- pStreamDict->SetNewFor<CPDF_Number>("FormType", 1);
- pStreamDict->SetNewFor<CPDF_String>("Subtype", "Form", false);
- pStreamDict->SetMatrixFor("Matrix", CFX_Matrix());
+ if (pStreamDict) {
+ pStreamDict->SetMatrixFor("Matrix", matrix);
+ pStreamDict->SetRectFor("BBox", rcBBox);
+ CPDF_Dictionary* pStreamResList = pStreamDict->GetDictFor("Resources");
+ if (pStreamResList) {
+ CPDF_Dictionary* pStreamResFontList = pStreamResList->GetDictFor("Font");
+ if (!pStreamResFontList)
+ pStreamResFontList = pStreamResList->SetNewFor<CPDF_Dictionary>("Font");
+ if (!pStreamResFontList->KeyExist(sFontName)) {
+ pStreamResFontList->SetNewFor<CPDF_Reference>(sFontName, pDoc,
+ pFontDict->GetObjNum());
+ }
+ } else {
+ pStreamDict->SetFor("Resources", pFormDict->GetDictFor("DR")->Clone());
+ pStreamResList = pStreamDict->GetDictFor("Resources");
+ }
+ }
+ switch (type) {
+ case CPVT_GenerateAP::kTextField: {
+ WideString swValue =
+ FPDF_GetFieldAttr(pAnnotDict, "V")
+ ? FPDF_GetFieldAttr(pAnnotDict, "V")->GetUnicodeText()
+ : WideString();
+ int32_t nAlign = FPDF_GetFieldAttr(pAnnotDict, "Q")
+ ? FPDF_GetFieldAttr(pAnnotDict, "Q")->GetInteger()
+ : 0;
+ uint32_t dwFlags = FPDF_GetFieldAttr(pAnnotDict, "Ff")
+ ? FPDF_GetFieldAttr(pAnnotDict, "Ff")->GetInteger()
+ : 0;
+ uint32_t dwMaxLen =
+ FPDF_GetFieldAttr(pAnnotDict, "MaxLen")
+ ? FPDF_GetFieldAttr(pAnnotDict, "MaxLen")->GetInteger()
+ : 0;
+ CPVT_FontMap map(
+ pDoc, pStreamDict ? pStreamDict->GetDictFor("Resources") : nullptr,
+ pDefFont, sFontName.Right(sFontName.GetLength() - 1));
+ CPDF_VariableText::Provider prd(&map);
+ CPDF_VariableText vt;
+ vt.SetProvider(&prd);
+ vt.SetPlateRect(rcBody);
+ vt.SetAlignment(nAlign);
+ if (IsFloatZero(fFontSize))
+ vt.SetAutoFontSize(true);
+ else
+ vt.SetFontSize(fFontSize);
- CFX_FloatRect rect = bIsTextMarkupAnnotation
- ? CPDF_Annot::RectFromQuadPoints(pAnnotDict)
- : pAnnotDict->GetRectFor("Rect");
- pStreamDict->SetRectFor("BBox", rect);
- pStreamDict->SetFor("Resources", std::move(pResourceDict));
+ bool bMultiLine = (dwFlags >> 12) & 1;
+ if (bMultiLine) {
+ vt.SetMultiLine(true);
+ vt.SetAutoReturn(true);
+ }
+ uint16_t subWord = 0;
+ if ((dwFlags >> 13) & 1) {
+ subWord = '*';
+ vt.SetPasswordChar(subWord);
+ }
+ bool bCharArray = (dwFlags >> 24) & 1;
+ if (bCharArray)
+ vt.SetCharArray(dwMaxLen);
+ else
+ vt.SetLimitChar(dwMaxLen);
+
+ vt.Initialize();
+ vt.SetText(swValue);
+ vt.RearrangeAll();
+ CFX_FloatRect rcContent = vt.GetContentRect();
+ CFX_PointF ptOffset;
+ if (!bMultiLine) {
+ ptOffset =
+ CFX_PointF(0.0f, (rcContent.Height() - rcBody.Height()) / 2.0f);
+ }
+ ByteString sBody = GenerateEditAP(&map, vt.GetIterator(), ptOffset,
+ !bCharArray, subWord);
+ if (sBody.GetLength() > 0) {
+ sAppStream << "/Tx BMC\n"
+ << "q\n";
+ if (rcContent.Width() > rcBody.Width() ||
+ rcContent.Height() > rcBody.Height()) {
+ sAppStream << rcBody.left << " " << rcBody.bottom << " "
+ << rcBody.Width() << " " << rcBody.Height()
+ << " re\nW\nn\n";
+ }
+ sAppStream << "BT\n"
+ << GenerateColorAP(crText, PaintOperation::FILL) << sBody
+ << "ET\n"
+ << "Q\nEMC\n";
+ }
+ break;
+ }
+ case CPVT_GenerateAP::kComboBox: {
+ WideString swValue =
+ FPDF_GetFieldAttr(pAnnotDict, "V")
+ ? FPDF_GetFieldAttr(pAnnotDict, "V")->GetUnicodeText()
+ : WideString();
+ CPVT_FontMap map(
+ pDoc, pStreamDict ? pStreamDict->GetDictFor("Resources") : nullptr,
+ pDefFont, sFontName.Right(sFontName.GetLength() - 1));
+ CPDF_VariableText::Provider prd(&map);
+ CPDF_VariableText vt;
+ vt.SetProvider(&prd);
+ CFX_FloatRect rcButton = rcBody;
+ rcButton.left = rcButton.right - 13;
+ rcButton.Normalize();
+ CFX_FloatRect rcEdit = rcBody;
+ rcEdit.right = rcButton.left;
+ rcEdit.Normalize();
+ vt.SetPlateRect(rcEdit);
+ if (IsFloatZero(fFontSize))
+ vt.SetAutoFontSize(true);
+ else
+ vt.SetFontSize(fFontSize);
+
+ vt.Initialize();
+ vt.SetText(swValue);
+ vt.RearrangeAll();
+ CFX_FloatRect rcContent = vt.GetContentRect();
+ CFX_PointF ptOffset =
+ CFX_PointF(0.0f, (rcContent.Height() - rcEdit.Height()) / 2.0f);
+ ByteString sEdit =
+ GenerateEditAP(&map, vt.GetIterator(), ptOffset, true, 0);
+ if (sEdit.GetLength() > 0) {
+ sAppStream << "/Tx BMC\n"
+ << "q\n";
+ sAppStream << rcEdit.left << " " << rcEdit.bottom << " "
+ << rcEdit.Width() << " " << rcEdit.Height() << " re\nW\nn\n";
+ sAppStream << "BT\n"
+ << GenerateColorAP(crText, PaintOperation::FILL) << sEdit
+ << "ET\n"
+ << "Q\nEMC\n";
+ }
+ ByteString sButton =
+ GenerateColorAP(CFX_Color(CFX_Color::kRGB, 220.0f / 255.0f,
+ 220.0f / 255.0f, 220.0f / 255.0f),
+ PaintOperation::FILL);
+ if (sButton.GetLength() > 0 && !rcButton.IsEmpty()) {
+ sAppStream << "q\n" << sButton;
+ sAppStream << rcButton.left << " " << rcButton.bottom << " "
+ << rcButton.Width() << " " << rcButton.Height() << " re f\n";
+ sAppStream << "Q\n";
+ ByteString sButtonBorder = GenerateBorderAP(
+ rcButton, 2, CFX_Color(CFX_Color::kGray, 0),
+ CFX_Color(CFX_Color::kGray, 1), CFX_Color(CFX_Color::kGray, 0.5),
+ BorderStyle::BEVELED, CPVT_Dash(3, 0, 0));
+ if (sButtonBorder.GetLength() > 0)
+ sAppStream << "q\n" << sButtonBorder << "Q\n";
+
+ CFX_PointF ptCenter = CFX_PointF((rcButton.left + rcButton.right) / 2,
+ (rcButton.top + rcButton.bottom) / 2);
+ if (IsFloatBigger(rcButton.Width(), 6) &&
+ IsFloatBigger(rcButton.Height(), 6)) {
+ sAppStream << "q\n"
+ << " 0 g\n";
+ sAppStream << ptCenter.x - 3 << " " << ptCenter.y + 1.5f << " m\n";
+ sAppStream << ptCenter.x + 3 << " " << ptCenter.y + 1.5f << " l\n";
+ sAppStream << ptCenter.x << " " << ptCenter.y - 1.5f << " l\n";
+ sAppStream << ptCenter.x - 3 << " " << ptCenter.y + 1.5f << " l f\n";
+ sAppStream << sButton << "Q\n";
+ }
+ }
+ break;
+ }
+ case CPVT_GenerateAP::kListBox: {
+ CPVT_FontMap map(
+ pDoc, pStreamDict ? pStreamDict->GetDictFor("Resources") : nullptr,
+ pDefFont, sFontName.Right(sFontName.GetLength() - 1));
+ CPDF_VariableText::Provider prd(&map);
+ CPDF_Array* pOpts = ToArray(FPDF_GetFieldAttr(pAnnotDict, "Opt"));
+ CPDF_Array* pSels = ToArray(FPDF_GetFieldAttr(pAnnotDict, "I"));
+ CPDF_Object* pTi = FPDF_GetFieldAttr(pAnnotDict, "TI");
+ int32_t nTop = pTi ? pTi->GetInteger() : 0;
+ std::ostringstream sBody;
+ if (pOpts) {
+ float fy = rcBody.top;
+ for (size_t i = nTop, sz = pOpts->GetCount(); i < sz; i++) {
+ if (IsFloatSmaller(fy, rcBody.bottom))
+ break;
+
+ if (CPDF_Object* pOpt = pOpts->GetDirectObjectAt(i)) {
+ WideString swItem;
+ if (pOpt->IsString())
+ swItem = pOpt->GetUnicodeText();
+ else if (CPDF_Array* pArray = pOpt->AsArray())
+ swItem = pArray->GetDirectObjectAt(1)->GetUnicodeText();
+
+ bool bSelected = false;
+ if (pSels) {
+ for (size_t s = 0, ssz = pSels->GetCount(); s < ssz; s++) {
+ int value = pSels->GetIntegerAt(s);
+ if (value >= 0 && i == static_cast<size_t>(value)) {
+ bSelected = true;
+ break;
+ }
+ }
+ }
+ CPDF_VariableText vt;
+ vt.SetProvider(&prd);
+ vt.SetPlateRect(
+ CFX_FloatRect(rcBody.left, 0.0f, rcBody.right, 0.0f));
+ vt.SetFontSize(IsFloatZero(fFontSize) ? 12.0f : fFontSize);
+
+ vt.Initialize();
+ vt.SetText(swItem);
+ vt.RearrangeAll();
+ float fItemHeight = vt.GetContentRect().Height();
+ if (bSelected) {
+ CFX_FloatRect rcItem = CFX_FloatRect(
+ rcBody.left, fy - fItemHeight, rcBody.right, fy);
+ sBody << "q\n"
+ << GenerateColorAP(
+ CFX_Color(CFX_Color::kRGB, 0, 51.0f / 255.0f,
+ 113.0f / 255.0f),
+ PaintOperation::FILL)
+ << rcItem.left << " " << rcItem.bottom << " "
+ << rcItem.Width() << " " << rcItem.Height() << " re f\n"
+ << "Q\n";
+ sBody << "BT\n"
+ << GenerateColorAP(CFX_Color(CFX_Color::kGray, 1),
+ PaintOperation::FILL)
+ << GenerateEditAP(&map, vt.GetIterator(),
+ CFX_PointF(0.0f, fy), true, 0)
+ << "ET\n";
+ } else {
+ sBody << "BT\n"
+ << GenerateColorAP(crText, PaintOperation::FILL)
+ << GenerateEditAP(&map, vt.GetIterator(),
+ CFX_PointF(0.0f, fy), true, 0)
+ << "ET\n";
+ }
+ fy -= fItemHeight;
+ }
+ }
+ }
+ if (sBody.tellp() > 0) {
+ sAppStream << "/Tx BMC\nq\n"
+ << rcBody.left << " " << rcBody.bottom << " "
+ << rcBody.Width() << " " << rcBody.Height() << " re\nW\nn\n"
+ << sBody.str() << "Q\nEMC\n";
+ }
+ break;
+ }
+ }
+
+ if (pNormalStream) {
+ pNormalStream->SetDataAndRemoveFilter(&sAppStream);
+ pStreamDict = pNormalStream->GetDict();
+ if (pStreamDict) {
+ pStreamDict->SetMatrixFor("Matrix", matrix);
+ pStreamDict->SetRectFor("BBox", rcBBox);
+ CPDF_Dictionary* pStreamResList = pStreamDict->GetDictFor("Resources");
+ if (pStreamResList) {
+ CPDF_Dictionary* pStreamResFontList =
+ pStreamResList->GetDictFor("Font");
+ if (!pStreamResFontList) {
+ pStreamResFontList =
+ pStreamResList->SetNewFor<CPDF_Dictionary>("Font");
+ }
+ if (!pStreamResFontList->KeyExist(sFontName)) {
+ pStreamResFontList->SetNewFor<CPDF_Reference>(sFontName, pDoc,
+ pFontDict->GetObjNum());
+ }
+ } else {
+ pStreamDict->SetFor("Resources", pFormDict->GetDictFor("DR")->Clone());
+ pStreamResList = pStreamDict->GetDictFor("Resources");
+ }
+ }
+ }
+ return;
+}
+
+// static
+void CPVT_GenerateAP::GenerateEmptyAP(CPDF_Document* pDoc,
+ CPDF_Dictionary* pAnnotDict) {
+ auto pExtGStateDict = GenerateExtGStateDict(*pAnnotDict, "GS", "Normal");
+ auto pResourceDict =
+ GenerateResourceDict(pDoc, std::move(pExtGStateDict), nullptr);
+
+ std::ostringstream sStream;
+ GenerateAndSetAPDict(pDoc, pAnnotDict, &sStream, std::move(pResourceDict),
+ false);
+}
+
+// static
+bool CPVT_GenerateAP::GenerateAnnotAP(CPDF_Annot::Subtype subtype,
+ CPDF_Document* pDoc,
+ CPDF_Dictionary* pAnnotDict) {
+ switch (subtype) {
+ case CPDF_Annot::Subtype::CIRCLE:
+ return GenerateCircleAP(pDoc, pAnnotDict);
+ case CPDF_Annot::Subtype::HIGHLIGHT:
+ return GenerateHighlightAP(pDoc, pAnnotDict);
+ case CPDF_Annot::Subtype::INK:
+ return GenerateInkAP(pDoc, pAnnotDict);
+ case CPDF_Annot::Subtype::POPUP:
+ return GeneratePopupAP(pDoc, pAnnotDict);
+ case CPDF_Annot::Subtype::SQUARE:
+ return GenerateSquareAP(pDoc, pAnnotDict);
+ case CPDF_Annot::Subtype::SQUIGGLY:
+ return GenerateSquigglyAP(pDoc, pAnnotDict);
+ case CPDF_Annot::Subtype::STRIKEOUT:
+ return GenerateStrikeOutAP(pDoc, pAnnotDict);
+ case CPDF_Annot::Subtype::TEXT:
+ return GenerateTextAP(pDoc, pAnnotDict);
+ case CPDF_Annot::Subtype::UNDERLINE:
+ return GenerateUnderlineAP(pDoc, pAnnotDict);
+ default:
+ return false;
+ }
}
diff --git a/core/fpdfdoc/cpvt_generateap.h b/core/fpdfdoc/cpvt_generateap.h
index 828e859..6f56993 100644
--- a/core/fpdfdoc/cpvt_generateap.h
+++ b/core/fpdfdoc/cpvt_generateap.h
@@ -22,42 +22,16 @@
class CPVT_GenerateAP {
public:
- static bool GenerateCircleAP(CPDF_Document* pDoc,
- CPDF_Dictionary* pAnnotDict);
- static void GenerateComboBoxAP(CPDF_Document* pDoc,
- CPDF_Dictionary* pAnnotDict);
- static bool GenerateHighlightAP(CPDF_Document* pDoc,
- CPDF_Dictionary* pAnnotDict);
- static bool GenerateInkAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict);
- static void GenerateListBoxAP(CPDF_Document* pDoc,
- CPDF_Dictionary* pAnnotDict);
- static bool GeneratePopupAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict);
- static bool GenerateSquareAP(CPDF_Document* pDoc,
- CPDF_Dictionary* pAnnotDict);
- static bool GenerateSquigglyAP(CPDF_Document* pDoc,
- CPDF_Dictionary* pAnnotDict);
- static bool GenerateStrikeOutAP(CPDF_Document* pDoc,
- CPDF_Dictionary* pAnnotDict);
- static bool GenerateTextAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict);
- static void GenerateTextFieldAP(CPDF_Document* pDoc,
- CPDF_Dictionary* pAnnotDict);
- static bool GenerateUnderlineAP(CPDF_Document* pDoc,
- CPDF_Dictionary* pAnnotDict);
+ enum Type { kTextField, kComboBox, kListBox };
- static std::unique_ptr<CPDF_Dictionary> GenerateExtGStateDict(
- const CPDF_Dictionary& pAnnotDict,
- const ByteString& sExtGSDictName,
- const ByteString& sBlendMode);
- static std::unique_ptr<CPDF_Dictionary> GenerateResourceDict(
- CPDF_Document* pDoc,
- std::unique_ptr<CPDF_Dictionary> pExtGStateDict,
- std::unique_ptr<CPDF_Dictionary> pResourceFontDict);
- static void GenerateAndSetAPDict(
- CPDF_Document* pDoc,
- CPDF_Dictionary* pAnnotDict,
- std::ostringstream* psAppStream,
- std::unique_ptr<CPDF_Dictionary> pResourceDict,
- bool bIsTextMarkupAnnotation);
+ static void GenerateFormAP(Type type,
+ CPDF_Document* pDoc,
+ CPDF_Dictionary* pAnnotDict);
+ static void GenerateEmptyAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict);
+
+ static bool GenerateAnnotAP(CPDF_Annot::Subtype subtype,
+ CPDF_Document* pDoc,
+ CPDF_Dictionary* pAnnotDict);
};
#endif // CORE_FPDFDOC_CPVT_GENERATEAP_H_
diff --git a/fpdfsdk/fpdfannot.cpp b/fpdfsdk/fpdfannot.cpp
index a671032..09bf42a 100644
--- a/fpdfsdk/fpdfannot.cpp
+++ b/fpdfsdk/fpdfannot.cpp
@@ -357,14 +357,7 @@
CPDF_Stream* pStream = FPDFDOC_GetAnnotAP(pAnnot->GetAnnotDict(),
CPDF_Annot::AppearanceMode::Normal);
if (!pStream) {
- auto pExtGStateDict =
- CPVT_GenerateAP::GenerateExtGStateDict(*pAnnotDict, "GS", "Normal");
- auto pResourceDict = CPVT_GenerateAP::GenerateResourceDict(
- pPage->m_pDocument.Get(), std::move(pExtGStateDict), nullptr);
- std::ostringstream sStream;
- CPVT_GenerateAP::GenerateAndSetAPDict(pPage->m_pDocument.Get(), pAnnotDict,
- &sStream, std::move(pResourceDict),
- false);
+ CPVT_GenerateAP::GenerateEmptyAP(pPage->m_pDocument.Get(), pAnnotDict);
pStream =
FPDFDOC_GetAnnotAP(pAnnotDict, CPDF_Annot::AppearanceMode::Normal);
if (!pStream)