Bug 1574307 - Part 1. Parse viewport-fit in meta element. draft
authorMakoto Kato <m_kato@ga2.so-net.ne.jp>
Mon, 02 Dec 2019 14:52:54 +0900
changeset 2526062 3e718fac4d5f48dfe95546fcecafd3141037f4c1
parent 2525322 86afe431ec559c111ae1c1f94e4ede25776e9c50
child 2526063 3f2cc39d1134c0c45b8b90a9c995bd348bc0b015
push id462928
push userm_kato@ga2.so-net.ne.jp
push dateTue, 10 Dec 2019 05:33:59 +0000
treeherdertry@b47e7a56c0a3 [default view] [failures only]
bugs1574307
milestone73.0a1
Bug 1574307 - Part 1. Parse viewport-fit in meta element. For safe area insets (cutout) support, CSS Round Display Level 1 (https://drafts.csswg.org/css-round-display/#viewport-fit-descriptor) has new viewport value as `viewport-fit`. To support safe area insets that is notch on display, CSS Environment Variables Module Level 1 (https://drafts.csswg.org/css-env-1/#safe-area-insets) adds `safearea-insets-*` (left, top, right and bottom). Also, `meta` element has `viewport-fit` enum value. (ex `<meta name="viewport" content="viewport-fit=cover>`) whether web browser window cover notch area. `viewport-fit` has 3 enum value, `auto`, `cover` and `contain`. GeckoView wants to expose this value to browser application such Fenix. Because Android API (https://developer.android.com/guide/topics/display-cutout) uses window root layout (It is set by Application) to cover notch on display. So I want to get this value via Chrome's JavaScript. nsIDOMWindowUtils already has an API to get viewport of meta element, then I would like to add additional parameter for this value. Differential Revision: https://phabricator.services.mozilla.com/D55609
devtools/server/actors/emulation/touch-simulator.js
dom/base/Document.cpp
dom/base/Document.h
dom/base/ViewportMetaData.cpp
dom/base/ViewportMetaData.h
dom/base/nsDOMWindowUtils.cpp
dom/base/nsViewportInfo.h
dom/base/test/mochitest.ini
dom/base/test/test_meta_viewport0.html
dom/base/test/test_meta_viewport9.html
dom/base/test/viewport_helpers.js
dom/interfaces/base/nsIDOMWindowUtils.idl
dom/tests/reftest/bug798068-ref.xhtml
dom/tests/reftest/bug798068.xhtml
gfx/layers/apz/test/gtest/mvm/TestMobileViewportManager.cpp
xpcom/ds/StaticAtoms.py
--- a/devtools/server/actors/emulation/touch-simulator.js
+++ b/devtools/server/actors/emulation/touch-simulator.js
@@ -400,17 +400,18 @@ TouchSimulator.prototype = {
       content.innerWidth,
       content.innerHeight,
       {},
       allowZoom,
       minZoom,
       maxZoom,
       {},
       {},
-      autoSize
+      autoSize,
+      {}
     );
 
     // FIXME: On Safari and Chrome mobile platform, if the css property
     // touch-action set to none or manipulation would also suppress 300ms
     // delay. But Firefox didn't support this property now, we can't get
     // this value from utils.getVisitedDependentComputedStyle() to check
     // if we should suppress 300ms delay.
     if (
--- a/dom/base/Document.cpp
+++ b/dom/base/Document.cpp
@@ -1331,16 +1331,17 @@ Document::Document(const char* aContentT
       mBlockDOMContentLoaded(0),
       mUseCounters(0),
       mChildDocumentUseCounters(0),
       mUserHasInteracted(false),
       mHasUserInteractionTimerScheduled(false),
       mStackRefCnt(0),
       mUpdateNestLevel(0),
       mViewportType(Unknown),
+      mViewportFit(ViewportFitType::Auto),
       mSubDocuments(nullptr),
       mHeaderData(nullptr),
       mFlashClassification(FlashClassification::Unknown),
       mScrollAnchorAdjustmentLength(0),
       mScrollAnchorAdjustmentCount(0),
       mServoRestyleRootDirtyBits(0),
       mThrowOnDynamicMarkupInsertionCounter(0),
       mIgnoreOpensDuringUnloadCounter(0),
@@ -9409,16 +9410,31 @@ nsViewportInfo Document::GetViewportInfo
           (metaData.mUserScalable.EqualsLiteral("no")) ||
           (metaData.mUserScalable.EqualsLiteral("false"))) {
         mAllowZoom = false;
       }
       if (!metaData.mUserScalable.IsEmpty()) {
         hasValidContents = true;
       }
 
+      // Resolve viewport-fit value.
+      // https://drafts.csswg.org/css-round-display/#viewport-fit-descriptor
+      if (!metaData.mViewportFit.IsEmpty()) {
+        if (metaData.mViewportFit.EqualsLiteral("auto")) {
+          mViewportFit = ViewportFitType::Auto;
+          hasValidContents = true;
+        } else if (metaData.mViewportFit.EqualsLiteral("contain")) {
+          mViewportFit = ViewportFitType::Contain;
+          hasValidContents = true;
+        } else if (metaData.mViewportFit.EqualsLiteral("cover")) {
+          mViewportFit = ViewportFitType::Cover;
+          hasValidContents = true;
+        }
+      }
+
       mWidthStrEmpty = metaData.mWidth.IsEmpty();
 
       mViewportType = hasValidContents ? Specified : NoValidContent;
       MOZ_FALLTHROUGH;
     }
     case Specified:
     case NoValidContent:
     default:
@@ -9619,17 +9635,17 @@ nsViewportInfo Document::GetViewportInfo
         size.width = std::max(size.width, displaySize.width);
         size.height = std::max(size.height, displaySize.height);
       }
 
       return nsViewportInfo(
           scaleFloat, scaleMinFloat, scaleMaxFloat, size, sizeFlag,
           mValidScaleFloat ? nsViewportInfo::AutoScaleFlag::FixedScale
                            : nsViewportInfo::AutoScaleFlag::AutoScale,
-          effectiveZoomFlag);
+          effectiveZoomFlag, mViewportFit);
   }
 }
 
 ViewportMetaData Document::GetViewportMetaData() const {
   // The order of mMetaViewport is first-modified is first. We want the last
   // modified since Chrome uses the last one.
   // See https://webcompat.com/issues/20701#issuecomment-436054739
   return !mMetaViewports.IsEmpty() ? mMetaViewports.LastElement().mData
--- a/dom/base/Document.h
+++ b/dom/base/Document.h
@@ -206,16 +206,17 @@ class ServiceWorkerDescriptor;
 class StyleSheetList;
 class SVGDocument;
 class SVGElement;
 class SVGSVGElement;
 class SVGUseElement;
 class Touch;
 class TouchList;
 class TreeWalker;
+enum class ViewportFitType : uint8_t;
 class XPathEvaluator;
 class XPathExpression;
 class XPathNSResolver;
 class XPathResult;
 class BrowsingContext;
 
 template <typename>
 class Sequence;
@@ -5157,16 +5158,20 @@ class Document : public nsINode,
     DisplayWidthHeight,
     Specified,
     Unknown,
     NoValidContent,
   };
 
   ViewportType mViewportType;
 
