blob: 8dfce00f3c77c4f5b88901c23db15c75bf778abd [file] [log] [blame]
/*
* Copyright (C) 2009 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "third_party/blink/public/web/web_ax_object.h"
#include "SkMatrix44.h"
#include "third_party/blink/public/platform/web_float_rect.h"
#include "third_party/blink/public/platform/web_point.h"
#include "third_party/blink/public/platform/web_rect.h"
#include "third_party/blink/public/platform/web_string.h"
#include "third_party/blink/public/platform/web_url.h"
#include "third_party/blink/public/web/web_document.h"
#include "third_party/blink/public/web/web_element.h"
#include "third_party/blink/public/web/web_node.h"
#include "third_party/blink/public/web/web_view.h"
#include "third_party/blink/renderer/core/css/css_primitive_value_mappings.h"
#include "third_party/blink/renderer/core/dom/node.h"
#include "third_party/blink/renderer/core/editing/markers/document_marker.h"
#include "third_party/blink/renderer/core/editing/visible_position.h"
#include "third_party/blink/renderer/core/exported/web_view_impl.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/frame/visual_viewport.h"
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
#include "third_party/blink/renderer/core/html_names.h"
#include "third_party/blink/renderer/core/input/keyboard_event_manager.h"
#include "third_party/blink/renderer/core/layout/layout_object.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
#include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
#include "third_party/blink/renderer/modules/accessibility/ax_object.h"
#include "third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h"
#include "third_party/blink/renderer/modules/accessibility/ax_range.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
namespace blink {
class WebAXSparseAttributeClientAdapter : public AXSparseAttributeClient {
public:
WebAXSparseAttributeClientAdapter(WebAXSparseAttributeClient& attribute_map)
: attribute_map_(attribute_map) {}
virtual ~WebAXSparseAttributeClientAdapter() = default;
private:
WebAXSparseAttributeClient& attribute_map_;
void AddBoolAttribute(AXBoolAttribute attribute, bool value) override {
attribute_map_.AddBoolAttribute(static_cast<WebAXBoolAttribute>(attribute),
value);
}
void AddStringAttribute(AXStringAttribute attribute,
const String& value) override {
attribute_map_.AddStringAttribute(
static_cast<WebAXStringAttribute>(attribute), value);
}
void AddObjectAttribute(AXObjectAttribute attribute,
AXObject& value) override {
attribute_map_.AddObjectAttribute(
static_cast<WebAXObjectAttribute>(attribute), WebAXObject(&value));
}
void AddObjectVectorAttribute(AXObjectVectorAttribute attribute,
HeapVector<Member<AXObject>>& value) override {
WebVector<WebAXObject> result(value.size());
std::copy(value.begin(), value.end(), result.begin());
attribute_map_.AddObjectVectorAttribute(
static_cast<WebAXObjectVectorAttribute>(attribute), result);
}
};
static bool IsLayoutClean(Document* document) {
if (!document || !document->View())
return false;
if (document->View()->NeedsLayout())
return false;
DocumentLifecycle::LifecycleState state = document->Lifecycle().GetState();
if (state >= DocumentLifecycle::kLayoutClean ||
state == DocumentLifecycle::kStyleClean ||
state == DocumentLifecycle::kLayoutSubtreeChangeClean) {
return true;
}
return false;
}
void WebAXObject::Reset() {
private_.Reset();
}
void WebAXObject::Assign(const WebAXObject& other) {
private_ = other.private_;
}
bool WebAXObject::Equals(const WebAXObject& n) const {
return private_.Get() == n.private_.Get();
}
bool WebAXObject::IsDetached() const {
if (private_.IsNull())
return true;
return private_->IsDetached();
}
int WebAXObject::AxID() const {
if (IsDetached())
return -1;
return private_->AXObjectID();
}
int WebAXObject::GenerateAXID() const {
if (IsDetached())
return -1;
return private_->AXObjectCache().GenerateAXID();
}
bool WebAXObject::UpdateLayoutAndCheckValidity() {
if (!IsDetached()) {
Document* document = private_->GetDocument();
if (!document || !document->View())
return false;
if (IsLayoutClean(document))
return true;
if (!document->View()->UpdateLifecycleToCompositingCleanPlusScrolling())
return false;
}
// Doing a layout can cause this object to be invalid, so check again.
return !IsDetached();
}
ax::mojom::DefaultActionVerb WebAXObject::Action() const {
if (IsDetached())
return ax::mojom::DefaultActionVerb::kNone;
return private_->Action();
}
bool WebAXObject::CanPress() const {
if (IsDetached())
return false;
return private_->ActionElement() || private_->IsButton() ||
private_->IsMenuRelated();
}
bool WebAXObject::CanSetFocusAttribute() const {
if (IsDetached())
return false;
return private_->CanSetFocusAttribute();
}
bool WebAXObject::CanSetValueAttribute() const {
if (IsDetached())
return false;
return private_->CanSetValueAttribute();
}
unsigned WebAXObject::ChildCount() const {
if (IsDetached())
return 0;
return private_->Children().size();
}
WebAXObject WebAXObject::ChildAt(unsigned index) const {
if (IsDetached())
return WebAXObject();
if (private_->Children().size() <= index)
return WebAXObject();
return WebAXObject(private_->Children()[index]);
}
WebAXObject WebAXObject::ParentObject() const {
if (IsDetached())
return WebAXObject();
return WebAXObject(private_->ParentObject());
}
void WebAXObject::GetSparseAXAttributes(
WebAXSparseAttributeClient& client) const {
if (IsDetached())
return;
WebAXSparseAttributeClientAdapter adapter(client);
private_->GetSparseAXAttributes(adapter);
}
bool WebAXObject::IsAnchor() const {
if (IsDetached())
return false;
return private_->IsAnchor();
}
bool WebAXObject::IsAutofillAvailable() const {
if (IsDetached())
return false;
return private_->IsAutofillAvailable();
}
WebString WebAXObject::AriaAutoComplete() const {
if (IsDetached())
return WebString();
return private_->AriaAutoComplete();
}
ax::mojom::AriaCurrentState WebAXObject::AriaCurrentState() const {
if (IsDetached())
return ax::mojom::AriaCurrentState::kNone;
return private_->GetAriaCurrentState();
}
ax::mojom::CheckedState WebAXObject::CheckedState() const {
if (IsDetached())
return ax::mojom::CheckedState::kNone;
return private_->CheckedState();
}
bool WebAXObject::IsClickable() const {
if (IsDetached())
return false;
return private_->IsClickable();
}
bool WebAXObject::IsControl() const {
if (IsDetached())
return false;
return private_->IsControl();
}
bool WebAXObject::IsDefault() const {
if (IsDetached())
return false;
return private_->IsDefault();
}
WebAXRestriction WebAXObject::Restriction() const {
if (IsDetached())
return kWebAXRestrictionNone;
return static_cast<WebAXRestriction>(private_->Restriction());
}
WebAXExpanded WebAXObject::IsExpanded() const {
if (IsDetached())
return kWebAXExpandedUndefined;
return static_cast<WebAXExpanded>(private_->IsExpanded());
}
bool WebAXObject::IsFocused() const {
if (IsDetached())
return false;
return private_->IsFocused();
}
bool WebAXObject::IsHovered() const {
if (IsDetached())
return false;
return private_->IsHovered();
}
bool WebAXObject::IsLinked() const {
if (IsDetached())
return false;
return private_->IsLinked();
}
bool WebAXObject::IsLoaded() const {
if (IsDetached())
return false;
return private_->IsLoaded();
}
bool WebAXObject::IsModal() const {
if (IsDetached())
return false;
return private_->IsModal();
}
bool WebAXObject::IsMultiSelectable() const {
if (IsDetached())
return false;
return private_->IsMultiSelectable();
}
bool WebAXObject::IsOffScreen() const {
if (IsDetached())
return false;
return private_->IsOffScreen();
}
bool WebAXObject::IsPasswordField() const {
if (IsDetached())
return false;
return private_->IsPasswordField();
}
bool WebAXObject::IsRequired() const {
if (IsDetached())
return false;
return private_->IsRequired();
}
WebAXSelectedState WebAXObject::IsSelected() const {
if (IsDetached())
return kWebAXSelectedStateUndefined;
return static_cast<WebAXSelectedState>(private_->IsSelected());
}
bool WebAXObject::IsSelectedOptionActive() const {
if (IsDetached())
return false;
return private_->IsSelectedOptionActive();
}
bool WebAXObject::IsVisible() const {
if (IsDetached())
return false;
return private_->IsVisible();
}
bool WebAXObject::IsVisited() const {
if (IsDetached())
return false;
return private_->IsVisited();
}
WebString WebAXObject::AccessKey() const {
if (IsDetached())
return WebString();
return WebString(private_->AccessKey());
}
unsigned WebAXObject::BackgroundColor() const {
if (IsDetached())
return 0;
// RGBA32 is an alias for unsigned int.
return private_->BackgroundColor();
}
unsigned WebAXObject::GetColor() const {
if (IsDetached())
return 0;
// RGBA32 is an alias for unsigned int.
return private_->GetColor();
}
// Deprecated.
void WebAXObject::ColorValue(int& r, int& g, int& b) const {
if (IsDetached())
return;
unsigned color = private_->ColorValue();
r = (color >> 16) & 0xFF;
g = (color >> 8) & 0xFF;
b = color & 0xFF;
}
unsigned WebAXObject::ColorValue() const {
if (IsDetached())
return 0;
// RGBA32 is an alias for unsigned int.
return private_->ColorValue();
}
WebAXObject WebAXObject::AriaActiveDescendant() const {
if (IsDetached())
return WebAXObject();
return WebAXObject(private_->ActiveDescendant());
}
WebAXObject WebAXObject::ErrorMessage() const {
if (IsDetached())
return WebAXObject();
return WebAXObject(private_->ErrorMessage());
}
ax::mojom::HasPopup WebAXObject::HasPopup() const {
if (IsDetached())
return ax::mojom::HasPopup::kFalse;
return private_->HasPopup();
}
bool WebAXObject::IsEditableRoot() const {
if (IsDetached())
return false;
return private_->IsEditableRoot();
}
bool WebAXObject::IsEditable() const {
if (IsDetached())
return false;
return private_->IsEditable();
}
bool WebAXObject::IsMultiline() const {
if (IsDetached())
return false;
return private_->IsMultiline();
}
bool WebAXObject::IsRichlyEditable() const {
if (IsDetached())
return false;
return private_->IsRichlyEditable();
}
int WebAXObject::PosInSet() const {
if (IsDetached())
return 0;
return private_->PosInSet();
}
int WebAXObject::SetSize() const {
if (IsDetached())
return 0;
return private_->SetSize();
}
bool WebAXObject::IsInLiveRegion() const {
if (IsDetached())
return false;
return !!private_->LiveRegionRoot();
}
bool WebAXObject::LiveRegionAtomic() const {
if (IsDetached())
return false;
return private_->LiveRegionAtomic();
}
WebString WebAXObject::LiveRegionRelevant() const {
if (IsDetached())
return WebString();
return private_->LiveRegionRelevant();
}
WebString WebAXObject::LiveRegionStatus() const {
if (IsDetached())
return WebString();
return private_->LiveRegionStatus();
}
WebAXObject WebAXObject::LiveRegionRoot() const {
if (IsDetached())
return WebAXObject();
AXObject* live_region_root = private_->LiveRegionRoot();
if (live_region_root)
return WebAXObject(live_region_root);
return WebAXObject();
}
bool WebAXObject::ContainerLiveRegionAtomic() const {
if (IsDetached())
return false;
return private_->ContainerLiveRegionAtomic();
}
bool WebAXObject::ContainerLiveRegionBusy() const {
if (IsDetached())
return false;
return private_->ContainerLiveRegionBusy();
}
WebString WebAXObject::ContainerLiveRegionRelevant() const {
if (IsDetached())
return WebString();
return private_->ContainerLiveRegionRelevant();
}
WebString WebAXObject::ContainerLiveRegionStatus() const {
if (IsDetached())
return WebString();
return private_->ContainerLiveRegionStatus();
}
bool WebAXObject::AriaOwns(WebVector<WebAXObject>& owns_elements) const {
// aria-owns rearranges the accessibility tree rather than just
// exposing an attribute.
// FIXME(dmazzoni): remove this function after we stop calling it
// from Chromium. http://crbug.com/489590
return false;
}
WebString WebAXObject::FontFamily() const {
if (IsDetached())
return WebString();
return private_->FontFamily();
}
float WebAXObject::FontSize() const {
if (IsDetached())
return 0.0f;
return private_->FontSize();
}
bool WebAXObject::CanvasHasFallbackContent() const {
if (IsDetached())
return false;
return private_->CanvasHasFallbackContent();
}
WebString WebAXObject::ImageDataUrl(const WebSize& max_size) const {
if (IsDetached())
return WebString();
return private_->ImageDataUrl(max_size);
}
ax::mojom::InvalidState WebAXObject::InvalidState() const {
if (IsDetached())
return ax::mojom::InvalidState::kNone;
return private_->GetInvalidState();
}
// Only used when invalidState() returns WebAXInvalidStateOther.
WebString WebAXObject::AriaInvalidValue() const {
if (IsDetached())
return WebString();
return private_->AriaInvalidValue();
}
double WebAXObject::EstimatedLoadingProgress() const {
if (IsDetached())
return 0.0;
return private_->EstimatedLoadingProgress();
}
int WebAXObject::HeadingLevel() const {
if (IsDetached())
return 0;
return private_->HeadingLevel();
}
int WebAXObject::HierarchicalLevel() const {
if (IsDetached())
return 0;
return private_->HierarchicalLevel();
}
// FIXME: This method passes in a point that has page scale applied but assumes
// that (0, 0) is the top left of the visual viewport. In other words, the
// point has the VisualViewport scale applied, but not the VisualViewport
// offset. crbug.com/459591.
WebAXObject WebAXObject::HitTest(const WebPoint& point) const {
if (IsDetached())
return WebAXObject();
IntPoint contents_point =
private_->DocumentFrameView()->SoonToBeRemovedUnscaledViewportToContents(
point);
AXObject* hit = private_->AccessibilityHitTest(contents_point);
if (hit)
return WebAXObject(hit);
if (private_->GetBoundsInFrameCoordinates().Contains(contents_point))
return *this;
return WebAXObject();
}
WebString WebAXObject::KeyboardShortcut() const {
if (IsDetached())
return WebString();
String access_key = private_->AccessKey();
if (access_key.IsNull())
return WebString();
DEFINE_STATIC_LOCAL(String, modifier_string, ());
if (modifier_string.IsNull()) {
unsigned modifiers = KeyboardEventManager::kAccessKeyModifiers;
// Follow the same order as Mozilla MSAA implementation:
// Ctrl+Alt+Shift+Meta+key. MSDN states that keyboard shortcut strings
// should not be localized and defines the separator as "+".
StringBuilder modifier_string_builder;
if (modifiers & WebInputEvent::kControlKey)
modifier_string_builder.Append("Ctrl+");
if (modifiers & WebInputEvent::kAltKey)
modifier_string_builder.Append("Alt+");
if (modifiers & WebInputEvent::kShiftKey)
modifier_string_builder.Append("Shift+");
if (modifiers & WebInputEvent::kMetaKey)
modifier_string_builder.Append("Win+");
modifier_string = modifier_string_builder.ToString();
}
return String(modifier_string + access_key);
}
WebString WebAXObject::Language() const {
if (IsDetached())
return WebString();
return private_->Language();
}
bool WebAXObject::ClearAccessibilityFocus() const {
if (IsDetached())
return false;
return private_->InternalClearAccessibilityFocusAction();
}
bool WebAXObject::Click() const {
if (IsDetached())
return false;
return private_->RequestClickAction();
}
bool WebAXObject::Increment() const {
if (IsDetached())
return false;
return private_->RequestIncrementAction();
}
bool WebAXObject::Decrement() const {
if (IsDetached())
return false;
return private_->RequestDecrementAction();
}
WebAXObject WebAXObject::InPageLinkTarget() const {
if (IsDetached())
return WebAXObject();
AXObject* target = private_->InPageLinkTarget();
if (!target)
return WebAXObject();
return WebAXObject(target);
}
WebAXOrientation WebAXObject::Orientation() const {
if (IsDetached())
return kWebAXOrientationUndefined;
return static_cast<WebAXOrientation>(private_->Orientation());
}
WebVector<WebAXObject> WebAXObject::RadioButtonsInGroup() const {
if (IsDetached())
return WebVector<WebAXObject>();
AXObject::AXObjectVector radio_buttons = private_->RadioButtonsInGroup();
WebVector<WebAXObject> web_radio_buttons(radio_buttons.size());
std::copy(radio_buttons.begin(), radio_buttons.end(),
web_radio_buttons.begin());
return web_radio_buttons;
}
ax::mojom::Role WebAXObject::Role() const {
if (IsDetached())
return ax::mojom::Role::kUnknown;
return private_->RoleValue();
}
static ax::mojom::TextAffinity ToAXAffinity(TextAffinity affinity) {
switch (affinity) {
case TextAffinity::kUpstream:
return ax::mojom::TextAffinity::kUpstream;
case TextAffinity::kDownstream:
return ax::mojom::TextAffinity::kDownstream;
default:
NOTREACHED();
return ax::mojom::TextAffinity::kDownstream;
}
}
void WebAXObject::Selection(WebAXObject& anchor_object,
int& anchor_offset,
ax::mojom::TextAffinity& anchor_affinity,
WebAXObject& focus_object,
int& focus_offset,
ax::mojom::TextAffinity& focus_affinity) const {
if (IsDetached()) {
anchor_object = WebAXObject();
anchor_offset = -1;
anchor_affinity = ax::mojom::TextAffinity::kDownstream;
focus_object = WebAXObject();
focus_offset = -1;
focus_affinity = ax::mojom::TextAffinity::kDownstream;
return;
}
AXObject::AXSelection ax_selection = private_->Selection();
anchor_object = WebAXObject(ax_selection.anchor_object);
anchor_offset = ax_selection.anchor_offset;
anchor_affinity = ToAXAffinity(ax_selection.anchor_affinity);
focus_object = WebAXObject(ax_selection.focus_object);
focus_offset = ax_selection.focus_offset;
focus_affinity = ToAXAffinity(ax_selection.focus_affinity);
return;
}
bool WebAXObject::SetAccessibilityFocus() const {
if (IsDetached())
return false;
return private_->InternalSetAccessibilityFocusAction();
}
bool WebAXObject::SetSelected(bool selected) const {
if (IsDetached())
return false;
return private_->RequestSetSelectedAction(selected);
}
bool WebAXObject::SetSelection(const WebAXObject& anchor_object,
int anchor_offset,
const WebAXObject& focus_object,
int focus_offset) const {
if (IsDetached())
return false;
AXObject::AXSelection ax_selection(anchor_object, anchor_offset,
TextAffinity::kUpstream, focus_object,
focus_offset, TextAffinity::kDownstream);
return private_->RequestSetSelectionAction(ax_selection);
}
unsigned WebAXObject::SelectionEnd() const {
if (IsDetached())
return 0;
AXObject::AXSelection ax_selection = private_->SelectionUnderObject();
if (ax_selection.focus_offset < 0)
return 0;
return ax_selection.focus_offset;
}
unsigned WebAXObject::SelectionStart() const {
if (IsDetached())
return 0;
AXObject::AXSelection ax_selection = private_->SelectionUnderObject();
if (ax_selection.anchor_offset < 0)
return 0;
return ax_selection.anchor_offset;
}
unsigned WebAXObject::SelectionEndLineNumber() const {
if (IsDetached())
return 0;
VisiblePosition position = private_->VisiblePositionForIndex(SelectionEnd());
int line_number = private_->LineForPosition(position);
if (line_number < 0)
return 0;
return line_number;
}
unsigned WebAXObject::SelectionStartLineNumber() const {
if (IsDetached())
return 0;
VisiblePosition position =
private_->VisiblePositionForIndex(SelectionStart());
int line_number = private_->LineForPosition(position);
if (line_number < 0)
return 0;
return line_number;
}
bool WebAXObject::Focus() const {
if (IsDetached())
return false;
return private_->RequestFocusAction();
}
bool WebAXObject::SetSequentialFocusNavigationStartingPoint() const {
if (IsDetached())
return false;
return private_->RequestSetSequentialFocusNavigationStartingPointAction();
}
bool WebAXObject::SetValue(WebString value) const {
if (IsDetached())
return false;
return private_->RequestSetValueAction(value);
}
bool WebAXObject::ShowContextMenu() const {
if (IsDetached())
return false;
return private_->RequestShowContextMenuAction();
}
WebString WebAXObject::StringValue() const {
if (IsDetached())
return WebString();
return private_->StringValue();
}
ax::mojom::TextDirection WebAXObject::GetTextDirection() const {
if (IsDetached())
return ax::mojom::TextDirection::kLtr;
return private_->GetTextDirection();
}
ax::mojom::TextPosition WebAXObject::GetTextPosition() const {
if (IsDetached())
return ax::mojom::TextPosition::kNone;
return private_->GetTextPosition();
}
int WebAXObject::TextStyle() const {
if (IsDetached())
return 0;
return private_->GetTextStyle();
}
WebURL WebAXObject::Url() const {
if (IsDetached())
return WebURL();
return private_->Url();
}
WebString WebAXObject::GetName(ax::mojom::NameFrom& out_name_from,
WebVector<WebAXObject>& out_name_objects) const {
if (IsDetached())
return WebString();
ax::mojom::NameFrom name_from = ax::mojom::NameFrom::kUninitialized;
HeapVector<Member<AXObject>> name_objects;
WebString result = private_->GetName(name_from, &name_objects);
out_name_from = name_from;
out_name_objects.reserve(name_objects.size());
out_name_objects.resize(name_objects.size());
std::copy(name_objects.begin(), name_objects.end(), out_name_objects.begin());
return result;
}
WebString WebAXObject::GetName() const {
if (IsDetached())
return WebString();
ax::mojom::NameFrom name_from;
HeapVector<Member<AXObject>> name_objects;
return private_->GetName(name_from, &name_objects);
}
WebString WebAXObject::Description(
ax::mojom::NameFrom name_from,
ax::mojom::DescriptionFrom& out_description_from,
WebVector<WebAXObject>& out_description_objects) const {
if (IsDetached())
return WebString();
ax::mojom::DescriptionFrom description_from =
ax::mojom::DescriptionFrom::kUninitialized;
HeapVector<Member<AXObject>> description_objects;
String result =
private_->Description(name_from, description_from, &description_objects);
out_description_from = description_from;
out_description_objects.reserve(description_objects.size());
out_description_objects.resize(description_objects.size());
std::copy(description_objects.begin(), description_objects.end(),
out_description_objects.begin());
return result;
}
WebString WebAXObject::Placeholder(ax::mojom::NameFrom name_from) const {
if (IsDetached())
return WebString();
return private_->Placeholder(name_from);
}
WebString WebAXObject::Title(ax::mojom::NameFrom name_from) const {
if (IsDetached())
return WebString();
return private_->Title(name_from);
}
bool WebAXObject::SupportsRangeValue() const {
if (IsDetached())
return false;
return private_->SupportsRangeValue();
}
WebString WebAXObject::ValueDescription() const {
if (IsDetached())
return WebString();
return private_->ValueDescription();
}
bool WebAXObject::ValueForRange(float* out_value) const {
if (IsDetached())
return false;
return private_->ValueForRange(out_value);
}
bool WebAXObject::MaxValueForRange(float* out_value) const {
if (IsDetached())
return false;
return private_->MaxValueForRange(out_value);
}
bool WebAXObject::MinValueForRange(float* out_value) const {
if (IsDetached())
return false;
return private_->MinValueForRange(out_value);
}
bool WebAXObject::StepValueForRange(float* out_value) const {
if (IsDetached())
return false;
return private_->StepValueForRange(out_value);
}
WebNode WebAXObject::GetNode() const {
if (IsDetached())
return WebNode();
Node* node = private_->GetNode();
if (!node)
return WebNode();
return WebNode(node);
}
WebDocument WebAXObject::GetDocument() const {
if (IsDetached())
return WebDocument();
Document* document = private_->GetDocument();
if (!document)
return WebDocument();
return WebDocument(document);
}
bool WebAXObject::HasComputedStyle() const {
if (IsDetached())
return false;
Document* document = private_->GetDocument();
if (document)
document->UpdateStyleAndLayoutTree();
Node* node = private_->GetNode();
if (!node)
return false;
return node->EnsureComputedStyle();
}
WebString WebAXObject::ComputedStyleDisplay() const {
if (IsDetached())
return WebString();
Document* document = private_->GetDocument();
if (document)
document->UpdateStyleAndLayoutTree();
Node* node = private_->GetNode();
if (!node)
return WebString();
const ComputedStyle* computed_style = node->EnsureComputedStyle();
if (!computed_style)
return WebString();
return WebString(CSSProperty::Get(CSSPropertyID::kDisplay)
.CSSValueFromComputedStyle(
*computed_style, /* layout_object */ nullptr, node,
/* allow_visited_style */ false)
->CssText());
}
bool WebAXObject::AccessibilityIsIgnored() const {
if (IsDetached())
return false;
return private_->AccessibilityIsIgnored();
}
bool WebAXObject::LineBreaks(WebVector<int>& result) const {
if (IsDetached())
return false;
Vector<int> line_breaks_vector;
private_->LineBreaks(line_breaks_vector);
result = line_breaks_vector;
return true;
}
int WebAXObject::AriaColumnCount() const {
if (IsDetached())
return 0;
return private_->IsTableLikeRole() ? private_->AriaColumnCount() : 0;
}
unsigned WebAXObject::AriaColumnIndex() const {
if (IsDetached())
return 0;
return private_->AriaColumnIndex();
}
int WebAXObject::AriaRowCount() const {
if (IsDetached())
return 0;
return private_->IsTableLikeRole() ? private_->AriaRowCount() : 0;
}
unsigned WebAXObject::AriaRowIndex() const {
if (IsDetached())
return 0;
return private_->AriaRowIndex();
}
unsigned WebAXObject::ColumnCount() const {
if (IsDetached())
return false;
return private_->IsTableLikeRole() ? private_->ColumnCount() : 0;
}
unsigned WebAXObject::RowCount() const {
if (IsDetached())
return 0;
if (!private_->IsTableLikeRole())
return 0;
return private_->RowCount();
}
WebAXObject WebAXObject::CellForColumnAndRow(unsigned column,
unsigned row) const {
if (IsDetached())
return WebAXObject();
if (!private_->IsTableLikeRole())
return WebAXObject();
return WebAXObject(private_->CellForColumnAndRow(column, row));
}
unsigned WebAXObject::RowIndex() const {
if (IsDetached())
return 0;
return private_->IsTableRowLikeRole() ? private_->RowIndex() : 0;
}
WebAXObject WebAXObject::RowHeader() const {
if (IsDetached())
return WebAXObject();
if (!private_->IsTableRowLikeRole())
return WebAXObject();
return WebAXObject(private_->HeaderObject());
}
void WebAXObject::RowHeaders(
WebVector<WebAXObject>& row_header_elements) const {
if (IsDetached())
return;
if (!private_->IsTableLikeRole())
return;
AXObject::AXObjectVector headers;
private_->RowHeaders(headers);
row_header_elements.reserve(headers.size());
row_header_elements.resize(headers.size());
std::copy(headers.begin(), headers.end(), row_header_elements.begin());
}
unsigned WebAXObject::ColumnIndex() const {
if (IsDetached())
return 0;
if (private_->RoleValue() != ax::mojom::Role::kColumn)
return 0;
return private_->ColumnIndex();
}
WebAXObject WebAXObject::ColumnHeader() const {
if (IsDetached())
return WebAXObject();
if (private_->RoleValue() != ax::mojom::Role::kColumn)
return WebAXObject();
return WebAXObject(private_->HeaderObject());
}
void WebAXObject::ColumnHeaders(
WebVector<WebAXObject>& column_header_elements) const {
if (IsDetached())
return;
if (!private_->IsTableLikeRole())
return;
AXObject::AXObjectVector headers;
private_->ColumnHeaders(headers);
column_header_elements.reserve(headers.size());
column_header_elements.resize(headers.size());
std::copy(headers.begin(), headers.end(), column_header_elements.begin());
}
unsigned WebAXObject::CellColumnIndex() const {
if (IsDetached())
return 0;
return private_->IsTableCellLikeRole() ? private_->ColumnIndex() : 0;
}
unsigned WebAXObject::CellColumnSpan() const {
if (IsDetached())
return 0;
return private_->IsTableCellLikeRole() ? private_->ColumnSpan() : 0;
}
unsigned WebAXObject::CellRowIndex() const {
if (IsDetached())
return 0;
return private_->IsTableCellLikeRole() ? private_->RowIndex() : 0;
}
unsigned WebAXObject::CellRowSpan() const {
if (IsDetached())
return 0;
return private_->IsTableCellLikeRole() ? private_->RowSpan() : 0;
}
ax::mojom::SortDirection WebAXObject::SortDirection() const {
if (IsDetached())
return ax::mojom::SortDirection::kNone;
return private_->GetSortDirection();
}
void WebAXObject::LoadInlineTextBoxes() const {
if (IsDetached())
return;
private_->LoadInlineTextBoxes();
}
WebAXObject WebAXObject::NextOnLine() const {
if (IsDetached())
return WebAXObject();
return WebAXObject(private_.Get()->NextOnLine());
}
WebAXObject WebAXObject::PreviousOnLine() const {
if (IsDetached())
return WebAXObject();
return WebAXObject(private_.Get()->PreviousOnLine());
}
static ax::mojom::MarkerType ToAXMarkerType(
DocumentMarker::MarkerType marker_type) {
switch (marker_type) {
case DocumentMarker::kSpelling:
return ax::mojom::MarkerType::kSpelling;
case DocumentMarker::kGrammar:
return ax::mojom::MarkerType::kGrammar;
case DocumentMarker::kTextMatch:
return ax::mojom::MarkerType::kTextMatch;
case DocumentMarker::kActiveSuggestion:
return ax::mojom::MarkerType::kActiveSuggestion;
case DocumentMarker::kSuggestion:
return ax::mojom::MarkerType::kSuggestion;
default:
return ax::mojom::MarkerType::kNone;
}
}
void WebAXObject::Markers(WebVector<ax::mojom::MarkerType>& types,
WebVector<int>& starts,
WebVector<int>& ends) const {
if (IsDetached())
return;
Vector<DocumentMarker::MarkerType> marker_types;
Vector<AXRange> marker_ranges;
private_->Markers(marker_types, marker_ranges);
DCHECK_EQ(marker_types.size(), marker_ranges.size());
WebVector<ax::mojom::MarkerType> web_marker_types(marker_types.size());
WebVector<int> start_offsets(marker_ranges.size());
WebVector<int> end_offsets(marker_ranges.size());
for (wtf_size_t i = 0; i < marker_types.size(); ++i) {
web_marker_types[i] = ToAXMarkerType(marker_types[i]);
DCHECK(marker_ranges[i].IsValid());
DCHECK_EQ(marker_ranges[i].Start().ContainerObject(),
marker_ranges[i].End().ContainerObject());
start_offsets[i] = marker_ranges[i].Start().TextOffset();
end_offsets[i] = marker_ranges[i].End().TextOffset();
}
types.Swap(web_marker_types);
starts.Swap(start_offsets);
ends.Swap(end_offsets);
}
void WebAXObject::CharacterOffsets(WebVector<int>& offsets) const {
if (IsDetached())
return;
Vector<int> offsets_vector;
private_->TextCharacterOffsets(offsets_vector);
offsets = offsets_vector;
}
void WebAXObject::GetWordBoundaries(WebVector<int>& starts,
WebVector<int>& ends) const {
if (IsDetached())
return;
Vector<int> src_starts;
Vector<int> src_ends;
private_->GetWordBoundaries(src_starts, src_ends);
DCHECK_EQ(src_starts.size(), src_ends.size());
WebVector<int> word_start_offsets(src_starts.size());
WebVector<int> word_end_offsets(src_ends.size());
for (wtf_size_t i = 0; i < src_starts.size(); ++i) {
word_start_offsets[i] = src_starts[i];
word_end_offsets[i] = src_ends[i];
}
starts.Swap(word_start_offsets);
ends.Swap(word_end_offsets);
}
bool WebAXObject::IsScrollableContainer() const {
if (IsDetached())
return false;
return private_->IsScrollableContainer();
}
WebPoint WebAXObject::GetScrollOffset() const {
if (IsDetached())
return WebPoint();
return private_->GetScrollOffset();
}
WebPoint WebAXObject::MinimumScrollOffset() const {
if (IsDetached())
return WebPoint();
return private_->MinimumScrollOffset();
}
WebPoint WebAXObject::MaximumScrollOffset() const {
if (IsDetached())
return WebPoint();
return private_->MaximumScrollOffset();
}
void WebAXObject::SetScrollOffset(const WebPoint& offset) const {
if (IsDetached())
return;
private_->SetScrollOffset(offset);
}
void WebAXObject::GetRelativeBounds(WebAXObject& offset_container,
WebFloatRect& bounds_in_container,
SkMatrix44& container_transform,
bool* clips_children) const {
if (IsDetached())
return;
#if DCHECK_IS_ON()
DCHECK(IsLayoutClean(private_->GetDocument()));
#endif
AXObject* container = nullptr;
FloatRect bounds;
private_->GetRelativeBounds(&container, bounds, container_transform,
clips_children);
offset_container = WebAXObject(container);
bounds_in_container = WebFloatRect(bounds);
}
bool WebAXObject::ScrollToMakeVisible() const {
if (IsDetached())
return false;
return private_->RequestScrollToMakeVisibleAction();
}
bool WebAXObject::ScrollToMakeVisibleWithSubFocus(
const WebRect& subfocus) const {
if (IsDetached())
return false;
return private_->RequestScrollToMakeVisibleWithSubFocusAction(subfocus);
}
bool WebAXObject::ScrollToGlobalPoint(const WebPoint& point) const {
if (IsDetached())
return false;
return private_->RequestScrollToGlobalPointAction(point);
}
WebAXObject::WebAXObject(AXObject* object) : private_(object) {}
WebAXObject& WebAXObject::operator=(AXObject* object) {
private_ = object;
return *this;
}
WebAXObject::operator AXObject*() const {
return private_.Get();
}
// static
WebAXObject WebAXObject::FromWebNode(const WebNode& web_node) {
WebDocument web_document = web_node.GetDocument();
const Document* doc = web_document.ConstUnwrap<Document>();
AXObjectCacheImpl* cache = ToAXObjectCacheImpl(doc->ExistingAXObjectCache());
const Node* node = web_node.ConstUnwrap<Node>();
return cache ? WebAXObject(cache->Get(node)) : WebAXObject();
}
// static
WebAXObject WebAXObject::FromWebDocument(const WebDocument& web_document) {
const Document* document = web_document.ConstUnwrap<Document>();
AXObjectCacheImpl* cache =
ToAXObjectCacheImpl(document->ExistingAXObjectCache());
return cache ? WebAXObject(cache->GetOrCreate(document->GetLayoutView()))
: WebAXObject();
}
// static
WebAXObject WebAXObject::FromWebDocumentByID(const WebDocument& web_document,
int ax_id) {
const Document* document = web_document.ConstUnwrap<Document>();
AXObjectCacheImpl* cache =
ToAXObjectCacheImpl(document->ExistingAXObjectCache());
return cache ? WebAXObject(cache->ObjectFromAXID(ax_id)) : WebAXObject();
}
// static
WebAXObject WebAXObject::FromWebDocumentFocused(
const WebDocument& web_document) {
const Document* document = web_document.ConstUnwrap<Document>();
AXObjectCacheImpl* cache =
ToAXObjectCacheImpl(document->ExistingAXObjectCache());
return cache ? WebAXObject(cache->FocusedObject()) : WebAXObject();
}
} // namespace blink