accessible/src/atk/Platform.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* vim: set ts=2 et sw=2 tw=80: */
michael@0 3 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #include "Platform.h"
michael@0 8
michael@0 9 #include "nsIAccessibleEvent.h"
michael@0 10 #include "nsIGConfService.h"
michael@0 11 #include "nsIServiceManager.h"
michael@0 12 #include "nsMai.h"
michael@0 13 #include "AtkSocketAccessible.h"
michael@0 14 #include "prenv.h"
michael@0 15 #include "prlink.h"
michael@0 16
michael@0 17 #ifdef MOZ_ENABLE_DBUS
michael@0 18 #include <dbus/dbus.h>
michael@0 19 #endif
michael@0 20 #include <gtk/gtk.h>
michael@0 21
michael@0 22 using namespace mozilla;
michael@0 23 using namespace mozilla::a11y;
michael@0 24
michael@0 25 int atkMajorVersion = 1, atkMinorVersion = 12;
michael@0 26
michael@0 27 extern "C" {
michael@0 28 typedef GType (* AtkGetTypeType) (void);
michael@0 29 typedef void (*GnomeAccessibilityInit) (void);
michael@0 30 typedef void (*GnomeAccessibilityShutdown) (void);
michael@0 31 }
michael@0 32
michael@0 33 static PRLibrary* sATKLib = nullptr;
michael@0 34 static const char sATKLibName[] = "libatk-1.0.so.0";
michael@0 35 static const char sATKHyperlinkImplGetTypeSymbol[] =
michael@0 36 "atk_hyperlink_impl_get_type";
michael@0 37
michael@0 38 gboolean toplevel_event_watcher(GSignalInvocationHint*, guint, const GValue*,
michael@0 39 gpointer);
michael@0 40 static bool sToplevel_event_hook_added = false;
michael@0 41 static gulong sToplevel_show_hook = 0;
michael@0 42 static gulong sToplevel_hide_hook = 0;
michael@0 43
michael@0 44 GType g_atk_hyperlink_impl_type = G_TYPE_INVALID;
michael@0 45
michael@0 46 struct GnomeAccessibilityModule
michael@0 47 {
michael@0 48 const char *libName;
michael@0 49 PRLibrary *lib;
michael@0 50 const char *initName;
michael@0 51 GnomeAccessibilityInit init;
michael@0 52 const char *shutdownName;
michael@0 53 GnomeAccessibilityShutdown shutdown;
michael@0 54 };
michael@0 55
michael@0 56 static GnomeAccessibilityModule sAtkBridge = {
michael@0 57 #ifdef AIX
michael@0 58 "libatk-bridge.a(libatk-bridge.so.0)", nullptr,
michael@0 59 #else
michael@0 60 "libatk-bridge.so", nullptr,
michael@0 61 #endif
michael@0 62 "gnome_accessibility_module_init", nullptr,
michael@0 63 "gnome_accessibility_module_shutdown", nullptr
michael@0 64 };
michael@0 65
michael@0 66 static GnomeAccessibilityModule sGail = {
michael@0 67 "libgail.so", nullptr,
michael@0 68 "gnome_accessibility_module_init", nullptr,
michael@0 69 "gnome_accessibility_module_shutdown", nullptr
michael@0 70 };
michael@0 71
michael@0 72 static nsresult
michael@0 73 LoadGtkModule(GnomeAccessibilityModule& aModule)
michael@0 74 {
michael@0 75 NS_ENSURE_ARG(aModule.libName);
michael@0 76
michael@0 77 if (!(aModule.lib = PR_LoadLibrary(aModule.libName))) {
michael@0 78 //try to load the module with "gtk-2.0/modules" appended
michael@0 79 char *curLibPath = PR_GetLibraryPath();
michael@0 80 nsAutoCString libPath(curLibPath);
michael@0 81 #if defined(LINUX) && defined(__x86_64__)
michael@0 82 libPath.Append(":/usr/lib64:/usr/lib");
michael@0 83 #else
michael@0 84 libPath.Append(":/usr/lib");
michael@0 85 #endif
michael@0 86 PR_FreeLibraryName(curLibPath);
michael@0 87
michael@0 88 int16_t loc1 = 0, loc2 = 0;
michael@0 89 int16_t subLen = 0;
michael@0 90 while (loc2 >= 0) {
michael@0 91 loc2 = libPath.FindChar(':', loc1);
michael@0 92 if (loc2 < 0)
michael@0 93 subLen = libPath.Length() - loc1;
michael@0 94 else
michael@0 95 subLen = loc2 - loc1;
michael@0 96 nsAutoCString sub(Substring(libPath, loc1, subLen));
michael@0 97 sub.Append("/gtk-2.0/modules/");
michael@0 98 sub.Append(aModule.libName);
michael@0 99 aModule.lib = PR_LoadLibrary(sub.get());
michael@0 100 if (aModule.lib)
michael@0 101 break;
michael@0 102
michael@0 103 loc1 = loc2+1;
michael@0 104 }
michael@0 105 if (!aModule.lib)
michael@0 106 return NS_ERROR_FAILURE;
michael@0 107 }
michael@0 108
michael@0 109 //we have loaded the library, try to get the function ptrs
michael@0 110 if (!(aModule.init = PR_FindFunctionSymbol(aModule.lib,
michael@0 111 aModule.initName)) ||
michael@0 112 !(aModule.shutdown = PR_FindFunctionSymbol(aModule.lib,
michael@0 113 aModule.shutdownName))) {
michael@0 114
michael@0 115 //fail, :(
michael@0 116 PR_UnloadLibrary(aModule.lib);
michael@0 117 aModule.lib = nullptr;
michael@0 118 return NS_ERROR_FAILURE;
michael@0 119 }
michael@0 120 return NS_OK;
michael@0 121 }
michael@0 122
michael@0 123 void
michael@0 124 a11y::PlatformInit()
michael@0 125 {
michael@0 126 if (!ShouldA11yBeEnabled())
michael@0 127 return;
michael@0 128
michael@0 129 sATKLib = PR_LoadLibrary(sATKLibName);
michael@0 130 if (!sATKLib)
michael@0 131 return;
michael@0 132
michael@0 133 AtkGetTypeType pfn_atk_hyperlink_impl_get_type =
michael@0 134 (AtkGetTypeType) PR_FindFunctionSymbol(sATKLib, sATKHyperlinkImplGetTypeSymbol);
michael@0 135 if (pfn_atk_hyperlink_impl_get_type)
michael@0 136 g_atk_hyperlink_impl_type = pfn_atk_hyperlink_impl_get_type();
michael@0 137
michael@0 138 AtkGetTypeType pfn_atk_socket_get_type = (AtkGetTypeType)
michael@0 139 PR_FindFunctionSymbol(sATKLib, AtkSocketAccessible::sATKSocketGetTypeSymbol);
michael@0 140 if (pfn_atk_socket_get_type) {
michael@0 141 AtkSocketAccessible::g_atk_socket_type = pfn_atk_socket_get_type();
michael@0 142 AtkSocketAccessible::g_atk_socket_embed = (AtkSocketEmbedType)
michael@0 143 PR_FindFunctionSymbol(sATKLib, AtkSocketAccessible ::sATKSocketEmbedSymbol);
michael@0 144 AtkSocketAccessible::gCanEmbed =
michael@0 145 AtkSocketAccessible::g_atk_socket_type != G_TYPE_INVALID &&
michael@0 146 AtkSocketAccessible::g_atk_socket_embed;
michael@0 147 }
michael@0 148
michael@0 149 const char* (*atkGetVersion)() =
michael@0 150 (const char* (*)()) PR_FindFunctionSymbol(sATKLib, "atk_get_version");
michael@0 151 if (atkGetVersion) {
michael@0 152 const char* version = atkGetVersion();
michael@0 153 if (version) {
michael@0 154 char* endPtr = nullptr;
michael@0 155 atkMajorVersion = strtol(version, &endPtr, 10);
michael@0 156 if (*endPtr == '.')
michael@0 157 atkMinorVersion = strtol(endPtr + 1, &endPtr, 10);
michael@0 158 }
michael@0 159 }
michael@0 160
michael@0 161 // Load and initialize gail library.
michael@0 162 nsresult rv = LoadGtkModule(sGail);
michael@0 163 if (NS_SUCCEEDED(rv))
michael@0 164 (*sGail.init)();
michael@0 165
michael@0 166 // Initialize the MAI Utility class, it will overwrite gail_util.
michael@0 167 g_type_class_unref(g_type_class_ref(mai_util_get_type()));
michael@0 168
michael@0 169 // Init atk-bridge now
michael@0 170 PR_SetEnv("NO_AT_BRIDGE=0");
michael@0 171 rv = LoadGtkModule(sAtkBridge);
michael@0 172 if (NS_SUCCEEDED(rv)) {
michael@0 173 (*sAtkBridge.init)();
michael@0 174 }
michael@0 175
michael@0 176 if (!sToplevel_event_hook_added) {
michael@0 177 sToplevel_event_hook_added = true;
michael@0 178 sToplevel_show_hook =
michael@0 179 g_signal_add_emission_hook(g_signal_lookup("show", GTK_TYPE_WINDOW),
michael@0 180 0, toplevel_event_watcher,
michael@0 181 reinterpret_cast<gpointer>(nsIAccessibleEvent::EVENT_SHOW),
michael@0 182 nullptr);
michael@0 183 sToplevel_hide_hook =
michael@0 184 g_signal_add_emission_hook(g_signal_lookup("hide", GTK_TYPE_WINDOW), 0,
michael@0 185 toplevel_event_watcher,
michael@0 186 reinterpret_cast<gpointer>(nsIAccessibleEvent::EVENT_HIDE),
michael@0 187 nullptr);
michael@0 188 }
michael@0 189 }
michael@0 190
michael@0 191 void
michael@0 192 a11y::PlatformShutdown()
michael@0 193 {
michael@0 194 if (sToplevel_event_hook_added) {
michael@0 195 sToplevel_event_hook_added = false;
michael@0 196 g_signal_remove_emission_hook(g_signal_lookup("show", GTK_TYPE_WINDOW),
michael@0 197 sToplevel_show_hook);
michael@0 198 g_signal_remove_emission_hook(g_signal_lookup("hide", GTK_TYPE_WINDOW),
michael@0 199 sToplevel_hide_hook);
michael@0 200 }
michael@0 201
michael@0 202 if (sAtkBridge.lib) {
michael@0 203 // Do not shutdown/unload atk-bridge,
michael@0 204 // an exit function registered will take care of it
michael@0 205 // if (sAtkBridge.shutdown)
michael@0 206 // (*sAtkBridge.shutdown)();
michael@0 207 // PR_UnloadLibrary(sAtkBridge.lib);
michael@0 208 sAtkBridge.lib = nullptr;
michael@0 209 sAtkBridge.init = nullptr;
michael@0 210 sAtkBridge.shutdown = nullptr;
michael@0 211 }
michael@0 212 if (sGail.lib) {
michael@0 213 // Do not shutdown gail because
michael@0 214 // 1) Maybe it's not init-ed by us. e.g. GtkEmbed
michael@0 215 // 2) We need it to avoid assert in spi_atk_tidy_windows
michael@0 216 // if (sGail.shutdown)
michael@0 217 // (*sGail.shutdown)();
michael@0 218 // PR_UnloadLibrary(sGail.lib);
michael@0 219 sGail.lib = nullptr;
michael@0 220 sGail.init = nullptr;
michael@0 221 sGail.shutdown = nullptr;
michael@0 222 }
michael@0 223 // if (sATKLib) {
michael@0 224 // PR_UnloadLibrary(sATKLib);
michael@0 225 // sATKLib = nullptr;
michael@0 226 // }
michael@0 227 }
michael@0 228
michael@0 229 static const char sAccEnv [] = "GNOME_ACCESSIBILITY";
michael@0 230 #ifdef MOZ_ENABLE_DBUS
michael@0 231 static DBusPendingCall *sPendingCall = nullptr;
michael@0 232 #endif
michael@0 233
michael@0 234 void
michael@0 235 a11y::PreInit()
michael@0 236 {
michael@0 237 #ifdef MOZ_ENABLE_DBUS
michael@0 238 static bool sChecked = FALSE;
michael@0 239 if (sChecked)
michael@0 240 return;
michael@0 241
michael@0 242 sChecked = TRUE;
michael@0 243
michael@0 244 // dbus is only checked if GNOME_ACCESSIBILITY is unset
michael@0 245 // also make sure that a session bus address is available to prevent dbus from
michael@0 246 // starting a new one. Dbus confuses the test harness when it creates a new
michael@0 247 // process (see bug 693343)
michael@0 248 if (PR_GetEnv(sAccEnv) || !PR_GetEnv("DBUS_SESSION_BUS_ADDRESS"))
michael@0 249 return;
michael@0 250
michael@0 251 DBusConnection* bus = dbus_bus_get(DBUS_BUS_SESSION, nullptr);
michael@0 252 if (!bus)
michael@0 253 return;
michael@0 254
michael@0 255 dbus_connection_set_exit_on_disconnect(bus, FALSE);
michael@0 256
michael@0 257 static const char* iface = "org.a11y.Status";
michael@0 258 static const char* member = "IsEnabled";
michael@0 259 DBusMessage *message;
michael@0 260 message = dbus_message_new_method_call("org.a11y.Bus", "/org/a11y/bus",
michael@0 261 "org.freedesktop.DBus.Properties",
michael@0 262 "Get");
michael@0 263 if (!message)
michael@0 264 goto dbus_done;
michael@0 265
michael@0 266 dbus_message_append_args(message, DBUS_TYPE_STRING, &iface,
michael@0 267 DBUS_TYPE_STRING, &member, DBUS_TYPE_INVALID);
michael@0 268 dbus_connection_send_with_reply(bus, message, &sPendingCall, 1000);
michael@0 269 dbus_message_unref(message);
michael@0 270
michael@0 271 dbus_done:
michael@0 272 dbus_connection_unref(bus);
michael@0 273 #endif
michael@0 274 }
michael@0 275
michael@0 276 bool
michael@0 277 a11y::ShouldA11yBeEnabled()
michael@0 278 {
michael@0 279 static bool sChecked = false, sShouldEnable = false;
michael@0 280 if (sChecked)
michael@0 281 return sShouldEnable;
michael@0 282
michael@0 283 sChecked = true;
michael@0 284
michael@0 285 EPlatformDisabledState disabledState = PlatformDisabledState();
michael@0 286 if (disabledState == ePlatformIsDisabled)
michael@0 287 return sShouldEnable = false;
michael@0 288
michael@0 289 // check if accessibility enabled/disabled by environment variable
michael@0 290 const char* envValue = PR_GetEnv(sAccEnv);
michael@0 291 if (envValue)
michael@0 292 return sShouldEnable = !!atoi(envValue);
michael@0 293
michael@0 294 #ifdef MOZ_ENABLE_DBUS
michael@0 295 PreInit();
michael@0 296 bool dbusSuccess = false;
michael@0 297 DBusMessage *reply = nullptr;
michael@0 298 if (!sPendingCall)
michael@0 299 goto dbus_done;
michael@0 300
michael@0 301 dbus_pending_call_block(sPendingCall);
michael@0 302 reply = dbus_pending_call_steal_reply(sPendingCall);
michael@0 303 dbus_pending_call_unref(sPendingCall);
michael@0 304 sPendingCall = nullptr;
michael@0 305 if (!reply ||
michael@0 306 dbus_message_get_type(reply) != DBUS_MESSAGE_TYPE_METHOD_RETURN ||
michael@0 307 strcmp(dbus_message_get_signature (reply), DBUS_TYPE_VARIANT_AS_STRING))
michael@0 308 goto dbus_done;
michael@0 309
michael@0 310 DBusMessageIter iter, iter_variant, iter_struct;
michael@0 311 dbus_bool_t dResult;
michael@0 312 dbus_message_iter_init(reply, &iter);
michael@0 313 dbus_message_iter_recurse (&iter, &iter_variant);
michael@0 314 switch (dbus_message_iter_get_arg_type(&iter_variant)) {
michael@0 315 case DBUS_TYPE_STRUCT:
michael@0 316 // at-spi2-core 2.2.0-2.2.1 had a bug where it returned a struct
michael@0 317 dbus_message_iter_recurse(&iter_variant, &iter_struct);
michael@0 318 if (dbus_message_iter_get_arg_type(&iter_struct) == DBUS_TYPE_BOOLEAN) {
michael@0 319 dbus_message_iter_get_basic(&iter_struct, &dResult);
michael@0 320 sShouldEnable = dResult;
michael@0 321 dbusSuccess = true;
michael@0 322 }
michael@0 323
michael@0 324 break;
michael@0 325 case DBUS_TYPE_BOOLEAN:
michael@0 326 dbus_message_iter_get_basic(&iter_variant, &dResult);
michael@0 327 sShouldEnable = dResult;
michael@0 328 dbusSuccess = true;
michael@0 329 break;
michael@0 330 default:
michael@0 331 break;
michael@0 332 }
michael@0 333
michael@0 334 dbus_done:
michael@0 335 if (reply)
michael@0 336 dbus_message_unref(reply);
michael@0 337
michael@0 338 if (dbusSuccess)
michael@0 339 return sShouldEnable;
michael@0 340 #endif
michael@0 341
michael@0 342 //check gconf-2 setting
michael@0 343 static const char sGconfAccessibilityKey[] =
michael@0 344 "/desktop/gnome/interface/accessibility";
michael@0 345 nsresult rv = NS_OK;
michael@0 346 nsCOMPtr<nsIGConfService> gconf =
michael@0 347 do_GetService(NS_GCONFSERVICE_CONTRACTID, &rv);
michael@0 348 if (NS_SUCCEEDED(rv) && gconf)
michael@0 349 gconf->GetBool(NS_LITERAL_CSTRING(sGconfAccessibilityKey), &sShouldEnable);
michael@0 350
michael@0 351 return sShouldEnable;
michael@0 352 }

mercurial