Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(940)

Unified Diff: third_party/WebKit/Source/modules/accessibility/AXObject.cpp

Issue 2858493002: Rename AXObject to AXObjectImpl in modules/ and web/ (Closed)
Patch Set: Fixed rebase Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/WebKit/Source/modules/accessibility/AXObject.cpp
diff --git a/third_party/WebKit/Source/modules/accessibility/AXObject.cpp b/third_party/WebKit/Source/modules/accessibility/AXObject.cpp
deleted file mode 100644
index 2cae448cea5924e6a4d2b86e6dc2643618255bf7..0000000000000000000000000000000000000000
--- a/third_party/WebKit/Source/modules/accessibility/AXObject.cpp
+++ /dev/null
@@ -1,1871 +0,0 @@
-/*
- * Copyright (C) 2008, 2009, 2011 Apple 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:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. 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.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "modules/accessibility/AXObject.h"
-
-#include "SkMatrix44.h"
-#include "core/InputTypeNames.h"
-#include "core/css/resolver/StyleResolver.h"
-#include "core/dom/AccessibleNode.h"
-#include "core/dom/DocumentUserGestureToken.h"
-#include "core/editing/EditingUtilities.h"
-#include "core/editing/VisibleUnits.h"
-#include "core/frame/FrameView.h"
-#include "core/frame/LocalFrame.h"
-#include "core/frame/Settings.h"
-#include "core/html/HTMLDialogElement.h"
-#include "core/html/HTMLFrameOwnerElement.h"
-#include "core/html/HTMLInputElement.h"
-#include "core/html/parser/HTMLParserIdioms.h"
-#include "core/layout/LayoutBoxModelObject.h"
-#include "modules/accessibility/AXObjectCacheImpl.h"
-#include "platform/UserGestureIndicator.h"
-#include "platform/text/PlatformLocale.h"
-#include "platform/wtf/HashSet.h"
-#include "platform/wtf/StdLibExtras.h"
-#include "platform/wtf/text/WTFString.h"
-
-using blink::WebLocalizedString;
-
-namespace blink {
-
-using namespace HTMLNames;
-
-namespace {
-typedef HashMap<String, AccessibilityRole, CaseFoldingHash> ARIARoleMap;
-typedef HashSet<String, CaseFoldingHash> ARIAWidgetSet;
-
-struct RoleEntry {
- const char* aria_role;
- AccessibilityRole webcore_role;
-};
-
-const RoleEntry kRoles[] = {{"alert", kAlertRole},
- {"alertdialog", kAlertDialogRole},
- {"application", kApplicationRole},
- {"article", kArticleRole},
- {"banner", kBannerRole},
- {"button", kButtonRole},
- {"cell", kCellRole},
- {"checkbox", kCheckBoxRole},
- {"columnheader", kColumnHeaderRole},
- {"combobox", kComboBoxRole},
- {"complementary", kComplementaryRole},
- {"contentinfo", kContentInfoRole},
- {"definition", kDefinitionRole},
- {"dialog", kDialogRole},
- {"directory", kDirectoryRole},
- {"document", kDocumentRole},
- {"feed", kFeedRole},
- {"figure", kFigureRole},
- {"form", kFormRole},
- {"grid", kGridRole},
- {"gridcell", kCellRole},
- {"group", kGroupRole},
- {"heading", kHeadingRole},
- {"img", kImageRole},
- {"link", kLinkRole},
- {"list", kListRole},
- {"listbox", kListBoxRole},
- {"listitem", kListItemRole},
- {"log", kLogRole},
- {"main", kMainRole},
- {"marquee", kMarqueeRole},
- {"math", kMathRole},
- {"menu", kMenuRole},
- {"menubar", kMenuBarRole},
- {"menuitem", kMenuItemRole},
- {"menuitemcheckbox", kMenuItemCheckBoxRole},
- {"menuitemradio", kMenuItemRadioRole},
- {"navigation", kNavigationRole},
- {"none", kNoneRole},
- {"note", kNoteRole},
- {"option", kListBoxOptionRole},
- {"presentation", kPresentationalRole},
- {"progressbar", kProgressIndicatorRole},
- {"radio", kRadioButtonRole},
- {"radiogroup", kRadioGroupRole},
- {"region", kRegionRole},
- {"row", kRowRole},
- {"rowheader", kRowHeaderRole},
- {"scrollbar", kScrollBarRole},
- {"search", kSearchRole},
- {"searchbox", kSearchBoxRole},
- {"separator", kSplitterRole},
- {"slider", kSliderRole},
- {"spinbutton", kSpinButtonRole},
- {"status", kStatusRole},
- {"switch", kSwitchRole},
- {"tab", kTabRole},
- {"table", kTableRole},
- {"tablist", kTabListRole},
- {"tabpanel", kTabPanelRole},
- {"term", kTermRole},
- {"text", kStaticTextRole},
- {"textbox", kTextFieldRole},
- {"timer", kTimerRole},
- {"toolbar", kToolbarRole},
- {"tooltip", kUserInterfaceTooltipRole},
- {"tree", kTreeRole},
- {"treegrid", kTreeGridRole},
- {"treeitem", kTreeItemRole}};
-
-struct InternalRoleEntry {
- AccessibilityRole webcore_role;
- const char* internal_role_name;
-};
-
-const InternalRoleEntry kInternalRoles[] = {
- {kUnknownRole, "Unknown"},
- {kAbbrRole, "Abbr"},
- {kAlertDialogRole, "AlertDialog"},
- {kAlertRole, "Alert"},
- {kAnchorRole, "Anchor"},
- {kAnnotationRole, "Annotation"},
- {kApplicationRole, "Application"},
- {kArticleRole, "Article"},
- {kAudioRole, "Audio"},
- {kBannerRole, "Banner"},
- {kBlockquoteRole, "Blockquote"},
- // TODO(nektar): Delete busy_indicator role. It's used nowhere.
- {kBusyIndicatorRole, "BusyIndicator"},
- {kButtonRole, "Button"},
- {kCanvasRole, "Canvas"},
- {kCaptionRole, "Caption"},
- {kCellRole, "Cell"},
- {kCheckBoxRole, "CheckBox"},
- {kColorWellRole, "ColorWell"},
- {kColumnHeaderRole, "ColumnHeader"},
- {kColumnRole, "Column"},
- {kComboBoxRole, "ComboBox"},
- {kComplementaryRole, "Complementary"},
- {kContentInfoRole, "ContentInfo"},
- {kDateRole, "Date"},
- {kDateTimeRole, "DateTime"},
- {kDefinitionRole, "Definition"},
- {kDescriptionListDetailRole, "DescriptionListDetail"},
- {kDescriptionListRole, "DescriptionList"},
- {kDescriptionListTermRole, "DescriptionListTerm"},
- {kDetailsRole, "Details"},
- {kDialogRole, "Dialog"},
- {kDirectoryRole, "Directory"},
- {kDisclosureTriangleRole, "DisclosureTriangle"},
- {kDivRole, "Div"},
- {kDocumentRole, "Document"},
- {kEmbeddedObjectRole, "EmbeddedObject"},
- {kFeedRole, "feed"},
- {kFigcaptionRole, "Figcaption"},
- {kFigureRole, "Figure"},
- {kFooterRole, "Footer"},
- {kFormRole, "Form"},
- {kGridRole, "Grid"},
- {kGroupRole, "Group"},
- {kHeadingRole, "Heading"},
- {kIframePresentationalRole, "IframePresentational"},
- {kIframeRole, "Iframe"},
- {kIgnoredRole, "Ignored"},
- {kImageMapLinkRole, "ImageMapLink"},
- {kImageMapRole, "ImageMap"},
- {kImageRole, "Image"},
- {kInlineTextBoxRole, "InlineTextBox"},
- {kInputTimeRole, "InputTime"},
- {kLabelRole, "Label"},
- {kLegendRole, "Legend"},
- {kLinkRole, "Link"},
- {kLineBreakRole, "LineBreak"},
- {kListBoxOptionRole, "ListBoxOption"},
- {kListBoxRole, "ListBox"},
- {kListItemRole, "ListItem"},
- {kListMarkerRole, "ListMarker"},
- {kListRole, "List"},
- {kLogRole, "Log"},
- {kMainRole, "Main"},
- {kMarkRole, "Mark"},
- {kMarqueeRole, "Marquee"},
- {kMathRole, "Math"},
- {kMenuBarRole, "MenuBar"},
- {kMenuButtonRole, "MenuButton"},
- {kMenuItemRole, "MenuItem"},
- {kMenuItemCheckBoxRole, "MenuItemCheckBox"},
- {kMenuItemRadioRole, "MenuItemRadio"},
- {kMenuListOptionRole, "MenuListOption"},
- {kMenuListPopupRole, "MenuListPopup"},
- {kMenuRole, "Menu"},
- {kMeterRole, "Meter"},
- {kNavigationRole, "Navigation"},
- {kNoneRole, "None"},
- {kNoteRole, "Note"},
- {kOutlineRole, "Outline"},
- {kParagraphRole, "Paragraph"},
- {kPopUpButtonRole, "PopUpButton"},
- {kPreRole, "Pre"},
- {kPresentationalRole, "Presentational"},
- {kProgressIndicatorRole, "ProgressIndicator"},
- {kRadioButtonRole, "RadioButton"},
- {kRadioGroupRole, "RadioGroup"},
- {kRegionRole, "Region"},
- {kRootWebAreaRole, "RootWebArea"},
- {kRowHeaderRole, "RowHeader"},
- {kRowRole, "Row"},
- {kRubyRole, "Ruby"},
- {kRulerRole, "Ruler"},
- {kSVGRootRole, "SVGRoot"},
- {kScrollAreaRole, "ScrollArea"},
- {kScrollBarRole, "ScrollBar"},
- {kSeamlessWebAreaRole, "SeamlessWebArea"},
- {kSearchRole, "Search"},
- {kSearchBoxRole, "SearchBox"},
- {kSliderRole, "Slider"},
- {kSliderThumbRole, "SliderThumb"},
- {kSpinButtonPartRole, "SpinButtonPart"},
- {kSpinButtonRole, "SpinButton"},
- {kSplitterRole, "Splitter"},
- {kStaticTextRole, "StaticText"},
- {kStatusRole, "Status"},
- {kSwitchRole, "Switch"},
- {kTabGroupRole, "TabGroup"},
- {kTabListRole, "TabList"},
- {kTabPanelRole, "TabPanel"},
- {kTabRole, "Tab"},
- {kTableHeaderContainerRole, "TableHeaderContainer"},
- {kTableRole, "Table"},
- {kTermRole, "Term"},
- {kTextFieldRole, "TextField"},
- {kTimeRole, "Time"},
- {kTimerRole, "Timer"},
- {kToggleButtonRole, "ToggleButton"},
- {kToolbarRole, "Toolbar"},
- {kTreeGridRole, "TreeGrid"},
- {kTreeItemRole, "TreeItem"},
- {kTreeRole, "Tree"},
- {kUserInterfaceTooltipRole, "UserInterfaceTooltip"},
- {kVideoRole, "Video"},
- {kWebAreaRole, "WebArea"},
- {kWindowRole, "Window"}};
-
-static_assert(WTF_ARRAY_LENGTH(kInternalRoles) == kNumRoles,
- "Not all internal roles have an entry in internalRoles array");
-
-// Roles which we need to map in the other direction
-const RoleEntry kReverseRoles[] = {
- {"button", kToggleButtonRole}, {"combobox", kPopUpButtonRole},
- {"contentinfo", kFooterRole}, {"menuitem", kMenuButtonRole},
- {"menuitem", kMenuListOptionRole}, {"progressbar", kMeterRole},
- {"textbox", kTextFieldRole}};
-
-static ARIARoleMap* CreateARIARoleMap() {
- ARIARoleMap* role_map = new ARIARoleMap;
-
- for (size_t i = 0; i < WTF_ARRAY_LENGTH(kRoles); ++i)
- role_map->Set(String(kRoles[i].aria_role), kRoles[i].webcore_role);
- return role_map;
-}
-
-static Vector<AtomicString>* CreateRoleNameVector() {
- Vector<AtomicString>* role_name_vector = new Vector<AtomicString>(kNumRoles);
- for (int i = 0; i < kNumRoles; i++)
- (*role_name_vector)[i] = g_null_atom;
-
- for (size_t i = 0; i < WTF_ARRAY_LENGTH(kRoles); ++i)
- (*role_name_vector)[kRoles[i].webcore_role] =
- AtomicString(kRoles[i].aria_role);
-
- for (size_t i = 0; i < WTF_ARRAY_LENGTH(kReverseRoles); ++i)
- (*role_name_vector)[kReverseRoles[i].webcore_role] =
- AtomicString(kReverseRoles[i].aria_role);
-
- return role_name_vector;
-}
-
-static Vector<AtomicString>* CreateInternalRoleNameVector() {
- Vector<AtomicString>* internal_role_name_vector =
- new Vector<AtomicString>(kNumRoles);
- for (size_t i = 0; i < WTF_ARRAY_LENGTH(kInternalRoles); i++)
- (*internal_role_name_vector)[kInternalRoles[i].webcore_role] =
- AtomicString(kInternalRoles[i].internal_role_name);
-
- return internal_role_name_vector;
-}
-
-const char* g_aria_widgets[] = {
- // From http://www.w3.org/TR/wai-aria/roles#widget_roles
- "alert", "alertdialog", "button", "checkbox", "dialog", "gridcell", "link",
- "log", "marquee", "menuitem", "menuitemcheckbox", "menuitemradio", "option",
- "progressbar", "radio", "scrollbar", "slider", "spinbutton", "status",
- "tab", "tabpanel", "textbox", "timer", "tooltip", "treeitem",
- // Composite user interface widgets.
- // This list is also from the w3.org site referenced above.
- "combobox", "grid", "listbox", "menu", "menubar", "radiogroup", "tablist",
- "tree", "treegrid"};
-
-static ARIAWidgetSet* CreateARIARoleWidgetSet() {
- ARIAWidgetSet* widget_set = new HashSet<String, CaseFoldingHash>();
- for (size_t i = 0; i < WTF_ARRAY_LENGTH(g_aria_widgets); ++i)
- widget_set->insert(String(g_aria_widgets[i]));
- return widget_set;
-}
-
-const char* g_aria_interactive_widget_attributes[] = {
- // These attributes implicitly indicate the given widget is interactive.
- // From http://www.w3.org/TR/wai-aria/states_and_properties#attrs_widgets
- "aria-activedescendant", "aria-checked", "aria-controls",
- "aria-disabled", // If it's disabled, it can be made interactive.
- "aria-expanded", "aria-haspopup", "aria-multiselectable",
- "aria-pressed", "aria-required", "aria-selected"};
-
-HTMLDialogElement* GetActiveDialogElement(Node* node) {
- return node->GetDocument().ActiveModalDialog();
-}
-
-} // namespace
-
-unsigned AXObject::number_of_live_ax_objects_ = 0;
-
-AXObject::AXObject(AXObjectCacheImpl& ax_object_cache)
- : id_(0),
- have_children_(false),
- role_(kUnknownRole),
- last_known_is_ignored_value_(kDefaultBehavior),
- explicit_container_id_(0),
- parent_(nullptr),
- last_modification_count_(-1),
- cached_is_ignored_(false),
- cached_is_inert_or_aria_hidden_(false),
- cached_is_descendant_of_leaf_node_(false),
- cached_is_descendant_of_disabled_node_(false),
- cached_has_inherited_presentational_role_(false),
- cached_is_presentational_child_(false),
- cached_ancestor_exposes_active_descendant_(false),
- cached_live_region_root_(nullptr),
- ax_object_cache_(&ax_object_cache) {
- ++number_of_live_ax_objects_;
-}
-
-AXObject::~AXObject() {
- DCHECK(IsDetached());
- --number_of_live_ax_objects_;
-}
-
-void AXObject::Detach() {
- // Clear any children and call detachFromParent on them so that
- // no children are left with dangling pointers to their parent.
- ClearChildren();
-
- ax_object_cache_ = nullptr;
-}
-
-bool AXObject::IsDetached() const {
- return !ax_object_cache_;
-}
-
-const AtomicString& AXObject::GetAOMPropertyOrARIAAttribute(
- AOMStringProperty property) const {
- Node* node = this->GetNode();
- if (!node || !node->IsElementNode())
- return g_null_atom;
-
- return AccessibleNode::GetPropertyOrARIAAttribute(ToElement(node), property);
-}
-
-bool AXObject::IsARIATextControl() const {
- return AriaRoleAttribute() == kTextFieldRole ||
- AriaRoleAttribute() == kSearchBoxRole ||
- AriaRoleAttribute() == kComboBoxRole;
-}
-
-bool AXObject::IsButton() const {
- AccessibilityRole role = RoleValue();
-
- return role == kButtonRole || role == kPopUpButtonRole ||
- role == kToggleButtonRole;
-}
-
-bool AXObject::IsCheckable() const {
- switch (RoleValue()) {
- case kCheckBoxRole:
- case kMenuItemCheckBoxRole:
- case kMenuItemRadioRole:
- case kRadioButtonRole:
- case kSwitchRole:
- return true;
- default:
- return false;
- }
-}
-
-// Why this is here instead of AXNodeObject:
-// Because an AXMenuListOption (<option>) can
-// have an ARIA role of menuitemcheckbox/menuitemradio
-// yet does not inherit from AXNodeObject
-AccessibilityButtonState AXObject::CheckedState() const {
- if (!IsCheckable())
- return kButtonStateOff;
-
- const AtomicString& checkedAttribute =
- GetAOMPropertyOrARIAAttribute(AOMStringProperty::kChecked);
- if (checkedAttribute) {
- if (EqualIgnoringASCIICase(checkedAttribute, "true"))
- return kButtonStateOn;
-
- if (EqualIgnoringASCIICase(checkedAttribute, "mixed")) {
- // Only checkboxes and radios should support the mixed state.
- const AccessibilityRole role = RoleValue();
- if (role == kCheckBoxRole || role == kMenuItemCheckBoxRole ||
- role == kRadioButtonRole || role == kMenuItemRadioRole)
- return kButtonStateMixed;
- }
-
- return kButtonStateOff;
- }
-
- const Node* node = this->GetNode();
- if (!node)
- return kButtonStateOff;
-
- if (IsNativeInputInMixedState(node))
- return kButtonStateMixed;
-
- if (isHTMLInputElement(*node) &&
- toHTMLInputElement(*node).ShouldAppearChecked()) {
- return kButtonStateOn;
- }
-
- return kButtonStateOff;
-}
-
-bool AXObject::IsNativeInputInMixedState(const Node* node) {
- if (!isHTMLInputElement(node))
- return false;
-
- const HTMLInputElement* input = toHTMLInputElement(node);
- const auto inputType = input->type();
- if (inputType != InputTypeNames::checkbox &&
- inputType != InputTypeNames::radio)
- return false;
- return input->ShouldAppearIndeterminate();
-}
-
-bool AXObject::IsLandmarkRelated() const {
- switch (RoleValue()) {
- case kApplicationRole:
- case kArticleRole:
- case kBannerRole:
- case kComplementaryRole:
- case kContentInfoRole:
- case kFooterRole:
- case kFormRole:
- case kMainRole:
- case kNavigationRole:
- case kRegionRole:
- case kSearchRole:
- return true;
- default:
- return false;
- }
-}
-
-bool AXObject::IsMenuRelated() const {
- switch (RoleValue()) {
- case kMenuRole:
- case kMenuBarRole:
- case kMenuButtonRole:
- case kMenuItemRole:
- case kMenuItemCheckBoxRole:
- case kMenuItemRadioRole:
- return true;
- default:
- return false;
- }
-}
-
-bool AXObject::IsPasswordFieldAndShouldHideValue() const {
- Settings* settings = GetDocument()->GetSettings();
- if (!settings || settings->GetAccessibilityPasswordValuesEnabled())
- return false;
-
- return IsPasswordField();
-}
-
-bool AXObject::IsClickable() const {
- switch (RoleValue()) {
- case kButtonRole:
- case kCheckBoxRole:
- case kColorWellRole:
- case kComboBoxRole:
- case kImageMapLinkRole:
- case kLinkRole:
- case kListBoxOptionRole:
- case kMenuButtonRole:
- case kPopUpButtonRole:
- case kRadioButtonRole:
- case kSpinButtonRole:
- case kTabRole:
- case kTextFieldRole:
- case kToggleButtonRole:
- return true;
- default:
- return false;
- }
-}
-
-bool AXObject::AccessibilityIsIgnored() const {
- UpdateCachedAttributeValuesIfNeeded();
- return cached_is_ignored_;
-}
-
-void AXObject::UpdateCachedAttributeValuesIfNeeded() const {
- if (IsDetached())
- return;
-
- AXObjectCacheImpl& cache = AxObjectCache();
-
- if (cache.ModificationCount() == last_modification_count_)
- return;
-
- last_modification_count_ = cache.ModificationCount();
- cached_background_color_ = ComputeBackgroundColor();
- cached_is_inert_or_aria_hidden_ = ComputeIsInertOrAriaHidden();
- cached_is_descendant_of_leaf_node_ = (LeafNodeAncestor() != 0);
- cached_is_descendant_of_disabled_node_ = (DisabledAncestor() != 0);
- cached_has_inherited_presentational_role_ =
- (InheritsPresentationalRoleFrom() != 0);
- cached_is_presentational_child_ =
- (AncestorForWhichThisIsAPresentationalChild() != 0);
- cached_is_ignored_ = ComputeAccessibilityIsIgnored();
- cached_live_region_root_ =
- IsLiveRegion()
- ? const_cast<AXObject*>(this)
- : (ParentObjectIfExists() ? ParentObjectIfExists()->LiveRegionRoot()
- : 0);
- cached_ancestor_exposes_active_descendant_ =
- ComputeAncestorExposesActiveDescendant();
-}
-
-bool AXObject::AccessibilityIsIgnoredByDefault(
- IgnoredReasons* ignored_reasons) const {
- return DefaultObjectInclusion(ignored_reasons) == kIgnoreObject;
-}
-
-AXObjectInclusion AXObject::AccessibilityPlatformIncludesObject() const {
- if (IsMenuListPopup() || IsMenuListOption())
- return kIncludeObject;
-
- return kDefaultBehavior;
-}
-
-AXObjectInclusion AXObject::DefaultObjectInclusion(
- IgnoredReasons* ignored_reasons) const {
- if (IsInertOrAriaHidden()) {
- if (ignored_reasons)
- ComputeIsInertOrAriaHidden(ignored_reasons);
- return kIgnoreObject;
- }
-
- if (IsPresentationalChild()) {
- if (ignored_reasons) {
- AXObject* ancestor = AncestorForWhichThisIsAPresentationalChild();
- ignored_reasons->push_back(
- IgnoredReason(kAXAncestorDisallowsChild, ancestor));
- }
- return kIgnoreObject;
- }
-
- return AccessibilityPlatformIncludesObject();
-}
-
-bool AXObject::IsInertOrAriaHidden() const {
- UpdateCachedAttributeValuesIfNeeded();
- return cached_is_inert_or_aria_hidden_;
-}
-
-bool AXObject::ComputeIsInertOrAriaHidden(
- IgnoredReasons* ignored_reasons) const {
- if (GetNode()) {
- if (GetNode()->IsInert()) {
- if (ignored_reasons) {
- HTMLDialogElement* dialog = GetActiveDialogElement(GetNode());
- if (dialog) {
- AXObject* dialog_object = AxObjectCache().GetOrCreate(dialog);
- if (dialog_object)
- ignored_reasons->push_back(
- IgnoredReason(kAXActiveModalDialog, dialog_object));
- else
- ignored_reasons->push_back(IgnoredReason(kAXInert));
- } else {
- // TODO(aboxhall): handle inert attribute if it eventuates
- ignored_reasons->push_back(IgnoredReason(kAXInert));
- }
- }
- return true;
- }
- } else {
- AXObject* parent = ParentObject();
- if (parent && parent->IsInertOrAriaHidden()) {
- if (ignored_reasons)
- parent->ComputeIsInertOrAriaHidden(ignored_reasons);
- return true;
- }
- }
-
- const AXObject* hidden_root = AriaHiddenRoot();
- if (hidden_root) {
- if (ignored_reasons) {
- if (hidden_root == this)
- ignored_reasons->push_back(IgnoredReason(kAXAriaHidden));
- else
- ignored_reasons->push_back(
- IgnoredReason(kAXAriaHiddenRoot, hidden_root));
- }
- return true;
- }
-
- return false;
-}
-
-bool AXObject::IsDescendantOfLeafNode() const {
- UpdateCachedAttributeValuesIfNeeded();
- return cached_is_descendant_of_leaf_node_;
-}
-
-AXObject* AXObject::LeafNodeAncestor() const {
- if (AXObject* parent = ParentObject()) {
- if (!parent->CanHaveChildren())
- return parent;
-
- return parent->LeafNodeAncestor();
- }
-
- return 0;
-}
-
-const AXObject* AXObject::AriaHiddenRoot() const {
- for (const AXObject* object = this; object; object = object->ParentObject()) {
- if (EqualIgnoringASCIICase(object->GetAttribute(aria_hiddenAttr), "true"))
- return object;
- }
-
- return 0;
-}
-
-bool AXObject::IsDescendantOfDisabledNode() const {
- UpdateCachedAttributeValuesIfNeeded();
- return cached_is_descendant_of_disabled_node_;
-}
-
-const AXObject* AXObject::DisabledAncestor() const {
- const AtomicString& disabled = GetAttribute(aria_disabledAttr);
- if (EqualIgnoringASCIICase(disabled, "true"))
- return this;
- if (EqualIgnoringASCIICase(disabled, "false"))
- return 0;
-
- if (AXObject* parent = ParentObject())
- return parent->DisabledAncestor();
-
- return 0;
-}
-
-bool AXObject::LastKnownIsIgnoredValue() {
- if (last_known_is_ignored_value_ == kDefaultBehavior)
- last_known_is_ignored_value_ =
- AccessibilityIsIgnored() ? kIgnoreObject : kIncludeObject;
-
- return last_known_is_ignored_value_ == kIgnoreObject;
-}
-
-void AXObject::SetLastKnownIsIgnoredValue(bool is_ignored) {
- last_known_is_ignored_value_ = is_ignored ? kIgnoreObject : kIncludeObject;
-}
-
-bool AXObject::HasInheritedPresentationalRole() const {
- UpdateCachedAttributeValuesIfNeeded();
- return cached_has_inherited_presentational_role_;
-}
-
-bool AXObject::IsPresentationalChild() const {
- UpdateCachedAttributeValuesIfNeeded();
- return cached_is_presentational_child_;
-}
-
-bool AXObject::AncestorExposesActiveDescendant() const {
- UpdateCachedAttributeValuesIfNeeded();
- return cached_ancestor_exposes_active_descendant_;
-}
-
-bool AXObject::ComputeAncestorExposesActiveDescendant() const {
- const AXObject* parent = ParentObjectUnignored();
- if (!parent)
- return false;
-
- if (parent->SupportsActiveDescendant() &&
- !parent->GetAttribute(aria_activedescendantAttr).IsEmpty()) {
- return true;
- }
-
- return parent->AncestorExposesActiveDescendant();
-}
-
-// Simplify whitespace, but preserve a single leading and trailing whitespace
-// character if it's present.
-// static
-String AXObject::CollapseWhitespace(const String& str) {
- StringBuilder result;
- if (!str.IsEmpty() && IsHTMLSpace<UChar>(str[0]))
- result.Append(' ');
- result.Append(str.SimplifyWhiteSpace(IsHTMLSpace<UChar>));
- if (!str.IsEmpty() && IsHTMLSpace<UChar>(str[str.length() - 1]))
- result.Append(' ');
- return result.ToString();
-}
-
-String AXObject::ComputedName() const {
- AXNameFrom name_from;
- AXObject::AXObjectVector name_objects;
- return GetName(name_from, &name_objects);
-}
-
-String AXObject::GetName(AXNameFrom& name_from,
- AXObject::AXObjectVector* name_objects) const {
- HeapHashSet<Member<const AXObject>> visited;
- AXRelatedObjectVector related_objects;
- String text = TextAlternative(false, false, visited, name_from,
- &related_objects, nullptr);
-
- AccessibilityRole role = RoleValue();
- if (!GetNode() || (!isHTMLBRElement(GetNode()) && role != kStaticTextRole &&
- role != kInlineTextBoxRole))
- text = CollapseWhitespace(text);
-
- if (name_objects) {
- name_objects->clear();
- for (size_t i = 0; i < related_objects.size(); i++)
- name_objects->push_back(related_objects[i]->object);
- }
-
- return text;
-}
-
-String AXObject::GetName(NameSources* name_sources) const {
- AXObjectSet visited;
- AXNameFrom tmp_name_from;
- AXRelatedObjectVector tmp_related_objects;
- String text = TextAlternative(false, false, visited, tmp_name_from,
- &tmp_related_objects, name_sources);
- text = text.SimplifyWhiteSpace(IsHTMLSpace<UChar>);
- return text;
-}
-
-String AXObject::RecursiveTextAlternative(const AXObject& ax_obj,
- bool in_aria_labelled_by_traversal,
- AXObjectSet& visited) {
- if (visited.Contains(&ax_obj) && !in_aria_labelled_by_traversal)
- return String();
-
- AXNameFrom tmp_name_from;
- return ax_obj.TextAlternative(true, in_aria_labelled_by_traversal, visited,
- tmp_name_from, nullptr, nullptr);
-}
-
-bool AXObject::IsHiddenForTextAlternativeCalculation() const {
- if (EqualIgnoringASCIICase(GetAttribute(aria_hiddenAttr), "false"))
- return false;
-
- if (GetLayoutObject())
- return GetLayoutObject()->Style()->Visibility() != EVisibility::kVisible;
-
- // This is an obscure corner case: if a node has no LayoutObject, that means
- // it's not rendered, but we still may be exploring it as part of a text
- // alternative calculation, for example if it was explicitly referenced by
- // aria-labelledby. So we need to explicitly call the style resolver to check
- // whether it's invisible or display:none, rather than relying on the style
- // cached in the LayoutObject.
- Document* document = GetDocument();
- if (!document || !document->GetFrame())
- return false;
- if (Node* node = GetNode()) {
- if (node->isConnected() && node->IsElementNode()) {
- RefPtr<ComputedStyle> style =
- document->EnsureStyleResolver().StyleForElement(ToElement(node));
- return style->Display() == EDisplay::kNone ||
- style->Visibility() != EVisibility::kVisible;
- }
- }
- return false;
-}
-
-String AXObject::AriaTextAlternative(bool recursive,
- bool in_aria_labelled_by_traversal,
- AXObjectSet& visited,
- AXNameFrom& name_from,
- AXRelatedObjectVector* related_objects,
- NameSources* name_sources,
- bool* found_text_alternative) const {
- String text_alternative;
- bool already_visited = visited.Contains(this);
- visited.insert(this);
-
- // Step 2A from: http://www.w3.org/TR/accname-aam-1.1
- // If you change this logic, update AXNodeObject::nameFromLabelElement, too.
- if (!in_aria_labelled_by_traversal &&
- IsHiddenForTextAlternativeCalculation()) {
- *found_text_alternative = true;
- return String();
- }
-
- // Step 2B from: http://www.w3.org/TR/accname-aam-1.1
- // If you change this logic, update AXNodeObject::nameFromLabelElement, too.
- if (!in_aria_labelled_by_traversal && !already_visited) {
- const QualifiedName& attr =
- HasAttribute(aria_labeledbyAttr) && !HasAttribute(aria_labelledbyAttr)
- ? aria_labeledbyAttr
- : aria_labelledbyAttr;
- name_from = kAXNameFromRelatedElement;
- if (name_sources) {
- name_sources->push_back(NameSource(*found_text_alternative, attr));
- name_sources->back().type = name_from;
- }
-
- const AtomicString& aria_labelledby = GetAttribute(attr);
- if (!aria_labelledby.IsNull()) {
- if (name_sources)
- name_sources->back().attribute_value = aria_labelledby;
-
- // Operate on a copy of |visited| so that if |nameSources| is not null,
- // the set of visited objects is preserved unmodified for future
- // calculations.
- AXObjectSet visited_copy = visited;
- text_alternative = TextFromAriaLabelledby(visited_copy, related_objects);
- if (!text_alternative.IsNull()) {
- if (name_sources) {
- NameSource& source = name_sources->back();
- source.type = name_from;
- source.related_objects = *related_objects;
- source.text = text_alternative;
- *found_text_alternative = true;
- } else {
- *found_text_alternative = true;
- return text_alternative;
- }
- } else if (name_sources) {
- name_sources->back().invalid = true;
- }
- }
- }
-
- // Step 2C from: http://www.w3.org/TR/accname-aam-1.1
- // If you change this logic, update AXNodeObject::nameFromLabelElement, too.
- name_from = kAXNameFromAttribute;
- if (name_sources) {
- name_sources->push_back(
- NameSource(*found_text_alternative, aria_labelAttr));
- name_sources->back().type = name_from;
- }
- const AtomicString& aria_label =
- GetAOMPropertyOrARIAAttribute(AOMStringProperty::kLabel);
- if (!aria_label.IsEmpty()) {
- text_alternative = aria_label;
-
- if (name_sources) {
- NameSource& source = name_sources->back();
- source.text = text_alternative;
- source.attribute_value = aria_label;
- *found_text_alternative = true;
- } else {
- *found_text_alternative = true;
- return text_alternative;
- }
- }
-
- return text_alternative;
-}
-
-String AXObject::TextFromElements(
- bool in_aria_labelledby_traversal,
- AXObjectSet& visited,
- HeapVector<Member<Element>>& elements,
- AXRelatedObjectVector* related_objects) const {
- StringBuilder accumulated_text;
- bool found_valid_element = false;
- AXRelatedObjectVector local_related_objects;
-
- for (const auto& element : elements) {
- AXObject* ax_element = AxObjectCache().GetOrCreate(element);
- if (ax_element) {
- found_valid_element = true;
-
- String result = RecursiveTextAlternative(
- *ax_element, in_aria_labelledby_traversal, visited);
- local_related_objects.push_back(
- new NameSourceRelatedObject(ax_element, result));
- if (!result.IsEmpty()) {
- if (!accumulated_text.IsEmpty())
- accumulated_text.Append(' ');
- accumulated_text.Append(result);
- }
- }
- }
- if (!found_valid_element)
- return String();
- if (related_objects)
- *related_objects = local_related_objects;
- return accumulated_text.ToString();
-}
-
-void AXObject::TokenVectorFromAttribute(Vector<String>& tokens,
- const QualifiedName& attribute) const {
- Node* node = this->GetNode();
- if (!node || !node->IsElementNode())
- return;
-
- String attribute_value = GetAttribute(attribute).GetString();
- if (attribute_value.IsEmpty())
- return;
-
- attribute_value.SimplifyWhiteSpace();
- attribute_value.Split(' ', tokens);
-}
-
-void AXObject::ElementsFromAttribute(HeapVector<Member<Element>>& elements,
- const QualifiedName& attribute) const {
- Vector<String> ids;
- TokenVectorFromAttribute(ids, attribute);
- if (ids.IsEmpty())
- return;
-
- TreeScope& scope = GetNode()->GetTreeScope();
- for (const auto& id : ids) {
- if (Element* id_element = scope.getElementById(AtomicString(id)))
- elements.push_back(id_element);
- }
-}
-
-void AXObject::AriaLabelledbyElementVector(
- HeapVector<Member<Element>>& elements) const {
- // Try both spellings, but prefer aria-labelledby, which is the official spec.
- ElementsFromAttribute(elements, aria_labelledbyAttr);
- if (!elements.size())
- ElementsFromAttribute(elements, aria_labeledbyAttr);
-}
-
-String AXObject::TextFromAriaLabelledby(
- AXObjectSet& visited,
- AXRelatedObjectVector* related_objects) const {
- HeapVector<Member<Element>> elements;
- AriaLabelledbyElementVector(elements);
- return TextFromElements(true, visited, elements, related_objects);
-}
-
-String AXObject::TextFromAriaDescribedby(
- AXRelatedObjectVector* related_objects) const {
- AXObjectSet visited;
- HeapVector<Member<Element>> elements;
- ElementsFromAttribute(elements, aria_describedbyAttr);
- return TextFromElements(true, visited, elements, related_objects);
-}
-
-RGBA32 AXObject::BackgroundColor() const {
- UpdateCachedAttributeValuesIfNeeded();
- return cached_background_color_;
-}
-
-AccessibilityOrientation AXObject::Orientation() const {
- // In ARIA 1.1, the default value for aria-orientation changed from
- // horizontal to undefined.
- return kAccessibilityOrientationUndefined;
-}
-
-AXSupportedAction AXObject::Action() const {
- if (!ActionElement())
- return AXSupportedAction::kNone;
-
- switch (RoleValue()) {
- case kButtonRole:
- case kToggleButtonRole:
- return AXSupportedAction::kPress;
- case kTextFieldRole:
- return AXSupportedAction::kActivate;
- case kRadioButtonRole:
- return AXSupportedAction::kSelect;
- case kCheckBoxRole:
- case kSwitchRole:
- return CheckedState() == kButtonStateOff ? AXSupportedAction::kCheck
- : AXSupportedAction::kUncheck;
- case kLinkRole:
- return AXSupportedAction::kJump;
- case kPopUpButtonRole:
- return AXSupportedAction::kOpen;
- default:
- return AXSupportedAction::kClick;
- }
-}
-
-bool AXObject::IsMultiline() const {
- Node* node = this->GetNode();
- if (!node)
- return false;
-
- if (isHTMLTextAreaElement(*node))
- return true;
-
- if (HasEditableStyle(*node))
- return true;
-
- if (!IsNativeTextControl() && !IsNonNativeTextControl())
- return false;
-
- return EqualIgnoringASCIICase(GetAttribute(aria_multilineAttr), "true");
-}
-
-bool AXObject::AriaPressedIsPresent() const {
- return !GetAttribute(aria_pressedAttr).IsEmpty();
-}
-
-bool AXObject::SupportsActiveDescendant() const {
- // According to the ARIA Spec, all ARIA composite widgets, ARIA text boxes
- // and ARIA groups should be able to expose an active descendant.
- // Implicitly, <input> and <textarea> elements should also have this ability.
- switch (AriaRoleAttribute()) {
- case kComboBoxRole:
- case kGridRole:
- case kGroupRole:
- case kListBoxRole:
- case kMenuRole:
- case kMenuBarRole:
- case kRadioGroupRole:
- case kRowRole:
- case kSearchBoxRole:
- case kTabListRole:
- case kTextFieldRole:
- case kToolbarRole:
- case kTreeRole:
- case kTreeGridRole:
- return true;
- default:
- return false;
- }
-}
-
-bool AXObject::SupportsARIAAttributes() const {
- return IsLiveRegion() || SupportsARIADragging() || SupportsARIADropping() ||
- SupportsARIAFlowTo() || SupportsARIAOwns() ||
- HasAttribute(aria_labelAttr);
-}
-
-bool AXObject::SupportsRangeValue() const {
- return IsProgressIndicator() || IsMeter() || IsSlider() || IsScrollbar() ||
- IsSpinButton();
-}
-
-bool AXObject::SupportsSetSizeAndPosInSet() const {
- AXObject* parent = ParentObject();
- if (!parent)
- return false;
-
- int role = RoleValue();
- int parent_role = parent->RoleValue();
-
- if ((role == kListBoxOptionRole && parent_role == kListBoxRole) ||
- (role == kListItemRole && parent_role == kListRole) ||
- (role == kMenuItemRole && parent_role == kMenuRole) ||
- (role == kRadioButtonRole) ||
- (role == kTabRole && parent_role == kTabListRole) ||
- (role == kTreeItemRole && parent_role == kTreeRole) ||
- (role == kTreeItemRole && parent_role == kGroupRole)) {
- return true;
- }
-
- return false;
-}
-
-int AXObject::IndexInParent() const {
- if (!ParentObject())
- return 0;
-
- const auto& siblings = ParentObject()->Children();
- int child_count = siblings.size();
-
- for (int index = 0; index < child_count; ++index) {
- if (siblings[index].Get() == this) {
- return index;
- }
- }
- return 0;
-}
-
-bool AXObject::IsLiveRegion() const {
- const AtomicString& live_region = LiveRegionStatus();
- return EqualIgnoringASCIICase(live_region, "polite") ||
- EqualIgnoringASCIICase(live_region, "assertive");
-}
-
-AXObject* AXObject::LiveRegionRoot() const {
- UpdateCachedAttributeValuesIfNeeded();
- return cached_live_region_root_;
-}
-
-const AtomicString& AXObject::ContainerLiveRegionStatus() const {
- UpdateCachedAttributeValuesIfNeeded();
- return cached_live_region_root_ ? cached_live_region_root_->LiveRegionStatus()
- : g_null_atom;
-}
-
-const AtomicString& AXObject::ContainerLiveRegionRelevant() const {
- UpdateCachedAttributeValuesIfNeeded();
- return cached_live_region_root_
- ? cached_live_region_root_->LiveRegionRelevant()
- : g_null_atom;
-}
-
-bool AXObject::ContainerLiveRegionAtomic() const {
- UpdateCachedAttributeValuesIfNeeded();
- return cached_live_region_root_ &&
- cached_live_region_root_->LiveRegionAtomic();
-}
-
-bool AXObject::ContainerLiveRegionBusy() const {
- UpdateCachedAttributeValuesIfNeeded();
- return cached_live_region_root_ && cached_live_region_root_->LiveRegionBusy();
-}
-
-AXObject* AXObject::ElementAccessibilityHitTest(const IntPoint& point) const {
- // Check if there are any mock elements that need to be handled.
- for (const auto& child : children_) {
- if (child->IsMockObject() &&
- child->GetBoundsInFrameCoordinates().Contains(point))
- return child->ElementAccessibilityHitTest(point);
- }
-
- return const_cast<AXObject*>(this);
-}
-
-const AXObject::AXObjectVector& AXObject::Children() {
- UpdateChildrenIfNecessary();
-
- return children_;
-}
-
-AXObject* AXObject::ParentObject() const {
- if (IsDetached())
- return 0;
-
- if (parent_)
- return parent_;
-
- if (AxObjectCache().IsAriaOwned(this))
- return AxObjectCache().GetAriaOwnedParent(this);
-
- return ComputeParent();
-}
-
-AXObject* AXObject::ParentObjectIfExists() const {
- if (IsDetached())
- return 0;
-
- if (parent_)
- return parent_;
-
- return ComputeParentIfExists();
-}
-
-AXObject* AXObject::ParentObjectUnignored() const {
- AXObject* parent;
- for (parent = ParentObject(); parent && parent->AccessibilityIsIgnored();
- parent = parent->ParentObject()) {
- }
-
- return parent;
-}
-
-void AXObject::UpdateChildrenIfNecessary() {
- if (!HasChildren())
- AddChildren();
-}
-
-void AXObject::ClearChildren() {
- // Detach all weak pointers from objects to their parents.
- for (const auto& child : children_)
- child->DetachFromParent();
-
- children_.clear();
- have_children_ = false;
-}
-
-Document* AXObject::GetDocument() const {
- FrameView* frame_view = DocumentFrameView();
- if (!frame_view)
- return 0;
-
- return frame_view->GetFrame().GetDocument();
-}
-
-FrameView* AXObject::DocumentFrameView() const {
- const AXObject* object = this;
- while (object && !object->IsAXLayoutObject())
- object = object->ParentObject();
-
- if (!object)
- return 0;
-
- return object->DocumentFrameView();
-}
-
-String AXObject::Language() const {
- const AtomicString& lang = GetAttribute(langAttr);
- if (!lang.IsEmpty())
- return lang;
-
- AXObject* parent = ParentObject();
-
- // As a last resort, fall back to the content language specified in the meta
- // tag.
- if (!parent) {
- Document* doc = GetDocument();
- if (doc)
- return doc->ContentLanguage();
- return g_null_atom;
- }
-
- return parent->Language();
-}
-
-bool AXObject::HasAttribute(const QualifiedName& attribute) const {
- Node* element_node = GetNode();
- if (!element_node)
- return false;
-
- if (!element_node->IsElementNode())
- return false;
-
- Element* element = ToElement(element_node);
- return element->FastHasAttribute(attribute);
-}
-
-const AtomicString& AXObject::GetAttribute(
- const QualifiedName& attribute) const {
- Node* element_node = GetNode();
- if (!element_node)
- return g_null_atom;
-
- if (!element_node->IsElementNode())
- return g_null_atom;
-
- Element* element = ToElement(element_node);
- return element->FastGetAttribute(attribute);
-}
-
-//
-// Scrollable containers.
-//
-
-bool AXObject::IsScrollableContainer() const {
- return !!GetScrollableAreaIfScrollable();
-}
-
-IntPoint AXObject::GetScrollOffset() const {
- ScrollableArea* area = GetScrollableAreaIfScrollable();
- if (!area)
- return IntPoint();
-
- return IntPoint(area->ScrollOffsetInt().Width(),
- area->ScrollOffsetInt().Height());
-}
-
-IntPoint AXObject::MinimumScrollOffset() const {
- ScrollableArea* area = GetScrollableAreaIfScrollable();
- if (!area)
- return IntPoint();
-
- return IntPoint(area->MinimumScrollOffsetInt().Width(),
- area->MinimumScrollOffsetInt().Height());
-}
-
-IntPoint AXObject::MaximumScrollOffset() const {
- ScrollableArea* area = GetScrollableAreaIfScrollable();
- if (!area)
- return IntPoint();
-
- return IntPoint(area->MaximumScrollOffsetInt().Width(),
- area->MaximumScrollOffsetInt().Height());
-}
-
-void AXObject::SetScrollOffset(const IntPoint& offset) const {
- ScrollableArea* area = GetScrollableAreaIfScrollable();
- if (!area)
- return;
-
- // TODO(bokan): This should potentially be a UserScroll.
- area->SetScrollOffset(ScrollOffset(offset.X(), offset.Y()),
- kProgrammaticScroll);
-}
-
-void AXObject::GetRelativeBounds(AXObject** out_container,
- FloatRect& out_bounds_in_container,
- SkMatrix44& out_container_transform) const {
- *out_container = nullptr;
- out_bounds_in_container = FloatRect();
- out_container_transform.setIdentity();
-
- // First check if it has explicit bounds, for example if this element is tied
- // to a canvas path. When explicit coordinates are provided, the ID of the
- // explicit container element that the coordinates are relative to must be
- // provided too.
- if (!explicit_element_rect_.IsEmpty()) {
- *out_container = AxObjectCache().ObjectFromAXID(explicit_container_id_);
- if (*out_container) {
- out_bounds_in_container = FloatRect(explicit_element_rect_);
- return;
- }
- }
-
- LayoutObject* layout_object = LayoutObjectForRelativeBounds();
- if (!layout_object)
- return;
-
- if (IsWebArea()) {
- if (layout_object->GetFrame()->View())
- out_bounds_in_container.SetSize(
- FloatSize(layout_object->GetFrame()->View()->ContentsSize()));
- return;
- }
-
- // First compute the container. The container must be an ancestor in the
- // accessibility tree, and its LayoutObject must be an ancestor in the layout
- // tree. Get the first such ancestor that's either scrollable or has a paint
- // layer.
- AXObject* container = ParentObjectUnignored();
- LayoutObject* container_layout_object = nullptr;
- while (container) {
- container_layout_object = container->GetLayoutObject();
- if (container_layout_object &&
- container_layout_object->IsBoxModelObject() &&
- layout_object->IsDescendantOf(container_layout_object)) {
- if (container->IsScrollableContainer() ||
- container_layout_object->HasLayer())
- break;
- }
-
- container = container->ParentObjectUnignored();
- }
-
- if (!container)
- return;
- *out_container = container;
- out_bounds_in_container =
- layout_object->LocalBoundingBoxRectForAccessibility();
-
- // If the container has a scroll offset, subtract that out because we want our
- // bounds to be relative to the *unscrolled* position of the container object.
- ScrollableArea* scrollable_area = container->GetScrollableAreaIfScrollable();
- if (scrollable_area && !container->IsWebArea()) {
- ScrollOffset scroll_offset = scrollable_area->GetScrollOffset();
- out_bounds_in_container.Move(scroll_offset);
- }
-
- // Compute the transform between the container's coordinate space and this
- // object. If the transform is just a simple translation, apply that to the
- // bounding box, but if it's a non-trivial transformation like a rotation,
- // scaling, etc. then return the full matrix instead.
- TransformationMatrix transform = layout_object->LocalToAncestorTransform(
- ToLayoutBoxModelObject(container_layout_object));
- if (transform.IsIdentityOr2DTranslation()) {
- out_bounds_in_container.Move(transform.To2DTranslation());
- } else {
- out_container_transform = TransformationMatrix::ToSkMatrix44(transform);
- }
-}
-
-LayoutRect AXObject::GetBoundsInFrameCoordinates() const {
- AXObject* container = nullptr;
- FloatRect bounds;
- SkMatrix44 transform;
- GetRelativeBounds(&container, bounds, transform);
- FloatRect computed_bounds(0, 0, bounds.Width(), bounds.Height());
- while (container && container != this) {
- computed_bounds.Move(bounds.X(), bounds.Y());
- if (!container->IsWebArea()) {
- computed_bounds.Move(-container->GetScrollOffset().X(),
- -container->GetScrollOffset().Y());
- }
- if (!transform.isIdentity()) {
- TransformationMatrix transformation_matrix(transform);
- transformation_matrix.MapRect(computed_bounds);
- }
- container->GetRelativeBounds(&container, bounds, transform);
- }
- return LayoutRect(computed_bounds);
-}
-
-//
-// Modify or take an action on an object.
-//
-
-bool AXObject::Press() {
- Document* document = GetDocument();
- if (!document)
- return false;
-
- UserGestureIndicator gesture_indicator(DocumentUserGestureToken::Create(
- document, UserGestureToken::kNewGesture));
- Element* action_elem = ActionElement();
- if (action_elem) {
- action_elem->AccessKeyAction(true);
- return true;
- }
-
- if (CanSetFocusAttribute()) {
- SetFocused(true);
- return true;
- }
-
- return false;
-}
-
-void AXObject::ScrollToMakeVisible() const {
- IntRect object_rect = PixelSnappedIntRect(GetBoundsInFrameCoordinates());
- object_rect.SetLocation(IntPoint());
- ScrollToMakeVisibleWithSubFocus(object_rect);
-}
-
-// This is a 1-dimensional scroll offset helper function that's applied
-// separately in the horizontal and vertical directions, because the
-// logic is the same. The goal is to compute the best scroll offset
-// in order to make an object visible within a viewport.
-//
-// If the object is already fully visible, returns the same scroll
-// offset.
-//
-// In case the whole object cannot fit, you can specify a
-// subfocus - a smaller region within the object that should
-// be prioritized. If the whole object can fit, the subfocus is
-// ignored.
-//
-// If possible, the object and subfocus are centered within the
-// viewport.
-//
-// Example 1: the object is already visible, so nothing happens.
-// +----------Viewport---------+
-// +---Object---+
-// +--SubFocus--+
-//
-// Example 2: the object is not fully visible, so it's centered
-// within the viewport.
-// Before:
-// +----------Viewport---------+
-// +---Object---+
-// +--SubFocus--+
-//
-// After:
-// +----------Viewport---------+
-// +---Object---+
-// +--SubFocus--+
-//
-// Example 3: the object is larger than the viewport, so the
-// viewport moves to show as much of the object as possible,
-// while also trying to center the subfocus.
-// Before:
-// +----------Viewport---------+
-// +---------------Object--------------+
-// +-SubFocus-+
-//
-// After:
-// +----------Viewport---------+
-// +---------------Object--------------+
-// +-SubFocus-+
-//
-// When constraints cannot be fully satisfied, the min
-// (left/top) position takes precedence over the max (right/bottom).
-//
-// Note that the return value represents the ideal new scroll offset.
-// This may be out of range - the calling function should clip this
-// to the available range.
-static int ComputeBestScrollOffset(int current_scroll_offset,
- int subfocus_min,
- int subfocus_max,
- int object_min,
- int object_max,
- int viewport_min,
- int viewport_max) {
- int viewport_size = viewport_max - viewport_min;
-
- // If the object size is larger than the viewport size, consider
- // only a portion that's as large as the viewport, centering on
- // the subfocus as much as possible.
- if (object_max - object_min > viewport_size) {
- // Since it's impossible to fit the whole object in the
- // viewport, exit now if the subfocus is already within the viewport.
- if (subfocus_min - current_scroll_offset >= viewport_min &&
- subfocus_max - current_scroll_offset <= viewport_max)
- return current_scroll_offset;
-
- // Subfocus must be within focus.
- subfocus_min = std::max(subfocus_min, object_min);
- subfocus_max = std::min(subfocus_max, object_max);
-
- // Subfocus must be no larger than the viewport size; favor top/left.
- if (subfocus_max - subfocus_min > viewport_size)
- subfocus_max = subfocus_min + viewport_size;
-
- // Compute the size of an object centered on the subfocus, the size of the
- // viewport.
- int centered_object_min = (subfocus_min + subfocus_max - viewport_size) / 2;
- int centered_object_max = centered_object_min + viewport_size;
-
- object_min = std::max(object_min, centered_object_min);
- object_max = std::min(object_max, centered_object_max);
- }
-
- // Exit now if the focus is already within the viewport.
- if (object_min - current_scroll_offset >= viewport_min &&
- object_max - current_scroll_offset <= viewport_max)
- return current_scroll_offset;
-
- // Center the object in the viewport.
- return (object_min + object_max - viewport_min - viewport_max) / 2;
-}
-
-void AXObject::ScrollToMakeVisibleWithSubFocus(const IntRect& subfocus) const {
- // Search up the parent chain until we find the first one that's scrollable.
- const AXObject* scroll_parent = ParentObject() ? ParentObject() : this;
- ScrollableArea* scrollable_area = 0;
- while (scroll_parent) {
- scrollable_area = scroll_parent->GetScrollableAreaIfScrollable();
- if (scrollable_area)
- break;
- scroll_parent = scroll_parent->ParentObject();
- }
- if (!scroll_parent || !scrollable_area)
- return;
-
- IntRect object_rect = PixelSnappedIntRect(GetBoundsInFrameCoordinates());
- IntSize scroll_offset = scrollable_area->ScrollOffsetInt();
- IntRect scroll_visible_rect = scrollable_area->VisibleContentRect();
-
- // Convert the object rect into local coordinates.
- if (!scroll_parent->IsWebArea()) {
- object_rect.MoveBy(IntPoint(scroll_offset));
- object_rect.MoveBy(
- -PixelSnappedIntRect(scroll_parent->GetBoundsInFrameCoordinates())
- .Location());
- }
-
- int desired_x = ComputeBestScrollOffset(
- scroll_offset.Width(), object_rect.X() + subfocus.X(),
- object_rect.X() + subfocus.MaxX(), object_rect.X(), object_rect.MaxX(), 0,
- scroll_visible_rect.Width());
- int desired_y = ComputeBestScrollOffset(
- scroll_offset.Height(), object_rect.Y() + subfocus.Y(),
- object_rect.Y() + subfocus.MaxY(), object_rect.Y(), object_rect.MaxY(), 0,
- scroll_visible_rect.Height());
-
- scroll_parent->SetScrollOffset(IntPoint(desired_x, desired_y));
-
- // Convert the subfocus into the coordinates of the scroll parent.
- IntRect new_subfocus = subfocus;
- IntRect new_element_rect = PixelSnappedIntRect(GetBoundsInFrameCoordinates());
- IntRect scroll_parent_rect =
- PixelSnappedIntRect(scroll_parent->GetBoundsInFrameCoordinates());
- new_subfocus.Move(new_element_rect.X(), new_element_rect.Y());
- new_subfocus.Move(-scroll_parent_rect.X(), -scroll_parent_rect.Y());
-
- if (scroll_parent->ParentObject()) {
- // Recursively make sure the scroll parent itself is visible.
- scroll_parent->ScrollToMakeVisibleWithSubFocus(new_subfocus);
- } else {
- // To minimize the number of notifications, only fire one on the topmost
- // object that has been scrolled.
- AxObjectCache().PostNotification(const_cast<AXObject*>(this),
- AXObjectCacheImpl::kAXLocationChanged);
- }
-}
-
-void AXObject::ScrollToGlobalPoint(const IntPoint& global_point) const {
- // Search up the parent chain and create a vector of all scrollable parent
- // objects and ending with this object itself.
- HeapVector<Member<const AXObject>> objects;
- AXObject* parent_object;
- for (parent_object = this->ParentObject(); parent_object;
- parent_object = parent_object->ParentObject()) {
- if (parent_object->GetScrollableAreaIfScrollable())
- objects.push_front(parent_object);
- }
- objects.push_back(this);
-
- // Start with the outermost scrollable (the main window) and try to scroll the
- // next innermost object to the given point.
- int offset_x = 0, offset_y = 0;
- IntPoint point = global_point;
- size_t levels = objects.size() - 1;
- for (size_t i = 0; i < levels; i++) {
- const AXObject* outer = objects[i];
- const AXObject* inner = objects[i + 1];
- ScrollableArea* scrollable_area = outer->GetScrollableAreaIfScrollable();
-
- IntRect inner_rect =
- inner->IsWebArea()
- ? PixelSnappedIntRect(
- inner->ParentObject()->GetBoundsInFrameCoordinates())
- : PixelSnappedIntRect(inner->GetBoundsInFrameCoordinates());
- IntRect object_rect = inner_rect;
- IntSize scroll_offset = scrollable_area->ScrollOffsetInt();
-
- // Convert the object rect into local coordinates.
- object_rect.Move(offset_x, offset_y);
- if (!outer->IsWebArea())
- object_rect.Move(scroll_offset.Width(), scroll_offset.Height());
-
- int desired_x = ComputeBestScrollOffset(
- 0, object_rect.X(), object_rect.MaxX(), object_rect.X(),
- object_rect.MaxX(), point.X(), point.X());
- int desired_y = ComputeBestScrollOffset(
- 0, object_rect.Y(), object_rect.MaxY(), object_rect.Y(),
- object_rect.MaxY(), point.Y(), point.Y());
- outer->SetScrollOffset(IntPoint(desired_x, desired_y));
-
- if (outer->IsWebArea() && !inner->IsWebArea()) {
- // If outer object we just scrolled is a web area (frame) but the inner
- // object is not, keep track of the coordinate transformation to apply to
- // future nested calculations.
- scroll_offset = scrollable_area->ScrollOffsetInt();
- offset_x -= (scroll_offset.Width() + point.X());
- offset_y -= (scroll_offset.Height() + point.Y());
- point.Move(scroll_offset.Width() - inner_rect.Width(),
- scroll_offset.Height() - inner_rect.Y());
- } else if (inner->IsWebArea()) {
- // Otherwise, if the inner object is a web area, reset the coordinate
- // transformation.
- offset_x = 0;
- offset_y = 0;
- }
- }
-
- // To minimize the number of notifications, only fire one on the topmost
- // object that has been scrolled.
- DCHECK(objects[0]);
- // TODO(nektar): Switch to postNotification(objects[0] and remove |getNode|.
- AxObjectCache().PostNotification(objects[0]->GetNode(),
- AXObjectCacheImpl::kAXLocationChanged);
-}
-
-void AXObject::SetSequentialFocusNavigationStartingPoint() {
- // Call it on the nearest ancestor that overrides this with a specific
- // implementation.
- if (ParentObject())
- ParentObject()->SetSequentialFocusNavigationStartingPoint();
-}
-
-void AXObject::NotifyIfIgnoredValueChanged() {
- bool is_ignored = AccessibilityIsIgnored();
- if (LastKnownIsIgnoredValue() != is_ignored) {
- AxObjectCache().ChildrenChanged(ParentObject());
- SetLastKnownIsIgnoredValue(is_ignored);
- }
-}
-
-void AXObject::SelectionChanged() {
- if (AXObject* parent = ParentObjectIfExists())
- parent->SelectionChanged();
-}
-
-int AXObject::LineForPosition(const VisiblePosition& position) const {
- if (position.IsNull() || !GetNode())
- return -1;
-
- // If the position is not in the same editable region as this AX object,
- // return -1.
- Node* container_node = position.DeepEquivalent().ComputeContainerNode();
- if (!container_node->IsShadowIncludingInclusiveAncestorOf(GetNode()) &&
- !GetNode()->IsShadowIncludingInclusiveAncestorOf(container_node))
- return -1;
-
- int line_count = -1;
- VisiblePosition current_position = position;
- VisiblePosition previous_position;
-
- // Move up until we get to the top.
- // FIXME: This only takes us to the top of the rootEditableElement, not the
- // top of the top document.
- do {
- previous_position = current_position;
- current_position = PreviousLinePosition(current_position, LayoutUnit(),
- kHasEditableAXRole);
- ++line_count;
- } while (current_position.IsNotNull() &&
- !InSameLine(current_position, previous_position));
-
- return line_count;
-}
-
-bool AXObject::IsARIAControl(AccessibilityRole aria_role) {
- return IsARIAInput(aria_role) || aria_role == kButtonRole ||
- aria_role == kComboBoxRole || aria_role == kSliderRole;
-}
-
-bool AXObject::IsARIAInput(AccessibilityRole aria_role) {
- return aria_role == kRadioButtonRole || aria_role == kCheckBoxRole ||
- aria_role == kTextFieldRole || aria_role == kSwitchRole ||
- aria_role == kSearchBoxRole;
-}
-
-AccessibilityRole AXObject::AriaRoleToWebCoreRole(const String& value) {
- DCHECK(!value.IsEmpty());
-
- static const ARIARoleMap* role_map = CreateARIARoleMap();
-
- Vector<String> role_vector;
- value.Split(' ', role_vector);
- AccessibilityRole role = kUnknownRole;
- for (const auto& child : role_vector) {
- role = role_map->at(child);
- if (role)
- return role;
- }
-
- return role;
-}
-
-bool AXObject::IsInsideFocusableElementOrARIAWidget(const Node& node) {
- const Node* cur_node = &node;
- do {
- if (cur_node->IsElementNode()) {
- const Element* element = ToElement(cur_node);
- if (element->IsFocusable())
- return true;
- String role = element->getAttribute("role");
- if (!role.IsEmpty() && AXObject::IncludesARIAWidgetRole(role))
- return true;
- if (HasInteractiveARIAAttribute(*element))
- return true;
- }
- cur_node = cur_node->parentNode();
- } while (cur_node && !isHTMLBodyElement(node));
- return false;
-}
-
-bool AXObject::HasInteractiveARIAAttribute(const Element& element) {
- for (size_t i = 0; i < WTF_ARRAY_LENGTH(g_aria_interactive_widget_attributes);
- ++i) {
- const char* attribute = g_aria_interactive_widget_attributes[i];
- if (element.hasAttribute(attribute)) {
- return true;
- }
- }
- return false;
-}
-
-bool AXObject::IncludesARIAWidgetRole(const String& role) {
- static const HashSet<String, CaseFoldingHash>* role_set =
- CreateARIARoleWidgetSet();
-
- Vector<String> role_vector;
- role.Split(' ', role_vector);
- for (const auto& child : role_vector) {
- if (role_set->Contains(child))
- return true;
- }
- return false;
-}
-
-bool AXObject::NameFromContents() const {
- // ARIA 1.1, section 5.2.7.5.
- switch (RoleValue()) {
- case kAnchorRole:
- case kButtonRole:
- case kCellRole:
- case kCheckBoxRole:
- case kColumnHeaderRole:
- case kDirectoryRole:
- case kDisclosureTriangleRole:
- case kHeadingRole:
- case kLineBreakRole:
- case kLinkRole:
- case kListBoxOptionRole:
- case kListItemRole:
- case kMenuItemRole:
- case kMenuItemCheckBoxRole:
- case kMenuItemRadioRole:
- case kMenuListOptionRole:
- case kPopUpButtonRole:
- case kRadioButtonRole:
- case kRowHeaderRole:
- case kStaticTextRole:
- case kStatusRole:
- case kSwitchRole:
- case kTabRole:
- case kToggleButtonRole:
- case kTreeItemRole:
- case kUserInterfaceTooltipRole:
- return true;
- case kRowRole: {
- // Spec says we should always expose the name on rows,
- // but for performance reasons we only do it
- // if the row might receive focus
- if (AncestorExposesActiveDescendant()) {
- return true;
- }
- const Node* node = this->GetNode();
- return node && node->IsElementNode() && ToElement(node)->IsFocusable();
- }
- default:
- return false;
- }
-}
-
-AccessibilityRole AXObject::ButtonRoleType() const {
- // If aria-pressed is present, then it should be exposed as a toggle button.
- // http://www.w3.org/TR/wai-aria/states_and_properties#aria-pressed
- if (AriaPressedIsPresent())
- return kToggleButtonRole;
- if (AriaHasPopup())
- return kPopUpButtonRole;
- // We don't contemplate RadioButtonRole, as it depends on the input
- // type.
-
- return kButtonRole;
-}
-
-const AtomicString& AXObject::RoleName(AccessibilityRole role) {
- static const Vector<AtomicString>* role_name_vector = CreateRoleNameVector();
-
- return role_name_vector->at(role);
-}
-
-const AtomicString& AXObject::InternalRoleName(AccessibilityRole role) {
- static const Vector<AtomicString>* internal_role_name_vector =
- CreateInternalRoleNameVector();
-
- return internal_role_name_vector->at(role);
-}
-
-DEFINE_TRACE(AXObject) {
- visitor->Trace(children_);
- visitor->Trace(parent_);
- visitor->Trace(cached_live_region_root_);
- visitor->Trace(ax_object_cache_);
-}
-
-} // namespace blink

Powered by Google App Engine
This is Rietveld 408576698