Bug 1398963 part 7: Add an about:config flag to optionally emulate -moz-box with flexbox. r?mats draft
authorDaniel Holbert <dholbert@cs.stanford.edu>
Thu, 26 Oct 2017 11:12:17 -0700
changeset 712755 7e4d04726b331b63ccb1b5886caf1861e4ef5d42
parent 712754 0fa6b57e0a117564594baad354c09c9f5fbde8d6
child 744125 11ce50eaaa2116990eb904cf39f4e694a620ad86
push id93413
push userdholbert@mozilla.com
push dateMon, 18 Dec 2017 18:17:28 +0000
reviewersmats
bugs1398963
milestone59.0a1
Bug 1398963 part 7: Add an about:config flag to optionally emulate -moz-box with flexbox. r?mats This feature is intended to help Firefox frontend developers experiment with replacing XUL content with modern flexbox. We might also eventually use this emulation to *actually* render most or all of our legacy XUL UI. MozReview-Commit-ID: 3g2W9o3t23H
layout/base/nsCSSFrameConstructor.cpp
layout/style/StylePrefs.cpp
layout/style/StylePrefs.h
modules/libpref/init/all.js
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -86,16 +86,17 @@
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/ElementInlines.h"
 #include "nsAutoLayoutPhase.h"
 #include "nsStyleStructInlines.h"
 #include "nsPageContentFrame.h"
 #include "mozilla/GeckoStyleContext.h"
 #include "mozilla/RestyleManager.h"
 #include "mozilla/RestyleManagerInlines.h"
+#include "mozilla/StylePrefs.h"
 #include "StickyScrollContainer.h"
 #include "nsFieldSetFrame.h"
 #include "nsInlineFrame.h"
 #include "nsBlockFrame.h"
 #include "nsCanvasFrame.h"
 #include "nsFirstLetterFrame.h"
 #include "nsGfxScrollFrame.h"
 #include "nsPageFrame.h"
@@ -2683,17 +2684,19 @@ nsCSSFrameConstructor::ConstructDocEleme
     nsFrameItems frameItems;
     contentFrame = static_cast<nsContainerFrame*>(
       ConstructOuterSVG(state, item, mDocElementContainingBlock,
                         styleContext->StyleDisplay(),
                         frameItems));
     newFrame = frameItems.FirstChild();
     NS_ASSERTION(frameItems.OnlyChild(), "multiple root element frames");
   } else if (display->mDisplay == StyleDisplay::Flex ||
-             display->mDisplay == StyleDisplay::WebkitBox) {
+             display->mDisplay == StyleDisplay::WebkitBox ||
+             (StylePrefs::sEmulateMozBoxWithFlex &&
+              display->mDisplay == StyleDisplay::MozBox)) {
     contentFrame = NS_NewFlexContainerFrame(mPresShell, styleContext);
     InitAndRestoreFrame(state, aDocElement, mDocElementContainingBlock,
                         contentFrame);
     newFrame = contentFrame;
     processChildren = true;
 
     newFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
     if (display->IsAbsPosContainingBlock(newFrame)) {
@@ -4392,18 +4395,20 @@ nsCSSFrameConstructor::GetAnonymousConte
   }
 
   return NS_OK;
 }
 
 static
 bool IsXULDisplayType(const nsStyleDisplay* aDisplay)
 {
-  if  (aDisplay->mDisplay == StyleDisplay::MozInlineBox ||
-       aDisplay->mDisplay == StyleDisplay::MozBox) {
+  // -moz-{inline-}box is XUL, unless we're emulating it with flexbox.
+  if  (!StylePrefs::sEmulateMozBoxWithFlex &&
+       (aDisplay->mDisplay == StyleDisplay::MozInlineBox ||
+        aDisplay->mDisplay == StyleDisplay::MozBox)) {
     return true;
   }
 
 #ifdef MOZ_XUL
   return (aDisplay->mDisplay == StyleDisplay::MozInlineGrid ||
           aDisplay->mDisplay == StyleDisplay::MozInlineStack ||
           aDisplay->mDisplay == StyleDisplay::MozGrid ||
           aDisplay->mDisplay == StyleDisplay::MozStack ||
@@ -4643,16 +4648,27 @@ nsCSSFrameConstructor::FindXULDisplayDat
                   FCDATA_SKIP_ABSPOS_PUSH, NS_NewMenuPopupFrame))
 #endif /* MOZ_XUL */
   };
 
   if (aDisplay->mDisplay < StyleDisplay::MozBox) {
     return nullptr;
   }
 
