imported patch rollup.patch
authorDavid Anderson <danderson@mozilla.com>
Wed, 17 Jun 2015 02:06:56 -0700
changeset 490140 2554aef83341dce2c729a4abd3fa637338f65a2e
parent 489746 d7c148c84594df61eda3ac5d22ec6c533fd5cf3d
child 490141 8a14e6366493e683928b531f948dae6992810016
push id74748
push userdanderson@mozilla.com
push dateWed, 17 Jun 2015 09:07:10 +0000
treeherdertry@8a14e6366493 [default view] [failures only]
milestone41.0a1
imported patch rollup.patch
toolkit/components/telemetry/TelemetryEnvironment.jsm
toolkit/components/telemetry/docs/environment.rst
toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment.js
widget/GfxInfoBase.cpp
widget/GfxInfoBase.h
widget/GfxInfoX11.cpp
widget/GfxInfoX11.h
widget/cocoa/GfxInfo.h
widget/cocoa/GfxInfo.mm
widget/nsIGfxInfo.idl
widget/windows/GfxInfo.cpp
widget/windows/GfxInfo.h
--- a/toolkit/components/telemetry/TelemetryEnvironment.jsm
+++ b/toolkit/components/telemetry/TelemetryEnvironment.jsm
@@ -1122,18 +1122,28 @@ EnvironmentCache.prototype = {
   _getGFXData: function () {
     let gfxData = {
       D2DEnabled: getGfxField("D2DEnabled", null),
       DWriteEnabled: getGfxField("DWriteEnabled", null),
       // The following line is disabled due to main thread jank and will be enabled
       // again as part of bug 1154500.
       //DWriteVersion: getGfxField("DWriteVersion", null),
       adapters: [],
+      monitors: [],
     };
 
+#if !defined(MOZ_WIDGET_GONK) && !defined(MOZ_WIDGET_ANDROID)
+    let gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo);
+    try {
+      gfxData.monitors = gfxInfo.getMonitors();
+    } catch (e) {
+      this._log.error("nsIGfxInfo.getMonitors() caught error", e);
+    }
+#endif
+
     // GfxInfo does not yet expose a way to iterate through all the adapters.
     gfxData.adapters.push(getGfxAdapter(""));
     gfxData.adapters[0].GPUActive = true;
 
     // If we have a second adapter add it to the gfxData.adapters section.
     let hasGPU2 = getGfxField("adapterDeviceID2", null) !== null;
     if (!hasGPU2) {
       this._log.trace("_getGFXData - Only one display adapter detected.");
--- a/toolkit/components/telemetry/docs/environment.rst
+++ b/toolkit/components/telemetry/docs/environment.rst
@@ -128,16 +128,28 @@ Structure::
                 RAM: <number>, // in MB, null on failure
                 driver: <string>, // null on failure
                 driverVersion: <string>, // null on failure
                 driverDate: <string>, // null on failure
                 GPUActive: <bool>, // currently always true for the first adapter
               },
               ...
             ],
