Split core/include/fpdfdoc/fpdf_ap.h

This CL splits the fpdf_ap.h file apart into individual pieces and moves the
implementations to their own CPP files.

Review URL: https://codereview.chromium.org/1840413002
diff --git a/BUILD.gn b/BUILD.gn
index ad12068..0ba2998 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -194,6 +194,14 @@
 
 static_library("fpdfdoc") {
   sources = [
+    "core/fpdfdoc/cpvt_color.cpp",
+    "core/fpdfdoc/cpvt_color.h",
+    "core/fpdfdoc/cpvt_dash.h",
+    "core/fpdfdoc/cpvt_fontmap.cpp",
+    "core/fpdfdoc/cpvt_fontmap.h",
+    "core/fpdfdoc/cpvt_generateap.cpp",
+    "core/fpdfdoc/cpvt_generateap.h",
+    "core/fpdfdoc/cpvt_provider.h",
     "core/fpdfdoc/doc_action.cpp",
     "core/fpdfdoc/doc_annot.cpp",
     "core/fpdfdoc/doc_ap.cpp",
@@ -211,9 +219,11 @@
     "core/fpdfdoc/doc_viewerPreferences.cpp",
     "core/fpdfdoc/doc_vt.cpp",
     "core/fpdfdoc/doc_vtmodule.cpp",
+    "core/fpdfdoc/include/ipdf_variabletext_provider.h",
+    "core/fpdfdoc/ipdf_variabletext_provider.cpp",
+    "core/fpdfdoc/ipvt_fontmap.h",
     "core/fpdfdoc/pdf_vt.h",
     "core/fpdfdoc/tagged_int.h",
-    "core/include/fpdfdoc/fpdf_ap.h",
     "core/include/fpdfdoc/fpdf_doc.h",
     "core/include/fpdfdoc/fpdf_tagged.h",
     "core/include/fpdfdoc/fpdf_vt.h",
diff --git a/core/fpdfdoc/cpvt_color.cpp b/core/fpdfdoc/cpvt_color.cpp
new file mode 100644
index 0000000..afeff23
--- /dev/null
+++ b/core/fpdfdoc/cpvt_color.cpp
@@ -0,0 +1,51 @@
+// Copyright 2016 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/fpdfdoc/cpvt_color.h"
+
+#include "core/fpdfapi/fpdf_parser/include/cpdf_simple_parser.h"
+
+// Static.
+CPVT_Color 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 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;
+}
diff --git a/core/fpdfdoc/cpvt_color.h b/core/fpdfdoc/cpvt_color.h
new file mode 100644
index 0000000..da23ce4
--- /dev/null
+++ b/core/fpdfdoc/cpvt_color.h
@@ -0,0 +1,38 @@
+// Copyright 2016 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
+
+#ifndef CORE_FPDFDOC_CPVT_COLOR_H_
+#define CORE_FPDFDOC_CPVT_COLOR_H_
+
+#include "core/fpdfapi/fpdf_parser/include/cpdf_array.h"
+#include "core/fxcrt/include/fx_string.h"
+#include "core/fxcrt/include/fx_system.h"
+
+struct CPVT_Color {
+  enum Type { kTransparent = 0, kGray, kRGB, kCMYK };
+
+  CPVT_Color(Type type = kTransparent,
+             FX_FLOAT color1 = 0.0f,
+             FX_FLOAT color2 = 0.0f,
+             FX_FLOAT color3 = 0.0f,
+             FX_FLOAT color4 = 0.0f)
+      : nColorType(type),
+        fColor1(color1),
+        fColor2(color2),
+        fColor3(color3),
+        fColor4(color4) {}
+
+  Type nColorType;
+  FX_FLOAT fColor1;
+  FX_FLOAT fColor2;
+  FX_FLOAT fColor3;
+  FX_FLOAT fColor4;
+
+  static CPVT_Color ParseColor(const CFX_ByteString& str);
+  static CPVT_Color ParseColor(const CPDF_Array& array);
+};
+
+#endif  // CORE_FPDFDOC_CPVT_COLOR_H_
diff --git a/core/fpdfdoc/cpvt_dash.h b/core/fpdfdoc/cpvt_dash.h
new file mode 100644
index 0000000..f80d104
--- /dev/null
+++ b/core/fpdfdoc/cpvt_dash.h
@@ -0,0 +1,21 @@
+// Copyright 2016 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
+
+#ifndef CORE_FPDFDOC_CPVT_DASH_H_
+#define CORE_FPDFDOC_CPVT_DASH_H_
+
+#include <stdint.h>
+
+struct CPVT_Dash {
+  CPVT_Dash(int32_t dash, int32_t gap, int32_t phase)
+      : nDash(dash), nGap(gap), nPhase(phase) {}
+
+  int32_t nDash;
+  int32_t nGap;
+  int32_t nPhase;
+};
+
+#endif  // CORE_FPDFDOC_CPVT_DASH_H_
diff --git a/core/fpdfdoc/cpvt_fontmap.cpp b/core/fpdfdoc/cpvt_fontmap.cpp
new file mode 100644
index 0000000..529f851
--- /dev/null
+++ b/core/fpdfdoc/cpvt_fontmap.cpp
@@ -0,0 +1,75 @@
+// Copyright 2016 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/fpdfdoc/cpvt_fontmap.h"
+
+#include "core/fpdfapi/fpdf_font/include/cpdf_font.h"
+#include "core/fpdfapi/fpdf_parser/include/cpdf_dictionary.h"
+#include "core/fpdfapi/fpdf_parser/include/cpdf_document.h"
+#include "core/fpdfdoc/doc_utils.h"
+
+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(nullptr),
+      m_sSysFontAlias() {}
+
+CPVT_FontMap::~CPVT_FontMap() {}
+
+void CPVT_FontMap::GetAnnotSysPDFFont(CPDF_Document* pDoc,
+                                      const CPDF_Dictionary* pResDict,
+                                      CPDF_Font*& pSysFont,
+                                      CFX_ByteString& sSysFontAlias) {
+  if (!pDoc || !pResDict)
+    return;
+
+  CFX_ByteString sFontAlias;
+  CPDF_Dictionary* pFormDict = pDoc->GetRoot()->GetDictBy("AcroForm");
+  CPDF_Font* pPDFFont = AddNativeInterFormFont(pFormDict, pDoc, sSysFontAlias);
+  if (!pPDFFont)
+    return;
+
+  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;
+    default:
+      return nullptr;
+  }
+}
+
+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;
+    default:
+      return "";
+  }
+}
diff --git a/core/fpdfdoc/cpvt_fontmap.h b/core/fpdfdoc/cpvt_fontmap.h
new file mode 100644
index 0000000..d6f931a
--- /dev/null
+++ b/core/fpdfdoc/cpvt_fontmap.h
@@ -0,0 +1,45 @@
+// Copyright 2016 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
+
+#ifndef CORE_FPDFDOC_CPVT_FONTMAP_H_
+#define CORE_FPDFDOC_CPVT_FONTMAP_H_
+
+#include <stdint.h>
+
+#include "core/fpdfdoc/ipvt_fontmap.h"
+#include "core/fxcrt/include/fx_string.h"
+
+class CPDF_Document;
+class CPDF_Dictionary;
+class CPDF_Font;
+
+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,
+                                 const CPDF_Dictionary* pResDict,
+                                 CPDF_Font*& pSysFont,
+                                 CFX_ByteString& sSysFontAlias);
+
+ private:
+  CPDF_Document* const m_pDocument;
+  const CPDF_Dictionary* const m_pResDict;
+  CPDF_Font* const m_pDefFont;
+  const CFX_ByteString m_sDefFontAlias;
+  CPDF_Font* m_pSysFont;
+  CFX_ByteString m_sSysFontAlias;
+};
+
+#endif  // CORE_FPDFDOC_CPVT_FONTMAP_H_
diff --git a/core/fpdfdoc/cpvt_generateap.cpp b/core/fpdfdoc/cpvt_generateap.cpp
new file mode 100644
index 0000000..f9d6e96
--- /dev/null
+++ b/core/fpdfdoc/cpvt_generateap.cpp
@@ -0,0 +1,769 @@
+// Copyright 2016 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/fpdfdoc/cpvt_generateap.h"
+
+#include "core/fpdfapi/fpdf_font/include/cpdf_font.h"
+#include "core/fpdfapi/fpdf_parser/include/cpdf_dictionary.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/cpvt_color.h"
+#include "core/fpdfdoc/cpvt_fontmap.h"
+#include "core/fpdfdoc/cpvt_provider.h"
+#include "core/fpdfdoc/pdf_vt.h"
+#include "core/include/fpdfdoc/fpdf_doc.h"
+
+namespace {
+
+FX_BOOL GenerateWidgetAP(CPDF_Document* pDoc,
+                         CPDF_Dictionary* pAnnotDict,
+                         const int32_t& nWidgetType) {
+  CPDF_Dictionary* pFormDict = nullptr;
+  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 = CPVT_Color::ParseColor(DA);
+  FX_BOOL bUseFormRes = FALSE;
+  CPDF_Dictionary* pFontDict = nullptr;
+  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 = CPVT_Color::ParseColor(*pArray);
+    if (CPDF_Array* pArray = pMKDict->GetArrayBy("BG"))
+      crBG = CPVT_Color::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;
+      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->GetDictBy("Resources") : nullptr,
+          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") : nullptr,
+          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") : nullptr,
+          pDefFont, sFontName.Right(sFontName.GetLength() - 1));
+      CPVT_Provider prd(&map);
+      CPDF_Array* pOpts = FPDF_GetFieldAttr(pAnnotDict, "Opt")
+                              ? FPDF_GetFieldAttr(pAnnotDict, "Opt")->GetArray()
+                              : nullptr;
+      CPDF_Array* pSels = FPDF_GetFieldAttr(pAnnotDict, "I")
+                              ? FPDF_GetFieldAttr(pAnnotDict, "I")->GetArray()
+                              : nullptr;
+      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->GetDirectObjectAt(i)) {
+            CFX_WideString swItem;
+            if (pOpt->IsString())
+              swItem = pOpt->GetUnicodeText();
+            else if (CPDF_Array* pArray = pOpt->AsArray())
+              swItem = pArray->GetDirectObjectAt(1)->GetUnicodeText();
+
+            FX_BOOL bSelected = FALSE;
+            if (pSels) {
+              for (uint32_t 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));
+            vt.SetFontSize(IsFloatZero(fFontSize) ? 12.0f : 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;
+}
+
+}  // namespace
+
+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();
+  uint32_t 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;
+}
+
+// Static.
+FX_BOOL CPVT_GenerateAP::GenerateTextFieldAP(CPDF_Document* pDoc,
+                                             CPDF_Dictionary* pAnnotDict) {
+  return GenerateWidgetAP(pDoc, pAnnotDict, 0);
+}
+
+// Static.
+FX_BOOL CPVT_GenerateAP::GenerateComboBoxAP(CPDF_Document* pDoc,
+                                            CPDF_Dictionary* pAnnotDict) {
+  return GenerateWidgetAP(pDoc, pAnnotDict, 1);
+}
+
+// Static.
+FX_BOOL CPVT_GenerateAP::GenerateListBoxAP(CPDF_Document* pDoc,
+                                           CPDF_Dictionary* pAnnotDict) {
+  return GenerateWidgetAP(pDoc, pAnnotDict, 2);
+}
+
+// Static.
+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();
+}
+
+// Static.
+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();
+}
+
+// Static.
+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();
+}
+
+// Static.
+CFX_ByteString CPVT_GenerateAP::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 {
+      uint32_t dwCharCode = pPDFFont->CharCodeFromUnicode(Word);
+      if (dwCharCode != CPDF_Font::kInvalidCharCode)
+        pPDFFont->AppendChar(sWord, dwCharCode);
+    }
+  }
+  return sWord;
+}
+
+// Static.
+CFX_ByteString CPVT_GenerateAP::GetWordRenderString(
+    const CFX_ByteString& strWords) {
+  if (strWords.GetLength() > 0)
+    return PDF_EncodeString(strWords) + " Tj\n";
+  return "";
+}
+
+// Static.
+CFX_ByteString CPVT_GenerateAP::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();
+}
diff --git a/core/fpdfdoc/cpvt_generateap.h b/core/fpdfdoc/cpvt_generateap.h
new file mode 100644
index 0000000..b97b38a
--- /dev/null
+++ b/core/fpdfdoc/cpvt_generateap.h
@@ -0,0 +1,66 @@
+// Copyright 2016 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
+
+#ifndef CORE_FPDFDOC_CPVT_GENERATEAP_H_
+#define CORE_FPDFDOC_CPVT_GENERATEAP_H_
+
+#include "core/fpdfdoc/cpvt_color.h"
+#include "core/fpdfdoc/cpvt_dash.h"
+#include "core/fxcrt/include/fx_coordinates.h"
+#include "core/fxcrt/include/fx_string.h"
+#include "core/fxcrt/include/fx_system.h"
+
+// border style
+#define PBS_SOLID 0
+#define PBS_DASH 1
+#define PBS_BEVELED 2
+#define PBS_INSET 3
+#define PBS_UNDERLINED 4
+#define PBS_SHADOW 5
+
+class CPDF_Dictionary;
+class CPDF_Document;
+class IPDF_VariableText_Iterator;
+class IPVT_FontMap;
+struct CPVT_WordRange;
+
+FX_BOOL FPDF_GenerateAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict);
+
+class CPVT_GenerateAP {
+ public:
+  static FX_BOOL GenerateTextFieldAP(CPDF_Document* pDoc,
+                                     CPDF_Dictionary* pAnnotDict);
+  static FX_BOOL GenerateComboBoxAP(CPDF_Document* pDoc,
+                                    CPDF_Dictionary* pAnnotDict);
+  static FX_BOOL GenerateListBoxAP(CPDF_Document* pDoc,
+                                   CPDF_Dictionary* pAnnotDict);
+  static CFX_ByteString GenerateEditAP(IPVT_FontMap* pFontMap,
+                                       IPDF_VariableText_Iterator* pIterator,
+                                       const CFX_FloatPoint& ptOffset,
+                                       FX_BOOL bContinuous,
+                                       uint16_t SubWord = 0,
+                                       const CPVT_WordRange* pVisible = NULL);
+  static CFX_ByteString 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);
+  static CFX_ByteString GenerateColorAP(const CPVT_Color& color,
+                                        const FX_BOOL& bFillOrStroke);
+
+  static CFX_ByteString GetPDFWordString(IPVT_FontMap* pFontMap,
+                                         int32_t nFontIndex,
+                                         uint16_t Word,
+                                         uint16_t SubWord);
+  static CFX_ByteString GetWordRenderString(const CFX_ByteString& strWords);
+  static CFX_ByteString GetFontSetString(IPVT_FontMap* pFontMap,
+                                         int32_t nFontIndex,
+                                         FX_FLOAT fFontSize);
+};
+
+#endif  // CORE_FPDFDOC_CPVT_GENERATEAP_H_
diff --git a/core/fpdfdoc/cpvt_provider.h b/core/fpdfdoc/cpvt_provider.h
new file mode 100644
index 0000000..e7edd53
--- /dev/null
+++ b/core/fpdfdoc/cpvt_provider.h
@@ -0,0 +1,35 @@
+// Copyright 2016 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
+
+#ifndef CORE_FPDFDOC_CPVT_PROVIDER_H_
+#define CORE_FPDFDOC_CPVT_PROVIDER_H_
+
+#include "core/fpdfdoc/include/ipdf_variabletext_provider.h"
+#include "core/fpdfdoc/ipvt_fontmap.h"
+#include "core/fxcrt/include/fx_system.h"
+
+class CPVT_Provider : public IPDF_VariableText_Provider {
+ public:
+  CPVT_Provider(IPVT_FontMap* pFontMap);
+  ~CPVT_Provider() override;
+
+  // IPDF_VariableText_Provider
+  int32_t GetCharWidth(int32_t nFontIndex,
+                       uint16_t word,
+                       int32_t nWordStyle) override;
+  int32_t GetTypeAscent(int32_t nFontIndex) override;
+  int32_t GetTypeDescent(int32_t nFontIndex) override;
+  int32_t GetWordFontIndex(uint16_t word,
+                           int32_t charset,
+                           int32_t nFontIndex) override;
+  FX_BOOL IsLatinWord(uint16_t word) override;
+  int32_t GetDefaultFontIndex() override;
+
+ private:
+  IPVT_FontMap* m_pFontMap;
+};
+
+#endif  // CORE_FPDFDOC_CPVT_PROVIDER_H_
diff --git a/core/fpdfdoc/doc_annot.cpp b/core/fpdfdoc/doc_annot.cpp
index 1ea6c8b..2765165 100644
--- a/core/fpdfdoc/doc_annot.cpp
+++ b/core/fpdfdoc/doc_annot.cpp
@@ -12,6 +12,7 @@
 #include "core/fpdfapi/fpdf_parser/ipdf_occontext.h"
 #include "core/fpdfapi/fpdf_render/include/cpdf_rendercontext.h"
 #include "core/fpdfapi/fpdf_render/include/cpdf_renderoptions.h"
