Bug 798068: Return sane values for min/max zoom when handheldFriendly, WAP, Mobile, or WML is set in the viewport metadata. [r=mbrubeck,bent]
authorScott Johnson <sjohnson@mozilla.com>
Mon, 08 Oct 2012 15:41:48 -0500
changeset 109813 07ff446d1bd51cfe35a4474b30fc8fc7d7c46407
parent 109812 5a3ebc9d46ac85982e98cb4e024f512adbc6479c
child 109814 7b9bd4030c86bd1b2acbc073aff15f753288248d
push id84
push usernmatsakis@mozilla.com
push dateThu, 11 Oct 2012 23:26:24 +0000
reviewersmbrubeck, bent
bugs798068
milestone18.0a1
Bug 798068: Return sane values for min/max zoom when handheldFriendly, WAP, Mobile, or WML is set in the viewport metadata. [r=mbrubeck,bent]
content/base/public/nsContentUtils.h
content/base/src/nsContentUtils.cpp
content/test/reftest/bug798068-ref.xhtml
content/test/reftest/bug798068.xhtml
content/test/reftest/reftest.list
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -1566,16 +1566,23 @@ 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);
 
   /**
+   * Constrain the viewport calculations from the GetViewportInfo() function
+   * in order to always return sane minimum/maximum values. This modifies the
+   * ViewportInfo struct passed as an input parameter, in place.
+   */
+  static void ConstrainViewportValues(ViewportInfo& aViewInfo);
+
+  /**
    * 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();
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -245,18 +245,18 @@ nsIParser* nsContentUtils::sXMLFragmentP
 nsIFragmentContentSink* nsContentUtils::sXMLFragmentSink = nullptr;
 bool nsContentUtils::sFragmentParsingActive = false;
 
 namespace {
 
 /**
  * Default values for the ViewportInfo structure.
  */
-static const float    kViewportMinScale = 0.0;
-static const float    kViewportMaxScale = 10.0;
+static const double   kViewportMinScale = 0.0;
+static const double   kViewportMaxScale = 10.0;
 static const uint32_t kViewportMinWidth = 200;
 static const uint32_t kViewportMaxWidth = 10000;
 static const uint32_t kViewportMinHeight = 223;
 static const uint32_t kViewportMaxHeight = 10000;
 static const int32_t  kViewportDefaultScreenWidth = 980;
 
 static const char kJSStackContractID[] = "@mozilla.org/js/xpc/ContextStack;1";
 static NS_DEFINE_CID(kParserServiceCID, NS_PARSERSERVICE_CID);
@@ -5097,25 +5097,41 @@ static void ProcessViewportToken(nsIDocu
   else if (key_atom == nsGkAtoms::user_scalable)
     aDocument->SetHeaderData(nsGkAtoms::viewport_user_scalable, value);
 }
 
 #define IS_SEPARATOR(c) ((c == '=') || (c == ',') || (c == ';') || \
                          (c == '\t') || (c == '\n') || (c == '\r'))
 
 /* static */