+  // If we're emulating -moz-box with flexbox, then treat it as non-XUL and
+  // return null (except for scrollcorners which have to be XUL becuase their
+  // parent reflows them with BoxReflow() which means they have to get
+  // actual-XUL frames).
+  if (StylePrefs::sEmulateMozBoxWithFlex &&
+      aElement && !aElement->IsXULElement(nsGkAtoms::scrollcorner) &&
+      (aDisplay->mDisplay == StyleDisplay::MozBox ||
+       aDisplay->mDisplay == StyleDisplay::MozInlineBox)) {
+    return nullptr;
+  }
+
   MOZ_ASSERT(aDisplay->mDisplay <= StyleDisplay::MozPopup,
              "Someone added a new display value?");
 
   const FrameConstructionDataByDisplay& data =
     sXULDisplayData[size_t(aDisplay->mDisplay) - size_t(StyleDisplay::MozBox)];
   MOZ_ASSERT(aDisplay->mDisplay == data.mDisplay,
              "Did someone mess with the order?");
 
@@ -4869,17 +4885,19 @@ nsCSSFrameConstructor::FindDisplayData(c
     return &sNonScrollableBlockData[suppressScrollFrame][caption];
   }
 
   // If this is for a <body> node and we've propagated the scroll-frame to the
   // viewport, we need to make sure not to add another layer of scrollbars, so
   // we use a different FCData struct without FCDATA_MAY_NEED_SCROLLFRAME.
   if (propagatedScrollToViewport && aDisplay->IsScrollableOverflow()) {
     if (aDisplay->mDisplay == StyleDisplay::Flex ||
-        aDisplay->mDisplay == StyleDisplay::WebkitBox) {
+        aDisplay->mDisplay == StyleDisplay::WebkitBox ||
+        (StylePrefs::sEmulateMozBoxWithFlex &&
+         aDisplay->mDisplay == StyleDisplay::MozBox)) {
       static const FrameConstructionData sNonScrollableFlexData =
         FCDATA_DECL(0, NS_NewFlexContainerFrame);
       return &sNonScrollableFlexData;
     }
     if (aDisplay->mDisplay == StyleDisplay::Grid) {
       static const FrameConstructionData sNonScrollableGridData =
         FCDATA_DECL(0, NS_NewGridContainerFrame);
       return &sNonScrollableGridData;
@@ -4963,20 +4981,27 @@ nsCSSFrameConstructor::FindDisplayData(c
       FCDATA_DECL(FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRuby),
                   NS_NewRubyTextContainerFrame)),
     FCDATA_FOR_DISPLAY(StyleDisplay::Contents,
       FULL_CTOR_FCDATA(FCDATA_IS_CONTENTS, nullptr/*never called*/)),
     FCDATA_FOR_DISPLAY(StyleDisplay::WebkitBox,
       FCDATA_DECL(FCDATA_MAY_NEED_SCROLLFRAME, NS_NewFlexContainerFrame)),
     FCDATA_FOR_DISPLAY(StyleDisplay::WebkitInlineBox,
       FCDATA_DECL(FCDATA_MAY_NEED_SCROLLFRAME, NS_NewFlexContainerFrame)),
+    FCDATA_FOR_DISPLAY(StyleDisplay::MozBox,
+      FCDATA_DECL(FCDATA_MAY_NEED_SCROLLFRAME, NS_NewFlexContainerFrame)),
+    FCDATA_FOR_DISPLAY(StyleDisplay::MozInlineBox,
+      FCDATA_DECL(FCDATA_MAY_NEED_SCROLLFRAME, NS_NewFlexContainerFrame)),
   };
