⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 278683 in webkit


Ignore:
Timestamp:
Jun 9, 2021, 5:11:41 PM (5 years ago)
Author:
Andres Gonzalez
Message:

iOS - VoiceOver reads the old heading text when updated with heading.firstChild.data.
https://bugs.webkit.org/show_bug.cgi?id=226754
Source/WebCore:

rdar://44949563

Reviewed by Chris Fleizach.

Tests: accessibility/ios-simulator/heading-text-updates.html

accessibility/mac/heading-text-updates.html

The problem was caused by [WebAccessibilityObjectWrapper _accessibilityTraitsFromAncestors]
setting the value and label of static text inside headings. since this
method is called only on the initialization of the object, the label is
never updated when the text changes.
The solution is to move the logic to return the label and value of
static text inside headings to the accessibilityLabel and accessibilityValue
respectively.

  • accessibility/ios/WebAccessibilityObjectWrapperIOS.mm:

(-[WebAccessibilityObjectWrapper _accessibilityTraitsFromAncestors]):
(-[WebAccessibilityObjectWrapper accessibilityLabel]):
(-[WebAccessibilityObjectWrapper accessibilityValue]):

LayoutTests:

Reviewed by Chris Fleizach.

  • accessibility/ios-simulator/heading-text-updates-expected.txt: Added.
  • accessibility/ios-simulator/heading-text-updates.html: Added.
  • accessibility/mac/heading-text-updates-expected.txt: Added.
  • accessibility/mac/heading-text-updates.html: Added.
