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 |