AXObjectCache gets recreated during document tear-down.
authorcfleizach@apple.com <cfleizach@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 24 Mar 2013 07:37:37 +0000 (07:37 +0000)
committercfleizach@apple.com <cfleizach@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 24 Mar 2013 07:37:37 +0000 (07:37 +0000)
https://bugs.webkit.org/show_bug.cgi?id=112525

Reviewed by Simon Fraser.

In many cases, a document's AXObjectCache was being created after the
document had detached, which is wasteful and could potentially lead to
crashes because the AXObjectCache has a timer and relies on its document
to exist.

This patch provides a way to get the existing AX object cache, instead of
always creating a new one.
It moves the accessibilityEnabled() checks into the axObjectCache retrieval
for easier readability.
It adds a number of ASSERTs to vieryf that only the correct (top) document is used
for cache manipulation.

* accessibility/AXObjectCache.cpp:
(WebCore::AXObjectCache::stopCachingComputedObjectAttributes):
* dom/ContainerNode.cpp:
(WebCore::ContainerNode::~ContainerNode):
* dom/Document.cpp:
(WebCore::Document::~Document):
(WebCore::Document::clearAXObjectCache):
(WebCore::Document::existingAXObjectCache):
(WebCore::Document::axObjectCache):
(WebCore::Document::setFocusedNode):
* dom/Document.h:
(Document):
* dom/Element.cpp:
(WebCore::Element::attributeChanged):
* dom/Node.cpp:
(WebCore::Node::~Node):
(WebCore::Node::isEditableToAccessibility):
(WebCore::Node::attach):
(WebCore::Node::rootEditableElement):
(WebCore::Node::didMoveToNewDocument):
* editing/AppendNodeCommand.cpp:
(WebCore::sendAXTextChangedIgnoringLineBreaks):
* editing/DeleteFromTextNodeCommand.cpp:
(WebCore::DeleteFromTextNodeCommand::doApply):
(WebCore::DeleteFromTextNodeCommand::doUnapply):
* editing/Editor.cpp:
(WebCore::Editor::respondToChangedContents):
(WebCore::Editor::markAndReplaceFor):
* editing/InsertIntoTextNodeCommand.cpp:
(WebCore::InsertIntoTextNodeCommand::doApply):
(WebCore::InsertIntoTextNodeCommand::doUnapply):
* editing/InsertNodeBeforeCommand.cpp:
(WebCore::InsertNodeBeforeCommand::doApply):
(WebCore::InsertNodeBeforeCommand::doUnapply):
* editing/atk/FrameSelectionAtk.cpp:
(WebCore::FrameSelection::notifyAccessibilityForSelectionChange):
* editing/chromium/FrameSelectionChromium.cpp:
(WebCore::FrameSelection::notifyAccessibilityForSelectionChange):
* editing/mac/FrameSelectionMac.mm:
(WebCore::FrameSelection::notifyAccessibilityForSelectionChange):
* html/HTMLInputElement.cpp:
(WebCore::HTMLInputElement::setChecked):
* html/HTMLSelectElement.cpp:
(WebCore::HTMLSelectElement::optionElementChildrenChanged):
(WebCore::HTMLSelectElement::setRecalcListItems):
* html/HTMLTextFormControlElement.cpp:
(WebCore::HTMLTextFormControlElement::setInnerTextValue):
* html/InputType.cpp:
(WebCore::InputType::applyStep):
* html/RangeInputType.cpp:
(WebCore::RangeInputType::handleKeydownEvent):
* loader/FrameLoader.cpp:
(WebCore::FrameLoader::prepareForLoadStart):
(WebCore::FrameLoader::checkLoadCompleteForThisFrame):
* page/FocusController.cpp:
(WebCore::FocusController::setInitialFocus):
* page/Frame.cpp:
(WebCore::Frame::disconnectOwnerElement):
* page/FrameView.cpp:
(WebCore::FrameView::removeFromAXObjectCache):
(WebCore::FrameView::layout):
(WebCore::FrameView::scrollToAnchor):
(WebCore::FrameView::axObjectCache):
* platform/ScrollView.cpp:
(WebCore::ScrollView::setHasHorizontalScrollbar):
(WebCore::ScrollView::setHasVerticalScrollbar):
* platform/Scrollbar.cpp:
(WebCore::Scrollbar::~Scrollbar):
(WebCore):
(WebCore::Scrollbar::existingAXObjectCache):
* platform/Scrollbar.h:
(Scrollbar):
* rendering/RenderBlock.cpp:
(WebCore::RenderBlock::deleteLineBoxTree):
(WebCore::RenderBlock::createRootInlineBox):
(WebCore::RenderBlock::createAndAppendRootInlineBox):
* rendering/RenderListBox.cpp:
(WebCore::RenderListBox::selectionChanged):
* rendering/RenderMenuList.cpp:
(WebCore::RenderMenuList::addChild):
(WebCore::RenderMenuList::didUpdateActiveOption):
* rendering/RenderObject.cpp:
(WebCore::RenderObject::styleWillChange):
(WebCore::RenderObject::willBeDestroyed):
* rendering/RenderObjectChildList.cpp:
(WebCore::RenderObjectChildList::removeChildNode):
(WebCore::RenderObjectChildList::insertChildNode):
* rendering/RenderText.cpp:
(WebCore::RenderText::setText):
* rendering/RenderWidget.cpp:
(WebCore::RenderWidget::willBeDestroyed):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@146726 268f45cc-cd09-0410-ab3c-d52691b4dbfc

