Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(444)

Unified Diff: Source/core/accessibility/AccessibilityRenderObject.cpp

Issue 14740025: Simplify and add caching for accessible bounding box calculation. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Re-landing with null check fix Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « Source/core/accessibility/AccessibilityRenderObject.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: Source/core/accessibility/AccessibilityRenderObject.cpp
diff --git a/Source/core/accessibility/AccessibilityRenderObject.cpp b/Source/core/accessibility/AccessibilityRenderObject.cpp
index 5a6d7e97aacfd72664fdda9c2922e66f4dc97321..86594e681d888900a9609b4bd5f37c9e32074bd8 100644
--- a/Source/core/accessibility/AccessibilityRenderObject.cpp
+++ b/Source/core/accessibility/AccessibilityRenderObject.cpp
@@ -223,6 +223,7 @@ static RenderBoxModelObject* nextContinuation(RenderObject* renderer)
AccessibilityRenderObject::AccessibilityRenderObject(RenderObject* renderer)
: AccessibilityNodeObject(renderer->node())
, m_renderer(renderer)
+ , m_cachedElementRectDirty(true)
{
#ifndef NDEBUG
m_renderer->setHasAXObject(true);
@@ -241,11 +242,17 @@ AccessibilityRenderObject::~AccessibilityRenderObject()
LayoutRect AccessibilityRenderObject::elementRect() const
{
- // a checkbox or radio button should encompass its label
- if (isCheckboxOrRadio())
- return checkboxOrRadioRect();
+ if (!m_renderer)
+ return LayoutRect();
+ if (!m_renderer->isBox())
+ return computeElementRect();
+
+ for (const AccessibilityObject* obj = this; obj; obj = obj->parentObject())
+ obj->checkCachedElementRect();
+ for (const AccessibilityObject* obj = this; obj; obj = obj->parentObject())
+ obj->updateCachedElementRect();
- return boundingBoxRect();
+ return m_cachedElementRect;
}
int AccessibilityRenderObject::layoutCount() const
@@ -1153,20 +1160,6 @@ const String& AccessibilityRenderObject::actionVerb() const
}
}
-LayoutRect AccessibilityRenderObject::checkboxOrRadioRect() const
-{
- if (!m_renderer)
- return LayoutRect();
-
- HTMLLabelElement* label = labelForElement(toElement(m_renderer->node()));
- if (!label || !label->renderer())
- return boundingBoxRect();
-
- LayoutRect labelRect = axObjectCache()->getOrCreate(label)->elementRect();
- labelRect.unite(boundingBoxRect());
- return labelRect;
-}
-
void AccessibilityRenderObject::selectedChildren(AccessibilityChildrenVector& result)
{
ASSERT(result.isEmpty());
@@ -1533,45 +1526,69 @@ String AccessibilityRenderObject::helpText() const
// Position and size.
//
-LayoutRect AccessibilityRenderObject::boundingBoxRect() const
+void AccessibilityRenderObject::checkCachedElementRect() const
{
- RenderObject* obj = m_renderer;
+ if (m_cachedElementRectDirty)
+ return;
- if (!obj)
- return LayoutRect();
+ if (!m_renderer)
+ return;
- if (obj->node()) // If we are a continuation, we want to make sure to use the primary renderer.
- obj = obj->node()->renderer();
+ if (!m_renderer->isBox()) {
+ AccessibilityNodeObject::checkCachedElementRect();
+ return;
+ }
- // absoluteFocusRingQuads will query the hierarchy below this element, which for large webpages can be very slow.
- // For a web area, which will have the most elements of any element, absoluteQuads should be used.
- // We should also use absoluteQuads for SVG elements, otherwise transforms won't be applied.
- Vector<FloatQuad> quads;
- bool isSVGRoot = false;
-#if ENABLE(SVG)
- if (obj->isSVGRoot())
- isSVGRoot = true;
-#endif
- if (obj->isText())
- toRenderText(obj)->absoluteQuads(quads, 0, RenderText::ClipToEllipsis);
- else if (isWebArea() || isSeamlessWebArea() || isSVGRoot)
- obj->absoluteQuads(quads);
- else
- obj->absoluteFocusRingQuads(quads);
+ bool dirty = false;
+ RenderBox* box = toRenderBox(m_renderer);
+ if (box->frameRect() != m_cachedFrameRect)
+ dirty = true;
- LayoutRect result = boundingBoxForQuads(obj, quads);
+ if (box->canBeScrolledAndHasScrollableArea()) {
+ ScrollableArea* scrollableArea = box->layer();
+ if (scrollableArea && scrollableArea->scrollPosition() != m_cachedScrollPosition)
+ dirty = true;
+ }
-#if ENABLE(SVG)
- Document* document = this->document();
- if (document && document->isSVGDocument())
- offsetBoundingBoxForRemoteSVGElement(result);
-#endif
+ if (dirty)
+ markCachedElementRectDirty();
+}
- // The size of the web area should be the content size, not the clipped size.
- if ((isWebArea() || isSeamlessWebArea()) && obj->frame()->view())
- result.setSize(obj->frame()->view()->contentsSize());
+void AccessibilityRenderObject::updateCachedElementRect() const
+{
+ if (!m_cachedElementRectDirty)
+ return;
- return result;
+ if (!m_renderer)
+ return;
+
+ if (!m_renderer->isBox()) {
+ AccessibilityNodeObject::updateCachedElementRect();
+ return;
+ }
+
+ RenderBox* box = toRenderBox(m_renderer);
+ m_cachedFrameRect = box->frameRect();
+
+ if (box->canBeScrolledAndHasScrollableArea()) {
+ ScrollableArea* scrollableArea = box->layer();
+ if (scrollableArea)
+ m_cachedScrollPosition = scrollableArea->scrollPosition();
+ }
+
+ m_cachedElementRect = computeElementRect();
+ m_cachedElementRectDirty = false;
+}
+
+void AccessibilityRenderObject::markCachedElementRectDirty() const
+{
+ if (m_cachedElementRectDirty)
+ return;
+
+ // Marks children recursively, if this element changed.
+ m_cachedElementRectDirty = true;
+ for (AccessibilityObject* child = firstChild(); child; child = child->nextSibling())
+ child->markCachedElementRectDirty();
}
IntPoint AccessibilityRenderObject::clickPoint()
@@ -2889,7 +2906,7 @@ AccessibilityObject* AccessibilityRenderObject::remoteSVGElementHitTest(const In
if (!remote)
return 0;
- IntSize offset = point - roundedIntPoint(boundingBoxRect().location());
+ IntSize offset = point - roundedIntPoint(elementRect().location());
return remote->accessibilityHitTest(IntPoint(offset));
}
@@ -2899,7 +2916,7 @@ void AccessibilityRenderObject::offsetBoundingBoxForRemoteSVGElement(LayoutRect&
{
for (AccessibilityObject* parent = parentObject(); parent; parent = parent->parentObject()) {
if (parent->isAccessibilitySVGRoot()) {
- rect.moveBy(parent->parentObject()->boundingBoxRect().location());
+ rect.moveBy(parent->parentObject()->elementRect().location());
break;
}
}
@@ -3129,4 +3146,54 @@ bool AccessibilityRenderObject::inheritsPresentationalRole() const
return false;
}
+LayoutRect AccessibilityRenderObject::computeElementRect() const
+{
+ RenderObject* obj = m_renderer;
+
+ if (!obj)
+ return LayoutRect();
+
+ if (obj->node()) // If we are a continuation, we want to make sure to use the primary renderer.
+ obj = obj->node()->renderer();
+
+ // absoluteFocusRingQuads will query the hierarchy below this element, which for large webpages can be very slow.
+ // For a web area, which will have the most elements of any element, absoluteQuads should be used.
+ // We should also use absoluteQuads for SVG elements, otherwise transforms won't be applied.
+ Vector<FloatQuad> quads;
+ bool isSVGRoot = false;
+#if ENABLE(SVG)
+ if (obj->isSVGRoot())
+ isSVGRoot = true;
+#endif
+ if (obj->isText())
+ toRenderText(obj)->absoluteQuads(quads, 0, RenderText::ClipToEllipsis);
+ else if (isWebArea() || isSeamlessWebArea() || isSVGRoot)
+ obj->absoluteQuads(quads);
+ else
+ obj->absoluteFocusRingQuads(quads);
+
+ LayoutRect result = boundingBoxForQuads(obj, quads);
+
+#if ENABLE(SVG)
+ Document* document = this->document();
+ if (document && document->isSVGDocument())
+ offsetBoundingBoxForRemoteSVGElement(result);
+#endif
+
+ // The size of the web area should be the content size, not the clipped size.
+ if ((isWebArea() || isSeamlessWebArea()) && obj->frame()->view())
+ result.setSize(obj->frame()->view()->contentsSize());
+
+ // Checkboxes and radio buttons include their label as part of their rect.
+ if (isCheckboxOrRadio()) {
+ HTMLLabelElement* label = labelForElement(toElement(m_renderer->node()));
+ if (label && !label->renderer()) {
+ LayoutRect labelRect = axObjectCache()->getOrCreate(label)->elementRect();
+ result.unite(labelRect);
+ }
+ }
+
+ return result;
+}
+
} // namespace WebCore
« no previous file with comments | « Source/core/accessibility/AccessibilityRenderObject.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698