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

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: Update comment Created 7 years, 8 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
Index: Source/core/accessibility/AccessibilityRenderObject.cpp
diff --git a/Source/core/accessibility/AccessibilityRenderObject.cpp b/Source/core/accessibility/AccessibilityRenderObject.cpp
index 5a6d7e97aacfd72664fdda9c2922e66f4dc97321..5b10beb4917b41babadfafe383d58240b97c286e 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);
@@ -239,13 +240,17 @@ AccessibilityRenderObject::~AccessibilityRenderObject()
ASSERT(isDetached());
}
-LayoutRect AccessibilityRenderObject::elementRect() const
+LayoutRect AccessibilityRenderObject::elementRect()
{
- // a checkbox or radio button should encompass its label
- if (isCheckboxOrRadio())
- return checkboxOrRadioRect();
+ for (AccessibilityObject* obj = this; obj; obj = obj->parentObject())
+ updateCachedElementRect();
+
+ if (m_cachedElementRectDirty) {
+ m_cachedElementRect = computeElementRect();
+ m_cachedElementRectDirty = false;
+ }
- return boundingBoxRect();
+ return m_cachedElementRect;
}
int AccessibilityRenderObject::layoutCount() const
@@ -1028,7 +1033,7 @@ void AccessibilityRenderObject::linkedUIElements(AccessibilityChildrenVector& li
addRadioButtonGroupMembers(linkedUIElements);
}
-AccessibilityOrientation AccessibilityRenderObject::orientation() const
+AccessibilityOrientation AccessibilityRenderObject::orientation()
{
const AtomicString& ariaOrientation = getAttribute(aria_orientationAttr);
if (equalIgnoringCase(ariaOrientation, "horizontal"))
@@ -1153,20 +1158,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 +1524,30 @@ String AccessibilityRenderObject::helpText() const
// Position and size.
//
-LayoutRect AccessibilityRenderObject::boundingBoxRect() const
+void AccessibilityRenderObject::updateCachedElementRect()
{
- 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 (!renderer())
+ return;
-#if ENABLE(SVG)
- Document* document = this->document();
- if (document && document->isSVGDocument())
- offsetBoundingBoxForRemoteSVGElement(result);
-#endif
+ if (!renderer()->isBox()) {
+ AccessibilityNodeObject::updateCachedElementRect();
+ return;
+ }
- // 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());
+ RenderBox* box = toRenderBox(m_renderer);
+ if (box->frameRect() != m_cachedFrameRect) {
+ m_cachedFrameRect = box->frameRect();
+ markCachedElementRectDirty();
+ }
+}
- return result;
+void AccessibilityRenderObject::markCachedElementRectDirty()
+{
+ if (!m_cachedElementRectDirty) {
Julien - ping for review 2013/05/03 20:54:20 WebKit favored early returns to avoid unneeded nes
dmazzoni 2013/05/06 04:58:01 Done.
+ m_cachedElementRectDirty = true;
+ // Marks children recursively, if this element changed.
+ AccessibilityNodeObject::markCachedElementRectDirty();
+ }
}
IntPoint AccessibilityRenderObject::clickPoint()
@@ -1636,7 +1612,7 @@ AccessibilityObject* AccessibilityRenderObject::accessibilityHitTest(const IntPo
return result;
}
-AccessibilityObject* AccessibilityRenderObject::elementAccessibilityHitTest(const IntPoint& point) const
+AccessibilityObject* AccessibilityRenderObject::elementAccessibilityHitTest(const IntPoint& point)
{
if (isSVGImage())
return remoteSVGElementHitTest(point);
@@ -2883,13 +2859,13 @@ AccessibilitySVGRoot* AccessibilityRenderObject::remoteSVGRootElement() const
#endif
}
-AccessibilityObject* AccessibilityRenderObject::remoteSVGElementHitTest(const IntPoint& point) const
+AccessibilityObject* AccessibilityRenderObject::remoteSVGElementHitTest(const IntPoint& point)
{
AccessibilityObject* remote = remoteSVGRootElement();
if (!remote)
return 0;
- IntSize offset = point - roundedIntPoint(boundingBoxRect().location());
+ IntSize offset = point - roundedIntPoint(elementRect().location());
return remote->accessibilityHitTest(IntPoint(offset));
}
@@ -2899,7 +2875,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 +3105,54 @@ bool AccessibilityRenderObject::inheritsPresentationalRole() const
return false;
}
+LayoutRect AccessibilityRenderObject::computeElementRect()
+{
+ 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

Powered by Google App Engine
This is Rietveld 408576698