0

Add button structs for PDF accessibility

This change adds struct PP_PrivateAccessibilityButtonFieldInfo to
PP_PrivateAccessibilityFormFieldInfo to transfer accessibility related
PDF button data (radio button, checkbox and push button) from the plugin
process to the mimehandler process. Made the same changes to the C++
versions of these structs and added the appropriate conversion code.

Bug: 1030242
Change-Id: I33eaab3c6471e017799c54ad8d9c98c43e1baeca
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2217716
Commit-Queue: Mansi Awasthi <maawas@microsoft.com>
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
Reviewed-by: Ankit Kumar 🌪️ <ankk@microsoft.com>
Cr-Commit-Position: refs/heads/master@{#775964}
This commit is contained in:
Mansi Awasthi
2020-06-08 08:34:54 +00:00
committed by Commit Bot
parent 1f5eb7a46b
commit 0a648583ff
9 changed files with 324 additions and 0 deletions

@ -410,6 +410,29 @@ bool PdfAccessibilityTree::IsDataFromPluginValid(
return false;
}
const std::vector<ppapi::PdfAccessibilityButtonInfo>& buttons =
page_objects.form_fields.buttons;
if (!std::is_sorted(
buttons.begin(), buttons.end(),
CompareTextRuns<ppapi::PdfAccessibilityButtonInfo>)) {
return false;
}
for (const ppapi::PdfAccessibilityButtonInfo& button :
buttons) {
// Text run index of an |button| works on the same logic as the text run
// index of a |link| as mentioned above.
if (button.text_run_index > text_runs.size())
return false;
// For radio button or checkbox, value of |button.control_index| should
// always be less than |button.control_count|.
if ((button.type == PP_PrivateButtonType::PP_PRIVATEBUTTON_CHECKBOX ||
button.type == PP_PrivateButtonType::PP_PRIVATEBUTTON_RADIOBUTTON) &&
(button.control_index >= button.control_count)) {
return false;
}
}
return true;
}

@ -300,4 +300,122 @@ TEST(PdfAccessibilityTreeUnitTest, OutOfBoundChoiceField) {
page_objects));
}
TEST(PdfAccessibilityTreeUnitTest, UnsortedButtonVector) {
std::vector<ppapi::PdfAccessibilityTextRunInfo> text_runs;
text_runs.emplace_back(kFirstTextRun);
text_runs.emplace_back(kSecondTextRun);
std::vector<PP_PrivateAccessibilityCharInfo> chars(
std::begin(kDummyCharsData), std::end(kDummyCharsData));
ppapi::PdfAccessibilityPageObjects page_objects;
{
// Add first button in the vector.
ppapi::PdfAccessibilityButtonInfo button;
button.text_run_index = 2;
page_objects.form_fields.buttons.push_back(std::move(button));
}
{
// Add second button in the vector.
ppapi::PdfAccessibilityButtonInfo button;
button.text_run_index = 0;
page_objects.form_fields.buttons.push_back(std::move(button));
}
EXPECT_FALSE(PdfAccessibilityTree::IsDataFromPluginValid(text_runs, chars,
page_objects));
}
TEST(PdfAccessibilityTreeUnitTest, OutOfBoundButton) {
std::vector<ppapi::PdfAccessibilityTextRunInfo> text_runs;
text_runs.emplace_back(kFirstTextRun);
text_runs.emplace_back(kSecondTextRun);
std::vector<PP_PrivateAccessibilityCharInfo> chars(
std::begin(kDummyCharsData), std::end(kDummyCharsData));
ppapi::PdfAccessibilityPageObjects page_objects;
{
ppapi::PdfAccessibilityButtonInfo button;
button.text_run_index = 3;
page_objects.form_fields.buttons.push_back(std::move(button));
}
EXPECT_FALSE(PdfAccessibilityTree::IsDataFromPluginValid(text_runs, chars,
page_objects));
}
TEST(PdfAccessibilityTreeUnitTest, OutOfBoundRadioButton) {
std::vector<ppapi::PdfAccessibilityTextRunInfo> text_runs;
text_runs.emplace_back(kFirstTextRun);
text_runs.emplace_back(kSecondTextRun);
std::vector<PP_PrivateAccessibilityCharInfo> chars(
std::begin(kDummyCharsData), std::end(kDummyCharsData));
ppapi::PdfAccessibilityPageObjects page_objects;
{
ppapi::PdfAccessibilityButtonInfo button;
button.type = PP_PrivateButtonType::PP_PRIVATEBUTTON_RADIOBUTTON;
button.text_run_index = 0;
button.control_index = 1;
button.control_count = 2;
page_objects.form_fields.buttons.push_back(std::move(button));
}
EXPECT_TRUE(PdfAccessibilityTree::IsDataFromPluginValid(text_runs, chars,
page_objects));
{
ppapi::PdfAccessibilityButtonInfo button;
button.type = PP_PrivateButtonType::PP_PRIVATEBUTTON_RADIOBUTTON;
button.text_run_index = 0;
button.control_index = 3;
button.control_count = 2;
page_objects.form_fields.buttons.push_back(std::move(button));
}
EXPECT_FALSE(PdfAccessibilityTree::IsDataFromPluginValid(text_runs, chars,
page_objects));
}
TEST(PdfAccessibilityTreeUnitTest, OutOfBoundCheckBox) {
std::vector<ppapi::PdfAccessibilityTextRunInfo> text_runs;
text_runs.emplace_back(kFirstTextRun);
text_runs.emplace_back(kSecondTextRun);
std::vector<PP_PrivateAccessibilityCharInfo> chars(
std::begin(kDummyCharsData), std::end(kDummyCharsData));
ppapi::PdfAccessibilityPageObjects page_objects;
{
ppapi::PdfAccessibilityButtonInfo button;
button.type = PP_PrivateButtonType::PP_PRIVATEBUTTON_CHECKBOX;
button.text_run_index = 0;
button.control_index = 1;
button.control_count = 2;
page_objects.form_fields.buttons.push_back(std::move(button));
}
EXPECT_TRUE(PdfAccessibilityTree::IsDataFromPluginValid(text_runs, chars,
page_objects));
{
ppapi::PdfAccessibilityButtonInfo button;
button.type = PP_PrivateButtonType::PP_PRIVATEBUTTON_CHECKBOX;
button.text_run_index = 0;
button.control_index = 3;
button.control_count = 2;
page_objects.form_fields.buttons.push_back(std::move(button));
}
EXPECT_FALSE(PdfAccessibilityTree::IsDataFromPluginValid(text_runs, chars,
page_objects));
}
} // namespace pdf

