Friday, December 7, 2012

IServiceProvider implementation in Firefox

In Firefox every MSAA accessible object implements IServiceProvider interface which is used to obtain different accessible objects that are in connection to the given one. The idea of IServiceProvider is quite close to IAccessible2/ATK relation concept but it operates on different set of relation types. It has IServiceProvider::QueryService method which is defined as:

  HRESULT QueryService(
      REFGUID guidService,
      REFIID riid,
      void **ppv
  );

guidService identifies the accessible object you need, riid is an interface the object should be queried to.

In Firefox we support the following guid services:

IID_IAccessibleApplication  to get an IAccessible2 application accessible implementing IAccessibleApplication interface.

SID_IAccessibleContentDocument = { 0xa5d8e1f3,0x3571,0x4d8f,{0x95,0x21,0x07,0xed,0x28,0xfb,0x07,0x2e} } a Firefox specific service used to get a tab document the accessible object belongs to.

IID_IAccessibleEx used to obtain UIA IRawElementProviderSimple instance. It works under "accessibility.uia.enable" preference.

Also we support IID_ISimpleDOMNode, IID_IAccessible and IID_IAccessible2 as guid services but they are basically query interfaces and they return the same object as query interface does.

Note, all said above works in Firefox 16 and later. Prior to Firefox 16 we used to have a different logic that allowed tricks like

  accessible->QueryService(IID_IAccessible2,
                           IID_IApplicationAccessible,
                           (void**)&appAcc);

to get an application accessible. It's not possible anymore. Please double check your code if you rely on IServiceProvider::QueryService.

Monday, December 3, 2012

ISimpleDOM support

As you probably know Firefox implements ISimpleDOM interfaces to provide a MS COM access to DOM in the browser. IE maintains similar interfaces. In accessibility world they were used to workaround lacks of MSAA API. Early days screen readers didn't have a choice how to make the browser accessible and they were DOM based.

Years later after IAccessible2 and UIA appeared the ISimpleDOM interfaces got obsolete. A bright demo of this statement is the NVDA screen reader which doesn't rely on ISimpleDOM at all and works nicely with Firefox. Nonetheless periodically I hear that ISimpleDOM is still very useful for AT. As a rule this opinion comes from proprietary screen reader vendors so I don't really aware of details. We trust them and we continue to support ISimpleDOM. However we don't recommend anyone to use ISimpleDOM.

We consider ISimpleDOM as optional API and thus we think that our support of it shouldn't affect on AT software that don't rely on ISimpleDOM. As a first part of this idea the ISimpleDOMNode interface was implemented as a tear off. That means whenever you query ISimpleDOMNode interface you always get a new instance implementing this interface. That allows us to save 4 bytes per accessible object and that was good for memory usage. The change was landed on Firefox 20.

We didn't find any problems during testing stage but if you would like to give it a spin, please try a nightly build. Especially it makes sense if you are developer of AT software relying on ISimpleDOM. Please let us know if you have concerns.

Sunday, December 2, 2012

Accessible Mozilla: Tech overview of Firefox 19

ARIA


ARIA spec enriched by test suite so lately we've got reported a lot about ARIA problems in Firefox. On that wave we improved a little bit our ARIA support. You can check out this wiki to see how we do on ARIA test suite failures.

* ARIA role="rowgroup" is a strong role now, in other words it overrides native role, and it is mapped as grouping role into accessibility APIs (ATK_ROLE_PANEL on ATK, NSAccessibilityGroupRole on OS X, ROLE_SYSTEM_GROUPING on MSAA/IA2). See bug for details.

* When ARIA role="tab" gets selected within containing role="tablist" then selection event (EVENT_SELECTION on MSAA / "selection_changed" on ATK) is fired on the tablist, see bug for more info.

* Inherited role="presentation" is now ignored if the element has global ARIA attribute or relation. For example:

  <table role="presentation">
    <tr>
      <td aria-hidden="true" id="cell">cell1</td>
      <td aria-labelledby="cell1">cell2</td>
      <td>cell3</td>
    </tr>
  </table> 

HTML td elements "cell1" and "cell2" have both a generic accessible, "cell3" is not accessible (its text leaf it is of course). See bug for more info.

* ARIA menu item containing a sub menu (i.e. having aria-haspopup attribute) is exposed as ATK_ROLE_MENU on Linux, see bug for more info.

* Previously we rejected to use values of ARIA slider, spinbutton and scrollbar in name computation. For example:

  <input id="input">
  <label for="input">
    foo <span role="slider" aria-valuetext="middle"> foo</span>
  </label>

Expected name for "input" accessible is "foo middle foo". Refer to bug for more info.

Attributes


* A document accessible picks up object attributes from container (like iframe element) provided by ARIA markup only. Previously we used to propagate object attributes like "class", "id" or "xml-roles" to the document. That didn't make huge sense but it's behavioral change and you might want to be aware of it. See bug for more info.

* New "explicit-name" object attribute was introduced as a part of ongoing IAccessible2 1.3 spec. This attribute is exposed with "true" value when the author specified accessible name explicitly (for example, by HTML label element). Otherwise this attribute is omitted (for example, when name is computed from subtree like in case of <button>press me</button> or there's no accessible name at all like <p>it's a paragraph</p>). See bug for more info.

Roles


A document accessible doesn't inherit ARIA role from container anymore. This behavior was introduced a long time ago to let the author to change a role of 3d party ARIA widget. This approach added certain problems for web developers:
  • If the author applies a navigation landmark on the iframe then Firefox copies it over the role of the child document.
  • If the author has actually set a role on the child document contained within the iframe and the author had applied a role to it (such as role="application") it will be overridden.
So behavior opposite to what we do is wanted actually. Also we didn't have a good idea whether our behavior is used anywhere on the web, thus we decided to change. Refer to bug for more info.

States


If XUL deck panel is not selected then all its children expose invisible state (instead offscreen state as we used to do). The problem has been seen in Firefox "About dialog" where hidden elements used for different update statuses of the browser had offscreen state and that made them discoverable for screen reader users. This was regression from Firefox 18 (note, the fix was backported to Firefox 18). See bug for details.

Events


* HTML5 progress element is a subject of value change events now, similar to ARIA progressbar role (thanks to James Kitchener for fixing this one). See bug for more info.

* When the user clicks a link then state_change event for traversed state (ATK_STATE_VISITED on ATK,  STATE_SYSTEM_TRAVERSED on MSAA) is fired on the link accessible. See bug for more info.

* When the user clicks a link to download a file then we used to fire state_change event for busy:true state (ATK_STATE_BUSY on ATK, STATE_SYSTEM_BUSY on MSAA) on document accessible but we never fired concomitant state_change event for busy:false state. The issue was fixed. Refer to bug for details.

Zoom level


Finally all zoom level work was finished in Firefox 19. Before that we didn't respected a zoom level in accessibility APIs implementation, for example, methods operating on coordinates and size didn't take into account whether the web page was zoomed or not. That made us, for example, to return a wrong accessible in hit testing. Primarily it was a problem for screen magnifiers and it was pulled from Firefox 4 times. Refer to bug for more info.

Random notes


We dropped obsolete xlink support on HTML elements. Previously we used to expose them as accessible actions. Generic Xlink support has gone in Firefox for years ago so we just dropped a vain baggage (see bug for more info).