Bug 716575 (3/4) - Move viewport pixel ratio calculations into the platform [r=dbaron,jwir3,mfinkle,roc]
authorMatt Brubeck <mbrubeck@mozilla.com>
Wed, 22 Aug 2012 13:18:10 -0700
changeset 107779 39803b4c2b9d0bf3011379ec6079b2cf5878af27
parent 107778 ab874d12dcde471855f0a5de5b40d3400018f86d
child 107780 9108fa673bfee54a3611fd0c261134c51160b0d8
push id23509
push userryanvm@gmail.com
push dateSat, 22 Sep 2012 12:28:38 +0000
treeherdermozilla-central@b461a7cd250e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdbaron, jwir3, mfinkle, roc
bugs716575
milestone18.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 716575 (3/4) - Move viewport pixel ratio calculations into the platform [r=dbaron,jwir3,mfinkle,roc]
content/base/public/nsContentUtils.h
content/base/src/nsContentUtils.cpp
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -1544,16 +1544,21 @@ public:
    *
    * NOTE: If the site is optimized for mobile (via the doctype), this
    * will return viewport information that specifies default information.
    */
   static ViewportInfo GetViewportInfo(nsIDocument* aDocument,
                                       uint32_t aDisplayWidth,
                                       uint32_t aDisplayHeight);
 
+  /**
+   * The device-pixel-to-CSS-px ratio used to adjust meta viewport values.
+   */
+  static double GetDevicePixelsPerMetaViewportPixel(nsIWidget* aWidget);
+
   // Call EnterMicroTask when you're entering JS execution.
   // Usually the best way to do this is to use nsAutoMicroTask.
   static void EnterMicroTask() { ++sMicroTaskLevel; }
   static void LeaveMicroTask();
 
   static bool IsInMicroTask() { return sMicroTaskLevel != 0; }
   static uint32_t MicroTaskLevel() { return sMicroTaskLevel; }
   static void SetMicroTaskLevel(uint32_t aLevel) { sMicroTaskLevel = aLevel; }
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -7,16 +7,18 @@
 /* A namespace class for static layout utilities. */
 
 #include "mozilla/Util.h"
 
 #include "jsapi.h"
 #include "jsdbgapi.h"
 #include "jsfriendapi.h"
 
+#include <math.h>
+
 #include "Layers.h"
 #include "nsJSUtils.h"
 #include "nsCOMPtr.h"
 #include "nsAString.h"
 #include "nsPrintfCString.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIScriptContext.h"
 #include "nsDOMCID.h"
@@ -5169,44 +5171,64 @@ nsContentUtils::GetViewportInfo(nsIDocum
 
   if (widthStr.IsEmpty() &&
      (heightStr.EqualsLiteral("device-height") ||
           scaleFloat == 1.0))
   {
     autoSize = true;
   }
 
-  uint32_t width = widthStr.ToInteger(&errorCode);
-  if (NS_FAILED(errorCode)) {
-    if (autoSize) {
-      width = aDisplayWidth;
-    } else {
-      width = Preferences::GetInt("browser.viewport.desktopWidth", 0);
+  // Now convert the scale into device pixels per CSS pixel.
+  nsIWidget *widget = WidgetForDocument(aDocument);
+  double pixelRatio = widget ? GetDevicePixelsPerMetaViewportPixel(widget) : 1.0;
+  scaleFloat *= pixelRatio;
+  scaleMinFloat *= pixelRatio;
+  scaleMaxFloat *= pixelRatio;
+
+  uint32_t width, height;
+  if (autoSize) {
+    // aDisplayWidth and aDisplayHeight are in device pixels; convert them to
+    // CSS pixels for the viewport size.
+    width = aDisplayWidth / pixelRatio;
+    height = aDisplayHeight / pixelRatio;
+  } else {
+    nsresult widthErrorCode, heightErrorCode;
+    width = widthStr.ToInteger(&widthErrorCode);
+    height = heightStr.ToInteger(&heightErrorCode);
+
+    // If width or height has not been set to a valid number by this point,
+    // fall back to a default value.
+    bool validWidth = (!widthStr.IsEmpty() && NS_SUCCEEDED(widthErrorCode) && width > 0);
+    bool validHeight = (!heightStr.IsEmpty() && NS_SUCCEEDED(heightErrorCode) && height > 0);
+
+    if (!validWidth) {
+      if (validHeight && aDisplayWidth > 0 && aDisplayHeight > 0) {
+        width = uint32_t((height * aDisplayWidth) / aDisplayHeight);
+      } else {
+        width = Preferences::GetInt("browser.viewport.desktopWidth",
+                                    kViewportDefaultScreenWidth);
+      }
+    }
+
+    if (!validHeight) {
+      if (aDisplayWidth > 0 && aDisplayHeight > 0) {
+        height = uint32_t((width * aDisplayHeight) / aDisplayWidth);
+      } else {
+        height = width;
+      }
     }
   }
 
   width = NS_MIN(width, kViewportMaxWidth);
   width = NS_MAX(width, kViewportMinWidth);
 
   // Also recalculate the default zoom, if it wasn't specified in the metadata,
   // and the width is specified.
   if (scaleStr.IsEmpty() && !widthStr.IsEmpty()) {
-    scaleFloat = NS_MAX(scaleFloat, (float)(aDisplayWidth/width));
-  }
-
-  uint32_t height = heightStr.ToInteger(&errorCode);
-
-  if (NS_FAILED(errorCode)) {
-    height = width * ((float)aDisplayHeight / aDisplayWidth);
-  }
-
-  // If height was provided by the user, but width wasn't, then we should
-  // calculate the width.
-  if (widthStr.IsEmpty() && !heightStr.IsEmpty()) {
-    width = (uint32_t) ((height * aDisplayWidth) / aDisplayHeight);
+    scaleFloat = NS_MAX(scaleFloat, float(aDisplayWidth) / float(width));
   }
 
   height = NS_MIN(height, kViewportMaxHeight);
   height = NS_MAX(height, kViewportMinHeight);
 
   // We need to perform a conversion, but only if the initial or maximum
   // scale were set explicitly by the user.
   if (!scaleStr.IsEmpty() && NS_SUCCEEDED(scaleErrorCode)) {
@@ -5233,16 +5255,38 @@ nsContentUtils::GetViewportInfo(nsIDocum
   ret.defaultZoom = scaleFloat;
   ret.minZoom = scaleMinFloat;
   ret.maxZoom = scaleMaxFloat;
   ret.autoSize = autoSize;
   return ret;
 }
 
 /* static */
+double
+nsContentUtils::GetDevicePixelsPerMetaViewportPixel(nsIWidget* aWidget)
+{
+  int32_t prefValue = Preferences::GetInt("browser.viewport.scaleRatio", 0);
+  if (prefValue > 0) {
+    return double(prefValue) / 100.0;
+  }
+
+  float dpi = aWidget->GetDPI();
+  if (dpi < 200.0) {
+    // Includes desktop displays, LDPI and MDPI Android devices
+    return 1.0;
+  }
+  if (dpi < 300.0) {
+    // Includes Nokia N900, and HDPI Android devices
+    return 1.5;
+  }
+  // For very high-density displays like the iPhone 4, use an integer ratio.
+  return floor(dpi / 150.0);
+}
+
+/* static */
 nsresult
 nsContentUtils::ProcessViewportInfo(nsIDocument *aDocument,
                                     const nsAString &viewportInfo) {
 
   /* We never fail. */
   nsresult rv = NS_OK;
 
   aDocument->SetHeaderData(nsGkAtoms::viewport, viewportInfo);