|  | /* | 
|  | * 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 "core/dom/AXObjectCache.h" | 
|  | #include "modules/ModulesExport.h" | 
|  | #include "modules/accessibility/AXObject.h" | 
|  | #include "platform/Timer.h" | 
|  | #include "wtf/Forward.h" | 
|  | #include "wtf/HashMap.h" | 
|  | #include "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 AXObjectCache { | 
|  | WTF_MAKE_NONCOPYABLE(AXObjectCacheImpl); | 
|  | public: | 
|  | static AXObjectCache* create(Document&); | 
|  |  | 
|  | explicit AXObjectCacheImpl(Document&); | 
|  | ~AXObjectCacheImpl(); | 
|  | DECLARE_VIRTUAL_TRACE(); | 
|  |  | 
|  | AXObject* 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; | 
|  | // Called when a node has just been attached, so we can make sure we have the right subclass of AXObject. | 
|  | void updateCacheAfterNodeIsAttached(Node*) override; | 
|  |  | 
|  | void handleAttributeChanged(const QualifiedName& attrName, Element*) override; | 
|  | void handleFocusedUIElementChanged(Node* oldFocusedNode, Node* newFocusedNode) override; | 
|  | void handleInitialFocus() override; | 
|  | void handleTextFormControlChanged(Node*) override; | 
|  | void handleEditableTextContentChanged(Node*) override; | 
|  | void handleValueChanged(Node*) override; | 
|  | void handleUpdateActiveMenuOption(LayoutMenuList*, int optionIndex) override; | 
|  | void didShowMenuListPopup(LayoutMenuList*) override; | 
|  | void didHideMenuListPopup(LayoutMenuList*) override; | 
|  | void handleLoadComplete(Document*) override; | 
|  | void handleLayoutComplete(Document*) override; | 
|  | void handleClicked(Node*) override; | 
|  |  | 
|  | void setCanvasObjectBounds(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* anchorNode) override; | 
|  |  | 
|  | const AtomicString& computedRoleForNode(Node*) override; | 
|  | String computedNameForNode(Node*) override; | 
|  |  | 
|  | void onTouchAccessibilityHover(const IntPoint&) override; | 
|  |  | 
|  | // Returns the root object for the entire document. | 
|  | AXObject* rootObject(); | 
|  |  | 
|  | AXObject* objectFromAXID(AXID id) const { return m_objects.get(id); } | 
|  | AXObject* root(); | 
|  |  | 
|  | // used for objects without backing elements | 
|  | AXObject* getOrCreate(AccessibilityRole); | 
|  | AXObject* getOrCreate(LayoutObject*); | 
|  | AXObject* getOrCreate(Node*); | 
|  | AXObject* getOrCreate(AbstractInlineTextBox*); | 
|  |  | 
|  | // will only return the AXObject if it already exists | 
|  | AXObject* get(Node*); | 
|  | AXObject* get(LayoutObject*); | 
|  | AXObject* get(AbstractInlineTextBox*); | 
|  |  | 
|  | AXObject* firstAccessibleObjectFromNode(const Node*); | 
|  |  | 
|  | void remove(AXID); | 
|  |  | 
|  | void childrenChanged(AXObject*); | 
|  |  | 
|  | void handleActiveDescendantChanged(Node*); | 
|  | void handleAriaRoleChanged(Node*); | 
|  | void handleAriaExpandedChange(Node*); | 
|  | void handleAriaSelectedChanged(Node*); | 
|  |  | 
|  | bool accessibilityEnabled(); | 
|  | bool inlineTextBoxAccessibilityEnabled(); | 
|  |  | 
|  | void removeAXID(AXObject*); | 
|  |  | 
|  | AXID platformGenerateAXID() 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 m_modificationCount; } | 
|  |  | 
|  | void postNotification(LayoutObject*, AXNotification); | 
|  | void postNotification(Node*, AXNotification); | 
|  | void postNotification(AXObject*, AXNotification); | 
|  |  | 
|  | // | 
|  | // Aria-owns support. | 
|  | // | 
|  |  | 
|  | // Returns true if the given object's position in the tree was due to aria-owns. | 
|  | bool isAriaOwned(const AXObject*) const; | 
|  |  | 
|  | // Returns the parent of the given object due to aria-owns. | 
|  | AXObject* getAriaOwnedParent(const AXObject*) 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 AXObject* owner, const Vector<String>& idVector, HeapVector<Member<AXObject>>& ownedChildren); | 
|  |  | 
|  | // 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(AXObject*, AXNotification); | 
|  | void textChanged(AXObject*); | 
|  | void labelChanged(Element*); | 
|  |  | 
|  | AXObject* createFromRenderer(LayoutObject*); | 
|  | AXObject* createFromNode(Node*); | 
|  | AXObject* createFromInlineTextBox(AbstractInlineTextBox*); | 
|  |  | 
|  | private: | 
|  |  | 
|  | Member<Document> m_document; | 
|  | HeapHashMap<AXID, Member<AXObject>> m_objects; | 
|  | // LayoutObject and AbstractInlineTextBox are not on the Oilpan heap so we | 
|  | // do not use HeapHashMap for those mappings. | 
|  | HashMap<LayoutObject*, AXID> m_layoutObjectMapping; | 
|  | HeapHashMap<Member<Node>, AXID> m_nodeObjectMapping; | 
|  | HashMap<AbstractInlineTextBox*, AXID> m_inlineTextBoxObjectMapping; | 
|  | int m_modificationCount; | 
|  |  | 
|  | HashSet<AXID> m_idsInUse; | 
|  |  | 
|  | #if ENABLE(ASSERT) | 
|  | // Verified when finalizing. | 
|  | bool m_hasBeenDisposed; | 
|  | #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>> m_ariaOwnerToChildrenMapping; | 
|  |  | 
|  | // Map from the AXID of a child to the AXID of the parent that owns it. | 
|  | HashMap<AXID, AXID> m_ariaOwnedChildToOwnerMapping; | 
|  |  | 
|  | // 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> m_ariaOwnedChildToRealParentMapping; | 
|  |  | 
|  | // 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>> m_ariaOwnerToIdsMapping; | 
|  |  | 
|  | // 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, OwnPtr<HashSet<AXID>>> m_idToAriaOwnersMapping; | 
|  |  | 
|  | Timer<AXObjectCacheImpl> m_notificationPostTimer; | 
|  | HeapVector<std::pair<Member<AXObject>, AXNotification>> m_notificationsToPost; | 
|  | void notificationPostTimerFired(Timer<AXObjectCacheImpl>*); | 
|  |  | 
|  | AXObject* focusedImageMapUIElement(HTMLAreaElement*); | 
|  |  | 
|  | AXID getAXID(AXObject*); | 
|  |  | 
|  | void textChanged(Node*); | 
|  | bool nodeIsTextControl(const Node*); | 
|  |  | 
|  | Settings* settings(); | 
|  | }; | 
|  |  | 
|  | // 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 |