34 files changed:
Source/WebCore/ChangeLog
Source/WebCore/accessibility/AXObjectCache.cpp
Source/WebCore/dom/ContainerNode.cpp
Source/WebCore/dom/Document.cpp
Source/WebCore/dom/Document.h
Source/WebCore/dom/Element.cpp
Source/WebCore/dom/Node.cpp
Source/WebCore/editing/AppendNodeCommand.cpp
Source/WebCore/editing/DeleteFromTextNodeCommand.cpp
Source/WebCore/editing/Editor.cpp
Source/WebCore/editing/InsertIntoTextNodeCommand.cpp
Source/WebCore/editing/InsertNodeBeforeCommand.cpp
Source/WebCore/editing/atk/FrameSelectionAtk.cpp
Source/WebCore/editing/chromium/FrameSelectionChromium.cpp
Source/WebCore/editing/mac/FrameSelectionMac.mm
Source/WebCore/html/HTMLInputElement.cpp
Source/WebCore/html/HTMLSelectElement.cpp
Source/WebCore/html/HTMLTextFormControlElement.cpp
Source/WebCore/html/InputType.cpp
Source/WebCore/html/RangeInputType.cpp
Source/WebCore/loader/FrameLoader.cpp
Source/WebCore/page/FocusController.cpp
Source/WebCore/page/Frame.cpp
Source/WebCore/page/FrameView.cpp
Source/WebCore/platform/ScrollView.cpp
Source/WebCore/platform/Scrollbar.cpp
Source/WebCore/platform/Scrollbar.h
Source/WebCore/rendering/RenderBlock.cpp
Source/WebCore/rendering/RenderListBox.cpp
Source/WebCore/rendering/RenderMenuList.cpp
Source/WebCore/rendering/RenderObject.cpp
Source/WebCore/rendering/RenderObjectChildList.cpp
Source/WebCore/rendering/RenderText.cpp
Source/WebCore/rendering/RenderWidget.cpp

index 32f6758..2690d25 100644 (file)
@@ -1,3 +1,114 @@
+2013-03-24  Chris Fleizach  <cfleizach@apple.com>
+
+        AXObjectCache gets recreated during document tear-down.
+        https://bugs.webkit.org/show_bug.cgi?id=112525
+
+        Reviewed by Simon Fraser.
+
+        In many cases, a document's AXObjectCache was being created after the
+        document had detached, which is wasteful and could potentially lead to
+        crashes because the AXObjectCache has a timer and relies on its document
+        to exist.
+
+        This patch provides a way to get the existing AX object cache, instead of
+        always creating a new one.
+        It moves the accessibilityEnabled() checks into the axObjectCache retrieval
+        for easier readability.
+        It adds a number of ASSERTs to vieryf that only the correct (top) document is used
+        for cache manipulation.
+
+        * accessibility/AXObjectCache.cpp:
+        (WebCore::AXObjectCache::stopCachingComputedObjectAttributes):
+        * dom/ContainerNode.cpp:
+        (WebCore::ContainerNode::~ContainerNode):
+        * dom/Document.cpp:
+        (WebCore::Document::~Document):
+        (WebCore::Document::clearAXObjectCache):
+        (WebCore::Document::existingAXObjectCache):
+        (WebCore::Document::axObjectCache):
+        (WebCore::Document::setFocusedNode):
+        * dom/Document.h:
+        (Document):
+        * dom/Element.cpp:
+        (WebCore::Element::attributeChanged):
+        * dom/Node.cpp:
+        (WebCore::Node::~Node):
+        (WebCore::Node::isEditableToAccessibility):
+        (WebCore::Node::attach):
+        (WebCore::Node::rootEditableElement):
+        (WebCore::Node::didMoveToNewDocument):
+        * editing/AppendNodeCommand.cpp:
+        (WebCore::sendAXTextChangedIgnoringLineBreaks):
+        * editing/DeleteFromTextNodeCommand.cpp:
+        (WebCore::DeleteFromTextNodeCommand::doApply):
+        (WebCore::DeleteFromTextNodeCommand::doUnapply):
+        * editing/Editor.cpp:
+        (WebCore::Editor::respondToChangedContents):
+        (WebCore::Editor::markAndReplaceFor):
+        * editing/InsertIntoTextNodeCommand.cpp:
+        (WebCore::InsertIntoTextNodeCommand::doApply):
+        (WebCore::InsertIntoTextNodeCommand::doUnapply):
+        * editing/InsertNodeBeforeCommand.cpp:
+        (WebCore::InsertNodeBeforeCommand::doApply):
+        (WebCore::InsertNodeBeforeCommand::doUnapply):
+        * editing/atk/FrameSelectionAtk.cpp:
+        (WebCore::FrameSelection::notifyAccessibilityForSelectionChange):
+        * editing/chromium/FrameSelectionChromium.cpp:
+        (WebCore::FrameSelection::notifyAccessibilityForSelectionChange):
+        * editing/mac/FrameSelectionMac.mm:
+        (WebCore::FrameSelection::notifyAccessibilityForSelectionChange):
+        * html/HTMLInputElement.cpp:
+        (WebCore::HTMLInputElement::setChecked):
+        * html/HTMLSelectElement.cpp:
+        (WebCore::HTMLSelectElement::optionElementChildrenChanged):
+        (WebCore::HTMLSelectElement::setRecalcListItems):
+        * html/HTMLTextFormControlElement.cpp:
+        (WebCore::HTMLTextFormControlElement::setInnerTextValue):
+        * html/InputType.cpp:
+        (WebCore::InputType::applyStep):
+        * html/RangeInputType.cpp:
+        (WebCore::RangeInputType::handleKeydownEvent):
+        * loader/FrameLoader.cpp:
+        (WebCore::FrameLoader::prepareForLoadStart):
+        (WebCore::FrameLoader::checkLoadCompleteForThisFrame):
+        * page/FocusController.cpp:
+        (WebCore::FocusController::setInitialFocus):
+        * page/Frame.cpp:
+        (WebCore::Frame::disconnectOwnerElement):
+        * page/FrameView.cpp:
+        (WebCore::FrameView::removeFromAXObjectCache):
+        (WebCore::FrameView::layout):
+        (WebCore::FrameView::scrollToAnchor):
+        (WebCore::FrameView::axObjectCache):
+        * platform/ScrollView.cpp:
+        (WebCore::ScrollView::setHasHorizontalScrollbar):
+        (WebCore::ScrollView::setHasVerticalScrollbar):
+        * platform/Scrollbar.cpp:
+        (WebCore::Scrollbar::~Scrollbar):
+        (WebCore):
+        (WebCore::Scrollbar::existingAXObjectCache):
+        * platform/Scrollbar.h:
+        (Scrollbar):
+        * rendering/RenderBlock.cpp:
+        (WebCore::RenderBlock::deleteLineBoxTree):
+        (WebCore::RenderBlock::createRootInlineBox):
+        (WebCore::RenderBlock::createAndAppendRootInlineBox):
+        * rendering/RenderListBox.cpp:
+        (WebCore::RenderListBox::selectionChanged):
+        * rendering/RenderMenuList.cpp:
+        (WebCore::RenderMenuList::addChild):
+        (WebCore::RenderMenuList::didUpdateActiveOption):
+        * rendering/RenderObject.cpp:
+        (WebCore::RenderObject::styleWillChange):
+        (WebCore::RenderObject::willBeDestroyed):
+        * rendering/RenderObjectChildList.cpp:
+        (WebCore::RenderObjectChildList::removeChildNode):
+        (WebCore::RenderObjectChildList::insertChildNode):
+        * rendering/RenderText.cpp:
+        (WebCore::RenderText::setText):
+        * rendering/RenderWidget.cpp:
+        (WebCore::RenderWidget::willBeDestroyed):
+
 2013-03-23  Mike West  <mkwst@chromium.org>
 
         Drop full URLs from cross-origin access errors caused by sandboxing.
index 3c5e4d4..4d1efe8 100644 (file)
@@ -846,7 +846,8 @@ void AXObjectCache::startCachingComputedObjectAttributesUntilTreeMutates()
 
 void AXObjectCache::stopCachingComputedObjectAttributes()
 {
-    m_computedObjectAttributeCache.clear();
+    if (m_computedObjectAttributeCache)
+        m_computedObjectAttributeCache.clear();
 }
 
 VisiblePosition AXObjectCache::visiblePositionForTextMarkerData(TextMarkerData& textMarkerData)
index 5ccd7ac..9202e88 100644 (file)
@@ -138,8 +138,10 @@ void ContainerNode::takeAllChildrenFrom(ContainerNode* oldParent)
 
 ContainerNode::~ContainerNode()
 {
-    if (AXObjectCache::accessibilityEnabled() && documentInternal() && documentInternal()->axObjectCacheExists())
-        documentInternal()->axObjectCache()->remove(this);
+    if (documentInternal()) {
+        if (AXObjectCache* cache = documentInternal()->existingAXObjectCache())
+            cache->remove(this);
+    }
 
     removeDetachedChildren();
 }
index 75be481..93004ae 100644 (file)
@@ -629,7 +629,8 @@ Document::~Document()
 
     m_renderArena.clear();
 
-    clearAXObjectCache();
+    if (this == topDocument())
+        clearAXObjectCache();
 
     m_decoder = 0;
 
@@ -2211,23 +2212,40 @@ void Document::resumeActiveDOMObjects()
 
 void Document::clearAXObjectCache()
 {
+    ASSERT(topDocument() == this);
     // Clear the cache member variable before calling delete because attempts
     // are made to access it during destruction.
-    topDocument()->m_axObjectCache.release();
+    m_axObjectCache.clear();
 }
 
-bool Document::axObjectCacheExists() const
+AXObjectCache* Document::existingAXObjectCache() const
 {
-    return topDocument()->m_axObjectCache;
+    if (!AXObjectCache::accessibilityEnabled())
+        return 0;
+
+    // If the renderer is gone then we are in the process of destruction.
+    // This method will be called before m_frame = 0.
+    if (!topDocument()->renderer())
+        return 0;
+
+    return topDocument()->m_axObjectCache.get();
 }
 
 AXObjectCache* Document::axObjectCache() const
 {
+    if (!AXObjectCache::accessibilityEnabled())
+        return 0;
+    
     // The only document that actually has a AXObjectCache is the top-level
     // document.  This is because we need to be able to get from any WebCoreAXObject
     // to any other WebCoreAXObject on the same page.  Using a single cache allows
     // lookups across nested webareas (i.e. multiple documents).
     Document* topDocument = this->topDocument();
+
+    // If the document has already been detached, do not make a new axObjectCache.
+    if (!topDocument->renderer())
+        return 0;
+
     ASSERT(topDocument == this || !m_axObjectCache);
     if (!topDocument->m_axObjectCache)
         topDocument->m_axObjectCache = adoptPtr(new AXObjectCache(topDocument));
@@ -3476,10 +3494,12 @@ bool Document::setFocusedNode(PassRefPtr<Node> prpNewFocusedNode, FocusDirection
         }
     }
 
-#if PLATFORM(MAC) || PLATFORM(WIN) || PLATFORM(GTK) || PLATFORM(CHROMIUM)
-    if (!focusChangeBlocked && m_focusedNode && AXObjectCache::accessibilityEnabled())
-        axObjectCache()->handleFocusedUIElementChanged(oldFocusedNode.get(), newFocusedNode.get());
-#endif
+    if (!focusChangeBlocked && m_focusedNode) {
+        // Create the AXObject cache in a focus change because Chromium relies on it.
+        if (AXObjectCache* cache = axObjectCache())
+            cache->handleFocusedUIElementChanged(oldFocusedNode.get(), newFocusedNode.get());
+    }
+
     if (!focusChangeBlocked)
         page()->chrome()->focusedNodeChanged(m_focusedNode.get());
 
index 09af29d..05e7c69 100644 (file)
@@ -559,10 +559,10 @@ public:
         Node::setRenderer(renderer);
     }
 
-    void clearAXObjectCache();
+    AXObjectCache* existingAXObjectCache() const;
     AXObjectCache* axObjectCache() const;
-    bool axObjectCacheExists() const;
-    
+    void clearAXObjectCache();
+
     // to get visually ordered hebrew and arabic pages right
     void setVisuallyOrdered();
     bool visuallyOrdered() const { return m_visuallyOrdered; }
index 3254ec5..7d6d9f3 100644 (file)
@@ -884,8 +884,8 @@ void Element::attributeChanged(const QualifiedName& name, const AtomicString& ne
     if (shouldInvalidateStyle)
         setNeedsStyleRecalc();
 
-    if (AXObjectCache::accessibilityEnabled())
-        document()->axObjectCache()->handleAttributeChanged(name, this);
+    if (AXObjectCache* cache = document()->existingAXObjectCache())
+        cache->handleAttributeChanged(name, this);
 }
 
 inline void Element::attributeChangedFromParserOrByCloning(const QualifiedName& name, const AtomicString& newValue)
