| 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 229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 240 return StaticTextRole; | 240 return StaticTextRole; |
| 241 if (cssBox && isImageOrAltText(cssBox, node)) { | 241 if (cssBox && isImageOrAltText(cssBox, node)) { |
| 242 if (node && node->isLink()) | 242 if (node && node->isLink()) |
| 243 return ImageMapRole; | 243 return ImageMapRole; |
| 244 if (isHTMLInputElement(node)) | 244 if (isHTMLInputElement(node)) |
| 245 return ariaHasPopup() ? PopUpButtonRole : ButtonRole; | 245 return ariaHasPopup() ? PopUpButtonRole : ButtonRole; |
| 246 if (isSVGImage()) | 246 if (isSVGImage()) |
| 247 return SVGRootRole; | 247 return SVGRootRole; |
| 248 return ImageRole; | 248 return ImageRole; |
| 249 } | 249 } |
| 250 // Note: if JavaScript is disabled, the layoutObject won't be a LayoutHTMLCanv
as. | 250 // Note: if JavaScript is disabled, the layoutObject won't be a |
| 251 // LayoutHTMLCanvas. |
| 251 if (isHTMLCanvasElement(node) && m_layoutObject->isCanvas()) | 252 if (isHTMLCanvasElement(node) && m_layoutObject->isCanvas()) |
| 252 return CanvasRole; | 253 return CanvasRole; |
| 253 | 254 |
| 254 if (cssBox && cssBox->isLayoutView()) | 255 if (cssBox && cssBox->isLayoutView()) |
| 255 return WebAreaRole; | 256 return WebAreaRole; |
| 256 | 257 |
| 257 if (m_layoutObject->isSVGImage()) | 258 if (m_layoutObject->isSVGImage()) |
| 258 return ImageRole; | 259 return ImageRole; |
| 259 if (m_layoutObject->isSVGRoot()) | 260 if (m_layoutObject->isSVGRoot()) |
| 260 return SVGRootRole; | 261 return SVGRootRole; |
| (...skipping 15 matching lines...) Expand all Loading... |
| 276 if ((m_ariaRole = determineAriaRoleAttribute()) != UnknownRole) | 277 if ((m_ariaRole = determineAriaRoleAttribute()) != UnknownRole) |
| 277 return m_ariaRole; | 278 return m_ariaRole; |
| 278 | 279 |
| 279 AccessibilityRole role = nativeAccessibilityRoleIgnoringAria(); | 280 AccessibilityRole role = nativeAccessibilityRoleIgnoringAria(); |
| 280 if (role != UnknownRole) | 281 if (role != UnknownRole) |
| 281 return role; | 282 return role; |
| 282 | 283 |
| 283 if (m_layoutObject->isLayoutBlockFlow()) | 284 if (m_layoutObject->isLayoutBlockFlow()) |
| 284 return GroupRole; | 285 return GroupRole; |
| 285 | 286 |
| 286 // If the element does not have role, but it has ARIA attributes, accessibilit
y should fallback to exposing it as a group. | 287 // If the element does not have role, but it has ARIA attributes, |
| 288 // accessibility should fallback to exposing it as a group. |
| 287 if (supportsARIAAttributes()) | 289 if (supportsARIAAttributes()) |
| 288 return GroupRole; | 290 return GroupRole; |
| 289 | 291 |
| 290 return UnknownRole; | 292 return UnknownRole; |
| 291 } | 293 } |
| 292 | 294 |
| 293 void AXLayoutObject::init() { | 295 void AXLayoutObject::init() { |
| 294 AXNodeObject::init(); | 296 AXNodeObject::init(); |
| 295 } | 297 } |
| 296 | 298 |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 395 if (body && hasEditableStyle(*body)) | 397 if (body && hasEditableStyle(*body)) |
| 396 return false; | 398 return false; |
| 397 | 399 |
| 398 return !hasEditableStyle(document); | 400 return !hasEditableStyle(document); |
| 399 } | 401 } |
| 400 | 402 |
| 401 return AXNodeObject::isReadOnly(); | 403 return AXNodeObject::isReadOnly(); |
| 402 } | 404 } |
| 403 | 405 |
| 404 bool AXLayoutObject::isVisited() const { | 406 bool AXLayoutObject::isVisited() const { |
| 405 // FIXME: Is it a privacy violation to expose visited information to accessibi
lity APIs? | 407 // FIXME: Is it a privacy violation to expose visited information to |
| 408 // accessibility APIs? |
| 406 return m_layoutObject->style()->isLink() && | 409 return m_layoutObject->style()->isLink() && |
| 407 m_layoutObject->style()->insideLink() == InsideVisitedLink; | 410 m_layoutObject->style()->insideLink() == InsideVisitedLink; |
| 408 } | 411 } |
| 409 | 412 |
| 410 // | 413 // |
| 411 // Check object state. | 414 // Check object state. |
| 412 // | 415 // |
| 413 | 416 |
| 414 bool AXLayoutObject::isFocused() const { | 417 bool AXLayoutObject::isFocused() const { |
| 415 if (!getDocument()) | 418 if (!getDocument()) |
| 416 return false; | 419 return false; |
| 417 | 420 |
| 418 Element* focusedElement = getDocument()->focusedElement(); | 421 Element* focusedElement = getDocument()->focusedElement(); |
| 419 if (!focusedElement) | 422 if (!focusedElement) |
| 420 return false; | 423 return false; |
| 421 AXObject* focusedObject = axObjectCache().getOrCreate(focusedElement); | 424 AXObject* focusedObject = axObjectCache().getOrCreate(focusedElement); |
| 422 if (!focusedObject || !focusedObject->isAXLayoutObject()) | 425 if (!focusedObject || !focusedObject->isAXLayoutObject()) |
| 423 return false; | 426 return false; |
| 424 | 427 |
| 425 // A web area is represented by the Document node in the DOM tree, which isn't
focusable. | 428 // A web area is represented by the Document node in the DOM tree, which isn't |
| 426 // Check instead if the frame's selection controller is focused | 429 // focusable. Check instead if the frame's selection controller is focused |
| 427 if (focusedObject == this || | 430 if (focusedObject == this || |
| 428 (roleValue() == WebAreaRole && | 431 (roleValue() == WebAreaRole && |
| 429 getDocument()->frame()->selection().isFocusedAndActive())) | 432 getDocument()->frame()->selection().isFocusedAndActive())) |
| 430 return true; | 433 return true; |
| 431 | 434 |
| 432 return false; | 435 return false; |
| 433 } | 436 } |
| 434 | 437 |
| 435 bool AXLayoutObject::isSelected() const { | 438 bool AXLayoutObject::isSelected() const { |
| 436 if (!getLayoutObject() || !getNode()) | 439 if (!getLayoutObject() || !getNode()) |
| (...skipping 14 matching lines...) Expand all Loading... |
| 451 | 454 |
| 452 return false; | 455 return false; |
| 453 } | 456 } |
| 454 | 457 |
| 455 // | 458 // |
| 456 // Whether objects are ignored, i.e. not included in the tree. | 459 // Whether objects are ignored, i.e. not included in the tree. |
| 457 // | 460 // |
| 458 | 461 |
| 459 AXObjectInclusion AXLayoutObject::defaultObjectInclusion( | 462 AXObjectInclusion AXLayoutObject::defaultObjectInclusion( |
| 460 IgnoredReasons* ignoredReasons) const { | 463 IgnoredReasons* ignoredReasons) const { |
| 461 // The following cases can apply to any element that's a subclass of AXLayoutO
bject. | 464 // The following cases can apply to any element that's a subclass of |
| 465 // AXLayoutObject. |
| 462 | 466 |
| 463 if (!m_layoutObject) { | 467 if (!m_layoutObject) { |
| 464 if (ignoredReasons) | 468 if (ignoredReasons) |
| 465 ignoredReasons->append(IgnoredReason(AXNotRendered)); | 469 ignoredReasons->append(IgnoredReason(AXNotRendered)); |
| 466 return IgnoreObject; | 470 return IgnoreObject; |
| 467 } | 471 } |
| 468 | 472 |
| 469 if (m_layoutObject->style()->visibility() != EVisibility::Visible) { | 473 if (m_layoutObject->style()->visibility() != EVisibility::Visible) { |
| 470 // aria-hidden is meant to override visibility as the determinant in AX hier
archy inclusion. | 474 // aria-hidden is meant to override visibility as the determinant in AX |
| 475 // hierarchy inclusion. |
| 471 if (equalIgnoringCase(getAttribute(aria_hiddenAttr), "false")) | 476 if (equalIgnoringCase(getAttribute(aria_hiddenAttr), "false")) |
| 472 return DefaultBehavior; | 477 return DefaultBehavior; |
| 473 | 478 |
| 474 if (ignoredReasons) | 479 if (ignoredReasons) |
| 475 ignoredReasons->append(IgnoredReason(AXNotVisible)); | 480 ignoredReasons->append(IgnoredReason(AXNotVisible)); |
| 476 return IgnoreObject; | 481 return IgnoreObject; |
| 477 } | 482 } |
| 478 | 483 |
| 479 return AXObject::defaultObjectInclusion(ignoredReasons); | 484 return AXObject::defaultObjectInclusion(ignoredReasons); |
| 480 } | 485 } |
| 481 | 486 |
| 482 bool AXLayoutObject::computeAccessibilityIsIgnored( | 487 bool AXLayoutObject::computeAccessibilityIsIgnored( |
| 483 IgnoredReasons* ignoredReasons) const { | 488 IgnoredReasons* ignoredReasons) const { |
| 484 #if ENABLE(ASSERT) | 489 #if ENABLE(ASSERT) |
| 485 ASSERT(m_initialized); | 490 ASSERT(m_initialized); |
| 486 #endif | 491 #endif |
| 487 | 492 |
| 488 if (!m_layoutObject) | 493 if (!m_layoutObject) |
| 489 return true; | 494 return true; |
| 490 | 495 |
| 491 // Check first if any of the common reasons cause this element to be ignored. | 496 // Check first if any of the common reasons cause this element to be ignored. |
| 492 // Then process other use cases that need to be applied to all the various rol
es | 497 // Then process other use cases that need to be applied to all the various |
| 493 // that AXLayoutObjects take on. | 498 // roles that AXLayoutObjects take on. |
| 494 AXObjectInclusion decision = defaultObjectInclusion(ignoredReasons); | 499 AXObjectInclusion decision = defaultObjectInclusion(ignoredReasons); |
| 495 if (decision == IncludeObject) | 500 if (decision == IncludeObject) |
| 496 return false; | 501 return false; |
| 497 if (decision == IgnoreObject) | 502 if (decision == IgnoreObject) |
| 498 return true; | 503 return true; |
| 499 | 504 |
| 500 // If this element is within a parent that cannot have children, it should not
be exposed | 505 // If this element is within a parent that cannot have children, it should not |
| 506 // be exposed. |
| 501 if (isDescendantOfLeafNode()) { | 507 if (isDescendantOfLeafNode()) { |
| 502 if (ignoredReasons) | 508 if (ignoredReasons) |
| 503 ignoredReasons->append( | 509 ignoredReasons->append( |
| 504 IgnoredReason(AXAncestorIsLeafNode, leafNodeAncestor())); | 510 IgnoredReason(AXAncestorIsLeafNode, leafNodeAncestor())); |
| 505 return true; | 511 return true; |
| 506 } | 512 } |
| 507 | 513 |
| 508 if (roleValue() == IgnoredRole) { | 514 if (roleValue() == IgnoredRole) { |
| 509 if (ignoredReasons) | 515 if (ignoredReasons) |
| 510 ignoredReasons->append(IgnoredReason(AXUninteresting)); | 516 ignoredReasons->append(IgnoredReason(AXUninteresting)); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 524 } | 530 } |
| 525 | 531 |
| 526 // An ARIA tree can only have tree items and static text as children. | 532 // An ARIA tree can only have tree items and static text as children. |
| 527 if (AXObject* treeAncestor = treeAncestorDisallowingChild()) { | 533 if (AXObject* treeAncestor = treeAncestorDisallowingChild()) { |
| 528 if (ignoredReasons) | 534 if (ignoredReasons) |
| 529 ignoredReasons->append( | 535 ignoredReasons->append( |
| 530 IgnoredReason(AXAncestorDisallowsChild, treeAncestor)); | 536 IgnoredReason(AXAncestorDisallowsChild, treeAncestor)); |
| 531 return true; | 537 return true; |
| 532 } | 538 } |
| 533 | 539 |
| 534 // A LayoutPart is an iframe element or embedded object element or something l
ike | 540 // A LayoutPart is an iframe element or embedded object element or something |
| 535 // that. We don't want to ignore those. | 541 // like that. We don't want to ignore those. |
| 536 if (m_layoutObject->isLayoutPart()) | 542 if (m_layoutObject->isLayoutPart()) |
| 537 return false; | 543 return false; |
| 538 | 544 |
| 539 // Make sure renderers with layers stay in the tree. | 545 // Make sure renderers with layers stay in the tree. |
| 540 if (getLayoutObject() && getLayoutObject()->hasLayer() && getNode() && | 546 if (getLayoutObject() && getLayoutObject()->hasLayer() && getNode() && |
| 541 getNode()->hasChildren()) | 547 getNode()->hasChildren()) |
| 542 return false; | 548 return false; |
| 543 | 549 |
| 544 // find out if this element is inside of a label element. | 550 // Find out if this element is inside of a label element. If so, it may be |
| 545 // if so, it may be ignored because it's the label for a checkbox or radio but
ton | 551 // ignored because it's the label for a checkbox or radio button. |
| 546 AXObject* controlObject = correspondingControlForLabelElement(); | 552 AXObject* controlObject = correspondingControlForLabelElement(); |
| 547 if (controlObject && controlObject->isCheckboxOrRadio() && | 553 if (controlObject && controlObject->isCheckboxOrRadio() && |
| 548 controlObject->nameFromLabelElement()) { | 554 controlObject->nameFromLabelElement()) { |
| 549 if (ignoredReasons) { | 555 if (ignoredReasons) { |
| 550 HTMLLabelElement* label = labelElementContainer(); | 556 HTMLLabelElement* label = labelElementContainer(); |
| 551 if (label && label != getNode()) { | 557 if (label && label != getNode()) { |
| 552 AXObject* labelAXObject = axObjectCache().getOrCreate(label); | 558 AXObject* labelAXObject = axObjectCache().getOrCreate(label); |
| 553 ignoredReasons->append(IgnoredReason(AXLabelContainer, labelAXObject)); | 559 ignoredReasons->append(IgnoredReason(AXLabelContainer, labelAXObject)); |
| 554 } | 560 } |
| 555 | 561 |
| 556 ignoredReasons->append(IgnoredReason(AXLabelFor, controlObject)); | 562 ignoredReasons->append(IgnoredReason(AXLabelFor, controlObject)); |
| 557 } | 563 } |
| 558 return true; | 564 return true; |
| 559 } | 565 } |
| 560 | 566 |
| 561 if (m_layoutObject->isBR()) | 567 if (m_layoutObject->isBR()) |
| 562 return false; | 568 return false; |
| 563 | 569 |
| 564 if (m_layoutObject->isText()) { | 570 if (m_layoutObject->isText()) { |
| 565 // static text beneath MenuItems and MenuButtons are just reported along wit
h the menu item, so it's ignored on an individual level | 571 // Static text beneath MenuItems and MenuButtons are just reported along |
| 572 // with the menu item, so it's ignored on an individual level. |
| 566 AXObject* parent = parentObjectUnignored(); | 573 AXObject* parent = parentObjectUnignored(); |
| 567 if (parent && (parent->ariaRoleAttribute() == MenuItemRole || | 574 if (parent && (parent->ariaRoleAttribute() == MenuItemRole || |
| 568 parent->ariaRoleAttribute() == MenuButtonRole)) { | 575 parent->ariaRoleAttribute() == MenuButtonRole)) { |
| 569 if (ignoredReasons) | 576 if (ignoredReasons) |
| 570 ignoredReasons->append( | 577 ignoredReasons->append( |
| 571 IgnoredReason(AXStaticTextUsedAsNameFor, parent)); | 578 IgnoredReason(AXStaticTextUsedAsNameFor, parent)); |
| 572 return true; | 579 return true; |
| 573 } | 580 } |
| 574 LayoutText* layoutText = toLayoutText(m_layoutObject); | 581 LayoutText* layoutText = toLayoutText(m_layoutObject); |
| 575 if (!layoutText->hasTextBoxes()) { | 582 if (!layoutText->hasTextBoxes()) { |
| 576 if (ignoredReasons) | 583 if (ignoredReasons) |
| 577 ignoredReasons->append(IgnoredReason(AXEmptyText)); | 584 ignoredReasons->append(IgnoredReason(AXEmptyText)); |
| 578 return true; | 585 return true; |
| 579 } | 586 } |
| 580 | 587 |
| 581 // Don't ignore static text in editable text controls. | 588 // Don't ignore static text in editable text controls. |
| 582 for (AXObject* parent = parentObject(); parent; | 589 for (AXObject* parent = parentObject(); parent; |
| 583 parent = parent->parentObject()) { | 590 parent = parent->parentObject()) { |
| 584 if (parent->roleValue() == TextFieldRole) | 591 if (parent->roleValue() == TextFieldRole) |
| 585 return false; | 592 return false; |
| 586 } | 593 } |
| 587 | 594 |
| 588 // text elements that are just empty whitespace should not be returned | 595 // Text elements that are just empty whitespace should not be returned. |
| 589 // FIXME(dmazzoni): we probably shouldn't ignore this if the style is 'pre',
or similar... | 596 // FIXME(dmazzoni): we probably shouldn't ignore this if the style is 'pre', |
| 597 // or similar... |
| 590 if (layoutText->text().impl()->containsOnlyWhitespace()) { | 598 if (layoutText->text().impl()->containsOnlyWhitespace()) { |
| 591 if (ignoredReasons) | 599 if (ignoredReasons) |
| 592 ignoredReasons->append(IgnoredReason(AXEmptyText)); | 600 ignoredReasons->append(IgnoredReason(AXEmptyText)); |
| 593 return true; | 601 return true; |
| 594 } | 602 } |
| 595 return false; | 603 return false; |
| 596 } | 604 } |
| 597 | 605 |
| 598 if (isHeading()) | 606 if (isHeading()) |
| 599 return false; | 607 return false; |
| 600 | 608 |
| 601 if (isLandmarkRelated()) | 609 if (isLandmarkRelated()) |
| 602 return false; | 610 return false; |
| 603 | 611 |
| 604 // Header and footer tags may also be exposed as landmark roles but not always
. | 612 // Header and footer tags may also be exposed as landmark roles but not |
| 613 // always. |
| 605 if (getNode() && | 614 if (getNode() && |
| 606 (getNode()->hasTagName(headerTag) || getNode()->hasTagName(footerTag))) | 615 (getNode()->hasTagName(headerTag) || getNode()->hasTagName(footerTag))) |
| 607 return false; | 616 return false; |
| 608 | 617 |
| 609 if (isLink()) | 618 if (isLink()) |
| 610 return false; | 619 return false; |
| 611 | 620 |
| 612 // all controls are accessible | 621 // all controls are accessible |
| 613 if (isControl()) | 622 if (isControl()) |
| 614 return false; | 623 return false; |
| 615 | 624 |
| 616 if (ariaRoleAttribute() != UnknownRole) | 625 if (ariaRoleAttribute() != UnknownRole) |
| 617 return false; | 626 return false; |
| 618 | 627 |
| 619 // don't ignore labels, because they serve as TitleUIElements | 628 // don't ignore labels, because they serve as TitleUIElements |
| 620 Node* node = m_layoutObject->node(); | 629 Node* node = m_layoutObject->node(); |
| 621 if (isHTMLLabelElement(node)) | 630 if (isHTMLLabelElement(node)) |
| 622 return false; | 631 return false; |
| 623 | 632 |
| 624 // Anything that is content editable should not be ignored. | 633 // Anything that is content editable should not be ignored. |
| 625 // However, one cannot just call node->hasEditableStyle() since that will ask
if its parents | 634 // However, one cannot just call node->hasEditableStyle() since that will ask |
| 626 // are also editable. Only the top level content editable region should be exp
osed. | 635 // if its parents are also editable. Only the top level content editable |
| 636 // region should be exposed. |
| 627 if (hasContentEditableAttributeSet()) | 637 if (hasContentEditableAttributeSet()) |
| 628 return false; | 638 return false; |
| 629 | 639 |
| 630 if (roleValue() == AbbrRole) | 640 if (roleValue() == AbbrRole) |
| 631 return false; | 641 return false; |
| 632 | 642 |
| 633 // List items play an important role in defining the structure of lists. They
should not be ignored. | 643 // List items play an important role in defining the structure of lists. They |
| 644 // should not be ignored. |
| 634 if (roleValue() == ListItemRole) | 645 if (roleValue() == ListItemRole) |
| 635 return false; | 646 return false; |
| 636 | 647 |
| 637 if (roleValue() == BlockquoteRole) | 648 if (roleValue() == BlockquoteRole) |
| 638 return false; | 649 return false; |
| 639 | 650 |
| 640 if (roleValue() == DialogRole) | 651 if (roleValue() == DialogRole) |
| 641 return false; | 652 return false; |
| 642 | 653 |
| 643 if (roleValue() == FigcaptionRole) | 654 if (roleValue() == FigcaptionRole) |
| (...skipping 20 matching lines...) Expand all Loading... |
| 664 if (roleValue() == SplitterRole) | 675 if (roleValue() == SplitterRole) |
| 665 return false; | 676 return false; |
| 666 | 677 |
| 667 if (roleValue() == TimeRole) | 678 if (roleValue() == TimeRole) |
| 668 return false; | 679 return false; |
| 669 | 680 |
| 670 // if this element has aria attributes on it, it should not be ignored. | 681 // if this element has aria attributes on it, it should not be ignored. |
| 671 if (supportsARIAAttributes()) | 682 if (supportsARIAAttributes()) |
| 672 return false; | 683 return false; |
| 673 | 684 |
| 674 // <span> tags are inline tags and not meant to convey information if they hav
e no other aria | 685 // <span> tags are inline tags and not meant to convey information if they |
| 675 // information on them. If we don't ignore them, they may emit signals expecte
d to come from | 686 // have no other aria information on them. If we don't ignore them, they may |
| 676 // their parent. In addition, because included spans are GroupRole objects, an
d GroupRole | 687 // emit signals expected to come from their parent. In addition, because |
| 677 // objects are often containers with meaningful information, the inclusion of
a span can have | 688 // included spans are GroupRole objects, and GroupRole objects are often |
| 678 // the side effect of causing the immediate parent accessible to be ignored. T
his is especially | 689 // containers with meaningful information, the inclusion of a span can have |
| 679 // problematic for platforms which have distinct roles for textual block eleme
nts. | 690 // the side effect of causing the immediate parent accessible to be ignored. |
| 691 // This is especially problematic for platforms which have distinct roles for |
| 692 // textual block elements. |
| 680 if (isHTMLSpanElement(node)) { | 693 if (isHTMLSpanElement(node)) { |
| 681 if (ignoredReasons) | 694 if (ignoredReasons) |
| 682 ignoredReasons->append(IgnoredReason(AXUninteresting)); | 695 ignoredReasons->append(IgnoredReason(AXUninteresting)); |
| 683 return true; | 696 return true; |
| 684 } | 697 } |
| 685 | 698 |
| 686 // ignore images seemingly used as spacers | 699 // ignore images seemingly used as spacers |
| 687 if (isImage()) { | 700 if (isImage()) { |
| 688 // If the image can take focus, it should not be ignored, lest the user not
be able to interact with something important. | 701 // If the image can take focus, it should not be ignored, lest the user not |
| 702 // be able to interact with something important. |
| 689 if (canSetFocusAttribute()) | 703 if (canSetFocusAttribute()) |
| 690 return false; | 704 return false; |
| 691 | 705 |
| 692 if (node && node->isElementNode()) { | 706 if (node && node->isElementNode()) { |
| 693 Element* elt = toElement(node); | 707 Element* elt = toElement(node); |
| 694 const AtomicString& alt = elt->getAttribute(altAttr); | 708 const AtomicString& alt = elt->getAttribute(altAttr); |
| 695 // don't ignore an image that has an alt tag | 709 // don't ignore an image that has an alt tag |
| 696 if (!alt.getString().containsOnlyWhitespace()) | 710 if (!alt.getString().containsOnlyWhitespace()) |
| 697 return false; | 711 return false; |
| 698 // informal standard is to ignore images with zero-length alt strings | 712 // informal standard is to ignore images with zero-length alt strings |
| 699 if (!alt.isNull()) { | 713 if (!alt.isNull()) { |
| 700 if (ignoredReasons) | 714 if (ignoredReasons) |
| 701 ignoredReasons->append(IgnoredReason(AXEmptyAlt)); | 715 ignoredReasons->append(IgnoredReason(AXEmptyAlt)); |
| 702 return true; | 716 return true; |
| 703 } | 717 } |
| 704 } | 718 } |
| 705 | 719 |
| 706 if (isNativeImage() && m_layoutObject->isImage()) { | 720 if (isNativeImage() && m_layoutObject->isImage()) { |
| 707 // check for one-dimensional image | 721 // check for one-dimensional image |
| 708 LayoutImage* image = toLayoutImage(m_layoutObject); | 722 LayoutImage* image = toLayoutImage(m_layoutObject); |
| 709 if (image->size().height() <= 1 || image->size().width() <= 1) { | 723 if (image->size().height() <= 1 || image->size().width() <= 1) { |
| 710 if (ignoredReasons) | 724 if (ignoredReasons) |
| 711 ignoredReasons->append(IgnoredReason(AXProbablyPresentational)); | 725 ignoredReasons->append(IgnoredReason(AXProbablyPresentational)); |
| 712 return true; | 726 return true; |
| 713 } | 727 } |
| 714 | 728 |
| 715 // check whether laid out image was stretched from one-dimensional file im
age | 729 // Check whether laid out image was stretched from one-dimensional file |
| 730 // image. |
| 716 if (image->cachedImage()) { | 731 if (image->cachedImage()) { |
| 717 LayoutSize imageSize = image->cachedImage()->imageSize( | 732 LayoutSize imageSize = image->cachedImage()->imageSize( |
| 718 LayoutObject::shouldRespectImageOrientation(m_layoutObject), | 733 LayoutObject::shouldRespectImageOrientation(m_layoutObject), |
| 719 image->view()->zoomFactor()); | 734 image->view()->zoomFactor()); |
| 720 if (imageSize.height() <= 1 || imageSize.width() <= 1) { | 735 if (imageSize.height() <= 1 || imageSize.width() <= 1) { |
| 721 if (ignoredReasons) | 736 if (ignoredReasons) |
| 722 ignoredReasons->append(IgnoredReason(AXProbablyPresentational)); | 737 ignoredReasons->append(IgnoredReason(AXProbablyPresentational)); |
| 723 return true; | 738 return true; |
| 724 } | 739 } |
| 725 return false; | 740 return false; |
| 726 } | 741 } |
| 727 } | 742 } |
| 728 return false; | 743 return false; |
| 729 } | 744 } |
| 730 | 745 |
| 731 if (isCanvas()) { | 746 if (isCanvas()) { |
| 732 if (canvasHasFallbackContent()) | 747 if (canvasHasFallbackContent()) |
| 733 return false; | 748 return false; |
| 734 LayoutHTMLCanvas* canvas = toLayoutHTMLCanvas(m_layoutObject); | 749 LayoutHTMLCanvas* canvas = toLayoutHTMLCanvas(m_layoutObject); |
| 735 if (canvas->size().height() <= 1 || canvas->size().width() <= 1) { | 750 if (canvas->size().height() <= 1 || canvas->size().width() <= 1) { |
| 736 if (ignoredReasons) | 751 if (ignoredReasons) |
| 737 ignoredReasons->append(IgnoredReason(AXProbablyPresentational)); | 752 ignoredReasons->append(IgnoredReason(AXProbablyPresentational)); |
| 738 return true; | 753 return true; |
| 739 } | 754 } |
| 740 // Otherwise fall through; use presence of help text, title, or description
to decide. | 755 // Otherwise fall through; use presence of help text, title, or description |
| 756 // to decide. |
| 741 } | 757 } |
| 742 | 758 |
| 743 if (isWebArea() || m_layoutObject->isListMarker()) | 759 if (isWebArea() || m_layoutObject->isListMarker()) |
| 744 return false; | 760 return false; |
| 745 | 761 |
| 746 // Using the help text, title or accessibility description (so we | 762 // Using the help text, title or accessibility description (so we |
| 747 // check if there's some kind of accessible name for the element) | 763 // check if there's some kind of accessible name for the element) |
| 748 // to decide an element's visibility is not as definitive as | 764 // to decide an element's visibility is not as definitive as |
| 749 // previous checks, so this should remain as one of the last. | 765 // previous checks, so this should remain as one of the last. |
| 750 // | 766 // |
| (...skipping 273 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1024 AXObject* result = nullptr; | 1040 AXObject* result = nullptr; |
| 1025 for (InlineBox* next = inlineBox->nextOnLine(); next; | 1041 for (InlineBox* next = inlineBox->nextOnLine(); next; |
| 1026 next = next->nextOnLine()) { | 1042 next = next->nextOnLine()) { |
| 1027 LayoutObject* layoutObject = | 1043 LayoutObject* layoutObject = |
| 1028 LineLayoutAPIShim::layoutObjectFrom(next->getLineLayoutItem()); | 1044 LineLayoutAPIShim::layoutObjectFrom(next->getLineLayoutItem()); |
| 1029 result = axObjectCache().getOrCreate(layoutObject); | 1045 result = axObjectCache().getOrCreate(layoutObject); |
| 1030 if (result) | 1046 if (result) |
| 1031 break; | 1047 break; |
| 1032 } | 1048 } |
| 1033 | 1049 |
| 1034 // A static text node might span multiple lines. Try to return the first inlin
e | 1050 // A static text node might span multiple lines. Try to return the first |
| 1035 // text box within that static text if possible. | 1051 // inline text box within that static text if possible. |
| 1036 if (result && result->roleValue() == StaticTextRole && | 1052 if (result && result->roleValue() == StaticTextRole && |
| 1037 result->children().size()) | 1053 result->children().size()) |
| 1038 result = result->children()[0].get(); | 1054 result = result->children()[0].get(); |
| 1039 | 1055 |
| 1040 return result; | 1056 return result; |
| 1041 } | 1057 } |
| 1042 | 1058 |
| 1043 AXObject* AXLayoutObject::previousOnLine() const { | 1059 AXObject* AXLayoutObject::previousOnLine() const { |
| 1044 if (!getLayoutObject()) | 1060 if (!getLayoutObject()) |
| 1045 return nullptr; | 1061 return nullptr; |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1077 // | 1093 // |
| 1078 | 1094 |
| 1079 String AXLayoutObject::stringValue() const { | 1095 String AXLayoutObject::stringValue() const { |
| 1080 if (!m_layoutObject) | 1096 if (!m_layoutObject) |
| 1081 return String(); | 1097 return String(); |
| 1082 | 1098 |
| 1083 LayoutBoxModelObject* cssBox = getLayoutBoxModelObject(); | 1099 LayoutBoxModelObject* cssBox = getLayoutBoxModelObject(); |
| 1084 | 1100 |
| 1085 if (cssBox && cssBox->isMenuList()) { | 1101 if (cssBox && cssBox->isMenuList()) { |
| 1086 // LayoutMenuList will go straight to the text() of its selected item. | 1102 // LayoutMenuList will go straight to the text() of its selected item. |
| 1087 // This has to be overridden in the case where the selected item has an ARIA
label. | 1103 // This has to be overridden in the case where the selected item has an ARIA |
| 1104 // label. |
| 1088 HTMLSelectElement* selectElement = | 1105 HTMLSelectElement* selectElement = |
| 1089 toHTMLSelectElement(m_layoutObject->node()); | 1106 toHTMLSelectElement(m_layoutObject->node()); |
| 1090 int selectedIndex = selectElement->selectedIndex(); | 1107 int selectedIndex = selectElement->selectedIndex(); |
| 1091 const HeapVector<Member<HTMLElement>>& listItems = | 1108 const HeapVector<Member<HTMLElement>>& listItems = |
| 1092 selectElement->listItems(); | 1109 selectElement->listItems(); |
| 1093 if (selectedIndex >= 0 && | 1110 if (selectedIndex >= 0 && |
| 1094 static_cast<size_t>(selectedIndex) < listItems.size()) { | 1111 static_cast<size_t>(selectedIndex) < listItems.size()) { |
| 1095 const AtomicString& overriddenDescription = | 1112 const AtomicString& overriddenDescription = |
| 1096 listItems[selectedIndex]->fastGetAttribute(aria_labelAttr); | 1113 listItems[selectedIndex]->fastGetAttribute(aria_labelAttr); |
| 1097 if (!overriddenDescription.isNull()) | 1114 if (!overriddenDescription.isNull()) |
| 1098 return overriddenDescription; | 1115 return overriddenDescription; |
| 1099 } | 1116 } |
| 1100 return toLayoutMenuList(m_layoutObject)->text(); | 1117 return toLayoutMenuList(m_layoutObject)->text(); |
| 1101 } | 1118 } |
| 1102 | 1119 |
| 1103 if (isWebArea()) { | 1120 if (isWebArea()) { |
| 1104 // FIXME: Why would a layoutObject exist when the Document isn't attached to
a frame? | 1121 // FIXME: Why would a layoutObject exist when the Document isn't attached to |
| 1122 // a frame? |
| 1105 if (m_layoutObject->frame()) | 1123 if (m_layoutObject->frame()) |
| 1106 return String(); | 1124 return String(); |
| 1107 | 1125 |
| 1108 ASSERT_NOT_REACHED(); | 1126 ASSERT_NOT_REACHED(); |
| 1109 } | 1127 } |
| 1110 | 1128 |
| 1111 if (isTextControl()) | 1129 if (isTextControl()) |
| 1112 return text(); | 1130 return text(); |
| 1113 | 1131 |
| 1114 if (m_layoutObject->isFileUploadControl()) | 1132 if (m_layoutObject->isFileUploadControl()) |
| 1115 return toLayoutFileUploadControl(m_layoutObject)->fileTextValue(); | 1133 return toLayoutFileUploadControl(m_layoutObject)->fileTextValue(); |
| 1116 | 1134 |
| 1117 // Handle other HTML input elements that aren't text controls, like date and t
ime | 1135 // Handle other HTML input elements that aren't text controls, like date and |
| 1118 // controls, by returning the string value, with the exception of checkboxes | 1136 // time controls, by returning the string value, with the exception of |
| 1119 // and radio buttons (which would return "on"). | 1137 // checkboxes and radio buttons (which would return "on"). |
| 1120 if (getNode() && isHTMLInputElement(getNode())) { | 1138 if (getNode() && isHTMLInputElement(getNode())) { |
| 1121 HTMLInputElement* input = toHTMLInputElement(getNode()); | 1139 HTMLInputElement* input = toHTMLInputElement(getNode()); |
| 1122 if (input->type() != InputTypeNames::checkbox && | 1140 if (input->type() != InputTypeNames::checkbox && |
| 1123 input->type() != InputTypeNames::radio) | 1141 input->type() != InputTypeNames::radio) |
| 1124 return input->value(); | 1142 return input->value(); |
| 1125 } | 1143 } |
| 1126 | 1144 |
| 1127 // FIXME: We might need to implement a value here for more types | 1145 // FIXME: We might need to implement a value here for more types |
| 1128 // FIXME: It would be better not to advertise a value at all for the types for
which we don't implement one; | 1146 // FIXME: It would be better not to advertise a value at all for the types for |
| 1129 // this would require subclassing or making accessibilityAttributeNames do som
ething other than return a | 1147 // which we don't implement one; this would require subclassing or making |
| 1130 // single static array. | 1148 // accessibilityAttributeNames do something other than return a single static |
| 1149 // array. |
| 1131 return String(); | 1150 return String(); |
| 1132 } | 1151 } |
| 1133 | 1152 |
| 1134 String AXLayoutObject::textAlternative(bool recursive, | 1153 String AXLayoutObject::textAlternative(bool recursive, |
| 1135 bool inAriaLabelledByTraversal, | 1154 bool inAriaLabelledByTraversal, |
| 1136 AXObjectSet& visited, | 1155 AXObjectSet& visited, |
| 1137 AXNameFrom& nameFrom, | 1156 AXNameFrom& nameFrom, |
| 1138 AXRelatedObjectVector* relatedObjects, | 1157 AXRelatedObjectVector* relatedObjects, |
| 1139 NameSources* nameSources) const { | 1158 NameSources* nameSources) const { |
| 1140 if (m_layoutObject) { | 1159 if (m_layoutObject) { |
| (...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1296 const AtomicString& relevant = getAttribute(aria_relevantAttr); | 1315 const AtomicString& relevant = getAttribute(aria_relevantAttr); |
| 1297 | 1316 |
| 1298 // Default aria-relevant = "additions text". | 1317 // Default aria-relevant = "additions text". |
| 1299 if (relevant.isEmpty()) | 1318 if (relevant.isEmpty()) |
| 1300 return defaultLiveRegionRelevant; | 1319 return defaultLiveRegionRelevant; |
| 1301 | 1320 |
| 1302 return relevant; | 1321 return relevant; |
| 1303 } | 1322 } |
| 1304 | 1323 |
| 1305 bool AXLayoutObject::liveRegionAtomic() const { | 1324 bool AXLayoutObject::liveRegionAtomic() const { |
| 1306 // ARIA roles "alert" and "status" should have an implicit aria-atomic value o
f true. | 1325 // ARIA roles "alert" and "status" should have an implicit aria-atomic value |
| 1326 // of true. |
| 1307 if (getAttribute(aria_atomicAttr).isEmpty() && | 1327 if (getAttribute(aria_atomicAttr).isEmpty() && |
| 1308 (roleValue() == AlertRole || roleValue() == StatusRole)) { | 1328 (roleValue() == AlertRole || roleValue() == StatusRole)) { |
| 1309 return true; | 1329 return true; |
| 1310 } | 1330 } |
| 1311 return elementAttributeValue(aria_atomicAttr); | 1331 return elementAttributeValue(aria_atomicAttr); |
| 1312 } | 1332 } |
| 1313 | 1333 |
| 1314 bool AXLayoutObject::liveRegionBusy() const { | 1334 bool AXLayoutObject::liveRegionBusy() const { |
| 1315 return elementAttributeValue(aria_busyAttr); | 1335 return elementAttributeValue(aria_busyAttr); |
| 1316 } | 1336 } |
| (...skipping 25 matching lines...) Expand all Loading... |
| 1342 return nullptr; | 1362 return nullptr; |
| 1343 } | 1363 } |
| 1344 | 1364 |
| 1345 LayoutObject* obj = node->layoutObject(); | 1365 LayoutObject* obj = node->layoutObject(); |
| 1346 if (!obj) | 1366 if (!obj) |
| 1347 return nullptr; | 1367 return nullptr; |
| 1348 | 1368 |
| 1349 AXObject* result = axObjectCache().getOrCreate(obj); | 1369 AXObject* result = axObjectCache().getOrCreate(obj); |
| 1350 result->updateChildrenIfNecessary(); | 1370 result->updateChildrenIfNecessary(); |
| 1351 | 1371 |
| 1352 // Allow the element to perform any hit-testing it might need to do to reach n
on-layout children. | 1372 // Allow the element to perform any hit-testing it might need to do to reach |
| 1373 // non-layout children. |
| 1353 result = result->elementAccessibilityHitTest(point); | 1374 result = result->elementAccessibilityHitTest(point); |
| 1354 if (result && result->accessibilityIsIgnored()) { | 1375 if (result && result->accessibilityIsIgnored()) { |
| 1355 // If this element is the label of a control, a hit test should return the c
ontrol. | 1376 // If this element is the label of a control, a hit test should return the |
| 1377 // control. |
| 1356 if (result->isAXLayoutObject()) { | 1378 if (result->isAXLayoutObject()) { |
| 1357 AXObject* controlObject = | 1379 AXObject* controlObject = |
| 1358 toAXLayoutObject(result)->correspondingControlForLabelElement(); | 1380 toAXLayoutObject(result)->correspondingControlForLabelElement(); |
| 1359 if (controlObject && controlObject->nameFromLabelElement()) | 1381 if (controlObject && controlObject->nameFromLabelElement()) |
| 1360 return controlObject; | 1382 return controlObject; |
| 1361 } | 1383 } |
| 1362 | 1384 |
| 1363 result = result->parentObjectUnignored(); | 1385 result = result->parentObjectUnignored(); |
| 1364 } | 1386 } |
| 1365 | 1387 |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1379 // | 1401 // |
| 1380 | 1402 |
| 1381 AXObject* AXLayoutObject::computeParent() const { | 1403 AXObject* AXLayoutObject::computeParent() const { |
| 1382 ASSERT(!isDetached()); | 1404 ASSERT(!isDetached()); |
| 1383 if (!m_layoutObject) | 1405 if (!m_layoutObject) |
| 1384 return 0; | 1406 return 0; |
| 1385 | 1407 |
| 1386 if (ariaRoleAttribute() == MenuBarRole) | 1408 if (ariaRoleAttribute() == MenuBarRole) |
| 1387 return axObjectCache().getOrCreate(m_layoutObject->parent()); | 1409 return axObjectCache().getOrCreate(m_layoutObject->parent()); |
| 1388 | 1410 |
| 1389 // menuButton and its corresponding menu are DOM siblings, but Accessibility n
eeds them to be parent/child | 1411 // menuButton and its corresponding menu are DOM siblings, but Accessibility |
| 1412 // needs them to be parent/child. |
| 1390 if (ariaRoleAttribute() == MenuRole) { | 1413 if (ariaRoleAttribute() == MenuRole) { |
| 1391 AXObject* parent = menuButtonForMenu(); | 1414 AXObject* parent = menuButtonForMenu(); |
| 1392 if (parent) | 1415 if (parent) |
| 1393 return parent; | 1416 return parent; |
| 1394 } | 1417 } |
| 1395 | 1418 |
| 1396 LayoutObject* parentObj = layoutParentObject(); | 1419 LayoutObject* parentObj = layoutParentObject(); |
| 1397 if (parentObj) | 1420 if (parentObj) |
| 1398 return axObjectCache().getOrCreate(parentObj); | 1421 return axObjectCache().getOrCreate(parentObj); |
| 1399 | 1422 |
| 1400 // A WebArea's parent should be the page popup owner, if any, otherwise null. | 1423 // A WebArea's parent should be the page popup owner, if any, otherwise null. |
| 1401 if (isWebArea()) { | 1424 if (isWebArea()) { |
| 1402 LocalFrame* frame = m_layoutObject->frame(); | 1425 LocalFrame* frame = m_layoutObject->frame(); |
| 1403 return axObjectCache().getOrCreate(frame->pagePopupOwner()); | 1426 return axObjectCache().getOrCreate(frame->pagePopupOwner()); |
| 1404 } | 1427 } |
| 1405 | 1428 |
| 1406 return 0; | 1429 return 0; |
| 1407 } | 1430 } |
| 1408 | 1431 |
| 1409 AXObject* AXLayoutObject::computeParentIfExists() const { | 1432 AXObject* AXLayoutObject::computeParentIfExists() const { |
| 1410 if (!m_layoutObject) | 1433 if (!m_layoutObject) |
| 1411 return 0; | 1434 return 0; |
| 1412 | 1435 |
| 1413 if (ariaRoleAttribute() == MenuBarRole) | 1436 if (ariaRoleAttribute() == MenuBarRole) |
| 1414 return axObjectCache().get(m_layoutObject->parent()); | 1437 return axObjectCache().get(m_layoutObject->parent()); |
| 1415 | 1438 |
| 1416 // menuButton and its corresponding menu are DOM siblings, but Accessibility n
eeds them to be parent/child | 1439 // menuButton and its corresponding menu are DOM siblings, but Accessibility |
| 1440 // needs them to be parent/child. |
| 1417 if (ariaRoleAttribute() == MenuRole) { | 1441 if (ariaRoleAttribute() == MenuRole) { |
| 1418 AXObject* parent = menuButtonForMenu(); | 1442 AXObject* parent = menuButtonForMenu(); |
| 1419 if (parent) | 1443 if (parent) |
| 1420 return parent; | 1444 return parent; |
| 1421 } | 1445 } |
| 1422 | 1446 |
| 1423 LayoutObject* parentObj = layoutParentObject(); | 1447 LayoutObject* parentObj = layoutParentObject(); |
| 1424 if (parentObj) | 1448 if (parentObj) |
| 1425 return axObjectCache().get(parentObj); | 1449 return axObjectCache().get(parentObj); |
| 1426 | 1450 |
| 1427 // A WebArea's parent should be the page popup owner, if any, otherwise null. | 1451 // A WebArea's parent should be the page popup owner, if any, otherwise null. |
| 1428 if (isWebArea()) { | 1452 if (isWebArea()) { |
| 1429 LocalFrame* frame = m_layoutObject->frame(); | 1453 LocalFrame* frame = m_layoutObject->frame(); |
| 1430 return axObjectCache().get(frame->pagePopupOwner()); | 1454 return axObjectCache().get(frame->pagePopupOwner()); |
| 1431 } | 1455 } |
| 1432 | 1456 |
| 1433 return 0; | 1457 return 0; |
| 1434 } | 1458 } |
| 1435 | 1459 |
| 1436 // | 1460 // |
| 1437 // Low-level accessibility tree exploration, only for use within the accessibili
ty module. | 1461 // Low-level accessibility tree exploration, only for use within the |
| 1462 // accessibility module. |
| 1438 // | 1463 // |
| 1439 | 1464 |
| 1440 AXObject* AXLayoutObject::rawFirstChild() const { | 1465 AXObject* AXLayoutObject::rawFirstChild() const { |
| 1441 if (!m_layoutObject) | 1466 if (!m_layoutObject) |
| 1442 return 0; | 1467 return 0; |
| 1443 | 1468 |
| 1444 LayoutObject* firstChild = firstChildConsideringContinuation(m_layoutObject); | 1469 LayoutObject* firstChild = firstChildConsideringContinuation(m_layoutObject); |
| 1445 | 1470 |
| 1446 if (!firstChild) | 1471 if (!firstChild) |
| 1447 return 0; | 1472 return 0; |
| 1448 | 1473 |
| 1449 return axObjectCache().getOrCreate(firstChild); | 1474 return axObjectCache().getOrCreate(firstChild); |
| 1450 } | 1475 } |
| 1451 | 1476 |
| 1452 AXObject* AXLayoutObject::rawNextSibling() const { | 1477 AXObject* AXLayoutObject::rawNextSibling() const { |
| 1453 if (!m_layoutObject) | 1478 if (!m_layoutObject) |
| 1454 return 0; | 1479 return 0; |
| 1455 | 1480 |
| 1456 LayoutObject* nextSibling = 0; | 1481 LayoutObject* nextSibling = 0; |
| 1457 | 1482 |
| 1458 LayoutInline* inlineContinuation = | 1483 LayoutInline* inlineContinuation = |
| 1459 m_layoutObject->isLayoutBlockFlow() | 1484 m_layoutObject->isLayoutBlockFlow() |
| 1460 ? toLayoutBlockFlow(m_layoutObject)->inlineElementContinuation() | 1485 ? toLayoutBlockFlow(m_layoutObject)->inlineElementContinuation() |
| 1461 : nullptr; | 1486 : nullptr; |
| 1462 if (inlineContinuation) { | 1487 if (inlineContinuation) { |
| 1463 // Case 1: node is a block and has an inline continuation. Next sibling is t
he inline continuation's first child. | 1488 // Case 1: node is a block and has an inline continuation. Next sibling is |
| 1489 // the inline continuation's first child. |
| 1464 nextSibling = firstChildConsideringContinuation(inlineContinuation); | 1490 nextSibling = firstChildConsideringContinuation(inlineContinuation); |
| 1465 } else if (m_layoutObject->isAnonymousBlock() && | 1491 } else if (m_layoutObject->isAnonymousBlock() && |
| 1466 lastChildHasContinuation(m_layoutObject)) { | 1492 lastChildHasContinuation(m_layoutObject)) { |
| 1467 // Case 2: Anonymous block parent of the start of a continuation - skip all
the way to | 1493 // Case 2: Anonymous block parent of the start of a continuation - skip all |
| 1468 // after the parent of the end, since everything in between will be linked u
p via the continuation. | 1494 // the way to after the parent of the end, since everything in between will |
| 1495 // be linked up via the continuation. |
| 1469 LayoutObject* lastParent = | 1496 LayoutObject* lastParent = |
| 1470 endOfContinuations(toLayoutBlock(m_layoutObject)->lastChild()) | 1497 endOfContinuations(toLayoutBlock(m_layoutObject)->lastChild()) |
| 1471 ->parent(); | 1498 ->parent(); |
| 1472 while (lastChildHasContinuation(lastParent)) | 1499 while (lastChildHasContinuation(lastParent)) |
| 1473 lastParent = endOfContinuations(lastParent->slowLastChild())->parent(); | 1500 lastParent = endOfContinuations(lastParent->slowLastChild())->parent(); |
| 1474 nextSibling = lastParent->nextSibling(); | 1501 nextSibling = lastParent->nextSibling(); |
| 1475 } else if (LayoutObject* ns = m_layoutObject->nextSibling()) { | 1502 } else if (LayoutObject* ns = m_layoutObject->nextSibling()) { |
| 1476 // Case 3: node has an actual next sibling | 1503 // Case 3: node has an actual next sibling |
| 1477 nextSibling = ns; | 1504 nextSibling = ns; |
| 1478 } else if (isInlineWithContinuation(m_layoutObject)) { | 1505 } else if (isInlineWithContinuation(m_layoutObject)) { |
| 1479 // Case 4: node is an inline with a continuation. Next sibling is the next s
ibling of the end | 1506 // Case 4: node is an inline with a continuation. Next sibling is the next |
| 1480 // of the continuation chain. | 1507 // sibling of the end of the continuation chain. |
| 1481 nextSibling = endOfContinuations(m_layoutObject)->nextSibling(); | 1508 nextSibling = endOfContinuations(m_layoutObject)->nextSibling(); |
| 1482 } else if (m_layoutObject->parent() && | 1509 } else if (m_layoutObject->parent() && |
| 1483 isInlineWithContinuation(m_layoutObject->parent())) { | 1510 isInlineWithContinuation(m_layoutObject->parent())) { |
| 1484 // Case 5: node has no next sibling, and its parent is an inline with a cont
inuation. | 1511 // Case 5: node has no next sibling, and its parent is an inline with a |
| 1512 // continuation. |
| 1485 LayoutObject* continuation = | 1513 LayoutObject* continuation = |
| 1486 toLayoutInline(m_layoutObject->parent())->continuation(); | 1514 toLayoutInline(m_layoutObject->parent())->continuation(); |
| 1487 | 1515 |
| 1488 if (continuation->isLayoutBlock()) { | 1516 if (continuation->isLayoutBlock()) { |
| 1489 // Case 5a: continuation is a block - in this case the block itself is the
next sibling. | 1517 // Case 5a: continuation is a block - in this case the block itself is the |
| 1518 // next sibling. |
| 1490 nextSibling = continuation; | 1519 nextSibling = continuation; |
| 1491 } else { | 1520 } else { |
| 1492 // Case 5b: continuation is an inline - in this case the inline's first ch
ild is the next sibling. | 1521 // Case 5b: continuation is an inline - in this case the inline's first |
| 1522 // child is the next sibling. |
| 1493 nextSibling = firstChildConsideringContinuation(continuation); | 1523 nextSibling = firstChildConsideringContinuation(continuation); |
| 1494 } | 1524 } |
| 1495 } | 1525 } |
| 1496 | 1526 |
| 1497 if (!nextSibling) | 1527 if (!nextSibling) |
| 1498 return 0; | 1528 return 0; |
| 1499 | 1529 |
| 1500 return axObjectCache().getOrCreate(nextSibling); | 1530 return axObjectCache().getOrCreate(nextSibling); |
| 1501 } | 1531 } |
| 1502 | 1532 |
| 1503 void AXLayoutObject::addChildren() { | 1533 void AXLayoutObject::addChildren() { |
| 1504 ASSERT(!isDetached()); | 1534 ASSERT(!isDetached()); |
| 1505 // If the need to add more children in addition to existing children arises, | 1535 // If the need to add more children in addition to existing children arises, |
| 1506 // childrenChanged should have been called, leaving the object with no childre
n. | 1536 // childrenChanged should have been called, leaving the object with no |
| 1537 // children. |
| 1507 ASSERT(!m_haveChildren); | 1538 ASSERT(!m_haveChildren); |
| 1508 | 1539 |
| 1509 m_haveChildren = true; | 1540 m_haveChildren = true; |
| 1510 | 1541 |
| 1511 if (!canHaveChildren()) | 1542 if (!canHaveChildren()) |
| 1512 return; | 1543 return; |
| 1513 | 1544 |
| 1514 HeapVector<Member<AXObject>> ownedChildren; | 1545 HeapVector<Member<AXObject>> ownedChildren; |
| 1515 computeAriaOwnsChildren(ownedChildren); | 1546 computeAriaOwnsChildren(ownedChildren); |
| 1516 | 1547 |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1595 return getLayoutObject()->document().view(); | 1626 return getLayoutObject()->document().view(); |
| 1596 } | 1627 } |
| 1597 | 1628 |
| 1598 Element* AXLayoutObject::anchorElement() const { | 1629 Element* AXLayoutObject::anchorElement() const { |
| 1599 if (!m_layoutObject) | 1630 if (!m_layoutObject) |
| 1600 return 0; | 1631 return 0; |
| 1601 | 1632 |
| 1602 AXObjectCacheImpl& cache = axObjectCache(); | 1633 AXObjectCacheImpl& cache = axObjectCache(); |
| 1603 LayoutObject* currLayoutObject; | 1634 LayoutObject* currLayoutObject; |
| 1604 | 1635 |
| 1605 // Search up the layout tree for a LayoutObject with a DOM node. Defer to an e
arlier continuation, though. | 1636 // Search up the layout tree for a LayoutObject with a DOM node. Defer to an |
| 1637 // earlier continuation, though. |
| 1606 for (currLayoutObject = m_layoutObject; | 1638 for (currLayoutObject = m_layoutObject; |
| 1607 currLayoutObject && !currLayoutObject->node(); | 1639 currLayoutObject && !currLayoutObject->node(); |
| 1608 currLayoutObject = currLayoutObject->parent()) { | 1640 currLayoutObject = currLayoutObject->parent()) { |
| 1609 if (currLayoutObject->isAnonymousBlock() && | 1641 if (currLayoutObject->isAnonymousBlock() && |
| 1610 currLayoutObject->isLayoutBlockFlow()) { | 1642 currLayoutObject->isLayoutBlockFlow()) { |
| 1611 LayoutObject* continuation = | 1643 LayoutObject* continuation = |
| 1612 toLayoutBlockFlow(currLayoutObject)->continuation(); | 1644 toLayoutBlockFlow(currLayoutObject)->continuation(); |
| 1613 if (continuation) | 1645 if (continuation) |
| 1614 return cache.getOrCreate(continuation)->anchorElement(); | 1646 return cache.getOrCreate(continuation)->anchorElement(); |
| 1615 } | 1647 } |
| 1616 } | 1648 } |
| 1617 | 1649 |
| 1618 // bail if none found | 1650 // bail if none found |
| 1619 if (!currLayoutObject) | 1651 if (!currLayoutObject) |
| 1620 return 0; | 1652 return 0; |
| 1621 | 1653 |
| 1622 // search up the DOM tree for an anchor element | 1654 // Search up the DOM tree for an anchor element. |
| 1623 // NOTE: this assumes that any non-image with an anchor is an HTMLAnchorElemen
t | 1655 // NOTE: this assumes that any non-image with an anchor is an |
| 1656 // HTMLAnchorElement |
| 1624 Node* node = currLayoutObject->node(); | 1657 Node* node = currLayoutObject->node(); |
| 1625 if (!node) | 1658 if (!node) |
| 1626 return nullptr; | 1659 return nullptr; |
| 1627 for (Node& runner : NodeTraversal::inclusiveAncestorsOf(*node)) { | 1660 for (Node& runner : NodeTraversal::inclusiveAncestorsOf(*node)) { |
| 1628 if (isHTMLAnchorElement(runner) || | 1661 if (isHTMLAnchorElement(runner) || |
| 1629 (runner.layoutObject() && | 1662 (runner.layoutObject() && |
| 1630 cache.getOrCreate(runner.layoutObject())->isAnchor())) | 1663 cache.getOrCreate(runner.layoutObject())->isAnchor())) |
| 1631 return toElement(&runner); | 1664 return toElement(&runner); |
| 1632 } | 1665 } |
| 1633 | 1666 |
| (...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1812 | 1845 |
| 1813 // Convert from an accessible object and offset to a VisiblePosition. | 1846 // Convert from an accessible object and offset to a VisiblePosition. |
| 1814 static VisiblePosition toVisiblePosition(AXObject* obj, int offset) { | 1847 static VisiblePosition toVisiblePosition(AXObject* obj, int offset) { |
| 1815 if (!obj->getNode()) | 1848 if (!obj->getNode()) |
| 1816 return VisiblePosition(); | 1849 return VisiblePosition(); |
| 1817 | 1850 |
| 1818 Node* node = obj->getNode(); | 1851 Node* node = obj->getNode(); |
| 1819 if (!node->isTextNode()) { | 1852 if (!node->isTextNode()) { |
| 1820 int childCount = obj->children().size(); | 1853 int childCount = obj->children().size(); |
| 1821 | 1854 |
| 1822 // Place position immediately before the container node, if there was no chi
ldren. | 1855 // Place position immediately before the container node, if there was no |
| 1856 // children. |
| 1823 if (childCount == 0) { | 1857 if (childCount == 0) { |
| 1824 if (!obj->parentObject()) | 1858 if (!obj->parentObject()) |
| 1825 return VisiblePosition(); | 1859 return VisiblePosition(); |
| 1826 return toVisiblePosition(obj->parentObject(), obj->indexInParent()); | 1860 return toVisiblePosition(obj->parentObject(), obj->indexInParent()); |
| 1827 } | 1861 } |
| 1828 | 1862 |
| 1829 // The offsets are child offsets over the AX tree. Note that we allow | 1863 // The offsets are child offsets over the AX tree. Note that we allow |
| 1830 // for the offset to equal the number of children as |Range| does. | 1864 // for the offset to equal the number of children as |Range| does. |
| 1831 if (offset < 0 || offset > childCount) | 1865 if (offset < 0 || offset > childCount) |
| 1832 return VisiblePosition(); | 1866 return VisiblePosition(); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1846 | 1880 |
| 1847 // If we had to clamp the offset above, the client wants to select the | 1881 // If we had to clamp the offset above, the client wants to select the |
| 1848 // end of the node. | 1882 // end of the node. |
| 1849 if (clampedOffset != offset) | 1883 if (clampedOffset != offset) |
| 1850 adjustedOffset++; | 1884 adjustedOffset++; |
| 1851 | 1885 |
| 1852 return createVisiblePosition( | 1886 return createVisiblePosition( |
| 1853 Position::editingPositionOf(childNode->parentNode(), adjustedOffset)); | 1887 Position::editingPositionOf(childNode->parentNode(), adjustedOffset)); |
| 1854 } | 1888 } |
| 1855 | 1889 |
| 1856 // If it is a text node, we need to call some utility functions that use a Tex
tIterator | 1890 // If it is a text node, we need to call some utility functions that use a |
| 1857 // to walk the characters of the node and figure out the position correspondin
g to the | 1891 // TextIterator to walk the characters of the node and figure out the position |
| 1858 // visible character at position |offset|. | 1892 // corresponding to the visible character at position |offset|. |
| 1859 ContainerNode* parent = node->parentNode(); | 1893 ContainerNode* parent = node->parentNode(); |
| 1860 if (!parent) | 1894 if (!parent) |
| 1861 return VisiblePosition(); | 1895 return VisiblePosition(); |
| 1862 | 1896 |
| 1863 VisiblePosition nodePosition = blink::visiblePositionBeforeNode(*node); | 1897 VisiblePosition nodePosition = blink::visiblePositionBeforeNode(*node); |
| 1864 int nodeIndex = blink::indexForVisiblePosition(nodePosition, parent); | 1898 int nodeIndex = blink::indexForVisiblePosition(nodePosition, parent); |
| 1865 return blink::visiblePositionForIndex(nodeIndex + offset, parent); | 1899 return blink::visiblePositionForIndex(nodeIndex + offset, parent); |
| 1866 } | 1900 } |
| 1867 | 1901 |
| 1868 void AXLayoutObject::setSelection(const AXRange& selection) { | 1902 void AXLayoutObject::setSelection(const AXRange& selection) { |
| (...skipping 25 matching lines...) Expand all Loading... |
| 1894 selection.anchorOffset, | 1928 selection.anchorOffset, |
| 1895 SelectionHasBackwardDirection); | 1929 SelectionHasBackwardDirection); |
| 1896 } | 1930 } |
| 1897 return; | 1931 return; |
| 1898 } | 1932 } |
| 1899 | 1933 |
| 1900 LocalFrame* frame = getLayoutObject()->frame(); | 1934 LocalFrame* frame = getLayoutObject()->frame(); |
| 1901 if (!frame) | 1935 if (!frame) |
| 1902 return; | 1936 return; |
| 1903 | 1937 |
| 1904 // TODO(dglazkov): The use of updateStyleAndLayoutIgnorePendingStylesheets nee
ds to be audited. | 1938 // TODO(dglazkov): The use of updateStyleAndLayoutIgnorePendingStylesheets |
| 1905 // see http://crbug.com/590369 for more details. | 1939 // needs to be audited. see http://crbug.com/590369 for more details. |
| 1906 // This callsite should probably move up the stack. | 1940 // This callsite should probably move up the stack. |
| 1907 frame->document()->updateStyleAndLayoutIgnorePendingStylesheets(); | 1941 frame->document()->updateStyleAndLayoutIgnorePendingStylesheets(); |
| 1908 | 1942 |
| 1909 // Set the selection based on visible positions, because the offsets in access
ibility nodes | 1943 // Set the selection based on visible positions, because the offsets in |
| 1910 // are based on visible indexes, which often skips redundant whitespace, for e
xample. | 1944 // accessibility nodes are based on visible indexes, which often skips |
| 1945 // redundant whitespace, for example. |
| 1911 VisiblePosition anchorVisiblePosition = | 1946 VisiblePosition anchorVisiblePosition = |
| 1912 toVisiblePosition(anchorObject, selection.anchorOffset); | 1947 toVisiblePosition(anchorObject, selection.anchorOffset); |
| 1913 VisiblePosition focusVisiblePosition = | 1948 VisiblePosition focusVisiblePosition = |
| 1914 toVisiblePosition(focusObject, selection.focusOffset); | 1949 toVisiblePosition(focusObject, selection.focusOffset); |
| 1915 if (anchorVisiblePosition.isNull() || focusVisiblePosition.isNull()) | 1950 if (anchorVisiblePosition.isNull() || focusVisiblePosition.isNull()) |
| 1916 return; | 1951 return; |
| 1917 | 1952 |
| 1918 frame->selection().setSelection( | 1953 frame->selection().setSelection( |
| 1919 createVisibleSelection(anchorVisiblePosition, focusVisiblePosition)); | 1954 createVisibleSelection(anchorVisiblePosition, focusVisiblePosition)); |
| 1920 } | 1955 } |
| (...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2103 0) | 2138 0) |
| 2104 break; | 2139 break; |
| 2105 } | 2140 } |
| 2106 } | 2141 } |
| 2107 | 2142 |
| 2108 // | 2143 // |
| 2109 // Private. | 2144 // Private. |
| 2110 // | 2145 // |
| 2111 | 2146 |
| 2112 AXObject* AXLayoutObject::treeAncestorDisallowingChild() const { | 2147 AXObject* AXLayoutObject::treeAncestorDisallowingChild() const { |
| 2113 // Determine if this is in a tree. If so, we apply special behavior to make it
work like an AXOutline. | 2148 // Determine if this is in a tree. If so, we apply special behavior to make it |
| 2149 // work like an AXOutline. |
| 2114 AXObject* axObj = parentObject(); | 2150 AXObject* axObj = parentObject(); |
| 2115 AXObject* treeAncestor = 0; | 2151 AXObject* treeAncestor = 0; |
| 2116 while (axObj) { | 2152 while (axObj) { |
| 2117 if (axObj->isTree()) { | 2153 if (axObj->isTree()) { |
| 2118 treeAncestor = axObj; | 2154 treeAncestor = axObj; |
| 2119 break; | 2155 break; |
| 2120 } | 2156 } |
| 2121 axObj = axObj->parentObject(); | 2157 axObj = axObj->parentObject(); |
| 2122 } | 2158 } |
| 2123 | 2159 |
| 2124 // If the object is in a tree, only tree items should be exposed (and the chil
dren of tree items). | 2160 // If the object is in a tree, only tree items should be exposed (and the |
| 2161 // children of tree items). |
| 2125 if (treeAncestor) { | 2162 if (treeAncestor) { |
| 2126 AccessibilityRole role = roleValue(); | 2163 AccessibilityRole role = roleValue(); |
| 2127 if (role != TreeItemRole && role != StaticTextRole) | 2164 if (role != TreeItemRole && role != StaticTextRole) |
| 2128 return treeAncestor; | 2165 return treeAncestor; |
| 2129 } | 2166 } |
| 2130 return 0; | 2167 return 0; |
| 2131 } | 2168 } |
| 2132 | 2169 |
| 2133 bool AXLayoutObject::isTabItemSelected() const { | 2170 bool AXLayoutObject::isTabItemSelected() const { |
| 2134 if (!isTabItem() || !getLayoutObject()) | 2171 if (!isTabItem() || !getLayoutObject()) |
| 2135 return false; | 2172 return false; |
| 2136 | 2173 |
| 2137 Node* node = getNode(); | 2174 Node* node = getNode(); |
| 2138 if (!node || !node->isElementNode()) | 2175 if (!node || !node->isElementNode()) |
| 2139 return false; | 2176 return false; |
| 2140 | 2177 |
| 2141 // The ARIA spec says a tab item can also be selected if it is aria-labeled by
a tabpanel | 2178 // The ARIA spec says a tab item can also be selected if it is aria-labeled by |
| 2142 // that has keyboard focus inside of it, or if a tabpanel in its aria-controls
list has KB | 2179 // a tabpanel that has keyboard focus inside of it, or if a tabpanel in its |
| 2143 // focus inside of it. | 2180 // aria-controls list has KB focus inside of it. |
| 2144 AXObject* focusedElement = axObjectCache().focusedObject(); | 2181 AXObject* focusedElement = axObjectCache().focusedObject(); |
| 2145 if (!focusedElement) | 2182 if (!focusedElement) |
| 2146 return false; | 2183 return false; |
| 2147 | 2184 |
| 2148 HeapVector<Member<Element>> elements; | 2185 HeapVector<Member<Element>> elements; |
| 2149 elementsFromAttribute(elements, aria_controlsAttr); | 2186 elementsFromAttribute(elements, aria_controlsAttr); |
| 2150 | 2187 |
| 2151 for (const auto& element : elements) { | 2188 for (const auto& element : elements) { |
| 2152 AXObject* tabPanel = axObjectCache().getOrCreate(element); | 2189 AXObject* tabPanel = axObjectCache().getOrCreate(element); |
| 2153 | 2190 |
| 2154 // A tab item should only control tab panels. | 2191 // A tab item should only control tab panels. |
| 2155 if (!tabPanel || tabPanel->roleValue() != TabPanelRole) | 2192 if (!tabPanel || tabPanel->roleValue() != TabPanelRole) |
| 2156 continue; | 2193 continue; |
| 2157 | 2194 |
| 2158 AXObject* checkFocusElement = focusedElement; | 2195 AXObject* checkFocusElement = focusedElement; |
| 2159 // Check if the focused element is a descendant of the element controlled by
the tab item. | 2196 // Check if the focused element is a descendant of the element controlled by |
| 2197 // the tab item. |
| 2160 while (checkFocusElement) { | 2198 while (checkFocusElement) { |
| 2161 if (tabPanel == checkFocusElement) | 2199 if (tabPanel == checkFocusElement) |
| 2162 return true; | 2200 return true; |
| 2163 checkFocusElement = checkFocusElement->parentObject(); | 2201 checkFocusElement = checkFocusElement->parentObject(); |
| 2164 } | 2202 } |
| 2165 } | 2203 } |
| 2166 | 2204 |
| 2167 return false; | 2205 return false; |
| 2168 } | 2206 } |
| 2169 | 2207 |
| (...skipping 25 matching lines...) Expand all Loading... |
| 2195 if (startOfConts) { | 2233 if (startOfConts) { |
| 2196 // Case 1: node is a block and is an inline's continuation. Parent | 2234 // Case 1: node is a block and is an inline's continuation. Parent |
| 2197 // is the start of the continuation chain. | 2235 // is the start of the continuation chain. |
| 2198 return startOfConts; | 2236 return startOfConts; |
| 2199 } | 2237 } |
| 2200 | 2238 |
| 2201 LayoutObject* parent = m_layoutObject->parent(); | 2239 LayoutObject* parent = m_layoutObject->parent(); |
| 2202 startOfConts = | 2240 startOfConts = |
| 2203 parent && parent->isLayoutInline() ? startOfContinuations(parent) : 0; | 2241 parent && parent->isLayoutInline() ? startOfContinuations(parent) : 0; |
| 2204 if (startOfConts) { | 2242 if (startOfConts) { |
| 2205 // Case 2: node's parent is an inline which is some node's continuation; par
ent is | 2243 // Case 2: node's parent is an inline which is some node's continuation; |
| 2206 // the earliest node in the continuation chain. | 2244 // parent is the earliest node in the continuation chain. |
| 2207 return startOfConts; | 2245 return startOfConts; |
| 2208 } | 2246 } |
| 2209 | 2247 |
| 2210 LayoutObject* firstChild = parent ? parent->slowFirstChild() : 0; | 2248 LayoutObject* firstChild = parent ? parent->slowFirstChild() : 0; |
| 2211 if (firstChild && firstChild->node()) { | 2249 if (firstChild && firstChild->node()) { |
| 2212 // Case 3: The first sibling is the beginning of a continuation chain. Find
the origin of that continuation. | 2250 // Case 3: The first sibling is the beginning of a continuation chain. Find |
| 2213 // Get the node's layoutObject and follow that continuation chain until the
first child is found. | 2251 // the origin of that continuation. Get the node's layoutObject and follow |
| 2252 // that continuation chain until the first child is found. |
| 2214 for (LayoutObject* nodeLayoutFirstChild = | 2253 for (LayoutObject* nodeLayoutFirstChild = |
| 2215 firstChild->node()->layoutObject(); | 2254 firstChild->node()->layoutObject(); |
| 2216 nodeLayoutFirstChild != firstChild; | 2255 nodeLayoutFirstChild != firstChild; |
| 2217 nodeLayoutFirstChild = firstChild->node()->layoutObject()) { | 2256 nodeLayoutFirstChild = firstChild->node()->layoutObject()) { |
| 2218 for (LayoutObject* contsTest = nodeLayoutFirstChild; contsTest; | 2257 for (LayoutObject* contsTest = nodeLayoutFirstChild; contsTest; |
| 2219 contsTest = nextContinuation(contsTest)) { | 2258 contsTest = nextContinuation(contsTest)) { |
| 2220 if (contsTest == firstChild) { | 2259 if (contsTest == firstChild) { |
| 2221 parent = nodeLayoutFirstChild->parent(); | 2260 parent = nodeLayoutFirstChild->parent(); |
| 2222 break; | 2261 break; |
| 2223 } | 2262 } |
| (...skipping 13 matching lines...) Expand all Loading... |
| 2237 bool AXLayoutObject::isSVGImage() const { | 2276 bool AXLayoutObject::isSVGImage() const { |
| 2238 return remoteSVGRootElement(); | 2277 return remoteSVGRootElement(); |
| 2239 } | 2278 } |
| 2240 | 2279 |
| 2241 void AXLayoutObject::detachRemoteSVGRoot() { | 2280 void AXLayoutObject::detachRemoteSVGRoot() { |
| 2242 if (AXSVGRoot* root = remoteSVGRootElement()) | 2281 if (AXSVGRoot* root = remoteSVGRootElement()) |
| 2243 root->setParent(0); | 2282 root->setParent(0); |
| 2244 } | 2283 } |
| 2245 | 2284 |
| 2246 AXSVGRoot* AXLayoutObject::remoteSVGRootElement() const { | 2285 AXSVGRoot* AXLayoutObject::remoteSVGRootElement() const { |
| 2247 // FIXME(dmazzoni): none of this code properly handled multiple references to
the same | 2286 // FIXME(dmazzoni): none of this code properly handled multiple references to |
| 2248 // remote SVG document. I'm disabling this support until it can be fixed prope
rly. | 2287 // the same remote SVG document. I'm disabling this support until it can be |
| 2288 // fixed properly. |
| 2249 return 0; | 2289 return 0; |
| 2250 } | 2290 } |
| 2251 | 2291 |
| 2252 AXObject* AXLayoutObject::remoteSVGElementHitTest(const IntPoint& point) const { | 2292 AXObject* AXLayoutObject::remoteSVGElementHitTest(const IntPoint& point) const { |
| 2253 AXObject* remote = remoteSVGRootElement(); | 2293 AXObject* remote = remoteSVGRootElement(); |
| 2254 if (!remote) | 2294 if (!remote) |
| 2255 return 0; | 2295 return 0; |
| 2256 | 2296 |
| 2257 IntSize offset = | 2297 IntSize offset = |
| 2258 point - roundedIntPoint(getBoundsInFrameCoordinates().location()); | 2298 point - roundedIntPoint(getBoundsInFrameCoordinates().location()); |
| 2259 return remote->accessibilityHitTest(IntPoint(offset)); | 2299 return remote->accessibilityHitTest(IntPoint(offset)); |
| 2260 } | 2300 } |
| 2261 | 2301 |
| 2262 // The boundingBox for elements within the remote SVG element needs to be offset
by its position | 2302 // The boundingBox for elements within the remote SVG element needs to be offset |
| 2263 // within the parent page, otherwise they are in relative coordinates only. | 2303 // by its position within the parent page, otherwise they are in relative |
| 2304 // coordinates only. |
| 2264 void AXLayoutObject::offsetBoundingBoxForRemoteSVGElement( | 2305 void AXLayoutObject::offsetBoundingBoxForRemoteSVGElement( |
| 2265 LayoutRect& rect) const { | 2306 LayoutRect& rect) const { |
| 2266 for (AXObject* parent = parentObject(); parent; | 2307 for (AXObject* parent = parentObject(); parent; |
| 2267 parent = parent->parentObject()) { | 2308 parent = parent->parentObject()) { |
| 2268 if (parent->isAXSVGRoot()) { | 2309 if (parent->isAXSVGRoot()) { |
| 2269 rect.moveBy( | 2310 rect.moveBy( |
| 2270 parent->parentObject()->getBoundsInFrameCoordinates().location()); | 2311 parent->parentObject()->getBoundsInFrameCoordinates().location()); |
| 2271 break; | 2312 break; |
| 2272 } | 2313 } |
| 2273 } | 2314 } |
| 2274 } | 2315 } |
| 2275 | 2316 |
| 2276 // Hidden children are those that are not laid out or visible, but are specifica
lly marked as aria-hidden=false, | 2317 // Hidden children are those that are not laid out or visible, but are |
| 2318 // specifically marked as aria-hidden=false, |
| 2277 // meaning that they should be exposed to the AX hierarchy. | 2319 // meaning that they should be exposed to the AX hierarchy. |
| 2278 void AXLayoutObject::addHiddenChildren() { | 2320 void AXLayoutObject::addHiddenChildren() { |
| 2279 Node* node = this->getNode(); | 2321 Node* node = this->getNode(); |
| 2280 if (!node) | 2322 if (!node) |
| 2281 return; | 2323 return; |
| 2282 | 2324 |
| 2283 // First do a quick run through to determine if we have any hidden nodes (most
often we will not). | 2325 // First do a quick run through to determine if we have any hidden nodes (most |
| 2284 // If we do have hidden nodes, we need to determine where to insert them so th
ey match DOM order as close as possible. | 2326 // often we will not). If we do have hidden nodes, we need to determine where |
| 2327 // to insert them so they match DOM order as close as possible. |
| 2285 bool shouldInsertHiddenNodes = false; | 2328 bool shouldInsertHiddenNodes = false; |
| 2286 for (Node& child : NodeTraversal::childrenOf(*node)) { | 2329 for (Node& child : NodeTraversal::childrenOf(*node)) { |
| 2287 if (!child.layoutObject() && isNodeAriaVisible(&child)) { | 2330 if (!child.layoutObject() && isNodeAriaVisible(&child)) { |
| 2288 shouldInsertHiddenNodes = true; | 2331 shouldInsertHiddenNodes = true; |
| 2289 break; | 2332 break; |
| 2290 } | 2333 } |
| 2291 } | 2334 } |
| 2292 | 2335 |
| 2293 if (!shouldInsertHiddenNodes) | 2336 if (!shouldInsertHiddenNodes) |
| 2294 return; | 2337 return; |
| 2295 | 2338 |
| 2296 // Iterate through all of the children, including those that may have already
been added, and | 2339 // Iterate through all of the children, including those that may have already |
| 2297 // try to insert hidden nodes in the correct place in the DOM order. | 2340 // been added, and try to insert hidden nodes in the correct place in the DOM |
| 2341 // order. |
| 2298 unsigned insertionIndex = 0; | 2342 unsigned insertionIndex = 0; |
| 2299 for (Node& child : NodeTraversal::childrenOf(*node)) { | 2343 for (Node& child : NodeTraversal::childrenOf(*node)) { |
| 2300 if (child.layoutObject()) { | 2344 if (child.layoutObject()) { |
| 2301 // Find out where the last layout sibling is located within m_children. | 2345 // Find out where the last layout sibling is located within m_children. |
| 2302 if (AXObject* childObject = axObjectCache().get(child.layoutObject())) { | 2346 if (AXObject* childObject = axObjectCache().get(child.layoutObject())) { |
| 2303 if (childObject->accessibilityIsIgnored()) { | 2347 if (childObject->accessibilityIsIgnored()) { |
| 2304 const auto& children = childObject->children(); | 2348 const auto& children = childObject->children(); |
| 2305 childObject = children.size() ? children.last().get() : 0; | 2349 childObject = children.size() ? children.last().get() : 0; |
| 2306 } | 2350 } |
| 2307 if (childObject) | 2351 if (childObject) |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2362 else | 2406 else |
| 2363 axObjectCache().remove(areaObject->axObjectID()); | 2407 axObjectCache().remove(areaObject->axObjectID()); |
| 2364 } | 2408 } |
| 2365 } | 2409 } |
| 2366 } | 2410 } |
| 2367 | 2411 |
| 2368 void AXLayoutObject::addCanvasChildren() { | 2412 void AXLayoutObject::addCanvasChildren() { |
| 2369 if (!isHTMLCanvasElement(getNode())) | 2413 if (!isHTMLCanvasElement(getNode())) |
| 2370 return; | 2414 return; |
| 2371 | 2415 |
| 2372 // If it's a canvas, it won't have laid out children, but it might have access
ible fallback content. | 2416 // If it's a canvas, it won't have laid out children, but it might have |
| 2373 // Clear m_haveChildren because AXNodeObject::addChildren will expect it to be
false. | 2417 // accessible fallback content. Clear m_haveChildren because |
| 2418 // AXNodeObject::addChildren will expect it to be false. |
| 2374 ASSERT(!m_children.size()); | 2419 ASSERT(!m_children.size()); |
| 2375 m_haveChildren = false; | 2420 m_haveChildren = false; |
| 2376 AXNodeObject::addChildren(); | 2421 AXNodeObject::addChildren(); |
| 2377 } | 2422 } |
| 2378 | 2423 |
| 2379 void AXLayoutObject::addPopupChildren() { | 2424 void AXLayoutObject::addPopupChildren() { |
| 2380 if (!isHTMLInputElement(getNode())) | 2425 if (!isHTMLInputElement(getNode())) |
| 2381 return; | 2426 return; |
| 2382 if (AXObject* axPopup = toHTMLInputElement(getNode())->popupRootAXObject()) | 2427 if (AXObject* axPopup = toHTMLInputElement(getNode())->popupRootAXObject()) |
| 2383 m_children.append(axPopup); | 2428 m_children.append(axPopup); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 2400 | 2445 |
| 2401 bool AXLayoutObject::elementAttributeValue( | 2446 bool AXLayoutObject::elementAttributeValue( |
| 2402 const QualifiedName& attributeName) const { | 2447 const QualifiedName& attributeName) const { |
| 2403 if (!m_layoutObject) | 2448 if (!m_layoutObject) |
| 2404 return false; | 2449 return false; |
| 2405 | 2450 |
| 2406 return equalIgnoringCase(getAttribute(attributeName), "true"); | 2451 return equalIgnoringCase(getAttribute(attributeName), "true"); |
| 2407 } | 2452 } |
| 2408 | 2453 |
| 2409 } // namespace blink | 2454 } // namespace blink |
| OLD | NEW |