/* -*- 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 | inline-grid" */ #include "nsGridContainerFrame.h" #include "nsCSSAnonBoxes.h" #include "nsPresContext.h" #include "nsStyleContext.h" using namespace mozilla; //---------------------------------------------------------------------- // Frame class boilerplate // ======================= NS_QUERYFRAME_HEAD(nsGridContainerFrame) NS_QUERYFRAME_ENTRY(nsGridContainerFrame) NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame) NS_IMPL_FRAMEARENA_HELPERS(nsGridContainerFrame) nsContainerFrame* NS_NewGridContainerFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) { return new (aPresShell) nsGridContainerFrame(aContext); } //---------------------------------------------------------------------- // nsGridContainerFrame Method Implementations // =========================================== void nsGridContainerFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { DO_GLOBAL_REFLOW_COUNT("nsGridContainerFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); if (IsFrameTreeTooDeep(aReflowState, aDesiredSize, aStatus)) { return; } #ifdef DEBUG SanityCheckAnonymousGridItems(); #endif // DEBUG LogicalMargin bp = aReflowState.ComputedLogicalBorderPadding(); bp.ApplySkipSides(GetLogicalSkipSides()); nscoord contentBSize = GetEffectiveComputedBSize(aReflowState); if (contentBSize == NS_AUTOHEIGHT) { contentBSize = 0; } WritingMode wm = aReflowState.GetWritingMode(); LogicalSize finalSize(wm, aReflowState.ComputedISize() + bp.IStartEnd(wm), contentBSize + bp.BStartEnd(wm)); aDesiredSize.SetSize(wm, finalSize); aDesiredSize.SetOverflowAreasToDesiredBounds(); aStatus = NS_FRAME_COMPLETE; NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); } 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 #ifdef DEBUG static bool FrameWantsToBeInAnonymousGridItem(nsIFrame* aFrame) { // Note: This needs to match the logic in // nsCSSFrameConstructor::FrameConstructionItem::NeedsAnonFlexOrGridItem() return (aFrame->IsFrameOfType(nsIFrame::eLineParticipant) || nsGkAtoms::placeholderFrame == aFrame->GetType()); } // Debugging method, to let us assert that our anonymous grid items are // set up correctly -- in particular, we assert: // (1) we don't have any inline non-replaced children // (2) we don't have any consecutive anonymous grid items // (3) we don't have any empty anonymous grid items // (4) all children are on the expected child lists void nsGridContainerFrame::SanityCheckAnonymousGridItems() const { // XXX handle kOverflowContainersList / kExcessOverflowContainersList // when we implement fragmentation? ChildListIDs noCheckLists = kAbsoluteList | kFixedList; ChildListIDs checkLists = kPrincipalList | kOverflowList; for (nsIFrame::ChildListIterator childLists(this); !childLists.IsDone(); childLists.Next()) { if (!checkLists.Contains(childLists.CurrentID())) { MOZ_ASSERT(noCheckLists.Contains(childLists.CurrentID()), "unexpected non-empty child list"); continue; } bool prevChildWasAnonGridItem = false; nsFrameList children = childLists.CurrentList(); for (nsFrameList::Enumerator e(children); !e.AtEnd(); e.Next()) { nsIFrame* child = e.get(); MOZ_ASSERT(!FrameWantsToBeInAnonymousGridItem(child), "frame wants to be inside an anonymous grid item, " "but it isn't"); if (child->StyleContext()->GetPseudo() == nsCSSAnonBoxes::anonymousGridItem) { /* XXX haven't decided yet whether to reorder children or not. XXX If we do, we want this assertion instead of the one below. MOZ_ASSERT(!prevChildWasAnonGridItem || HasAnyStateBits(NS_STATE_GRID_CHILDREN_REORDERED), "two anon grid items in a row (shouldn't happen, unless our " "children have been reordered with the 'order' property)"); */ MOZ_ASSERT(!prevChildWasAnonGridItem, "two anon grid items in a row"); nsIFrame* firstWrappedChild = child->GetFirstPrincipalChild(); MOZ_ASSERT(firstWrappedChild, "anonymous grid item is empty (shouldn't happen)"); prevChildWasAnonGridItem = true; } else { prevChildWasAnonGridItem = false; } } } } #endif // DEBUG