index debda41..b88717e 100644 (file)
@@ -431,8 +431,10 @@ Node::~Node()
     if (renderer())
         detach();
 
-    if (AXObjectCache::accessibilityEnabled() && doc && doc->axObjectCacheExists() && !isContainerNode())
-        doc->axObjectCache()->remove(this);
+    if (doc && !isContainerNode()) {
+        if (AXObjectCache* cache = doc->existingAXObjectCache())
+            cache->remove(this);
+    }
     
     if (m_previous)
         m_previous->setNextSibling(0);
@@ -726,10 +728,12 @@ bool Node::isEditableToAccessibility(EditableLevel editableLevel) const
 
     ASSERT(document());
     ASSERT(AXObjectCache::accessibilityEnabled());
-    ASSERT(document()->axObjectCacheExists());
+    ASSERT(document()->existingAXObjectCache());
 
-    if (document() && AXObjectCache::accessibilityEnabled() && document()->axObjectCacheExists())
-        return document()->axObjectCache()->rootAXEditableElement(this);
+    if (document()) {
+        if (AXObjectCache* cache = document()->existingAXObjectCache())
+            return cache->rootAXEditableElement(this);
+    }
 
     return false;
 }
@@ -1090,9 +1094,10 @@ void Node::attach()
     setAttached();
     clearNeedsStyleRecalc();
 
-    Document* doc = documentInternal();
-    if (AXObjectCache::accessibilityEnabled() && doc && doc->axObjectCacheExists())
-        doc->axObjectCache()->updateCacheAfterNodeIsAttached(this);
+    if (Document* doc = documentInternal()) {
+        if (AXObjectCache* cache = doc->axObjectCache())
+            cache->updateCacheAfterNodeIsAttached(this);
+    }
 }
 
 #ifndef NDEBUG
@@ -1313,9 +1318,11 @@ bool Node::isRootEditableElement() const
 
 Element* Node::rootEditableElement(EditableType editableType) const
 {
-    if (editableType == HasEditableAXRole)
-        return const_cast<Element*>(document()->axObjectCache()->rootAXEditableElement(this));
-
+    if (editableType == HasEditableAXRole) {
+        if (AXObjectCache* cache = document()->existingAXObjectCache())
+            return const_cast<Element*>(cache->rootAXEditableElement(this));
+    }
+    
     return rootEditableElement();
 }
 
@@ -2093,8 +2100,9 @@ void Node::didMoveToNewDocument(Document* oldDocument)
 {
     TreeScopeAdopter::ensureDidMoveToNewDocumentWasCalled(oldDocument);
 
-    if (AXObjectCache::accessibilityEnabled() && oldDocument && oldDocument->axObjectCacheExists())
-        oldDocument->axObjectCache()->remove(this);
+    if (AXObjectCache::accessibilityEnabled() && oldDocument)
+        if (AXObjectCache* cache = oldDocument->existingAXObjectCache())
+            cache->remove(this);
 
     // FIXME: Event listener types for this node should be set on the new owner document here.
 
index 6d2cf23..e449d9d 100644 (file)
@@ -52,7 +52,8 @@ static void sendAXTextChangedIgnoringLineBreaks(Node* node, AXObjectCache::AXTex
     if (nodeValue == "\n")
       return;
 
-    node->document()->axObjectCache()->nodeTextChangeNotification(node, textChange, 0, nodeValue);
+    if (AXObjectCache* cache = node->document()->existingAXObjectCache())
+        cache->nodeTextChangeNotification(node, textChange, 0, nodeValue);
 }
 
 void AppendNodeCommand::doApply()
index 33aeb1c..e1a68ac 100644 (file)
@@ -57,8 +57,8 @@ void DeleteFromTextNodeCommand::doApply()
         return;
     
     // Need to notify this before actually deleting the text
-    if (AXObjectCache::accessibilityEnabled())
-        document()->axObjectCache()->nodeTextChangeNotification(m_node.get(), AXObjectCache::AXTextDeleted, m_offset, m_text);
+    if (AXObjectCache* cache = document()->existingAXObjectCache())
+        cache->nodeTextChangeNotification(m_node.get(), AXObjectCache::AXTextDeleted, m_offset, m_text);
 
     m_node->deleteData(m_offset, m_count, ec);
 }
@@ -72,8 +72,8 @@ void DeleteFromTextNodeCommand::doUnapply()
 
     m_node->insertData(m_offset, m_text, IGNORE_EXCEPTION);
 
-    if (AXObjectCache::accessibilityEnabled())
-        document()->axObjectCache()->nodeTextChangeNotification(m_node.get(), AXObjectCache::AXTextInserted, m_offset, m_text);
+    if (AXObjectCache* cache = document()->existingAXObjectCache())
+        cache->nodeTextChangeNotification(m_node.get(), AXObjectCache::AXTextInserted, m_offset, m_text);
 }
 
 #ifndef NDEBUG