+            // Note: currently only added on Desktop. On Linux, only a single
+            // monitor is returned representing the entire virtual screen.
+            monitors: [
+              {
+                screenWidth: <number>,  // screen width in pixels
+                screenHeight: <number>, // screen height in pixels
+                refreshRate: <number>,  // refresh rate in hertz (present on Windows only)
+                pseudoDisplay: <bool>,  // networked screen (present on Windows only)
+                scale: <number>,        // backing scale factor (present on Mac only)
+              },
+              ...
+            ],
           },
       },
       addons: {
         activeAddons: { // the currently enabled addons
           <addon id>: {
             blocklisted: <bool>,
             description: <string>, // null if not available
             name: <string>,
--- a/toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment.js
+++ b/toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment.js
@@ -411,16 +411,30 @@ function checkSystemSection(data) {
   Assert.ok("adapters" in gfxData);
   Assert.ok(gfxData.adapters.length > 0, "There must be at least one GFX adapter.");
   for (let adapter of gfxData.adapters) {
     checkGfxAdapter(adapter);
   }
   Assert.equal(typeof gfxData.adapters[0].GPUActive, "boolean");
   Assert.ok(gfxData.adapters[0].GPUActive, "The first GFX adapter must be active.");
 
+  Assert.ok(Array.isArray(gfxData.monitors));
+  if (gIsWindows || gIsMac) {
+    Assert.ok(gfxData.monitors.length >= 1, "There is at least one monitor.");
+    Assert.equal(typeof gfxData.monitors[0].screenWidth, "number");
+    Assert.equal(typeof gfxData.monitors[0].screenHeight, "number");
+    if (gIsWindows) {
+      Assert.equal(typeof gfxData.monitors[0].refreshRate, "number");
+      Assert.equal(typeof gfxData.monitors[0].pseudoDisplay, "boolean");
+    }
+    if (gIsMac) {
+      Assert.equal(typeof gfxData.monitors[0].scale, "number");
+    }
+  }
+
   try {
     // If we've not got nsIGfxInfoDebug, then this will throw and stop us doing
     // this test.
     let gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfoDebug);
 
     if (gIsWindows || gIsMac) {
       Assert.equal(GFX_VENDOR_ID, gfxData.adapters[0].vendorID);
       Assert.equal(GFX_DEVICE_ID, gfxData.adapters[0].deviceID);
--- a/widget/GfxInfoBase.cpp
+++ b/widget/GfxInfoBase.cpp
@@ -1157,16 +1157,30 @@ GfxInfoBase::RemoveCollector(GfxInfoColl
     }
   }
   if (sCollectors->IsEmpty()) {
     delete sCollectors;
     sCollectors = nullptr;
   }
 }
 
+NS_IMETHODIMP
+GfxInfoBase::GetMonitors(JSContext* aCx, JS::MutableHandleValue aResult)
+{
+  JS::Rooted<JSObject*> array(aCx, JS_NewArrayObject(aCx, 0));
+
+  nsresult rv = FindMonitors(aCx, array);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  aResult.setObject(*array);
+  return NS_OK;
+}
+
 GfxInfoCollectorBase::GfxInfoCollectorBase()
 {
   GfxInfoBase::AddCollector(this);
 }
 
 GfxInfoCollectorBase::~GfxInfoCollectorBase()
 {
   GfxInfoBase::RemoveCollector(this);
--- a/widget/GfxInfoBase.h
+++ b/widget/GfxInfoBase.h
@@ -49,17 +49,18 @@ public:
   // using GfxInfoBase::GetFeatureStatus;
   // using GfxInfoBase::GetFeatureSuggestedDriverVersion;
   // using GfxInfoBase::GetWebGLParameter;
   // to import the relevant methods into their namespace.
   NS_IMETHOD GetFeatureStatus(int32_t aFeature, int32_t *_retval) override;
   NS_IMETHOD GetFeatureSuggestedDriverVersion(int32_t aFeature, nsAString & _retval) override;
   NS_IMETHOD GetWebGLParameter(const nsAString & aParam, nsAString & _retval) override;
 
-    NS_IMETHOD GetFailures(uint32_t *failureCount, int32_t** indices, char ***failures) override;
+  NS_IMETHOD GetMonitors(JSContext* cx, JS::MutableHandleValue _retval);
+  NS_IMETHOD GetFailures(uint32_t *failureCount, int32_t** indices, char ***failures) override;
   NS_IMETHOD_(void) LogFailure(const nsACString &failure) override;
   NS_IMETHOD GetInfo(JSContext*, JS::MutableHandle<JS::Value>) override;
 
   // Initialization function. If you override this, you must call this class's
   // version of Init first.
   // We need Init to be called separately from the constructor so we can
   // register as an observer after all derived classes have been constructed
   // and we know we have a non-zero refcount.
@@ -80,16 +81,20 @@ public:
   virtual nsString Hardware() { return EmptyString(); }
   virtual nsString Product() { return EmptyString(); }
   virtual nsString Manufacturer() { return EmptyString(); }
   virtual uint32_t OperatingSystemVersion() { return 0; }
 
   // Convenience to get the application version
   static const nsCString& GetApplicationVersion();
 
+  virtual nsresult FindMonitors(JSContext* cx, JS::HandleObject array) {
+    return NS_ERROR_NOT_IMPLEMENTED;
+  }
+
 protected:
 
   virtual ~GfxInfoBase();
 
   virtual nsresult GetFeatureStatusImpl(int32_t aFeature, int32_t* aStatus,
                                         nsAString& aSuggestedDriverVersion,
                                         const nsTArray<GfxDriverInfo>& aDriverInfo,
                                         OperatingSystem* aOS = nullptr);
--- a/widget/GfxInfoX11.cpp
+++ b/widget/GfxInfoX11.cpp
@@ -9,16 +9,17 @@
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <errno.h>
 #include <sys/utsname.h>
 #include "nsCRTGlue.h"
 #include "prenv.h"
 
 #include "GfxInfoX11.h"
+#include "mozilla/X11Util.h"
 
 #ifdef MOZ_CRASHREPORTER
 #include "nsExceptionHandler.h"
 #include "nsICrashReporter.h"
 #endif
 
 namespace mozilla {
 namespace widget {
@@ -529,16 +530,44 @@ GfxInfo::GetAdapterSubsysID2(nsAString &
 
 /* readonly attribute boolean isGPU2Active; */
 NS_IMETHODIMP
 GfxInfo::GetIsGPU2Active(bool* aIsGPU2Active)
 {
   return NS_ERROR_FAILURE;
 }
 
+nsresult
+GfxInfo::FindMonitors(JSContext* aCx, JS::HandleObject aOutArray)
+{
+#if defined(MOZ_WIDGET_GTK)
+  // No display in xpcshell mode.
+  if (!gdk_display_get_default()) {
+    return NS_OK;
+  }
+#endif
+
+  // Note: this doesn't support Xinerama. Two physical displays will be
+  // reported as one monitor covering the entire virtual screen.
+  Display* display = DefaultXDisplay();
+  Screen* screen = DefaultScreenOfDisplay(display);
+
+  JS::Rooted<JSObject*> obj(aCx, JS_NewPlainObject(aCx));
+
+  JS::Rooted<JS::Value> screenWidth(aCx, JS::Int32Value(WidthOfScreen(screen)));
+  JS_SetProperty(aCx, obj, "screenWidth", screenWidth);
+
+  JS::Rooted<JS::Value> screenHeight(aCx, JS::Int32Value(HeightOfScreen(screen)));
+  JS_SetProperty(aCx, obj, "screenHeight", screenHeight);
+
+  JS::Rooted<JS::Value> element(aCx, JS::ObjectValue(*obj));
+  JS_SetElement(aCx, aOutArray, 0, element);
+  return NS_OK;
+}
+
 #ifdef DEBUG
 
 // Implement nsIGfxInfoDebug
 // We don't support spoofing anything on Linux
 
 /* void spoofVendorID (in DOMString aVendorID); */
 NS_IMETHODIMP GfxInfo::SpoofVendorID(const nsAString & aVendorID)
 {
--- a/widget/GfxInfoX11.h
+++ b/widget/GfxInfoX11.h
@@ -43,16 +43,18 @@ public:
   using GfxInfoBase::GetFeatureStatus;
   using GfxInfoBase::GetFeatureSuggestedDriverVersion;
   using GfxInfoBase::GetWebGLParameter;
 
   virtual nsresult Init() override;
   
   NS_IMETHOD_(void) GetData() override;
 
+  nsresult FindMonitors(JSContext* cx, JS::HandleObject array) override;
+
 #ifdef DEBUG
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIGFXINFODEBUG
 #endif
 
 protected:
   ~GfxInfo() {}
 
--- a/widget/cocoa/GfxInfo.h
+++ b/widget/cocoa/GfxInfo.h
@@ -54,16 +54,18 @@ public:
   NS_DECL_ISUPPORTS_INHERITED
 #ifdef DEBUG
   NS_DECL_NSIGFXINFODEBUG
 #endif
   NS_DECL_NSIGFXINFO2
 
   virtual uint32_t OperatingSystemVersion() override { return mOSXVersion; }
 
+  nsresult FindMonitors(JSContext* cx, JS::HandleObject array) override;
+
 protected:
 
   virtual ~GfxInfo() {}
 
   virtual nsresult GetFeatureStatusImpl(int32_t aFeature, 
                                         int32_t *aStatus, 
                                         nsAString & aSuggestedDriverVersion, 
                                         const nsTArray<GfxDriverInfo>& aDriverInfo,
--- a/widget/cocoa/GfxInfo.mm
+++ b/widget/cocoa/GfxInfo.mm
@@ -374,16 +374,43 @@ GfxInfo::GetFeatureStatusImpl(int32_t aF
         return NS_OK;
       }
     }
   }
 
   return GfxInfoBase::GetFeatureStatusImpl(aFeature, aStatus, aSuggestedDriverVersion, aDriverInfo, &os);
 }
 
+nsresult
+GfxInfo::FindMonitors(JSContext* aCx, JS::HandleObject aOutArray)
+{
+  // Getting the refresh rate is a little hard on OS X. We could use
+  // CVDisplayLinkGetNominalOutputVideoRefreshPeriod, but that's a little
+  // involved. Ideally we could query it from vsync. For now, we leave it out.
+  int32_t deviceCount = 0;
+  for (NSScreen* screen in [NSScreen screens]) {
+    NSRect rect = [screen frame];
+
+    JS::Rooted<JSObject*> obj(aCx, JS_NewPlainObject(aCx));
+
+    JS::Rooted<JS::Value> screenWidth(aCx, JS::Int32Value((int)rect.size.width));
+    JS_SetProperty(aCx, obj, "screenWidth", screenWidth);
+
+    JS::Rooted<JS::Value> screenHeight(aCx, JS::Int32Value((int)rect.size.height));
+    JS_SetProperty(aCx, obj, "screenHeight", screenHeight);
+
+    JS::Rooted<JS::Value> scale(aCx, JS::NumberValue(nsCocoaUtils::GetBackingScaleFactor(screen)));
+    JS_SetProperty(aCx, obj, "scale", scale);
+
+    JS::Rooted<JS::Value> element(aCx, JS::ObjectValue(*obj));
+    JS_SetElement(aCx, aOutArray, deviceCount++, element);
+  }
+  return NS_OK;
+}
+
 #ifdef DEBUG
 
 // Implement nsIGfxInfoDebug
 
 /* void spoofVendorID (in DOMString aVendorID); */
 NS_IMETHODIMP GfxInfo::SpoofVendorID(const nsAString & aVendorID)
 {
   mAdapterVendorID = aVendorID;
--- a/widget/nsIGfxInfo.idl
+++ b/widget/nsIGfxInfo.idl
@@ -3,17 +3,17 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 
 /* NOTE: this interface is completely undesigned, not stable and likely to change */
 
-[scriptable, uuid(b0cd9d34-8dba-4b1d-8126-ca21826dbf35)]
+[scriptable, uuid(47eedfa0-f7cb-445b-b5cf-a2ca83600560)]
 interface nsIGfxInfo : nsISupports
 {
   /*
    * These are win32-specific
    */
   readonly attribute boolean D2DEnabled;
   readonly attribute boolean DWriteEnabled;
   readonly attribute DOMString DWriteVersion;
@@ -49,16 +49,27 @@ interface nsIGfxInfo : nsISupports
   readonly attribute DOMString adapterDriverVersion;
   readonly attribute DOMString adapterDriverVersion2;
   
   readonly attribute DOMString adapterDriverDate;
   readonly attribute DOMString adapterDriverDate2;
 
   readonly attribute boolean isGPU2Active;
 
+  /**
+   * Returns an array of objects describing each monitor. Guaranteed properties
+   * are "screenWidth" and "screenHeight". This is only implemented on Desktop.
+   *
+   * Windows additionally supplies "refreshRate" and "pseudoDisplay".
+   *
+   * OS X additionally supplies "scale".
+   */
+  [implicit_jscontext]
+  jsval getMonitors();
+
   void getFailures(
                out unsigned long failureCount,
                [optional, array, size_is(failureCount)] out long indices,
                [retval, array, size_is(failureCount)] out string failures);
 
   [noscript, notxpcom] void logFailure(in ACString failure);
   /*
    * A set of constants for features that we can ask this GfxInfo object
--- a/widget/windows/GfxInfo.cpp
+++ b/widget/windows/GfxInfo.cpp
@@ -12,16 +12,17 @@
 #include "GfxInfoWebGL.h"
 #include "nsUnicharUtils.h"
 #include "prenv.h"
 #include "prprf.h"
 #include "GfxDriverInfo.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/gfx/Logging.h"
 #include "nsPrintfCString.h"
+#include "jsapi.h"
 
 #if defined(MOZ_CRASHREPORTER)
 #include "nsExceptionHandler.h"
 #include "nsICrashReporter.h"
 #define NS_CRASHREPORTER_CONTRACTID "@mozilla.org/toolkit/crash-reporter;1"
 #endif
 
 using namespace mozilla;
@@ -1211,16 +1212,59 @@ GfxInfo::GetFeatureStatusImpl(int32_t aF
       *aStatus = nsIGfxInfo::FEATURE_BLOCKED_MISMATCHED_VERSION;
       return NS_OK;
     }
   }
 
   return GfxInfoBase::GetFeatureStatusImpl(aFeature, aStatus, aSuggestedDriverVersion, aDriverInfo, &os);
 }
 
+nsresult
+GfxInfo::FindMonitors(JSContext* aCx, JS::HandleObject aOutArray)
+{
+  int deviceCount = 0;
+  for (int deviceIndex = 0;; deviceIndex++) {
+    DISPLAY_DEVICEA device;
+    device.cb = sizeof(device);
+    if (!::EnumDisplayDevicesA(nullptr, deviceIndex, &device, 0)) {
+      break;
+    }
+
+    if (!(device.StateFlags & DISPLAY_DEVICE_ACTIVE)) {
+      continue;
+    }
+
+    DEVMODEA mode;
+    mode.dmSize = sizeof(mode);
+    mode.dmDriverExtra = 0;
+    if (!::EnumDisplaySettingsA(device.DeviceName, ENUM_CURRENT_SETTINGS, &mode)) {
+      continue;
+    }
+
+    JS::Rooted<JSObject*> obj(aCx, JS_NewPlainObject(aCx));
+
+    JS::Rooted<JS::Value> screenWidth(aCx, JS::Int32Value(mode.dmPelsWidth));
+    JS_SetProperty(aCx, obj, "screenWidth", screenWidth);
+
+    JS::Rooted<JS::Value> screenHeight(aCx, JS::Int32Value(mode.dmPelsHeight));
+    JS_SetProperty(aCx, obj, "screenHeight", screenHeight);
+
+    JS::Rooted<JS::Value> refreshRate(aCx, JS::Int32Value(mode.dmDisplayFrequency));
+    JS_SetProperty(aCx, obj, "refreshRate", refreshRate);
+
+    JS::Rooted<JS::Value> pseudoDisplay(aCx,
+      JS::BooleanValue(!!(device.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER)));
+    JS_SetProperty(aCx, obj, "pseudoDisplay", pseudoDisplay);
+
+    JS::Rooted<JS::Value> element(aCx, JS::ObjectValue(*obj));
+    JS_SetElement(aCx, aOutArray, deviceCount++, element);
+  }
+  return NS_OK;
+}
+
 #ifdef DEBUG
 
 // Implement nsIGfxInfoDebug
 
 /* void spoofVendorID (in DOMString aVendorID); */
 NS_IMETHODIMP GfxInfo::SpoofVendorID(const nsAString & aVendorID)
 {
   mAdapterVendorID = aVendorID;
--- a/widget/windows/GfxInfo.h
+++ b/widget/windows/GfxInfo.h
@@ -46,16 +46,18 @@ public:
   using GfxInfoBase::GetFeatureStatus;
   using GfxInfoBase::GetFeatureSuggestedDriverVersion;
   using GfxInfoBase::GetWebGLParameter;
 
   virtual nsresult Init();
 
   virtual uint32_t OperatingSystemVersion() override { return mWindowsVersion; }
 
+  nsresult FindMonitors(JSContext* cx, JS::HandleObject array) override;
+
   NS_DECL_ISUPPORTS_INHERITED
 #ifdef DEBUG
   NS_DECL_NSIGFXINFODEBUG
 #endif
   NS_DECL_NSIGFXINFO2
 
 protected: