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() |
243 { | 244 { |
244 // a checkbox or radio button should encompass its label | 245 for (AccessibilityObject* obj = this; obj; obj = obj->parentObject()) |
245 if (isCheckboxOrRadio()) | 246 updateCachedElementRect(); |
246 return checkboxOrRadioRect(); | |
247 | 247 |
248 return boundingBoxRect(); | 248 if (m_cachedElementRectDirty) { |
249 m_cachedElementRect = computeElementRect(); | |
250 m_cachedElementRectDirty = false; | |
251 } | |
252 | |
253 return m_cachedElementRect; | |
249 } | 254 } |
250 | 255 |
251 int AccessibilityRenderObject::layoutCount() const | 256 int AccessibilityRenderObject::layoutCount() const |
252 { | 257 { |
253 if (!m_renderer->isRenderView()) | 258 if (!m_renderer->isRenderView()) |
254 return 0; | 259 return 0; |
255 return toRenderView(m_renderer)->frameView()->layoutCount(); | 260 return toRenderView(m_renderer)->frameView()->layoutCount(); |
256 } | 261 } |
257 | 262 |
258 void AccessibilityRenderObject::setRenderer(RenderObject* renderer) | 263 void AccessibilityRenderObject::setRenderer(RenderObject* renderer) |
(...skipping 762 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1021 if (isAnchor()) { | 1026 if (isAnchor()) { |
1022 AccessibilityObject* linkedAXElement = internalLinkElement(); | 1027 AccessibilityObject* linkedAXElement = internalLinkElement(); |
1023 if (linkedAXElement) | 1028 if (linkedAXElement) |
1024 linkedUIElements.append(linkedAXElement); | 1029 linkedUIElements.append(linkedAXElement); |
1025 } | 1030 } |
1026 | 1031 |
1027 if (roleValue() == RadioButtonRole) | 1032 if (roleValue() == RadioButtonRole) |
1028 addRadioButtonGroupMembers(linkedUIElements); | 1033 addRadioButtonGroupMembers(linkedUIElements); |
1029 } | 1034 } |
1030 | 1035 |
1031 AccessibilityOrientation AccessibilityRenderObject::orientation() const | 1036 AccessibilityOrientation AccessibilityRenderObject::orientation() |
1032 { | 1037 { |
1033 const AtomicString& ariaOrientation = getAttribute(aria_orientationAttr); | 1038 const AtomicString& ariaOrientation = getAttribute(aria_orientationAttr); |
1034 if (equalIgnoringCase(ariaOrientation, "horizontal")) | 1039 if (equalIgnoringCase(ariaOrientation, "horizontal")) |
1035 return AccessibilityOrientationHorizontal; | 1040 return AccessibilityOrientationHorizontal; |
1036 if (equalIgnoringCase(ariaOrientation, "vertical")) | 1041 if (equalIgnoringCase(ariaOrientation, "vertical")) |
1037 return AccessibilityOrientationVertical; | 1042 return AccessibilityOrientationVertical; |
1038 | 1043 |
1039 return AccessibilityObject::orientation(); | 1044 return AccessibilityObject::orientation(); |
1040 } | 1045 } |
1041 | 1046 |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1146 case CheckBoxRole: | 1151 case CheckBoxRole: |
1147 return isChecked() ? checkedCheckBoxAction : uncheckedCheckBoxAction; | 1152 return isChecked() ? checkedCheckBoxAction : uncheckedCheckBoxAction; |
1148 case LinkRole: | 1153 case LinkRole: |
1149 case WebCoreLinkRole: | 1154 case WebCoreLinkRole: |
1150 return linkAction; | 1155 return linkAction; |
1151 default: | 1156 default: |
1152 return noAction; | 1157 return noAction; |
1153 } | 1158 } |
1154 } | 1159 } |
1155 | 1160 |
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) | 1161 void AccessibilityRenderObject::selectedChildren(AccessibilityChildrenVector& re sult) |
1171 { | 1162 { |
1172 ASSERT(result.isEmpty()); | 1163 ASSERT(result.isEmpty()); |
1173 | 1164 |
1174 // only listboxes should be asked for their selected children. | 1165 // only listboxes should be asked for their selected children. |
1175 AccessibilityRole role = roleValue(); | 1166 AccessibilityRole role = roleValue(); |
1176 if (role == ListBoxRole) // native list boxes would be AccessibilityListBoxe s, so only check for aria list boxes | 1167 if (role == ListBoxRole) // native list boxes would be AccessibilityListBoxe s, so only check for aria list boxes |
1177 ariaListboxSelectedChildren(result); | 1168 ariaListboxSelectedChildren(result); |
1178 else if (role == TreeRole || role == TreeGridRole || role == TableRole) | 1169 else if (role == TreeRole || role == TreeGridRole || role == TableRole) |
1179 ariaSelectedRows(result); | 1170 ariaSelectedRows(result); |
(...skipping 346 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1526 } | 1517 } |
1527 } | 1518 } |
1528 | 1519 |
1529 return String(); | 1520 return String(); |
1530 } | 1521 } |
1531 | 1522 |
1532 // | 1523 // |
1533 // Position and size. | 1524 // Position and size. |
1534 // | 1525 // |
1535 | 1526 |
1536 LayoutRect AccessibilityRenderObject::boundingBoxRect() const | 1527 void AccessibilityRenderObject::updateCachedElementRect() |
1537 { | 1528 { |
1538 RenderObject* obj = m_renderer; | 1529 if (!renderer()) |
1530 return; | |
1539 | 1531 |
1540 if (!obj) | 1532 if (!renderer()->isBox()) { |
1541 return LayoutRect(); | 1533 AccessibilityNodeObject::updateCachedElementRect(); |
1534 return; | |
1535 } | |
1542 | 1536 |
1543 if (obj->node()) // If we are a continuation, we want to make sure to use th e primary renderer. | 1537 RenderBox* box = toRenderBox(m_renderer); |
1544 obj = obj->node()->renderer(); | 1538 if (box->frameRect() != m_cachedFrameRect) { |
1539 m_cachedFrameRect = box->frameRect(); | |
1540 markCachedElementRectDirty(); | |
1541 } | |
1542 } | |
1545 | 1543 |
1546 // absoluteFocusRingQuads will query the hierarchy below this element, which for large webpages can be very slow. | 1544 void AccessibilityRenderObject::markCachedElementRectDirty() |
1547 // For a web area, which will have the most elements of any element, absolut eQuads should be used. | 1545 { |
1548 // We should also use absoluteQuads for SVG elements, otherwise transforms w on't be applied. | 1546 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.
| |
1549 Vector<FloatQuad> quads; | 1547 m_cachedElementRectDirty = true; |
1550 bool isSVGRoot = false; | 1548 // Marks children recursively, if this element changed. |
1551 #if ENABLE(SVG) | 1549 AccessibilityNodeObject::markCachedElementRectDirty(); |
1552 if (obj->isSVGRoot()) | 1550 } |
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 | |
1562 LayoutRect result = boundingBoxForQuads(obj, quads); | |
1563 | |
1564 #if ENABLE(SVG) | |
1565 Document* document = this->document(); | |
1566 if (document && document->isSVGDocument()) | |
1567 offsetBoundingBoxForRemoteSVGElement(result); | |
1568 #endif | |
1569 | |
1570 // The size of the web area should be the content size, not the clipped size . | |
1571 if ((isWebArea() || isSeamlessWebArea()) && obj->frame()->view()) | |
1572 result.setSize(obj->frame()->view()->contentsSize()); | |
1573 | |
1574 return result; | |
1575 } | 1551 } |
1576 | 1552 |
1577 IntPoint AccessibilityRenderObject::clickPoint() | 1553 IntPoint AccessibilityRenderObject::clickPoint() |
1578 { | 1554 { |
1579 // Headings are usually much wider than their textual content. If the mid po int is used, often it can be wrong. | 1555 // 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) | 1556 if (isHeading() && children().size() == 1) |
1581 return children()[0]->clickPoint(); | 1557 return children()[0]->clickPoint(); |
1582 | 1558 |
1583 // use the default position unless this is an editable web area, in which ca se we use the selection bounds. | 1559 // use the default position unless this is an editable web area, in which ca se we use the selection bounds. |
1584 if (!isWebArea() || isReadOnly()) | 1560 if (!isWebArea() || isReadOnly()) |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1629 AccessibilityObject* controlObject = result->correspondingControlForLabe lElement(); | 1605 AccessibilityObject* controlObject = result->correspondingControlForLabe lElement(); |
1630 if (controlObject && !controlObject->exposesTitleUIElement()) | 1606 if (controlObject && !controlObject->exposesTitleUIElement()) |
1631 return controlObject; | 1607 return controlObject; |
1632 | 1608 |
1633 result = result->parentObjectUnignored(); | 1609 result = result->parentObjectUnignored(); |
1634 } | 1610 } |
1635 | 1611 |
1636 return result; | 1612 return result; |
1637 } | 1613 } |
1638 | 1614 |
1639 AccessibilityObject* AccessibilityRenderObject::elementAccessibilityHitTest(cons t IntPoint& point) const | 1615 AccessibilityObject* AccessibilityRenderObject::elementAccessibilityHitTest(cons t IntPoint& point) |
1640 { | 1616 { |
1641 if (isSVGImage()) | 1617 if (isSVGImage()) |
1642 return remoteSVGElementHitTest(point); | 1618 return remoteSVGElementHitTest(point); |
1643 | 1619 |
1644 return AccessibilityObject::elementAccessibilityHitTest(point); | 1620 return AccessibilityObject::elementAccessibilityHitTest(point); |
1645 } | 1621 } |
1646 | 1622 |
1647 // | 1623 // |
1648 // High-level accessibility tree access. | 1624 // High-level accessibility tree access. |
1649 // | 1625 // |
(...skipping 1226 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2876 ASSERT(rootSVGObject && rootSVGObject->isAccessibilitySVGRoot()); | 2852 ASSERT(rootSVGObject && rootSVGObject->isAccessibilitySVGRoot()); |
2877 if (!rootSVGObject->isAccessibilitySVGRoot()) | 2853 if (!rootSVGObject->isAccessibilitySVGRoot()) |
2878 return 0; | 2854 return 0; |
2879 | 2855 |
2880 return toAccessibilitySVGRoot(rootSVGObject); | 2856 return toAccessibilitySVGRoot(rootSVGObject); |
2881 #else | 2857 #else |
2882 return 0; | 2858 return 0; |
2883 #endif | 2859 #endif |
2884 } | 2860 } |
2885 | 2861 |
2886 AccessibilityObject* AccessibilityRenderObject::remoteSVGElementHitTest(const In tPoint& point) const | 2862 AccessibilityObject* AccessibilityRenderObject::remoteSVGElementHitTest(const In tPoint& point) |
2887 { | 2863 { |
2888 AccessibilityObject* remote = remoteSVGRootElement(); | 2864 AccessibilityObject* remote = remoteSVGRootElement(); |
2889 if (!remote) | 2865 if (!remote) |
2890 return 0; | 2866 return 0; |
2891 | 2867 |
2892 IntSize offset = point - roundedIntPoint(boundingBoxRect().location()); | 2868 IntSize offset = point - roundedIntPoint(elementRect().location()); |
2893 return remote->accessibilityHitTest(IntPoint(offset)); | 2869 return remote->accessibilityHitTest(IntPoint(offset)); |
2894 } | 2870 } |
2895 | 2871 |
2896 // The boundingBox for elements within the remote SVG element needs to be offset by its position | 2872 // 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. | 2873 // within the parent page, otherwise they are in relative coordinates only. |
2898 void AccessibilityRenderObject::offsetBoundingBoxForRemoteSVGElement(LayoutRect& rect) const | 2874 void AccessibilityRenderObject::offsetBoundingBoxForRemoteSVGElement(LayoutRect& rect) const |
2899 { | 2875 { |
2900 for (AccessibilityObject* parent = parentObject(); parent; parent = parent-> parentObject()) { | 2876 for (AccessibilityObject* parent = parentObject(); parent; parent = parent-> parentObject()) { |
2901 if (parent->isAccessibilitySVGRoot()) { | 2877 if (parent->isAccessibilitySVGRoot()) { |
2902 rect.moveBy(parent->parentObject()->boundingBoxRect().location()); | 2878 rect.moveBy(parent->parentObject()->elementRect().location()); |
2903 break; | 2879 break; |
2904 } | 2880 } |
2905 } | 2881 } |
2906 } | 2882 } |
2907 | 2883 |
2908 // Hidden children are those that are not rendered or visible, but are specifica lly marked as aria-hidden=false, | 2884 // 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. | 2885 // meaning that they should be exposed to the AX hierarchy. |
2910 void AccessibilityRenderObject::addHiddenChildren() | 2886 void AccessibilityRenderObject::addHiddenChildren() |
2911 { | 2887 { |
2912 Node* node = this->node(); | 2888 Node* node = this->node(); |
(...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3122 | 3098 |
3123 // If native tag of the parent element matches an acceptable name, then return | 3099 // If native tag of the parent element matches an acceptable name, then return |
3124 // based on its presentational status. | 3100 // based on its presentational status. |
3125 if (possibleParentTagNames->contains(toElement(elementNode)->tagQName()) ) | 3101 if (possibleParentTagNames->contains(toElement(elementNode)->tagQName()) ) |
3126 return parent->roleValue() == PresentationalRole; | 3102 return parent->roleValue() == PresentationalRole; |
3127 } | 3103 } |
3128 | 3104 |
3129 return false; | 3105 return false; |
3130 } | 3106 } |
3131 | 3107 |
3108 LayoutRect AccessibilityRenderObject::computeElementRect() | |
3109 { | |
3110 RenderObject* obj = m_renderer; | |
3111 | |
3112 if (!obj) | |
3113 return LayoutRect(); | |
3114 | |
3115 if (obj->node()) // If we are a continuation, we want to make sure to use th e primary renderer. | |
3116 obj = obj->node()->renderer(); | |
3117 | |
3118 // absoluteFocusRingQuads will query the hierarchy below this element, which for large webpages can be very slow. | |
3119 // For a web area, which will have the most elements of any element, absolut eQuads should be used. | |
3120 // We should also use absoluteQuads for SVG elements, otherwise transforms w on't be applied. | |
3121 Vector<FloatQuad> quads; | |
3122 bool isSVGRoot = false; | |
3123 #if ENABLE(SVG) | |
3124 if (obj->isSVGRoot()) | |
3125 isSVGRoot = true; | |
3126 #endif | |
3127 if (obj->isText()) | |
3128 toRenderText(obj)->absoluteQuads(quads, 0, RenderText::ClipToEllipsis); | |
3129 else if (isWebArea() || isSeamlessWebArea() || isSVGRoot) | |
3130 obj->absoluteQuads(quads); | |
3131 else | |
3132 obj->absoluteFocusRingQuads(quads); | |
3133 | |
3134 LayoutRect result = boundingBoxForQuads(obj, quads); | |
3135 | |
3136 #if ENABLE(SVG) | |
3137 Document* document = this->document(); | |
3138 if (document && document->isSVGDocument()) | |
3139 offsetBoundingBoxForRemoteSVGElement(result); | |
3140 #endif | |
3141 | |
3142 // The size of the web area should be the content size, not the clipped size . | |
3143 if ((isWebArea() || isSeamlessWebArea()) && obj->frame()->view()) | |
3144 result.setSize(obj->frame()->view()->contentsSize()); | |
3145 | |
3146 // Checkboxes and radio buttons include their label as part of their rect. | |
3147 if (isCheckboxOrRadio()) { | |
3148 HTMLLabelElement* label = labelForElement(toElement(m_renderer->node())) ; | |
3149 if (label && !label->renderer()) { | |
3150 LayoutRect labelRect = axObjectCache()->getOrCreate(label)->elementR ect(); | |
3151 result.unite(labelRect); | |
3152 } | |
3153 } | |
3154 | |
3155 return result; | |
3156 } | |
3157 | |
3132 } // namespace WebCore | 3158 } // namespace WebCore |
OLD | NEW |