Split combo/listbox code out of CPDF_GenerateAP::GenerateFormAP()

Move code into GenerateComboBoxAP() and GenerateListBoxAP() helpers.

Change-Id: Ib716083cbb76ec445ef275574fbeaa2f29df95ee
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/126651
Commit-Queue: Lei Zhang <thestig@chromium.org>
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Reviewed-by: Thomas Sepez <tsepez@google.com>
diff --git a/core/fpdfdoc/cpdf_generateap.cpp b/core/fpdfdoc/cpdf_generateap.cpp
index 711ea5e..beb05f8 100644
--- a/core/fpdfdoc/cpdf_generateap.cpp
+++ b/core/fpdfdoc/cpdf_generateap.cpp
@@ -689,6 +689,159 @@
   ap_dict->SetNewFor<CPDF_Reference>("N", doc, normal_stream->GetObjNum());
 }
 
+ByteString GenerateComboBoxAP(const CPDF_Dictionary* annot_dict,
+                              const CFX_FloatRect& body_rect,
+                              const CFX_Color& text_color,
+                              float font_size,
+                              CPVT_VariableText::Provider& provider) {
+  fxcrt::ostringstream body_stream;
+
+  RetainPtr<const CPDF_Object> v_field =
+      CPDF_FormField::GetFieldAttrForDict(annot_dict, pdfium::form_fields::kV);
+  WideString value = v_field ? v_field->GetUnicodeText() : WideString();
+  CPVT_VariableText vt(&provider);
+  CFX_FloatRect button_rect = body_rect;
+  button_rect.left = button_rect.right - 13;
+  button_rect.Normalize();
+  CFX_FloatRect edit_rect = body_rect;
+  edit_rect.right = button_rect.left;
+  edit_rect.Normalize();
+  vt.SetPlateRect(edit_rect);
+  if (FXSYS_IsFloatZero(font_size)) {
+    vt.SetAutoFontSize(true);
+  } else {
+    vt.SetFontSize(font_size);
+  }
+
+  vt.Initialize();
+  vt.SetText(value);
+  vt.RearrangeAll();
+  CFX_FloatRect content_rect = vt.GetContentRect();
+  CFX_PointF offset =
+      CFX_PointF(0.0f, (content_rect.Height() - edit_rect.Height()) / 2.0f);
+  ByteString edit =
+      GenerateEditAP(provider.GetFontMap(), vt.GetIterator(), offset, true, 0);
+  if (edit.GetLength() > 0) {
+    body_stream << "/Tx BMC\nq\n";
+    WriteRect(body_stream, edit_rect) << " re\nW\nn\n";
+    body_stream << "BT\n"
+                << GenerateColorAP(text_color, PaintOperation::kFill) << edit
+                << "ET\n"
+                << "Q\nEMC\n";
+  }
+  ByteString button =
+      GenerateColorAP(CFX_Color(CFX_Color::Type::kRGB, 220.0f / 255.0f,
+                                220.0f / 255.0f, 220.0f / 255.0f),
+                      PaintOperation::kFill);
+  if (button.GetLength() > 0 && !button_rect.IsEmpty()) {
+    body_stream << "q\n" << button;
+    WriteRect(body_stream, button_rect) << " re f\n";
+    body_stream << "Q\n";
+    static const BorderStyleInfo kButtonBorderStyleInfo{
+        .width = 2, .style = BorderStyle::kBeveled, .dash_pattern{3, 0, 0}};
+    ByteString button_border =
+        GenerateBorderAP(button_rect, kButtonBorderStyleInfo,
+                         CFX_Color(CFX_Color::Type::kGray, 0));
+    if (button_border.GetLength() > 0) {
+      body_stream << "q\n" << button_border << "Q\n";
+    }
+
+    CFX_PointF center((button_rect.left + button_rect.right) / 2,
+                      (button_rect.top + button_rect.bottom) / 2);
+    if (FXSYS_IsFloatBigger(button_rect.Width(), 6) &&
+        FXSYS_IsFloatBigger(button_rect.Height(), 6)) {
+      body_stream << "q\n0 g\n";
+      WritePoint(body_stream, {center.x - 3, center.y + 1.5f}) << " m\n";
+      WritePoint(body_stream, {center.x + 3, center.y + 1.5f}) << " l\n";
+      WritePoint(body_stream, {center.x, center.y - 1.5f}) << " l\n";
+      WritePoint(body_stream, {center.x - 3, center.y + 1.5f}) << " l f\n";
+      body_stream << button << "Q\n";
+    }
+  }
+  return ByteString(body_stream);
+}
+
+ByteString GenerateListBoxAP(const CPDF_Dictionary* annot_dict,
+                             const CFX_FloatRect& body_rect,
+                             const CFX_Color& text_color,
+                             float font_size,
+                             CPVT_VariableText::Provider& provider) {
+  RetainPtr<const CPDF_Array> opts =
+      ToArray(CPDF_FormField::GetFieldAttrForDict(annot_dict, "Opt"));
+  if (!opts) {
+    return ByteString();
+  }
+
+  RetainPtr<const CPDF_Array> selections =
+      ToArray(CPDF_FormField::GetFieldAttrForDict(annot_dict, "I"));
+  RetainPtr<const CPDF_Object> top_index =
+      CPDF_FormField::GetFieldAttrForDict(annot_dict, "TI");
+  const int32_t top = top_index ? top_index->GetInteger() : 0;
+  fxcrt::ostringstream body_stream;
+
+  float fy = body_rect.top;
+  for (size_t i = top, sz = opts->size(); i < sz; i++) {
+    if (FXSYS_IsFloatSmaller(fy, body_rect.bottom)) {
+      break;
+    }
+
+    if (RetainPtr<const CPDF_Object> opt = opts->GetDirectObjectAt(i)) {
+      WideString item;
+      if (opt->IsString()) {
+        item = opt->GetUnicodeText();
+      } else if (const CPDF_Array* opt_array = opt->AsArray()) {
+        RetainPtr<const CPDF_Object> opt_item = opt_array->GetDirectObjectAt(1);
+        if (opt_item) {
+          item = opt_item->GetUnicodeText();
+        }
+      }
+      bool is_selected = false;
+      if (selections) {
+        for (size_t s = 0, ssz = selections->size(); s < ssz; s++) {
+          int value = selections->GetIntegerAt(s);
+          if (value >= 0 && i == static_cast<size_t>(value)) {
+            is_selected = true;
+            break;
+          }
+        }
+      }
+      CPVT_VariableText vt(&provider);
+      vt.SetPlateRect(
+          CFX_FloatRect(body_rect.left, 0.0f, body_rect.right, 0.0f));
+      vt.SetFontSize(FXSYS_IsFloatZero(font_size) ? 12.0f : font_size);
+      vt.Initialize();
+      vt.SetText(item);
+      vt.RearrangeAll();
+
+      const float item_height = vt.GetContentRect().Height();
+      if (is_selected) {
+        CFX_FloatRect item_rect = CFX_FloatRect(
+            body_rect.left, fy - item_height, body_rect.right, fy);
+        body_stream << "q\n"
+                    << GenerateColorAP(
+                           CFX_Color(CFX_Color::Type::kRGB, 0, 51.0f / 255.0f,
+                                     113.0f / 255.0f),
+                           PaintOperation::kFill);
+        WriteRect(body_stream, item_rect) << " re f\nQ\n";
+        body_stream << "BT\n"
+                    << GenerateColorAP(CFX_Color(CFX_Color::Type::kGray, 1),
+                                       PaintOperation::kFill)
+                    << GenerateEditAP(provider.GetFontMap(), vt.GetIterator(),
+                                      CFX_PointF(0.0f, fy), true, 0)
+                    << "ET\n";
+      } else {
+        body_stream << "BT\n"
+                    << GenerateColorAP(text_color, PaintOperation::kFill)
+                    << GenerateEditAP(provider.GetFontMap(), vt.GetIterator(),
+                                      CFX_PointF(0.0f, fy), true, 0)
+                    << "ET\n";
+      }
+      fy -= item_height;
+    }
+  }
+  return ByteString(body_stream);
+}
+
 bool GenerateCircleAP(CPDF_Document* doc, CPDF_Dictionary* annot_dict) {
   fxcrt::ostringstream app_stream;
   app_stream << "/" << kGSDictName << " gs ";
@@ -1164,7 +1317,7 @@
 
   CPVT_FontMap map(doc, std::move(resources_dict), std::move(default_font),
                    font_name);
-  CPVT_VariableText::Provider prd(&map);
+  CPVT_VariableText::Provider provider(&map);
   switch (type) {
     case CPDF_GenerateAP::kTextField: {
       RetainPtr<const CPDF_Object> v_field =
@@ -1181,7 +1334,7 @@
       RetainPtr<const CPDF_Object> max_len_field =
           CPDF_FormField::GetFieldAttrForDict(annot_dict, "MaxLen");
       const uint32_t max_len = max_len_field ? max_len_field->GetInteger() : 0;
-      CPVT_VariableText vt(&prd);
+      CPVT_VariableText vt(&provider);
       vt.SetPlateRect(body_rect);
       vt.SetAlignment(align);
       if (FXSYS_IsFloatZero(font_size)) {
@@ -1232,147 +1385,16 @@
       break;
     }
     case CPDF_GenerateAP::kComboBox: {
-      RetainPtr<const CPDF_Object> v_field =
-          CPDF_FormField::GetFieldAttrForDict(annot_dict,
-                                              pdfium::form_fields::kV);
-      WideString value = v_field ? v_field->GetUnicodeText() : WideString();
-      CPVT_VariableText vt(&prd);
-      CFX_FloatRect button_rect = body_rect;
-      button_rect.left = button_rect.right - 13;
-      button_rect.Normalize();
-      CFX_FloatRect edit_rect = body_rect;
-      edit_rect.right = button_rect.left;
-      edit_rect.Normalize();
-      vt.SetPlateRect(edit_rect);
-      if (FXSYS_IsFloatZero(font_size)) {
-        vt.SetAutoFontSize(true);
-      } else {
-        vt.SetFontSize(font_size);
-      }
-
-      vt.Initialize();
-      vt.SetText(value);
-      vt.RearrangeAll();
-      CFX_FloatRect content_rect = vt.GetContentRect();
-      CFX_PointF offset =
-          CFX_PointF(0.0f, (content_rect.Height() - edit_rect.Height()) / 2.0f);
-      ByteString edit = GenerateEditAP(&map, vt.GetIterator(), offset, true, 0);
-      if (edit.GetLength() > 0) {
-        app_stream << "/Tx BMC\nq\n";
-        WriteRect(app_stream, edit_rect) << " re\nW\nn\n";
-        app_stream << "BT\n"
-                   << GenerateColorAP(text_color, PaintOperation::kFill) << edit
-                   << "ET\n"
-                   << "Q\nEMC\n";
-      }
-      ByteString button =
-          GenerateColorAP(CFX_Color(CFX_Color::Type::kRGB, 220.0f / 255.0f,
-                                    220.0f / 255.0f, 220.0f / 255.0f),
-                          PaintOperation::kFill);
-      if (button.GetLength() > 0 && !button_rect.IsEmpty()) {
-        app_stream << "q\n" << button;
-        WriteRect(app_stream, button_rect) << " re f\n";
-        app_stream << "Q\n";
-        static const BorderStyleInfo kButtonBorderStyleInfo{
-            .width = 2, .style = BorderStyle::kBeveled, .dash_pattern{3, 0, 0}};
-        ByteString button_border =
-            GenerateBorderAP(button_rect, kButtonBorderStyleInfo,
-                             CFX_Color(CFX_Color::Type::kGray, 0));
-        if (button_border.GetLength() > 0) {
-          app_stream << "q\n" << button_border << "Q\n";
-        }
-
-        CFX_PointF center((button_rect.left + button_rect.right) / 2,
-                          (button_rect.top + button_rect.bottom) / 2);
-        if (FXSYS_IsFloatBigger(button_rect.Width(), 6) &&
-            FXSYS_IsFloatBigger(button_rect.Height(), 6)) {
-          app_stream << "q\n0 g\n";
-          WritePoint(app_stream, {center.x - 3, center.y + 1.5f}) << " m\n";
-          WritePoint(app_stream, {center.x + 3, center.y + 1.5f}) << " l\n";
-          WritePoint(app_stream, {center.x, center.y - 1.5f}) << " l\n";
-          WritePoint(app_stream, {center.x - 3, center.y + 1.5f}) << " l f\n";
-          app_stream << button << "Q\n";
-        }
-      }
+      app_stream << GenerateComboBoxAP(annot_dict, body_rect, text_color,
+                                       font_size, provider);
       break;
     }
     case CPDF_GenerateAP::kListBox: {
-      RetainPtr<const CPDF_Array> opts =
-          ToArray(CPDF_FormField::GetFieldAttrForDict(annot_dict, "Opt"));
-      RetainPtr<const CPDF_Array> selections =
-          ToArray(CPDF_FormField::GetFieldAttrForDict(annot_dict, "I"));
-      RetainPtr<const CPDF_Object> top_index =
-          CPDF_FormField::GetFieldAttrForDict(annot_dict, "TI");
-      const int32_t top = top_index ? top_index->GetInteger() : 0;
-      fxcrt::ostringstream body_stream;
-      if (opts) {
-        float fy = body_rect.top;
-        for (size_t i = top, sz = opts->size(); i < sz; i++) {
-          if (FXSYS_IsFloatSmaller(fy, body_rect.bottom)) {
-            break;
-          }
-
-          if (RetainPtr<const CPDF_Object> opt = opts->GetDirectObjectAt(i)) {
-            WideString item;
-            if (opt->IsString()) {
-              item = opt->GetUnicodeText();
-            } else if (const CPDF_Array* opt_array = opt->AsArray()) {
-              RetainPtr<const CPDF_Object> opt_item =
-                  opt_array->GetDirectObjectAt(1);
-              if (opt_item) {
-                item = opt_item->GetUnicodeText();
-              }
-            }
-            bool is_selected = false;
-            if (selections) {
-              for (size_t s = 0, ssz = selections->size(); s < ssz; s++) {
-                int value = selections->GetIntegerAt(s);
-                if (value >= 0 && i == static_cast<size_t>(value)) {
-                  is_selected = true;
-                  break;
-                }
-              }
-            }
-            CPVT_VariableText vt(&prd);
-            vt.SetPlateRect(
-                CFX_FloatRect(body_rect.left, 0.0f, body_rect.right, 0.0f));
-            vt.SetFontSize(FXSYS_IsFloatZero(font_size) ? 12.0f : font_size);
-            vt.Initialize();
-            vt.SetText(item);
-            vt.RearrangeAll();
-
-            const float item_height = vt.GetContentRect().Height();
-            if (is_selected) {
-              CFX_FloatRect item_rect = CFX_FloatRect(
-                  body_rect.left, fy - item_height, body_rect.right, fy);
-              body_stream << "q\n"
-                          << GenerateColorAP(
-                                 CFX_Color(CFX_Color::Type::kRGB, 0,
-                                           51.0f / 255.0f, 113.0f / 255.0f),
-                                 PaintOperation::kFill);
-              WriteRect(body_stream, item_rect) << " re f\nQ\n";
-              body_stream << "BT\n"
-                          << GenerateColorAP(
-                                 CFX_Color(CFX_Color::Type::kGray, 1),
-                                 PaintOperation::kFill)
-                          << GenerateEditAP(&map, vt.GetIterator(),
-                                            CFX_PointF(0.0f, fy), true, 0)
-                          << "ET\n";
-            } else {
-              body_stream << "BT\n"
-                          << GenerateColorAP(text_color, PaintOperation::kFill)
-                          << GenerateEditAP(&map, vt.GetIterator(),
-                                            CFX_PointF(0.0f, fy), true, 0)
-                          << "ET\n";
-            }
-            fy -= item_height;
-          }
-        }
-      }
-      if (body_stream.tellp() > 0) {
+      const ByteString body = GenerateListBoxAP(
+          annot_dict, body_rect, text_color, font_size, provider);
+      if (body.GetLength() > 0) {
         app_stream << "/Tx BMC\nq\n";
-        WriteRect(app_stream, body_rect) << " re\nW\nn\n"
-                                         << body_stream.str() << "Q\nEMC\n";
+        WriteRect(app_stream, body_rect) << " re\nW\nn\n" << body << "Q\nEMC\n";
       }
       break;
     }