nsMaiInterfaceAction.cpp (5064B)
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/. */ 6 7 #include "InterfaceInitFuncs.h" 8 9 #include "LocalAccessible-inl.h" 10 #include "nsMai.h" 11 #include "mozilla/Likely.h" 12 #include "nsAccessibilityService.h" 13 #include "Relation.h" 14 #include "RemoteAccessible.h" 15 #include "nsString.h" 16 17 using namespace mozilla; 18 using namespace mozilla::a11y; 19 20 extern "C" { 21 22 static gboolean doActionCB(AtkAction* aAction, gint aActionIndex) { 23 AtkObject* atkObject = ATK_OBJECT(aAction); 24 Accessible* acc = GetInternalObj(atkObject); 25 if (!acc) { 26 // If we don't have an Accessible, we can't have any actions. 27 return false; 28 } 29 30 if (aActionIndex < acc->ActionCount()) { 31 acc->DoAction(aActionIndex); 32 return true; 33 } 34 35 // Check for custom actions. 36 Relation customActions(acc->RelationByType(RelationType::ACTION)); 37 gint actionIndex = acc->ActionCount(); 38 while (Accessible* target = customActions.Next()) { 39 if (target->HasPrimaryAction()) { 40 MOZ_ASSERT(target->ActionCount() > 0); 41 if (actionIndex == aActionIndex) { 42 target->DoAction(0); 43 return true; 44 } 45 actionIndex++; 46 } 47 } 48 49 return false; 50 } 51 52 static gint getActionCountCB(AtkAction* aAction) { 53 AtkObject* atkObject = ATK_OBJECT(aAction); 54 Accessible* acc = GetInternalObj(atkObject); 55 if (!acc) { 56 // If we don't have an Accessible, we can't have any actions. 57 return 0; 58 } 59 60 gint actionCount = acc->ActionCount(); 61 Relation customActions(acc->RelationByType(RelationType::ACTION)); 62 while (Accessible* target = customActions.Next()) { 63 if (target->HasPrimaryAction()) { 64 actionCount++; 65 } 66 } 67 68 return actionCount; 69 } 70 71 static const gchar* getActionDescriptionCB(AtkAction* aAction, 72 gint aActionIndex) { 73 AtkObject* atkObject = ATK_OBJECT(aAction); 74 nsAutoString description; 75 Accessible* acc = GetInternalObj(atkObject); 76 if (!acc) { 77 // If we don't have an Accessible, we can't have any actions. 78 return 0; 79 } 80 81 if (aActionIndex < acc->ActionCount()) { 82 acc->ActionDescriptionAt(aActionIndex, description); 83 } else { 84 // Check for custom actions. 85 Relation customActions(acc->RelationByType(RelationType::ACTION)); 86 gint actionIndex = acc->ActionCount(); 87 while (Accessible* target = customActions.Next()) { 88 if (target->HasPrimaryAction()) { 89 MOZ_ASSERT(target->ActionCount() > 0); 90 if (actionIndex == aActionIndex) { 91 // Use target's name as action description. 92 target->Name(description); 93 break; 94 } 95 actionIndex++; 96 } 97 } 98 } 99 100 if (!description.IsEmpty()) { 101 return AccessibleWrap::ReturnString(description); 102 } 103 104 return nullptr; 105 } 106 107 static const gchar* getActionNameCB(AtkAction* aAction, gint aActionIndex) { 108 AtkObject* atkObject = ATK_OBJECT(aAction); 109 nsAutoString name; 110 Accessible* acc = GetInternalObj(atkObject); 111 if (!acc) { 112 // If we don't have an Accessible, we can't have any actions. 113 return 0; 114 } 115 116 if (aActionIndex < acc->ActionCount()) { 117 acc->ActionNameAt(aActionIndex, name); 118 } else { 119 // Check for custom actions. 120 Relation customActions(acc->RelationByType(RelationType::ACTION)); 121 gint actionIndex = acc->ActionCount(); 122 while (Accessible* target = customActions.Next()) { 123 if (target->HasPrimaryAction()) { 124 MOZ_ASSERT(target->ActionCount() > 0); 125 if (actionIndex == aActionIndex) { 126 name.AssignLiteral("custom"); 127 nsAutoString domNodeId; 128 target->DOMNodeID(domNodeId); 129 if (!domNodeId.IsEmpty()) { 130 name.AppendPrintf("_%s", NS_ConvertUTF16toUTF8(domNodeId).get()); 131 } 132 break; 133 } 134 actionIndex++; 135 } 136 } 137 } 138 139 if (!name.IsEmpty()) { 140 return AccessibleWrap::ReturnString(name); 141 } 142 143 return nullptr; 144 } 145 146 static const gchar* getActionLocalizedNameCB(AtkAction* aAction, 147 gint aActionIndex) { 148 // Mirror action description into localized name. 149 return getActionDescriptionCB(aAction, aActionIndex); 150 } 151 152 static const gchar* getKeyBindingCB(AtkAction* aAction, gint aActionIndex) { 153 Accessible* acc = GetInternalObj(ATK_OBJECT(aAction)); 154 if (!acc) { 155 return nullptr; 156 } 157 nsAutoString keyBindingsStr; 158 AccessibleWrap::GetKeyBinding(acc, keyBindingsStr); 159 160 return AccessibleWrap::ReturnString(keyBindingsStr); 161 } 162 } 163 164 void actionInterfaceInitCB(AtkActionIface* aIface) { 165 NS_ASSERTION(aIface, "Invalid aIface"); 166 if (MOZ_UNLIKELY(!aIface)) return; 167 168 aIface->do_action = doActionCB; 169 aIface->get_n_actions = getActionCountCB; 170 aIface->get_description = getActionDescriptionCB; 171 aIface->get_keybinding = getKeyBindingCB; 172 aIface->get_name = getActionNameCB; 173 aIface->get_localized_name = getActionLocalizedNameCB; 174 }