// Copyright 2014 PDFium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #include "core/fpdfapi/fpdf_font/include/cpdf_font.h" #include "core/fpdfapi/fpdf_parser/include/cpdf_array.h" #include "core/fpdfapi/fpdf_parser/include/cpdf_document.h" #include "core/fpdfapi/fpdf_parser/include/cpdf_simple_parser.h" #include "core/fpdfapi/fpdf_parser/include/cpdf_stream.h" #include "core/fpdfdoc/doc_utils.h" #include "core/fpdfdoc/pdf_vt.h" #include "core/include/fpdfdoc/fpdf_ap.h" #include "core/include/fpdfdoc/fpdf_doc.h" #include "core/include/fpdfdoc/fpdf_vt.h" #define PBS_SOLID 0 #define PBS_DASH 1 #define PBS_BEVELED 2 #define PBS_INSET 3 #define PBS_UNDERLINED 4 FX_BOOL FPDF_GenerateAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict) { if (!pAnnotDict || pAnnotDict->GetConstStringBy("Subtype") != "Widget") { return FALSE; } CFX_ByteString field_type = FPDF_GetFieldAttr(pAnnotDict, "FT")->GetString(); FX_DWORD flags = FPDF_GetFieldAttr(pAnnotDict, "Ff") ? FPDF_GetFieldAttr(pAnnotDict, "Ff")->GetInteger() : 0; if (field_type == "Tx") { return CPVT_GenerateAP::GenerateTextFieldAP(pDoc, pAnnotDict); } if (field_type == "Ch") { return (flags & (1 << 17)) ? CPVT_GenerateAP::GenerateComboBoxAP(pDoc, pAnnotDict) : CPVT_GenerateAP::GenerateListBoxAP(pDoc, pAnnotDict); } if (field_type == "Btn") { if (!(flags & (1 << 16))) { if (!pAnnotDict->KeyExist("AS")) { if (CPDF_Dictionary* pParentDict = pAnnotDict->GetDictBy("Parent")) { if (pParentDict->KeyExist("AS")) { pAnnotDict->SetAtString("AS", pParentDict->GetStringBy("AS")); } } } } } return FALSE; } class CPVT_FontMap : public IPVT_FontMap { public: CPVT_FontMap(CPDF_Document* pDoc, CPDF_Dictionary* pResDict, CPDF_Font* pDefFont, const CFX_ByteString& sDefFontAlias); ~CPVT_FontMap() override; // IPVT_FontMap CPDF_Font* GetPDFFont(int32_t nFontIndex) override; CFX_ByteString GetPDFFontAlias(int32_t nFontIndex) override; static void GetAnnotSysPDFFont(CPDF_Document* pDoc, CPDF_Dictionary* pResDict, CPDF_Font*& pSysFont, CFX_ByteString& sSysFontAlias); private: CPDF_Document* m_pDocument; CPDF_Dictionary* m_pResDict; CPDF_Font* m_pDefFont; CFX_ByteString m_sDefFontAlias; CPDF_Font* m_pSysFont; CFX_ByteString m_sSysFontAlias; }; CPVT_FontMap::CPVT_FontMap(CPDF_Document* pDoc, CPDF_Dictionary* pResDict, CPDF_Font* pDefFont, const CFX_ByteString& sDefFontAlias) : m_pDocument(pDoc), m_pResDict(pResDict), m_pDefFont(pDefFont), m_sDefFontAlias(sDefFontAlias), m_pSysFont(NULL), m_sSysFontAlias() {} CPVT_FontMap::~CPVT_FontMap() {} void CPVT_FontMap::GetAnnotSysPDFFont(CPDF_Document* pDoc, CPDF_Dictionary* pResDict, CPDF_Font*& pSysFont, CFX_ByteString& sSysFontAlias) { if (pDoc && pResDict) { CFX_ByteString sFontAlias; CPDF_Dictionary* pFormDict = pDoc->GetRoot()->GetDictBy("AcroForm"); if (CPDF_Font* pPDFFont = AddNativeInterFormFont(pFormDict, pDoc, sSysFontAlias)) { if (CPDF_Dictionary* pFontList = pResDict->GetDictBy("Font")) { if (!pFontList->KeyExist(sSysFontAlias)) { pFontList->SetAtReference(sSysFontAlias, pDoc, pPDFFont->GetFontDict()); } } pSysFont = pPDFFont; } } } CPDF_Font* CPVT_FontMap::GetPDFFont(int32_t nFontIndex) { switch (nFontIndex) { case 0: return m_pDefFont; case 1: if (!m_pSysFont) { GetAnnotSysPDFFont(m_pDocument, m_pResDict, m_pSysFont, m_sSysFontAlias); } return m_pSysFont; } return NULL; } CFX_ByteString CPVT_FontMap::GetPDFFontAlias(int32_t nFontIndex) { switch (nFontIndex) { case 0: return m_sDefFontAlias; case 1: if (!m_pSysFont) { GetAnnotSysPDFFont(m_pDocument, m_pResDict, m_pSysFont, m_sSysFontAlias); } return m_sSysFontAlias; } return ""; } CPVT_Provider::CPVT_Provider(IPVT_FontMap* pFontMap) : m_pFontMap(pFontMap) { ASSERT(m_pFontMap); } CPVT_Provider::~CPVT_Provider() {} int32_t CPVT_Provider::GetCharWidth(int32_t nFontIndex, uint16_t word, int32_t nWordStyle) { if (CPDF_Font* pPDFFont = m_pFontMap->GetPDFFont(nFontIndex)) { FX_DWORD charcode = pPDFFont->CharCodeFromUnicode(word); if (charcode != CPDF_Font::kInvalidCharCode) { return pPDFFont->GetCharWidthF(charcode); } } return 0; } int32_t CPVT_Provider::GetTypeAscent(int32_t nFontIndex) { if (CPDF_Font* pPDFFont = m_pFontMap->GetPDFFont(nFontIndex)) { return pPDFFont->GetTypeAscent(); } return 0; } int32_t CPVT_Provider::GetTypeDescent(int32_t nFontIndex) { if (CPDF_Font* pPDFFont = m_pFontMap->GetPDFFont(nFontIndex)) { return pPDFFont->GetTypeDescent(); } return 0; } int32_t CPVT_Provider::GetWordFontIndex(uint16_t word, int32_t charset, int32_t nFontIndex) { if (CPDF_Font* pDefFont = m_pFontMap->GetPDFFont(0)) { if (pDefFont->CharCodeFromUnicode(word) != CPDF_Font::kInvalidCharCode) { return 0; } } if (CPDF_Font* pSysFont = m_pFontMap->GetPDFFont(1)) { if (pSysFont->CharCodeFromUnicode(word) != CPDF_Font::kInvalidCharCode) { return 1; } } return -1; } FX_BOOL CPVT_Provider::IsLatinWord(uint16_t word) { if ((word >= 0x61 && word <= 0x7A) || (word >= 0x41 && word <= 0x5A) || word == 0x2D || word == 0x27) { return TRUE; } return FALSE; } int32_t CPVT_Provider::GetDefaultFontIndex() { return 0; } static CFX_ByteString GetPDFWordString(IPVT_FontMap* pFontMap, int32_t nFontIndex, uint16_t Word, uint16_t SubWord) { CFX_ByteString sWord; if (SubWord > 0) { sWord.Format("%c", SubWord); return sWord; } if (!pFontMap) return sWord; if (CPDF_Font* pPDFFont = pFontMap->GetPDFFont(nFontIndex)) { if (pPDFFont->GetBaseFont().Compare("Symbol") == 0 || pPDFFont->GetBaseFont().Compare("ZapfDingbats") == 0) { sWord.Format("%c", Word); } else { FX_DWORD dwCharCode = pPDFFont->CharCodeFromUnicode(Word); if (dwCharCode != CPDF_Font::kInvalidCharCode) { pPDFFont->AppendChar(sWord, dwCharCode); } } } return sWord; } static CFX_ByteString GetWordRenderString(const CFX_ByteString& strWords) { if (strWords.GetLength() > 0) { return PDF_EncodeString(strWords) + " Tj\n"; } return ""; } static CFX_ByteString GetFontSetString(IPVT_FontMap* pFontMap, int32_t nFontIndex, FX_FLOAT fFontSize) { CFX_ByteTextBuf sRet; if (pFontMap) { CFX_ByteString sFontAlias = pFontMap->GetPDFFontAlias(nFontIndex); if (sFontAlias.GetLength() > 0 && fFontSize > 0) { sRet << "/" << sFontAlias << " " << fFontSize << " Tf\n"; } } return sRet.GetByteString(); } static CPVT_Color ParseColor(const CFX_ByteString& str) { CPDF_SimpleParser syntax(str); if (syntax.FindTagParamFromStart("g", 1)) { return CPVT_Color(CPVT_Color::kGray, FX_atof(syntax.GetWord())); } if (syntax.FindTagParamFromStart("rg", 3)) { FX_FLOAT f1 = FX_atof(syntax.GetWord()); FX_FLOAT f2 = FX_atof(syntax.GetWord()); FX_FLOAT f3 = FX_atof(syntax.GetWord()); return CPVT_Color(CPVT_Color::kRGB, f1, f2, f3); } if (syntax.FindTagParamFromStart("k", 4)) { FX_FLOAT f1 = FX_atof(syntax.GetWord()); FX_FLOAT f2 = FX_atof(syntax.GetWord()); FX_FLOAT f3 = FX_atof(syntax.GetWord()); FX_FLOAT f4 = FX_atof(syntax.GetWord()); return CPVT_Color(CPVT_Color::kCMYK, f1, f2, f3, f4); } return CPVT_Color(CPVT_Color::kTransparent); } static CPVT_Color ParseColor(const CPDF_Array& array) { CPVT_Color rt; switch (array.GetCount()) { case 1: rt = CPVT_Color(CPVT_Color::kGray, array.GetFloatAt(0)); break; case 3: rt = CPVT_Color(CPVT_Color::kRGB, array.GetFloatAt(0), array.GetFloatAt(1), array.GetFloatAt(2)); break; case 4: rt = CPVT_Color(CPVT_Color::kCMYK, array.GetFloatAt(0), array.GetFloatAt(1), array.GetFloatAt(2), array.GetFloatAt(3)); break; } return rt; } static FX_BOOL GenerateWidgetAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict, const int32_t& nWidgetType) { CPDF_Dictionary* pFormDict = NULL; if (CPDF_Dictionary* pRootDict = pDoc->GetRoot()) { pFormDict = pRootDict->GetDictBy("AcroForm"); } if (!pFormDict) { return FALSE; } CFX_ByteString DA; if (CPDF_Object* pDAObj = FPDF_GetFieldAttr(pAnnotDict, "DA")) { DA = pDAObj->GetString(); } if (DA.IsEmpty()) { DA = pFormDict->GetStringBy("DA"); } if (DA.IsEmpty()) { return FALSE; } CPDF_SimpleParser syntax(DA); syntax.FindTagParamFromStart("Tf", 2); CFX_ByteString sFontName = syntax.GetWord(); sFontName = PDF_NameDecode(sFontName); if (sFontName.IsEmpty()) { return FALSE; } FX_FLOAT fFontSize = FX_atof(syntax.GetWord()); CPVT_Color crText = ParseColor(DA); FX_BOOL bUseFormRes = FALSE; CPDF_Dictionary* pFontDict = NULL; CPDF_Dictionary* pDRDict = pAnnotDict->GetDictBy("DR"); if (!pDRDict) { pDRDict = pFormDict->GetDictBy("DR"); bUseFormRes = TRUE; } CPDF_Dictionary* pDRFontDict = pDRDict ? pDRDict->GetDictBy("Font") : nullptr; if (pDRFontDict) { pFontDict = pDRFontDict->GetDictBy(sFontName.Mid(1)); if (!pFontDict && !bUseFormRes) { pDRDict = pFormDict->GetDictBy("DR"); pDRFontDict = pDRDict->GetDictBy("Font"); if (pDRFontDict) { pFontDict = pDRFontDict->GetDictBy(sFontName.Mid(1)); } } } if (!pDRFontDict) { return FALSE; } if (!pFontDict) { pFontDict = new CPDF_Dictionary; pFontDict->SetAtName("Type", "Font"); pFontDict->SetAtName("Subtype", "Type1"); pFontDict->SetAtName("BaseFont", "Helvetica"); pFontDict->SetAtName("Encoding", "WinAnsiEncoding"); pDoc->AddIndirectObject(pFontDict); pDRFontDict->SetAtReference(sFontName.Mid(1), pDoc, pFontDict); } CPDF_Font* pDefFont = pDoc->LoadFont(pFontDict); if (!pDefFont) { return FALSE; } CFX_FloatRect rcAnnot = pAnnotDict->GetRectBy("Rect"); int32_t nRotate = 0; if (CPDF_Dictionary* pMKDict = pAnnotDict->GetDictBy("MK")) { nRotate = pMKDict->GetIntegerBy("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; } int32_t nBorderStyle = PBS_SOLID; FX_FLOAT fBorderWidth = 1; CPVT_Dash dsBorder(3, 0, 0); CPVT_Color crLeftTop, crRightBottom; if (CPDF_Dictionary* pBSDict = pAnnotDict->GetDictBy("BS")) { if (pBSDict->KeyExist("W")) { fBorderWidth = pBSDict->GetNumberBy("W"); } if (CPDF_Array* pArray = pBSDict->GetArrayBy("D")) { dsBorder = CPVT_Dash(pArray->GetIntegerAt(0), pArray->GetIntegerAt(1), pArray->GetIntegerAt(2)); } switch (pBSDict->GetStringBy("S").GetAt(0)) { case 'S': nBorderStyle = PBS_SOLID; break; case 'D': nBorderStyle = PBS_DASH; break; case 'B': nBorderStyle = PBS_BEVELED; fBorderWidth *= 2; crLeftTop = CPVT_Color(CPVT_Color::kGray, 1); crRightBottom = CPVT_Color(CPVT_Color::kGray, 0.5); break; case 'I': nBorderStyle = PBS_INSET; fBorderWidth *= 2; crLeftTop = CPVT_Color(CPVT_Color::kGray, 0.5); crRightBottom = CPVT_Color(CPVT_Color::kGray, 0.75); break; case 'U': nBorderStyle = PBS_UNDERLINED; break; } } CPVT_Color crBorder, crBG; if (CPDF_Dictionary* pMKDict = pAnnotDict->GetDictBy("MK")) { if (CPDF_Array* pArray = pMKDict->GetArrayBy("BC")) { crBorder = ParseColor(*pArray); } if (CPDF_Array* pArray = pMKDict->GetArrayBy("BG")) { crBG = ParseColor(*pArray); } } CFX_ByteTextBuf sAppStream; CFX_ByteString sBG = CPVT_GenerateAP::GenerateColorAP(crBG, TRUE); if (sBG.GetLength() > 0) { sAppStream << "q\n" << sBG << rcBBox.left << " " << rcBBox.bottom << " " << rcBBox.Width() << " " << rcBBox.Height() << " re f\n" << "Q\n"; } CFX_ByteString sBorderStream = CPVT_GenerateAP::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->GetDictBy("AP"); if (!pAPDict) { pAPDict = new CPDF_Dictionary; pAnnotDict->SetAt("AP", pAPDict); } CPDF_Stream* pNormalStream = pAPDict->GetStreamBy("N"); if (!pNormalStream) { pNormalStream = new CPDF_Stream(nullptr, 0, nullptr); int32_t objnum = pDoc->AddIndirectObject(pNormalStream); pAnnotDict->GetDictBy("AP")->SetAtReference("N", pDoc, objnum); } CPDF_Dictionary* pStreamDict = pNormalStream->GetDict(); if (pStreamDict) { pStreamDict->SetAtMatrix("Matrix", matrix); pStreamDict->SetAtRect("BBox", rcBBox); CPDF_Dictionary* pStreamResList = pStreamDict->GetDictBy("Resources"); if (pStreamResList) { CPDF_Dictionary* pStreamResFontList = pStreamResList->GetDictBy("Font"); if (!pStreamResFontList) { pStreamResFontList = new CPDF_Dictionary; pStreamResList->SetAt("Font", pStreamResFontList); } if (!pStreamResFontList->KeyExist(sFontName)) { pStreamResFontList->SetAtReference(sFontName, pDoc, pFontDict); } } else { pStreamDict->SetAt("Resources", pFormDict->GetDictBy("DR")->Clone()); pStreamResList = pStreamDict->GetDictBy("Resources"); } } switch (nWidgetType) { case 0: { CFX_WideString swValue = FPDF_GetFieldAttr(pAnnotDict, "V") ? FPDF_GetFieldAttr(pAnnotDict, "V")->GetUnicodeText() : CFX_WideString(); int32_t nAlign = FPDF_GetFieldAttr(pAnnotDict, "Q") ? FPDF_GetFieldAttr(pAnnotDict, "Q")->GetInteger() : 0; FX_DWORD dwFlags = FPDF_GetFieldAttr(pAnnotDict, "Ff") ? FPDF_GetFieldAttr(pAnnotDict, "Ff")->GetInteger() : 0; FX_DWORD dwMaxLen = FPDF_GetFieldAttr(pAnnotDict, "MaxLen") ? FPDF_GetFieldAttr(pAnnotDict, "MaxLen")->GetInteger() : 0; CPVT_FontMap map(pDoc, pStreamDict ? pStreamDict->GetDictBy("Resources") : NULL, pDefFont, sFontName.Right(sFontName.GetLength() - 1)); CPVT_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); } FX_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); } FX_BOOL bCharArray = (dwFlags >> 24) & 1; if (bCharArray) { vt.SetCharArray(dwMaxLen); } else { vt.SetLimitChar(dwMaxLen); } vt.Initialize(); vt.SetText(swValue.c_str()); vt.RearrangeAll(); CFX_FloatRect rcContent = vt.GetContentRect(); CFX_FloatPoint ptOffset(0.0f, 0.0f); if (!bMultiLine) { ptOffset = CFX_FloatPoint(0.0f, (rcContent.Height() - rcBody.Height()) / 2.0f); } CFX_ByteString sBody = CPVT_GenerateAP::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" << CPVT_GenerateAP::GenerateColorAP(crText, TRUE) << sBody << "ET\n" << "Q\nEMC\n"; } } break; case 1: { CFX_WideString swValue = FPDF_GetFieldAttr(pAnnotDict, "V") ? FPDF_GetFieldAttr(pAnnotDict, "V")->GetUnicodeText() : CFX_WideString(); CPVT_FontMap map(pDoc, pStreamDict ? pStreamDict->GetDictBy("Resources") : NULL, pDefFont, sFontName.Right(sFontName.GetLength() - 1)); CPVT_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.c_str()); vt.RearrangeAll(); CFX_FloatRect rcContent = vt.GetContentRect(); CFX_FloatPoint ptOffset = CFX_FloatPoint(0.0f, (rcContent.Height() - rcEdit.Height()) / 2.0f); CFX_ByteString sEdit = CPVT_GenerateAP::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" << CPVT_GenerateAP::GenerateColorAP(crText, TRUE) << sEdit << "ET\n" << "Q\nEMC\n"; } CFX_ByteString sButton = CPVT_GenerateAP::GenerateColorAP( CPVT_Color(CPVT_Color::kRGB, 220.0f / 255.0f, 220.0f / 255.0f, 220.0f / 255.0f), TRUE); 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"; CFX_ByteString sButtonBorder = CPVT_GenerateAP::GenerateBorderAP( rcButton, 2, CPVT_Color(CPVT_Color::kGray, 0), CPVT_Color(CPVT_Color::kGray, 1), CPVT_Color(CPVT_Color::kGray, 0.5), PBS_BEVELED, CPVT_Dash(3, 0, 0)); if (sButtonBorder.GetLength() > 0) { sAppStream << "q\n" << sButtonBorder << "Q\n"; } CFX_FloatPoint ptCenter = CFX_FloatPoint((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->GetDictBy("Resources") : NULL, pDefFont, sFontName.Right(sFontName.GetLength() - 1)); CPVT_Provider prd(&map); CPDF_Array* pOpts = FPDF_GetFieldAttr(pAnnotDict, "Opt") ? FPDF_GetFieldAttr(pAnnotDict, "Opt")->GetArray() : NULL; CPDF_Array* pSels = FPDF_GetFieldAttr(pAnnotDict, "I") ? FPDF_GetFieldAttr(pAnnotDict, "I")->GetArray() : NULL; int32_t nTop = FPDF_GetFieldAttr(pAnnotDict, "TI") ? FPDF_GetFieldAttr(pAnnotDict, "TI")->GetInteger() : 0; CFX_ByteTextBuf sBody; if (pOpts) { FX_FLOAT fy = rcBody.top; for (int32_t i = nTop, sz = pOpts->GetCount(); i < sz; i++) { if (IsFloatSmaller(fy, rcBody.bottom)) { break; } if (CPDF_Object* pOpt = pOpts->GetElementValue(i)) { CFX_WideString swItem; if (pOpt->IsString()) swItem = pOpt->GetUnicodeText(); else if (CPDF_Array* pArray = pOpt->AsArray()) swItem = pArray->GetElementValue(1)->GetUnicodeText(); FX_BOOL bSelected = FALSE; if (pSels) { for (FX_DWORD s = 0, ssz = pSels->GetCount(); s < ssz; s++) { if (i == pSels->GetIntegerAt(s)) { bSelected = TRUE; break; } } } CPDF_VariableText vt; vt.SetProvider(&prd); vt.SetPlateRect( CFX_FloatRect(rcBody.left, 0.0f, rcBody.right, 0.0f)); if (IsFloatZero(fFontSize)) { vt.SetFontSize(12.0f); } else { vt.SetFontSize(fFontSize); } vt.Initialize(); vt.SetText(swItem.c_str()); vt.RearrangeAll(); FX_FLOAT fItemHeight = vt.GetContentRect().Height(); if (bSelected) { CFX_FloatRect rcItem = CFX_FloatRect( rcBody.left, fy - fItemHeight, rcBody.right, fy); sBody << "q\n" << CPVT_GenerateAP::GenerateColorAP( CPVT_Color(CPVT_Color::kRGB, 0, 51.0f / 255.0f, 113.0f / 255.0f), TRUE) << rcItem.left << " " << rcItem.bottom << " " << rcItem.Width() << " " << rcItem.Height() << " re f\n" << "Q\n"; sBody << "BT\n" << CPVT_GenerateAP::GenerateColorAP( CPVT_Color(CPVT_Color::kGray, 1), TRUE) << CPVT_GenerateAP::GenerateEditAP(&map, vt.GetIterator(), CFX_FloatPoint(0.0f, fy), TRUE, 0) << "ET\n"; } else { sBody << "BT\n" << CPVT_GenerateAP::GenerateColorAP(crText, TRUE) << CPVT_GenerateAP::GenerateEditAP(&map, vt.GetIterator(), CFX_FloatPoint(0.0f, fy), TRUE, 0) << "ET\n"; } fy -= fItemHeight; } } } if (sBody.GetSize() > 0) { sAppStream << "/Tx BMC\n" << "q\n"; sAppStream << rcBody.left << " " << rcBody.bottom << " " << rcBody.Width() << " " << rcBody.Height() << " re\nW\nn\n"; sAppStream << sBody.GetByteString() << "Q\nEMC\n"; } } break; } if (pNormalStream) { pNormalStream->SetData((uint8_t*)sAppStream.GetBuffer(), sAppStream.GetSize(), FALSE, FALSE); pStreamDict = pNormalStream->GetDict(); if (pStreamDict) { pStreamDict->SetAtMatrix("Matrix", matrix); pStreamDict->SetAtRect("BBox", rcBBox); CPDF_Dictionary* pStreamResList = pStreamDict->GetDictBy("Resources"); if (pStreamResList) { CPDF_Dictionary* pStreamResFontList = pStreamResList->GetDictBy("Font"); if (!pStreamResFontList) { pStreamResFontList = new CPDF_Dictionary; pStreamResList->SetAt("Font", pStreamResFontList); } if (!pStreamResFontList->KeyExist(sFontName)) { pStreamResFontList->SetAtReference(sFontName, pDoc, pFontDict); } } else { pStreamDict->SetAt("Resources", pFormDict->GetDictBy("DR")->Clone()); pStreamResList = pStreamDict->GetDictBy("Resources"); } } } return TRUE; } FX_BOOL CPVT_GenerateAP::GenerateTextFieldAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict) { return GenerateWidgetAP(pDoc, pAnnotDict, 0); } FX_BOOL CPVT_GenerateAP::GenerateComboBoxAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict) { return GenerateWidgetAP(pDoc, pAnnotDict, 1); } FX_BOOL CPVT_GenerateAP::GenerateListBoxAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict) { return GenerateWidgetAP(pDoc, pAnnotDict, 2); } CFX_ByteString CPVT_GenerateAP::GenerateEditAP( IPVT_FontMap* pFontMap, IPDF_VariableText_Iterator* pIterator, const CFX_FloatPoint& ptOffset, FX_BOOL bContinuous, uint16_t SubWord, const CPVT_WordRange* pVisible) { CFX_ByteTextBuf sEditStream, sLineStream, sWords; CFX_FloatPoint ptOld(0.0f, 0.0f), ptNew(0.0f, 0.0f); int32_t nCurFontIndex = -1; if (pIterator) { if (pVisible) { pIterator->SetAt(pVisible->BeginPos); } else { pIterator->SetAt(0); } CPVT_WordPlace oldplace; while (pIterator->NextWord()) { CPVT_WordPlace place = pIterator->GetAt(); if (pVisible && place.WordCmp(pVisible->EndPos) > 0) { break; } if (bContinuous) { if (place.LineCmp(oldplace) != 0) { if (sWords.GetSize() > 0) { sLineStream << GetWordRenderString(sWords.GetByteString()); sEditStream << sLineStream; sLineStream.Clear(); sWords.Clear(); } CPVT_Word word; if (pIterator->GetWord(word)) { ptNew = CFX_FloatPoint(word.ptWord.x + ptOffset.x, word.ptWord.y + ptOffset.y); } else { CPVT_Line line; pIterator->GetLine(line); ptNew = CFX_FloatPoint(line.ptLine.x + ptOffset.x, line.ptLine.y + ptOffset.y); } if (ptNew.x != ptOld.x || ptNew.y != ptOld.y) { sLineStream << ptNew.x - ptOld.x << " " << ptNew.y - ptOld.y << " Td\n"; ptOld = ptNew; } } CPVT_Word word; if (pIterator->GetWord(word)) { if (word.nFontIndex != nCurFontIndex) { if (sWords.GetSize() > 0) { sLineStream << GetWordRenderString(sWords.GetByteString()); sWords.Clear(); } sLineStream << GetFontSetString(pFontMap, word.nFontIndex, word.fFontSize); nCurFontIndex = word.nFontIndex; } sWords << GetPDFWordString(pFontMap, nCurFontIndex, word.Word, SubWord); } oldplace = place; } else { CPVT_Word word; if (pIterator->GetWord(word)) { ptNew = CFX_FloatPoint(word.ptWord.x + ptOffset.x, word.ptWord.y + ptOffset.y); if (ptNew.x != ptOld.x || ptNew.y != ptOld.y) { sEditStream << ptNew.x - ptOld.x << " " << ptNew.y - ptOld.y << " Td\n"; ptOld = ptNew; } if (word.nFontIndex != nCurFontIndex) { sEditStream << GetFontSetString(pFontMap, word.nFontIndex, word.fFontSize); nCurFontIndex = word.nFontIndex; } sEditStream << GetWordRenderString( GetPDFWordString(pFontMap, nCurFontIndex, word.Word, SubWord)); } } } if (sWords.GetSize() > 0) { sLineStream << GetWordRenderString(sWords.GetByteString()); sEditStream << sLineStream; sWords.Clear(); } } return sEditStream.GetByteString(); } CFX_ByteString CPVT_GenerateAP::GenerateBorderAP( const CFX_FloatRect& rect, FX_FLOAT fWidth, const CPVT_Color& color, const CPVT_Color& crLeftTop, const CPVT_Color& crRightBottom, int32_t nStyle, const CPVT_Dash& dash) { CFX_ByteTextBuf sAppStream; CFX_ByteString sColor; FX_FLOAT fLeft = rect.left; FX_FLOAT fRight = rect.right; FX_FLOAT fTop = rect.top; FX_FLOAT fBottom = rect.bottom; if (fWidth > 0.0f) { FX_FLOAT fHalfWidth = fWidth / 2.0f; switch (nStyle) { default: case PBS_SOLID: sColor = GenerateColorAP(color, TRUE); if (sColor.GetLength() > 0) { sAppStream << sColor; sAppStream << fLeft << " " << fBottom << " " << fRight - fLeft << " " << fTop - fBottom << " re\n"; sAppStream << fLeft + fWidth << " " << fBottom + fWidth << " " << fRight - fLeft - fWidth * 2 << " " << fTop - fBottom - fWidth * 2 << " re\n"; sAppStream << "f*\n"; } break; case PBS_DASH: sColor = GenerateColorAP(color, FALSE); if (sColor.GetLength() > 0) { sAppStream << sColor; sAppStream << fWidth << " w" << " [" << dash.nDash << " " << dash.nGap << "] " << dash.nPhase << " d\n"; sAppStream << fLeft + fWidth / 2 << " " << fBottom + fWidth / 2 << " m\n"; sAppStream << fLeft + fWidth / 2 << " " << fTop - fWidth / 2 << " l\n"; sAppStream << fRight - fWidth / 2 << " " << fTop - fWidth / 2 << " l\n"; sAppStream << fRight - fWidth / 2 << " " << fBottom + fWidth / 2 << " l\n"; sAppStream << fLeft + fWidth / 2 << " " << fBottom + fWidth / 2 << " l S\n"; } break; case PBS_BEVELED: case PBS_INSET: sColor = GenerateColorAP(crLeftTop, TRUE); if (sColor.GetLength() > 0) { sAppStream << sColor; sAppStream << fLeft + fHalfWidth << " " << fBottom + fHalfWidth << " m\n"; sAppStream << fLeft + fHalfWidth << " " << fTop - fHalfWidth << " l\n"; sAppStream << fRight - fHalfWidth << " " << fTop - fHalfWidth << " l\n"; sAppStream << fRight - fHalfWidth * 2 << " " << fTop - fHalfWidth * 2 << " l\n"; sAppStream << fLeft + fHalfWidth * 2 << " " << fTop - fHalfWidth * 2 << " l\n"; sAppStream << fLeft + fHalfWidth * 2 << " " << fBottom + fHalfWidth * 2 << " l f\n"; } sColor = GenerateColorAP(crRightBottom, TRUE); if (sColor.GetLength() > 0) { sAppStream << sColor; sAppStream << fRight - fHalfWidth << " " << fTop - fHalfWidth << " m\n"; sAppStream << fRight - fHalfWidth << " " << fBottom + fHalfWidth << " l\n"; sAppStream << fLeft + fHalfWidth << " " << fBottom + fHalfWidth << " l\n"; sAppStream << fLeft + fHalfWidth * 2 << " " << fBottom + fHalfWidth * 2 << " l\n"; sAppStream << fRight - fHalfWidth * 2 << " " << fBottom + fHalfWidth * 2 << " l\n"; sAppStream << fRight - fHalfWidth * 2 << " " << fTop - fHalfWidth * 2 << " l f\n"; } sColor = GenerateColorAP(color, TRUE); if (sColor.GetLength() > 0) { sAppStream << sColor; sAppStream << fLeft << " " << fBottom << " " << fRight - fLeft << " " << fTop - fBottom << " re\n"; sAppStream << fLeft + fHalfWidth << " " << fBottom + fHalfWidth << " " << fRight - fLeft - fHalfWidth * 2 << " " << fTop - fBottom - fHalfWidth * 2 << " re f*\n"; } break; case PBS_UNDERLINED: sColor = GenerateColorAP(color, FALSE); if (sColor.GetLength() > 0) { sAppStream << sColor; sAppStream << fWidth << " w\n"; sAppStream << fLeft << " " << fBottom + fWidth / 2 << " m\n"; sAppStream << fRight << " " << fBottom + fWidth / 2 << " l S\n"; } break; } } return sAppStream.GetByteString(); } CFX_ByteString CPVT_GenerateAP::GenerateColorAP(const CPVT_Color& color, const FX_BOOL& bFillOrStroke) { CFX_ByteTextBuf sColorStream; switch (color.nColorType) { case CPVT_Color::kRGB: sColorStream << color.fColor1 << " " << color.fColor2 << " " << color.fColor3 << " " << (bFillOrStroke ? "rg" : "RG") << "\n"; break; case CPVT_Color::kGray: sColorStream << color.fColor1 << " " << (bFillOrStroke ? "g" : "G") << "\n"; break; case CPVT_Color::kCMYK: sColorStream << color.fColor1 << " " << color.fColor2 << " " << color.fColor3 << " " << color.fColor4 << " " << (bFillOrStroke ? "k" : "K") << "\n"; break; case CPVT_Color::kTransparent: break; } return sColorStream.GetByteString(); }