+#include "core/fpdfdoc/cpvt_generateap.h"
 #include "core/include/fpdfdoc/fpdf_doc.h"
 #include "core/include/fxge/fx_ge.h"
 
diff --git a/core/fpdfdoc/doc_ap.cpp b/core/fpdfdoc/doc_ap.cpp
index e87b21b..440979e 100644
--- a/core/fpdfdoc/doc_ap.cpp
+++ b/core/fpdfdoc/doc_ap.cpp
@@ -9,130 +9,12 @@
 #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/cpvt_provider.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();
-  uint32_t 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);
 }
@@ -186,753 +68,3 @@
   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 {
-      uint32_t 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;
-      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->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->GetDirectObjectAt(i)) {
-            CFX_WideString swItem;
-            if (pOpt->IsString())
-              swItem = pOpt->GetUnicodeText();
-            else if (CPDF_Array* pArray = pOpt->AsArray())
-              swItem = pArray->GetDirectObjectAt(1)->GetUnicodeText();
-
-            FX_BOOL bSelected = FALSE;
-            if (pSels) {
-              for (uint32_t 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();
-}
diff --git a/core/fpdfdoc/doc_formfield.cpp b/core/fpdfdoc/doc_formfield.cpp
index 4ebf2d3..0f8b3dd 100644
--- a/core/fpdfdoc/doc_formfield.cpp
+++ b/core/fpdfdoc/doc_formfield.cpp
@@ -10,6 +10,7 @@
 #include "core/fpdfapi/fpdf_parser/include/cpdf_number.h"
 #include "core/fpdfapi/fpdf_parser/include/cpdf_simple_parser.h"
 #include "core/fpdfapi/fpdf_parser/include/cpdf_string.h"
+#include "core/fpdfdoc/cpvt_generateap.h"
 #include "core/fpdfdoc/doc_utils.h"
 #include "core/include/fpdfdoc/fpdf_doc.h"
 
diff --git a/core/fpdfdoc/doc_vt.cpp b/core/fpdfdoc/doc_vt.cpp
index 028a220..5977288 100644
--- a/core/fpdfdoc/doc_vt.cpp
+++ b/core/fpdfdoc/doc_vt.cpp
@@ -6,6 +6,7 @@
 
 #include <algorithm>
 
+#include "core/fpdfdoc/include/ipdf_variabletext_provider.h"
 #include "core/fpdfdoc/pdf_vt.h"
 #include "core/include/fpdfdoc/fpdf_doc.h"
 #include "core/include/fpdfdoc/fpdf_vt.h"
diff --git a/core/fpdfdoc/include/ipdf_variabletext_provider.h b/core/fpdfdoc/include/ipdf_variabletext_provider.h
new file mode 100644
index 0000000..592c7da
--- /dev/null
+++ b/core/fpdfdoc/include/ipdf_variabletext_provider.h
@@ -0,0 +1,28 @@
+// Copyright 2016 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
+
+#ifndef CORE_FPDFDOC_INCLUDE_IPDF_VARIABLETEXT_PROVIDER_H_
+#define CORE_FPDFDOC_INCLUDE_IPDF_VARIABLETEXT_PROVIDER_H_
+
+#include "core/fxcrt/include/fx_system.h"
+
+class IPDF_VariableText_Provider {
+ public:
+  virtual ~IPDF_VariableText_Provider();
+
+  virtual int32_t GetCharWidth(int32_t nFontIndex,
+                               uint16_t word,
+                               int32_t nWordStyle) = 0;
+  virtual int32_t GetTypeAscent(int32_t nFontIndex) = 0;
+  virtual int32_t GetTypeDescent(int32_t nFontIndex) = 0;
+  virtual int32_t GetWordFontIndex(uint16_t word,
+                                   int32_t charset,
+                                   int32_t nFontIndex) = 0;
+  virtual int32_t GetDefaultFontIndex() = 0;
+  virtual FX_BOOL IsLatinWord(uint16_t word) = 0;
+};
+
+#endif  // CORE_FPDFDOC_INCLUDE_IPDF_VARIABLETEXT_PROVIDER_H_
diff --git a/core/fpdfdoc/ipdf_variabletext_provider.cpp b/core/fpdfdoc/ipdf_variabletext_provider.cpp
new file mode 100644
index 0000000..82937f7
--- /dev/null
+++ b/core/fpdfdoc/ipdf_variabletext_provider.cpp
@@ -0,0 +1,9 @@
+// Copyright 2016 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/fpdfdoc/include/ipdf_variabletext_provider.h"
+
+IPDF_VariableText_Provider::~IPDF_VariableText_Provider() {}
diff --git a/core/fpdfdoc/ipvt_fontmap.h b/core/fpdfdoc/ipvt_fontmap.h
new file mode 100644
index 0000000..eec414d
--- /dev/null
+++ b/core/fpdfdoc/ipvt_fontmap.h
@@ -0,0 +1,24 @@
+// Copyright 2016 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
+
+#ifndef CORE_FPDFDOC_IPVT_FONTMAP_H_
+#define CORE_FPDFDOC_IPVT_FONTMAP_H_
+
+#include <stdint.h>
+
+#include "core/fxcrt/include/fx_string.h"
+
+class CPDF_Font;
+
+class IPVT_FontMap {
+ public:
+  virtual ~IPVT_FontMap() {}
+
+  virtual CPDF_Font* GetPDFFont(int32_t nFontIndex) = 0;
+  virtual CFX_ByteString GetPDFFontAlias(int32_t nFontIndex) = 0;
+};
+
+#endif  // CORE_FPDFDOC_IPVT_FONTMAP_H_
diff --git a/core/include/fpdfdoc/fpdf_ap.h b/core/include/fpdfdoc/fpdf_ap.h
deleted file mode 100644
index b468d14..0000000
--- a/core/include/fpdfdoc/fpdf_ap.h
+++ /dev/null
@@ -1,100 +0,0 @@
-// 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
-
-#ifndef CORE_INCLUDE_FPDFDOC_FPDF_AP_H_
-#define CORE_INCLUDE_FPDFDOC_FPDF_AP_H_
-
-#include "core/include/fpdfdoc/fpdf_vt.h"
-
-class IPVT_FontMap {
- public:
-  virtual ~IPVT_FontMap() {}
-  virtual CPDF_Font* GetPDFFont(int32_t nFontIndex) = 0;
-  virtual CFX_ByteString GetPDFFontAlias(int32_t nFontIndex) = 0;
-};
-
-struct CPVT_Dash {
-  CPVT_Dash(int32_t dash, int32_t gap, int32_t phase)
-      : nDash(dash), nGap(gap), nPhase(phase) {}
-
-  int32_t nDash;
-  int32_t nGap;
-  int32_t nPhase;
-};
-
-struct CPVT_Color {
-  enum Type { kTransparent = 0, kGray, kRGB, kCMYK };
-
-  CPVT_Color(Type type = kTransparent,
-             FX_FLOAT color1 = 0.0f,
-             FX_FLOAT color2 = 0.0f,
-             FX_FLOAT color3 = 0.0f,
-             FX_FLOAT color4 = 0.0f)
-      : nColorType(type),
-        fColor1(color1),
-        fColor2(color2),
-        fColor3(color3),
-        fColor4(color4) {}
-
-  Type nColorType;
-  FX_FLOAT fColor1;
-  FX_FLOAT fColor2;
-  FX_FLOAT fColor3;
-  FX_FLOAT fColor4;
-};
-
-class CPVT_Provider : public IPDF_VariableText_Provider {
- public:
-  CPVT_Provider(IPVT_FontMap* pFontMap);
-  ~CPVT_Provider() override;
-
-  // IPDF_VariableText_Provider
-  int32_t GetCharWidth(int32_t nFontIndex,
-                       uint16_t word,
-                       int32_t nWordStyle) override;
-  int32_t GetTypeAscent(int32_t nFontIndex) override;
-  int32_t GetTypeDescent(int32_t nFontIndex) override;
-  int32_t GetWordFontIndex(uint16_t word,
-                           int32_t charset,
-                           int32_t nFontIndex) override;
-  FX_BOOL IsLatinWord(uint16_t word) override;
-  int32_t GetDefaultFontIndex() override;
-
- private:
-  IPVT_FontMap* m_pFontMap;
-};
-
-class CPVT_GenerateAP {
- public:
-  static FX_BOOL GenerateTextFieldAP(CPDF_Document* pDoc,
-                                     CPDF_Dictionary* pAnnotDict);
-
-  static FX_BOOL GenerateComboBoxAP(CPDF_Document* pDoc,
-                                    CPDF_Dictionary* pAnnotDict);
-
-  static FX_BOOL GenerateListBoxAP(CPDF_Document* pDoc,
-                                   CPDF_Dictionary* pAnnotDict);
-
-  static CFX_ByteString GenerateEditAP(IPVT_FontMap* pFontMap,
-                                       IPDF_VariableText_Iterator* pIterator,
-                                       const CFX_FloatPoint& ptOffset,
-                                       FX_BOOL bContinuous,
-                                       uint16_t SubWord = 0,
-                                       const CPVT_WordRange* pVisible = NULL);
-
-  static CFX_ByteString 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);
-
-  static CFX_ByteString GenerateColorAP(const CPVT_Color& color,
-                                        const FX_BOOL& bFillOrStroke);
-};
-
-#endif  // CORE_INCLUDE_FPDFDOC_FPDF_AP_H_
diff --git a/core/include/fpdfdoc/fpdf_doc.h b/core/include/fpdfdoc/fpdf_doc.h
index 5939966..f7788b7 100644
--- a/core/include/fpdfdoc/fpdf_doc.h
+++ b/core/include/fpdfdoc/fpdf_doc.h
@@ -947,8 +947,6 @@
   virtual void AfterFormImportData(CPDF_InterForm* pForm) {}
 };
 
