Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(54)

Side by Side Diff: Source/core/accessibility/AccessibilityRenderObject.cpp

Issue 14740025: Simplify and add caching for accessible bounding box calculation. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Re-landing with null check fix Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « Source/core/accessibility/AccessibilityRenderObject.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « Source/core/accessibility/AccessibilityRenderObject.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698