1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
|
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/modules/accessibility/ax_validation_message.h"
#include "third_party/blink/renderer/core/html/forms/listed_element.h"
#include "third_party/blink/renderer/core/html/html_element.h"
#include "third_party/blink/renderer/core/layout/layout_object.h"
#include "third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
#include "ui/gfx/geometry/transform.h"
namespace blink {
AXValidationMessage::AXValidationMessage(AXObjectCacheImpl& ax_object_cache)
: AXObject(ax_object_cache) {}
AXValidationMessage::~AXValidationMessage() {}
bool AXValidationMessage::ComputeIsIgnored(
IgnoredReasons* ignored_reasons) const {
return false;
}
Document* AXValidationMessage::GetDocument() const {
return &AXObjectCache().GetDocument();
}
// TODO(accessibility) Currently we return the bounds of the focused form
// control. If this becomes an issue, return the bounds of the alert itself.
void AXValidationMessage::GetRelativeBounds(
AXObject** out_container,
gfx::RectF& out_bounds_in_container,
gfx::Transform& out_container_transform,
bool* clips_children) const {
DCHECK(out_container);
*out_container = nullptr;
out_bounds_in_container = gfx::RectF();
out_container_transform.MakeIdentity();
if (clips_children)
*clips_children = false;
ListedElement* listed_element = RelatedFormControlIfVisible();
if (!listed_element)
return;
HTMLElement& form_control = listed_element->ToHTMLElement();
if (!form_control.GetLayoutObject())
return;
*out_container = ParentObject();
if (form_control.GetLayoutObject()) {
out_bounds_in_container =
gfx::RectF(form_control.GetLayoutObject()->AbsoluteBoundingBoxRect());
}
}
bool AXValidationMessage::IsVisible() const {
bool is_visible = RelatedFormControlIfVisible();
DCHECK(!is_visible || ParentObject() == AXObjectCache().Root())
<< "A visible validation message's parent must be the root object'.";
return is_visible;
}
const AtomicString& AXValidationMessage::LiveRegionStatus() const {
DEFINE_STATIC_LOCAL(const AtomicString, live_region_status_assertive,
("assertive"));
return live_region_status_assertive;
}
const AtomicString& AXValidationMessage::LiveRegionRelevant() const {
DEFINE_STATIC_LOCAL(const AtomicString, live_region_relevant_additions,
("additions"));
return live_region_relevant_additions;
}
ax::mojom::blink::Role AXValidationMessage::NativeRoleIgnoringAria() const {
return ax::mojom::blink::Role::kAlert;
}
ListedElement* AXValidationMessage::RelatedFormControlIfVisible() const {
AXObject* focused_object = AXObjectCache().FocusedObject();
if (!focused_object)
return nullptr;
Element* element = focused_object->GetElement();
if (!element)
return nullptr;
ListedElement* form_control = ListedElement::From(*element);
if (!form_control || !form_control->IsValidationMessageVisible())
return nullptr;
// The method IsValidationMessageVisible() is a superset of
// IsNotCandidateOrValid(), but has the benefit of not being true until user
// has tried to submit data. Waiting until the error message is visible
// before presenting to screen reader is preferable over hearing about the
// error while the user is still attempting to input data in the first place.
return form_control->IsValidationMessageVisible() ? form_control : nullptr;
}
String AXValidationMessage::TextAlternative(
bool recursive,
const AXObject* aria_label_or_description_root,
AXObjectSet& visited,
ax::mojom::NameFrom& name_from,
AXRelatedObjectVector* related_objects,
NameSources* name_sources) const {
// If nameSources is non-null, relatedObjects is used in filling it in, so it
// must be non-null as well.
if (name_sources)
DCHECK(related_objects);
ListedElement* form_control_element = RelatedFormControlIfVisible();
if (!form_control_element)
return String();
StringBuilder message;
message.Append(form_control_element->validationMessage());
if (form_control_element->ValidationSubMessage()) {
message.Append(' ');
message.Append(form_control_element->ValidationSubMessage());
}
if (name_sources) {
name_sources->push_back(NameSource(true));
name_sources->back().type = ax::mojom::NameFrom::kContents;
name_sources->back().text = message.ToString();
}
return message.ToString();
}
} // namespace blink
|