Bug 975501 part 2: Add display:{inline-,}grid behind a pref, and a stub nsGridContainerFrame. r=dholbert
authorSimon Sapin <simon.sapin@exyr.org>
Wed, 26 Feb 2014 23:45:29 -0800
changeset 170897 3038a5a34a753cd06e45b8e698a3c3b8edb7d538
parent 170896 3afc42ad21856a187f7c08445be1a97cc3dd86f2
child 170898 83115f0687d208daa5161b338796474f9ce41565
push id40337
push userdholbert@mozilla.com
push dateThu, 27 Feb 2014 07:45:47 +0000
treeherdermozilla-inbound@3038a5a34a75 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdholbert
bugs975501
milestone30.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 975501 part 2: Add display:{inline-,}grid behind a pref, and a stub nsGridContainerFrame. r=dholbert
content/base/src/nsGkAtomList.h
layout/base/nsCSSFrameConstructor.cpp
layout/base/nsLayoutUtils.cpp
layout/generic/moz.build
layout/generic/nsFrameIdList.h
layout/generic/nsGridContainerFrame.cpp
layout/generic/nsGridContainerFrame.h
layout/inspector/tests/test_bug877690.html
layout/style/nsCSSKeywordList.h
layout/style/nsCSSProps.cpp
layout/style/nsCSSProps.h
layout/style/nsRuleNode.cpp
layout/style/nsStyleConsts.h
layout/style/nsStyleContext.cpp
layout/style/nsStyleStruct.h
layout/style/test/property_database.js
testing/profiles/prefs_general.js
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -1816,16 +1816,17 @@ GK_ATOM(columnSetFrame, "ColumnSetFrame"
 GK_ATOM(comboboxControlFrame, "ComboboxControlFrame")
 GK_ATOM(comboboxDisplayFrame, "ComboboxDisplayFrame")
 GK_ATOM(deckFrame, "DeckFrame")
 GK_ATOM(fieldSetFrame, "FieldSetFrame")
 GK_ATOM(flexContainerFrame, "FlexContainerFrame")
 GK_ATOM(formControlFrame, "FormControlFrame") // radio or checkbox
 GK_ATOM(frameSetFrame, "FrameSetFrame")
 GK_ATOM(gfxButtonControlFrame, "gfxButtonControlFrame")
+GK_ATOM(gridContainerFrame, "GridContainerFrame")
 GK_ATOM(HTMLButtonControlFrame, "HTMLButtonControlFrame")
 GK_ATOM(HTMLCanvasFrame, "HTMLCanvasFrame")
 GK_ATOM(subDocumentFrame, "subDocumentFrame")
 GK_ATOM(imageBoxFrame, "ImageBoxFrame")
 GK_ATOM(imageFrame, "ImageFrame")
 GK_ATOM(imageControlFrame, "ImageControlFrame")
 GK_ATOM(inlineFrame, "InlineFrame")
 GK_ATOM(leafBoxFrame, "LeafBoxFrame")
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -53,16 +53,17 @@
 #endif
 #include "ChildIterator.h"
 #include "nsError.h"
 #include "nsLayoutUtils.h"
 #include "nsAutoPtr.h"
 #include "nsBoxFrame.h"
 #include "nsBoxLayout.h"
 #include "nsFlexContainerFrame.h"
+#include "nsGridContainerFrame.h"
 #include "nsImageFrame.h"
 #include "nsIObjectLoadingContent.h"
 #include "nsTArray.h"
 #include "nsGenericDOMDataNode.h"
 #include "mozilla/dom/Element.h"
 #include "nsAutoLayoutPhase.h"
 #include "nsStyleStructInlines.h"
 #include "nsPageContentFrame.h"
@@ -357,17 +358,18 @@ IsFrameForSVG(const nsIFrame* aFrame)
  * float-containing blocks -- those will manage the floating status of any
  * lower-level descendents inside them, of course).
  */
 static bool
 ShouldSuppressFloatingOfDescendants(nsIFrame* aFrame)
 {
   return aFrame->IsFrameOfType(nsIFrame::eMathML) ||
     aFrame->IsBoxFrame() ||
-    aFrame->GetType() == nsGkAtoms::flexContainerFrame;
+    aFrame->GetType() == nsGkAtoms::flexContainerFrame ||
+    aFrame->GetType() == nsGkAtoms::gridContainerFrame;
 }
 
 /**
  * If any children require a block parent, return the first such child.
  * Otherwise return null.
  */
 static nsIContent*
 AnyKidsNeedBlockParent(nsIFrame *aFrameList)
