Bug 666041 patch 2: Add "-moz-flex" & "-moz-inline-flex" values for "display" property. r=bz
authorDaniel Holbert <dholbert@cs.stanford.edu>
Tue, 26 Jun 2012 15:11:38 -0700
changeset 97733 56ccb1deb91d32bef937cc51a76f28e8d2ed31d7
parent 97732 5ab2723fc0e02fd706cdce07051cc6b80195c275
child 97734 4a363e159fb6704dca6d66cb6148df2d09b43942
push id22993
push useremorley@mozilla.com
push dateWed, 27 Jun 2012 10:31:27 +0000
treeherdermozilla-central@1a56f1f011c9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs666041
milestone16.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 666041 patch 2: Add "-moz-flex" & "-moz-inline-flex" values for "display" property. r=bz
content/base/src/nsGkAtomList.h
layout/base/nsCSSFrameConstructor.cpp
layout/base/nsCSSFrameConstructor.h
layout/base/nsStyleConsts.h
layout/style/nsCSSAnonBoxList.h
layout/style/nsCSSKeywordList.h
layout/style/nsCSSProps.cpp
layout/style/nsRuleNode.cpp
layout/style/nsStyleStruct.h
layout/style/test/property_database.js
layout/style/ua.css
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -1679,16 +1679,17 @@ GK_ATOM(blockFrame, "BlockFrame")
 GK_ATOM(boxFrame, "BoxFrame")
 GK_ATOM(brFrame, "BRFrame")
 GK_ATOM(bulletFrame, "BulletFrame")
 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(HTMLButtonControlFrame, "HTMLButtonControlFrame")
 GK_ATOM(HTMLCanvasFrame, "HTMLCanvasFrame")
 GK_ATOM(subDocumentFrame, "subDocumentFrame")
 GK_ATOM(imageBoxFrame, "ImageBoxFrame")
 GK_ATOM(imageFrame, "ImageFrame")
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -361,16 +361,30 @@ IsInlineOutside(nsIFrame* aFrame)
  */
 static bool
 IsInlineFrame(const nsIFrame* aFrame)
 {
   return aFrame->IsFrameOfType(nsIFrame::eLineParticipant);
 }
 
 /**
+ * Returns true iff aFrame explicitly prevents its descendants from floating
+ * (at least, down to the level of descendants which themselves are
+ * 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;
+}
+
+/**
  * If any children require a block parent, return the first such child.
  * Otherwise return null.
  */
 static nsIContent*
 AnyKidsNeedBlockParent(nsIFrame *aFrameList)
 {
   for (nsIFrame *k = aFrameList; k; k = k->GetNextSibling()) {
     // Line participants, such as text and inline frames, can't be
@@ -3679,16 +3693,24 @@ nsCSSFrameConstructor::ConstructFrameFro
       aState.PushAbsoluteContainingBlock(nsnull, absoluteSaveState);
     } else if (!(bits & FCDATA_SKIP_ABSPOS_PUSH) &&
                maybeAbsoluteContainingBlockDisplay->IsPositioned()) {
       aState.PushAbsoluteContainingBlock(maybeAbsoluteContainingBlock,
                                          absoluteSaveState);
     }
 
     if (bits & FCDATA_USE_CHILD_ITEMS) {
+      NS_ASSERTION(!ShouldSuppressFloatingOfDescendants(newFrame),
+                   "uh oh -- this frame is supposed to _suppress_ floats, but "
+                   "we're about to push it as a float containing block...");
+
+      nsFrameConstructorSaveState floatSaveState;
+      if (newFrame->IsFloatContainingBlock()) {
+        aState.PushFloatContainingBlock(newFrame, floatSaveState);
+      }
       rv = ConstructFramesFromItemList(aState, aItem.mChildItems, newFrame,
                                        childItems);
     } else {
       // Process the child frames.
       rv = ProcessChildren(aState, content, styleContext, newFrame,
                            !(bits & FCDATA_DISALLOW_GENERATED_CONTENT),
                            childItems,
                            (bits & FCDATA_ALLOW_BLOCK_STYLES) != 0,
@@ -4256,16 +4278,27 @@ nsCSSFrameConstructor::BuildScrollFrame(
     
     aScrolledFrame->SetStyleContextWithoutNotification(scrolledContentStyle);
     InitAndRestoreFrame(aState, aContent, aNewFrame, nsnull, aScrolledFrame);
 
     FinishBuildingScrollFrame(aNewFrame, aScrolledFrame);
     return NS_OK;
 }
 
+#ifdef MOZ_FLEXBOX
+// TEMPORARY CHUNK: No-op constructor, so we can compile at this
+// intermediate state.  Removed in subsequent patch.
+nsIFrame*
+NS_NewFlexContainerFrame(nsIPresShell* aPresShell,
+                         nsStyleContext* aContext)
+{
+  return nsnull;
+}
+#endif // MOZ_FLEXBOX
+
 const nsCSSFrameConstructor::FrameConstructionData*
 nsCSSFrameConstructor::FindDisplayData(const nsStyleDisplay* aDisplay,
                                        Element* aElement,
                                        nsStyleContext* aStyleContext)
 {
   PR_STATIC_ASSERT(eParentTypeCount < (1 << (32 - FCDATA_PARENT_TYPE_OFFSET)));
 
   // The style system ensures that floated and positioned frames are
@@ -4326,16 +4359,22 @@ nsCSSFrameConstructor::FindDisplayData(c
   static const FrameConstructionDataByInt sDisplayData[] = {
     // To keep the hash table small don't add inline frames (they're
     // typically things like FONT and B), because we can quickly
     // find them if we need to.
     // 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) },
+#ifdef MOZ_FLEXBOX
+    { NS_STYLE_DISPLAY_FLEX,
+      FCDATA_DECL(0, NS_NewFlexContainerFrame) },
+    { NS_STYLE_DISPLAY_INLINE_FLEX,
+      FCDATA_DECL(0, NS_NewFlexContainerFrame) },
+#endif // MOZ_FLEXBOX
     { NS_STYLE_DISPLAY_TABLE,
       FULL_CTOR_FCDATA(0, &nsCSSFrameConstructor::ConstructTable) },
     { NS_STYLE_DISPLAY_INLINE_TABLE,
       FULL_CTOR_FCDATA(0, &nsCSSFrameConstructor::ConstructTable) },
     { NS_STYLE_DISPLAY_TABLE_CAPTION,
       FCDATA_DECL(FCDATA_IS_TABLE_PART | FCDATA_ALLOW_BLOCK_STYLES |
                   FCDATA_DISALLOW_OUT_OF_FLOW | FCDATA_SKIP_ABSPOS_PUSH |
                   FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable),
@@ -5505,18 +5544,18 @@ nsCSSFrameConstructor::GetAbsoluteContai
 nsIFrame*
 nsCSSFrameConstructor::GetFloatContainingBlock(nsIFrame* aFrame)
 {
   // Starting with aFrame, look for a frame that is a float containing block.
   // IF we hit a mathml frame, bail out; we don't allow floating out of mathml
   // frames, because they don't seem to be able to deal.
   // The logic here needs to match the logic in ProcessChildren()
   for (nsIFrame* containingBlock = aFrame;
-       containingBlock && !containingBlock->IsFrameOfType(nsIFrame::eMathML) &&
-       !containingBlock->IsBoxFrame();
+       containingBlock &&
+         !ShouldSuppressFloatingOfDescendants(containingBlock);
        containingBlock = containingBlock->GetParent()) {
     if (containingBlock->IsFloatContainingBlock()) {
       return containingBlock;
     }
   }
 
   // If we didn't find a containing block, then there just isn't
   // one.... return null
@@ -9212,16 +9251,126 @@ nsCSSFrameConstructor::sPseudoParentData
   },
   { // Table
     FULL_CTOR_FCDATA(FCDATA_SKIP_FRAMESET | FCDATA_USE_CHILD_ITEMS,
                      &nsCSSFrameConstructor::ConstructTable),
     &nsCSSAnonBoxes::table
   }
 };
 
+#ifdef MOZ_FLEXBOX
+void
+nsCSSFrameConstructor::CreateNeededAnonFlexItems(
+  nsFrameConstructorState& aState,
+  FrameConstructionItemList& aItems,
+  nsIFrame* aParentFrame)
+{
+  NS_ABORT_IF_FALSE(aParentFrame->GetType() == nsGkAtoms::flexContainerFrame,
+                    "Should only be called for items in a flex container frame");
+  if (aItems.IsEmpty()) {
+    return;
+  }
+
+  FCItemIterator iter(aItems);
+  do {
+    // Advance iter past children that don't want to be wrapped
+    if (iter.SkipItemsThatDontNeedAnonFlexItem(aState)) {
+      // Hit the end of the items without finding any remaining children that
+      // need to be wrapped. We're finished!
+      return;
+    }
+
+    // If our next potentially-wrappable child is whitespace, then see if
+    // there's anything wrappable immediately after it. If not, we just drop
+    // the whitespace and move on. (We're not supposed to create any anonymous
+    // flex items that _only_ contain whitespace).
+    if (iter.item().IsWhitespace(aState)) {
+      FCItemIterator afterWhitespaceIter(iter);
+      bool hitEnd = afterWhitespaceIter.SkipWhitespace(aState);
+      bool nextChildNeedsAnonFlexItem =
+        !hitEnd && afterWhitespaceIter.item().NeedsAnonFlexItem(aState);
+
+      if (!nextChildNeedsAnonFlexItem) {
+        // There's nothing after the whitespace that we need to wrap, so we
+        // just drop this run of whitespace.
+        iter.DeleteItemsTo(afterWhitespaceIter);
+        if (hitEnd) {
+          // Nothing left to do -- we're finished!
+          return;
+        }
+        // else, we have a next child and it does not want to be wrapped.  So,
+        // we jump back to the beginning of the loop to skip over that child
+        // (and anything else non-wrappable after it)
+        NS_ABORT_IF_FALSE(!iter.IsDone() &&
+                          !iter.item().NeedsAnonFlexItem(aState),
+                          "hitEnd and/or nextChildNeedsAnonFlexItem lied");
+        continue;
+      }
+    }
+
+    // Now |iter| points to the first child that needs to be wrapped in an
+    // anonymous flex item. Now we see how many children after it also want
+    // to be wrapped in an anonymous flex item.
+    FCItemIterator endIter(iter); // iterator to find the end of the group
+    endIter.SkipItemsThatNeedAnonFlexItem(aState);
+
+    NS_ASSERTION(iter != endIter,
+                 "Should've had at least one wrappable child to seek past");
+
+    // Now, we create the anonymous flex item to contain the children
+    // between |iter| and |endIter|.
+    nsIAtom* pseudoType = nsCSSAnonBoxes::anonymousFlexItem;
+    nsStyleContext* parentStyle = aParentFrame->GetStyleContext();
+    nsIContent* parentContent = aParentFrame->GetContent();
+    nsRefPtr<nsStyleContext> wrapperStyle =
+      mPresShell->StyleSet()->ResolveAnonymousBoxStyle(pseudoType, parentStyle);
+
+    static const FrameConstructionData sBlockFormattingContextFCData =
+      FCDATA_DECL(FCDATA_SKIP_FRAMESET | FCDATA_USE_CHILD_ITEMS,
+                  NS_NewBlockFormattingContext);
+
+    FrameConstructionItem* newItem =
+      new FrameConstructionItem(&sBlockFormattingContextFCData,
+                                // Use the content of our parent frame
+                                parentContent,
+                                // Lie about the tag; it doesn't matter anyway
+                                pseudoType,
+                                iter.item().mNameSpaceID,
+                                // no pending binding
+                                nsnull,
+                                wrapperStyle.forget(),
+                                true);
+
+    newItem->mIsAllInline = newItem->mHasInlineEnds =
+      newItem->mStyleContext->GetStyleDisplay()->IsInlineOutside();
+    newItem->mIsBlock = !newItem->mIsAllInline;
+
+    NS_ABORT_IF_FALSE(!newItem->mIsAllInline && newItem->mIsBlock,
+                      "expecting anonymous flex items to be block-level "
+                      "(this will make a difference when we encounter "
+                      "'flex-align: baseline')");
+
+    // Anonymous flex items induce line boundaries around their
+    // contents.
+    newItem->mChildItems.SetLineBoundaryAtStart(true);
+    newItem->mChildItems.SetLineBoundaryAtEnd(true);
+    // The parent of the items in aItems is also the parent of the items
+    // in mChildItems
+    newItem->mChildItems.SetParentHasNoXBLChildren(
+      aItems.ParentHasNoXBLChildren());
+
+    // Eat up all items between |iter| and |endIter| and put them in our
+    // wrapper. This advances |iter| to point to |endIter|.
+    iter.AppendItemsToList(endIter, newItem->mChildItems);
+
+    iter.InsertItem(newItem);
+  } while (!iter.IsDone());
+}
+#endif // MOZ_FLEXBOX
+
 /*
  * This function works as follows: we walk through the child list (aItems) and
  * find items that cannot have aParentFrame as their parent.  We wrap
  * continuous runs of such items into a FrameConstructionItem for a frame that
  * gets them closer to their desired parents.  For example, a run of non-row
  * children of a row-group will get wrapped in a row.  When we later construct
  * the frame for this wrapper (in this case for the row), it'll be the correct
  * parent for the cells in the set of items we wrapped or we'll wrap cells
@@ -9432,16 +9581,22 @@ nsCSSFrameConstructor::ConstructFramesFr
                                                    FrameConstructionItemList& aItems,
                                                    nsIFrame* aParentFrame,
                                                    nsFrameItems& aFrameItems)
 {
   aItems.SetTriedConstructingFrames();
 
   CreateNeededTablePseudos(aState, aItems, aParentFrame);
 
+#ifdef MOZ_FLEXBOX
+  if (aParentFrame->GetType() == nsGkAtoms::flexContainerFrame) {
+    CreateNeededAnonFlexItems(aState, aItems, aParentFrame);
+  }
+#endif // MOZ_FLEXBOX
+
 #ifdef DEBUG
   for (FCItemIterator iter(aItems); !iter.IsDone(); iter.Next()) {
     NS_ASSERTION(iter.item().DesiredParentType() == GetParentType(aParentFrame),
                  "Needed pseudos didn't get created; expect bad things");
   }
 #endif
 
   for (FCItemIterator iter(aItems); !iter.IsDone(); iter.Next()) {
@@ -9481,18 +9636,17 @@ nsCSSFrameConstructor::ProcessChildren(n
   bool haveFirstLetterStyle = false, haveFirstLineStyle = false;
   if (aAllowBlockStyles) {
     ShouldHaveSpecialBlockStyle(aContent, aStyleContext, &haveFirstLetterStyle,
                                 &haveFirstLineStyle);
   }
 
   // The logic here needs to match the logic in GetFloatContainingBlock()
   nsFrameConstructorSaveState floatSaveState;
-  if (aFrame->IsFrameOfType(nsIFrame::eMathML) ||
-      aFrame->IsBoxFrame()) {
+  if (ShouldSuppressFloatingOfDescendants(aFrame)) {
     aState.PushFloatContainingBlock(nsnull, floatSaveState);
   } else if (aFrame->IsFloatContainingBlock()) {
     aState.PushFloatContainingBlock(aFrame, floatSaveState);
   }
 
   nsFrameConstructorState::PendingBindingAutoPusher pusher(aState,
                                                            aPendingBinding);
 
@@ -11805,16 +11959,69 @@ Iterator::SkipItemsWantingParentType(Par
     Next();
     if (IsDone()) {
       return true;
     }
   }
   return false;
 }
 
+#ifdef MOZ_FLEXBOX
+bool
+nsCSSFrameConstructor::FrameConstructionItem::
+  NeedsAnonFlexItem(const nsFrameConstructorState& aState)
+{
+  if (mFCData->mBits & FCDATA_IS_LINE_PARTICIPANT) {
+    // This will be an inline non-replaced box.
+    return true;
+  }
+
+  if (!(mFCData->mBits & FCDATA_DISALLOW_OUT_OF_FLOW) &&
+      aState.GetGeometricParent(mStyleContext->GetStyleDisplay(), nsnull)) {
+    // We're abspos or fixedpos, which means we'll spawn a placeholder which
+    // we'll need to wrap in an anonymous flex item.  So, we just treat
+    // _this_ frame as if _it_ needs to be wrapped in an anonymous flex item,
+    // and then when we spawn the placeholder, it'll end up in the right spot.
+    return true;
+  }
+
+  return false;
+}
+
+inline bool
+nsCSSFrameConstructor::FrameConstructionItemList::
+Iterator::SkipItemsThatNeedAnonFlexItem(
+  const nsFrameConstructorState& aState)
+{
+  NS_PRECONDITION(!IsDone(), "Shouldn't be done yet");
+  while (item().NeedsAnonFlexItem(aState)) {
+    Next();
+    if (IsDone()) {
+      return true;
+    }
+  }
+  return false;
+}
+
+inline bool
+nsCSSFrameConstructor::FrameConstructionItemList::
+Iterator::SkipItemsThatDontNeedAnonFlexItem(
+  const nsFrameConstructorState& aState)
+{
+  NS_PRECONDITION(!IsDone(), "Shouldn't be done yet");
+  while (!(item().NeedsAnonFlexItem(aState))) {
+    Next();
+    if (IsDone()) {
+      return true;
+    }
+  }
+  return false;
+}
+#endif // MOZ_FLEXBOX
+
 inline bool
 nsCSSFrameConstructor::FrameConstructionItemList::
 Iterator::SkipWhitespace(nsFrameConstructorState& aState)
 {
   NS_PRECONDITION(!IsDone(), "Shouldn't be done yet");
   NS_PRECONDITION(item().IsWhitespace(aState), "Not pointing to whitespace?");
   do {
     Next();
--- a/layout/base/nsCSSFrameConstructor.h
+++ b/layout/base/nsCSSFrameConstructor.h
@@ -911,16 +911,30 @@ private:
       }
       void SetToEnd() { mCurrent = mEnd; }
 
       // Skip over all items that want a parent type different from the given
       // one.  Return whether the iterator is done after doing that.  The
       // iterator must not be done when this is called.
       inline bool SkipItemsWantingParentType(ParentType aParentType);
 
+#ifdef MOZ_FLEXBOX
+      // Skip over non-replaced inline frames and positioned frames.
+      // Return whether the iterator is done after doing that.
+      // The iterator must not be done when this is called.
+      inline bool SkipItemsThatNeedAnonFlexItem(
+        const nsFrameConstructorState& aState);
+
+      // Skip to the first frame that is a non-replaced inline or is
+      // positioned.  Return whether the iterator is done after doing that.
+      // The iterator must not be done when this is called.
+      inline bool SkipItemsThatDontNeedAnonFlexItem(
+        const nsFrameConstructorState& aState);
+#endif // MOZ_FLEXBOX
+
       // Skip over whitespace.  Return whether the iterator is done after doing
       // that.  The iterator must not be done, and must be pointing to a
       // whitespace item when this is called.
       inline bool SkipWhitespace(nsFrameConstructorState& aState);
 
       // Remove the item pointed to by this iterator from its current list and
       // Append it to aTargetList.  This iterator is advanced to point to the
       // next item in its list.  aIter must not be done.  aOther must not be
@@ -1025,16 +1039,22 @@ private:
         NS_RELEASE(mContent);
       }
     }
 
     ParentType DesiredParentType() {
       return FCDATA_DESIRED_PARENT_TYPE(mFCData->mBits);
     }
 
+    // Indicates whether (when in a flexbox container) this item needs to be
+    // wrapped in an anonymous block.
+#ifdef MOZ_FLEXBOX
+    bool NeedsAnonFlexItem(const nsFrameConstructorState& aState);
+#endif // MOZ_FLEXBOX
+
     // Don't call this unless the frametree really depends on the answer!
     // Especially so for generated content, where we don't want to reframe
     // things.
     bool IsWhitespace(nsFrameConstructorState& aState) const;
 
     bool IsLineBoundary() const {
       return mIsBlock || (mFCData->mBits & FCDATA_IS_LINE_BREAK);
     }
@@ -1093,16 +1113,29 @@ private:
     // Child frame construction items.
     FrameConstructionItemList mChildItems;
 
   private:
     FrameConstructionItem(const FrameConstructionItem& aOther) MOZ_DELETE; /* not implemented */
   };
 
   /**
+   * Function to create the anonymous flex items that we need.
+   * aParentFrame _must_ be a nsFlexContainerFrame -- the caller is responsible
+   * for checking this.
+   * @param aItems the child frame construction items before pseudo creation
+   * @param aParentFrame the flex container frame
+   */
+#ifdef MOZ_FLEXBOX
+  void CreateNeededAnonFlexItems(nsFrameConstructorState& aState,
+                                    FrameConstructionItemList& aItems,
+                                    nsIFrame* aParentFrame);
+#endif // MOZ_FLEXBOX
+
+  /**
    * Function to create the table pseudo items we need.
    * @param aItems the child frame construction items before pseudo creation
    * @param aParentFrame the parent frame we're creating pseudos for
    */
   inline void CreateNeededTablePseudos(nsFrameConstructorState& aState,
                                        FrameConstructionItemList& aItems,
                                        nsIFrame* aParentFrame);
 
--- a/layout/base/nsStyleConsts.h
+++ b/layout/base/nsStyleConsts.h
@@ -387,16 +387,20 @@ static inline mozilla::css::Side operato
 #define NS_STYLE_DISPLAY_GRID_GROUP             22
 #define NS_STYLE_DISPLAY_GRID_LINE              23
 #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
+#ifdef MOZ_FLEXBOX
+#define NS_STYLE_DISPLAY_FLEX                   29
+#define NS_STYLE_DISPLAY_INLINE_FLEX            30
+#endif // MOZ_FLEXBOX
 
 // See nsStyleDisplay
 #define NS_STYLE_FLOAT_NONE                     0
 #define NS_STYLE_FLOAT_LEFT                     1
 #define NS_STYLE_FLOAT_RIGHT                    2
 
 // See nsStyleFont
 // We should eventually stop using the NS_STYLE_* variants here.
--- a/layout/style/nsCSSAnonBoxList.h
+++ b/layout/style/nsCSSAnonBoxList.h
@@ -57,16 +57,20 @@ CSS_ANON_BOX(pageContent, ":-moz-pagecon
 CSS_ANON_BOX(pageSequence, ":-moz-page-sequence")
 CSS_ANON_BOX(scrolledContent, ":-moz-scrolled-content")
 CSS_ANON_BOX(scrolledCanvas, ":-moz-scrolled-canvas")
 CSS_ANON_BOX(scrolledPageSequence, ":-moz-scrolled-page-sequence")
 CSS_ANON_BOX(columnContent, ":-moz-column-content")
 CSS_ANON_BOX(viewport, ":-moz-viewport")
 CSS_ANON_BOX(viewportScroll, ":-moz-viewport-scroll")
 
+// Inside a flex container, a contiguous run of non-replaced inline children
+// gets wrapped in an anonymous block, which is then treated as a flex item.
+CSS_ANON_BOX(anonymousFlexItem, ":-moz-anonymous-flex-item")
+
 #ifdef MOZ_XUL
 CSS_ANON_BOX(moztreecolumn, ":-moz-tree-column")
 CSS_ANON_BOX(moztreerow, ":-moz-tree-row")
 CSS_ANON_BOX(moztreeseparator, ":-moz-tree-separator")
 CSS_ANON_BOX(moztreecell, ":-moz-tree-cell")
 CSS_ANON_BOX(moztreeindentation, ":-moz-tree-indentation")
 CSS_ANON_BOX(moztreeline, ":-moz-tree-line")
 CSS_ANON_BOX(moztreetwisty, ":-moz-tree-twisty")
--- a/layout/style/nsCSSKeywordList.h
+++ b/layout/style/nsCSSKeywordList.h
@@ -69,16 +69,19 @@ CSS_KEY(-moz-eventreerow, _moz_eventreer
 CSS_KEY(-moz-ethiopic-halehame, _moz_ethiopic_halehame)
 CSS_KEY(-moz-ethiopic-numeric, _moz_ethiopic_numeric)
 CSS_KEY(-moz-ethiopic-halehame-am, _moz_ethiopic_halehame_am)
 CSS_KEY(-moz-ethiopic-halehame-ti-er, _moz_ethiopic_halehame_ti_er)
 CSS_KEY(-moz-ethiopic-halehame-ti-et, _moz_ethiopic_halehame_ti_et)
 CSS_KEY(-moz-field, _moz_field)
 CSS_KEY(-moz-fieldtext, _moz_fieldtext)
 CSS_KEY(-moz-fit-content, _moz_fit_content)
+#ifdef MOZ_FLEXBOX
+CSS_KEY(-moz-flex, _moz_flex)
+#endif // MOZ_FLEXBOX
 CSS_KEY(-moz-grabbing, _moz_grabbing)
 CSS_KEY(-moz-grab, _moz_grab)
 CSS_KEY(-moz-grid-group, _moz_grid_group)
 CSS_KEY(-moz-grid-line, _moz_grid_line)
 CSS_KEY(-moz-grid, _moz_grid)
 CSS_KEY(-moz-groupbox, _moz_groupbox)
 CSS_KEY(-moz-gujarati, _moz_gujarati)
 CSS_KEY(-moz-gurmukhi, _moz_gurmukhi)
@@ -87,16 +90,19 @@ CSS_KEY(-moz-hidden-unscrollable, _moz_h
 CSS_KEY(-moz-hangul, _moz_hangul)
 CSS_KEY(-moz-hyperlinktext, _moz_hyperlinktext)
 CSS_KEY(-moz-html-cellhighlight, _moz_html_cellhighlight)
 CSS_KEY(-moz-html-cellhighlighttext, _moz_html_cellhighlighttext)
 CSS_KEY(-moz-image-rect, _moz_image_rect)
 CSS_KEY(-moz-info, _moz_info)
 CSS_KEY(-moz-initial, _moz_initial)
 CSS_KEY(-moz-inline-box, _moz_inline_box)
+#ifdef MOZ_FLEXBOX
+CSS_KEY(-moz-inline-flex, _moz_inline_flex)
+#endif // MOZ_FLEXBOX
 CSS_KEY(-moz-inline-grid, _moz_inline_grid)
 CSS_KEY(-moz-inline-stack, _moz_inline_stack)
 CSS_KEY(-moz-isolate, _moz_isolate)
 CSS_KEY(-moz-japanese-formal, _moz_japanese_formal)
 CSS_KEY(-moz-japanese-informal, _moz_japanese_informal)
 CSS_KEY(-moz-kannada, _moz_kannada)
 CSS_KEY(-moz-khmer, _moz_khmer)
 CSS_KEY(-moz-lao, _moz_lao)
--- a/layout/style/nsCSSProps.cpp
+++ b/layout/style/nsCSSProps.cpp
@@ -883,16 +883,20 @@ const PRInt32 nsCSSProps::kDisplayKTable
   eCSSKeyword__moz_grid_group,    NS_STYLE_DISPLAY_GRID_GROUP,
   eCSSKeyword__moz_grid_line,     NS_STYLE_DISPLAY_GRID_LINE,
   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
+#ifdef MOZ_FLEXBOX
+  eCSSKeyword__moz_flex,          NS_STYLE_DISPLAY_FLEX,
+  eCSSKeyword__moz_inline_flex,   NS_STYLE_DISPLAY_INLINE_FLEX,
+#endif // MOZ_FLEXBOX
   eCSSKeyword_UNKNOWN,-1
 };
 
 const PRInt32 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/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -120,28 +120,38 @@ static void EnsureBlockDisplay(PRUint8& 
 {
   // see if the display value is already a block
   switch (display) {
   case NS_STYLE_DISPLAY_NONE :
     // never change display:none *ever*
   case NS_STYLE_DISPLAY_TABLE :
   case NS_STYLE_DISPLAY_BLOCK :
   case NS_STYLE_DISPLAY_LIST_ITEM :
+#ifdef MOZ_FLEXBOX
+  case NS_STYLE_DISPLAY_FLEX :
+#endif // MOZ_FLEXBOX
     // 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 :
     // make inline tables into tables
     display = NS_STYLE_DISPLAY_TABLE;
     break;
 
+#ifdef MOZ_FLEXBOX
+  case NS_STYLE_DISPLAY_INLINE_FLEX:
+    // make inline flex containers into flex containers
+    display = NS_STYLE_DISPLAY_FLEX;
+    break;
+#endif // MOZ_FLEXBOX
+
   default :
     // make it a block
     display = NS_STYLE_DISPLAY_BLOCK;
   }
 }
 
 static nscoord CalcLengthWith(const nsCSSValue& aValue,
                               nscoord aFontSize,
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -1591,25 +1591,31 @@ struct nsStyleDisplay {
            NS_STYLE_DISPLAY_INLINE_BLOCK == mDisplay;
     // Should TABLE_CELL and TABLE_CAPTION go here?  They have
     // block frames nested inside of them.
     // (But please audit all callers before changing.)
   }
 
   bool IsBlockOutside() const {
     return NS_STYLE_DISPLAY_BLOCK == mDisplay ||
+#ifdef MOZ_FLEXBOX
+           NS_STYLE_DISPLAY_FLEX == mDisplay ||
+#endif // MOZ_FLEXBOX
            NS_STYLE_DISPLAY_LIST_ITEM == mDisplay ||
            NS_STYLE_DISPLAY_TABLE == mDisplay;
   }
 
   static bool IsDisplayTypeInlineOutside(PRUint8 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 ||
+#ifdef MOZ_FLEXBOX
+           NS_STYLE_DISPLAY_INLINE_FLEX == aDisplay ||
+#endif // MOZ_FLEXBOX
            NS_STYLE_DISPLAY_INLINE_GRID == aDisplay ||
            NS_STYLE_DISPLAY_INLINE_STACK == aDisplay;
   }
 
   bool IsInlineOutside() const {
     return IsDisplayTypeInlineOutside(mDisplay);
   }
 
--- a/layout/style/test/property_database.js
+++ b/layout/style/test/property_database.js
@@ -1959,17 +1959,37 @@ var gCSSProperties = {
 	},
 	"display": {
 		domProp: "display",
 		inherited: false,
 		type: CSS_TYPE_LONGHAND,
 		initial_values: [ "inline" ],
 		/* XXX none will really mess with other properties */
 		prerequisites: { "float": "none", "position": "static" },
-		other_values: [ "block", "list-item", "inline-block", "table", "inline-table", "table-row-group", "table-header-group", "table-footer-group", "table-row", "table-column-group", "table-column", "table-cell", "table-caption", "none" ],
+		other_values: [
+			"block",
+			"list-item",
+			"inline-block",
+			"table",
+			"inline-table",
+			"table-row-group",
+			"table-header-group",
+			"table-footer-group",
+			"table-row",
+			"table-column-group",
+			"table-column",
+			"table-cell",
+			"table-caption",
+/* XXXdholbert In builds with MOZ_FLEXBOX enabled, this should be uncommented.
+   (This would be #ifdef MOZ_FLEXBOX, if that worked in JS files.)
+			"-moz-flex",
+			"-moz-inline-flex",
+*/
+			"none"
+		],
 		invalid_values: []
 	},
 	"empty-cells": {
 		domProp: "emptyCells",
 		inherited: true,
 		type: CSS_TYPE_LONGHAND,
 		initial_values: [ "show" ],
 		other_values: [ "hide", "-moz-show-background" ],
--- a/layout/style/ua.css
+++ b/layout/style/ua.css
@@ -160,16 +160,22 @@
   text-overflow: inherit;
   /* inherit the outer frame's display, otherwise we turn into an inline */
   display: inherit !important;
   /* Carry through our parent's height so that %-height children get
   their heights set */
   height: 100%;
 }
 
+*|*::-moz-anonymous-flex-item {
+  /* Anonymous blocks that wrap contiguous runs of inline non-replaced
+   * content inside of a flex container. */
+  display: block;
+}
+
 *|*::-moz-page-sequence, *|*::-moz-scrolled-page-sequence {
   /* Collection of pages in print/print preview. Visual styles may only appear
    * in print preview. */
   display: block !important;
   background: -moz-linear-gradient(top, #606060, #8a8a8a) fixed;
   height: 100%;
 }