blob: d307561963661e2fde8c5cf41d1772e427f37ede [file] [log] [blame]
/*
* Copyright (C) 2014, 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:
*
* 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.
*/
#ifndef AXObjectCacheImpl_h
#define AXObjectCacheImpl_h
#include <memory>
#include "core/dom/AXObjectCacheBase.h"
#include "modules/ModulesExport.h"
#include "modules/accessibility/AXObjectImpl.h"
#include "platform/wtf/Forward.h"
#include "platform/wtf/HashMap.h"
#include "platform/wtf/HashSet.h"
namespace blink {
class AbstractInlineTextBox;
class HTMLAreaElement;
class FrameView;
// This class should only be used from inside the accessibility directory.
class MODULES_EXPORT AXObjectCacheImpl : public AXObjectCacheBase {
WTF_MAKE_NONCOPYABLE(AXObjectCacheImpl);
public:
static AXObjectCache* Create(Document&);
explicit AXObjectCacheImpl(Document&);
virtual ~AXObjectCacheImpl();
DECLARE_VIRTUAL_TRACE();
AXObjectImpl* FocusedObject();
void Dispose() override;
void SelectionChanged(Node*) override;
void ChildrenChanged(Node*) override;
void ChildrenChanged(LayoutObject*) override;
void CheckedStateChanged(Node*) override;
virtual void ListboxOptionStateChanged(HTMLOptionElement*);
virtual void ListboxSelectedChildrenChanged(HTMLSelectElement*);
virtual void ListboxActiveIndexChanged(HTMLSelectElement*);
virtual void RadiobuttonRemovedFromGroup(HTMLInputElement*);
void Remove(LayoutObject*) override;
void Remove(Node*) override;
void Remove(AbstractInlineTextBox*) override;
const Element* RootAXEditableElement(const Node*) override;
// Called by a node when text or a text equivalent (e.g. alt) attribute is
// changed.
void TextChanged(LayoutObject*) override;
void TextChanged(AXObjectImpl*);
// Called when a node has just been attached, so we can make sure we have the
// right subclass of AXObjectImpl.
void UpdateCacheAfterNodeIsAttached(Node*) override;
void HandleAttributeChanged(const QualifiedName& attr_name,
Element*) override;
void HandleFocusedUIElementChanged(Node* old_focused_node,
Node* new_focused_node) override;
void HandleInitialFocus() override;
void HandleTextFormControlChanged(Node*) override;
void HandleEditableTextContentChanged(Node*) override;
void HandleValueChanged(Node*) override;
void HandleUpdateActiveMenuOption(LayoutMenuList*, int option_index) override;
void DidShowMenuListPopup(LayoutMenuList*) override;
void DidHideMenuListPopup(LayoutMenuList*) override;
void HandleLoadComplete(Document*) override;
void HandleLayoutComplete(Document*) override;
void HandleClicked(Node*) override;
void SetCanvasObjectBounds(HTMLCanvasElement*,
Element*,
const LayoutRect&) override;
void InlineTextBoxesUpdated(LineLayoutItem) override;
// Called when the scroll offset changes.
void HandleScrollPositionChanged(FrameView*) override;
void HandleScrollPositionChanged(LayoutObject*) override;
// Called when scroll bars are added / removed (as the view resizes).
void HandleLayoutComplete(LayoutObject*) override;
void HandleScrolledToAnchor(const Node* anchor_node) override;
const AtomicString& ComputedRoleForNode(Node*) override;
String ComputedNameForNode(Node*) override;
void OnTouchAccessibilityHover(const IntPoint&) override;
// Returns the root object for the entire document.
AXObjectImpl* RootObject();
AXObjectImpl* ObjectFromAXID(AXID id) const { return objects_.at(id); }
AXObjectImpl* Root();
// used for objects without backing elements
AXObjectImpl* GetOrCreate(AccessibilityRole);
AXObjectImpl* GetOrCreate(LayoutObject*);
AXObjectImpl* GetOrCreate(Node*);
AXObjectImpl* GetOrCreate(AbstractInlineTextBox*);
// will only return the AXObjectImpl if it already exists
AXObjectImpl* Get(Node*) override;
AXObjectImpl* Get(LayoutObject*);
AXObjectImpl* Get(AbstractInlineTextBox*);
AXObjectImpl* FirstAccessibleObjectFromNode(const Node*);
void Remove(AXID);
void ChildrenChanged(AXObjectImpl*);
void HandleActiveDescendantChanged(Node*);
void HandleAriaRoleChanged(Node*);
void HandleAriaExpandedChange(Node*);
void HandleAriaSelectedChanged(Node*);
bool AccessibilityEnabled();
bool InlineTextBoxAccessibilityEnabled();
void RemoveAXID(AXObjectImpl*);
AXID GenerateAXID() const;
// Counts the number of times the document has been modified. Some attribute
// values are cached as long as the modification count hasn't changed.
int ModificationCount() const { return modification_count_; }
void PostNotification(LayoutObject*, AXNotification);
void PostNotification(Node*, AXNotification);
void PostNotification(AXObjectImpl*, AXNotification);
//
// Aria-owns support.
//
// Returns true if the given object's position in the tree was due to
// aria-owns.
bool IsAriaOwned(const AXObjectImpl*) const;
// Returns the parent of the given object due to aria-owns.
AXObjectImpl* GetAriaOwnedParent(const AXObjectImpl*) const;
// Given an object that has an aria-owns attributes, and a vector of ids from
// the value of that attribute, updates the internal state to reflect the new
// set of children owned by this object, returning the result in
// |ownedChildren|. The result is validated - illegal, duplicate, or cyclical
// references have been removed.
//
// If one or more ids aren't found, they're added to a lookup table so that if
// an element with that id appears later, it can be added when you call
// updateTreeIfElementIdIsAriaOwned.
void UpdateAriaOwns(const AXObjectImpl* owner,
const Vector<String>& id_vector,
HeapVector<Member<AXObjectImpl>>& owned_children);
// Given an element in the DOM tree that was either just added or whose id
// just changed, check to see if another object wants to be its parent due to
// aria-owns. If so, update the tree by calling childrenChanged() on the
// potential owner, possibly reparenting this element.
void UpdateTreeIfElementIdIsAriaOwned(Element*);
protected:
void PostPlatformNotification(AXObjectImpl*, AXNotification);
void LabelChanged(Element*);
AXObjectImpl* CreateFromRenderer(LayoutObject*);
AXObjectImpl* CreateFromNode(Node*);
AXObjectImpl* CreateFromInlineTextBox(AbstractInlineTextBox*);
private:
Member<Document> document_;
HeapHashMap<AXID, Member<AXObjectImpl>> objects_;
// LayoutObject and AbstractInlineTextBox are not on the Oilpan heap so we
// do not use HeapHashMap for those mappings.
HashMap<LayoutObject*, AXID> layout_object_mapping_;
HeapHashMap<Member<Node>, AXID> node_object_mapping_;
HashMap<AbstractInlineTextBox*, AXID> inline_text_box_object_mapping_;
int modification_count_;
HashSet<AXID> ids_in_use_;
#if DCHECK_IS_ON()
// Verified when finalizing.
bool has_been_disposed_ = false;
#endif
//
// Aria-owns
//
// Map from the AXID of the owner to the AXIDs of the children.
// This is a validated map, it doesn't contain illegal, duplicate,
// or cyclical matches, or references to IDs that don't exist.
HashMap<AXID, Vector<AXID>> aria_owner_to_children_mapping_;
// Map from the AXID of a child to the AXID of the parent that owns it.
HashMap<AXID, AXID> aria_owned_child_to_owner_mapping_;
// Map from the AXID of a child to the AXID of its real parent in the tree if
// we ignored aria-owns. This is needed in case the owner no longer wants to
// own it.
HashMap<AXID, AXID> aria_owned_child_to_real_parent_mapping_;
// Map from the AXID of any object with an aria-owns attribute to the set of
// ids of its children. This is *unvalidated*, it includes ids that may not
// currently exist in the tree.
HashMap<AXID, HashSet<String>> aria_owner_to_ids_mapping_;
// Map from an ID (the ID attribute of a DOM element) to the set of elements
// that want to own that ID. This is *unvalidated*, it includes possible
// duplicates. This is used so that when an element with an ID is added to
// the tree or changes its ID, we can quickly determine if it affects an
// aria-owns relationship.
HashMap<String, std::unique_ptr<HashSet<AXID>>> id_to_aria_owners_mapping_;
TaskRunnerTimer<AXObjectCacheImpl> notification_post_timer_;
HeapVector<std::pair<Member<AXObjectImpl>, AXNotification>>
notifications_to_post_;
void NotificationPostTimerFired(TimerBase*);
AXObjectImpl* FocusedImageMapUIElement(HTMLAreaElement*);
AXID GetOrCreateAXID(AXObjectImpl*);
void TextChanged(Node*);
bool NodeIsTextControl(const Node*);
Settings* GetSettings();
};
// This is the only subclass of AXObjectCache.
DEFINE_TYPE_CASTS(AXObjectCacheImpl, AXObjectCache, cache, true, true);
bool NodeHasRole(Node*, const String& role);
// This will let you know if aria-hidden was explicitly set to false.
bool IsNodeAriaVisible(Node*);
} // namespace blink
#endif