Chromium Code Reviews| 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 |