index 49bf9be..17c2561 100644 (file)
@@ -549,8 +549,8 @@ void Editor::respondToChangedContents(const VisibleSelection& endingSelection)
 {
     if (AXObjectCache::accessibilityEnabled()) {
         Node* node = endingSelection.start().deprecatedNode();
-        if (node)
-            m_frame->document()->axObjectCache()->postNotification(node, AXObjectCache::AXValueChanged, false);
+        if (AXObjectCache* cache = m_frame->document()->existingAXObjectCache())
+            cache->postNotification(node, AXObjectCache::AXValueChanged, false);
     }
 
     updateMarkersForWordsAffectedByEditing(true);
@@ -2273,9 +2273,9 @@ void Editor::markAndReplaceFor(PassRefPtr<SpellCheckRequest> request, const Vect
                 RefPtr<Range> newParagraphRange = TextIterator::rangeFromLocationAndLength(toContainerNode(root), paragraphStartIndex, paragraphLength + replacementLength - resultLength);
                 paragraph = TextCheckingParagraph(TextIterator::subrange(newParagraphRange.get(), resultLocation, replacementLength), newParagraphRange);
                 
-                if (AXObjectCache::accessibilityEnabled()) {
+                if (AXObjectCache* cache = m_frame->document()->existingAXObjectCache()) {
                     if (Element* root = m_frame->selection()->selection().rootEditableElement())
-                        m_frame->document()->axObjectCache()->postNotification(root, AXObjectCache::AXAutocorrectionOccured, true);
+                        cache->postNotification(root, AXObjectCache::AXAutocorrectionOccured, true);
                 }
 
                 selectionChanged = true;
index 9d8867b..5c30074 100644 (file)
@@ -63,8 +63,8 @@ void InsertIntoTextNodeCommand::doApply()
 
     m_node->insertData(m_offset, m_text, IGNORE_EXCEPTION);
 
-    if (AXObjectCache::accessibilityEnabled())
-        document()->axObjectCache()->nodeTextChangeNotification(m_node.get(), AXObjectCache::AXTextInserted, m_offset, m_text);
+    if (AXObjectCache* cache = document()->existingAXObjectCache())
+        cache->nodeTextChangeNotification(m_node.get(), AXObjectCache::AXTextInserted, m_offset, m_text);
 }
 
 void InsertIntoTextNodeCommand::doUnapply()
@@ -73,8 +73,8 @@ void InsertIntoTextNodeCommand::doUnapply()
         return;
         
     // Need to notify this before actually deleting the text
-    if (AXObjectCache::accessibilityEnabled())
-        document()->axObjectCache()->nodeTextChangeNotification(m_node.get(), AXObjectCache::AXTextDeleted, m_offset, m_text);
+    if (AXObjectCache* cache = document()->existingAXObjectCache())
+        cache->nodeTextChangeNotification(m_node.get(), AXObjectCache::AXTextDeleted, m_offset, m_text);
 
     m_node->deleteData(m_offset, m_text.length(), IGNORE_EXCEPTION);
 }
index 7ede999..51a6915 100644 (file)
@@ -57,8 +57,8 @@ void InsertNodeBeforeCommand::doApply()
 
     parent->insertBefore(m_insertChild.get(), m_refChild.get(), IGNORE_EXCEPTION, AttachLazily);
 
-    if (AXObjectCache::accessibilityEnabled())
-        document()->axObjectCache()->nodeTextChangeNotification(m_insertChild.get(), AXObjectCache::AXTextInserted, 0, m_insertChild->nodeValue());
+    if (AXObjectCache* cache = document()->existingAXObjectCache())
+        cache->nodeTextChangeNotification(m_insertChild.get(), AXObjectCache::AXTextInserted, 0, m_insertChild->nodeValue());
 }
 
 void InsertNodeBeforeCommand::doUnapply()
@@ -67,8 +67,8 @@ void InsertNodeBeforeCommand::doUnapply()
         return;
 
     // Need to notify this before actually deleting the text
-    if (AXObjectCache::accessibilityEnabled())
-        document()->axObjectCache()->nodeTextChangeNotification(m_insertChild.get(), AXObjectCache::AXTextDeleted, 0, m_insertChild->nodeValue());
+    if (AXObjectCache* cache = document()->existingAXObjectCache())
+        cache->nodeTextChangeNotification(m_insertChild.get(), AXObjectCache::AXTextDeleted, 0, m_insertChild->nodeValue());
 
     m_insertChild->remove(IGNORE_EXCEPTION);
 }
index 4548e65..6dfd67c 100644 (file)
@@ -89,7 +89,11 @@ void FrameSelection::notifyAccessibilityForSelectionChange()
         return;
 
     RenderObject* focusedNode = m_selection.end().containerNode()->renderer();
-    AccessibilityObject* accessibilityObject = m_frame->document()->axObjectCache()->getOrCreate(focusedNode);
+    AXObjectCache* cache = m_frame->document()->existingAXObjectCache();
+    if (!cache)
+        return;
+
+    AccessibilityObject* accessibilityObject = cache->getOrCreate(focusedNode);
     if (!accessibilityObject)
         return;
 