-  static_assert(ArrayLength(sDisplayData) == size_t(StyleDisplay::WebkitInlineBox) + 1,
+  static_assert(ArrayLength(sDisplayData) == size_t(StyleDisplay::MozInlineBox) + 1,
                 "Be sure to update sDisplayData if you touch StyleDisplay");
-
+  MOZ_ASSERT(StylePrefs::sEmulateMozBoxWithFlex ||
+             (aDisplay->mDisplay != StyleDisplay::MozBox &&
+              aDisplay->mDisplay != StyleDisplay::MozInlineBox),
+             "-moz-{inline-}box as XUL should have already been handled");
   MOZ_ASSERT(size_t(aDisplay->mDisplay) < ArrayLength(sDisplayData),
              "XUL display data should have already been handled");
 
   // See the mDisplay fixup code in nsRuleNode::ComputeDisplayData.
   MOZ_ASSERT(aDisplay->mDisplay != StyleDisplay::Contents ||
              !aElement->IsRootOfNativeAnonymousSubtree(),
              "display:contents on anonymous content is unsupported");
 
--- a/layout/style/StylePrefs.cpp
+++ b/layout/style/StylePrefs.cpp
@@ -16,16 +16,17 @@ bool StylePrefs::sWebkitPrefixedAliasesE
 bool StylePrefs::sWebkitDevicePixelRatioEnabled;
 bool StylePrefs::sMozGradientsEnabled;
 bool StylePrefs::sControlCharVisibility;
 bool StylePrefs::sFramesTimingFunctionEnabled;
 bool StylePrefs::sUnprefixedFullscreenApiEnabled;
 bool StylePrefs::sVisitedLinksEnabled;
 bool StylePrefs::sMozDocumentEnabledInContent;
 bool StylePrefs::sGridTemplateSubgridValueEnabled;
+bool StylePrefs::sEmulateMozBoxWithFlex;
 
 /* static */ void
 StylePrefs::Init()
 {
   Preferences::AddBoolVarCache(&sFontDisplayEnabled,
                                "layout.css.font-display.enabled");
   Preferences::AddBoolVarCache(&sOpentypeSVGEnabled,
                                "gfx.font_rendering.opentype_svg.enabled");
@@ -42,11 +43,18 @@ StylePrefs::Init()
   Preferences::AddBoolVarCache(&sUnprefixedFullscreenApiEnabled,
                                "full-screen-api.unprefix.enabled");
   Preferences::AddBoolVarCache(&sVisitedLinksEnabled,
                                "layout.css.visited_links_enabled");
   Preferences::AddBoolVarCache(&sMozDocumentEnabledInContent,
                                "layout.css.moz-document.content.enabled");
   Preferences::AddBoolVarCache(&sGridTemplateSubgridValueEnabled,
                                "layout.css.grid-template-subgrid-value.enabled");
+
+  // Only honor layout.css.emulate-moz-box-with-flex in prerelease builds.
+  // (In release builds, sEmulateMozBoxWithFlex will be implicitly false.)
+#ifndef RELEASE_OR_BETA
+  Preferences::AddBoolVarCache(&sEmulateMozBoxWithFlex,
+                               "layout.css.emulate-moz-box-with-flex");
+#endif
 }
 
 } // namespace mozilla
--- a/layout/style/StylePrefs.h
+++ b/layout/style/StylePrefs.h
@@ -19,15 +19,16 @@ struct StylePrefs
   static bool sWebkitDevicePixelRatioEnabled;
   static bool sMozGradientsEnabled;
   static bool sControlCharVisibility;
   static bool sFramesTimingFunctionEnabled;
   static bool sUnprefixedFullscreenApiEnabled;
   static bool sVisitedLinksEnabled;
   static bool sMozDocumentEnabledInContent;
   static bool sGridTemplateSubgridValueEnabled;
+  static bool sEmulateMozBoxWithFlex;
 
   static void Init();
 };
 
 } // namespace mozilla
 
 #endif // mozilla_StylePrefs_h
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -2966,16 +2966,23 @@ pref("layout.css.font-variations.enabled
 
 // Is support for the frames() timing function enabled?
 #ifdef RELEASE_OR_BETA
 pref("layout.css.frames-timing.enabled", false);
 #else
 pref("layout.css.frames-timing.enabled", true);
 #endif
 
+// Are we emulating -moz-{inline}-box layout using CSS flexbox?
+// (This pref only takes effect in prerelease builds, so we only
+// bother specifying a default in prerelease builds as well.)
+#ifndef RELEASE_OR_BETA
+pref("layout.css.emulate-moz-box-with-flex", false);
+#endif
+
 // Are sets of prefixed properties supported?
 pref("layout.css.prefixes.border-image", true);
 pref("layout.css.prefixes.transforms", true);
 pref("layout.css.prefixes.transitions", true);
 pref("layout.css.prefixes.animations", true);
 pref("layout.css.prefixes.box-sizing", true);
 pref("layout.css.prefixes.font-features", true);