-FX_BOOL FPDF_GenerateAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict);
-
 class CPDF_PageLabel {
  public:
   explicit CPDF_PageLabel(CPDF_Document* pDocument) : m_pDocument(pDocument) {}
diff --git a/core/include/fpdfdoc/fpdf_vt.h b/core/include/fpdfdoc/fpdf_vt.h
index d79cad4..1e0d351 100644
--- a/core/include/fpdfdoc/fpdf_vt.h
+++ b/core/include/fpdfdoc/fpdf_vt.h
@@ -261,26 +261,7 @@
 
   CPVT_WordProps WordProps;
 };
-class IPDF_VariableText_Provider {
- public:
-  virtual ~IPDF_VariableText_Provider() {}
 
-  virtual int32_t GetCharWidth(int32_t nFontIndex,
-                               uint16_t word,
-                               int32_t nWordStyle) = 0;
-
-  virtual int32_t GetTypeAscent(int32_t nFontIndex) = 0;
-
-  virtual int32_t GetTypeDescent(int32_t nFontIndex) = 0;
-
-  virtual int32_t GetWordFontIndex(uint16_t word,
-                                   int32_t charset,
-                                   int32_t nFontIndex) = 0;
-
-  virtual FX_BOOL IsLatinWord(uint16_t word) = 0;
-
-  virtual int32_t GetDefaultFontIndex() = 0;
-};
 class IPDF_VariableText_Iterator {
  public:
   virtual ~IPDF_VariableText_Iterator() {}
diff --git a/fpdfsdk/include/fxedit/DEPS b/fpdfsdk/include/fxedit/DEPS
new file mode 100644
index 0000000..db9a09c
--- /dev/null
+++ b/fpdfsdk/include/fxedit/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  '+core/fpdfdoc/include',
+]
diff --git a/fpdfsdk/include/fxedit/fxet_edit.h b/fpdfsdk/include/fxedit/fxet_edit.h
index d3e354d..6f174a8 100644
--- a/fpdfsdk/include/fxedit/fxet_edit.h
+++ b/fpdfsdk/include/fxedit/fxet_edit.h
@@ -7,6 +7,7 @@
 #ifndef FPDFSDK_INCLUDE_FXEDIT_FXET_EDIT_H_
 #define FPDFSDK_INCLUDE_FXEDIT_FXET_EDIT_H_
 