@@ -2416,16 +2418,22 @@ nsCSSFrameConstructor::ConstructDocEleme
     newFrame = frameItems.FirstChild();
     NS_ASSERTION(frameItems.OnlyChild(), "multiple root element frames");
   } else if (display->mDisplay == NS_STYLE_DISPLAY_FLEX) {
     contentFrame = NS_NewFlexContainerFrame(mPresShell, styleContext);
     InitAndRestoreFrame(state, aDocElement, mDocElementContainingBlock,
                         contentFrame);
     newFrame = contentFrame;
     processChildren = true;
+  } else if (display->mDisplay == NS_STYLE_DISPLAY_GRID) {
+    contentFrame = NS_NewGridContainerFrame(mPresShell, styleContext);
+    InitAndRestoreFrame(state, aDocElement, mDocElementContainingBlock,
+                        contentFrame);
+    newFrame = contentFrame;
+    processChildren = true;
   } else if (display->mDisplay == NS_STYLE_DISPLAY_TABLE) {
     // We're going to call the right function ourselves, so no need to give a
     // function to this FrameConstructionData.
 
     // XXXbz on the other hand, if we converted this whole function to
     // FrameConstructionData/Item, then we'd need the right function
     // here... but would probably be able to get away with less code in this
     // function in general.
@@ -4357,16 +4365,20 @@ nsCSSFrameConstructor::FindDisplayData(c
     // XXXbz the "quickly" part is a bald-faced lie!
     { NS_STYLE_DISPLAY_INLINE,
       FULL_CTOR_FCDATA(FCDATA_IS_INLINE | FCDATA_IS_LINE_PARTICIPANT,
                        &nsCSSFrameConstructor::ConstructInline) },
     { NS_STYLE_DISPLAY_FLEX,
       FCDATA_DECL(FCDATA_MAY_NEED_SCROLLFRAME, NS_NewFlexContainerFrame) },
     { NS_STYLE_DISPLAY_INLINE_FLEX,
       FCDATA_DECL(FCDATA_MAY_NEED_SCROLLFRAME, NS_NewFlexContainerFrame) },
+    { NS_STYLE_DISPLAY_GRID,
+      FCDATA_DECL(FCDATA_MAY_NEED_SCROLLFRAME, NS_NewGridContainerFrame) },
+    { NS_STYLE_DISPLAY_INLINE_GRID,
+      FCDATA_DECL(FCDATA_MAY_NEED_SCROLLFRAME, NS_NewGridContainerFrame) },
     { NS_STYLE_DISPLAY_TABLE,
       FULL_CTOR_FCDATA(0, &nsCSSFrameConstructor::ConstructTable) },
     { NS_STYLE_DISPLAY_INLINE_TABLE,
       FULL_CTOR_FCDATA(0, &nsCSSFrameConstructor::ConstructTable) },
     // NOTE: In the unlikely event that we add another table-part here that has
     // a desired-parent-type (& hence triggers table fixup), we'll need to also
     // update the flexbox chunk in nsStyleContext::ApplyStyleFixups().
     { NS_STYLE_DISPLAY_TABLE_CAPTION,
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -92,16 +92,17 @@ using namespace mozilla::layers;
 using namespace mozilla::layout;
 using namespace mozilla::gfx;
 
 using mozilla::image::Angle;
 using mozilla::image::Flip;
 using mozilla::image::ImageOps;
 using mozilla::image::Orientation;
 
+#define GRID_ENABLED_PREF_NAME "layout.css.grid.enabled"
 #define STICKY_ENABLED_PREF_NAME "layout.css.sticky.enabled"
 #define TEXT_ALIGN_TRUE_ENABLED_PREF_NAME "layout.css.text-align-true-value.enabled"
 
 #ifdef DEBUG
 // TODO: remove, see bug 598468.
 bool nsLayoutUtils::gPreventAssertInCompareTreePosition = false;
 #endif // DEBUG
 
@@ -123,16 +124,61 @@ typedef nsDataHashtable<nsUint64HashKey,
 static ContentMap* sContentMap = nullptr;
 static ContentMap& GetContentMap() {
   if (!sContentMap) {
     sContentMap = new ContentMap();
   }
   return *sContentMap;
 }
 
+// When the pref "layout.css.grid.enabled" changes, this function is invoked
+// to let us update kDisplayKTable, to selectively disable or restore the
+// entries for "grid" and "inline-grid" in that table.
+static void
+GridEnabledPrefChangeCallback(const char* aPrefName, void* aClosure)
+{
+  MOZ_ASSERT(strncmp(aPrefName, GRID_ENABLED_PREF_NAME,
+                     ArrayLength(GRID_ENABLED_PREF_NAME)) == 0,
+             "We only registered this callback for a single pref, so it "
+             "should only be called for that pref");
+
+  static int32_t sIndexOfGridInDisplayTable;
+  static int32_t sIndexOfInlineGridInDisplayTable;
+  static bool sAreGridKeywordIndicesInitialized; // initialized to false
+
+  bool isGridEnabled =
+    Preferences::GetBool(GRID_ENABLED_PREF_NAME, false);
+  if (!sAreGridKeywordIndicesInitialized) {
+    // First run: find the position of "grid" and "inline-grid" in
+    // kDisplayKTable.
+    sIndexOfGridInDisplayTable =
+      nsCSSProps::FindIndexOfKeyword(eCSSKeyword_grid,
+                                     nsCSSProps::kDisplayKTable);
+    MOZ_ASSERT(sIndexOfGridInDisplayTable >= 0,
+               "Couldn't find grid in kDisplayKTable");
+    sIndexOfInlineGridInDisplayTable =
+      nsCSSProps::FindIndexOfKeyword(eCSSKeyword_inline_grid,
+                                     nsCSSProps::kDisplayKTable);
+    MOZ_ASSERT(sIndexOfInlineGridInDisplayTable >= 0,
+               "Couldn't find inline-grid in kDisplayKTable");
+    sAreGridKeywordIndicesInitialized = true;
+  }
+
+  // OK -- now, stomp on or restore the "grid" entries in kDisplayKTable,
+  // depending on whether the grid pref is enabled vs. disabled.
+  if (sIndexOfGridInDisplayTable >= 0) {
+    nsCSSProps::kDisplayKTable[sIndexOfGridInDisplayTable] =
+      isGridEnabled ? eCSSKeyword_grid : eCSSKeyword_UNKNOWN;
+  }
+  if (sIndexOfInlineGridInDisplayTable >= 0) {
+    nsCSSProps::kDisplayKTable[sIndexOfInlineGridInDisplayTable] =
+      isGridEnabled ? eCSSKeyword_inline_grid : eCSSKeyword_UNKNOWN;
+  }
+}
+
 // When the pref "layout.css.sticky.enabled" changes, this function is invoked
 // to let us update kPositionKTable, to selectively disable or restore the
 // entry for "sticky" in that table.
 static void
 StickyEnabledPrefChangeCallback(const char* aPrefName, void* aClosure)
 {
   MOZ_ASSERT(strncmp(aPrefName, STICKY_ENABLED_PREF_NAME,
                      ArrayLength(STICKY_ENABLED_PREF_NAME)) == 0,
@@ -5318,16 +5364,19 @@ nsLayoutUtils::Initialize()
                                "font.size.inflation.forceEnabled");
   Preferences::AddBoolVarCache(&sFontSizeInflationDisabledInMasterProcess,
                                "font.size.inflation.disabledInMasterProcess");
   Preferences::AddBoolVarCache(&sInvalidationDebuggingIsEnabled,
                                "nglayout.debug.invalidation");
   Preferences::AddBoolVarCache(&sCSSVariablesEnabled,
                                "layout.css.variables.enabled");
 
+  Preferences::RegisterCallback(GridEnabledPrefChangeCallback,
+                                GRID_ENABLED_PREF_NAME);
+  GridEnabledPrefChangeCallback(GRID_ENABLED_PREF_NAME, nullptr);
   Preferences::RegisterCallback(StickyEnabledPrefChangeCallback,
                                 STICKY_ENABLED_PREF_NAME);
   StickyEnabledPrefChangeCallback(STICKY_ENABLED_PREF_NAME, nullptr);
   Preferences::RegisterCallback(TextAlignTrueEnabledPrefChangeCallback,
                                 TEXT_ALIGN_TRUE_ENABLED_PREF_NAME);
   TextAlignTrueEnabledPrefChangeCallback(TEXT_ALIGN_TRUE_ENABLED_PREF_NAME,
                                          nullptr);
 
@@ -5338,16 +5387,18 @@ nsLayoutUtils::Initialize()
 void
 nsLayoutUtils::Shutdown()
 {
   if (sContentMap) {
     delete sContentMap;
     sContentMap = nullptr;
   }
 
+  Preferences::UnregisterCallback(GridEnabledPrefChangeCallback,
+                                  GRID_ENABLED_PREF_NAME);
   Preferences::UnregisterCallback(StickyEnabledPrefChangeCallback,
                                   STICKY_ENABLED_PREF_NAME);
 
   nsComputedDOMStyle::UnregisterPrefChangeCallbacks();
 }
 
 /* static */
 void
--- a/layout/generic/moz.build
+++ b/layout/generic/moz.build
@@ -59,16 +59,17 @@ UNIFIED_SOURCES += [
     'nsFloatManager.cpp',
     'nsFontInflationData.cpp',
     'nsFrame.cpp',
     'nsFrameList.cpp',
     'nsFrameSetFrame.cpp',
     'nsFrameState.cpp',
     'nsFrameUtil.cpp',
     'nsGfxScrollFrame.cpp',
+    'nsGridContainerFrame.cpp',
     'nsHTMLCanvasFrame.cpp',
     'nsHTMLReflowMetrics.cpp',
     'nsHTMLReflowState.cpp',
     'nsImageFrame.cpp',
     'nsImageMap.cpp',
     'nsInlineFrame.cpp',
     'nsIntervalSet.cpp',
     'nsLeafFrame.cpp',
--- a/layout/generic/nsFrameIdList.h
+++ b/layout/generic/nsFrameIdList.h
@@ -24,16 +24,17 @@ FRAME_ID(nsFileControlFrame)
 FRAME_ID(nsFirstLetterFrame)
 FRAME_ID(nsFirstLineFrame)
 FRAME_ID(nsFlexContainerFrame)
 FRAME_ID(nsFormControlFrame)
 FRAME_ID(nsFrame)
 FRAME_ID(nsGfxButtonControlFrame)
 FRAME_ID(nsGfxCheckboxControlFrame)
 FRAME_ID(nsGfxRadioControlFrame)
+FRAME_ID(nsGridContainerFrame)
 FRAME_ID(nsGridRowGroupFrame)
 FRAME_ID(nsGridRowLeafFrame)
 FRAME_ID(nsGroupBoxFrame)
 FRAME_ID(nsHTMLButtonControlFrame)
 FRAME_ID(nsHTMLCanvasFrame)
 FRAME_ID(nsHTMLFramesetBlankFrame)
 FRAME_ID(nsHTMLFramesetBorderFrame)
 FRAME_ID(nsHTMLFramesetFrame)
new file mode 100644
--- /dev/null
+++ b/layout/generic/nsGridContainerFrame.cpp
@@ -0,0 +1,55 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+
+/* This Source Code is subject to the terms of the Mozilla Public License
+ * version 2.0 (the "License"). You can obtain a copy of the License at
+ * http://mozilla.org/MPL/2.0/. */
+
+/* rendering object for CSS "display: grid" */
+
+#include "nsGridContainerFrame.h"
+#include "nsPresContext.h"
+#include "nsStyleContext.h"
+
+//----------------------------------------------------------------------
+
+// Frame class boilerplate
+// =======================
+
+NS_QUERYFRAME_HEAD(nsGridContainerFrame)
+  NS_QUERYFRAME_ENTRY(nsGridContainerFrame)
+NS_QUERYFRAME_TAIL_INHERITING(nsGridContainerFrameSuper)
+
+NS_IMPL_FRAMEARENA_HELPERS(nsGridContainerFrame)
+
+nsIFrame*
+NS_NewGridContainerFrame(nsIPresShell* aPresShell,
+                         nsStyleContext* aContext)
+{
+  return new (aPresShell) nsGridContainerFrame(aContext);
+}
+
+
+//----------------------------------------------------------------------
+
+// nsGridContainerFrame Method Implementations
+// ===========================================
+
+/* virtual */
+nsGridContainerFrame::~nsGridContainerFrame()
+{
+}
+
+nsIAtom*
+nsGridContainerFrame::GetType() const
+{
+  return nsGkAtoms::gridContainerFrame;
+}
+
+#ifdef DEBUG_FRAME_DUMP
+nsresult
+nsGridContainerFrame::GetFrameName(nsAString& aResult) const
+{
+  return MakeFrameName(NS_LITERAL_STRING("GridContainer"), aResult);
+}
+#endif
new file mode 100644
--- /dev/null
+++ b/layout/generic/nsGridContainerFrame.h
@@ -0,0 +1,43 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+
+/* This Source Code is subject to the terms of the Mozilla Public License
+ * version 2.0 (the "License"). You can obtain a copy of the License at
+ * http://mozilla.org/MPL/2.0/. */
+
+/* rendering object for CSS "display: grid" */
+
+#ifndef nsGridContainerFrame_h___
+#define nsGridContainerFrame_h___
+
+#include "nsContainerFrame.h"
+
+nsIFrame* NS_NewGridContainerFrame(nsIPresShell* aPresShell,
+                                   nsStyleContext* aContext);
+
+typedef nsContainerFrame nsGridContainerFrameSuper;
+
+class nsGridContainerFrame : public nsGridContainerFrameSuper {
+
+  NS_DECL_FRAMEARENA_HELPERS
+  NS_DECL_QUERYFRAME_TARGET(nsGridContainerFrame)
+  NS_DECL_QUERYFRAME
+
+  // Factory method:
+  friend nsIFrame* NS_NewGridContainerFrame(nsIPresShell* aPresShell,
+                                            nsStyleContext* aContext);
+
+public:
+  // nsIFrame overrides
+  virtual nsIAtom* GetType() const MOZ_OVERRIDE;
+#ifdef DEBUG_FRAME_DUMP
+  virtual nsresult GetFrameName(nsAString& aResult) const MOZ_OVERRIDE;
+#endif
+
+protected:
+  // Protected constructor & destructor
+  nsGridContainerFrame(nsStyleContext* aContext) : nsGridContainerFrameSuper(aContext) {}
+  virtual ~nsGridContainerFrame();
+};
+
+#endif /* nsGridContainerFrame_h___ */
--- a/layout/inspector/tests/test_bug877690.html
+++ b/layout/inspector/tests/test_bug877690.html
@@ -155,17 +155,17 @@ function do_test() {
 
   // test proprety
   var prop = "display";
   var values = utils.getCSSValuesForProperty(prop);
   var expected = [ "initial", "inherit", "unset", "none", "inline", "block", "inline-block", "list-item",
       "table", "inline-table", "table-row-group", "table-header-group", "table-footer-group", "table-row",
       "table-column-group", "table-column", "table-cell", "table-caption", "-moz-box", "-moz-inline-box",
       "-moz-grid", "-moz-inline-grid", "-moz-grid-group", "-moz-grid-line", "-moz-stack", "-moz-inline-stack",
-      "-moz-deck", "-moz-popup", "-moz-groupbox", "flex", "inline-flex" ];
+      "-moz-deck", "-moz-popup", "-moz-groupbox", "flex", "inline-flex", "grid", "inline-grid" ];
   ok(testValues(values, expected), "property display's values.");
 
   // test property
   var prop = "float";
   var values = utils.getCSSValuesForProperty(prop);
   var expected = [ "initial", "inherit", "unset", "none", "left", "right" ];
   ok(testValues(values, expected), "proprety float values");
 
--- a/layout/style/nsCSSKeywordList.h
+++ b/layout/style/nsCSSKeywordList.h
@@ -289,16 +289,17 @@ CSS_KEY(fraktur, fraktur)
 CSS_KEY(from-image, from_image)
 CSS_KEY(full-width, full_width)
 CSS_KEY(georgian, georgian)
 CSS_KEY(grab, grab)
 CSS_KEY(grabbing, grabbing)
 CSS_KEY(grad, grad)
 CSS_KEY(grayscale, grayscale)
 CSS_KEY(graytext, graytext)
+CSS_KEY(grid, grid)
 CSS_KEY(groove, groove)
 CSS_KEY(hard-light, hard_light)
 CSS_KEY(hebrew, hebrew)
 CSS_KEY(help, help)
 CSS_KEY(hidden, hidden)
 CSS_KEY(hide, hide)
 CSS_KEY(highlight, highlight)
 CSS_KEY(highlighttext, highlighttext)
@@ -323,16 +324,17 @@ CSS_KEY(infinite, infinite)
 CSS_KEY(infobackground, infobackground)
 CSS_KEY(infotext, infotext)
 CSS_KEY(inherit, inherit)
 CSS_KEY(initial, initial)
 CSS_KEY(inline, inline)
 CSS_KEY(inline-axis, inline_axis)
 CSS_KEY(inline-block, inline_block)
 CSS_KEY(inline-flex, inline_flex)
+CSS_KEY(inline-grid, inline_grid)
 CSS_KEY(inline-table, inline_table)
 CSS_KEY(inset, inset)
 CSS_KEY(inside, inside)
 CSS_KEY(interpolatematrix, interpolatematrix)
 CSS_KEY(invert, invert)
 CSS_KEY(italic, italic)
 CSS_KEY(japanese-formal, japanese_formal)
 CSS_KEY(japanese-informal, japanese_informal)
--- a/layout/style/nsCSSProps.cpp
+++ b/layout/style/nsCSSProps.cpp
@@ -973,17 +973,17 @@ const KTableValue nsCSSProps::kCursorKTa
 };
 
 const KTableValue nsCSSProps::kDirectionKTable[] = {
   eCSSKeyword_ltr,      NS_STYLE_DIRECTION_LTR,
   eCSSKeyword_rtl,      NS_STYLE_DIRECTION_RTL,
   eCSSKeyword_UNKNOWN,-1
 };
 
-const KTableValue nsCSSProps::kDisplayKTable[] = {
+KTableValue nsCSSProps::kDisplayKTable[] = {
   eCSSKeyword_none,               NS_STYLE_DISPLAY_NONE,
   eCSSKeyword_inline,             NS_STYLE_DISPLAY_INLINE,
   eCSSKeyword_block,              NS_STYLE_DISPLAY_BLOCK,
   eCSSKeyword_inline_block,       NS_STYLE_DISPLAY_INLINE_BLOCK,
   eCSSKeyword_list_item,          NS_STYLE_DISPLAY_LIST_ITEM,
   eCSSKeyword_table,              NS_STYLE_DISPLAY_TABLE,
   eCSSKeyword_inline_table,       NS_STYLE_DISPLAY_INLINE_TABLE,
   eCSSKeyword_table_row_group,    NS_STYLE_DISPLAY_TABLE_ROW_GROUP,
@@ -1006,16 +1006,19 @@ const KTableValue nsCSSProps::kDisplayKT
   eCSSKeyword__moz_stack,         NS_STYLE_DISPLAY_STACK,
   eCSSKeyword__moz_inline_stack,  NS_STYLE_DISPLAY_INLINE_STACK,
   eCSSKeyword__moz_deck,          NS_STYLE_DISPLAY_DECK,
   eCSSKeyword__moz_popup,         NS_STYLE_DISPLAY_POPUP,
   eCSSKeyword__moz_groupbox,      NS_STYLE_DISPLAY_GROUPBOX,
 #endif
   eCSSKeyword_flex,               NS_STYLE_DISPLAY_FLEX,
   eCSSKeyword_inline_flex,        NS_STYLE_DISPLAY_INLINE_FLEX,
+  // The next two entries are controlled by the layout.css.grid.enabled pref.
+  eCSSKeyword_grid,               NS_STYLE_DISPLAY_GRID,
+  eCSSKeyword_inline_grid,        NS_STYLE_DISPLAY_INLINE_GRID,
   eCSSKeyword_UNKNOWN,-1
 };
 
 const KTableValue nsCSSProps::kEmptyCellsKTable[] = {
   eCSSKeyword_show,                 NS_STYLE_TABLE_EMPTY_CELLS_SHOW,
   eCSSKeyword_hide,                 NS_STYLE_TABLE_EMPTY_CELLS_HIDE,
   eCSSKeyword__moz_show_background, NS_STYLE_TABLE_EMPTY_CELLS_SHOW_BACKGROUND,
   eCSSKeyword_UNKNOWN,-1
--- a/layout/style/nsCSSProps.h
+++ b/layout/style/nsCSSProps.h
@@ -507,17 +507,19 @@ public:
   static const KTableValue kBoxSizingKTable[];
   static const KTableValue kCaptionSideKTable[];
   static const KTableValue kClearKTable[];
   static const KTableValue kColorKTable[];
   static const KTableValue kContentKTable[];
   static const KTableValue kControlCharacterVisibilityKTable[];
   static const KTableValue kCursorKTable[];
   static const KTableValue kDirectionKTable[];
-  static const KTableValue kDisplayKTable[];
+  // Not const because we modify its entries when the pref
+  // "layout.css.grid.enabled" changes:
+  static KTableValue kDisplayKTable[];
   static const KTableValue kElevationKTable[];
   static const KTableValue kEmptyCellsKTable[];
   static const KTableValue kAlignContentKTable[];
   static const KTableValue kAlignItemsKTable[];
   static const KTableValue kAlignSelfKTable[];
   static const KTableValue kFlexDirectionKTable[];
   static const KTableValue kFlexWrapKTable[];
   static const KTableValue kJustifyContentKTable[];
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -146,16 +146,17 @@ nsRuleNode::EnsureBlockDisplay(uint8_t& 
       display = NS_STYLE_DISPLAY_BLOCK;
       break;
     } // else, fall through to share the 'break' for non-changing display vals
   case NS_STYLE_DISPLAY_NONE :
     // never change display:none *ever*
   case NS_STYLE_DISPLAY_TABLE :
   case NS_STYLE_DISPLAY_BLOCK :
   case NS_STYLE_DISPLAY_FLEX :
+  case NS_STYLE_DISPLAY_GRID :
     // do not muck with these at all - already blocks
     // This is equivalent to nsStyleDisplay::IsBlockOutside.  (XXX Maybe we
     // should just call that?)
     // This needs to match the check done in
     // nsCSSFrameConstructor::FindMathMLData for <math>.
     break;
 
   case NS_STYLE_DISPLAY_INLINE_TABLE :
@@ -163,16 +164,21 @@ nsRuleNode::EnsureBlockDisplay(uint8_t& 
     display = NS_STYLE_DISPLAY_TABLE;
     break;
 
   case NS_STYLE_DISPLAY_INLINE_FLEX:
     // make inline flex containers into flex containers
     display = NS_STYLE_DISPLAY_FLEX;
     break;
 
+  case NS_STYLE_DISPLAY_INLINE_GRID:
+    // make inline grid containers into grid containers
+    display = NS_STYLE_DISPLAY_GRID;
+    break;
+
   default :
     // make it a block
     display = NS_STYLE_DISPLAY_BLOCK;
   }
 }
 
 static nscoord CalcLengthWith(const nsCSSValue& aValue,
                               nscoord aFontSize,
--- a/layout/style/nsStyleConsts.h
+++ b/layout/style/nsStyleConsts.h
@@ -402,16 +402,18 @@ static inline mozilla::css::Side operato
 #define NS_STYLE_DISPLAY_STACK                  24
 #define NS_STYLE_DISPLAY_INLINE_STACK           25
 #define NS_STYLE_DISPLAY_DECK                   26
 #define NS_STYLE_DISPLAY_POPUP                  27
 #define NS_STYLE_DISPLAY_GROUPBOX               28
 #endif
 #define NS_STYLE_DISPLAY_FLEX                   29
 #define NS_STYLE_DISPLAY_INLINE_FLEX            30
+#define NS_STYLE_DISPLAY_GRID                   31
+#define NS_STYLE_DISPLAY_INLINE_GRID            32
 
 // See nsStylePosition
 #define NS_STYLE_ALIGN_CONTENT_FLEX_START       0
 #define NS_STYLE_ALIGN_CONTENT_FLEX_END         1
 #define NS_STYLE_ALIGN_CONTENT_CENTER           2
 #define NS_STYLE_ALIGN_CONTENT_SPACE_BETWEEN    3
 #define NS_STYLE_ALIGN_CONTENT_SPACE_AROUND     4
 #define NS_STYLE_ALIGN_CONTENT_STRETCH          5
--- a/layout/style/nsStyleContext.cpp
+++ b/layout/style/nsStyleContext.cpp
@@ -349,25 +349,27 @@ nsStyleContext::ApplyStyleFixups(bool aS
       // isn't living in the ruletree anyway), and for determining
       // hypothetical boxes it's better to have mOriginalDisplay
       // matching mDisplay here.
       mutable_display->mOriginalDisplay = mutable_display->mDisplay =
         displayVal;
     }
   }
 
-  // Adjust the "display" values of flex items (but not for raw text,
+  // Adjust the "display" values of flex and grid items (but not for raw text,
   // placeholders, or table-parts). CSS3 Flexbox section 4 says:
   //   # The computed 'display' of a flex item is determined
   //   # by applying the table in CSS 2.1 Chapter 9.7.
   // ...which converts inline-level elements to their block-level equivalents.
   if (!aSkipFlexItemStyleFixup && mParent) {
     const nsStyleDisplay* parentDisp = mParent->StyleDisplay();
     if ((parentDisp->mDisplay == NS_STYLE_DISPLAY_FLEX ||
-         parentDisp->mDisplay == NS_STYLE_DISPLAY_INLINE_FLEX) &&
+         parentDisp->mDisplay == NS_STYLE_DISPLAY_INLINE_FLEX ||
+         parentDisp->mDisplay == NS_STYLE_DISPLAY_GRID ||
+         parentDisp->mDisplay == NS_STYLE_DISPLAY_INLINE_GRID) &&
         GetPseudo() != nsCSSAnonBoxes::mozNonElement) {
       uint8_t displayVal = disp->mDisplay;
       // Skip table parts.
       // NOTE: This list needs to be kept in sync with
       // nsCSSFrameConstructor.cpp's "sDisplayData" array -- specifically,
       // this should be the list of display-values that have
       // FCDATA_DESIRED_PARENT_TYPE_TO_BITS specified in that array.
       if (NS_STYLE_DISPLAY_TABLE_CAPTION      != displayVal &&
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -1850,26 +1850,28 @@ struct nsStyleDisplay {
     // Should TABLE_CELL and TABLE_CAPTION go here?  They have
     // block frames nested inside of them.
     // (But please audit all callers before changing.)
   }
 
   bool IsBlockOutsideStyle() const {
     return NS_STYLE_DISPLAY_BLOCK == mDisplay ||
            NS_STYLE_DISPLAY_FLEX == mDisplay ||
+           NS_STYLE_DISPLAY_GRID == mDisplay ||
            NS_STYLE_DISPLAY_LIST_ITEM == mDisplay ||
            NS_STYLE_DISPLAY_TABLE == mDisplay;
   }
 
   static bool IsDisplayTypeInlineOutside(uint8_t aDisplay) {
     return NS_STYLE_DISPLAY_INLINE == aDisplay ||
            NS_STYLE_DISPLAY_INLINE_BLOCK == aDisplay ||
            NS_STYLE_DISPLAY_INLINE_TABLE == aDisplay ||
            NS_STYLE_DISPLAY_INLINE_BOX == aDisplay ||
            NS_STYLE_DISPLAY_INLINE_FLEX == aDisplay ||
+           NS_STYLE_DISPLAY_INLINE_GRID == aDisplay ||
            NS_STYLE_DISPLAY_INLINE_XUL_GRID == aDisplay ||
            NS_STYLE_DISPLAY_INLINE_STACK == aDisplay;
   }
 
   bool IsInlineOutsideStyle() const {
     return IsDisplayTypeInlineOutside(mDisplay);
   }
 
--- a/layout/style/test/property_database.js
+++ b/layout/style/test/property_database.js
@@ -4785,16 +4785,20 @@ if (SpecialPowers.getBoolPref("layout.cs
 			"sepia(0.5, 0.5)",
 			"sepia(#my-filter)",
 			"sepia(10px)",
 			"sepia(-1)",
 		]
 	};
 }
 
+if (SpecialPowers.getBoolPref("layout.css.grid.enabled")) {
+	gCSSProperties["display"].other_values.push("grid", "inline-grid");
+}
+
 if (SpecialPowers.getBoolPref("layout.css.image-orientation.enabled")) {
 	gCSSProperties["image-orientation"] = {
 		domProp: "imageOrientation",
 		inherited: true,
 		type: CSS_TYPE_LONGHAND,
 		initial_values: [
 			"0deg",
 			"0grad",
--- a/testing/profiles/prefs_general.js
+++ b/testing/profiles/prefs_general.js
@@ -110,16 +110,19 @@ user_pref("datareporting.policy.dataSubm
 
 // Point Firefox Health Report at a local server. We don't care if it actually
 // works. It just can't hit the default production endpoint.
 user_pref("datareporting.healthreport.documentServerURI", "http://%(server)s/healthreport/");
 
 // Make sure CSS error reporting is enabled for tests
 user_pref("layout.css.report_errors", true);
 
+// Enable CSS Grid for testing
+user_pref("layout.css.grid.enabled", true);
+
 // Enable mozContacts
 user_pref("dom.mozContacts.enabled", true);
 user_pref("dom.navigator-property.disable.mozContacts", false);
 user_pref("dom.global-constructor.disable.mozContact", false);
 
 // Enable mozSettings
 user_pref("dom.mozSettings.enabled", true);