index eb201f7..2ef7bdf 100644 (file)
@@ -40,9 +40,9 @@ namespace WebCore {
 void FrameSelection::notifyAccessibilityForSelectionChange()
 {
     // FIXME: Support editable text in chromium.
-    if (AXObjectCache::accessibilityEnabled() && m_selection.start().isNotNull() && m_selection.end().isNotNull()) {
-        Document* document = m_frame->document();
-        document->axObjectCache()->postNotification(m_selection.start().deprecatedNode(), AXObjectCache::AXSelectedTextChanged, false);
+    if (m_selection.start().isNotNull() && m_selection.end().isNotNull()) {
+        if (AXObjectCache* cache = m_frame->document()->existingAXObjectCache())
+            cache->postNotification(m_selection.start().deprecatedNode(), AXObjectCache::AXSelectedTextChanged, false);
     }
 }
 
index a1a272b..af7e8e3 100644 (file)
@@ -49,8 +49,10 @@ void FrameSelection::notifyAccessibilityForSelectionChange()
 {
     Document* document = m_frame->document();
 
-    if (AXObjectCache::accessibilityEnabled() && m_selection.start().isNotNull() && m_selection.end().isNotNull())
-        document->axObjectCache()->postNotification(m_selection.start().deprecatedNode()->renderer(), AXObjectCache::AXSelectedTextChanged, false);
+    if (m_selection.start().isNotNull() && m_selection.end().isNotNull()) {
+        if (AXObjectCache* cache = document->existingAXObjectCache())
+            cache->postNotification(m_selection.start().deprecatedNode()->renderer(), AXObjectCache::AXSelectedTextChanged, false);
+    }
 
     // if zoom feature is enabled, insertion point changes should update the zoom
     if (!UAZoomEnabled() || !m_selection.isCaret())
index 180b6f8..cd5cf09 100644 (file)
@@ -897,8 +897,10 @@ void HTMLInputElement::setChecked(bool nowChecked, TextFieldEventBehavior eventB
     // Ideally we'd do this from the render tree (matching
     // RenderTextView), but it's not possible to do it at the moment
     // because of the way the code is structured.
-    if (renderer() && AXObjectCache::accessibilityEnabled())
-        renderer()->document()->axObjectCache()->checkedStateChanged(this);
+    if (renderer()) {
+        if (AXObjectCache* cache = renderer()->document()->existingAXObjectCache())
+            cache->checkedStateChanged(this);
+    }
 
     // Only send a change event for items in the document (avoid firing during
     // parsing) and don't send a change event for a radio button that's getting
index a9bfcae..1ba8ae3 100644 (file)
@@ -380,8 +380,10 @@ void HTMLSelectElement::optionElementChildrenChanged()
     setRecalcListItems();
     setNeedsValidityCheck();
 
-    if (AXObjectCache::accessibilityEnabled() && renderer())
-        renderer()->document()->axObjectCache()->childrenChanged(this);
+    if (renderer()) {
+        if (AXObjectCache* cache = renderer()->document()->existingAXObjectCache())
+            cache->childrenChanged(this);
+    }
 }
 
 void HTMLSelectElement::accessKeyAction(bool sendMouseEvents)
@@ -722,8 +724,10 @@ void HTMLSelectElement::setRecalcListItems()
     if (!inDocument())
         invalidateSelectedItems();
     
-    if (AXObjectCache::accessibilityEnabled() && renderer())
-        renderer()->document()->axObjectCache()->childrenChanged(this);
+    if (renderer()) {
+        if (AXObjectCache* cache = renderer()->document()->existingAXObjectCache())
+            cache->childrenChanged(this);
+    }
 }
 
 void HTMLSelectElement::recalcListItems(bool updateSelectedStates) const
index 15d63d7..3a2a4d1 100644 (file)
@@ -534,9 +534,10 @@ void HTMLTextFormControlElement::setInnerTextValue(const String& value)
 
     bool textIsChanged = value != innerTextValue();
     if (textIsChanged || !innerTextElement()->hasChildNodes()) {
-        if (textIsChanged && document() && renderer() && AXObjectCache::accessibilityEnabled())
-            document()->axObjectCache()->postNotification(this, AXObjectCache::AXValueChanged, false);
-
+        if (textIsChanged && document() && renderer()) {
+            if (AXObjectCache* cache = document()->existingAXObjectCache())
+                cache->postNotification(this, AXObjectCache::AXValueChanged, false);
+        }
         innerTextElement()->setInnerText(value, ASSERT_NO_EXCEPTION);
 
         if (value.endsWith('\n') || value.endsWith('\r'))
index 2f77cf2..fedd26a 100644 (file)
@@ -1013,8 +1013,8 @@ void InputType::applyStep(int count, AnyStepHandling anyStepHandling, TextFieldE
 
     setValueAsDecimal(newValue, eventBehavior, ec);
 
-    if (AXObjectCache::accessibilityEnabled())
-         element()->document()->axObjectCache()->postNotification(element(), AXObjectCache::AXValueChanged, true);
+    if (AXObjectCache* cache = element()->document()->existingAXObjectCache())
+        cache->postNotification(element(), AXObjectCache::AXValueChanged, true);
 }
 
 bool InputType::getAllowedValueStep(Decimal* step) const
index 9c1cad8..1abedb8 100644 (file)
@@ -246,8 +246,8 @@ void RangeInputType::handleKeydownEvent(KeyboardEvent* event)
         TextFieldEventBehavior eventBehavior = DispatchChangeEvent;
         setValueAsDecimal(newValue, eventBehavior, IGNORE_EXCEPTION);
 
-        if (AXObjectCache::accessibilityEnabled())
-            element()->document()->axObjectCache()->postNotification(element(), AXObjectCache::AXValueChanged, true);
+        if (AXObjectCache* cache = element()->document()->existingAXObjectCache())
+            cache->postNotification(element(), AXObjectCache::AXValueChanged, true);
         element()->dispatchFormControlChangeEvent();
     }
 
index 06d93ff..0a6c638 100644 (file)
@@ -1120,9 +1120,9 @@ void FrameLoader::prepareForLoadStart()
     m_client->dispatchDidStartProvisionalLoad();
 
     // Notify accessibility.
-    if (AXObjectCache::accessibilityEnabled()) {
+    if (AXObjectCache* cache = m_frame->document()->existingAXObjectCache()) {
         AXObjectCache::AXLoadingEvent loadingEvent = loadType() == FrameLoadTypeReload ? AXObjectCache::AXLoadingReloaded : AXObjectCache::AXLoadingStarted;
-        m_frame->document()->axObjectCache()->frameLoadingEventNotification(m_frame, loadingEvent);
+        cache->frameLoadingEventNotification(m_frame, loadingEvent);
     }
 }
 
@@ -2209,8 +2209,8 @@ void FrameLoader::checkLoadCompleteForThisFrame()
             }
 
             // Notify accessibility.
-            if (AXObjectCache::accessibilityEnabled())
-                m_frame->document()->axObjectCache()->frameLoadingEventNotification(m_frame, loadingEvent);
+            if (AXObjectCache* cache = m_frame->document()->existingAXObjectCache())
+                cache->frameLoadingEventNotification(m_frame, loadingEvent);
 
             return;
         }
index bfd0359..7ef6fc6 100644 (file)
@@ -253,8 +253,8 @@ bool FocusController::setInitialFocus(FocusDirection direction, KeyboardEvent* e
     // If focus is being set initially, accessibility needs to be informed that system focus has moved 
     // into the web area again, even if focus did not change within WebCore. PostNotification is called instead
     // of handleFocusedUIElementChanged, because this will send the notification even if the element is the same.
-    if (AXObjectCache::accessibilityEnabled())
-        focusedOrMainFrame()->document()->axObjectCache()->postNotification(focusedOrMainFrame()->document(), AXObjectCache::AXFocusedUIElementChanged, true);
+    if (AXObjectCache* cache = focusedOrMainFrame()->document()->existingAXObjectCache())
+        cache->postNotification(focusedOrMainFrame()->document(), AXObjectCache::AXFocusedUIElementChanged, true);
 
     return didAdvanceFocus;
 }