@ -240,6 +240,10 @@ STATIC_ASSERT_ENUM(chrome_pdf::PDFEngine::FormType::kXFAForeground,
FORMTYPE_XFA_FOREGROUND);
STATIC_ASSERT_ENUM(chrome_pdf::PDFEngine::FormType::kCount, FORMTYPE_COUNT);
STATIC_ASSERT_ENUM(PP_PRIVATEBUTTON_PUSHBUTTON, FPDF_FORMFIELD_PUSHBUTTON);
STATIC_ASSERT_ENUM(PP_PRIVATEBUTTON_CHECKBOX, FPDF_FORMFIELD_CHECKBOX);
STATIC_ASSERT_ENUM(PP_PRIVATEBUTTON_RADIOBUTTON, FPDF_FORMFIELD_RADIOBUTTON);
#if defined(OS_WIN)
STATIC_ASSERT_ENUM(chrome_pdf::kEmf, FPDF_PRINTMODE_EMF);
STATIC_ASSERT_ENUM(chrome_pdf::kTextOnly, FPDF_PRINTMODE_TEXTONLY);

@ -124,6 +124,9 @@ struct PP_PrivateAccessibilityLinkInfo {
uint32_t url_length;
// Index of the link in the page. This will be used to identify the link on
// which action has to be performed in the page.
// |index_in_page| is populated and used in plugin process to handle
// accessiility actions from mimehandler process. It's value should be
// validated in plugin before usage.
uint32_t index_in_page;
// Link can either be part of the page text or not. If the link is part of the
// page text, then |text_run_index| denotes the text run which contains the
@ -167,6 +170,9 @@ struct PP_PrivateAccessibilityHighlightInfo {
uint32_t note_text_length;
// Index of the highlight in the page annotation list. Used to identify the
// annotation on which action needs to be performed.
// |index_in_page| is populated and used in plugin process to handle
// accessiility actions from mimehandler process. It's value should be
// validated in plugin before usage.
uint32_t index_in_page;
// Highlights are annotations over existing page text. |text_run_index|
// denotes the index of the text run where the highlight starts and
@ -202,6 +208,9 @@ struct PP_PrivateAccessibilityTextFieldInfo {
bool is_password;
// Index of the text field in the collection of text fields in the page. Used
// to identify the annotation on which action needs to be performed.
// |index_in_page| is populated and used in plugin process to handle
// accessiility actions from mimehandler process. It's value should be
// validated in plugin before usage.
uint32_t index_in_page;
// We anchor the text field to a text run index, this denotes the text run
// before which the text field should be inserted in the accessibility tree.
@ -252,6 +261,9 @@ struct PP_PrivateAccessibilityChoiceFieldInfo {
bool has_editable_text_box;
// Index of the choice field in the collection of choice fields in the page.
// Used to identify the annotation on which action needs to be performed.
// |index_in_page| is populated and used in plugin process to handle
// accessiility actions from mimehandler process. It's value should be
// validated in plugin before usage.
uint32_t index_in_page;
// We anchor the choice field to a text run index, this denotes the text run
// before which the choice field should be inserted in the accessibility tree.
@ -260,6 +272,56 @@ struct PP_PrivateAccessibilityChoiceFieldInfo {
struct PP_FloatRect bounds;
};
typedef enum {
PP_PRIVATEBUTTON_PUSHBUTTON = 1,
PP_PRIVATEBUTTON_FIRST = PP_PRIVATEBUTTON_PUSHBUTTON,
PP_PRIVATEBUTTON_CHECKBOX = 2,
PP_PRIVATEBUTTON_RADIOBUTTON = 3,
PP_PRIVATEBUTTON_LAST = PP_PRIVATEBUTTON_RADIOBUTTON
} PP_PrivateButtonType;
// This holds button form field information provided by the PDF and will be
// used in accessibility to expose it. Needs to stay in sync with C++ versions
// (PdfAccessibilityButtonInfo and PrivateAccessibilityButtonInfo).
// This struct contains index states that should be validated using
// PdfAccessibilityTree::IsDataFromPluginValid() before usage.
struct PP_PrivateAccessibilityButtonInfo {
// Represents the name property of button, if present.
const char* name;
uint32_t name_length;
// Represents the value property of button, if present.
const char* value;
uint32_t value_length;
// Represents the button type.
PP_PrivateButtonType type;
// Represents if the button is non-editable.
bool is_read_only;
// Represents if the radio button or check box is checked or not.
bool is_checked;
// Represents count of controls in the control group. A group of interactive
// form annotations is collectively called a form control group. Here, an
// interactive form annotation, should be either a radio button or a checkbox.
// Value of |control_count| is >= 1.
uint32_t control_count;
// Represents index of the control in the control group. A group of
// interactive form annotations is collectively called a form control group.
// Here, an interactive form annotation, should be either a radio button or a
// checkbox. Value of |control_index| should always be less than
// |control_count|.
uint32_t control_index;
// Index of the button in the collection of buttons in the page. Used
// to identify the annotation on which action needs to be performed.
// |index_in_page| is populated and used in plugin process to handle
// accessiility actions from mimehandler process. It's value should be
// validated in plugin before usage.
uint32_t index_in_page;
// We anchor the button to a text run index, this denotes the text run
// before which the button should be inserted in the accessibility tree.
uint32_t text_run_index;
// Bounding box of the button.
struct PP_FloatRect bounds;
};
// This holds form fields within a PDF page. Needs to stay in sync with C++
// versions (PdfAccessibilityFormFieldInfo and
// PrivateAccessibilityFormFieldInfo).
@ -268,6 +330,8 @@ struct PP_PrivateAccessibilityFormFieldInfo {
uint32_t text_field_count;
struct PP_PrivateAccessibilityChoiceFieldInfo* choice_fields;
uint32_t choice_field_count;
struct PP_PrivateAccessibilityButtonInfo* buttons;
uint32_t button_count;
};
// This holds different PDF page objects - links, images, highlights and

@ -113,6 +113,23 @@ void ConvertPrivateAccessibilityChoiceFieldInfo(
info->bounds = choice_field.bounds;
}
void ConvertPrivateAccessibilityButtonInfo(
const PDF::PrivateAccessibilityButtonInfo& button,
PP_PrivateAccessibilityButtonInfo* info) {
info->name = button.name.c_str();
info->name_length = button.name.size();
info->value = button.value.c_str();
info->value_length = button.value.size();
info->type = button.type;
info->is_read_only = button.is_read_only;
info->is_checked = button.is_checked;
info->control_count = button.control_count;
info->control_index = button.control_index;
info->index_in_page = button.index_in_page;
info->text_run_index = button.text_run_index;
info->bounds = button.bounds;
}
} // namespace
// static
@ -344,6 +361,12 @@ void PDF::SetAccessibilityPageInfo(
&choice_field_option_info[i]);
}
const std::vector<PrivateAccessibilityButtonInfo>& buttons =
page_objects.form_fields.buttons;
std::vector<PP_PrivateAccessibilityButtonInfo> button_info(buttons.size());
for (size_t i = 0; i < buttons.size(); ++i)
ConvertPrivateAccessibilityButtonInfo(buttons[i], &button_info[i]);
PP_PrivateAccessibilityPageObjects pp_page_objects;
pp_page_objects.links = link_info.data();
pp_page_objects.link_count = link_info.size();
@ -355,6 +378,8 @@ void PDF::SetAccessibilityPageInfo(
pp_page_objects.form_fields.text_field_count = text_field_info.size();
pp_page_objects.form_fields.choice_fields = choice_field_info.data();
pp_page_objects.form_fields.choice_field_count = choice_field_info.size();
pp_page_objects.form_fields.buttons = button_info.data();
pp_page_objects.form_fields.button_count = button_info.size();
get_interface<PPB_PDF>()->SetAccessibilityPageInfo(
instance.pp_instance(), page_info, text_run_info.data(), chars.data(),

@ -128,11 +128,42 @@ class PDF {
FloatRect bounds;
};
// C++ version of PP_PrivateAccessibilityButtonInfo.
// Needs to stay in sync with the C version.
struct PrivateAccessibilityButtonInfo {
std::string name;
std::string value;
// Represents the button type.
PP_PrivateButtonType type;
// Represents if the button is non-editable.
bool is_read_only;
// Represents if the radio button or check box is checked or not.
bool is_checked;
// Represents count of controls in the control group. A group of interactive
// form annotations is collectively called a form control group. Here, an
// interactive form annotation, should be either a radio button or a
// checkbox. Value of |control_count| is >= 1.
uint32_t control_count;
// Represents index of the control in the control group. A group of
// interactive form annotations is collectively called a form control group.
// Here, an interactive form annotation, should be either a radio button or
// a checkbox. Value of |control_index| should always be less than
// |control_count|.
uint32_t control_index;
// Index of this button in the collection of buttons in the page.
uint32_t index_in_page;
// We anchor the button to a text run index, this denotes the text run
// before which the button should be inserted in the accessibility tree.
uint32_t text_run_index;
FloatRect bounds;
};
// C++ version of PP_PrivateAccessibilityFormFieldInfo.
// Needs to stay in sync with the C version.
struct PrivateAccessibilityFormFieldInfo {
std::vector<PrivateAccessibilityTextFieldInfo> text_fields;
std::vector<PrivateAccessibilityChoiceFieldInfo> choice_fields;
std::vector<PrivateAccessibilityButtonInfo> buttons;
};
// C++ version of PP_PrivateAccessibilityPageObjects.

@ -160,6 +160,9 @@ IPC_ENUM_TRAITS_MAX_VALUE(PP_PdfAccessibilityScrollAlignment,
IPC_ENUM_TRAITS_MAX_VALUE(PP_PdfAccessibilityAnnotationType,
PP_PDF_ACCESSIBILITY_ANNOTATIONTYPE_LAST)
IPC_ENUM_TRAITS_MAX_VALUE(PP_PrivateChoiceFieldType, PP_PRIVATECHOICEFIELD_LAST)
IPC_ENUM_TRAITS_MIN_MAX_VALUE(PP_PrivateButtonType,
PP_PRIVATEBUTTON_FIRST,
PP_PRIVATEBUTTON_LAST)
IPC_STRUCT_TRAITS_BEGIN(PP_Point)
IPC_STRUCT_TRAITS_MEMBER(x)
@ -365,9 +368,23 @@ IPC_STRUCT_TRAITS_BEGIN(ppapi::PdfAccessibilityChoiceFieldInfo)
IPC_STRUCT_TRAITS_MEMBER(bounds)
IPC_STRUCT_TRAITS_END()
IPC_STRUCT_TRAITS_BEGIN(ppapi::PdfAccessibilityButtonInfo)
IPC_STRUCT_TRAITS_MEMBER(name)
IPC_STRUCT_TRAITS_MEMBER(value)
IPC_STRUCT_TRAITS_MEMBER(type)
IPC_STRUCT_TRAITS_MEMBER(is_read_only)
IPC_STRUCT_TRAITS_MEMBER(is_checked)
IPC_STRUCT_TRAITS_MEMBER(control_count)
IPC_STRUCT_TRAITS_MEMBER(control_index)
IPC_STRUCT_TRAITS_MEMBER(index_in_page)
IPC_STRUCT_TRAITS_MEMBER(text_run_index)
IPC_STRUCT_TRAITS_MEMBER(bounds)
IPC_STRUCT_TRAITS_END()
IPC_STRUCT_TRAITS_BEGIN(ppapi::PdfAccessibilityFormFieldInfo)
IPC_STRUCT_TRAITS_MEMBER(text_fields)
IPC_STRUCT_TRAITS_MEMBER(choice_fields)
IPC_STRUCT_TRAITS_MEMBER(buttons)
IPC_STRUCT_TRAITS_END()
IPC_STRUCT_TRAITS_BEGIN(ppapi::PdfAccessibilityPageObjects)

@ -120,6 +120,23 @@ PdfAccessibilityChoiceFieldInfo::PdfAccessibilityChoiceFieldInfo(
}
}
PdfAccessibilityButtonInfo::PdfAccessibilityButtonInfo() = default;
PdfAccessibilityButtonInfo::~PdfAccessibilityButtonInfo() = default;
PdfAccessibilityButtonInfo::PdfAccessibilityButtonInfo(
const PP_PrivateAccessibilityButtonInfo& button)
: name(std::string(button.name, button.name_length)),
value(std::string(button.value, button.value_length)),
type(button.type),
is_read_only(button.is_read_only),
is_checked(button.is_checked),
control_count(button.control_count),
control_index(button.control_index),
index_in_page(button.index_in_page),
text_run_index(button.text_run_index),
bounds(button.bounds) {}
PdfAccessibilityFormFieldInfo::PdfAccessibilityFormFieldInfo() = default;
PdfAccessibilityFormFieldInfo::PdfAccessibilityFormFieldInfo(
@ -133,6 +150,11 @@ PdfAccessibilityFormFieldInfo::PdfAccessibilityFormFieldInfo(
for (size_t i = 0; i < form_fields.choice_field_count; i++) {
choice_fields.emplace_back(form_fields.choice_fields[i]);
}
buttons.reserve(form_fields.button_count);
for (size_t i = 0; i < form_fields.button_count; i++) {
buttons.emplace_back(form_fields.buttons[i]);
}
}
PdfAccessibilityFormFieldInfo::~PdfAccessibilityFormFieldInfo() = default;

@ -137,6 +137,25 @@ struct PPAPI_SHARED_EXPORT PdfAccessibilityChoiceFieldInfo {
PP_FloatRect bounds;
};
// Needs to stay in sync with PP_PrivateAccessibilityButtonInfo.
struct PPAPI_SHARED_EXPORT PdfAccessibilityButtonInfo {
PdfAccessibilityButtonInfo();
explicit PdfAccessibilityButtonInfo(
const PP_PrivateAccessibilityButtonInfo& button);
~PdfAccessibilityButtonInfo();
std::string name;
std::string value;
PP_PrivateButtonType type;
bool is_read_only;
bool is_checked;
uint32_t control_count;
uint32_t control_index;
uint32_t index_in_page;
uint32_t text_run_index;
PP_FloatRect bounds;
};
// Needs to stay in sync with PP_PrivateAccessibilityFormFieldInfo.
struct PPAPI_SHARED_EXPORT PdfAccessibilityFormFieldInfo {
PdfAccessibilityFormFieldInfo();
@ -146,6 +165,7 @@ struct PPAPI_SHARED_EXPORT PdfAccessibilityFormFieldInfo {
std::vector<PdfAccessibilityTextFieldInfo> text_fields;
std::vector<PdfAccessibilityChoiceFieldInfo> choice_fields;
std::vector<PdfAccessibilityButtonInfo> buttons;
};
// Needs to stay in sync with PP_PrivateAccessibilityPageObjects.