AccessibilityObjectInclusion AccessibilityObject::accessibilityPlatformIncludesObject() const { AccessibilityObject* parent = parentObject(); if (!parent) return DefaultBehavior; AccessibilityRole role = roleValue(); // We expose the slider as a whole but not its value indicator. if (role == SliderThumbRole) return IgnoreObject; // When a list item is made up entirely of children (e.g. paragraphs) // the list item gets ignored. We need it. if (isGroup() && parent->isList()) return IncludeObject; // Entries and password fields have extraneous children which we want to ignore. if (parent->isPasswordField() || parent->isTextControl()) return IgnoreObject; // Include all tables, even layout tables. The AT can decide what to do with each. if (role == CellRole || role == TableRole || role == ColumnHeaderRole || role == RowHeaderRole) return IncludeObject; // The object containing the text should implement AtkText itself. if (role == StaticTextRole) return IgnoreObject; // Include all list items, regardless they have or not inline children if (role == ListItemRole) return IncludeObject; // Bullets/numbers for list items shouldn't be exposed as AtkObjects. if (role == ListMarkerRole) return IgnoreObject; // Never expose an unknown object, since AT's won't know what to // do with them. This is what is done on the Mac as well. if (role == UnknownRole) return IgnoreObject; if (role == InlineRole) return IncludeObject; // Lines past this point only make sense for AccessibilityRenderObjects. RenderObject* renderObject = renderer(); if (!renderObject) return DefaultBehavior; // We don't want <span> elements to show up in the accessibility hierarchy unless // we have good reasons for that (e.g. focusable or visible because of containing // a meaningful accessible name, maybe set through ARIA), so we can use // atk_component_grab_focus() to set the focus to it. Node* node = renderObject->node(); if (node && node->hasTagName(HTMLNames::spanTag) && !canSetFocusAttribute() && !hasAttributesRequiredForInclusion()) return IgnoreObject; // Given a paragraph or div containing a non-nested anonymous block, WebCore // ignores the paragraph or div and includes the block. We want the opposite: // ATs are expecting accessible objects associated with textual elements. They // usually have no need for the anonymous block. And when the wrong objects // get included or ignored, needed accessibility signals do not get emitted. if (role == ParagraphRole || role == DivRole) { // Don't call textUnderElement() here, because it's slow and it can // crash when called while we're in the middle of a subtree being deleted. if (!renderObject->firstChildSlow()) return DefaultBehavior; if (!parent->renderer() || parent->renderer()->isAnonymousBlock()) return DefaultBehavior; for (RenderObject* r = renderObject->firstChildSlow(); r; r = r->nextSibling()) { if (r->isAnonymousBlock()) return IncludeObject; } } // Block spans result in objects of ATK_ROLE_PANEL which are almost always unwanted. // However, if we ignore block spans whose parent is the body, the child controls // will become immediate children of the ATK_ROLE_DOCUMENT_FRAME and any text will // become text within the document frame itself. This ultimately may be what we want // and would largely be consistent with what we see from Gecko. However, ignoring // spans whose parent is the body changes the current behavior we see from WebCore. // Until we have sufficient time to properly analyze these cases, we will defer to // WebCore. We only check that the parent is not aria because we do not expect // anonymous blocks which are aria-related to themselves have an aria role, nor // have we encountered instances where the parent of an anonymous block also lacked // an aria role but the grandparent had one. if (renderObject && renderObject->isAnonymousBlock() && !parent->renderer()->isBody() && parent->ariaRoleAttribute() == UnknownRole) return IgnoreObject; return DefaultBehavior; }