index 8859dc0..28fde49 100644 (file)
@@ -704,7 +704,7 @@ void Frame::disconnectOwnerElement()
 {
     if (m_ownerElement) {
         if (Document* doc = document())
-            doc->clearAXObjectCache();
+            doc->topDocument()->clearAXObjectCache();
         m_ownerElement->clearContentFrame();
         if (m_page)
             m_page->decrementSubframeCount();
index 1460831..4b11aba 100644 (file)
@@ -302,8 +302,8 @@ void FrameView::reset()
 
 void FrameView::removeFromAXObjectCache()
 {
-    if (AXObjectCache::accessibilityEnabled() && axObjectCache())
-        axObjectCache()->remove(this);
+    if (AXObjectCache* cache = axObjectCache())
+        cache->remove(this);
 }
 
 void FrameView::clearFrame()
@@ -1305,8 +1305,8 @@ void FrameView::layout(bool allowSubtree)
     m_layoutCount++;
 
 #if PLATFORM(MAC) || PLATFORM(CHROMIUM)
-    if (AXObjectCache::accessibilityEnabled())
-        root->document()->axObjectCache()->postNotification(root, AXObjectCache::AXLayoutComplete, true);
+    if (AXObjectCache* cache = root->document()->existingAXObjectCache())
+        cache->postNotification(root, AXObjectCache::AXLayoutComplete, true);
 #endif
 #if ENABLE(DASHBOARD_SUPPORT) || ENABLE(DRAGGABLE_REGION)
     updateAnnotatedRegions();
@@ -2504,8 +2504,8 @@ void FrameView::scrollToAnchor()
     // Align to the top and to the closest side (this matches other browsers).
     anchorNode->renderer()->scrollRectToVisible(rect, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignTopAlways);
 
-    if (AXObjectCache::accessibilityEnabled())
-        m_frame->document()->axObjectCache()->handleScrolledToAnchor(anchorNode.get());
+    if (AXObjectCache* cache = m_frame->document()->existingAXObjectCache())
+        cache->handleScrolledToAnchor(anchorNode.get());
 
     // scrollRectToVisible can call into setScrollPosition(), which resets m_maintainScrollPositionAnchor.
     m_maintainScrollPositionAnchor = anchorNode;
@@ -3972,8 +3972,8 @@ void FrameView::notifyWidgetsInAllFrames(WidgetNotification notification)
     
 AXObjectCache* FrameView::axObjectCache() const
 {
-    if (frame() && frame()->document() && frame()->document()->axObjectCacheExists())
-        return frame()->document()->axObjectCache();
+    if (frame() && frame()->document())
+        return frame()->document()->existingAXObjectCache();
     return 0;
 }
     
index 3c97a85..3b9b687 100644 (file)
@@ -99,8 +99,8 @@ void ScrollView::setHasHorizontalScrollbar(bool hasBar)
         m_horizontalScrollbar = 0;
     }
     
-    if (AXObjectCache::accessibilityEnabled() && axObjectCache())
-        axObjectCache()->handleScrollbarUpdate(this);
+    if (AXObjectCache* cache = axObjectCache())
+        cache->handleScrollbarUpdate(this);
 }
 
 void ScrollView::setHasVerticalScrollbar(bool hasBar)
@@ -117,8 +117,8 @@ void ScrollView::setHasVerticalScrollbar(bool hasBar)
         m_verticalScrollbar = 0;
     }
     
-    if (AXObjectCache::accessibilityEnabled() && axObjectCache())
-        axObjectCache()->handleScrollbarUpdate(this);
+    if (AXObjectCache* cache = axObjectCache())
+        cache->handleScrollbarUpdate(this);
 }
 
 #if !PLATFORM(GTK)
index ff1e805..bb1ce57 100644 (file)
@@ -110,8 +110,8 @@ Scrollbar::Scrollbar(ScrollableArea* scrollableArea, ScrollbarOrientation orient
 
 Scrollbar::~Scrollbar()
 {
-    if (AXObjectCache::accessibilityEnabled() && axObjectCache())
-        axObjectCache()->remove(this);
+    if (AXObjectCache* cache = existingAXObjectCache())
+        cache->remove(this);
     
     stopTimerIfNeeded();
     
@@ -566,16 +566,13 @@ bool Scrollbar::isWindowActive() const
 {
     return m_scrollableArea && m_scrollableArea->isActive();
 }
-    
-AXObjectCache* Scrollbar::axObjectCache() const
+
+AXObjectCache* Scrollbar::existingAXObjectCache() const
 {
-    if (!parent() || !parent()->isFrameView())
+    if (!parent())
         return 0;
     
-    // FIXME: Accessing the FrameView and Document here is a layering violation
-    // and should be removed.
-    Document* document = toFrameView(parent())->frame()->document();
-    return document->axObjectCache();
+    return parent()->axObjectCache();
 }
 
 void Scrollbar::invalidateRect(const IntRect& rect)
index dbc0d14..d574cc6 100644 (file)
@@ -174,7 +174,7 @@ protected:
     void autoscrollPressedPart(double delay);
     ScrollDirection pressedPartScrollDirection();
     ScrollGranularity pressedPartScrollGranularity();
-    
+
     ScrollableArea* m_scrollableArea;
     ScrollbarOrientation m_orientation;
     ScrollbarControlSize m_controlSize;
@@ -206,7 +206,7 @@ protected:
 
 private:
     virtual bool isScrollbar() const { return true; }
-    virtual AXObjectCache* axObjectCache() const;
+    virtual AXObjectCache* existingAXObjectCache() const;
 };
 
 } // namespace WebCore
index 37b103e..70fc314 100644 (file)
@@ -1001,11 +1001,12 @@ void RenderBlock::deleteLineBoxTree()
         }
     }
     m_lineBoxes.deleteLineBoxTree(renderArena());
-    if (UNLIKELY(AXObjectCache::accessibilityEnabled()))
-        document()->axObjectCache()->recomputeIsIgnored(this);
+
+    if (AXObjectCache* cache = document()->existingAXObjectCache())
+        cache->recomputeIsIgnored(this);
 }
 
-RootInlineBox* RenderBlock::createRootInlineBox() 
+RootInlineBox* RenderBlock::createRootInlineBox()
 {
     return new (renderArena()) RootInlineBox(this);
 }
