Commit 27bc6bee authored by Morgan Reschenberg's avatar Morgan Reschenberg
Browse files

Bug 1649720: Ensure XUL trees expose their internal columns to VoiceOver r=eeejay

parent 8195c357
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -125,6 +125,9 @@
// override
- (NSArray*)moxSelectedRows;

// override
- (NSString*)moxOrientation;

@end

@interface mozOutlineRowAccessible : mozTableRowAccessible
@@ -135,6 +138,9 @@
// override
- (NSNumber*)moxDisclosing;

// override
- (NSNumber*)moxExpanded;

// override
- (id)moxDisclosedByRow;

+32 −3
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@
#include "Accessible.h"
#include "TableAccessible.h"
#include "TableCellAccessible.h"
#include "XULTreeAccessible.h"
#include "Pivot.h"
#include "Relation.h"

@@ -409,7 +410,26 @@ using namespace mozilla::a11y;
}

- (NSArray*)moxColumns {
  // Webkit says we shouldn't do anything here
  if (Accessible* acc = mGeckoAccessible.AsAccessible()) {
    if (acc->IsContent() && acc->GetContent()->IsXULElement(nsGkAtoms::tree)) {
      XULTreeAccessible* treeAcc = (XULTreeAccessible*)acc;
      NSMutableArray* cols = [[NSMutableArray alloc] init];
      // XUL trees store their columns in a group at the tree's first
      // child. Here, we iterate over that group to get each column's
      // native accessible and add it to our col array.
      Accessible* treeColumns = treeAcc->GetChildAt(0);
      if (treeColumns) {
        uint32_t colCount = treeColumns->ChildCount();
        for (uint32_t i = 0; i < colCount; i++) {
          Accessible* treeColumnItem = treeColumns->GetChildAt(i);
          [cols addObject:GetNativeFromGeckoAccessible(treeColumnItem)];
        }
        return cols;
      }
    }
  }
  // Webkit says we shouldn't expose any cols for aria-tree
  // so we return an empty array here
  return @[];
}

@@ -425,6 +445,10 @@ using namespace mozilla::a11y;
  return selectedRows;
}

- (NSString*)moxOrientation {
  return NSAccessibilityVerticalOrientationValue;
}

@end

@implementation mozOutlineRowAccessible
@@ -437,6 +461,10 @@ using namespace mozilla::a11y;
  return @([self stateWithMask:states::EXPANDED] != 0);
}

- (NSNumber*)moxExpanded {
  return @([self stateWithMask:states::EXPANDED] != 0);
}

- (id)moxDisclosedByRow {
  // According to webkit: this attr corresponds to the row
  // that contains this row. It should be the same as the
@@ -492,8 +520,9 @@ using namespace mozilla::a11y;
  } else if (ProxyAccessible* proxy = mGeckoAccessible.AsProxy()) {
    groupPos = proxy->GroupPosition();
  }

  return @(groupPos.level);
  // mac expects 0-indexed levels, but groupPos.level is 1-indexed
  // so we subtract 1 here for levels above 0
  return groupPos.level > 0 ? @(groupPos.level - 1) : @(groupPos.level);
}

- (NSArray*)moxDisclosedRows {
+1 −0
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ skip-if = os == 'mac' && debug # Bug 1664577
[browser_text_selection.js]
[browser_navigate.js]
[browser_outline.js]
[browser_outline_xul.js]
[browser_hierarchy.js]
[browser_menulist.js]
[browser_rich_listbox.js]
+20 −20
Original line number Diff line number Diff line
@@ -80,8 +80,8 @@ addAccessibleTask(
    );
    is(
      outRows[0].getAttributeValue("AXDisclosureLevel"),
      1,
      "Row is level one"
      0,
      "Row is level zero"
    );

    is(outRows[1].getAttributeValue("AXDisclosing"), 1, "Row is disclosing");
@@ -97,8 +97,8 @@ addAccessibleTask(
    );
    is(
      outRows[1].getAttributeValue("AXDisclosureLevel"),
      1,
      "Row is level one"
      0,
      "Row is level zero"
    );

    is(
@@ -118,8 +118,8 @@ addAccessibleTask(
    );
    is(
      outRows[2].getAttributeValue("AXDisclosureLevel"),
      1,
      "Row is level one"
      0,
      "Row is level zero"
    );

    is(outRows[3].getAttributeValue("AXDisclosing"), 1, "Row is disclosing");
@@ -137,8 +137,8 @@ addAccessibleTask(
    );
    is(
      outRows[3].getAttributeValue("AXDisclosureLevel"),
      2,
      "Row is level two"
      1,
      "Row is level one"
    );
  }
);
@@ -260,8 +260,8 @@ addAccessibleTask(
    );
    is(
      outRows[0].getAttributeValue("AXDisclosureLevel"),
      1,
      "Row is level one"
      0,
      "Row is level zero"
    );

    is(outRows[2].getAttributeValue("AXDisclosing"), 1, "Row is disclosing");