+  // viewport-fit described by
+  // https://drafts.csswg.org/css-round-display/#viewport-fit-descriptor
+  ViewportFitType mViewportFit;
+
   PLDHashTable* mSubDocuments;
 
   DocHeaderData* mHeaderData;
 
   // For determining if this is a flash document which should be
   // blocked based on its principal.
   FlashClassification mFlashClassification;
 
--- a/dom/base/ViewportMetaData.cpp
+++ b/dom/base/ViewportMetaData.cpp
@@ -50,16 +50,18 @@ static void ProcessViewportToken(Viewpor
   } else if (key_atom == nsGkAtoms::initial_scale) {
     aData.mInitialScale.Assign(value);
   } else if (key_atom == nsGkAtoms::minimum_scale) {
     aData.mMinimumScale.Assign(value);
   } else if (key_atom == nsGkAtoms::maximum_scale) {
     aData.mMaximumScale.Assign(value);
   } else if (key_atom == nsGkAtoms::user_scalable) {
     aData.mUserScalable.Assign(value);
+  } else if (key_atom == nsGkAtoms::viewport_fit) {
+    aData.mViewportFit.Assign(value);
   }
 }
 
 #define IS_SEPARATOR(c)                                             \
   (((c) == '=') || ((c) == ',') || ((c) == ';') || ((c) == '\t') || \
    ((c) == '\n') || ((c) == '\r'))
 
 ViewportMetaData::ViewportMetaData(const nsAString& aViewportInfo) {
--- a/dom/base/ViewportMetaData.h
+++ b/dom/base/ViewportMetaData.h
@@ -15,23 +15,25 @@ namespace dom {
 struct ViewportMetaData {
   // https://drafts.csswg.org/css-device-adapt/#meta-properties
   nsString mWidth;
   nsString mHeight;
   nsString mInitialScale;
   nsString mMinimumScale;
   nsString mMaximumScale;
   nsString mUserScalable;
+  nsString mViewportFit;
 
   bool operator==(const ViewportMetaData& aOther) const {
     return mWidth == aOther.mWidth && mHeight == aOther.mHeight &&
            mInitialScale == aOther.mInitialScale &&
            mMinimumScale == aOther.mMinimumScale &&
            mMaximumScale == aOther.mMaximumScale &&
-           mUserScalable == aOther.mUserScalable;
+           mUserScalable == aOther.mUserScalable &&
+           mViewportFit == aOther.mViewportFit;
   }
   bool operator!=(const ViewportMetaData& aOther) const {
     return !(*this == aOther);
   }
 
   ViewportMetaData() = default;
   /* Process viewport META data. This gives us information for the scale
    * and zoom of a page on mobile devices. We stick the information in
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -382,30 +382,42 @@ nsDOMWindowUtils::GetContentViewerSize(u
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::GetViewportInfo(uint32_t aDisplayWidth,
                                   uint32_t aDisplayHeight, double* aDefaultZoom,
                                   bool* aAllowZoom, double* aMinZoom,
                                   double* aMaxZoom, uint32_t* aWidth,
-                                  uint32_t* aHeight, bool* aAutoSize) {
+                                  uint32_t* aHeight, bool* aAutoSize,
+                                  nsAString& aViewportFit) {
   Document* doc = GetDocument();
   NS_ENSURE_STATE(doc);
 
   nsViewportInfo info =
       doc->GetViewportInfo(ScreenIntSize(aDisplayWidth, aDisplayHeight));
   *aDefaultZoom = info.GetDefaultZoom().scale;
   *aAllowZoom = info.IsZoomAllowed();
   *aMinZoom = info.GetMinZoom().scale;
   *aMaxZoom = info.GetMaxZoom().scale;
   CSSIntSize size = gfx::RoundedToInt(info.GetSize());
   *aWidth = size.width;
   *aHeight = size.height;
   *aAutoSize = info.IsAutoSizeEnabled();
+  switch (info.GetViewportFit()) {
+    case ViewportFitType::Contain:
+      aViewportFit.AssignLiteral("contain");
+      break;
+    case ViewportFitType::Cover:
+      aViewportFit.AssignLiteral("cover");
+      break;
+    default:
+      aViewportFit.AssignLiteral("auto");
+      break;
+  }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::SetDisplayPortForElement(float aXPx, float aYPx,
                                            float aWidthPx, float aHeightPx,
                                            Element* aElement,
                                            uint32_t aPriority) {
--- a/dom/base/nsViewportInfo.h
+++ b/dom/base/nsViewportInfo.h
@@ -4,16 +4,26 @@
 
 #ifndef nsViewportInfo_h___
 #define nsViewportInfo_h___
 
 #include <stdint.h>
 #include "mozilla/Attributes.h"
 #include "Units.h"
 
+namespace mozilla {
+namespace dom {
+enum class ViewportFitType : uint8_t {
+  Auto,
+  Contain,
+  Cover,
+};
+}
+}
+
 /**
  * Default values for the nsViewportInfo class.
  */
 static const mozilla::LayoutDeviceToScreenScale kViewportMinScale(0.25f);
 static const mozilla::LayoutDeviceToScreenScale kViewportMaxScale(10.0f);
 static const mozilla::CSSIntSize kViewportMinSize(200, 40);
 static const mozilla::CSSIntSize kViewportMaxSize(10000, 10000);
 
@@ -34,51 +44,56 @@ class MOZ_STACK_CLASS nsViewportInfo {
   enum class ZoomFlag {
     AllowZoom,
     DisallowZoom,
   };
   nsViewportInfo(const mozilla::ScreenIntSize& aDisplaySize,
                  const mozilla::CSSToScreenScale& aDefaultZoom,
                  ZoomFlag aZoomFlag)
       : mDefaultZoom(aDefaultZoom),
+        mViewportFit(mozilla::dom::ViewportFitType::Auto),
         mDefaultZoomValid(true),
         mAutoSize(true),
         mAllowZoom(aZoomFlag == ZoomFlag::AllowZoom) {
     mSize = mozilla::ScreenSize(aDisplaySize) / mDefaultZoom;
     mozilla::CSSToLayoutDeviceScale pixelRatio(1.0f);
     mMinZoom = pixelRatio * kViewportMinScale;
     mMaxZoom = pixelRatio * kViewportMaxScale;
     ConstrainViewportValues();
   }
 
   nsViewportInfo(const mozilla::CSSToScreenScale& aDefaultZoom,
                  const mozilla::CSSToScreenScale& aMinZoom,
                  const mozilla::CSSToScreenScale& aMaxZoom,
                  const mozilla::CSSSize& aSize, AutoSizeFlag aAutoSizeFlag,
-                 AutoScaleFlag aAutoScaleFlag, ZoomFlag aZoomFlag)
+                 AutoScaleFlag aAutoScaleFlag, ZoomFlag aZoomFlag,
+                 mozilla::dom::ViewportFitType aViewportFit)
       : mDefaultZoom(aDefaultZoom),
         mMinZoom(aMinZoom),
         mMaxZoom(aMaxZoom),
         mSize(aSize),
+        mViewportFit(aViewportFit),
         mDefaultZoomValid(aAutoScaleFlag != AutoScaleFlag::AutoScale),
         mAutoSize(aAutoSizeFlag == AutoSizeFlag::AutoSize),
         mAllowZoom(aZoomFlag == ZoomFlag::AllowZoom) {
     ConstrainViewportValues();
   }
 
   bool IsDefaultZoomValid() const { return mDefaultZoomValid; }
   mozilla::CSSToScreenScale GetDefaultZoom() const { return mDefaultZoom; }
   mozilla::CSSToScreenScale GetMinZoom() const { return mMinZoom; }
   mozilla::CSSToScreenScale GetMaxZoom() const { return mMaxZoom; }
 
   mozilla::CSSSize GetSize() const { return mSize; }
 
   bool IsAutoSizeEnabled() const { return mAutoSize; }
   bool IsZoomAllowed() const { return mAllowZoom; }
 
+  mozilla::dom::ViewportFitType GetViewportFit() const { return mViewportFit; }
+
   enum {
     Auto = -1,
     ExtendToZoom = -2,
     DeviceSize = -3,  // for device-width or device-height
   };
   // MIN/MAX computations where one of the arguments is auto resolve to the
   // other argument. For instance, MIN(0.25, auto) = 0.25, and
   // MAX(5, auto) = 5.
@@ -102,16 +117,19 @@ class MOZ_STACK_CLASS nsViewportInfo {
   mozilla::CSSToScreenScale mMinZoom;
 
   // The maximum zoom level permitted by the page.
   mozilla::CSSToScreenScale mMaxZoom;
 
   // The size of the viewport, specified by the <meta name="viewport"> tag.
   mozilla::CSSSize mSize;
 
+  // The value of the viewport-fit.
+  mozilla::dom::ViewportFitType mViewportFit;
+
   // If the default zoom was specified and was between the min and max
   // zoom values.
   // FIXME: Bug 1504362 - Unify this and mDefaultZoom into
   // Maybe<CSSToScreenScale>.
   bool mDefaultZoomValid;
 
   // Whether or not we should automatically size the viewport to the device's
   // width. This is true if the document has been optimized for mobile, and
--- a/dom/base/test/mochitest.ini
+++ b/dom/base/test/mochitest.ini
@@ -698,16 +698,17 @@ skip-if = !e10s # Track Bug 1281415
 [test_meta_viewport1.html]
 [test_meta_viewport2.html]
 [test_meta_viewport3.html]
 [test_meta_viewport4.html]
 [test_meta_viewport5.html]
 [test_meta_viewport6.html]
 [test_meta_viewport7.html]
 [test_meta_viewport8.html]
+[test_meta_viewport9.html]
 [test_meta_viewport_auto_size_by_device_height.html]
 [test_meta_viewport_auto_size_by_device_width.html]
 [test_meta_viewport_auto_size_by_fixed_height_and_initial_scale_1.html]
 [test_meta_viewport_auto_size_by_fixed_width_and_device_height.html]
 [test_meta_viewport_auto_size_by_fixed_width_and_initial_scale_1.html]
 [test_meta_viewport_auto_size_by_initial_scale_0_5.html]
 [test_meta_viewport_auto_size_by_initial_scale_1.html]
 [test_meta_viewport_auto_size_by_invalid_width.html]
--- a/dom/base/test/test_meta_viewport0.html
+++ b/dom/base/test/test_meta_viewport0.html
@@ -18,16 +18,17 @@
       let info = getViewportInfo(800, 480);
       fuzzeq(info.defaultZoom, 0.25, "initial scale is clamped to the default mimumim scale");
       fuzzeq(info.minZoom, 0.25,     "minimum scale defaults to the absolute minimum");
       is(info.maxZoom,     10,       "maximum scale defaults to the absolute maximum");
       is(info.width,       980,      "width is the default width");
       is(info.height,      588,      "height is proportional to displayHeight");
       is(info.autoSize,    false,    "autoSize is disabled by default");
       is(info.allowZoom,   true,     "zooming is enabled by default");
+      is(info.viewportFit, "auto",   "viewport-fit is auto by default");
 
       info = getViewportInfo(490, 600);
       is(info.width,       980,     "width is still the default width");
       is(info.height,      1200,    "height is proportional to the new displayHeight");
     });
 
     add_task(async function test2() {
       await SpecialPowers.pushPrefEnv(scaleRatio(1.5));
new file mode 100644
--- /dev/null
+++ b/dom/base/test/test_meta_viewport9.html
@@ -0,0 +1,34 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>meta viewport test</title>
+  <script src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <meta name="viewport" content="viewport-fit=cover">
+  <script src="viewport_helpers.js"></script>
+</head>
+<body>
+  <p>viewport-fit=cover</p>
+  <script type="application/javascript">
+    "use strict";
+
+    add_task(async function test1() {
+      await SpecialPowers.pushPrefEnv(scaleRatio(1.0));
+
+      let info = getViewportInfo(800, 480);
+      is(info.viewportFit, "cover", "viewport-fit is cover correctly");
+
+      let elements = document.getElementsByTagName("meta");
+      for (let meta of elements) {
+        if (meta.getAttribute("name") == "viewport") {
+          meta.setAttribute("content", "viewport-fit=contain");
+        }
+      }
+
+      info = getViewportInfo(800, 480);
+      is(info.viewportFit, "contain", "viewport-fit is cover correctly");
+    });
+  </script>
+</body>
+</html>
--- a/dom/base/test/viewport_helpers.js
+++ b/dom/base/test/viewport_helpers.js
@@ -10,36 +10,39 @@ function scaleRatio(scale) {
 
 function getViewportInfo(aDisplayWidth, aDisplayHeight) {
   let defaultZoom = {},
     allowZoom = {},
     minZoom = {},
     maxZoom = {},
     width = {},
     height = {},
-    autoSize = {};
+    autoSize = {},
+    viewportFit = {};
 
   let cwu = SpecialPowers.getDOMWindowUtils(window);
   cwu.getViewportInfo(
     aDisplayWidth,
     aDisplayHeight,
     defaultZoom,
     allowZoom,
     minZoom,
     maxZoom,
     width,
     height,
-    autoSize
+    autoSize,
+    viewportFit
   );
   return {
     defaultZoom: defaultZoom.value,
     minZoom: minZoom.value,
     maxZoom: maxZoom.value,
     width: width.value,
     height: height.value,
     autoSize: autoSize.value,
     allowZoom: allowZoom.value,
+    viewportFit: viewportFit.value,
   };
 }
 
 function fuzzeq(a, b, msg) {
   ok(Math.abs(a - b) < 1e-6, msg);
 }
--- a/dom/interfaces/base/nsIDOMWindowUtils.idl
+++ b/dom/interfaces/base/nsIDOMWindowUtils.idl
@@ -109,17 +109,17 @@ interface nsIDOMWindowUtils : nsISupport
   /**
    * Information retrieved from the <meta name="viewport"> tag.
    * See Document::GetViewportInfo for more information.
    */
   void getViewportInfo(in uint32_t aDisplayWidth, in uint32_t aDisplayHeight,
                        out double aDefaultZoom, out boolean aAllowZoom,
                        out double aMinZoom, out double aMaxZoom,
                        out uint32_t aWidth, out uint32_t aHeight,
-                       out boolean aAutoSize);
+                       out boolean aAutoSize, out AString aViewportFit);
 
   /**
    * Information about the window size in device pixels.
    */
   void getContentViewerSize(out uint32_t aDisplayWidth, out uint32_t aDisplayHeight);
 
   /**
    * For any scrollable element, this allows you to override the
--- a/dom/tests/reftest/bug798068-ref.xhtml
+++ b/dom/tests/reftest/bug798068-ref.xhtml
@@ -1,16 +1,16 @@
 <?xml version = '1.0' encoding = 'utf-8'?>
 <html xmlns="http://www.w3.org/1999/xhtml">
   <head>
     <script>
       function doTest() {
         var defaultZoom = {}, allowZoom = {}, minZoom = {}, maxZoom ={}, width = {}, height = {}, autoSize = {};
         var windowUtils = window.windowUtils;
-        windowUtils.getViewportInfo(1, 1, defaultZoom, allowZoom, minZoom, maxZoom, width, height, autoSize);
+        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>
--- a/dom/tests/reftest/bug798068.xhtml
+++ b/dom/tests/reftest/bug798068.xhtml
@@ -1,17 +1,17 @@
 <?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 defaultZoom = {}, allowZoom = {}, minZoom = {}, maxZoom ={}, width = {}, height = {}, autoSize = {};
         var windowUtils = window.windowUtils;
-        windowUtils.getViewportInfo(1, 1, defaultZoom, allowZoom, minZoom, maxZoom, width, height, autoSize);
+        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>
--- a/gfx/layers/apz/test/gtest/mvm/TestMobileViewportManager.cpp
+++ b/gfx/layers/apz/test/gtest/mvm/TestMobileViewportManager.cpp
@@ -54,17 +54,18 @@ class MockMVMContext : public MVMContext
     // this test harness.
     CSSSize viewportSize = mDisplaySize / mDeviceScale;
     if (mAutoSizeFlag == AutoSizeFlag::FixedSize) {
       viewportSize = CSSSize(mFixedViewportWidth,
                              mFixedViewportWidth * (float(mDisplaySize.height) /
                                                     mDisplaySize.width));
     }
     return nsViewportInfo(mDefaultScale, mMinScale, mMaxScale, viewportSize,
-                          mAutoSizeFlag, mAutoScaleFlag, mZoomFlag);
+                          mAutoSizeFlag, mAutoScaleFlag, mZoomFlag,
+                          dom::ViewportFitType::Auto);
   }
   CSSToLayoutDeviceScale CSSToDevPixelScale() const { return mDeviceScale; }
   float GetResolution() const { return mResolution; }
   bool SubjectMatchesDocument(nsISupports* aSubject) const { return true; }
   Maybe<CSSRect> CalculateScrollableRectForRSF() const {
     return Some(CSSRect(CSSPoint(), mContentSize));
   }
   bool IsResolutionUpdatedByApz() const { return false; }
--- a/xpcom/ds/StaticAtoms.py
+++ b/xpcom/ds/StaticAtoms.py
@@ -1238,16 +1238,17 @@ STATIC_ATOMS = [
     Atom("variable", "variable"),
     Atom("vendor", "vendor"),
     Atom("vendorUrl", "vendor-url"),
     Atom("version", "version"),
     Atom("vertical", "vertical"),
     Atom("audio", "audio"),
     Atom("video", "video"),
     Atom("viewport", "viewport"),
+    Atom("viewport_fit", "viewport-fit"),
     Atom("viewport_height", "viewport-height"),
     Atom("viewport_initial_scale", "viewport-initial-scale"),
     Atom("viewport_maximum_scale", "viewport-maximum-scale"),
     Atom("viewport_minimum_scale", "viewport-minimum-scale"),
     Atom("viewport_user_scalable", "viewport-user-scalable"),
     Atom("viewport_width", "viewport-width"),
     Atom("visibility", "visibility"),
     Atom("visuallyselected", "visuallyselected"),