Bug 666041 patch 2: Add "-moz-flex" & "-moz-inline-flex" values for "display" property. r=bz

This commit is contained in:
Daniel Holbert
2012-06-26 15:11:38 -07:00
parent 8d0a462cbd
commit 917cd2a0cb
11 changed files with 306 additions and 5 deletions

View File

@@ -1684,6 +1684,7 @@ 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")

View File

@@ -365,6 +365,20 @@ 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.
@@ -3684,6 +3698,14 @@ nsCSSFrameConstructor::ConstructFrameFromItemInternal(FrameConstructionItem& aIt
}
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 {
@@ -4261,6 +4283,17 @@ nsCSSFrameConstructor::BuildScrollFrame(nsFrameConstructorState& aState,
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,
@@ -4331,6 +4364,12 @@ nsCSSFrameConstructor::FindDisplayData(const nsStyleDisplay* aDisplay,
{ 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,
@@ -5510,8 +5549,8 @@ nsCSSFrameConstructor::GetFloatContainingBlock(nsIFrame* aFrame)
// 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;
@@ -9217,6 +9256,116 @@ nsCSSFrameConstructor::sPseudoParentData[eParentTypeCount] = {
}
};
#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
@@ -9437,6 +9586,12 @@ nsCSSFrameConstructor::ConstructFramesFromItemList(nsFrameConstructorState& aSta
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),
@@ -9486,8 +9641,7 @@ nsCSSFrameConstructor::ProcessChildren(nsFrameConstructorState& aState,
// 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);
@@ -11810,6 +11964,59 @@ Iterator::SkipItemsWantingParentType(ParentType aParentType)
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)

View File

@@ -916,6 +916,20 @@ private:
// 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.
@@ -1030,6 +1044,12 @@ private:
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.
@@ -1097,6 +1117,19 @@ 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

View File

@@ -392,6 +392,10 @@ static inline mozilla::css::Side operator++(mozilla::css::Side& side, int) {
#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

View File

@@ -62,6 +62,10 @@ 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")

View File

@@ -74,6 +74,9 @@ 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)
@@ -92,6 +95,9 @@ 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)

View File

@@ -888,6 +888,10 @@ const PRInt32 nsCSSProps::kDisplayKTable[] = {
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
};

View File

@@ -125,6 +125,9 @@ static void EnsureBlockDisplay(PRUint8& display)
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?)
@@ -137,6 +140,13 @@ static void EnsureBlockDisplay(PRUint8& display)
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;

View File

@@ -1596,6 +1596,9 @@ struct nsStyleDisplay {
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;
}
@@ -1605,6 +1608,9 @@ struct nsStyleDisplay {
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;
}

View File

@@ -1964,7 +1964,27 @@ var gCSSProperties = {
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": {

View File

@@ -165,6 +165,12 @@
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. */