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 |