@@ -1015,8 +1016,10 @@ RootInlineBox* RenderBlock::createAndAppendRootInlineBox()
     RootInlineBox* rootBox = createRootInlineBox();
     m_lineBoxes.appendLineBox(rootBox);
 
-    if (UNLIKELY(AXObjectCache::accessibilityEnabled()) && m_lineBoxes.firstLineBox() == rootBox)
-        document()->axObjectCache()->recomputeIsIgnored(this);
+    if (UNLIKELY(AXObjectCache::accessibilityEnabled()) && m_lineBoxes.firstLineBox() == rootBox) {
+        if (AXObjectCache* cache = document()->existingAXObjectCache())
+            cache->recomputeIsIgnored(this);
+    }
 
     return rootBox;
 }
index f45fda3..1fd8878 100644 (file)
@@ -166,8 +166,8 @@ void RenderListBox::selectionChanged()
             scrollToRevealSelection();
     }
     
-    if (AXObjectCache::accessibilityEnabled())
-        document()->axObjectCache()->selectedChildrenChanged(this);
+    if (AXObjectCache* cache = document()->existingAXObjectCache())
+        cache->selectedChildrenChanged(this);
 }
 
 void RenderListBox::layout()
index 2dc89fe..475c7d7 100644 (file)
@@ -142,8 +142,8 @@ void RenderMenuList::addChild(RenderObject* newChild, RenderObject* beforeChild)
     m_innerBlock->addChild(newChild, beforeChild);
     ASSERT(m_innerBlock == firstChild());
 
-    if (AXObjectCache::accessibilityEnabled())
-        document()->axObjectCache()->childrenChanged(this);
+    if (AXObjectCache* cache = document()->existingAXObjectCache())
+        cache->childrenChanged(this);
 }
 
 void RenderMenuList::removeChild(RenderObject* oldChild)
@@ -378,7 +378,7 @@ void RenderMenuList::didSetSelectedIndex(int listIndex)
 
 void RenderMenuList::didUpdateActiveOption(int optionIndex)
 {
-    if (!AXObjectCache::accessibilityEnabled())
+    if (!AXObjectCache::accessibilityEnabled() || !document()->existingAXObjectCache())
         return;
 
     if (m_lastActiveIndex == optionIndex)
index b46912a..e8e7511 100644 (file)
@@ -1865,8 +1865,10 @@ void RenderObject::styleWillChange(StyleDifference diff, const RenderStyle* newS
             if (visibilityChanged)
                 document()->setAnnotatedRegionsDirty(true);
 #endif
-            if (visibilityChanged && AXObjectCache::accessibilityEnabled())
-                document()->axObjectCache()->childrenChanged(parent());
+            if (visibilityChanged) {
+                if (AXObjectCache* cache = document()->existingAXObjectCache())
+                    cache->childrenChanged(parent());
+            }
 
             // Keep layer hierarchy visibility bits up to date if visibility changes.
             if (m_style->visibility() != newStyle->visibility()) {
@@ -2409,15 +2411,15 @@ void RenderObject::willBeDestroyed()
 
     // For accessibility management, notify the parent of the imminent change to its child set.
     // We do it now, before remove(), while the parent pointer is still available.
-    if (AXObjectCache::accessibilityEnabled())
-        document()->axObjectCache()->childrenChanged(this->parent());
+    if (AXObjectCache* cache = document()->existingAXObjectCache())
+        cache->childrenChanged(this->parent());
 
     remove();
 
     // The remove() call above may invoke axObjectCache()->childrenChanged() on the parent, which may require the AX render
     // object for this renderer. So we remove the AX render object now, after the renderer is removed.
-    if (AXObjectCache::accessibilityEnabled())
-        document()->axObjectCache()->remove(this);
+    if (AXObjectCache* cache = document()->existingAXObjectCache())
+        cache->remove(this);
 
 #ifndef NDEBUG
     if (!documentBeingDestroyed() && view() && view()->hasRenderNamedFlowThreads()) {
index 21347c4..9e4a30c 100644 (file)
@@ -109,8 +109,8 @@ RenderObject* RenderObjectChildList::removeChildNode(RenderObject* owner, Render
     if (!owner->documentBeingDestroyed())
         RenderCounter::rendererRemovedFromTree(oldChild);
 
-    if (AXObjectCache::accessibilityEnabled())
-        owner->document()->axObjectCache()->childrenChanged(owner);
+    if (AXObjectCache* cache = owner->document()->existingAXObjectCache())
+        cache->childrenChanged(owner);
 
     return oldChild;
 }
@@ -161,8 +161,8 @@ void RenderObjectChildList::insertChildNode(RenderObject* owner, RenderObject* n
     if (!owner->normalChildNeedsLayout())
         owner->setChildNeedsLayout(true); // We may supply the static position for an absolute positioned child.
 
-    if (AXObjectCache::accessibilityEnabled())
-        owner->document()->axObjectCache()->childrenChanged(owner);
+    if (AXObjectCache* cache = owner->document()->axObjectCache())
+        cache->childrenChanged(owner);
 }
 
 } // namespace WebCore
index 7195e50..1a31fe5 100644 (file)
@@ -1465,9 +1465,8 @@ void RenderText::setText(PassRefPtr<StringImpl> text, bool force)
     setNeedsLayoutAndPrefWidthsRecalc();
     m_knownToHaveNoOverflowAndNoFallbackFonts = false;
     
-    AXObjectCache* axObjectCache = document()->axObjectCache();
-    if (axObjectCache->accessibilityEnabled())
-        axObjectCache->textChanged(this);
+    if (AXObjectCache* cache = document()->existingAXObjectCache())
+        cache->textChanged(this);
 }
 
 String RenderText::textWithoutTranscoding() const
index 9af5317..190827a 100644 (file)
@@ -102,9 +102,9 @@ void RenderWidget::willBeDestroyed()
     if (RenderView* v = view())
         v->removeWidget(this);
     
-    if (AXObjectCache::accessibilityEnabled()) {
-        document()->axObjectCache()->childrenChanged(this->parent());
-        document()->axObjectCache()->remove(this);
+    if (AXObjectCache* cache = document()->existingAXObjectCache()) {
+        cache->childrenChanged(this->parent());
+        cache->remove(this);
     }
 
     setWidget(0);