@@ -277,8 +277,8 @@ addAccessibleTask(
    );
    is(
      outRows[2].getAttributeValue("AXDisclosureLevel"),
      2,
      "Row is level two"
      1,
      "Row is level one"
    );

    is(
@@ -301,8 +301,8 @@ addAccessibleTask(
    );
    is(
      outRows[3].getAttributeValue("AXDisclosureLevel"),
      3,
      "Row is level three"
      2,
      "Row is level two"
    );

    is(
@@ -322,8 +322,8 @@ addAccessibleTask(
    );
    is(
      outRows[5].getAttributeValue("AXDisclosureLevel"),
      1,
      "Row is level one"
      0,
      "Row is level zero"
    );

    is(outRows[6].getAttributeValue("AXDisclosing"), 1, "Row is disclosing");
@@ -341,8 +341,8 @@ addAccessibleTask(
    );
    is(
      outRows[6].getAttributeValue("AXDisclosureLevel"),
      2,
      "Row is level two"
      1,
      "Row is level one"
    );

    is(
@@ -364,8 +364,8 @@ addAccessibleTask(
    );
    is(
      outRows[7].getAttributeValue("AXDisclosureLevel"),
      3,
      "Row is level three"
      2,
      "Row is level two"
    );
  }
);
+274 −0
Original line number Diff line number Diff line
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/* import-globals-from ../../mochitest/attributes.js */
loadScripts({ name: "attributes.js", dir: MOCHITESTS_DIR });

addAccessibleTask(
  "mac/doc_tree.xhtml",
  async (browser, accDoc) => {
    const tree = getNativeInterface(accDoc, "tree");
    is(
      tree.getAttributeValue("AXRole"),
      "AXOutline",
      "Found tree with role outline"
    );
    // XUL trees store all rows as direct children of the outline,
    // so we should see nine here instead of just three:
    // (Groceries, Fruits, Veggies)
    const treeChildren = tree.getAttributeValue("AXChildren");
    is(treeChildren.length, 9, "Found nine direct children");

    const treeCols = tree.getAttributeValue("AXColumns");
    is(treeCols.length, 1, "Found one column in tree");

    // Here, we should get only outline rows, not the title
    const treeRows = tree.getAttributeValue("AXRows");
    is(treeRows.length, 8, "Found 8 total rows");

    is(
      treeRows[0].getAttributeValue("AXDescription"),
      "Fruits",
      "Located correct first row, row has correct desc"
    );
    is(
      treeRows[0].getAttributeValue("AXDisclosing"),
      1,
      "Fruits is disclosing"
    );
    is(
      treeRows[0].getAttributeValue("AXDisclosedByRow"),
      null,
      "Fruits is disclosed by outline"
    );
    is(
      treeRows[0].getAttributeValue("AXDisclosureLevel"),
      0,
      "Fruits is level zero"
    );
    let disclosedRows = treeRows[0].getAttributeValue("AXDisclosedRows");
    is(disclosedRows.length, 2, "Fruits discloses two rows");
    is(
      disclosedRows[0].getAttributeValue("AXDescription"),
      "Apple",
      "fruits discloses apple"
    );
    is(
      disclosedRows[1].getAttributeValue("AXDescription"),
      "Orange",
      "fruits discloses orange"
    );

    is(
      treeRows[1].getAttributeValue("AXDescription"),
      "Apple",
      "Located correct second row, row has correct desc"
    );
    is(
      treeRows[1].getAttributeValue("AXDisclosing"),
      0,
      "Apple is not disclosing"
    );
    is(
      treeRows[1]
        .getAttributeValue("AXDisclosedByRow")
        .getAttributeValue("AXDescription"),
      "Fruits",
      "Apple is disclosed by fruits"
    );
    is(
      treeRows[1].getAttributeValue("AXDisclosureLevel"),
      1,
      "Apple is level one"
    );
    is(
      treeRows[1].getAttributeValue("AXDisclosedRows").length,
      0,
      "Apple does not disclose rows"
    );

    is(
      treeRows[2].getAttributeValue("AXDescription"),
      "Orange",
      "Located correct third row, row has correct desc"
    );
    is(
      treeRows[2].getAttributeValue("AXDisclosing"),
      0,
      "Orange is not disclosing"
    );
    is(
      treeRows[2]
        .getAttributeValue("AXDisclosedByRow")
        .getAttributeValue("AXDescription"),
      "Fruits",
      "Orange is disclosed by fruits"
    );
    is(
      treeRows[2].getAttributeValue("AXDisclosureLevel"),
      1,
      "Orange is level one"
    );
    is(
      treeRows[2].getAttributeValue("AXDisclosedRows").length,
      0,
      "Orange does not disclose rows"
    );

    is(
      treeRows[3].getAttributeValue("AXDescription"),
      "Veggies",
      "Located correct fourth row, row has correct desc"
    );
    is(
      treeRows[3].getAttributeValue("AXDisclosing"),
      1,
      "Veggies is disclosing"
    );
    is(
      treeRows[3].getAttributeValue("AXDisclosedByRow"),
      null,
      "Veggies is disclosed by outline"
    );
    is(
      treeRows[3].getAttributeValue("AXDisclosureLevel"),
      0,
      "Veggies is level zero"
    );
    disclosedRows = treeRows[3].getAttributeValue("AXDisclosedRows");
    is(disclosedRows.length, 2, "Veggies discloses two rows");
    is(
      disclosedRows[0].getAttributeValue("AXDescription"),
      "Green Veggies",
      "Veggies discloses green veggies"
    );
    is(
      disclosedRows[1].getAttributeValue("AXDescription"),
      "Squash",
      "Veggies discloses squash"
    );

    is(
      treeRows[4].getAttributeValue("AXDescription"),
      "Green Veggies",
      "Located correct fifth row, row has correct desc"
    );
    is(
      treeRows[4].getAttributeValue("AXDisclosing"),
      1,
      "Green veggies is disclosing"
    );
    is(
      treeRows[4]
        .getAttributeValue("AXDisclosedByRow")
        .getAttributeValue("AXDescription"),
      "Veggies",
      "Green Veggies is disclosed by veggies"
    );
    is(
      treeRows[4].getAttributeValue("AXDisclosureLevel"),
      1,
      "Green veggies is level one"
    );
    disclosedRows = treeRows[4].getAttributeValue("AXDisclosedRows");
    is(disclosedRows.length, 2, "Green veggies has two rows");
    is(
      disclosedRows[0].getAttributeValue("AXDescription"),
      "Spinach",
      "Green veggies discloses spinach"
    );
    is(
      disclosedRows[1].getAttributeValue("AXDescription"),
      "Peas",
      "Green veggies discloses peas"
    );

    is(
      treeRows[5].getAttributeValue("AXDescription"),
      "Spinach",
      "Located correct sixth row, row has correct desc"
    );
    is(
      treeRows[5].getAttributeValue("AXDisclosing"),
      0,
      "Spinach is not disclosing"
    );
    is(
      treeRows[5]
        .getAttributeValue("AXDisclosedByRow")
        .getAttributeValue("AXDescription"),
      "Green Veggies",
      "Spinach is disclosed by green veggies"
    );
    is(
      treeRows[5].getAttributeValue("AXDisclosureLevel"),
      2,
      "Spinach is level two"
    );
    is(
      treeRows[5].getAttributeValue("AXDisclosedRows").length,
      0,
      "Spinach does not disclose rows"
    );

    is(
      treeRows[6].getAttributeValue("AXDescription"),
      "Peas",
      "Located correct seventh row, row has correct desc"
    );
    is(
      treeRows[6].getAttributeValue("AXDisclosing"),
      0,
      "Peas is not disclosing"
    );
    is(
      treeRows[6]
        .getAttributeValue("AXDisclosedByRow")
        .getAttributeValue("AXDescription"),
      "Green Veggies",
      "Peas is disclosed by green veggies"
    );
    is(
      treeRows[6].getAttributeValue("AXDisclosureLevel"),
      2,
      "Peas is level two"
    );
    is(
      treeRows[6].getAttributeValue("AXDisclosedRows").length,
      0,
      "Peas does not disclose rows"
    );

    is(
      treeRows[7].getAttributeValue("AXDescription"),
      "Squash",
      "Located correct eighth row, row has correct desc"
    );
    is(
      treeRows[7].getAttributeValue("AXDisclosing"),
      0,
      "Squash is not disclosing"
    );
    is(
      treeRows[7]
        .getAttributeValue("AXDisclosedByRow")
        .getAttributeValue("AXDescription"),
      "Veggies",
      "Squash is disclosed by veggies"
    );
    is(
      treeRows[7].getAttributeValue("AXDisclosureLevel"),
      1,
      "Squash is level one"
    );
    is(
      treeRows[7].getAttributeValue("AXDisclosedRows").length,
      0,
      "Squash does not disclose rows"
    );
  },
  { topLevel: false, chrome: true }
);
Loading