accessible/src/windows/ia2/ia2Accessible.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim: set ts=2 et sw=2 tw=80: */
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include "AccessibleWrap.h"
     9 #include "Accessible2_i.c"
    10 #include "Accessible2_2_i.c"
    11 #include "AccessibleRole.h"
    12 #include "AccessibleStates.h"
    14 #include "Compatibility.h"
    15 #include "ia2AccessibleRelation.h"
    16 #include "IUnknownImpl.h"
    17 #include "nsCoreUtils.h"
    18 #include "nsIAccessibleTypes.h"
    19 #include "Relation.h"
    21 #include "nsIPersistentProperties2.h"
    22 #include "nsISimpleEnumerator.h"
    24 using namespace mozilla;
    25 using namespace mozilla::a11y;
    27 ////////////////////////////////////////////////////////////////////////////////
    28 // ia2Accessible
    29 ////////////////////////////////////////////////////////////////////////////////
    31 STDMETHODIMP
    32 ia2Accessible::QueryInterface(REFIID iid, void** ppv)
    33 {
    34   if (!ppv)
    35     return E_INVALIDARG;
    37   *ppv = nullptr;
    39   if (IID_IAccessible2_2 == iid)
    40     *ppv = static_cast<IAccessible2_2*>(this);
    41   else if (IID_IAccessible2 == iid && !Compatibility::IsIA2Off())
    42     *ppv = static_cast<IAccessible2*>(this);
    44   if (*ppv) {
    45     (reinterpret_cast<IUnknown*>(*ppv))->AddRef();
    46     return S_OK;
    47   }
    49   return E_NOINTERFACE;
    50 }
    52 ////////////////////////////////////////////////////////////////////////////////
    53 // IAccessible2
    55 STDMETHODIMP
    56 ia2Accessible::get_nRelations(long* aNRelations)
    57 {
    58   A11Y_TRYBLOCK_BEGIN
    60   if (!aNRelations)
    61     return E_INVALIDARG;
    62   *aNRelations = 0;
    64   AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
    65   if (acc->IsDefunct())
    66     return CO_E_OBJNOTCONNECTED;
    68   for (uint32_t idx = 0; idx < ArrayLength(sRelationTypePairs); idx++) {
    69     if (sRelationTypePairs[idx].second == IA2_RELATION_NULL)
    70       continue;
    72     Relation rel = acc->RelationByType(sRelationTypePairs[idx].first);
    73     if (rel.Next())
    74       (*aNRelations)++;
    75   }
    76   return S_OK;
    78   A11Y_TRYBLOCK_END
    79 }
    81 STDMETHODIMP
    82 ia2Accessible::get_relation(long aRelationIndex,
    83                             IAccessibleRelation** aRelation)
    84 {
    85   A11Y_TRYBLOCK_BEGIN
    87   if (!aRelation)
    88     return E_INVALIDARG;
    89   *aRelation = nullptr;
    91   AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
    92   if (acc->IsDefunct())
    93     return CO_E_OBJNOTCONNECTED;
    95   long relIdx = 0;
    96   for (uint32_t idx = 0; idx < ArrayLength(sRelationTypePairs); idx++) {
    97     if (sRelationTypePairs[idx].second == IA2_RELATION_NULL)
    98       continue;
   100     RelationType relationType = sRelationTypePairs[idx].first;
   101     Relation rel = acc->RelationByType(relationType);
   102     nsRefPtr<ia2AccessibleRelation> ia2Relation =
   103       new ia2AccessibleRelation(relationType, &rel);
   104     if (ia2Relation->HasTargets()) {
   105       if (relIdx == aRelationIndex) {
   106         ia2Relation.forget(aRelation);
   107         return S_OK;
   108       }
   110       relIdx++;
   111     }
   112   }
   114   return E_INVALIDARG;
   116   A11Y_TRYBLOCK_END
   117 }
   119 STDMETHODIMP
   120 ia2Accessible::get_relations(long aMaxRelations,
   121                              IAccessibleRelation** aRelation,
   122                              long *aNRelations)
   123 {
   124   A11Y_TRYBLOCK_BEGIN
   126   if (!aRelation || !aNRelations)
   127     return E_INVALIDARG;
   128   *aNRelations = 0;
   130   AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
   131   if (acc->IsDefunct())
   132     return CO_E_OBJNOTCONNECTED;
   134   for (uint32_t idx = 0; idx < ArrayLength(sRelationTypePairs) &&
   135        *aNRelations < aMaxRelations; idx++) {
   136     if (sRelationTypePairs[idx].second == IA2_RELATION_NULL)
   137       continue;
   139     RelationType relationType = sRelationTypePairs[idx].first;
   140     Relation rel = acc->RelationByType(relationType);
   141     nsRefPtr<ia2AccessibleRelation> ia2Rel =
   142       new ia2AccessibleRelation(relationType, &rel);
   143     if (ia2Rel->HasTargets()) {
   144       ia2Rel.forget(aRelation + (*aNRelations));
   145       (*aNRelations)++;
   146     }
   147   }
   148   return S_OK;
   150   A11Y_TRYBLOCK_END
   151 }
   153 STDMETHODIMP
   154 ia2Accessible::role(long* aRole)
   155 {
   156   A11Y_TRYBLOCK_BEGIN
   158   if (!aRole)
   159     return E_INVALIDARG;
   160   *aRole = 0;
   162   AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
   163   if (acc->IsDefunct())
   164     return CO_E_OBJNOTCONNECTED;
   166 #define ROLE(_geckoRole, stringRole, atkRole, macRole, \
   167              msaaRole, ia2Role, nameRule) \
   168   case roles::_geckoRole: \
   169     *aRole = ia2Role; \
   170     break;
   172   a11y::role geckoRole = acc->Role();
   173   switch (geckoRole) {
   174 #include "RoleMap.h"
   175     default:
   176       MOZ_CRASH("Unknown role.");
   177   };
   179 #undef ROLE
   181   // Special case, if there is a ROLE_ROW inside of a ROLE_TREE_TABLE, then call
   182   // the IA2 role a ROLE_OUTLINEITEM.
   183   if (geckoRole == roles::ROW) {
   184     Accessible* xpParent = acc->Parent();
   185     if (xpParent && xpParent->Role() == roles::TREE_TABLE)
   186       *aRole = ROLE_SYSTEM_OUTLINEITEM;
   187   }
   189   return S_OK;
   191   A11Y_TRYBLOCK_END
   192 }
   194 STDMETHODIMP
   195 ia2Accessible::scrollTo(enum IA2ScrollType aScrollType)
   196 {
   197   A11Y_TRYBLOCK_BEGIN
   199   AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
   200   if (acc->IsDefunct())
   201     return CO_E_OBJNOTCONNECTED;
   203   nsCoreUtils::ScrollTo(acc->Document()->PresShell(),
   204                         acc->GetContent(), aScrollType);
   205   return S_OK;
   207   A11Y_TRYBLOCK_END
   208 }
   210 STDMETHODIMP
   211 ia2Accessible::scrollToPoint(enum IA2CoordinateType aCoordType,
   212                               long aX, long aY)
   213 {
   214   A11Y_TRYBLOCK_BEGIN
   216   AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
   217   if (acc->IsDefunct())
   218     return CO_E_OBJNOTCONNECTED;
   220   uint32_t geckoCoordType = (aCoordType == IA2_COORDTYPE_SCREEN_RELATIVE) ?
   221     nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE :
   222     nsIAccessibleCoordinateType::COORDTYPE_PARENT_RELATIVE;
   224   nsresult rv = acc->ScrollToPoint(geckoCoordType, aX, aY);
   225   return GetHRESULT(rv);
   227   A11Y_TRYBLOCK_END
   228 }
   230 STDMETHODIMP
   231 ia2Accessible::get_groupPosition(long* aGroupLevel,
   232                                  long* aSimilarItemsInGroup,
   233                                  long* aPositionInGroup)
   234 {
   235   A11Y_TRYBLOCK_BEGIN
   237   if (!aGroupLevel || !aSimilarItemsInGroup || !aPositionInGroup)
   238     return E_INVALIDARG;
   240   *aGroupLevel = 0;
   241   *aSimilarItemsInGroup = 0;
   242   *aPositionInGroup = 0;
   244   AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
   245   if (acc->IsDefunct())
   246     return CO_E_OBJNOTCONNECTED;
   248   GroupPos groupPos = acc->GroupPosition();
   250   // Group information for accessibles having level only (like html headings
   251   // elements) isn't exposed by this method. AT should look for 'level' object
   252   // attribute.
   253   if (!groupPos.setSize && !groupPos.posInSet)
   254     return S_FALSE;
   256   *aGroupLevel = groupPos.level;
   257   *aSimilarItemsInGroup = groupPos.setSize;
   258   *aPositionInGroup = groupPos.posInSet;
   260   return S_OK;
   262   A11Y_TRYBLOCK_END
   263 }
   265 STDMETHODIMP
   266 ia2Accessible::get_states(AccessibleStates* aStates)
   267 {
   268   A11Y_TRYBLOCK_BEGIN
   270   if (!aStates)
   271     return E_INVALIDARG;
   272   *aStates = 0;
   274   // XXX: bug 344674 should come with better approach that we have here.
   276   AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
   277   uint64_t state = acc->State();
   279   if (state & states::INVALID)
   280     *aStates |= IA2_STATE_INVALID_ENTRY;
   281   if (state & states::REQUIRED)
   282     *aStates |= IA2_STATE_REQUIRED;
   284   // The following IA2 states are not supported by Gecko
   285   // IA2_STATE_ARMED
   286   // IA2_STATE_MANAGES_DESCENDANTS
   287   // IA2_STATE_ICONIFIED
   288   // IA2_STATE_INVALID // This is not a state, it is the absence of a state
   290   if (state & states::ACTIVE)
   291     *aStates |= IA2_STATE_ACTIVE;
   292   if (state & states::DEFUNCT)
   293     *aStates |= IA2_STATE_DEFUNCT;
   294   if (state & states::EDITABLE)
   295     *aStates |= IA2_STATE_EDITABLE;
   296   if (state & states::HORIZONTAL)
   297     *aStates |= IA2_STATE_HORIZONTAL;
   298   if (state & states::MODAL)
   299     *aStates |= IA2_STATE_MODAL;
   300   if (state & states::MULTI_LINE)
   301     *aStates |= IA2_STATE_MULTI_LINE;
   302   if (state & states::OPAQUE1)
   303     *aStates |= IA2_STATE_OPAQUE;
   304   if (state & states::SELECTABLE_TEXT)
   305     *aStates |= IA2_STATE_SELECTABLE_TEXT;
   306   if (state & states::SINGLE_LINE)
   307     *aStates |= IA2_STATE_SINGLE_LINE;
   308   if (state & states::STALE)
   309     *aStates |= IA2_STATE_STALE;
   310   if (state & states::SUPPORTS_AUTOCOMPLETION)
   311     *aStates |= IA2_STATE_SUPPORTS_AUTOCOMPLETION;
   312   if (state & states::TRANSIENT)
   313     *aStates |= IA2_STATE_TRANSIENT;
   314   if (state & states::VERTICAL)
   315     *aStates |= IA2_STATE_VERTICAL;
   316   if (state & states::CHECKED)
   317     *aStates |= IA2_STATE_CHECKABLE;
   318   if (state & states::PINNED)
   319     *aStates |= IA2_STATE_PINNED;
   321   return S_OK;
   323   A11Y_TRYBLOCK_END
   324 }
   326 STDMETHODIMP
   327 ia2Accessible::get_extendedRole(BSTR* aExtendedRole)
   328 {
   329   A11Y_TRYBLOCK_BEGIN
   331   if (!aExtendedRole)
   332     return E_INVALIDARG;
   334   *aExtendedRole = nullptr;
   335   return E_NOTIMPL;
   337   A11Y_TRYBLOCK_END
   338 }
   340 STDMETHODIMP
   341 ia2Accessible::get_localizedExtendedRole(BSTR* aLocalizedExtendedRole)
   342 {
   343   A11Y_TRYBLOCK_BEGIN
   345   if (!aLocalizedExtendedRole)
   346     return E_INVALIDARG;
   348   *aLocalizedExtendedRole = nullptr;
   349   return E_NOTIMPL;
   351   A11Y_TRYBLOCK_END
   352 }
   354 STDMETHODIMP
   355 ia2Accessible::get_nExtendedStates(long* aNExtendedStates)
   356 {
   357   A11Y_TRYBLOCK_BEGIN
   359   if (!aNExtendedStates)
   360     return E_INVALIDARG;
   362   *aNExtendedStates = 0;
   363   return E_NOTIMPL;
   365   A11Y_TRYBLOCK_END
   366 }
   368 STDMETHODIMP
   369 ia2Accessible::get_extendedStates(long aMaxExtendedStates,
   370                                   BSTR** aExtendedStates,
   371                                   long* aNExtendedStates)
   372 {
   373   A11Y_TRYBLOCK_BEGIN
   375   if (!aExtendedStates || !aNExtendedStates)
   376     return E_INVALIDARG;
   378   *aExtendedStates = nullptr;
   379   *aNExtendedStates = 0;
   380   return E_NOTIMPL;
   382   A11Y_TRYBLOCK_END
   383 }
   385 STDMETHODIMP
   386 ia2Accessible::get_localizedExtendedStates(long aMaxLocalizedExtendedStates,
   387                                            BSTR** aLocalizedExtendedStates,
   388                                            long* aNLocalizedExtendedStates)
   389 {
   390   A11Y_TRYBLOCK_BEGIN
   392   if (!aLocalizedExtendedStates || !aNLocalizedExtendedStates)
   393     return E_INVALIDARG;
   395   *aLocalizedExtendedStates = nullptr;
   396   *aNLocalizedExtendedStates = 0;
   397   return E_NOTIMPL;
   399   A11Y_TRYBLOCK_END
   400 }
   402 STDMETHODIMP
   403 ia2Accessible::get_uniqueID(long* aUniqueID)
   404 {
   405   A11Y_TRYBLOCK_BEGIN
   407   if (!aUniqueID)
   408     return E_INVALIDARG;
   410   AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
   411   *aUniqueID = - reinterpret_cast<intptr_t>(acc->UniqueID());
   412   return S_OK;
   414   A11Y_TRYBLOCK_END
   415 }
   417 STDMETHODIMP
   418 ia2Accessible::get_windowHandle(HWND* aWindowHandle)
   419 {
   420   A11Y_TRYBLOCK_BEGIN
   422   if (!aWindowHandle)
   423     return E_INVALIDARG;
   424   *aWindowHandle = 0;
   426   AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
   427   if (acc->IsDefunct())
   428     return CO_E_OBJNOTCONNECTED;
   430   *aWindowHandle = AccessibleWrap::GetHWNDFor(acc);
   431   return S_OK;
   433   A11Y_TRYBLOCK_END
   434 }
   436 STDMETHODIMP
   437 ia2Accessible::get_indexInParent(long* aIndexInParent)
   438 {
   439   A11Y_TRYBLOCK_BEGIN
   441   if (!aIndexInParent)
   442     return E_INVALIDARG;
   443   *aIndexInParent = -1;
   445   AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
   446   if (acc->IsDefunct())
   447     return CO_E_OBJNOTCONNECTED;
   449   *aIndexInParent = acc->IndexInParent();
   450   if (*aIndexInParent == -1)
   451     return S_FALSE;
   453   return S_OK;
   455   A11Y_TRYBLOCK_END
   456 }
   458 STDMETHODIMP
   459 ia2Accessible::get_locale(IA2Locale* aLocale)
   460 {
   461   A11Y_TRYBLOCK_BEGIN
   463   if (!aLocale)
   464     return E_INVALIDARG;
   466   // Language codes consist of a primary code and a possibly empty series of
   467   // subcodes: language-code = primary-code ( "-" subcode )*
   468   // Two-letter primary codes are reserved for [ISO639] language abbreviations.
   469   // Any two-letter subcode is understood to be a [ISO3166] country code.
   471   AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
   472   if (acc->IsDefunct())
   473     return CO_E_OBJNOTCONNECTED;
   475   nsAutoString lang;
   476   acc->Language(lang);
   478   // If primary code consists from two letters then expose it as language.
   479   int32_t offset = lang.FindChar('-', 0);
   480   if (offset == -1) {
   481     if (lang.Length() == 2) {
   482       aLocale->language = ::SysAllocString(lang.get());
   483       return S_OK;
   484     }
   485   } else if (offset == 2) {
   486     aLocale->language = ::SysAllocStringLen(lang.get(), 2);
   488     // If the first subcode consists from two letters then expose it as
   489     // country.
   490     offset = lang.FindChar('-', 3);
   491     if (offset == -1) {
   492       if (lang.Length() == 5) {
   493         aLocale->country = ::SysAllocString(lang.get() + 3);
   494         return S_OK;
   495       }
   496     } else if (offset == 5) {
   497       aLocale->country = ::SysAllocStringLen(lang.get() + 3, 2);
   498     }
   499   }
   501   // Expose as a string if primary code or subcode cannot point to language or
   502   // country abbreviations or if there are more than one subcode.
   503   aLocale->variant = ::SysAllocString(lang.get());
   504   return S_OK;
   506   A11Y_TRYBLOCK_END
   507 }
   509 STDMETHODIMP
   510 ia2Accessible::get_attributes(BSTR* aAttributes)
   511 {
   512   A11Y_TRYBLOCK_BEGIN
   514   if (!aAttributes)
   515     return E_INVALIDARG;
   516   *aAttributes = nullptr;
   518   AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
   519   if (acc->IsDefunct())
   520     return CO_E_OBJNOTCONNECTED;
   522   // The format is name:value;name:value; with \ for escaping these
   523   // characters ":;=,\".
   524   nsCOMPtr<nsIPersistentProperties> attributes = acc->Attributes();
   525   return ConvertToIA2Attributes(attributes, aAttributes);
   527   A11Y_TRYBLOCK_END
   528 }
   530 ////////////////////////////////////////////////////////////////////////////////
   531 // IAccessible2_2
   533 STDMETHODIMP
   534 ia2Accessible::get_attribute(BSTR name, VARIANT* aAttribute)
   535 {
   536   A11Y_TRYBLOCK_BEGIN
   538   if (!aAttribute)
   539     return E_INVALIDARG;
   541   return E_NOTIMPL;
   543   A11Y_TRYBLOCK_END
   544 }
   546 STDMETHODIMP
   547 ia2Accessible::get_accessibleWithCaret(IUnknown** aAccessible,
   548                                        long* aCaretOffset)
   549 {
   550   A11Y_TRYBLOCK_BEGIN
   552   if (!aAccessible || !aCaretOffset)
   553     return E_INVALIDARG;
   555   *aAccessible = nullptr;
   556   *aCaretOffset = -1;
   557   return E_NOTIMPL;
   559   A11Y_TRYBLOCK_END
   560 }
   562 STDMETHODIMP
   563 ia2Accessible::get_relationTargetsOfType(BSTR aType,
   564                                          long aMaxTargets,
   565                                          IUnknown*** aTargets,
   566                                          long* aNTargets)
   567 {
   568   A11Y_TRYBLOCK_BEGIN
   570   if (!aTargets || !aNTargets)
   571     return E_INVALIDARG;
   572   *aNTargets = 0;
   574   Maybe<RelationType> relationType;
   575   for (uint32_t idx = 0; idx < ArrayLength(sRelationTypePairs); idx++) {
   576     if (wcscmp(aType, sRelationTypePairs[idx].second) == 0) {
   577       relationType.construct(sRelationTypePairs[idx].first);
   578       break;
   579     }
   580   }
   581   if (relationType.empty())
   582     return E_INVALIDARG;
   584   AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
   585   if (acc->IsDefunct())
   586     return CO_E_OBJNOTCONNECTED;
   588   Relation rel = acc->RelationByType(relationType.ref());
   590   nsTArray<Accessible*> targets;
   591   Accessible* target = nullptr;
   592   while ((target = rel.Next()) &&
   593          static_cast<long>(targets.Length()) <= aMaxTargets)
   594     targets.AppendElement(target);
   596   *aNTargets = targets.Length();
   597   *aTargets = static_cast<IUnknown**>(
   598     ::CoTaskMemAlloc(sizeof(IUnknown*) * *aNTargets));
   599   if (!*aTargets)
   600     return E_OUTOFMEMORY;
   602   for (int32_t i = 0; i < *aNTargets; i++) {
   603     AccessibleWrap* target= static_cast<AccessibleWrap*>(targets[i]);
   604     (*aTargets)[i] = static_cast<IAccessible2*>(target);
   605     (*aTargets)[i]->AddRef();
   606   }
   608   return S_OK;
   610   A11Y_TRYBLOCK_END
   611 }
   613 ////////////////////////////////////////////////////////////////////////////////
   614 // Helpers
   616 HRESULT
   617 ia2Accessible::ConvertToIA2Attributes(nsIPersistentProperties* aAttributes,
   618                                       BSTR* aIA2Attributes)
   619 {
   620   *aIA2Attributes = nullptr;
   622   // The format is name:value;name:value; with \ for escaping these
   623   // characters ":;=,\".
   625   if (!aAttributes)
   626     return S_FALSE;
   628   nsCOMPtr<nsISimpleEnumerator> propEnum;
   629   aAttributes->Enumerate(getter_AddRefs(propEnum));
   630   if (!propEnum)
   631     return E_FAIL;
   633   nsAutoString strAttrs;
   635   const char kCharsToEscape[] = ":;=,\\";
   637   bool hasMore = false;
   638   while (NS_SUCCEEDED(propEnum->HasMoreElements(&hasMore)) && hasMore) {
   639     nsCOMPtr<nsISupports> propSupports;
   640     propEnum->GetNext(getter_AddRefs(propSupports));
   642     nsCOMPtr<nsIPropertyElement> propElem(do_QueryInterface(propSupports));
   643     if (!propElem)
   644       return E_FAIL;
   646     nsAutoCString name;
   647     if (NS_FAILED(propElem->GetKey(name)))
   648       return E_FAIL;
   650     int32_t offset = 0;
   651     while ((offset = name.FindCharInSet(kCharsToEscape, offset)) != kNotFound) {
   652       name.Insert('\\', offset);
   653       offset += 2;
   654     }
   656     nsAutoString value;
   657     if (NS_FAILED(propElem->GetValue(value)))
   658       return E_FAIL;
   660     offset = 0;
   661     while ((offset = value.FindCharInSet(kCharsToEscape, offset)) != kNotFound) {
   662       value.Insert('\\', offset);
   663       offset += 2;
   664     }
   666     AppendUTF8toUTF16(name, strAttrs);
   667     strAttrs.Append(':');
   668     strAttrs.Append(value);
   669     strAttrs.Append(';');
   670   }
   672   if (strAttrs.IsEmpty())
   673     return S_FALSE;
   675   *aIA2Attributes = ::SysAllocStringLen(strAttrs.get(), strAttrs.Length());
   676   return *aIA2Attributes ? S_OK : E_OUTOFMEMORY;
   677 }

mercurial