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