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

Side by Side Diff: third_party/WebKit/Source/modules/accessibility/AXLayoutObject.cpp

Issue 2287433003: Get rid of remaining uses of AXObject::elementRect (Closed)
Patch Set: Rebase Created 4 years, 3 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
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 162 matching lines...) Expand 10 before | Expand all | Expand 10 after
173 if (layoutObject->isLayoutInline() && !layoutObject->isAtomicInlineLevel()) 173 if (layoutObject->isLayoutInline() && !layoutObject->isAtomicInlineLevel())
174 return toLayoutInline(layoutObject)->continuation(); 174 return toLayoutInline(layoutObject)->continuation();
175 if (layoutObject->isLayoutBlockFlow()) 175 if (layoutObject->isLayoutBlockFlow())
176 return toLayoutBlockFlow(layoutObject)->inlineElementContinuation(); 176 return toLayoutBlockFlow(layoutObject)->inlineElementContinuation();
177 return 0; 177 return 0;
178 } 178 }
179 179
180 AXLayoutObject::AXLayoutObject(LayoutObject* layoutObject, AXObjectCacheImpl& ax ObjectCache) 180 AXLayoutObject::AXLayoutObject(LayoutObject* layoutObject, AXObjectCacheImpl& ax ObjectCache)
181 : AXNodeObject(layoutObject->node(), axObjectCache) 181 : AXNodeObject(layoutObject->node(), axObjectCache)
182 , m_layoutObject(layoutObject) 182 , m_layoutObject(layoutObject)
183 , m_cachedElementRectDirty(true)
184 { 183 {
185 #if ENABLE(ASSERT) 184 #if ENABLE(ASSERT)
186 m_layoutObject->setHasAXObject(true); 185 m_layoutObject->setHasAXObject(true);
187 #endif 186 #endif
188 } 187 }
189 188
190 AXLayoutObject* AXLayoutObject::create(LayoutObject* layoutObject, AXObjectCache Impl& axObjectCache) 189 AXLayoutObject* AXLayoutObject::create(LayoutObject* layoutObject, AXObjectCache Impl& axObjectCache)
191 { 190 {
192 return new AXLayoutObject(layoutObject, axObjectCache); 191 return new AXLayoutObject(layoutObject, axObjectCache);
193 } 192 }
194 193
195 AXLayoutObject::~AXLayoutObject() 194 AXLayoutObject::~AXLayoutObject()
196 { 195 {
197 ASSERT(isDetached()); 196 ASSERT(isDetached());
198 } 197 }
199 198
200 LayoutRect AXLayoutObject::elementRect() const
201 {
202 if (!m_explicitElementRect.isEmpty()) {
203 LayoutRect bounds = m_explicitElementRect;
204 AXObject* canvas = axObjectCache().objectFromAXID(m_explicitContainerID) ;
205 if (canvas)
206 bounds.moveBy(canvas->elementRect().location());
207 return bounds;
208 }
209
210 // FIXME(dmazzoni): use relative bounds instead since this is a bottleneck.
211 // http://crbug.com/618120
212 return computeElementRect();
213 }
214
215 SkMatrix44 AXLayoutObject::transformFromLocalParentFrame() const
216 {
217 if (!m_layoutObject)
218 return SkMatrix44();
219 LayoutView* layoutView = toLayoutView(LayoutAPIShim::layoutObjectFrom(docume ntFrameView()->layoutViewItem()));
220
221 FrameView* parentFrameView = documentFrameView()->parentFrameView();
222 if (!parentFrameView)
223 return SkMatrix44();
224 LayoutView* parentLayoutView = toLayoutView(LayoutAPIShim::layoutObjectFrom( parentFrameView->layoutViewItem()));
225
226 TransformationMatrix accumulatedTransform = layoutView->localToAncestorTrans form(parentLayoutView, TraverseDocumentBoundaries);
227 IntPoint scrollPosition = documentFrameView()->scrollPosition();
228 accumulatedTransform.translate(scrollPosition.x(), scrollPosition.y());
229 return TransformationMatrix::toSkMatrix44(accumulatedTransform);
230 }
231
232 LayoutBoxModelObject* AXLayoutObject::getLayoutBoxModelObject() const 199 LayoutBoxModelObject* AXLayoutObject::getLayoutBoxModelObject() const
233 { 200 {
234 if (!m_layoutObject || !m_layoutObject->isBoxModelObject()) 201 if (!m_layoutObject || !m_layoutObject->isBoxModelObject())
235 return 0; 202 return 0;
236 return toLayoutBoxModelObject(m_layoutObject); 203 return toLayoutBoxModelObject(m_layoutObject);
237 } 204 }
238 205
239 ScrollableArea* AXLayoutObject::getScrollableAreaIfScrollable() const 206 ScrollableArea* AXLayoutObject::getScrollableAreaIfScrollable() const
240 { 207 {
241 if (isWebArea()) 208 if (isWebArea())
242 return documentFrameView(); 209 return documentFrameView();
243 210
244 if (!m_layoutObject || !m_layoutObject->isBox()) 211 if (!m_layoutObject || !m_layoutObject->isBox())
245 return 0; 212 return 0;
246 213
247 LayoutBox* box = toLayoutBox(m_layoutObject); 214 LayoutBox* box = toLayoutBox(m_layoutObject);
248 if (!box->canBeScrolledAndHasScrollableArea()) 215 if (!box->canBeScrolledAndHasScrollableArea())
249 return 0; 216 return 0;
250 217
251 return box->getScrollableArea(); 218 return box->getScrollableArea();
252 } 219 }
253 220
254 void AXLayoutObject::getRelativeBounds(AXObject** outContainer, FloatRect& outBo undsInContainer, SkMatrix44& outContainerTransform) const
255 {
256 *outContainer = nullptr;
257 outBoundsInContainer = FloatRect();
258 outContainerTransform.setIdentity();
259
260 // First check if it has explicit bounds, for example if this element is tie d to a
261 // canvas path. When explicit coordinates are provided, the ID of the explic it container
262 // element that the coordinates are relative to must be provided too.
263 if (!m_explicitElementRect.isEmpty()) {
264 *outContainer = axObjectCache().objectFromAXID(m_explicitContainerID);
265 if (*outContainer) {
266 outBoundsInContainer = FloatRect(m_explicitElementRect);
267 return;
268 }
269 }
270
271 if (!m_layoutObject)
272 return;
273
274 if (isWebArea()) {
275 if (m_layoutObject->frame()->view())
276 outBoundsInContainer.setSize(FloatSize(m_layoutObject->frame()->view ()->contentsSize()));
277 return;
278 }
279
280 // First compute the container. The container must be an ancestor in the acc essibility tree, and
281 // its LayoutObject must be an ancestor in the layout tree. Get the first su ch ancestor that's
282 // either scrollable or has a paint layer.
283 AXObject* container = parentObjectUnignored();
284 LayoutObject* containerLayoutObject = nullptr;
285 while (container) {
286 containerLayoutObject = container->getLayoutObject();
287 if (containerLayoutObject && containerLayoutObject->isBoxModelObject() & & m_layoutObject->isDescendantOf(containerLayoutObject)) {
288 if (container->isScrollableContainer() || containerLayoutObject->has Layer())
289 break;
290 }
291
292 container = container->parentObjectUnignored();
293 }
294
295 if (!container)
296 return;
297 *outContainer = container;
298
299 // Next get the local bounds of this LayoutObject, which is typically
300 // a rect at point (0, 0) with the width and height of the LayoutObject.
301 LayoutRect localBounds;
302 if (m_layoutObject->isText()) {
303 Vector<FloatQuad> quads;
304 toLayoutText(m_layoutObject)->quads(quads, LayoutText::ClipToEllipsis, L ayoutText::LocalQuads);
305 for (const FloatQuad& quad : quads)
306 localBounds.unite(LayoutRect(quad.boundingBox()));
307 } else if (m_layoutObject->isLayoutInline()) {
308 Vector<LayoutRect> rects;
309 toLayoutInline(m_layoutObject)->addOutlineRects(rects, LayoutPoint(), La youtObject::IncludeBlockVisualOverflow);
310 localBounds = unionRect(rects);
311 } else if (m_layoutObject->isBox()) {
312 localBounds = LayoutRect(LayoutPoint(), toLayoutBox(m_layoutObject)->siz e());
313 } else if (m_layoutObject->isSVG()) {
314 localBounds = LayoutRect(m_layoutObject->strokeBoundingBox());
315 } else {
316 DCHECK(false);
317 }
318 outBoundsInContainer = FloatRect(localBounds);
319
320 // If the container has a scroll offset, subtract that out because we want o ur
321 // bounds to be relative to the *unscrolled* position of the container objec t.
322 ScrollableArea* scrollableArea = container->getScrollableAreaIfScrollable();
323 if (scrollableArea && !container->isWebArea()) {
324 IntPoint scrollPosition = scrollableArea->scrollPosition();
325 outBoundsInContainer.move(FloatSize(scrollPosition.x(), scrollPosition.y ()));
326 }
327
328 // Compute the transform between the container's coordinate space and this o bject.
329 // If the transform is just a simple translation, apply that to the bounding box, but
330 // if it's a non-trivial transformation like a rotation, scaling, etc. then return
331 // the full matrix instead.
332 TransformationMatrix transform = m_layoutObject->localToAncestorTransform(to LayoutBoxModelObject(containerLayoutObject));
333 if (transform.isIdentityOr2DTranslation()) {
334 outBoundsInContainer.move(transform.to2DTranslation());
335 } else {
336 outContainerTransform = TransformationMatrix::toSkMatrix44(transform);
337 }
338 }
339
340 static bool isImageOrAltText(LayoutBoxModelObject* box, Node* node) 221 static bool isImageOrAltText(LayoutBoxModelObject* box, Node* node)
341 { 222 {
342 if (box && box->isImage()) 223 if (box && box->isImage())
343 return true; 224 return true;
344 if (isHTMLImageElement(node)) 225 if (isHTMLImageElement(node))
345 return true; 226 return true;
346 if (isHTMLInputElement(node) && toHTMLInputElement(node)->hasFallbackContent ()) 227 if (isHTMLInputElement(node) && toHTMLInputElement(node)->hasFallbackContent ())
347 return true; 228 return true;
348 return false; 229 return false;
349 } 230 }
(...skipping 1083 matching lines...) Expand 10 before | Expand all | Expand 10 after
1433 } 1314 }
1434 return elementAttributeValue(aria_atomicAttr); 1315 return elementAttributeValue(aria_atomicAttr);
1435 } 1316 }
1436 1317
1437 bool AXLayoutObject::liveRegionBusy() const 1318 bool AXLayoutObject::liveRegionBusy() const
1438 { 1319 {
1439 return elementAttributeValue(aria_busyAttr); 1320 return elementAttributeValue(aria_busyAttr);
1440 } 1321 }
1441 1322
1442 // 1323 //
1443 // Position and size.
1444 //
1445
1446 void AXLayoutObject::checkCachedElementRect() const
1447 {
1448 if (m_cachedElementRectDirty)
1449 return;
1450
1451 if (!m_layoutObject)
1452 return;
1453
1454 if (!m_layoutObject->isBox())
1455 return;
1456
1457 bool dirty = false;
1458 LayoutBox* box = toLayoutBox(m_layoutObject);
1459 if (box->frameRect() != m_cachedFrameRect)
1460 dirty = true;
1461
1462 if (box->canBeScrolledAndHasScrollableArea()) {
1463 ScrollableArea* scrollableArea = box->getScrollableArea();
1464 if (scrollableArea && scrollableArea->scrollPosition() != m_cachedScroll Position)
1465 dirty = true;
1466 }
1467
1468 if (dirty)
1469 markCachedElementRectDirty();
1470 }
1471
1472 void AXLayoutObject::updateCachedElementRect() const
1473 {
1474 if (!m_cachedElementRectDirty)
1475 return;
1476
1477 if (!m_layoutObject)
1478 return;
1479
1480 if (!m_layoutObject->isBox())
1481 return;
1482
1483 LayoutBox* box = toLayoutBox(m_layoutObject);
1484 m_cachedFrameRect = box->frameRect();
1485
1486 if (box->canBeScrolledAndHasScrollableArea()) {
1487 ScrollableArea* scrollableArea = box->getScrollableArea();
1488 if (scrollableArea)
1489 m_cachedScrollPosition = scrollableArea->scrollPosition();
1490 }
1491
1492 m_cachedElementRect = computeElementRect();
1493 m_cachedElementRectDirty = false;
1494 }
1495
1496 void AXLayoutObject::markCachedElementRectDirty() const
1497 {
1498 if (m_cachedElementRectDirty)
1499 return;
1500
1501 // Marks children recursively, if this element changed.
1502 m_cachedElementRectDirty = true;
1503 for (AXObject* child = rawFirstChild(); child; child = child->rawNextSibling ())
1504 child->markCachedElementRectDirty();
1505 }
1506
1507 IntPoint AXLayoutObject::clickPoint()
1508 {
1509 // Headings are usually much wider than their textual content. If the mid po int is used, often it can be wrong.
1510 if (isHeading() && children().size() == 1)
1511 return children()[0]->clickPoint();
1512
1513 // use the default position unless this is an editable web area, in which ca se we use the selection bounds.
1514 if (!isWebArea() || isReadOnly())
1515 return AXObject::clickPoint();
1516
1517 IntRect bounds = pixelSnappedIntRect(elementRect());
1518 return IntPoint(bounds.x() + (bounds.width() / 2), bounds.y() - (bounds.heig ht() / 2));
1519 }
1520
1521 //
1522 // Hit testing. 1324 // Hit testing.
1523 // 1325 //
1524 1326
1525 AXObject* AXLayoutObject::accessibilityHitTest(const IntPoint& point) const 1327 AXObject* AXLayoutObject::accessibilityHitTest(const IntPoint& point) const
1526 { 1328 {
1527 if (!m_layoutObject || !m_layoutObject->hasLayer()) 1329 if (!m_layoutObject || !m_layoutObject->hasLayer())
1528 return nullptr; 1330 return nullptr;
1529 1331
1530 PaintLayer* layer = toLayoutBox(m_layoutObject)->layer(); 1332 PaintLayer* layer = toLayoutBox(m_layoutObject)->layer();
1531 1333
(...skipping 809 matching lines...) Expand 10 before | Expand all | Expand 10 after
2341 AXObject* AXLayoutObject::accessibilityImageMapHitTest(HTMLAreaElement* area, co nst IntPoint& point) const 2143 AXObject* AXLayoutObject::accessibilityImageMapHitTest(HTMLAreaElement* area, co nst IntPoint& point) const
2342 { 2144 {
2343 if (!area) 2145 if (!area)
2344 return 0; 2146 return 0;
2345 2147
2346 AXObject* parent = axObjectCache().getOrCreate(area->imageElement()); 2148 AXObject* parent = axObjectCache().getOrCreate(area->imageElement());
2347 if (!parent) 2149 if (!parent)
2348 return 0; 2150 return 0;
2349 2151
2350 for (const auto& child : parent->children()) { 2152 for (const auto& child : parent->children()) {
2351 if (child->elementRect().contains(point)) 2153 if (child->getBoundsInFrameCoordinates().contains(point))
2352 return child.get(); 2154 return child.get();
2353 } 2155 }
2354 2156
2355 return 0; 2157 return 0;
2356 } 2158 }
2357 2159
2358 LayoutObject* AXLayoutObject::layoutParentObject() const 2160 LayoutObject* AXLayoutObject::layoutParentObject() const
2359 { 2161 {
2360 if (!m_layoutObject) 2162 if (!m_layoutObject)
2361 return 0; 2163 return 0;
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
2415 // remote SVG document. I'm disabling this support until it can be fixed pro perly. 2217 // remote SVG document. I'm disabling this support until it can be fixed pro perly.
2416 return 0; 2218 return 0;
2417 } 2219 }
2418 2220
2419 AXObject* AXLayoutObject::remoteSVGElementHitTest(const IntPoint& point) const 2221 AXObject* AXLayoutObject::remoteSVGElementHitTest(const IntPoint& point) const
2420 { 2222 {
2421 AXObject* remote = remoteSVGRootElement(); 2223 AXObject* remote = remoteSVGRootElement();
2422 if (!remote) 2224 if (!remote)
2423 return 0; 2225 return 0;
2424 2226
2425 IntSize offset = point - roundedIntPoint(elementRect().location()); 2227 IntSize offset = point - roundedIntPoint(getBoundsInFrameCoordinates().locat ion());
2426 return remote->accessibilityHitTest(IntPoint(offset)); 2228 return remote->accessibilityHitTest(IntPoint(offset));
2427 } 2229 }
2428 2230
2429 // The boundingBox for elements within the remote SVG element needs to be offset by its position 2231 // The boundingBox for elements within the remote SVG element needs to be offset by its position
2430 // within the parent page, otherwise they are in relative coordinates only. 2232 // within the parent page, otherwise they are in relative coordinates only.
2431 void AXLayoutObject::offsetBoundingBoxForRemoteSVGElement(LayoutRect& rect) cons t 2233 void AXLayoutObject::offsetBoundingBoxForRemoteSVGElement(LayoutRect& rect) cons t
2432 { 2234 {
2433 for (AXObject* parent = parentObject(); parent; parent = parent->parentObjec t()) { 2235 for (AXObject* parent = parentObject(); parent; parent = parent->parentObjec t()) {
2434 if (parent->isAXSVGRoot()) { 2236 if (parent->isAXSVGRoot()) {
2435 rect.moveBy(parent->parentObject()->elementRect().location()); 2237 rect.moveBy(parent->parentObject()->getBoundsInFrameCoordinates().lo cation());
2436 break; 2238 break;
2437 } 2239 }
2438 } 2240 }
2439 } 2241 }
2440 2242
2441 // Hidden children are those that are not laid out or visible, but are specifica lly marked as aria-hidden=false, 2243 // Hidden children are those that are not laid out or visible, but are specifica lly marked as aria-hidden=false,
2442 // meaning that they should be exposed to the AX hierarchy. 2244 // meaning that they should be exposed to the AX hierarchy.
2443 void AXLayoutObject::addHiddenChildren() 2245 void AXLayoutObject::addHiddenChildren()
2444 { 2246 {
2445 Node* node = this->getNode(); 2247 Node* node = this->getNode();
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after
2567 } 2369 }
2568 2370
2569 bool AXLayoutObject::elementAttributeValue(const QualifiedName& attributeName) c onst 2371 bool AXLayoutObject::elementAttributeValue(const QualifiedName& attributeName) c onst
2570 { 2372 {
2571 if (!m_layoutObject) 2373 if (!m_layoutObject)
2572 return false; 2374 return false;
2573 2375
2574 return equalIgnoringCase(getAttribute(attributeName), "true"); 2376 return equalIgnoringCase(getAttribute(attributeName), "true");
2575 } 2377 }
2576 2378
2577 LayoutRect AXLayoutObject::computeElementRect() const
2578 {
2579 LayoutObject* obj = m_layoutObject;
2580
2581 if (!obj)
2582 return LayoutRect();
2583
2584 if (obj->node()) // If we are a continuation, we want to make sure to use th e primary layoutObject.
2585 obj = obj->node()->layoutObject();
2586
2587 // absoluteFocusRingBoundingBox will query the hierarchy below this element, which for large webpages can be very slow.
2588 // For a web area, which will have the most elements of any element, absolut eQuads should be used.
2589 // We should also use absoluteQuads for SVG elements, otherwise transforms w on't be applied.
2590
2591 LayoutRect result;
2592 if (obj->isText()) {
2593 Vector<FloatQuad> quads;
2594 toLayoutText(obj)->quads(quads, LayoutText::ClipToEllipsis, LayoutText:: AbsoluteQuads);
2595 result = LayoutRect(boundingBoxForQuads(obj, quads));
2596 } else if (isWebArea() || obj->isSVGRoot()) {
2597 result = LayoutRect(obj->absoluteBoundingBoxRect());
2598 } else {
2599 result = LayoutRect(obj->absoluteElementBoundingBoxRect());
2600 }
2601
2602 Document* document = this->getDocument();
2603 if (document && document->isSVGDocument())
2604 offsetBoundingBoxForRemoteSVGElement(result);
2605 if (document && document->frame() && document->frame()->pagePopupOwner()) {
2606 IntPoint popupOrigin = document->view()->contentsToScreen(IntRect()).loc ation();
2607 IntPoint mainOrigin = axObjectCache().rootObject()->documentFrameView()- >contentsToScreen(IntRect()).location();
2608 result.moveBy(IntPoint(popupOrigin - mainOrigin));
2609 }
2610
2611 // The size of the web area should be the content size, not the clipped size .
2612 if (isWebArea() && obj->frame()->view())
2613 result.setSize(LayoutSize(obj->frame()->view()->contentsSize()));
2614
2615 // Checkboxes and radio buttons include their labels as part of their rect.
2616 if (isCheckboxOrRadio() && isLabelableElement(obj->node())) {
2617 LabelsNodeList* labels = toLabelableElement(obj->node())->labels();
2618 if (labels) {
2619 for (unsigned labelIndex = 0; labelIndex < labels->length(); ++label Index) {
2620 AXObject* labelAXObject = axObjectCache().getOrCreate(labels->it em(labelIndex));
2621 if (labelAXObject) {
2622 LayoutRect labelRect = labelAXObject->elementRect();
2623 result.unite(labelRect);
2624 }
2625 }
2626 }
2627 }
2628
2629 return result;
2630 }
2631
2632 } // namespace blink 2379 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698