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 +}