+#include "core/fpdfdoc/include/ipdf_variabletext_provider.h"
 #include "core/include/fpdfdoc/fpdf_vt.h"
 #include "fpdfsdk/include/fxedit/fx_edit.h"
 
diff --git a/pdfium.gyp b/pdfium.gyp
index ed6003e..7b53772 100644
--- a/pdfium.gyp
+++ b/pdfium.gyp
@@ -219,10 +219,17 @@
       'target_name': 'fpdfdoc',
       'type': 'static_library',
       'sources': [
-        'core/include/fpdfdoc/fpdf_ap.h',
         'core/include/fpdfdoc/fpdf_doc.h',
         'core/include/fpdfdoc/fpdf_tagged.h',
         'core/include/fpdfdoc/fpdf_vt.h',
+        'core/fpdfdoc/cpvt_color.cpp',
+        'core/fpdfdoc/cpvt_color.h',
+        'core/fpdfdoc/cpvt_dash.h',
+        'core/fpdfdoc/cpvt_fontmap.cpp',
+        'core/fpdfdoc/cpvt_fontmap.h',
+        'core/fpdfdoc/cpvt_generateap.cpp',
+        'core/fpdfdoc/cpvt_generateap.h',
+        'core/fpdfdoc/cpvt_provider.h',
         'core/fpdfdoc/doc_action.cpp',
         'core/fpdfdoc/doc_annot.cpp',
         'core/fpdfdoc/doc_ap.cpp',
@@ -240,6 +247,9 @@
         'core/fpdfdoc/doc_viewerPreferences.cpp',
         'core/fpdfdoc/doc_vt.cpp',
         'core/fpdfdoc/doc_vtmodule.cpp',
+        'core/fpdfdoc/include/ipdf_variabletext_provider.h',
+        'core/fpdfdoc/ipdf_variabletext_provider.cpp',
+        'core/fpdfdoc/ipvt_fontmap.h',
         'core/fpdfdoc/pdf_vt.h',
         'core/fpdfdoc/tagged_int.h',
       ],