+void
+nsContentUtils::ConstrainViewportValues(ViewportInfo& aViewInfo)
+{
+  // Constrain the min/max zoom as specified at:
+  // dev.w3.org/csswg/css-device-adapt section 6.2
+  aViewInfo.maxZoom = NS_MAX(aViewInfo.minZoom, aViewInfo.maxZoom);
+
+  aViewInfo.defaultZoom = NS_MIN(aViewInfo.defaultZoom, aViewInfo.maxZoom);
+  aViewInfo.defaultZoom = NS_MAX(aViewInfo.defaultZoom, aViewInfo.minZoom);
+}
+
+/* static */
 ViewportInfo
 nsContentUtils::GetViewportInfo(nsIDocument *aDocument,
                                 uint32_t aDisplayWidth,
                                 uint32_t aDisplayHeight)
 {
   ViewportInfo ret;
   ret.defaultZoom = 1.0;
   ret.autoSize = true;
   ret.allowZoom = true;
+  ret.width = aDisplayWidth;
+  ret.height = aDisplayHeight;
+  ret.minZoom = kViewportMinScale;
+  ret.maxZoom = kViewportMaxScale;
 
   nsAutoString viewport;
   aDocument->GetHeaderData(nsGkAtoms::viewport, viewport);
   if (viewport.IsEmpty()) {
     // If the docType specifies that we are on a site optimized for mobile,
     // then we want to return specially crafted defaults for the viewport info.
     nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(aDocument));
     nsCOMPtr<nsIDOMDocumentType> docType;
@@ -5123,63 +5139,63 @@ nsContentUtils::GetViewportInfo(nsIDocum
     if (NS_SUCCEEDED(rv) && docType) {
       nsAutoString docId;
       rv = docType->GetPublicId(docId);
       if (NS_SUCCEEDED(rv)) {
         if ((docId.Find("WAP") != -1) ||
             (docId.Find("Mobile") != -1) ||
             (docId.Find("WML") != -1))
         {
+          nsContentUtils::ConstrainViewportValues(ret);
           return ret;
         }
       }
     }
 
     nsAutoString handheldFriendly;
     aDocument->GetHeaderData(nsGkAtoms::handheldFriendly, handheldFriendly);
     if (handheldFriendly.EqualsLiteral("true")) {
+      nsContentUtils::ConstrainViewportValues(ret);
       return ret;
     }
   }
 
   nsAutoString minScaleStr;
   aDocument->GetHeaderData(nsGkAtoms::viewport_minimum_scale, minScaleStr);
 
   nsresult errorCode;
   float scaleMinFloat = minScaleStr.ToFloat(&errorCode);
 
   if (NS_FAILED(errorCode)) {
     scaleMinFloat = kViewportMinScale;
   }
 
-  scaleMinFloat = NS_MIN(scaleMinFloat, kViewportMaxScale);
-  scaleMinFloat = NS_MAX(scaleMinFloat, kViewportMinScale);
+  scaleMinFloat = NS_MIN((double)scaleMinFloat, kViewportMaxScale);
+  scaleMinFloat = NS_MAX((double)scaleMinFloat, kViewportMinScale);
 
   nsAutoString maxScaleStr;
   aDocument->GetHeaderData(nsGkAtoms::viewport_maximum_scale, maxScaleStr);
 
   // We define a special error code variable for the scale and max scale,
   // because they are used later (see the width calculations).
   nsresult scaleMaxErrorCode;
   float scaleMaxFloat = maxScaleStr.ToFloat(&scaleMaxErrorCode);
 
   if (NS_FAILED(scaleMaxErrorCode)) {
     scaleMaxFloat = kViewportMaxScale;
   }
 
-  scaleMaxFloat = NS_MIN(scaleMaxFloat, kViewportMaxScale);
-  scaleMaxFloat = NS_MAX(scaleMaxFloat, kViewportMinScale);
+  scaleMaxFloat = NS_MIN((double)scaleMaxFloat, kViewportMaxScale);
+  scaleMaxFloat = NS_MAX((double)scaleMaxFloat, kViewportMinScale);
 
   nsAutoString scaleStr;
   aDocument->GetHeaderData(nsGkAtoms::viewport_initial_scale, scaleStr);
 
   nsresult scaleErrorCode;
   float scaleFloat = scaleStr.ToFloat(&scaleErrorCode);
-  scaleFloat = NS_MIN(scaleFloat, scaleMaxFloat);
-  scaleFloat = NS_MAX(scaleFloat, scaleMinFloat);
 
   nsAutoString widthStr, heightStr;
 
   aDocument->GetHeaderData(nsGkAtoms::viewport_height, heightStr);
   aDocument->GetHeaderData(nsGkAtoms::viewport_width, widthStr);
 
   bool autoSize = false;
 
@@ -5269,16 +5285,18 @@ nsContentUtils::GetViewportInfo(nsIDocum
 
   ret.allowZoom = allowZoom;
   ret.width = width;
   ret.height = height;
   ret.defaultZoom = scaleFloat;
   ret.minZoom = scaleMinFloat;
   ret.maxZoom = scaleMaxFloat;
   ret.autoSize = autoSize;
+
+  nsContentUtils::ConstrainViewportValues(ret);
   return ret;
 }
 
 /* static */
 double
 nsContentUtils::GetDevicePixelsPerMetaViewportPixel(nsIWidget* aWidget)
 {
   int32_t prefValue = Preferences::GetInt("browser.viewport.scaleRatio", 0);
new file mode 100644
--- /dev/null
+++ b/content/test/reftest/bug798068-ref.xhtml
@@ -0,0 +1,19 @@
+<?xml version = '1.0' encoding = 'utf-8'?>
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <script>
+      function doTest() {
+        var Ci = Components.interfaces;
+        var defaultZoom = {}, allowZoom = {}, minZoom = {}, maxZoom ={}, width = {}, height = {}, autoSize = {};
+        var windowUtils = window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
+        windowUtils.getViewportInfo(1, 1, defaultZoom, allowZoom, minZoom, maxZoom, width, height, autoSize);
+        document.getElementById("minZoom").innerHTML = minZoom.value.toPrecision(10);
+        document.getElementById("maxZoom").innerHTML = maxZoom.value.toPrecision(10);
+      }
+    </script>
+  </head>
+  <body onload="doTest();">
+  MinZoom: <span id="minZoom"></span><br />
+  MaxZoom: <span id="maxZoom"></span>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/test/reftest/bug798068.xhtml
@@ -0,0 +1,20 @@
+<?xml version = '1.0' encoding = 'utf-8'?>
+<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.0//EN" "http://www.wapforum.org/DTD/xhtml-mobile10.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <script>
+      function doTest() {
+        var Ci = Components.interfaces;
+        var defaultZoom = {}, allowZoom = {}, minZoom = {}, maxZoom ={}, width = {}, height = {}, autoSize = {};
+        var windowUtils = window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
+        windowUtils.getViewportInfo(1, 1, defaultZoom, allowZoom, minZoom, maxZoom, width, height, autoSize);
+        document.getElementById("minZoom").innerHTML = minZoom.value.toPrecision(10);
+        document.getElementById("maxZoom").innerHTML = maxZoom.value.toPrecision(10);
+      }
+    </script>
+  </head>
+  <body onload="doTest();">
+  MinZoom: <span id="minZoom"></span><br />
+  MaxZoom: <span id="maxZoom"></span>
+  </body>
+</html>
--- a/content/test/reftest/reftest.list
+++ b/content/test/reftest/reftest.list
@@ -10,8 +10,9 @@ skip-if(xulFennec) include ../../canvas/
 == bug427779.xml bug427779-ref.xml
 == bug559996.html bug559996-ref.html
 == bug591981-1.html bug591981-ref.html
 == bug591981-2.html bug591981-ref.html
 == bug592366-1.html bug592366-ref.html
 == bug592366-2.html bug592366-ref.html
 == bug592366-1.xhtml bug592366-ref.xhtml
 == bug592366-2.xhtml bug592366-ref.xhtml
+== bug798068.xhtml bug798068-ref.xhtml