widget/xpwidgets/GfxInfoBase.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/widget/xpwidgets/GfxInfoBase.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,962 @@
     1.4 +/* vim: se cin sw=2 ts=2 et : */
     1.5 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
     1.6 + *
     1.7 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.8 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.9 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
    1.10 +
    1.11 +#include "mozilla/ArrayUtils.h"
    1.12 +
    1.13 +#include "GfxInfoBase.h"
    1.14 +
    1.15 +#include "GfxInfoWebGL.h"
    1.16 +#include "GfxDriverInfo.h"
    1.17 +#include "nsCOMPtr.h"
    1.18 +#include "nsCOMArray.h"
    1.19 +#include "nsAutoPtr.h"
    1.20 +#include "nsString.h"
    1.21 +#include "nsUnicharUtils.h"
    1.22 +#include "mozilla/Services.h"
    1.23 +#include "mozilla/Observer.h"
    1.24 +#include "nsIObserver.h"
    1.25 +#include "nsIObserverService.h"
    1.26 +#include "nsIDOMElement.h"
    1.27 +#include "nsIDOMHTMLCollection.h"
    1.28 +#include "nsIDOMNode.h"
    1.29 +#include "nsIDOMNodeList.h"
    1.30 +#include "nsTArray.h"
    1.31 +#include "nsXULAppAPI.h"
    1.32 +#include "mozilla/Preferences.h"
    1.33 +#include "mozilla/dom/ContentChild.h"
    1.34 +
    1.35 +#if defined(MOZ_CRASHREPORTER)
    1.36 +#include "nsExceptionHandler.h"
    1.37 +#endif
    1.38 +
    1.39 +using namespace mozilla::widget;
    1.40 +using namespace mozilla;
    1.41 +using mozilla::MutexAutoLock;
    1.42 +
    1.43 +nsTArray<GfxDriverInfo>* GfxInfoBase::mDriverInfo;
    1.44 +bool GfxInfoBase::mDriverInfoObserverInitialized;
    1.45 +
    1.46 +// Observes for shutdown so that the child GfxDriverInfo list is freed.
    1.47 +class ShutdownObserver : public nsIObserver
    1.48 +{
    1.49 +public:
    1.50 +  ShutdownObserver() {}
    1.51 +  virtual ~ShutdownObserver() {}
    1.52 +
    1.53 +  NS_DECL_ISUPPORTS
    1.54 +
    1.55 +  NS_IMETHOD Observe(nsISupports *subject, const char *aTopic,
    1.56 +                     const char16_t *aData)
    1.57 +  {
    1.58 +    MOZ_ASSERT(strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0);
    1.59 +
    1.60 +    delete GfxInfoBase::mDriverInfo;
    1.61 +    GfxInfoBase::mDriverInfo = nullptr;
    1.62 +
    1.63 +    for (uint32_t i = 0; i < DeviceFamilyMax; i++)
    1.64 +      delete GfxDriverInfo::mDeviceFamilies[i];
    1.65 +
    1.66 +    for (uint32_t i = 0; i < DeviceVendorMax; i++)
    1.67 +      delete GfxDriverInfo::mDeviceVendors[i];
    1.68 +
    1.69 +    return NS_OK;
    1.70 +  }
    1.71 +};
    1.72 +
    1.73 +NS_IMPL_ISUPPORTS(ShutdownObserver, nsIObserver)
    1.74 +
    1.75 +void InitGfxDriverInfoShutdownObserver()
    1.76 +{
    1.77 +  if (GfxInfoBase::mDriverInfoObserverInitialized)
    1.78 +    return;
    1.79 +
    1.80 +  GfxInfoBase::mDriverInfoObserverInitialized = true;
    1.81 +
    1.82 +  nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
    1.83 +  if (!observerService) {
    1.84 +    NS_WARNING("Could not get observer service!");
    1.85 +    return;
    1.86 +  }
    1.87 +
    1.88 +  ShutdownObserver *obs = new ShutdownObserver();
    1.89 +  observerService->AddObserver(obs, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
    1.90 +}
    1.91 +
    1.92 +using namespace mozilla::widget;
    1.93 +using namespace mozilla;
    1.94 +
    1.95 +NS_IMPL_ISUPPORTS(GfxInfoBase, nsIGfxInfo, nsIObserver, nsISupportsWeakReference)
    1.96 +
    1.97 +#define BLACKLIST_PREF_BRANCH "gfx.blacklist."
    1.98 +#define SUGGESTED_VERSION_PREF BLACKLIST_PREF_BRANCH "suggested-driver-version"
    1.99 +#define BLACKLIST_ENTRY_TAG_NAME "gfxBlacklistEntry"
   1.100 +
   1.101 +static const char*
   1.102 +GetPrefNameForFeature(int32_t aFeature)
   1.103 +{
   1.104 +  const char* name = nullptr;
   1.105 +  switch(aFeature) {
   1.106 +    case nsIGfxInfo::FEATURE_DIRECT2D:
   1.107 +      name = BLACKLIST_PREF_BRANCH "direct2d";
   1.108 +      break;
   1.109 +    case nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS:
   1.110 +      name = BLACKLIST_PREF_BRANCH "layers.direct3d9";
   1.111 +      break;
   1.112 +    case nsIGfxInfo::FEATURE_DIRECT3D_10_LAYERS:
   1.113 +      name = BLACKLIST_PREF_BRANCH "layers.direct3d10";
   1.114 +      break;
   1.115 +    case nsIGfxInfo::FEATURE_DIRECT3D_10_1_LAYERS:
   1.116 +      name = BLACKLIST_PREF_BRANCH "layers.direct3d10-1";
   1.117 +      break;
   1.118 +    case nsIGfxInfo::FEATURE_OPENGL_LAYERS:
   1.119 +      name = BLACKLIST_PREF_BRANCH "layers.opengl";
   1.120 +      break;
   1.121 +    case nsIGfxInfo::FEATURE_WEBGL_OPENGL:
   1.122 +      name = BLACKLIST_PREF_BRANCH "webgl.opengl";
   1.123 +      break;
   1.124 +    case nsIGfxInfo::FEATURE_WEBGL_ANGLE:
   1.125 +      name = BLACKLIST_PREF_BRANCH "webgl.angle";
   1.126 +      break;
   1.127 +    case nsIGfxInfo::FEATURE_WEBGL_MSAA:
   1.128 +      name = BLACKLIST_PREF_BRANCH "webgl.msaa";
   1.129 +      break;
   1.130 +    case nsIGfxInfo::FEATURE_STAGEFRIGHT:
   1.131 +      name = BLACKLIST_PREF_BRANCH "stagefright";
   1.132 +      break;
   1.133 +    default:
   1.134 +      break;
   1.135 +  };
   1.136 +
   1.137 +  return name;
   1.138 +}
   1.139 +
   1.140 +// Returns the value of the pref for the relevant feature in aValue.
   1.141 +// If the pref doesn't exist, aValue is not touched, and returns false.
   1.142 +static bool
   1.143 +GetPrefValueForFeature(int32_t aFeature, int32_t& aValue)
   1.144 +{
   1.145 +  const char *prefname = GetPrefNameForFeature(aFeature);
   1.146 +  if (!prefname)
   1.147 +    return false;
   1.148 +
   1.149 +  aValue = false;
   1.150 +  return NS_SUCCEEDED(Preferences::GetInt(prefname, &aValue));
   1.151 +}
   1.152 +
   1.153 +static void
   1.154 +SetPrefValueForFeature(int32_t aFeature, int32_t aValue)
   1.155 +{
   1.156 +  const char *prefname = GetPrefNameForFeature(aFeature);
   1.157 +  if (!prefname)
   1.158 +    return;
   1.159 +
   1.160 +  Preferences::SetInt(prefname, aValue);
   1.161 +}
   1.162 +
   1.163 +static void
   1.164 +RemovePrefForFeature(int32_t aFeature)
   1.165 +{
   1.166 +  const char *prefname = GetPrefNameForFeature(aFeature);
   1.167 +  if (!prefname)
   1.168 +    return;
   1.169 +
   1.170 +  Preferences::ClearUser(prefname);
   1.171 +}
   1.172 +
   1.173 +static bool
   1.174 +GetPrefValueForDriverVersion(nsCString& aVersion)
   1.175 +{
   1.176 +  return NS_SUCCEEDED(Preferences::GetCString(SUGGESTED_VERSION_PREF,
   1.177 +                                              &aVersion));
   1.178 +}
   1.179 +
   1.180 +static void
   1.181 +SetPrefValueForDriverVersion(const nsAString& aVersion)
   1.182 +{
   1.183 +  Preferences::SetString(SUGGESTED_VERSION_PREF, aVersion);
   1.184 +}
   1.185 +
   1.186 +static void
   1.187 +RemovePrefForDriverVersion()
   1.188 +{
   1.189 +  Preferences::ClearUser(SUGGESTED_VERSION_PREF);
   1.190 +}
   1.191 +
   1.192 +// <foo>Hello</foo> - "Hello" is stored as a child text node of the foo node.
   1.193 +static bool
   1.194 +BlacklistNodeToTextValue(nsIDOMNode *aBlacklistNode, nsAString& aValue)
   1.195 +{
   1.196 +  nsAutoString value;
   1.197 +  if (NS_FAILED(aBlacklistNode->GetTextContent(value)))
   1.198 +    return false;
   1.199 +
   1.200 +  value.Trim(" \t\r\n");
   1.201 +  aValue = value;
   1.202 +
   1.203 +  return true;
   1.204 +}
   1.205 +
   1.206 +static OperatingSystem
   1.207 +BlacklistOSToOperatingSystem(const nsAString& os)
   1.208 +{
   1.209 +  if (os == NS_LITERAL_STRING("WINNT 5.1"))
   1.210 +    return DRIVER_OS_WINDOWS_XP;
   1.211 +  else if (os == NS_LITERAL_STRING("WINNT 5.2"))
   1.212 +    return DRIVER_OS_WINDOWS_SERVER_2003;
   1.213 +  else if (os == NS_LITERAL_STRING("WINNT 6.0"))
   1.214 +    return DRIVER_OS_WINDOWS_VISTA;
   1.215 +  else if (os == NS_LITERAL_STRING("WINNT 6.1"))
   1.216 +    return DRIVER_OS_WINDOWS_7;
   1.217 +  else if (os == NS_LITERAL_STRING("WINNT 6.2"))
   1.218 +    return DRIVER_OS_WINDOWS_8;
   1.219 +  else if (os == NS_LITERAL_STRING("WINNT 6.3"))
   1.220 +    return DRIVER_OS_WINDOWS_8_1;
   1.221 +  else if (os == NS_LITERAL_STRING("Linux"))
   1.222 +    return DRIVER_OS_LINUX;
   1.223 +  else if (os == NS_LITERAL_STRING("Darwin 9"))
   1.224 +    return DRIVER_OS_OS_X_10_5;
   1.225 +  else if (os == NS_LITERAL_STRING("Darwin 10"))
   1.226 +    return DRIVER_OS_OS_X_10_6;
   1.227 +  else if (os == NS_LITERAL_STRING("Darwin 11"))
   1.228 +    return DRIVER_OS_OS_X_10_7;
   1.229 +  else if (os == NS_LITERAL_STRING("Darwin 12"))
   1.230 +    return DRIVER_OS_OS_X_10_8;
   1.231 +  else if (os == NS_LITERAL_STRING("Android"))
   1.232 +    return DRIVER_OS_ANDROID;
   1.233 +  else if (os == NS_LITERAL_STRING("All"))
   1.234 +    return DRIVER_OS_ALL;
   1.235 +
   1.236 +  return DRIVER_OS_UNKNOWN;
   1.237 +}
   1.238 +
   1.239 +static GfxDeviceFamily*
   1.240 +BlacklistDevicesToDeviceFamily(nsIDOMHTMLCollection* aDevices)
   1.241 +{
   1.242 +  uint32_t length;
   1.243 +  if (NS_FAILED(aDevices->GetLength(&length)))
   1.244 +    return nullptr;
   1.245 +
   1.246 +  // For each <device>, get its device ID, and return a freshly-allocated
   1.247 +  // GfxDeviceFamily with the contents of that array.
   1.248 +  GfxDeviceFamily* deviceIds = new GfxDeviceFamily;
   1.249 +
   1.250 +  for (uint32_t i = 0; i < length; ++i) {
   1.251 +    nsCOMPtr<nsIDOMNode> node;
   1.252 +    if (NS_FAILED(aDevices->Item(i, getter_AddRefs(node))) || !node)
   1.253 +      continue;
   1.254 +
   1.255 +    nsAutoString deviceValue;
   1.256 +    if (!BlacklistNodeToTextValue(node, deviceValue))
   1.257 +      continue;
   1.258 +
   1.259 +    deviceIds->AppendElement(deviceValue);
   1.260 +  }
   1.261 +
   1.262 +  return deviceIds;
   1.263 +}
   1.264 +
   1.265 +static int32_t
   1.266 +BlacklistFeatureToGfxFeature(const nsAString& aFeature)
   1.267 +{
   1.268 +  if (aFeature == NS_LITERAL_STRING("DIRECT2D"))
   1.269 +    return nsIGfxInfo::FEATURE_DIRECT2D;
   1.270 +  else if (aFeature == NS_LITERAL_STRING("DIRECT3D_9_LAYERS"))
   1.271 +    return nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS;
   1.272 +  else if (aFeature == NS_LITERAL_STRING("DIRECT3D_10_LAYERS"))
   1.273 +    return nsIGfxInfo::FEATURE_DIRECT3D_10_LAYERS;
   1.274 +  else if (aFeature == NS_LITERAL_STRING("DIRECT3D_10_1_LAYERS"))
   1.275 +    return nsIGfxInfo::FEATURE_DIRECT3D_10_1_LAYERS;
   1.276 +  else if (aFeature == NS_LITERAL_STRING("OPENGL_LAYERS"))
   1.277 +    return nsIGfxInfo::FEATURE_OPENGL_LAYERS;
   1.278 +  else if (aFeature == NS_LITERAL_STRING("WEBGL_OPENGL"))
   1.279 +    return nsIGfxInfo::FEATURE_WEBGL_OPENGL;
   1.280 +  else if (aFeature == NS_LITERAL_STRING("WEBGL_ANGLE"))
   1.281 +    return nsIGfxInfo::FEATURE_WEBGL_ANGLE;
   1.282 +  else if (aFeature == NS_LITERAL_STRING("WEBGL_MSAA"))
   1.283 +    return nsIGfxInfo::FEATURE_WEBGL_MSAA;
   1.284 +  else if (aFeature == NS_LITERAL_STRING("STAGEFRIGHT"))
   1.285 +    return nsIGfxInfo::FEATURE_STAGEFRIGHT;
   1.286 +  return 0;
   1.287 +}
   1.288 +
   1.289 +static int32_t
   1.290 +BlacklistFeatureStatusToGfxFeatureStatus(const nsAString& aStatus)
   1.291 +{
   1.292 +  if (aStatus == NS_LITERAL_STRING("NO_INFO"))
   1.293 +    return nsIGfxInfo::FEATURE_NO_INFO;
   1.294 +  else if (aStatus == NS_LITERAL_STRING("BLOCKED_DRIVER_VERSION"))
   1.295 +    return nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION;
   1.296 +  else if (aStatus == NS_LITERAL_STRING("BLOCKED_DEVICE"))
   1.297 +    return nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
   1.298 +  else if (aStatus == NS_LITERAL_STRING("DISCOURAGED"))
   1.299 +    return nsIGfxInfo::FEATURE_DISCOURAGED;
   1.300 +  else if (aStatus == NS_LITERAL_STRING("BLOCKED_OS_VERSION"))
   1.301 +    return nsIGfxInfo::FEATURE_BLOCKED_OS_VERSION;
   1.302 +
   1.303 +  // Do not allow it to set STATUS_UNKNOWN.
   1.304 +
   1.305 +  return nsIGfxInfo::FEATURE_NO_INFO;
   1.306 +}
   1.307 +
   1.308 +static VersionComparisonOp
   1.309 +BlacklistComparatorToComparisonOp(const nsAString& op)
   1.310 +{
   1.311 +  if (op == NS_LITERAL_STRING("LESS_THAN"))
   1.312 +    return DRIVER_LESS_THAN;
   1.313 +  else if (op == NS_LITERAL_STRING("LESS_THAN_OR_EQUAL"))
   1.314 +    return DRIVER_LESS_THAN_OR_EQUAL;
   1.315 +  else if (op == NS_LITERAL_STRING("GREATER_THAN"))
   1.316 +    return DRIVER_GREATER_THAN;
   1.317 +  else if (op == NS_LITERAL_STRING("GREATER_THAN_OR_EQUAL"))
   1.318 +    return DRIVER_GREATER_THAN_OR_EQUAL;
   1.319 +  else if (op == NS_LITERAL_STRING("EQUAL"))
   1.320 +    return DRIVER_EQUAL;
   1.321 +  else if (op == NS_LITERAL_STRING("NOT_EQUAL"))
   1.322 +    return DRIVER_NOT_EQUAL;
   1.323 +  else if (op == NS_LITERAL_STRING("BETWEEN_EXCLUSIVE"))
   1.324 +    return DRIVER_BETWEEN_EXCLUSIVE;
   1.325 +  else if (op == NS_LITERAL_STRING("BETWEEN_INCLUSIVE"))
   1.326 +    return DRIVER_BETWEEN_INCLUSIVE;
   1.327 +  else if (op == NS_LITERAL_STRING("BETWEEN_INCLUSIVE_START"))
   1.328 +    return DRIVER_BETWEEN_INCLUSIVE_START;
   1.329 +
   1.330 +  return DRIVER_COMPARISON_IGNORED;
   1.331 +}
   1.332 +
   1.333 +// Arbitrarily returns the first |tagname| child of |element|.
   1.334 +static bool
   1.335 +BlacklistNodeGetChildByName(nsIDOMElement *element,
   1.336 +                            const nsAString& tagname,
   1.337 +                            nsIDOMNode** firstchild)
   1.338 +{
   1.339 +  nsCOMPtr<nsIDOMHTMLCollection> nodelist;
   1.340 +  if (NS_FAILED(element->GetElementsByTagName(tagname,
   1.341 +                                              getter_AddRefs(nodelist))) ||
   1.342 +      !nodelist) {
   1.343 +    return false;
   1.344 +  }
   1.345 +
   1.346 +  nsCOMPtr<nsIDOMNode> node;
   1.347 +  if (NS_FAILED(nodelist->Item(0, getter_AddRefs(node))) || !node)
   1.348 +    return false;
   1.349 +
   1.350 +  node.forget(firstchild);
   1.351 +  return true;
   1.352 +}
   1.353 +
   1.354 +/*
   1.355 +
   1.356 +<gfxBlacklistEntry>
   1.357 +  <os>WINNT 6.0</os>
   1.358 +  <vendor>0x8086</vendor>
   1.359 +  <devices>
   1.360 +    <device>0x2582</device>
   1.361 +    <device>0x2782</device>
   1.362 +  </devices>
   1.363 +  <feature> DIRECT3D_10_LAYERS </feature>
   1.364 +  <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
   1.365 +  <driverVersion> 8.52.322.2202 </driverVersion>
   1.366 +  <driverVersionComparator> LESS_THAN_OR_EQUAL </driverVersionComparator>
   1.367 +</gfxBlacklistEntry>
   1.368 +
   1.369 +*/
   1.370 +static bool
   1.371 +BlacklistEntryToDriverInfo(nsIDOMNode* aBlacklistEntry,
   1.372 +                           GfxDriverInfo& aDriverInfo)
   1.373 +{
   1.374 +  nsAutoString nodename;
   1.375 +  if (NS_FAILED(aBlacklistEntry->GetNodeName(nodename)) ||
   1.376 +      nodename != NS_LITERAL_STRING(BLACKLIST_ENTRY_TAG_NAME)) {
   1.377 +    return false;
   1.378 +  }
   1.379 +
   1.380 +  nsCOMPtr<nsIDOMElement> element = do_QueryInterface(aBlacklistEntry);
   1.381 +  if (!element)
   1.382 +    return false;
   1.383 +
   1.384 +  nsCOMPtr<nsIDOMNode> dataNode;
   1.385 +  nsAutoString dataValue;
   1.386 +
   1.387 +  // <os>WINNT 6.0</os>
   1.388 +  if (BlacklistNodeGetChildByName(element, NS_LITERAL_STRING("os"),
   1.389 +                                  getter_AddRefs(dataNode))) {
   1.390 +    BlacklistNodeToTextValue(dataNode, dataValue);
   1.391 +    aDriverInfo.mOperatingSystem = BlacklistOSToOperatingSystem(dataValue);
   1.392 +  }
   1.393 +
   1.394 +  // <osversion>14</osversion> currently only used for Android
   1.395 +  if (BlacklistNodeGetChildByName(element, NS_LITERAL_STRING("osversion"),
   1.396 +                                  getter_AddRefs(dataNode))) {
   1.397 +    BlacklistNodeToTextValue(dataNode, dataValue);
   1.398 +    aDriverInfo.mOperatingSystemVersion = strtoul(NS_LossyConvertUTF16toASCII(dataValue).get(),
   1.399 +                                                  nullptr, 10);
   1.400 +  }
   1.401 +
   1.402 +  // <vendor>0x8086</vendor>
   1.403 +  if (BlacklistNodeGetChildByName(element, NS_LITERAL_STRING("vendor"),
   1.404 +                                  getter_AddRefs(dataNode))) {
   1.405 +    BlacklistNodeToTextValue(dataNode, dataValue);
   1.406 +    aDriverInfo.mAdapterVendor = dataValue;
   1.407 +  }
   1.408 +
   1.409 +  // <devices>
   1.410 +  //   <device>0x2582</device>
   1.411 +  //   <device>0x2782</device>
   1.412 +  // </devices>
   1.413 +  if (BlacklistNodeGetChildByName(element, NS_LITERAL_STRING("devices"),
   1.414 +                                  getter_AddRefs(dataNode))) {
   1.415 +    nsCOMPtr<nsIDOMElement> devicesElement = do_QueryInterface(dataNode);
   1.416 +    if (devicesElement) {
   1.417 +
   1.418 +      // Get only the <device> nodes, because BlacklistDevicesToDeviceFamily
   1.419 +      // assumes it is passed no other nodes.
   1.420 +      nsCOMPtr<nsIDOMHTMLCollection> devices;
   1.421 +      if (NS_SUCCEEDED(devicesElement->GetElementsByTagName(NS_LITERAL_STRING("device"),
   1.422 +                                                            getter_AddRefs(devices)))) {
   1.423 +        GfxDeviceFamily* deviceIds = BlacklistDevicesToDeviceFamily(devices);
   1.424 +        if (deviceIds) {
   1.425 +          // Get GfxDriverInfo to adopt the devices array we created.
   1.426 +          aDriverInfo.mDeleteDevices = true;
   1.427 +          aDriverInfo.mDevices = deviceIds;
   1.428 +        }
   1.429 +      }
   1.430 +    }
   1.431 +  }
   1.432 +
   1.433 +  // <feature> DIRECT3D_10_LAYERS </feature>
   1.434 +  if (BlacklistNodeGetChildByName(element, NS_LITERAL_STRING("feature"),
   1.435 +                                  getter_AddRefs(dataNode))) {
   1.436 +    BlacklistNodeToTextValue(dataNode, dataValue);
   1.437 +    aDriverInfo.mFeature = BlacklistFeatureToGfxFeature(dataValue);
   1.438 +  }
   1.439 +
   1.440 +  // <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
   1.441 +  if (BlacklistNodeGetChildByName(element, NS_LITERAL_STRING("featureStatus"),
   1.442 +                                  getter_AddRefs(dataNode))) {
   1.443 +    BlacklistNodeToTextValue(dataNode, dataValue);
   1.444 +    aDriverInfo.mFeatureStatus = BlacklistFeatureStatusToGfxFeatureStatus(dataValue);
   1.445 +  }
   1.446 +
   1.447 +  // <driverVersion> 8.52.322.2202 </driverVersion>
   1.448 +  if (BlacklistNodeGetChildByName(element, NS_LITERAL_STRING("driverVersion"),
   1.449 +                                  getter_AddRefs(dataNode))) {
   1.450 +    BlacklistNodeToTextValue(dataNode, dataValue);
   1.451 +    uint64_t version;
   1.452 +    if (ParseDriverVersion(dataValue, &version))
   1.453 +      aDriverInfo.mDriverVersion = version;
   1.454 +  }
   1.455 +
   1.456 +  // <driverVersionComparator> LESS_THAN_OR_EQUAL </driverVersionComparator>
   1.457 +  if (BlacklistNodeGetChildByName(element, NS_LITERAL_STRING("driverVersionComparator"),
   1.458 +                                  getter_AddRefs(dataNode))) {
   1.459 +    BlacklistNodeToTextValue(dataNode, dataValue);
   1.460 +    aDriverInfo.mComparisonOp = BlacklistComparatorToComparisonOp(dataValue);
   1.461 +  }
   1.462 +
   1.463 +  // <model>foo</model>
   1.464 +  if (BlacklistNodeGetChildByName(element, NS_LITERAL_STRING("model"),
   1.465 +                                  getter_AddRefs(dataNode))) {
   1.466 +    BlacklistNodeToTextValue(dataNode, dataValue);
   1.467 +    aDriverInfo.mModel = dataValue;
   1.468 +  }
   1.469 +  // <product>foo</product>
   1.470 +  if (BlacklistNodeGetChildByName(element, NS_LITERAL_STRING("product"),
   1.471 +                                  getter_AddRefs(dataNode))) {
   1.472 +    BlacklistNodeToTextValue(dataNode, dataValue);
   1.473 +    aDriverInfo.mProduct = dataValue;
   1.474 +  }
   1.475 +  // <manufacturer>foo</manufacturer>
   1.476 +  if (BlacklistNodeGetChildByName(element, NS_LITERAL_STRING("manufacturer"),
   1.477 +                                  getter_AddRefs(dataNode))) {
   1.478 +    BlacklistNodeToTextValue(dataNode, dataValue);
   1.479 +    aDriverInfo.mManufacturer = dataValue;
   1.480 +  }
   1.481 +  // <hardware>foo</hardware>
   1.482 +  if (BlacklistNodeGetChildByName(element, NS_LITERAL_STRING("hardware"),
   1.483 +                                  getter_AddRefs(dataNode))) {
   1.484 +    BlacklistNodeToTextValue(dataNode, dataValue);
   1.485 +    aDriverInfo.mHardware = dataValue;
   1.486 +  }
   1.487 +
   1.488 +  // We explicitly ignore unknown elements.
   1.489 +
   1.490 +  return true;
   1.491 +}
   1.492 +
   1.493 +static void
   1.494 +BlacklistEntriesToDriverInfo(nsIDOMHTMLCollection* aBlacklistEntries,
   1.495 +                             nsTArray<GfxDriverInfo>& aDriverInfo)
   1.496 +{
   1.497 +  uint32_t length;
   1.498 +  if (NS_FAILED(aBlacklistEntries->GetLength(&length)))
   1.499 +    return;
   1.500 +
   1.501 +  aDriverInfo.Clear();
   1.502 +  aDriverInfo.SetLength(length);
   1.503 +  for (uint32_t i = 0; i < length; ++i) {
   1.504 +    nsCOMPtr<nsIDOMNode> blacklistEntry;
   1.505 +    if (NS_SUCCEEDED(aBlacklistEntries->Item(i,
   1.506 +                                             getter_AddRefs(blacklistEntry))) &&
   1.507 +        blacklistEntry) {
   1.508 +      GfxDriverInfo di;
   1.509 +      if (BlacklistEntryToDriverInfo(blacklistEntry, di)) {
   1.510 +        aDriverInfo[i] = di;
   1.511 +      }
   1.512 +      // Prevent di falling out of scope from destroying the devices.
   1.513 +      di.mDeleteDevices = false;
   1.514 +    }
   1.515 +  }
   1.516 +}
   1.517 +
   1.518 +NS_IMETHODIMP
   1.519 +GfxInfoBase::Observe(nsISupports* aSubject, const char* aTopic,
   1.520 +                     const char16_t* aData)
   1.521 +{
   1.522 +  if (strcmp(aTopic, "blocklist-data-gfxItems") == 0) {
   1.523 +    nsCOMPtr<nsIDOMElement> gfxItems = do_QueryInterface(aSubject);
   1.524 +    if (gfxItems) {
   1.525 +      nsCOMPtr<nsIDOMHTMLCollection> blacklistEntries;
   1.526 +      if (NS_SUCCEEDED(gfxItems->
   1.527 +            GetElementsByTagName(NS_LITERAL_STRING(BLACKLIST_ENTRY_TAG_NAME),
   1.528 +                                 getter_AddRefs(blacklistEntries))) &&
   1.529 +          blacklistEntries)
   1.530 +      {
   1.531 +        nsTArray<GfxDriverInfo> driverInfo;
   1.532 +        BlacklistEntriesToDriverInfo(blacklistEntries, driverInfo);
   1.533 +        EvaluateDownloadedBlacklist(driverInfo);
   1.534 +      }
   1.535 +    }
   1.536 +  }
   1.537 +
   1.538 +  return NS_OK;
   1.539 +}
   1.540 +
   1.541 +GfxInfoBase::GfxInfoBase()
   1.542 +    : mFailureCount(0)
   1.543 +    , mMutex("GfxInfoBase")
   1.544 +{
   1.545 +}
   1.546 +
   1.547 +GfxInfoBase::~GfxInfoBase()
   1.548 +{
   1.549 +}
   1.550 +
   1.551 +nsresult
   1.552 +GfxInfoBase::Init()
   1.553 +{
   1.554 +  InitGfxDriverInfoShutdownObserver();
   1.555 +
   1.556 +  nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
   1.557 +  if (os) {
   1.558 +    os->AddObserver(this, "blocklist-data-gfxItems", true);
   1.559 +  }
   1.560 +
   1.561 +  return NS_OK;
   1.562 +}
   1.563 +
   1.564 +NS_IMETHODIMP
   1.565 +GfxInfoBase::GetFeatureStatus(int32_t aFeature, int32_t* aStatus)
   1.566 +{
   1.567 +  if (GetPrefValueForFeature(aFeature, *aStatus))
   1.568 +    return NS_OK;
   1.569 +
   1.570 +  if (XRE_GetProcessType() == GeckoProcessType_Content) {
   1.571 +      // Delegate to the parent process.
   1.572 +      mozilla::dom::ContentChild* cc = mozilla::dom::ContentChild::GetSingleton();
   1.573 +      bool success;
   1.574 +      cc->SendGetGraphicsFeatureStatus(aFeature, aStatus, &success);
   1.575 +      return success ? NS_OK : NS_ERROR_FAILURE;
   1.576 +  }
   1.577 +
   1.578 +  nsString version;
   1.579 +  nsTArray<GfxDriverInfo> driverInfo;
   1.580 +  return GetFeatureStatusImpl(aFeature, aStatus, version, driverInfo);
   1.581 +}
   1.582 +
   1.583 +int32_t
   1.584 +GfxInfoBase::FindBlocklistedDeviceInList(const nsTArray<GfxDriverInfo>& info,
   1.585 +                                         nsAString& aSuggestedVersion,
   1.586 +                                         int32_t aFeature,
   1.587 +                                         OperatingSystem os)
   1.588 +{
   1.589 +  int32_t status = nsIGfxInfo::FEATURE_STATUS_UNKNOWN;
   1.590 +
   1.591 +  nsAutoString adapterVendorID;
   1.592 +  nsAutoString adapterDeviceID;
   1.593 +  nsAutoString adapterDriverVersionString;
   1.594 +  if (NS_FAILED(GetAdapterVendorID(adapterVendorID)) ||
   1.595 +      NS_FAILED(GetAdapterDeviceID(adapterDeviceID)) ||
   1.596 +      NS_FAILED(GetAdapterDriverVersion(adapterDriverVersionString)))
   1.597 +  {
   1.598 +    return 0;
   1.599 +  }
   1.600 +
   1.601 +#if defined(XP_WIN) || defined(ANDROID)
   1.602 +  uint64_t driverVersion;
   1.603 +  ParseDriverVersion(adapterDriverVersionString, &driverVersion);
   1.604 +#endif
   1.605 +
   1.606 +  uint32_t i = 0;
   1.607 +  for (; i < info.Length(); i++) {
   1.608 +    if (info[i].mOperatingSystem != DRIVER_OS_ALL &&
   1.609 +        info[i].mOperatingSystem != os)
   1.610 +    {
   1.611 +      continue;
   1.612 +    }
   1.613 +
   1.614 +    if (info[i].mOperatingSystemVersion && info[i].mOperatingSystemVersion != OperatingSystemVersion()) {
   1.615 +        continue;
   1.616 +    }
   1.617 +
   1.618 +    if (!info[i].mAdapterVendor.Equals(GfxDriverInfo::GetDeviceVendor(VendorAll), nsCaseInsensitiveStringComparator()) &&
   1.619 +        !info[i].mAdapterVendor.Equals(adapterVendorID, nsCaseInsensitiveStringComparator())) {
   1.620 +      continue;
   1.621 +    }
   1.622 +
   1.623 +    if (info[i].mDevices != GfxDriverInfo::allDevices && info[i].mDevices->Length()) {
   1.624 +        bool deviceMatches = false;
   1.625 +        for (uint32_t j = 0; j < info[i].mDevices->Length(); j++) {
   1.626 +            if ((*info[i].mDevices)[j].Equals(adapterDeviceID, nsCaseInsensitiveStringComparator())) {
   1.627 +                deviceMatches = true;
   1.628 +                break;
   1.629 +            }
   1.630 +        }
   1.631 +
   1.632 +        if (!deviceMatches) {
   1.633 +            continue;
   1.634 +        }
   1.635 +    }
   1.636 +
   1.637 +    bool match = false;
   1.638 +
   1.639 +    if (!info[i].mHardware.IsEmpty() && !info[i].mHardware.Equals(Hardware())) {
   1.640 +        continue;
   1.641 +    }
   1.642 +    if (!info[i].mModel.IsEmpty() && !info[i].mModel.Equals(Model())) {
   1.643 +        continue;
   1.644 +    }
   1.645 +    if (!info[i].mProduct.IsEmpty() && !info[i].mProduct.Equals(Product())) {
   1.646 +        continue;
   1.647 +    }
   1.648 +    if (!info[i].mManufacturer.IsEmpty() && !info[i].mManufacturer.Equals(Manufacturer())) {
   1.649 +        continue;
   1.650 +    }
   1.651 +
   1.652 +#if defined(XP_WIN) || defined(ANDROID)
   1.653 +    switch (info[i].mComparisonOp) {
   1.654 +    case DRIVER_LESS_THAN:
   1.655 +      match = driverVersion < info[i].mDriverVersion;
   1.656 +      break;
   1.657 +    case DRIVER_LESS_THAN_OR_EQUAL:
   1.658 +      match = driverVersion <= info[i].mDriverVersion;
   1.659 +      break;
   1.660 +    case DRIVER_GREATER_THAN:
   1.661 +      match = driverVersion > info[i].mDriverVersion;
   1.662 +      break;
   1.663 +    case DRIVER_GREATER_THAN_OR_EQUAL:
   1.664 +      match = driverVersion >= info[i].mDriverVersion;
   1.665 +      break;
   1.666 +    case DRIVER_EQUAL:
   1.667 +      match = driverVersion == info[i].mDriverVersion;
   1.668 +      break;
   1.669 +    case DRIVER_NOT_EQUAL:
   1.670 +      match = driverVersion != info[i].mDriverVersion;
   1.671 +      break;
   1.672 +    case DRIVER_BETWEEN_EXCLUSIVE:
   1.673 +      match = driverVersion > info[i].mDriverVersion && driverVersion < info[i].mDriverVersionMax;
   1.674 +      break;
   1.675 +    case DRIVER_BETWEEN_INCLUSIVE:
   1.676 +      match = driverVersion >= info[i].mDriverVersion && driverVersion <= info[i].mDriverVersionMax;
   1.677 +      break;
   1.678 +    case DRIVER_BETWEEN_INCLUSIVE_START:
   1.679 +      match = driverVersion >= info[i].mDriverVersion && driverVersion < info[i].mDriverVersionMax;
   1.680 +      break;
   1.681 +    case DRIVER_COMPARISON_IGNORED:
   1.682 +      // We don't have a comparison op, so we match everything.
   1.683 +      match = true;
   1.684 +      break;
   1.685 +    default:
   1.686 +      NS_WARNING("Bogus op in GfxDriverInfo");
   1.687 +      break;
   1.688 +    }
   1.689 +#else
   1.690 +    // We don't care what driver version it was. We only check OS version and if
   1.691 +    // the device matches.
   1.692 +    match = true;
   1.693 +#endif
   1.694 +
   1.695 +    if (match || info[i].mDriverVersion == GfxDriverInfo::allDriverVersions) {
   1.696 +      if (info[i].mFeature == GfxDriverInfo::allFeatures ||
   1.697 +          info[i].mFeature == aFeature)
   1.698 +      {
   1.699 +        status = info[i].mFeatureStatus;
   1.700 +        break;
   1.701 +      }
   1.702 +    }
   1.703 +  }
   1.704 +
   1.705 +  // Depends on Windows driver versioning. We don't pass a GfxDriverInfo object
   1.706 +  // back to the Windows handler, so we must handle this here.
   1.707 +#if defined(XP_WIN)
   1.708 +  if (status == FEATURE_BLOCKED_DRIVER_VERSION) {
   1.709 +    if (info[i].mSuggestedVersion) {
   1.710 +        aSuggestedVersion.AppendPrintf("%s", info[i].mSuggestedVersion);
   1.711 +    } else if (info[i].mComparisonOp == DRIVER_LESS_THAN &&
   1.712 +               info[i].mDriverVersion != GfxDriverInfo::allDriverVersions)
   1.713 +    {
   1.714 +        aSuggestedVersion.AppendPrintf("%lld.%lld.%lld.%lld",
   1.715 +                                      (info[i].mDriverVersion & 0xffff000000000000) >> 48,
   1.716 +                                      (info[i].mDriverVersion & 0x0000ffff00000000) >> 32,
   1.717 +                                      (info[i].mDriverVersion & 0x00000000ffff0000) >> 16,
   1.718 +                                      (info[i].mDriverVersion & 0x000000000000ffff));
   1.719 +    }
   1.720 +  }
   1.721 +#endif
   1.722 +
   1.723 +  return status;
   1.724 +}
   1.725 +
   1.726 +nsresult
   1.727 +GfxInfoBase::GetFeatureStatusImpl(int32_t aFeature,
   1.728 +                                  int32_t* aStatus,
   1.729 +                                  nsAString& aSuggestedVersion,
   1.730 +                                  const nsTArray<GfxDriverInfo>& aDriverInfo,
   1.731 +                                  OperatingSystem* aOS /* = nullptr */)
   1.732 +{
   1.733 +  if (*aStatus != nsIGfxInfo::FEATURE_STATUS_UNKNOWN) {
   1.734 +    // Terminate now with the status determined by the derived type (OS-specific
   1.735 +    // code).
   1.736 +    return NS_OK;
   1.737 +  }
   1.738 +
   1.739 +  // If an operating system was provided by the derived GetFeatureStatusImpl,
   1.740 +  // grab it here. Otherwise, the OS is unknown.
   1.741 +  OperatingSystem os = DRIVER_OS_UNKNOWN;
   1.742 +  if (aOS)
   1.743 +    os = *aOS;
   1.744 +
   1.745 +  nsAutoString adapterVendorID;
   1.746 +  nsAutoString adapterDeviceID;
   1.747 +  nsAutoString adapterDriverVersionString;
   1.748 +  if (NS_FAILED(GetAdapterVendorID(adapterVendorID)) ||
   1.749 +      NS_FAILED(GetAdapterDeviceID(adapterDeviceID)) ||
   1.750 +      NS_FAILED(GetAdapterDriverVersion(adapterDriverVersionString)))
   1.751 +  {
   1.752 +    return NS_OK;
   1.753 +  }
   1.754 +
   1.755 +  // Check if the device is blocked from the downloaded blocklist. If not, check
   1.756 +  // the static list after that. This order is used so that we can later escape
   1.757 +  // out of static blocks (i.e. if we were wrong or something was patched, we
   1.758 +  // can back out our static block without doing a release).
   1.759 +  int32_t status;
   1.760 +  if (aDriverInfo.Length()) {
   1.761 +    status = FindBlocklistedDeviceInList(aDriverInfo, aSuggestedVersion, aFeature, os);
   1.762 +  } else {
   1.763 +    if (!mDriverInfo) {
   1.764 +      mDriverInfo = new nsTArray<GfxDriverInfo>();
   1.765 +    }
   1.766 +    status = FindBlocklistedDeviceInList(GetGfxDriverInfo(), aSuggestedVersion, aFeature, os);
   1.767 +  }
   1.768 +
   1.769 +  // It's now done being processed. It's safe to set the status to NO_INFO.
   1.770 +  if (status == nsIGfxInfo::FEATURE_STATUS_UNKNOWN) {
   1.771 +    *aStatus = nsIGfxInfo::FEATURE_NO_INFO;
   1.772 +  } else {
   1.773 +    *aStatus = status;
   1.774 +  }
   1.775 +
   1.776 +  return NS_OK;
   1.777 +}
   1.778 +
   1.779 +NS_IMETHODIMP
   1.780 +GfxInfoBase::GetFeatureSuggestedDriverVersion(int32_t aFeature,
   1.781 +                                              nsAString& aVersion)
   1.782 +{
   1.783 +  nsCString version;
   1.784 +  if (GetPrefValueForDriverVersion(version)) {
   1.785 +    aVersion = NS_ConvertASCIItoUTF16(version);
   1.786 +    return NS_OK;
   1.787 +  }
   1.788 +
   1.789 +  int32_t status;
   1.790 +  nsTArray<GfxDriverInfo> driverInfo;
   1.791 +  return GetFeatureStatusImpl(aFeature, &status, aVersion, driverInfo);
   1.792 +}
   1.793 +
   1.794 +
   1.795 +NS_IMETHODIMP
   1.796 +GfxInfoBase::GetWebGLParameter(const nsAString& aParam,
   1.797 +                               nsAString& aResult)
   1.798 +{
   1.799 +  return GfxInfoWebGL::GetWebGLParameter(aParam, aResult);
   1.800 +}
   1.801 +
   1.802 +void
   1.803 +GfxInfoBase::EvaluateDownloadedBlacklist(nsTArray<GfxDriverInfo>& aDriverInfo)
   1.804 +{
   1.805 +  int32_t features[] = {
   1.806 +    nsIGfxInfo::FEATURE_DIRECT2D,
   1.807 +    nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS,
   1.808 +    nsIGfxInfo::FEATURE_DIRECT3D_10_LAYERS,
   1.809 +    nsIGfxInfo::FEATURE_DIRECT3D_10_1_LAYERS,
   1.810 +    nsIGfxInfo::FEATURE_OPENGL_LAYERS,
   1.811 +    nsIGfxInfo::FEATURE_WEBGL_OPENGL,
   1.812 +    nsIGfxInfo::FEATURE_WEBGL_ANGLE,
   1.813 +    nsIGfxInfo::FEATURE_WEBGL_MSAA,
   1.814 +    nsIGfxInfo::FEATURE_STAGEFRIGHT,
   1.815 +    0
   1.816 +  };
   1.817 +
   1.818 +  // For every feature we know about, we evaluate whether this blacklist has a
   1.819 +  // non-NO_INFO status. If it does, we set the pref we evaluate in
   1.820 +  // GetFeatureStatus above, so we don't need to hold on to this blacklist
   1.821 +  // anywhere permanent.
   1.822 +  int i = 0;
   1.823 +  while (features[i]) {
   1.824 +    int32_t status;
   1.825 +    nsAutoString suggestedVersion;
   1.826 +    if (NS_SUCCEEDED(GetFeatureStatusImpl(features[i], &status,
   1.827 +                                          suggestedVersion,
   1.828 +                                          aDriverInfo))) {
   1.829 +      switch (status) {
   1.830 +        default:
   1.831 +        case nsIGfxInfo::FEATURE_NO_INFO:
   1.832 +          RemovePrefForFeature(features[i]);
   1.833 +          break;
   1.834 +
   1.835 +        case nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION:
   1.836 +          if (!suggestedVersion.IsEmpty()) {
   1.837 +            SetPrefValueForDriverVersion(suggestedVersion);
   1.838 +          } else {
   1.839 +            RemovePrefForDriverVersion();
   1.840 +          }
   1.841 +          // FALLTHROUGH
   1.842 +
   1.843 +        case nsIGfxInfo::FEATURE_BLOCKED_DEVICE:
   1.844 +        case nsIGfxInfo::FEATURE_DISCOURAGED:
   1.845 +        case nsIGfxInfo::FEATURE_BLOCKED_OS_VERSION:
   1.846 +          SetPrefValueForFeature(features[i], status);
   1.847 +          break;
   1.848 +      }
   1.849 +    }
   1.850 +
   1.851 +    ++i;
   1.852 +  }
   1.853 +}
   1.854 +
   1.855 +NS_IMETHODIMP_(void)
   1.856 +GfxInfoBase::LogFailure(const nsACString &failure)
   1.857 +{
   1.858 +  MutexAutoLock lock(mMutex);
   1.859 +  /* We only keep the first 9 failures */
   1.860 +  if (mFailureCount < ArrayLength(mFailures)) {
   1.861 +    mFailures[mFailureCount++] = failure;
   1.862 +
   1.863 +    /* record it in the crash notes too */
   1.864 +    #if defined(MOZ_CRASHREPORTER)
   1.865 +      CrashReporter::AppendAppNotesToCrashReport(failure);
   1.866 +    #endif
   1.867 +  }
   1.868 +
   1.869 +}
   1.870 +
   1.871 +/* void getFailures ([optional] out unsigned long failureCount, [array, size_is (failureCount), retval] out string failures); */
   1.872 +/* XPConnect method of returning arrays is very ugly. Would not recommend. Fallable nsMemory::Alloc makes things worse */
   1.873 +NS_IMETHODIMP GfxInfoBase::GetFailures(uint32_t *failureCount, char ***failures)
   1.874 +{
   1.875 +
   1.876 +  NS_ENSURE_ARG_POINTER(failureCount);
   1.877 +  NS_ENSURE_ARG_POINTER(failures);
   1.878 +
   1.879 +  *failures = nullptr;
   1.880 +  *failureCount = mFailureCount;
   1.881 +
   1.882 +  if (*failureCount != 0) {
   1.883 +    *failures = (char**)nsMemory::Alloc(*failureCount * sizeof(char*));
   1.884 +    if (!failures)
   1.885 +      return NS_ERROR_OUT_OF_MEMORY;
   1.886 +
   1.887 +    /* copy over the failure messages into the array we just allocated */
   1.888 +    for (uint32_t i = 0; i < *failureCount; i++) {
   1.889 +      nsCString& flattenedFailureMessage(mFailures[i]);
   1.890 +      (*failures)[i] = (char*)nsMemory::Clone(flattenedFailureMessage.get(), flattenedFailureMessage.Length() + 1);
   1.891 +
   1.892 +      if (!(*failures)[i]) {
   1.893 +        /* <sarcasm> I'm too afraid to use an inline function... </sarcasm> */
   1.894 +        NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(i, (*failures));
   1.895 +        return NS_ERROR_OUT_OF_MEMORY;
   1.896 +      }
   1.897 +    }
   1.898 +  }
   1.899 +
   1.900 +  return NS_OK;
   1.901 +}
   1.902 +
   1.903 +nsTArray<GfxInfoCollectorBase*> *sCollectors;
   1.904 +
   1.905 +static void
   1.906 +InitCollectors()
   1.907 +{
   1.908 +  if (!sCollectors)
   1.909 +    sCollectors = new nsTArray<GfxInfoCollectorBase*>;
   1.910 +}
   1.911 +
   1.912 +nsresult GfxInfoBase::GetInfo(JSContext* aCx, JS::MutableHandle<JS::Value> aResult)
   1.913 +{
   1.914 +  InitCollectors();
   1.915 +  InfoObject obj(aCx);
   1.916 +
   1.917 +  for (uint32_t i = 0; i < sCollectors->Length(); i++) {
   1.918 +    (*sCollectors)[i]->GetInfo(obj);
   1.919 +  }
   1.920 +
   1.921 +  // Some example property definitions
   1.922 +  // obj.DefineProperty("wordCacheSize", gfxTextRunWordCache::Count());
   1.923 +  // obj.DefineProperty("renderer", mRendererIDsString);
   1.924 +  // obj.DefineProperty("five", 5);
   1.925 +
   1.926 +  if (!obj.mOk) {
   1.927 +    return NS_ERROR_FAILURE;
   1.928 +  }
   1.929 +
   1.930 +  aResult.setObject(*obj.mObj);
   1.931 +  return NS_OK;
   1.932 +}
   1.933 +
   1.934 +void
   1.935 +GfxInfoBase::AddCollector(GfxInfoCollectorBase* collector)
   1.936 +{
   1.937 +  InitCollectors();
   1.938 +  sCollectors->AppendElement(collector);
   1.939 +}
   1.940 +
   1.941 +void
   1.942 +GfxInfoBase::RemoveCollector(GfxInfoCollectorBase* collector)
   1.943 +{
   1.944 +  InitCollectors();
   1.945 +  for (uint32_t i = 0; i < sCollectors->Length(); i++) {
   1.946 +    if ((*sCollectors)[i] == collector) {
   1.947 +      sCollectors->RemoveElementAt(i);
   1.948 +      break;
   1.949 +    }
   1.950 +  }
   1.951 +  if (sCollectors->IsEmpty()) {
   1.952 +    delete sCollectors;
   1.953 +    sCollectors = nullptr;
   1.954 +  }
   1.955 +}
   1.956 +
   1.957 +GfxInfoCollectorBase::GfxInfoCollectorBase()
   1.958 +{
   1.959 +  GfxInfoBase::AddCollector(this);
   1.960 +}
   1.961 +
   1.962 +GfxInfoCollectorBase::~GfxInfoCollectorBase()
   1.963 +{
   1.964 +  GfxInfoBase::RemoveCollector(this);
   1.965 +}

mercurial