Location:
trunk
Files:
4 added
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r278678 r278683  
     12021-06-09  Andres Gonzalez  <andresg_22@apple.com>
     2
     3        iOS - VoiceOver reads the old heading text when updated with heading.firstChild.data.
     4        https://bugs.webkit.org/show_bug.cgi?id=226754
     5
     6        Reviewed by Chris Fleizach.
     7
     8        * accessibility/ios-simulator/heading-text-updates-expected.txt: Added.
     9        * accessibility/ios-simulator/heading-text-updates.html: Added.
     10        * accessibility/mac/heading-text-updates-expected.txt: Added.
     11        * accessibility/mac/heading-text-updates.html: Added.
     12
    1132021-06-09  Devin Rousso  <drousso@apple.com>
    214
  • trunk/Source/WebCore/ChangeLog

    r278681 r278683  
     12021-06-09  Andres Gonzalez  <andresg_22@apple.com>
     2
     3        iOS - VoiceOver reads the old heading text when updated with heading.firstChild.data.
     4        https://bugs.webkit.org/show_bug.cgi?id=226754
     5        rdar://44949563
     6
     7        Reviewed by Chris Fleizach.
     8
     9        Tests: accessibility/ios-simulator/heading-text-updates.html
     10               accessibility/mac/heading-text-updates.html
     11
     12        The problem was caused by [WebAccessibilityObjectWrapper _accessibilityTraitsFromAncestors]
     13        setting the value and label of static text inside headings. since this
     14        method is called only on the initialization of the object, the label is
     15        never updated when the text changes.
     16        The solution is to move the logic to return the label and value of
     17        static text inside headings to the accessibilityLabel and accessibilityValue
     18        respectively.
     19
     20        * accessibility/ios/WebAccessibilityObjectWrapperIOS.mm:
     21        (-[WebAccessibilityObjectWrapper _accessibilityTraitsFromAncestors]):
     22        (-[WebAccessibilityObjectWrapper accessibilityLabel]):
     23        (-[WebAccessibilityObjectWrapper accessibilityValue]):
     24
    1252021-06-09  Eric Carlson  <eric.carlson@apple.com>
    226
  • trunk/Source/WebCore/accessibility/ios/WebAccessibilityObjectWrapperIOS.mm

    r278253 r278683  
    662662{
    663663    uint64_t traits = 0;
    664     AccessibilityRole role = self.axBackingObject->roleValue();
    665    
     664    auto* backingObject = self.axBackingObject;
     665
    666666    // Trait information also needs to be gathered from the parents above the object.
    667     // The parentObject is needed instead of the unignoredParentObject, because a table might be ignored, but information still needs to be gathered from it.   
    668     for (auto* parent = self.axBackingObject->parentObject(); parent != nil; parent = parent->parentObject()) {
     667    // The parentObject is needed instead of the unignoredParentObject, because a table might be ignored, but information still needs to be gathered from it.
     668    for (auto* parent = backingObject->parentObject(); parent; parent = parent->parentObject()) {
    669669        AccessibilityRole parentRole = parent->roleValue();
    670670        if (parentRole == AccessibilityRole::WebArea)
    671671            break;
    672        
     672
    673673        switch (parentRole) {
    674674        case AccessibilityRole::Link:
     
    678678                traits |= [self _axVisitedTrait];
    679679            break;
    680         case AccessibilityRole::Heading: {
     680        case AccessibilityRole::Heading:
    681681            traits |= [self _axHeaderTrait];
    682             // If this object has the header trait, we should set the value
    683             // to the heading level. If it was a static text element, we need to store
    684             // the value as the label, because the heading level needs to the value.
    685             AccessibilityObjectWrapper* wrapper = parent->wrapper();
    686             if (role == AccessibilityRole::StaticText) {
    687                 // We should only set the text value as the label when there's no
    688                 // alternate text on the heading parent.
    689                 NSString *headingLabel = [wrapper baseAccessibilityDescription];
    690                 if (![headingLabel length])
    691                     [self setAccessibilityLabel:self.axBackingObject->stringValue()];
    692                 else
    693                     [self setAccessibilityLabel:headingLabel];
    694             }
    695             [self setAccessibilityValue:[wrapper accessibilityValue]];
    696682            break;
    697         }
    698683        default:
    699684            if ([self _accessibilityIsLandmarkRole:parentRole])
     
    701686            break;
    702687        }
    703        
     688
    704689        // If this object has fieldset parent, we should add containedByFieldsetTrait to it.
    705690        if (parent->isFieldset())
    706691            traits |= [self _axContainedByFieldsetTrait];
    707692    }
    708    
     693
    709694    return traits;
    710695}
     
    11901175        return label;
    11911176
     1177    auto* backingObject = self.axBackingObject;
     1178
    11921179    // iOS doesn't distinguish between a title and description field,
    11931180    // so concatentation will yield the best result.
    1194     NSString *axTitle = self.axBackingObject->titleAttributeValue();
    1195     NSString *axDescription = [self baseAccessibilityDescription];
     1181    NSString *axTitle = backingObject->titleAttributeValue();
     1182    NSString *axDescription = backingObject->descriptionAttributeValue();
    11961183    NSString *landmarkDescription = [self ariaLandmarkRoleDescription];
    11971184    NSString *interactiveVideoDescription = [self interactiveVideoDescription];
    1198    
     1185
     1186    // If self is static text inside a heading, the label should be the string
     1187    // value of the static text object, except when the heading has alternative
     1188    // text, in which case, that alternative text is returned here.
     1189    // The reason is that the string value for static text inside a heading is
     1190    // used to convey the heading level instead.
     1191    if (backingObject->roleValue() == AccessibilityRole::StaticText
     1192        && self.accessibilityTraits & self._axHeaderTrait) {
     1193        auto* heading = Accessibility::findAncestor(*backingObject, false, [] (const auto& ancestor) {
     1194            return ancestor.roleValue() == AccessibilityRole::Heading;
     1195        });
     1196
     1197        if (heading) {
     1198            auto headingLabel = heading->descriptionAttributeValue();
     1199            if (!headingLabel.isEmpty())
     1200                return headingLabel;
     1201            return backingObject->stringValue();
     1202        }
     1203    }
     1204
    11991205    // We should expose the value of the input type date or time through AXValue instead of AXTitle.
    1200     if (self.axBackingObject->isInputTypePopupButton() && [axTitle isEqualToString:[self accessibilityValue]])
     1206    if (backingObject->isInputTypePopupButton() && [axTitle isEqualToString:[self accessibilityValue]])
    12011207        axTitle = nil;
    12021208
    12031209    // Footer is not considered a landmark, but we want the role description.
    1204     if (self.axBackingObject->roleValue() == AccessibilityRole::Footer)
     1210    if (backingObject->roleValue() == AccessibilityRole::Footer)
    12051211        landmarkDescription = AXFooterRoleDescriptionText();
    12061212
    12071213    NSMutableString *result = [NSMutableString string];
    1208     if (self.axBackingObject->roleValue() == AccessibilityRole::HorizontalRule)
     1214    if (backingObject->roleValue() == AccessibilityRole::HorizontalRule)
    12091215        appendStringToResult(result, AXHorizontalRuleDescriptionText());
    12101216
     
    12121218    appendStringToResult(result, axDescription);
    12131219    if ([self stringValueShouldBeUsedInLabel]) {
    1214         NSString *valueLabel = self.axBackingObject->stringValue();
     1220        NSString *valueLabel = backingObject->stringValue();
    12151221        valueLabel = [valueLabel stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
    12161222        appendStringToResult(result, valueLabel);
     
    12181224    appendStringToResult(result, landmarkDescription);
    12191225    appendStringToResult(result, interactiveVideoDescription);
    1220    
     1226
    12211227    return [result length] ? result : nil;
    12221228}
     
    14651471    if (![self _prepareAccessibilityCall])
    14661472        return nil;
    1467    
     1473
    14681474    // check if the value was overridden
    14691475    NSString *value = [super accessibilityValue];
    14701476    if (value)
    14711477        return value;
    1472    
    1473     if (self.axBackingObject->supportsCheckedState()) {
    1474         switch (self.axBackingObject->checkboxOrRadioValue()) {
     1478
     1479    auto* backingObject = self.axBackingObject;
     1480    if (backingObject->supportsCheckedState()) {
     1481        switch (backingObject->checkboxOrRadioValue()) {
    14751482        case AccessibilityButtonState::Off:
    14761483            return [NSString stringWithFormat:@"%d", 0];
     
    14831490        return [NSString stringWithFormat:@"%d", 0];
    14841491    }
    1485    
    1486     if (self.axBackingObject->isButton() && self.axBackingObject->isPressed())
     1492
     1493    if (backingObject->isButton() && backingObject->isPressed())
    14871494        return [NSString stringWithFormat:@"%d", 1];
    14881495
     1496    // If self has the header trait, value should be the heading level.
     1497    if (self.accessibilityTraits & self._axHeaderTrait) {
     1498        auto* heading = Accessibility::findAncestor(*backingObject, true, [] (const auto& ancestor) {
     1499            return ancestor.roleValue() == AccessibilityRole::Heading;
     1500        });
     1501        ASSERT(heading);
     1502
     1503        if (heading)
     1504            return [NSString stringWithFormat:@"%d", heading->headingLevel()];
     1505    }
     1506
    14891507    // rdar://8131388 WebKit should expose the same info as UIKit for its password fields.
    1490     if (self.axBackingObject->isPasswordField() && ![self _accessibilityIsStrongPasswordField]) {
    1491         int passwordLength = self.axBackingObject->accessibilityPasswordFieldLength();
     1508    if (backingObject->isPasswordField() && ![self _accessibilityIsStrongPasswordField]) {
     1509        int passwordLength = backingObject->accessibilityPasswordFieldLength();
    14921510        NSMutableString* string = [NSMutableString string];
    14931511        for (int k = 0; k < passwordLength; ++k)
     
    14951513        return string;
    14961514    }
    1497    
     1515
    14981516    // A text control should return its text data as the axValue (per iPhone AX API).
    14991517    if (![self stringValueShouldBeUsedInLabel])
    1500         return self.axBackingObject->stringValue();
    1501    
    1502     if (self.axBackingObject->isRangeControl()) {
     1518        return backingObject->stringValue();
     1519
     1520    if (backingObject->isRangeControl()) {
    15031521        // Prefer a valueDescription if provided by the author (through aria-valuetext).
    1504         String valueDescription = self.axBackingObject->valueDescription();
     1522        String valueDescription = backingObject->valueDescription();
    15051523        if (!valueDescription.isEmpty())
    15061524            return valueDescription;
    15071525
    1508         return [NSString stringWithFormat:@"%.2f", self.axBackingObject->valueForRange()];
    1509     }
    1510 
    1511     if (is<AccessibilityAttachment>(self.axBackingObject) && downcast<AccessibilityAttachment>(self.axBackingObject)->hasProgress())
    1512         return [NSString stringWithFormat:@"%.2f", self.axBackingObject->valueForRange()];
    1513    
    1514     if (self.axBackingObject->isHeading())
    1515         return [NSString stringWithFormat:@"%d", self.axBackingObject->headingLevel()];
    1516    
     1526        return [NSString stringWithFormat:@"%.2f", backingObject->valueForRange()];
     1527    }
     1528
     1529    if (is<AccessibilityAttachment>(backingObject) && downcast<AccessibilityAttachment>(backingObject)->hasProgress())
     1530        return [NSString stringWithFormat:@"%.2f", backingObject->valueForRange()];
     1531
    15171532    return nil;
    15181533}
Note: See TracChangeset for help on using the changeset viewer.