Commit d67f46f4 authored by dmazzoni@chromium.org's avatar dmazzoni@chromium.org

Get rid of AXComputedObjectAttributeCache

We added AXComputedObjectAttributeCache to WebKit because we wanted to
cache some expensive computations in the AX tree, but none of the other
WebKit ports wanted it.

A much simpler solution is to just store the cached value inside the
AXObject. To determine if the value is out of date, I added a
modification count that increments whenever there's a layout or DOM
mutation. We can reuse the same modification count for more cached
attributes.

BUG=425879

Review URL: https://codereview.chromium.org/670093002

git-svn-id: svn://svn.chromium.org/blink/trunk@184331 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 214102ca
......@@ -134,6 +134,8 @@ AXObject::AXObject()
, m_role(UnknownRole)
, m_lastKnownIsIgnoredValue(DefaultBehavior)
, m_detached(false)
, m_lastModificationCount(-1)
, m_cachedIsIgnored(false)
{
}
......@@ -247,30 +249,22 @@ bool AXObject::isClickable() const
}
bool AXObject::accessibilityIsIgnored() const
{
updateCachedAttributeValuesIfNeeded();
return m_cachedIsIgnored;
}
void AXObject::updateCachedAttributeValuesIfNeeded() const
{
AXObjectCacheImpl* cache = axObjectCache();
if (!cache)
return true;
AXComputedObjectAttributeCache* attributeCache = cache->computedObjectAttributeCache();
if (attributeCache) {
AXObjectInclusion ignored = attributeCache->getIgnored(axObjectID());
switch (ignored) {
case IgnoreObject:
return true;
case IncludeObject:
return false;
case DefaultBehavior:
break;
}
}
bool result = computeAccessibilityIsIgnored();
return;
if (attributeCache)
attributeCache->setIgnored(axObjectID(), result ? IgnoreObject : IncludeObject);
if (cache->modificationCount() == m_lastModificationCount)
return;
return result;
m_cachedIsIgnored = computeAccessibilityIsIgnored();
m_lastModificationCount = cache->modificationCount();
}
bool AXObject::accessibilityIsIgnoredByDefault() const
......
......@@ -579,6 +579,14 @@ protected:
unsigned getLengthForTextRange() const { return text().length(); }
bool m_detached;
private:
// The following cached attribute values (the ones starting with m_cached*)
// are only valid if m_lastModificationCount matches AXObjectCacheImpl::modificationCount().
mutable int m_lastModificationCount;
mutable bool m_cachedIsIgnored;
void updateCachedAttributeValuesIfNeeded() const;
};
#define DEFINE_AX_OBJECT_TYPE_CASTS(thisType, predicate) \
......
......@@ -88,34 +88,11 @@ AXObjectCache* AXObjectCache::create(Document& document)
return new AXObjectCacheImpl(document);
}
AXObjectInclusion AXComputedObjectAttributeCache::getIgnored(AXID id) const
{
HashMap<AXID, CachedAXObjectAttributes>::const_iterator it = m_idMapping.find(id);
return it != m_idMapping.end() ? it->value.ignored : DefaultBehavior;
}
void AXComputedObjectAttributeCache::setIgnored(AXID id, AXObjectInclusion inclusion)
{
HashMap<AXID, CachedAXObjectAttributes>::iterator it = m_idMapping.find(id);
if (it != m_idMapping.end()) {
it->value.ignored = inclusion;
} else {
CachedAXObjectAttributes attributes;
attributes.ignored = inclusion;
m_idMapping.set(id, attributes);
}
}
void AXComputedObjectAttributeCache::clear()
{
m_idMapping.clear();
}
AXObjectCacheImpl::AXObjectCacheImpl(Document& document)
: m_document(document)
, m_modificationCount(0)
, m_notificationPostTimer(this, &AXObjectCacheImpl::notificationPostTimerFired)
{
m_computedObjectAttributeCache = AXComputedObjectAttributeCache::create();
}
AXObjectCacheImpl::~AXObjectCacheImpl()
......@@ -758,7 +735,7 @@ void AXObjectCacheImpl::postNotification(RenderObject* renderer, AXNotification
if (!renderer)
return;
m_computedObjectAttributeCache->clear();
m_modificationCount++;
// Get an accessibility object that already exists. One should not be created here
// because a render update may be in progress and creating an AX object can re-trigger a layout
......@@ -779,7 +756,7 @@ void AXObjectCacheImpl::postNotification(Node* node, AXNotification notification
if (!node)
return;
m_computedObjectAttributeCache->clear();
m_modificationCount++;
// Get an accessibility object that already exists. One should not be created here
// because a render update may be in progress and creating an AX object can re-trigger a layout
......@@ -797,7 +774,7 @@ void AXObjectCacheImpl::postNotification(Node* node, AXNotification notification
void AXObjectCacheImpl::postNotification(AXObject* object, Document* document, AXNotification notification, bool postToElement, PostType postType)
{
m_computedObjectAttributeCache->clear();
m_modificationCount++;
if (object && !postToElement)
object = object->observableObject();
......@@ -843,7 +820,7 @@ void AXObjectCacheImpl::handleScrollbarUpdate(FrameView* view)
// We don't want to create a scroll view from this method, only update an existing one.
if (AXObject* scrollViewObject = get(view)) {
m_computedObjectAttributeCache->clear();
m_modificationCount++;
scrollViewObject->updateChildrenIfNecessary();
}
}
......@@ -853,7 +830,7 @@ void AXObjectCacheImpl::handleLayoutComplete(RenderObject* renderer)
if (!renderer)
return;
m_computedObjectAttributeCache->clear();
m_modificationCount++;
// Create the AXObject if it didn't yet exist - that's always safe at the end of a layout, and it
// allows an AX notification to be sent when a page has its first layout, rather than when the
......@@ -878,7 +855,7 @@ void AXObjectCacheImpl::handleAriaRoleChanged(Node* node)
{
if (AXObject* obj = getOrCreate(node)) {
obj->updateAccessibilityRole();
m_computedObjectAttributeCache->clear();
m_modificationCount++;
obj->notifyIfIgnoredValueChanged();
}
}
......
......@@ -52,27 +52,6 @@ struct TextMarkerData {
EAffinity affinity;
};
class AXComputedObjectAttributeCache {
public:
static PassOwnPtr<AXComputedObjectAttributeCache> create() { return adoptPtr(new AXComputedObjectAttributeCache()); }
AXObjectInclusion getIgnored(AXID) const;
void setIgnored(AXID, AXObjectInclusion);
void clear();
private:
AXComputedObjectAttributeCache() { }
struct CachedAXObjectAttributes {
CachedAXObjectAttributes() : ignored(DefaultBehavior) { }
AXObjectInclusion ignored;
};
HashMap<AXID, CachedAXObjectAttributes> m_idMapping;
};
enum PostType { PostSynchronously, PostAsynchronously };
// This class should only be used from inside the accessibility directory.
......@@ -174,7 +153,9 @@ public:
bool nodeHasRole(Node*, const AtomicString& role);
AXComputedObjectAttributeCache* computedObjectAttributeCache() { return m_computedObjectAttributeCache.get(); }
// 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(RenderObject*, AXNotification, bool postToElement, PostType = PostAsynchronously);
void postNotification(Node*, AXNotification, bool postToElement, PostType = PostAsynchronously);
......@@ -198,7 +179,7 @@ private:
HashMap<Node*, AXID> m_nodeObjectMapping;
HashMap<AbstractInlineTextBox*, AXID> m_inlineTextBoxObjectMapping;
HashSet<Node*> m_textMarkerNodes;
OwnPtr<AXComputedObjectAttributeCache> m_computedObjectAttributeCache;
int m_modificationCount;
HashSet<AXID> m_idsInUse;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment