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; }