| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2008 Apple Inc. All rights reserved. | 2 * Copyright (C) 2008 Apple Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
| 6 * are met: | 6 * are met: |
| 7 * | 7 * |
| 8 * 1. Redistributions of source code must retain the above copyright | 8 * 1. Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * 2. Redistributions in binary form must reproduce the above copyright | 10 * 2. Redistributions in binary form must reproduce the above copyright |
| (...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 216 if (renderer->isRenderInline() && !renderer->isReplaced()) | 216 if (renderer->isRenderInline() && !renderer->isReplaced()) |
| 217 return toRenderInline(renderer)->continuation(); | 217 return toRenderInline(renderer)->continuation(); |
| 218 if (renderer->isRenderBlock()) | 218 if (renderer->isRenderBlock()) |
| 219 return toRenderBlock(renderer)->inlineElementContinuation(); | 219 return toRenderBlock(renderer)->inlineElementContinuation(); |
| 220 return 0; | 220 return 0; |
| 221 } | 221 } |
| 222 | 222 |
| 223 AccessibilityRenderObject::AccessibilityRenderObject(RenderObject* renderer) | 223 AccessibilityRenderObject::AccessibilityRenderObject(RenderObject* renderer) |
| 224 : AccessibilityNodeObject(renderer->node()) | 224 : AccessibilityNodeObject(renderer->node()) |
| 225 , m_renderer(renderer) | 225 , m_renderer(renderer) |
| 226 , m_cachedElementRectDirty(true) |
| 226 { | 227 { |
| 227 #ifndef NDEBUG | 228 #ifndef NDEBUG |
| 228 m_renderer->setHasAXObject(true); | 229 m_renderer->setHasAXObject(true); |
| 229 #endif | 230 #endif |
| 230 } | 231 } |
| 231 | 232 |
| 232 PassRefPtr<AccessibilityRenderObject> AccessibilityRenderObject::create(RenderOb
ject* renderer) | 233 PassRefPtr<AccessibilityRenderObject> AccessibilityRenderObject::create(RenderOb
ject* renderer) |
| 233 { | 234 { |
| 234 return adoptRef(new AccessibilityRenderObject(renderer)); | 235 return adoptRef(new AccessibilityRenderObject(renderer)); |
| 235 } | 236 } |
| 236 | 237 |
| 237 AccessibilityRenderObject::~AccessibilityRenderObject() | 238 AccessibilityRenderObject::~AccessibilityRenderObject() |
| 238 { | 239 { |
| 239 ASSERT(isDetached()); | 240 ASSERT(isDetached()); |
| 240 } | 241 } |
| 241 | 242 |
| 242 LayoutRect AccessibilityRenderObject::elementRect() const | 243 LayoutRect AccessibilityRenderObject::elementRect() const |
| 243 { | 244 { |
| 244 // a checkbox or radio button should encompass its label | 245 if (!m_renderer) |
| 245 if (isCheckboxOrRadio()) | 246 return LayoutRect(); |
| 246 return checkboxOrRadioRect(); | 247 if (!m_renderer->isBox()) |
| 248 return computeElementRect(); |
| 247 | 249 |
| 248 return boundingBoxRect(); | 250 for (const AccessibilityObject* obj = this; obj; obj = obj->parentObject()) |
| 251 obj->checkCachedElementRect(); |
| 252 for (const AccessibilityObject* obj = this; obj; obj = obj->parentObject()) |
| 253 obj->updateCachedElementRect(); |
| 254 |
| 255 return m_cachedElementRect; |
| 249 } | 256 } |
| 250 | 257 |
| 251 int AccessibilityRenderObject::layoutCount() const | 258 int AccessibilityRenderObject::layoutCount() const |
| 252 { | 259 { |
| 253 if (!m_renderer->isRenderView()) | 260 if (!m_renderer->isRenderView()) |
| 254 return 0; | 261 return 0; |
| 255 return toRenderView(m_renderer)->frameView()->layoutCount(); | 262 return toRenderView(m_renderer)->frameView()->layoutCount(); |
| 256 } | 263 } |
| 257 | 264 |
| 258 void AccessibilityRenderObject::setRenderer(RenderObject* renderer) | 265 void AccessibilityRenderObject::setRenderer(RenderObject* renderer) |
| (...skipping 887 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1146 case CheckBoxRole: | 1153 case CheckBoxRole: |
| 1147 return isChecked() ? checkedCheckBoxAction : uncheckedCheckBoxAction; | 1154 return isChecked() ? checkedCheckBoxAction : uncheckedCheckBoxAction; |
| 1148 case LinkRole: | 1155 case LinkRole: |
| 1149 case WebCoreLinkRole: | 1156 case WebCoreLinkRole: |
| 1150 return linkAction; | 1157 return linkAction; |
| 1151 default: | 1158 default: |
| 1152 return noAction; | 1159 return noAction; |
| 1153 } | 1160 } |
| 1154 } | 1161 } |
| 1155 | 1162 |
| 1156 LayoutRect AccessibilityRenderObject::checkboxOrRadioRect() const | |
| 1157 { | |
| 1158 if (!m_renderer) | |
| 1159 return LayoutRect(); | |
| 1160 | |
| 1161 HTMLLabelElement* label = labelForElement(toElement(m_renderer->node())); | |
| 1162 if (!label || !label->renderer()) | |
| 1163 return boundingBoxRect(); | |
| 1164 | |
| 1165 LayoutRect labelRect = axObjectCache()->getOrCreate(label)->elementRect(); | |
| 1166 labelRect.unite(boundingBoxRect()); | |
| 1167 return labelRect; | |
| 1168 } | |
| 1169 | |
| 1170 void AccessibilityRenderObject::selectedChildren(AccessibilityChildrenVector& re
sult) | 1163 void AccessibilityRenderObject::selectedChildren(AccessibilityChildrenVector& re
sult) |
| 1171 { | 1164 { |
| 1172 ASSERT(result.isEmpty()); | 1165 ASSERT(result.isEmpty()); |
| 1173 | 1166 |
| 1174 // only listboxes should be asked for their selected children. | 1167 // only listboxes should be asked for their selected children. |
| 1175 AccessibilityRole role = roleValue(); | 1168 AccessibilityRole role = roleValue(); |
| 1176 if (role == ListBoxRole) // native list boxes would be AccessibilityListBoxe
s, so only check for aria list boxes | 1169 if (role == ListBoxRole) // native list boxes would be AccessibilityListBoxe
s, so only check for aria list boxes |
| 1177 ariaListboxSelectedChildren(result); | 1170 ariaListboxSelectedChildren(result); |
| 1178 else if (role == TreeRole || role == TreeGridRole || role == TableRole) | 1171 else if (role == TreeRole || role == TreeGridRole || role == TableRole) |
| 1179 ariaSelectedRows(result); | 1172 ariaSelectedRows(result); |
| (...skipping 346 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1526 } | 1519 } |
| 1527 } | 1520 } |
| 1528 | 1521 |
| 1529 return String(); | 1522 return String(); |
| 1530 } | 1523 } |
| 1531 | 1524 |
| 1532 // | 1525 // |
| 1533 // Position and size. | 1526 // Position and size. |
| 1534 // | 1527 // |
| 1535 | 1528 |
| 1536 LayoutRect AccessibilityRenderObject::boundingBoxRect() const | 1529 void AccessibilityRenderObject::checkCachedElementRect() const |
| 1537 { | 1530 { |
| 1538 RenderObject* obj = m_renderer; | 1531 if (m_cachedElementRectDirty) |
| 1532 return; |
| 1539 | 1533 |
| 1540 if (!obj) | 1534 if (!m_renderer) |
| 1541 return LayoutRect(); | 1535 return; |
| 1542 | 1536 |
| 1543 if (obj->node()) // If we are a continuation, we want to make sure to use th
e primary renderer. | 1537 if (!m_renderer->isBox()) { |
| 1544 obj = obj->node()->renderer(); | 1538 AccessibilityNodeObject::checkCachedElementRect(); |
| 1539 return; |
| 1540 } |
| 1545 | 1541 |
| 1546 // absoluteFocusRingQuads will query the hierarchy below this element, which
for large webpages can be very slow. | 1542 bool dirty = false; |
| 1547 // For a web area, which will have the most elements of any element, absolut
eQuads should be used. | 1543 RenderBox* box = toRenderBox(m_renderer); |
| 1548 // We should also use absoluteQuads for SVG elements, otherwise transforms w
on't be applied. | 1544 if (box->frameRect() != m_cachedFrameRect) |
| 1549 Vector<FloatQuad> quads; | 1545 dirty = true; |
| 1550 bool isSVGRoot = false; | |
| 1551 #if ENABLE(SVG) | |
| 1552 if (obj->isSVGRoot()) | |
| 1553 isSVGRoot = true; | |
| 1554 #endif | |
| 1555 if (obj->isText()) | |
| 1556 toRenderText(obj)->absoluteQuads(quads, 0, RenderText::ClipToEllipsis); | |
| 1557 else if (isWebArea() || isSeamlessWebArea() || isSVGRoot) | |
| 1558 obj->absoluteQuads(quads); | |
| 1559 else | |
| 1560 obj->absoluteFocusRingQuads(quads); | |
| 1561 | 1546 |
| 1562 LayoutRect result = boundingBoxForQuads(obj, quads); | 1547 if (box->canBeScrolledAndHasScrollableArea()) { |
| 1548 ScrollableArea* scrollableArea = box->layer(); |
| 1549 if (scrollableArea && scrollableArea->scrollPosition() != m_cachedScroll
Position) |
| 1550 dirty = true; |
| 1551 } |
| 1563 | 1552 |
| 1564 #if ENABLE(SVG) | 1553 if (dirty) |
| 1565 Document* document = this->document(); | 1554 markCachedElementRectDirty(); |
| 1566 if (document && document->isSVGDocument()) | 1555 } |
| 1567 offsetBoundingBoxForRemoteSVGElement(result); | |
| 1568 #endif | |
| 1569 | 1556 |
| 1570 // The size of the web area should be the content size, not the clipped size
. | 1557 void AccessibilityRenderObject::updateCachedElementRect() const |
| 1571 if ((isWebArea() || isSeamlessWebArea()) && obj->frame()->view()) | 1558 { |
| 1572 result.setSize(obj->frame()->view()->contentsSize()); | 1559 if (!m_cachedElementRectDirty) |
| 1560 return; |
| 1573 | 1561 |
| 1574 return result; | 1562 if (!m_renderer) |
| 1563 return; |
| 1564 |
| 1565 if (!m_renderer->isBox()) { |
| 1566 AccessibilityNodeObject::updateCachedElementRect(); |
| 1567 return; |
| 1568 } |
| 1569 |
| 1570 RenderBox* box = toRenderBox(m_renderer); |
| 1571 m_cachedFrameRect = box->frameRect(); |
| 1572 |
| 1573 if (box->canBeScrolledAndHasScrollableArea()) { |
| 1574 ScrollableArea* scrollableArea = box->layer(); |
| 1575 if (scrollableArea) |
| 1576 m_cachedScrollPosition = scrollableArea->scrollPosition(); |
| 1577 } |
| 1578 |
| 1579 m_cachedElementRect = computeElementRect(); |
| 1580 m_cachedElementRectDirty = false; |
| 1581 } |
| 1582 |
| 1583 void AccessibilityRenderObject::markCachedElementRectDirty() const |
| 1584 { |
| 1585 if (m_cachedElementRectDirty) |
| 1586 return; |
| 1587 |
| 1588 // Marks children recursively, if this element changed. |
| 1589 m_cachedElementRectDirty = true; |
| 1590 for (AccessibilityObject* child = firstChild(); child; child = child->nextSi
bling()) |
| 1591 child->markCachedElementRectDirty(); |
| 1575 } | 1592 } |
| 1576 | 1593 |
| 1577 IntPoint AccessibilityRenderObject::clickPoint() | 1594 IntPoint AccessibilityRenderObject::clickPoint() |
| 1578 { | 1595 { |
| 1579 // Headings are usually much wider than their textual content. If the mid po
int is used, often it can be wrong. | 1596 // Headings are usually much wider than their textual content. If the mid po
int is used, often it can be wrong. |
| 1580 if (isHeading() && children().size() == 1) | 1597 if (isHeading() && children().size() == 1) |
| 1581 return children()[0]->clickPoint(); | 1598 return children()[0]->clickPoint(); |
| 1582 | 1599 |
| 1583 // use the default position unless this is an editable web area, in which ca
se we use the selection bounds. | 1600 // use the default position unless this is an editable web area, in which ca
se we use the selection bounds. |
| 1584 if (!isWebArea() || isReadOnly()) | 1601 if (!isWebArea() || isReadOnly()) |
| (...skipping 1297 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2882 return 0; | 2899 return 0; |
| 2883 #endif | 2900 #endif |
| 2884 } | 2901 } |
| 2885 | 2902 |
| 2886 AccessibilityObject* AccessibilityRenderObject::remoteSVGElementHitTest(const In
tPoint& point) const | 2903 AccessibilityObject* AccessibilityRenderObject::remoteSVGElementHitTest(const In
tPoint& point) const |
| 2887 { | 2904 { |
| 2888 AccessibilityObject* remote = remoteSVGRootElement(); | 2905 AccessibilityObject* remote = remoteSVGRootElement(); |
| 2889 if (!remote) | 2906 if (!remote) |
| 2890 return 0; | 2907 return 0; |
| 2891 | 2908 |
| 2892 IntSize offset = point - roundedIntPoint(boundingBoxRect().location()); | 2909 IntSize offset = point - roundedIntPoint(elementRect().location()); |
| 2893 return remote->accessibilityHitTest(IntPoint(offset)); | 2910 return remote->accessibilityHitTest(IntPoint(offset)); |
| 2894 } | 2911 } |
| 2895 | 2912 |
| 2896 // The boundingBox for elements within the remote SVG element needs to be offset
by its position | 2913 // The boundingBox for elements within the remote SVG element needs to be offset
by its position |
| 2897 // within the parent page, otherwise they are in relative coordinates only. | 2914 // within the parent page, otherwise they are in relative coordinates only. |
| 2898 void AccessibilityRenderObject::offsetBoundingBoxForRemoteSVGElement(LayoutRect&
rect) const | 2915 void AccessibilityRenderObject::offsetBoundingBoxForRemoteSVGElement(LayoutRect&
rect) const |
| 2899 { | 2916 { |
| 2900 for (AccessibilityObject* parent = parentObject(); parent; parent = parent->
parentObject()) { | 2917 for (AccessibilityObject* parent = parentObject(); parent; parent = parent->
parentObject()) { |
| 2901 if (parent->isAccessibilitySVGRoot()) { | 2918 if (parent->isAccessibilitySVGRoot()) { |
| 2902 rect.moveBy(parent->parentObject()->boundingBoxRect().location()); | 2919 rect.moveBy(parent->parentObject()->elementRect().location()); |
| 2903 break; | 2920 break; |
| 2904 } | 2921 } |
| 2905 } | 2922 } |
| 2906 } | 2923 } |
| 2907 | 2924 |
| 2908 // Hidden children are those that are not rendered or visible, but are specifica
lly marked as aria-hidden=false, | 2925 // Hidden children are those that are not rendered or visible, but are specifica
lly marked as aria-hidden=false, |
| 2909 // meaning that they should be exposed to the AX hierarchy. | 2926 // meaning that they should be exposed to the AX hierarchy. |
| 2910 void AccessibilityRenderObject::addHiddenChildren() | 2927 void AccessibilityRenderObject::addHiddenChildren() |
| 2911 { | 2928 { |
| 2912 Node* node = this->node(); | 2929 Node* node = this->node(); |
| (...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3122 | 3139 |
| 3123 // If native tag of the parent element matches an acceptable name, then
return | 3140 // If native tag of the parent element matches an acceptable name, then
return |
| 3124 // based on its presentational status. | 3141 // based on its presentational status. |
| 3125 if (possibleParentTagNames->contains(toElement(elementNode)->tagQName())
) | 3142 if (possibleParentTagNames->contains(toElement(elementNode)->tagQName())
) |
| 3126 return parent->roleValue() == PresentationalRole; | 3143 return parent->roleValue() == PresentationalRole; |
| 3127 } | 3144 } |
| 3128 | 3145 |
| 3129 return false; | 3146 return false; |
| 3130 } | 3147 } |
| 3131 | 3148 |
| 3149 LayoutRect AccessibilityRenderObject::computeElementRect() const |
| 3150 { |
| 3151 RenderObject* obj = m_renderer; |
| 3152 |
| 3153 if (!obj) |
| 3154 return LayoutRect(); |
| 3155 |
| 3156 if (obj->node()) // If we are a continuation, we want to make sure to use th
e primary renderer. |
| 3157 obj = obj->node()->renderer(); |
| 3158 |
| 3159 // absoluteFocusRingQuads will query the hierarchy below this element, which
for large webpages can be very slow. |
| 3160 // For a web area, which will have the most elements of any element, absolut
eQuads should be used. |
| 3161 // We should also use absoluteQuads for SVG elements, otherwise transforms w
on't be applied. |
| 3162 Vector<FloatQuad> quads; |
| 3163 bool isSVGRoot = false; |
| 3164 #if ENABLE(SVG) |
| 3165 if (obj->isSVGRoot()) |
| 3166 isSVGRoot = true; |
| 3167 #endif |
| 3168 if (obj->isText()) |
| 3169 toRenderText(obj)->absoluteQuads(quads, 0, RenderText::ClipToEllipsis); |
| 3170 else if (isWebArea() || isSeamlessWebArea() || isSVGRoot) |
| 3171 obj->absoluteQuads(quads); |
| 3172 else |
| 3173 obj->absoluteFocusRingQuads(quads); |
| 3174 |
| 3175 LayoutRect result = boundingBoxForQuads(obj, quads); |
| 3176 |
| 3177 #if ENABLE(SVG) |
| 3178 Document* document = this->document(); |
| 3179 if (document && document->isSVGDocument()) |
| 3180 offsetBoundingBoxForRemoteSVGElement(result); |
| 3181 #endif |
| 3182 |
| 3183 // The size of the web area should be the content size, not the clipped size
. |
| 3184 if ((isWebArea() || isSeamlessWebArea()) && obj->frame()->view()) |
| 3185 result.setSize(obj->frame()->view()->contentsSize()); |
| 3186 |
| 3187 // Checkboxes and radio buttons include their label as part of their rect. |
| 3188 if (isCheckboxOrRadio()) { |
| 3189 HTMLLabelElement* label = labelForElement(toElement(m_renderer->node()))
; |
| 3190 if (label && !label->renderer()) { |
| 3191 LayoutRect labelRect = axObjectCache()->getOrCreate(label)->elementR
ect(); |
| 3192 result.unite(labelRect); |
| 3193 } |
| 3194 } |
| 3195 |
| 3196 return result; |
| 3197 } |
| 3198 |
| 3132 } // namespace WebCore | 3199 } // namespace WebCore |
| OLD | NEW |