void
nsSVGForeignObjectFrame::Reflow(nsPresContext*           aPresContext,
                                nsHTMLReflowMetrics&     aDesiredSize,
                                const nsHTMLReflowState& aReflowState,
                                nsReflowStatus&          aStatus)
{
  MOZ_ASSERT(!(GetStateBits() & NS_FRAME_IS_NONDISPLAY),
             "Should not have been called");

  // Only InvalidateAndScheduleBoundsUpdate marks us with NS_FRAME_IS_DIRTY,
  // so if that bit is still set we still have a resize pending. If we hit
  // this assertion, then we should get the presShell to skip reflow roots
  // that have a dirty parent since a reflow is going to come via the
  // reflow root's parent anyway.
  NS_ASSERTION(!(GetStateBits() & NS_FRAME_IS_DIRTY),
               "Reflowing while a resize is pending is wasteful");

  // ReflowSVG makes sure mRect is up to date before we're called.

  NS_ASSERTION(!aReflowState.parentReflowState,
               "should only get reflow from being reflow root");
  NS_ASSERTION(aReflowState.ComputedWidth() == GetSize().width &&
               aReflowState.ComputedHeight() == GetSize().height,
               "reflow roots should be reflowed at existing size and "
               "svg.css should ensure we have no padding/border/margin");

  DoReflow();

  WritingMode wm = aReflowState.GetWritingMode();
  LogicalSize finalSize(wm, aReflowState.ComputedISize(),
                        aReflowState.ComputedBSize());
  aDesiredSize.SetSize(wm, finalSize);
  aDesiredSize.SetOverflowAreasToDesiredBounds();
  aStatus = NS_FRAME_COMPLETE;
}
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);
}
Esempio n. 3
0
void
nsRangeFrame::Reflow(nsPresContext*           aPresContext,
                     nsHTMLReflowMetrics&     aDesiredSize,
                     const nsHTMLReflowState& aReflowState,
                     nsReflowStatus&          aStatus)
{
  MarkInReflow();
  DO_GLOBAL_REFLOW_COUNT("nsRangeFrame");
  DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);

  NS_ASSERTION(mTrackDiv, "::-moz-range-track div must exist!");
  NS_ASSERTION(mProgressDiv, "::-moz-range-progress div must exist!");
  NS_ASSERTION(mThumbDiv, "::-moz-range-thumb div must exist!");
  NS_ASSERTION(!GetPrevContinuation() && !GetNextContinuation(),
               "nsRangeFrame should not have continuations; if it does we "
               "need to call RegUnregAccessKey only for the first.");

  if (mState & NS_FRAME_FIRST_REFLOW) {
    nsFormControlFrame::RegUnRegAccessKey(this, true);
  }

  WritingMode wm = aReflowState.GetWritingMode();
  nscoord computedBSize = aReflowState.ComputedBSize();
  if (computedBSize == NS_AUTOHEIGHT) {
    computedBSize = 0;
  }
  LogicalSize
    finalSize(wm,
              aReflowState.ComputedISize() +
              aReflowState.ComputedLogicalBorderPadding().IStartEnd(wm),
              computedBSize +
              aReflowState.ComputedLogicalBorderPadding().BStartEnd(wm));
  aDesiredSize.SetSize(wm, finalSize);

  ReflowAnonymousContent(aPresContext, aDesiredSize, aReflowState);

  aDesiredSize.SetOverflowAreasToDesiredBounds();

  nsIFrame* trackFrame = mTrackDiv->GetPrimaryFrame();
  if (trackFrame) {
    ConsiderChildOverflow(aDesiredSize.mOverflowAreas, trackFrame);
  }

  nsIFrame* rangeProgressFrame = mProgressDiv->GetPrimaryFrame();
  if (rangeProgressFrame) {
    ConsiderChildOverflow(aDesiredSize.mOverflowAreas, rangeProgressFrame);
  }

  nsIFrame* thumbFrame = mThumbDiv->GetPrimaryFrame();
  if (thumbFrame) {
    ConsiderChildOverflow(aDesiredSize.mOverflowAreas, thumbFrame);
  }

  FinishAndStoreOverflow(&aDesiredSize);

  aStatus = NS_FRAME_COMPLETE;

  NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
}
void
nsGridContainerFrame::Reflow(nsPresContext*           aPresContext,
                             nsHTMLReflowMetrics&     aDesiredSize,
                             const nsHTMLReflowState& aReflowState,
                             nsReflowStatus&          aStatus)
{
  MarkInReflow();
  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());
  const nsStylePosition* stylePos = aReflowState.mStylePosition;
  InitImplicitNamedAreas(stylePos);
  GridItemCSSOrderIterator normalFlowIter(this, kPrincipalList);
  mIsNormalFlowInCSSOrder = normalFlowIter.ItemsAreAlreadyInOrder();
  PlaceGridItems(normalFlowIter, stylePos);

  nsAutoTArray<TrackSize, 32> colSizes;
  nsAutoTArray<TrackSize, 32> rowSizes;
  WritingMode wm = aReflowState.GetWritingMode();
  const nscoord computedBSize = aReflowState.ComputedBSize();
  const nscoord computedISize = aReflowState.ComputedISize();
  LogicalSize percentageBasis(wm, computedISize,
      computedBSize == NS_AUTOHEIGHT ? 0 : computedBSize);
  CalculateTrackSizes(percentageBasis, stylePos, colSizes, rowSizes);

  nscoord bSize = 0;
  if (computedBSize == NS_AUTOHEIGHT) {
    for (uint32_t i = 0; i < mGridRowEnd - 1; ++i) {
      bSize += rowSizes[i].mBase;
    }
  } else {
    bSize = computedBSize;
  }
  bSize = std::max(bSize - GetConsumedBSize(), 0);
  LogicalSize desiredSize(wm, computedISize + bp.IStartEnd(wm),
                          bSize + bp.BStartEnd(wm));
  aDesiredSize.SetSize(wm, desiredSize);
  aDesiredSize.SetOverflowAreasToDesiredBounds();

  LogicalRect contentArea(wm, bp.IStart(wm), bp.BStart(wm),
                          computedISize, bSize);
  normalFlowIter.Reset();
  ReflowChildren(normalFlowIter, contentArea, colSizes, rowSizes, aDesiredSize,
                 aReflowState, aStatus);

  FinishAndStoreOverflow(&aDesiredSize);
  aStatus = NS_FRAME_COMPLETE;
  NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
}
void
nsTextControlFrame::Reflow(nsPresContext*   aPresContext,
                           nsHTMLReflowMetrics&     aDesiredSize,
                           const nsHTMLReflowState& aReflowState,
                           nsReflowStatus&          aStatus)
{
  MarkInReflow();
  DO_GLOBAL_REFLOW_COUNT("nsTextControlFrame");
  DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);

  // make sure that the form registers itself on the initial/first reflow
  if (mState & NS_FRAME_FIRST_REFLOW) {
    nsFormControlFrame::RegUnRegAccessKey(this, true);
  }

  // set values of reflow's out parameters
  WritingMode wm = aReflowState.GetWritingMode();
  LogicalSize
    finalSize(wm,
              aReflowState.ComputedISize() +
              aReflowState.ComputedLogicalBorderPadding().IStartEnd(wm),
              aReflowState.ComputedBSize() +
              aReflowState.ComputedLogicalBorderPadding().BStartEnd(wm));
  aDesiredSize.SetSize(wm, finalSize);

  // computation of the ascent wrt the input height
  nscoord lineHeight = aReflowState.ComputedBSize();
  float inflation = nsLayoutUtils::FontSizeInflationFor(this);
  if (!IsSingleLineTextControl()) {
    lineHeight = nsHTMLReflowState::CalcLineHeight(GetContent(), StyleContext(),
                                                   NS_AUTOHEIGHT, inflation);
  }
  RefPtr<nsFontMetrics> fontMet;
  nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fontMet),
                                        inflation);
  // now adjust for our borders and padding
  aDesiredSize.SetBlockStartAscent(
    nsLayoutUtils::GetCenteredFontBaseline(fontMet, lineHeight,
                                           wm.IsLineInverted()) +
    aReflowState.ComputedLogicalBorderPadding().BStart(wm));

  // overflow handling
  aDesiredSize.SetOverflowAreasToDesiredBounds();
  // perform reflow on all kids
  nsIFrame* kid = mFrames.FirstChild();
  while (kid) {
    ReflowTextControlChild(kid, aPresContext, aReflowState, aStatus, aDesiredSize);
    kid = kid->GetNextSibling();
  }

  // take into account css properties that affect overflow handling
  FinishAndStoreOverflow(&aDesiredSize);

  aStatus = NS_FRAME_COMPLETE;
  NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
}
void
nsHTMLButtonControlFrame::Reflow(nsPresContext* aPresContext,
                                 nsHTMLReflowMetrics& aDesiredSize,
                                 const nsHTMLReflowState& aReflowState,
                                 nsReflowStatus& aStatus)
{
  MarkInReflow();
  DO_GLOBAL_REFLOW_COUNT("nsHTMLButtonControlFrame");
  DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);

  NS_PRECONDITION(aReflowState.ComputedISize() != NS_INTRINSICSIZE,
                  "Should have real computed inline-size by now");

  if (mState & NS_FRAME_FIRST_REFLOW) {
    nsFormControlFrame::RegUnRegAccessKey(static_cast<nsIFrame*>(this), true);
  }

  // Reflow the child
  nsIFrame* firstKid = mFrames.FirstChild();

  MOZ_ASSERT(firstKid, "Button should have a child frame for its contents");
  MOZ_ASSERT(!firstKid->GetNextSibling(),
             "Button should have exactly one child frame");
  MOZ_ASSERT(firstKid->StyleContext()->GetPseudo() ==
             nsCSSAnonBoxes::buttonContent,
             "Button's child frame has unexpected pseudo type!");

  // XXXbz Eventually we may want to check-and-bail if
  // !aReflowState.ShouldReflowAllKids() &&
  // !NS_SUBTREE_DIRTY(firstKid).
  // We'd need to cache our ascent for that, of course.

  // Reflow the contents of the button.
  // (This populates our aDesiredSize, too.)
  ReflowButtonContents(aPresContext, aDesiredSize,
                       aReflowState, firstKid);

  ConsiderChildOverflow(aDesiredSize.mOverflowAreas, firstKid);

  aStatus = NS_FRAME_COMPLETE;
  FinishReflowWithAbsoluteFrames(aPresContext, aDesiredSize,
                                 aReflowState, aStatus);

  // We're always complete and we don't support overflow containers
  // so we shouldn't have a next-in-flow ever.
  aStatus = NS_FRAME_COMPLETE;
  MOZ_ASSERT(!GetNextInFlow());

  NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
}
Esempio n. 7
0
nsColumnSetFrame::ReflowConfig
nsColumnSetFrame::ChooseColumnStrategy(const nsHTMLReflowState& aReflowState,
                                       bool aForceAuto = false,
                                       nscoord aFeasibleBSize = NS_INTRINSICSIZE,
                                       nscoord aInfeasibleBSize = 0)
{
    nscoord knownFeasibleBSize = aFeasibleBSize;
    nscoord knownInfeasibleBSize = aInfeasibleBSize;

    const nsStyleColumn* colStyle = StyleColumn();
    nscoord availContentISize = GetAvailableContentISize(aReflowState);
    if (aReflowState.ComputedISize() != NS_INTRINSICSIZE) {
        availContentISize = aReflowState.ComputedISize();
    }

    nscoord consumedBSize = GetConsumedBSize();

    // The effective computed height is the height of the current continuation
    // of the column set frame. This should be the same as the computed height
    // if we have an unconstrained available height.
    nscoord computedBSize = GetEffectiveComputedBSize(aReflowState,
                            consumedBSize);
    nscoord colBSize = GetAvailableContentBSize(aReflowState);

    if (aReflowState.ComputedBSize() != NS_INTRINSICSIZE) {
        colBSize = aReflowState.ComputedBSize();
    } else if (aReflowState.ComputedMaxBSize() != NS_INTRINSICSIZE) {
        colBSize = std::min(colBSize, aReflowState.ComputedMaxBSize());
    }

    nscoord colGap = GetColumnGap(this, colStyle);
    int32_t numColumns = colStyle->mColumnCount;

    // If column-fill is set to 'balance', then we want to balance the columns.
    const bool isBalancing = colStyle->mColumnFill == NS_STYLE_COLUMN_FILL_BALANCE
                             && !aForceAuto;
    if (isBalancing) {
        const uint32_t MAX_NESTED_COLUMN_BALANCING = 2;
        uint32_t cnt = 0;
        for (const nsHTMLReflowState* rs = aReflowState.parentReflowState;
                rs && cnt < MAX_NESTED_COLUMN_BALANCING; rs = rs->parentReflowState) {
            if (rs->mFlags.mIsColumnBalancing) {
                ++cnt;
            }
        }
        if (cnt == MAX_NESTED_COLUMN_BALANCING) {
            numColumns = 1;
        }
    }

    nscoord colISize;
    // In vertical writing-mode, "column-width" (inline size) will actually be
    // physical height, but its CSS name is still column-width.
    if (colStyle->mColumnWidth.GetUnit() == eStyleUnit_Coord) {
        colISize = colStyle->mColumnWidth.GetCoordValue();
        NS_ASSERTION(colISize >= 0, "negative column width");
        // Reduce column count if necessary to make columns fit in the
        // available width. Compute max number of columns that fit in
        // availContentISize, satisfying colGap*(maxColumns - 1) +
        // colISize*maxColumns <= availContentISize
        if (availContentISize != NS_INTRINSICSIZE && colGap + colISize > 0
                && numColumns > 0) {
            // This expression uses truncated rounding, which is what we
            // want
            int32_t maxColumns =
                std::min(nscoord(nsStyleColumn::kMaxColumnCount),
                         (availContentISize + colGap) / (colGap + colISize));
            numColumns = std::max(1, std::min(numColumns, maxColumns));
        }
    } else if (numColumns > 0 && availContentISize != NS_INTRINSICSIZE) {
        nscoord iSizeMinusGaps = availContentISize - colGap * (numColumns - 1);
        colISize = iSizeMinusGaps / numColumns;
    } else {
        colISize = NS_INTRINSICSIZE;
    }
    // Take care of the situation where there's only one column but it's
    // still too wide
    colISize = std::max(1, std::min(colISize, availContentISize));

    nscoord expectedISizeLeftOver = 0;

    if (colISize != NS_INTRINSICSIZE && availContentISize != NS_INTRINSICSIZE) {
        // distribute leftover space

        // First, determine how many columns will be showing if the column
        // count is auto
        if (numColumns <= 0) {
            // choose so that colGap*(nominalColumnCount - 1) +
            // colISize*nominalColumnCount is nearly availContentISize
            // make sure to round down
            if (colGap + colISize > 0) {
                numColumns = (availContentISize + colGap) / (colGap + colISize);
                // The number of columns should never exceed kMaxColumnCount.
                numColumns = std::min(nscoord(nsStyleColumn::kMaxColumnCount),
                                      numColumns);
            }
            if (numColumns <= 0) {
                numColumns = 1;
            }
        }

        // Compute extra space and divide it among the columns
        nscoord extraSpace =
            std::max(0, availContentISize - (colISize * numColumns +
                                             colGap * (numColumns - 1)));
        nscoord extraToColumns = extraSpace / numColumns;
        colISize += extraToColumns;
        expectedISizeLeftOver = extraSpace - (extraToColumns * numColumns);
    }

    if (isBalancing) {
        if (numColumns <= 0) {
            // Hmm, auto column count, column width or available width is unknown,
            // and balancing is required. Let's just use one column then.
            numColumns = 1;
        }
        colBSize = std::min(mLastBalanceBSize, colBSize);
    } else {
        // This is the case when the column-fill property is set to 'auto'.
        // No balancing, so don't limit the column count
        numColumns = INT32_MAX;

        // XXX_jwir3: If a page's height is set to 0, we could continually
        //            create continuations, resulting in an infinite loop, since
        //            no progress is ever made. This is an issue with the spec
        //            (css3-multicol, css3-page, and css3-break) that is
        //            unresolved as of 27 Feb 2013. For the time being, we set this
        //            to have a minimum of 1 css px. Once a resolution is made
        //            on what minimum to have for a page height, we may need to
        //            change this value to match the appropriate spec(s).
        colBSize = std::max(colBSize, nsPresContext::CSSPixelsToAppUnits(1));
    }

#ifdef DEBUG_roc
    printf("*** nsColumnSetFrame::ChooseColumnStrategy: numColumns=%d, colISize=%d,"
           " expectedISizeLeftOver=%d, colBSize=%d, colGap=%d\n",
           numColumns, colISize, expectedISizeLeftOver, colBSize, colGap);
#endif
    ReflowConfig config = { numColumns, colISize, expectedISizeLeftOver, colGap,
                            colBSize, isBalancing, knownFeasibleBSize,
                            knownInfeasibleBSize, computedBSize, consumedBSize
                          };
    return config;
}
Esempio n. 8
0
bool
nsColumnSetFrame::ReflowChildren(nsHTMLReflowMetrics&     aDesiredSize,
                                 const nsHTMLReflowState& aReflowState,
                                 nsReflowStatus&          aStatus,
                                 const ReflowConfig&      aConfig,
                                 bool                     aUnboundedLastColumn,
                                 nsCollapsingMargin*      aBottomMarginCarriedOut,
                                 ColumnBalanceData&       aColData)
{
  aColData.Reset();
  bool allFit = true;
  bool RTL = StyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL;
  bool shrinkingHeightOnly = !NS_SUBTREE_DIRTY(this) &&
    mLastBalanceHeight > aConfig.mColMaxHeight;
  
#ifdef DEBUG_roc
  printf("*** Doing column reflow pass: mLastBalanceHeight=%d, mColMaxHeight=%d, RTL=%d\n, mBalanceColCount=%d, mColWidth=%d, mColGap=%d\n",
         mLastBalanceHeight, aConfig.mColMaxHeight, RTL, aConfig.mBalanceColCount,
         aConfig.mColWidth, aConfig.mColGap);
#endif

  DrainOverflowColumns();

  const bool colHeightChanged = mLastBalanceHeight != aConfig.mColMaxHeight;

  if (colHeightChanged) {
    mLastBalanceHeight = aConfig.mColMaxHeight;
    // XXX Seems like this could fire if incremental reflow pushed the column set
    // down so we reflow incrementally with a different available height.
    // We need a way to do an incremental reflow and be sure availableHeight
    // changes are taken account of! Right now I think block frames with absolute
    // children might exit early.
    //NS_ASSERTION(aKidReason != eReflowReason_Incremental,
    //             "incremental reflow should not have changed the balance height");
  }

  // get our border and padding
  nsMargin borderPadding = aReflowState.ComputedPhysicalBorderPadding();
  borderPadding.ApplySkipSides(GetSkipSides(&aReflowState));
  
  nsRect contentRect(0, 0, 0, 0);
  nsOverflowAreas overflowRects;

  nsIFrame* child = mFrames.FirstChild();
  nsPoint childOrigin = nsPoint(borderPadding.left, borderPadding.top);
  // For RTL, figure out where the last column's left edge should be. Since the
  // columns might not fill the frame exactly, we need to account for the
  // slop. Otherwise we'll waste time moving the columns by some tiny
  // amount unnecessarily.
  if (RTL) {
    nscoord availWidth = aReflowState.AvailableWidth();
    if (aReflowState.ComputedWidth() != NS_INTRINSICSIZE) {
      availWidth = aReflowState.ComputedWidth();
    }
    if (availWidth != NS_INTRINSICSIZE) {
      childOrigin.x += availWidth - aConfig.mColWidth;
#ifdef DEBUG_roc
      printf("*** childOrigin.x = %d\n", childOrigin.x);
#endif
    }
  }
  int columnCount = 0;
  int contentBEnd = 0;
  bool reflowNext = false;

  while (child) {
    // Try to skip reflowing the child. We can't skip if the child is dirty. We also can't
    // skip if the next column is dirty, because the next column's first line(s)
    // might be pullable back to this column. We can't skip if it's the last child
    // because we need to obtain the bottom margin. We can't skip
    // if this is the last column and we're supposed to assign unbounded
    // height to it, because that could change the available height from
    // the last time we reflowed it and we should try to pull all the
    // content from its next sibling. (Note that it might be the last
    // column, but not be the last child because the desired number of columns
    // has changed.)
    bool skipIncremental = !aReflowState.ShouldReflowAllKids()
      && !NS_SUBTREE_DIRTY(child)
      && child->GetNextSibling()
      && !(aUnboundedLastColumn && columnCount == aConfig.mBalanceColCount - 1)
      && !NS_SUBTREE_DIRTY(child->GetNextSibling());
    // If we need to pull up content from the prev-in-flow then this is not just
    // a height shrink. The prev in flow will have set the dirty bit.
    // Check the overflow rect YMost instead of just the child's content height. The child
    // may have overflowing content that cares about the available height boundary.
    // (It may also have overflowing content that doesn't care about the available height
    // boundary, but if so, too bad, this optimization is defeated.)
    // We want scrollable overflow here since this is a calculation that
    // affects layout.
    bool skipResizeHeightShrink = shrinkingHeightOnly
      && child->GetScrollableOverflowRect().YMost() <= aConfig.mColMaxHeight;

    nscoord childContentBEnd = 0;
    WritingMode wm = child->GetWritingMode();
    if (!reflowNext && (skipIncremental || skipResizeHeightShrink)) {
      // This child does not need to be reflowed, but we may need to move it
      MoveChildTo(this, child, childOrigin);
      
      // If this is the last frame then make sure we get the right status
      nsIFrame* kidNext = child->GetNextSibling();
      if (kidNext) {
        aStatus = (kidNext->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)
                  ? NS_FRAME_OVERFLOW_INCOMPLETE
                  : NS_FRAME_NOT_COMPLETE;
      } else {
        aStatus = mLastFrameStatus;
      }
      childContentBEnd = nsLayoutUtils::CalculateContentBEnd(wm, child);
#ifdef DEBUG_roc
      printf("*** Skipping child #%d %p (incremental %d, resize height shrink %d): status = %d\n",
             columnCount, (void*)child, skipIncremental, skipResizeHeightShrink, aStatus);
#endif
    } else {
      nsSize physicalSize(aConfig.mColWidth, aConfig.mColMaxHeight);

      if (aUnboundedLastColumn && columnCount == aConfig.mBalanceColCount - 1) {
        physicalSize.height = GetAvailableContentHeight(aReflowState);
      }
      LogicalSize availSize(wm, physicalSize);
      LogicalSize computedSize = aReflowState.ComputedSize(wm);

      if (reflowNext)
        child->AddStateBits(NS_FRAME_IS_DIRTY);

      nsHTMLReflowState kidReflowState(PresContext(), aReflowState, child,
                                       availSize, availSize.ISize(wm),
                                       computedSize.BSize(wm));
      kidReflowState.mFlags.mIsTopOfPage = true;
      kidReflowState.mFlags.mTableIsSplittable = false;
      kidReflowState.mFlags.mIsColumnBalancing = aConfig.mBalanceColCount < INT32_MAX;

      // We need to reflow any float placeholders, even if our column height
      // hasn't changed.
      kidReflowState.mFlags.mMustReflowPlaceholders = !colHeightChanged;

#ifdef DEBUG_roc
      printf("*** Reflowing child #%d %p: availHeight=%d\n",
             columnCount, (void*)child,availSize.BSize(wm));
#endif

      // Note if the column's next in flow is not being changed by this incremental reflow.
      // This may allow the current column to avoid trying to pull lines from the next column.
      if (child->GetNextSibling() &&
          !(GetStateBits() & NS_FRAME_IS_DIRTY) &&
        !(child->GetNextSibling()->GetStateBits() & NS_FRAME_IS_DIRTY)) {
        kidReflowState.mFlags.mNextInFlowUntouched = true;
      }

      nsHTMLReflowMetrics kidDesiredSize(wm, aDesiredSize.mFlags);

      // XXX it would be cool to consult the float manager for the
      // previous block to figure out the region of floats from the
      // previous column that extend into this column, and subtract
      // that region from the new float manager.  So you could stick a
      // really big float in the first column and text in following
      // columns would flow around it.

      // Reflow the frame
      ReflowChild(child, PresContext(), kidDesiredSize, kidReflowState,
                  childOrigin.x + kidReflowState.ComputedPhysicalMargin().left,
                  childOrigin.y + kidReflowState.ComputedPhysicalMargin().top,
                  0, aStatus);

      reflowNext = (aStatus & NS_FRAME_REFLOW_NEXTINFLOW) != 0;
    
#ifdef DEBUG_roc
      printf("*** Reflowed child #%d %p: status = %d, desiredSize=%d,%d CarriedOutBottomMargin=%d\n",
             columnCount, (void*)child, aStatus, kidDesiredSize.Width(), kidDesiredSize.Height(),
             kidDesiredSize.mCarriedOutBEndMargin.get());
#endif

      NS_FRAME_TRACE_REFLOW_OUT("Column::Reflow", aStatus);

      *aBottomMarginCarriedOut = kidDesiredSize.mCarriedOutBEndMargin;
      
      FinishReflowChild(child, PresContext(), kidDesiredSize,
                        &kidReflowState, childOrigin.x, childOrigin.y, 0);

      childContentBEnd = nsLayoutUtils::CalculateContentBEnd(wm, child);
      if (childContentBEnd > aConfig.mColMaxHeight) {
        allFit = false;
      }
      if (childContentBEnd > availSize.BSize(wm)) {
        aColData.mMaxOverflowingHeight = std::max(childContentBEnd,
            aColData.mMaxOverflowingHeight);
      }
    }

    contentRect.UnionRect(contentRect, child->GetRect());

    ConsiderChildOverflow(overflowRects, child);
    contentBEnd = std::max(contentBEnd, childContentBEnd);
    aColData.mLastHeight = childContentBEnd;
    aColData.mSumHeight += childContentBEnd;

    // Build a continuation column if necessary
    nsIFrame* kidNextInFlow = child->GetNextInFlow();

    if (NS_FRAME_IS_FULLY_COMPLETE(aStatus) && !NS_FRAME_IS_TRUNCATED(aStatus)) {
      NS_ASSERTION(!kidNextInFlow, "next in flow should have been deleted");
      child = nullptr;
      break;
    } else {
      ++columnCount;
      // Make sure that the column has a next-in-flow. If not, we must
      // create one to hold the overflowing stuff, even if we're just
      // going to put it on our overflow list and let *our*
      // next in flow handle it.
      if (!kidNextInFlow) {
        NS_ASSERTION(aStatus & NS_FRAME_REFLOW_NEXTINFLOW,
                     "We have to create a continuation, but the block doesn't want us to reflow it?");

        // We need to create a continuing column
        nsresult rv = CreateNextInFlow(child, kidNextInFlow);
        
        if (NS_FAILED(rv)) {
          NS_NOTREACHED("Couldn't create continuation");
          child = nullptr;
          break;
        }
      }

      // Make sure we reflow a next-in-flow when it switches between being
      // normal or overflow container
      if (NS_FRAME_OVERFLOW_IS_INCOMPLETE(aStatus)) {
        if (!(kidNextInFlow->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)) {
          aStatus |= NS_FRAME_REFLOW_NEXTINFLOW;
          reflowNext = true;
          kidNextInFlow->AddStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER);
        }
      }
      else if (kidNextInFlow->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) {
        aStatus |= NS_FRAME_REFLOW_NEXTINFLOW;
        reflowNext = true;
        kidNextInFlow->RemoveStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER);
      }

      if ((contentBEnd > aReflowState.ComputedMaxBSize() ||
           contentBEnd > aReflowState.ComputedBSize()) &&
           aConfig.mBalanceColCount < INT32_MAX) {
        // We overflowed vertically, but have not exceeded the number of
        // columns. We're going to go into overflow columns now, so balancing
        // no longer applies.
        aColData.mHasExcessHeight = true;
      }

      if (columnCount >= aConfig.mBalanceColCount) {
        // No more columns allowed here. Stop.
        aStatus |= NS_FRAME_REFLOW_NEXTINFLOW;
        kidNextInFlow->AddStateBits(NS_FRAME_IS_DIRTY);
        // Move any of our leftover columns to our overflow list. Our
        // next-in-flow will eventually pick them up.
        const nsFrameList& continuationColumns = mFrames.RemoveFramesAfter(child);
        if (continuationColumns.NotEmpty()) {
          SetOverflowFrames(continuationColumns);
        }
        child = nullptr;
        break;
      }
    }

    if (PresContext()->HasPendingInterrupt()) {
      // Stop the loop now while |child| still points to the frame that bailed
      // out.  We could keep going here and condition a bunch of the code in
      // this loop on whether there's an interrupt, or even just keep going and
      // trying to reflow the blocks (even though we know they'll interrupt
      // right after their first line), but stopping now is conceptually the
      // simplest (and probably fastest) thing.
      break;
    }

    // Advance to the next column
    child = child->GetNextSibling();

    if (child) {
      if (!RTL) {
        childOrigin.x += aConfig.mColWidth + aConfig.mColGap;
      } else {
        childOrigin.x -= aConfig.mColWidth + aConfig.mColGap;
      }
      
#ifdef DEBUG_roc
      printf("*** NEXT CHILD ORIGIN.x = %d\n", childOrigin.x);
#endif
    }
  }

  if (PresContext()->CheckForInterrupt(this) &&
      (GetStateBits() & NS_FRAME_IS_DIRTY)) {
    // Mark all our kids starting with |child| dirty

    // Note that this is a CheckForInterrupt call, not a HasPendingInterrupt,
    // because we might have interrupted while reflowing |child|, and since
    // we're about to add a dirty bit to |child| we need to make sure that
    // |this| is scheduled to have dirty bits marked on it and its ancestors.
    // Otherwise, when we go to mark dirty bits on |child|'s ancestors we'll
    // bail out immediately, since it'll already have a dirty bit.
    for (; child; child = child->GetNextSibling()) {
      child->AddStateBits(NS_FRAME_IS_DIRTY);
    }
  }
  
  aColData.mMaxHeight = contentBEnd;
  contentRect.height = std::max(contentRect.height, contentBEnd);
  mLastFrameStatus = aStatus;
  
  // contentRect included the borderPadding.left,borderPadding.top of the child rects
  contentRect -= nsPoint(borderPadding.left, borderPadding.top);

  WritingMode wm = aReflowState.GetWritingMode();
  LogicalSize contentSize(wm, nsSize(contentRect.XMost(), contentRect.YMost()));

  // Apply computed and min/max values
  // (aConfig members need to be converted from Width/Height to ISize/BSize)
  if (aConfig.mComputedHeight != NS_INTRINSICSIZE) {
    if (aReflowState.AvailableHeight() != NS_INTRINSICSIZE) {
      contentSize.BSize(wm) = std::min(contentSize.BSize(wm),
                                       aConfig.mComputedHeight);
    } else {
      contentSize.BSize(wm) = aConfig.mComputedHeight;
    }
  } else {
    // We add the "consumed" height back in so that we're applying
    // constraints to the correct height value, then subtract it again
    // after we've finished with the min/max calculation. This prevents us from
    // having a last continuation that is smaller than the min height. but which
    // has prev-in-flows, trigger a larger height than actually required.
    contentSize.BSize(wm) =
      aReflowState.ApplyMinMaxHeight(contentSize.BSize(wm),
                                     aConfig.mConsumedHeight);
  }
  if (aReflowState.ComputedISize() != NS_INTRINSICSIZE) {
    contentSize.ISize(wm) = aReflowState.ComputedISize();
  } else {
    contentSize.ISize(wm) =
      aReflowState.ApplyMinMaxWidth(contentSize.ISize(wm));
  }

  LogicalMargin bp(wm, borderPadding);
  contentSize.ISize(wm) += bp.IStartEnd(wm);
  contentSize.BSize(wm) += bp.BStartEnd(wm);
  aDesiredSize.SetSize(wm, contentSize);
  aDesiredSize.mOverflowAreas = overflowRects;
  aDesiredSize.UnionOverflowAreasWithDesiredBounds();

#ifdef DEBUG_roc
  printf("*** DONE PASS feasible=%d\n", allFit && NS_FRAME_IS_FULLY_COMPLETE(aStatus)
         && !NS_FRAME_IS_TRUNCATED(aStatus));
#endif
  return allFit && NS_FRAME_IS_FULLY_COMPLETE(aStatus)
    && !NS_FRAME_IS_TRUNCATED(aStatus);
}
Esempio n. 9
0
void
nsFieldSetFrame::Reflow(nsPresContext*           aPresContext,
                        nsHTMLReflowMetrics&     aDesiredSize,
                        const nsHTMLReflowState& aReflowState,
                        nsReflowStatus&          aStatus)
{
  MarkInReflow();
  DO_GLOBAL_REFLOW_COUNT("nsFieldSetFrame");
  DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);

  NS_PRECONDITION(aReflowState.ComputedISize() != NS_INTRINSICSIZE,
                  "Should have a precomputed inline-size!");

  // Initialize OUT parameter
  aStatus = NS_FRAME_COMPLETE;

  nsOverflowAreas ocBounds;
  nsReflowStatus ocStatus = NS_FRAME_COMPLETE;
  if (GetPrevInFlow()) {
    ReflowOverflowContainerChildren(aPresContext, aReflowState, ocBounds, 0,
                                    ocStatus);
  }

  //------------ Handle Incremental Reflow -----------------
  bool reflowInner;
  bool reflowLegend;
  nsIFrame* legend = GetLegend();
  nsIFrame* inner = GetInner();
  if (aReflowState.ShouldReflowAllKids()) {
    reflowInner = inner != nullptr;
    reflowLegend = legend != nullptr;
  } else {
    reflowInner = inner && NS_SUBTREE_DIRTY(inner);
    reflowLegend = legend && NS_SUBTREE_DIRTY(legend);
  }

  // We don't allow fieldsets to break vertically. If we did, we'd
  // need logic here to push and pull overflow frames.
  // Since we're not applying our padding in this frame, we need to add it here
  // to compute the available width for our children.
  WritingMode wm = GetWritingMode();
  WritingMode innerWM = inner ? inner->GetWritingMode() : wm;
  WritingMode legendWM = legend ? legend->GetWritingMode() : wm;
  LogicalSize innerAvailSize = aReflowState.ComputedSizeWithPadding(innerWM);
  LogicalSize legendAvailSize = aReflowState.ComputedSizeWithPadding(legendWM);
  innerAvailSize.BSize(innerWM) = legendAvailSize.BSize(legendWM) =
    NS_UNCONSTRAINEDSIZE;
  NS_ASSERTION(!inner ||
      nsLayoutUtils::IntrinsicForContainer(aReflowState.rendContext,
                                           inner,
                                           nsLayoutUtils::MIN_ISIZE) <=
               innerAvailSize.ISize(innerWM),
               "Bogus availSize.ISize; should be bigger");
  NS_ASSERTION(!legend ||
      nsLayoutUtils::IntrinsicForContainer(aReflowState.rendContext,
                                           legend,
                                           nsLayoutUtils::MIN_ISIZE) <=
               legendAvailSize.ISize(legendWM),
               "Bogus availSize.ISize; should be bigger");

  // get our border and padding
  LogicalMargin border = aReflowState.ComputedLogicalBorderPadding() -
                         aReflowState.ComputedLogicalPadding();

  // Figure out how big the legend is if there is one.
  // get the legend's margin
  LogicalMargin legendMargin(wm);
  // reflow the legend only if needed
  Maybe<nsHTMLReflowState> legendReflowState;
  if (legend) {
    legendReflowState.emplace(aPresContext, aReflowState, legend,
                                legendAvailSize);
  }
  if (reflowLegend) {
    nsHTMLReflowMetrics legendDesiredSize(aReflowState);

    // We'll move the legend to its proper place later, so the position
    // and containerSize passed here are unimportant.
    const nsSize dummyContainerSize;
    ReflowChild(legend, aPresContext, legendDesiredSize, *legendReflowState,
                wm, LogicalPoint(wm), dummyContainerSize,
                NS_FRAME_NO_MOVE_FRAME, aStatus);
#ifdef NOISY_REFLOW
    printf("  returned (%d, %d)\n",
           legendDesiredSize.Width(), legendDesiredSize.Height());
#endif
    // figure out the legend's rectangle
    legendMargin = legend->GetLogicalUsedMargin(wm);
    mLegendRect =
      LogicalRect(wm, 0, 0,
                  legendDesiredSize.ISize(wm) + legendMargin.IStartEnd(wm),
                  legendDesiredSize.BSize(wm) + legendMargin.BStartEnd(wm));
    nscoord oldSpace = mLegendSpace;
    mLegendSpace = 0;
    if (mLegendRect.BSize(wm) > border.BStart(wm)) {
      // center the border on the legend
      mLegendSpace = mLegendRect.BSize(wm) - border.BStart(wm);
    } else {
      mLegendRect.BStart(wm) =
        (border.BStart(wm) - mLegendRect.BSize(wm)) / 2;
    }

    // if the legend space changes then we need to reflow the
    // content area as well.
    if (mLegendSpace != oldSpace && inner) {
      reflowInner = true;
    }

    FinishReflowChild(legend, aPresContext, legendDesiredSize,
                      legendReflowState.ptr(), wm, LogicalPoint(wm),
                      dummyContainerSize, NS_FRAME_NO_MOVE_FRAME);
  } else if (!legend) {
    mLegendRect.SetEmpty();
    mLegendSpace = 0;
  } else {
    // mLegendSpace and mLegendRect haven't changed, but we need
    // the used margin when placing the legend.
    legendMargin = legend->GetLogicalUsedMargin(wm);
  }

  // This containerSize is incomplete as yet: it does not include the size
  // of the |inner| frame itself.
  nsSize containerSize = (LogicalSize(wm, 0, mLegendSpace) +
                          border.Size(wm)).GetPhysicalSize(wm);
  // reflow the content frame only if needed
  if (reflowInner) {
    nsHTMLReflowState kidReflowState(aPresContext, aReflowState, inner,
                                     innerAvailSize, nullptr,
                                     nsHTMLReflowState::CALLER_WILL_INIT);
    // Override computed padding, in case it's percentage padding
    kidReflowState.Init(aPresContext, nullptr, nullptr,
                        &aReflowState.ComputedPhysicalPadding());
    // Our child is "height:100%" but we actually want its height to be reduced
    // by the amount of content-height the legend is eating up, unless our
    // height is unconstrained (in which case the child's will be too).
    if (aReflowState.ComputedBSize() != NS_UNCONSTRAINEDSIZE) {
      kidReflowState.SetComputedBSize(
         std::max(0, aReflowState.ComputedBSize() - mLegendSpace));
    }

    if (aReflowState.ComputedMinBSize() > 0) {
      kidReflowState.ComputedMinBSize() =
        std::max(0, aReflowState.ComputedMinBSize() - mLegendSpace);
    }

    if (aReflowState.ComputedMaxBSize() != NS_UNCONSTRAINEDSIZE) {
      kidReflowState.ComputedMaxBSize() =
        std::max(0, aReflowState.ComputedMaxBSize() - mLegendSpace);
    }

    nsHTMLReflowMetrics kidDesiredSize(kidReflowState,
                                       aDesiredSize.mFlags);
    // Reflow the frame
    NS_ASSERTION(kidReflowState.ComputedPhysicalMargin() == nsMargin(0,0,0,0),
                 "Margins on anonymous fieldset child not supported!");
    LogicalPoint pt(wm, border.IStart(wm), border.BStart(wm) + mLegendSpace);

    // We don't know the correct containerSize until we have reflowed |inner|,
    // so we use a dummy value for now; FinishReflowChild will fix the position
    // if necessary.
    const nsSize dummyContainerSize;
    ReflowChild(inner, aPresContext, kidDesiredSize, kidReflowState,
                wm, pt, dummyContainerSize, 0, aStatus);

    // Update containerSize to account for size of the inner frame, so that
    // FinishReflowChild can position it correctly.
    containerSize += kidDesiredSize.PhysicalSize();
    FinishReflowChild(inner, aPresContext, kidDesiredSize,
                      &kidReflowState, wm, pt, containerSize, 0);
    NS_FRAME_TRACE_REFLOW_OUT("FieldSet::Reflow", aStatus);
  } else if (inner) {
    // |inner| didn't need to be reflowed but we do need to include its size
    // in containerSize.
    containerSize += inner->GetSize();
  }

  LogicalRect contentRect(wm);
  if (inner) {
    // We don't support margins on inner, so our content rect is just the
    // inner's border-box. (We don't really care about container size at this
    // point, as we'll figure out the actual positioning later.)
    contentRect = inner->GetLogicalRect(wm, containerSize);
  }

  // Our content rect must fill up the available width
  LogicalSize availSize = aReflowState.ComputedSizeWithPadding(wm);
  if (availSize.ISize(wm) > contentRect.ISize(wm)) {
    contentRect.ISize(wm) = innerAvailSize.ISize(wm);
  }

  if (legend) {
    // The legend is positioned inline-wards within the inner's content rect
    // (so that padding on the fieldset affects the legend position).
    LogicalRect innerContentRect = contentRect;
    innerContentRect.Deflate(wm, aReflowState.ComputedLogicalPadding());
    // If the inner content rect is larger than the legend, we can align the
    // legend.
    if (innerContentRect.ISize(wm) > mLegendRect.ISize(wm)) {
      int32_t align = static_cast<nsLegendFrame*>
        (legend->GetContentInsertionFrame())->GetAlign();
      if (!wm.IsBidiLTR()) {
        if (align == NS_STYLE_TEXT_ALIGN_LEFT ||
            align == NS_STYLE_TEXT_ALIGN_MOZ_LEFT) {
          align = NS_STYLE_TEXT_ALIGN_END;
        } else if (align == NS_STYLE_TEXT_ALIGN_RIGHT ||
                   align == NS_STYLE_TEXT_ALIGN_MOZ_RIGHT) {
          align = NS_STYLE_TEXT_ALIGN_DEFAULT;
        }
      }
      switch (align) {
        case NS_STYLE_TEXT_ALIGN_END:
          mLegendRect.IStart(wm) =
            innerContentRect.IEnd(wm) - mLegendRect.ISize(wm);
          break;
        case NS_STYLE_TEXT_ALIGN_CENTER:
        case NS_STYLE_TEXT_ALIGN_MOZ_CENTER:
          // Note: rounding removed; there doesn't seem to be any need
          mLegendRect.IStart(wm) = innerContentRect.IStart(wm) +
            (innerContentRect.ISize(wm) - mLegendRect.ISize(wm)) / 2;
          break;
        default:
          mLegendRect.IStart(wm) = innerContentRect.IStart(wm);
          break;
      }
    } else {
      // otherwise make place for the legend
      mLegendRect.IStart(wm) = innerContentRect.IStart(wm);
      innerContentRect.ISize(wm) = mLegendRect.ISize(wm);
      contentRect.ISize(wm) = mLegendRect.ISize(wm) +
        aReflowState.ComputedLogicalPadding().IStartEnd(wm);
    }

    // place the legend
    LogicalRect actualLegendRect = mLegendRect;
    actualLegendRect.Deflate(wm, legendMargin);
    LogicalPoint actualLegendPos(actualLegendRect.Origin(wm));

    // Note that legend's writing mode may be different from the fieldset's,
    // so we need to convert offsets before applying them to it (bug 1134534).
    LogicalMargin offsets =
      legendReflowState->ComputedLogicalOffsets().
        ConvertTo(wm, legendReflowState->GetWritingMode());
    nsHTMLReflowState::ApplyRelativePositioning(legend, wm, offsets,
                                                &actualLegendPos,
                                                containerSize);

    legend->SetPosition(wm, actualLegendPos, containerSize);
    nsContainerFrame::PositionFrameView(legend);
    nsContainerFrame::PositionChildViews(legend);
  }

  // Return our size and our result.
  LogicalSize finalSize(wm, contentRect.ISize(wm) + border.IStartEnd(wm),
                        mLegendSpace + border.BStartEnd(wm) +
                        (inner ? inner->BSize(wm) : 0));
  aDesiredSize.SetSize(wm, finalSize);
  aDesiredSize.SetOverflowAreasToDesiredBounds();

  if (legend) {
    ConsiderChildOverflow(aDesiredSize.mOverflowAreas, legend);
  }
  if (inner) {
    ConsiderChildOverflow(aDesiredSize.mOverflowAreas, inner);
  }

  // Merge overflow container bounds and status.
  aDesiredSize.mOverflowAreas.UnionWith(ocBounds);
  NS_MergeReflowStatusInto(&aStatus, ocStatus);

  FinishReflowWithAbsoluteFrames(aPresContext, aDesiredSize, aReflowState, aStatus);

  InvalidateFrame();

  NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
}
Esempio n. 10
0
void
nsCanvasFrame::Reflow(nsPresContext*           aPresContext,
                      nsHTMLReflowMetrics&     aDesiredSize,
                      const nsHTMLReflowState& aReflowState,
                      nsReflowStatus&          aStatus)
{
  MarkInReflow();
  DO_GLOBAL_REFLOW_COUNT("nsCanvasFrame");
  DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
  NS_FRAME_TRACE_REFLOW_IN("nsCanvasFrame::Reflow");

  // Initialize OUT parameter
  aStatus = NS_FRAME_COMPLETE;

  nsCanvasFrame* prevCanvasFrame = static_cast<nsCanvasFrame*>
                                               (GetPrevInFlow());
  if (prevCanvasFrame) {
    AutoFrameListPtr overflow(aPresContext,
                              prevCanvasFrame->StealOverflowFrames());
    if (overflow) {
      NS_ASSERTION(overflow->OnlyChild(),
                   "must have doc root as canvas frame's only child");
      nsContainerFrame::ReparentFrameViewList(*overflow, prevCanvasFrame, this);
      // Prepend overflow to the our child list. There may already be
      // children placeholders for fixed-pos elements, which don't get
      // reflowed but must not be lost until the canvas frame is destroyed.
      mFrames.InsertFrames(this, nullptr, *overflow);
    }
  }

  // Set our size up front, since some parts of reflow depend on it
  // being already set.  Note that the computed height may be
  // unconstrained; that's ok.  Consumers should watch out for that.
  SetSize(nsSize(aReflowState.ComputedWidth(), aReflowState.ComputedHeight())); 

  // Reflow our one and only normal child frame. It's either the root
  // element's frame or a placeholder for that frame, if the root element
  // is abs-pos or fixed-pos. We may have additional children which
  // are placeholders for continuations of fixed-pos content, but those
  // don't need to be reflowed. The normal child is always comes before
  // the fixed-pos placeholders, because we insert it at the start
  // of the child list, above.
  nsHTMLReflowMetrics kidDesiredSize(aReflowState);
  if (mFrames.IsEmpty()) {
    // We have no child frame, so return an empty size
    aDesiredSize.Width() = aDesiredSize.Height() = 0;
  } else {
    nsIFrame* kidFrame = mFrames.FirstChild();
    bool kidDirty = (kidFrame->GetStateBits() & NS_FRAME_IS_DIRTY) != 0;

    nsHTMLReflowState
      kidReflowState(aPresContext, aReflowState, kidFrame,
                     aReflowState.AvailableSize(kidFrame->GetWritingMode()));

    if (aReflowState.IsVResize() &&
        (kidFrame->GetStateBits() & NS_FRAME_CONTAINS_RELATIVE_HEIGHT)) {
      // Tell our kid it's being vertically resized too.  Bit of a
      // hack for framesets.
      kidReflowState.SetVResize(true);
    }

    WritingMode wm = aReflowState.GetWritingMode();
    WritingMode kidWM = kidReflowState.GetWritingMode();
    nscoord containerWidth = aReflowState.ComputedWidth();

    LogicalMargin margin = kidReflowState.ComputedLogicalMargin();
    LogicalPoint kidPt(kidWM, margin.IStart(kidWM), margin.BStart(kidWM));

    kidReflowState.ApplyRelativePositioning(&kidPt, containerWidth);

    // Reflow the frame
    ReflowChild(kidFrame, aPresContext, kidDesiredSize, kidReflowState,
                kidWM, kidPt, containerWidth, 0, aStatus);

    // Complete the reflow and position and size the child frame
    FinishReflowChild(kidFrame, aPresContext, kidDesiredSize, &kidReflowState,
                      kidWM, kidPt, containerWidth, 0);

    if (!NS_FRAME_IS_FULLY_COMPLETE(aStatus)) {
      nsIFrame* nextFrame = kidFrame->GetNextInFlow();
      NS_ASSERTION(nextFrame || aStatus & NS_FRAME_REFLOW_NEXTINFLOW,
        "If it's incomplete and has no nif yet, it must flag a nif reflow.");
      if (!nextFrame) {
        nextFrame = aPresContext->PresShell()->FrameConstructor()->
          CreateContinuingFrame(aPresContext, kidFrame, this);
        SetOverflowFrames(nsFrameList(nextFrame, nextFrame));
        // Root overflow containers will be normal children of
        // the canvas frame, but that's ok because there
        // aren't any other frames we need to isolate them from
        // during reflow.
      }
      if (NS_FRAME_OVERFLOW_IS_INCOMPLETE(aStatus)) {
        nextFrame->AddStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER);
      }
    }

    // If the child frame was just inserted, then we're responsible for making sure
    // it repaints
    if (kidDirty) {
      // But we have a new child, which will affect our background, so
      // invalidate our whole rect.
      // Note: Even though we request to be sized to our child's size, our
      // scroll frame ensures that we are always the size of the viewport.
      // Also note: GetPosition() on a CanvasFrame is always going to return
      // (0, 0). We only want to invalidate GetRect() since Get*OverflowRect()
      // could also include overflow to our top and left (out of the viewport)
      // which doesn't need to be painted.
      nsIFrame* viewport = PresContext()->GetPresShell()->GetRootFrame();
      viewport->InvalidateFrame();
    }
    
    // Return our desired size. Normally it's what we're told, but
    // sometimes we can be given an unconstrained height (when a window
    // is sizing-to-content), and we should compute our desired height.
    LogicalSize finalSize(wm);
    finalSize.ISize(wm) = aReflowState.ComputedISize();
    if (aReflowState.ComputedBSize() == NS_UNCONSTRAINEDSIZE) {
      finalSize.BSize(wm) = kidFrame->GetLogicalSize(wm).BSize(wm) +
        kidReflowState.ComputedLogicalMargin().BStartEnd(wm);
    } else {
      finalSize.BSize(wm) = aReflowState.ComputedBSize();
    }

    aDesiredSize.SetSize(wm, finalSize);
    aDesiredSize.SetOverflowAreasToDesiredBounds();
    aDesiredSize.mOverflowAreas.UnionWith(
      kidDesiredSize.mOverflowAreas + kidFrame->GetPosition());
  }

  if (prevCanvasFrame) {
    ReflowOverflowContainerChildren(aPresContext, aReflowState,
                                    aDesiredSize.mOverflowAreas, 0,
                                    aStatus);
  }

  FinishReflowWithAbsoluteFrames(aPresContext, aDesiredSize, aReflowState, aStatus);

  NS_FRAME_TRACE_REFLOW_OUT("nsCanvasFrame::Reflow", aStatus);
  NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
}
Esempio n. 11
0
nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
                                       nsPresContext* aPresContext,
                                       nsBlockFrame* aFrame,
                                       bool aBStartMarginRoot,
                                       bool aBEndMarginRoot,
                                       bool aBlockNeedsFloatManager,
                                       nscoord aConsumedBSize)
  : mBlock(aFrame),
    mPresContext(aPresContext),
    mReflowState(aReflowState),
    mContentArea(aReflowState.GetWritingMode()),
    mPushedFloats(nullptr),
    mOverflowTracker(nullptr),
    mBorderPadding(mReflowState.ComputedLogicalBorderPadding()),
    mPrevBEndMargin(),
    mLineNumber(0),
    mFlags(0),
    mFloatBreakType(NS_STYLE_CLEAR_NONE),
    mConsumedBSize(aConsumedBSize)
{
  if (!sFloatFragmentsInsideColumnPrefCached) {
    sFloatFragmentsInsideColumnPrefCached = true;
    Preferences::AddBoolVarCache(&sFloatFragmentsInsideColumnEnabled,
                                 "layout.float-fragments-inside-column.enabled");
  }
  SetFlag(BRS_FLOAT_FRAGMENTS_INSIDE_COLUMN_ENABLED, sFloatFragmentsInsideColumnEnabled);
  
  WritingMode wm = aReflowState.GetWritingMode();
  SetFlag(BRS_ISFIRSTINFLOW, aFrame->GetPrevInFlow() == nullptr);
  SetFlag(BRS_ISOVERFLOWCONTAINER, IS_TRUE_OVERFLOW_CONTAINER(aFrame));

  nsIFrame::LogicalSides logicalSkipSides =
    aFrame->GetLogicalSkipSides(&aReflowState);
  mBorderPadding.ApplySkipSides(logicalSkipSides);

  // Note that mContainerSize is the physical size, needed to
  // convert logical block-coordinates in vertical-rl writing mode
  // (measured from a RHS origin) to physical coordinates within the
  // containing block.
  // If aReflowState doesn't have a constrained ComputedWidth(), we set
  // mContainerSize.width to zero, which means lines will be positioned
  // (physically) incorrectly; we will fix them up at the end of
  // nsBlockFrame::Reflow, after we know the total block-size of the
  // frame.
  mContainerSize.width = aReflowState.ComputedWidth();
  if (mContainerSize.width == NS_UNCONSTRAINEDSIZE) {
    mContainerSize.width = 0;
  }

  mContainerSize.width += mBorderPadding.LeftRight(wm);

  // For now at least, we don't do that fix-up for mContainerHeight.
  // It's only used in nsBidiUtils::ReorderFrames for vertical rtl
  // writing modes, which aren't fully supported for the time being.
  mContainerSize.height = aReflowState.ComputedHeight() +
                          mBorderPadding.TopBottom(wm);

  if ((aBStartMarginRoot && !logicalSkipSides.BStart()) ||
      0 != mBorderPadding.BStart(wm)) {
    SetFlag(BRS_ISBSTARTMARGINROOT, true);
    SetFlag(BRS_APPLYBSTARTMARGIN, true);
  }
  if ((aBEndMarginRoot && !logicalSkipSides.BEnd()) ||
      0 != mBorderPadding.BEnd(wm)) {
    SetFlag(BRS_ISBENDMARGINROOT, true);
  }
  if (aBlockNeedsFloatManager) {
    SetFlag(BRS_FLOAT_MGR, true);
  }
  
  mFloatManager = aReflowState.mFloatManager;

  NS_ASSERTION(mFloatManager,
               "FloatManager should be set in nsBlockReflowState" );
  if (mFloatManager) {
    // Save the coordinate system origin for later.
    mFloatManager->GetTranslation(mFloatManagerI, mFloatManagerB);
    mFloatManager->PushState(&mFloatManagerStateBefore); // never popped
  }

  mReflowStatus = NS_FRAME_COMPLETE;

  mNextInFlow = static_cast<nsBlockFrame*>(mBlock->GetNextInFlow());

  LAYOUT_WARN_IF_FALSE(NS_UNCONSTRAINEDSIZE != aReflowState.ComputedISize(),
                       "have unconstrained width; this should only result "
                       "from very large sizes, not attempts at intrinsic "
                       "width calculation");
  mContentArea.ISize(wm) = aReflowState.ComputedISize();

  // Compute content area height. Unlike the width, if we have a
  // specified style height we ignore it since extra content is
  // managed by the "overflow" property. When we don't have a
  // specified style height then we may end up limiting our height if
  // the availableHeight is constrained (this situation occurs when we
  // are paginated).
  if (NS_UNCONSTRAINEDSIZE != aReflowState.AvailableBSize()) {
    // We are in a paginated situation. The bottom edge is just inside
    // the bottom border and padding. The content area height doesn't
    // include either border or padding edge.
    mBEndEdge = aReflowState.AvailableBSize() - mBorderPadding.BEnd(wm);
    mContentArea.BSize(wm) = std::max(0, mBEndEdge - mBorderPadding.BStart(wm));
  }
  else {
    // When we are not in a paginated situation then we always use
    // an constrained height.
    SetFlag(BRS_UNCONSTRAINEDBSIZE, true);
    mContentArea.BSize(wm) = mBEndEdge = NS_UNCONSTRAINEDSIZE;
  }
  mContentArea.IStart(wm) = mBorderPadding.IStart(wm);
  mBCoord = mContentArea.BStart(wm) = mBorderPadding.BStart(wm);

  mPrevChild = nullptr;
  mCurrentLine = aFrame->end_lines();

  mMinLineHeight = aReflowState.CalcLineHeight();
}
void
nsPageContentFrame::Reflow(nsPresContext*           aPresContext,
                           nsHTMLReflowMetrics&     aDesiredSize,
                           const nsHTMLReflowState& aReflowState,
                           nsReflowStatus&          aStatus)
{
  DO_GLOBAL_REFLOW_COUNT("nsPageContentFrame");
  DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
  aStatus = NS_FRAME_COMPLETE;  // initialize out parameter

  if (GetPrevInFlow() && (GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
    nsresult rv = aPresContext->PresShell()->FrameConstructor()
                    ->ReplicateFixedFrames(this);
    if (NS_FAILED(rv)) {
      return;
    }
  }

  // Set our size up front, since some parts of reflow depend on it
  // being already set.  Note that the computed height may be
  // unconstrained; that's ok.  Consumers should watch out for that.
  nsSize  maxSize(aReflowState.ComputedWidth(),
                  aReflowState.ComputedHeight());
  SetSize(maxSize);
 
  // A PageContentFrame must always have one child: the canvas frame.
  // Resize our frame allowing it only to be as big as we are
  // XXX Pay attention to the page's border and padding...
  if (mFrames.NotEmpty()) {
    nsIFrame* frame = mFrames.FirstChild();
    WritingMode wm = frame->GetWritingMode();
    LogicalSize logicalSize(wm, maxSize);
    nsHTMLReflowState kidReflowState(aPresContext, aReflowState,
                                     frame, logicalSize);
    kidReflowState.SetComputedBSize(logicalSize.BSize(wm));

    // Reflow the page content area
    ReflowChild(frame, aPresContext, aDesiredSize, kidReflowState, 0, 0, 0, aStatus);

    // The document element's background should cover the entire canvas, so
    // take into account the combined area and any space taken up by
    // absolutely positioned elements
    nsMargin padding(0,0,0,0);

    // XXXbz this screws up percentage padding (sets padding to zero
    // in the percentage padding case)
    kidReflowState.mStylePadding->GetPadding(padding);

    // This is for shrink-to-fit, and therefore we want to use the
    // scrollable overflow, since the purpose of shrink to fit is to
    // make the content that ought to be reachable (represented by the
    // scrollable overflow) fit in the page.
    if (frame->HasOverflowAreas()) {
      // The background covers the content area and padding area, so check
      // for children sticking outside the child frame's padding edge
      nscoord xmost = aDesiredSize.ScrollableOverflow().XMost();
      if (xmost > aDesiredSize.Width()) {
        nscoord widthToFit = xmost + padding.right +
          kidReflowState.mStyleBorder->GetComputedBorderWidth(NS_SIDE_RIGHT);
        float ratio = float(maxSize.width) / widthToFit;
        NS_ASSERTION(ratio >= 0.0 && ratio < 1.0, "invalid shrink-to-fit ratio");
        mPD->mShrinkToFitRatio = std::min(mPD->mShrinkToFitRatio, ratio);
      }
    }

    // Place and size the child
    FinishReflowChild(frame, aPresContext, aDesiredSize, &kidReflowState, 0, 0, 0);

    NS_ASSERTION(aPresContext->IsDynamic() || !NS_FRAME_IS_FULLY_COMPLETE(aStatus) ||
                  !frame->GetNextInFlow(), "bad child flow list");
  }

  // Reflow our fixed frames
  nsReflowStatus fixedStatus = NS_FRAME_COMPLETE;
  ReflowAbsoluteFrames(aPresContext, aDesiredSize, aReflowState, fixedStatus);
  NS_ASSERTION(NS_FRAME_IS_COMPLETE(fixedStatus), "fixed frames can be truncated, but not incomplete");

  // Return our desired size
  WritingMode wm = aReflowState.GetWritingMode();
  LogicalSize finalSize(wm);
  finalSize.ISize(wm) = aReflowState.ComputedISize();
  if (aReflowState.ComputedBSize() != NS_UNCONSTRAINEDSIZE) {
    finalSize.BSize(wm) = aReflowState.ComputedBSize();
  }
  aDesiredSize.SetSize(wm, finalSize);
  FinishAndStoreOverflow(&aDesiredSize);

  NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
}
Esempio n. 13
0
void
nsNumberControlFrame::Reflow(nsPresContext* aPresContext,
                             nsHTMLReflowMetrics& aDesiredSize,
                             const nsHTMLReflowState& aReflowState,
                             nsReflowStatus& aStatus)
{
    MarkInReflow();
    DO_GLOBAL_REFLOW_COUNT("nsNumberControlFrame");
    DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);

    NS_ASSERTION(mOuterWrapper, "Outer wrapper div must exist!");

    NS_ASSERTION(!GetPrevContinuation() && !GetNextContinuation(),
                 "nsNumberControlFrame should not have continuations; if it does we "
                 "need to call RegUnregAccessKey only for the first");

    NS_ASSERTION(!mFrames.FirstChild() ||
                 !mFrames.FirstChild()->GetNextSibling(),
                 "We expect at most one direct child frame");

    if (mState & NS_FRAME_FIRST_REFLOW) {
        nsFormControlFrame::RegUnRegAccessKey(this, true);
    }

    const WritingMode myWM = aReflowState.GetWritingMode();

    // The ISize of our content box, which is the available ISize
    // for our anonymous content:
    const nscoord contentBoxISize = aReflowState.ComputedISize();
    nscoord contentBoxBSize = aReflowState.ComputedBSize();

    // Figure out our border-box sizes as well (by adding borderPadding to
    // content-box sizes):
    const nscoord borderBoxISize = contentBoxISize +
                                   aReflowState.ComputedLogicalBorderPadding().IStartEnd(myWM);

    nscoord borderBoxBSize;
    if (contentBoxBSize != NS_INTRINSICSIZE) {
        borderBoxBSize = contentBoxBSize +
                         aReflowState.ComputedLogicalBorderPadding().BStartEnd(myWM);
    } // else, we'll figure out borderBoxBSize after we resolve contentBoxBSize.

    nsIFrame* outerWrapperFrame = mOuterWrapper->GetPrimaryFrame();

    if (!outerWrapperFrame) { // display:none?
        if (contentBoxBSize == NS_INTRINSICSIZE) {
            contentBoxBSize = 0;
            borderBoxBSize =
                aReflowState.ComputedLogicalBorderPadding().BStartEnd(myWM);
        }
    } else {
        NS_ASSERTION(outerWrapperFrame == mFrames.FirstChild(), "huh?");

        nsHTMLReflowMetrics wrappersDesiredSize(aReflowState);

        WritingMode wrapperWM = outerWrapperFrame->GetWritingMode();
        LogicalSize availSize = aReflowState.ComputedSize(wrapperWM);
        availSize.BSize(wrapperWM) = NS_UNCONSTRAINEDSIZE;

        nsHTMLReflowState wrapperReflowState(aPresContext, aReflowState,
                                             outerWrapperFrame, availSize);

        // Convert wrapper margin into my own writing-mode (in case it differs):
        LogicalMargin wrapperMargin =
            wrapperReflowState.ComputedLogicalMargin().ConvertTo(myWM, wrapperWM);

        // offsets of wrapper frame within this frame:
        LogicalPoint
        wrapperOffset(myWM,
                      aReflowState.ComputedLogicalBorderPadding().IStart(myWM) +
                      wrapperMargin.IStart(myWM),
                      aReflowState.ComputedLogicalBorderPadding().BStart(myWM) +
                      wrapperMargin.BStart(myWM));

        nsReflowStatus childStatus;
        // We initially reflow the child with a dummy containerSize; positioning
        // will be fixed later.
        const nsSize dummyContainerSize;
        ReflowChild(outerWrapperFrame, aPresContext, wrappersDesiredSize,
                    wrapperReflowState, myWM, wrapperOffset, dummyContainerSize, 0,
                    childStatus);
        MOZ_ASSERT(NS_FRAME_IS_FULLY_COMPLETE(childStatus),
                   "We gave our child unconstrained available block-size, "
                   "so it should be complete");

        nscoord wrappersMarginBoxBSize =
            wrappersDesiredSize.BSize(myWM) + wrapperMargin.BStartEnd(myWM);

        if (contentBoxBSize == NS_INTRINSICSIZE) {
            // We are intrinsically sized -- we should shrinkwrap the outer wrapper's
            // block-size:
            contentBoxBSize = wrappersMarginBoxBSize;

            // Make sure we obey min/max-bsize in the case when we're doing intrinsic
            // sizing (we get it for free when we have a non-intrinsic
            // aReflowState.ComputedBSize()).  Note that we do this before
            // adjusting for borderpadding, since ComputedMaxBSize and
            // ComputedMinBSize are content heights.
            contentBoxBSize =
                NS_CSS_MINMAX(contentBoxBSize,
                              aReflowState.ComputedMinBSize(),
                              aReflowState.ComputedMaxBSize());

            borderBoxBSize = contentBoxBSize +
                             aReflowState.ComputedLogicalBorderPadding().BStartEnd(myWM);
        }

        // Center child in block axis
        nscoord extraSpace = contentBoxBSize - wrappersMarginBoxBSize;
        wrapperOffset.B(myWM) += std::max(0, extraSpace / 2);

        // Needed in FinishReflowChild, for logical-to-physical conversion:
        nsSize borderBoxSize = LogicalSize(myWM, borderBoxISize, borderBoxBSize).
                               GetPhysicalSize(myWM);

        // Place the child
        FinishReflowChild(outerWrapperFrame, aPresContext, wrappersDesiredSize,
                          &wrapperReflowState, myWM, wrapperOffset,
                          borderBoxSize, 0);

        nsSize contentBoxSize =
            LogicalSize(myWM, contentBoxISize, contentBoxBSize).
            GetPhysicalSize(myWM);
        aDesiredSize.SetBlockStartAscent(
            wrappersDesiredSize.BlockStartAscent() +
            outerWrapperFrame->BStart(aReflowState.GetWritingMode(),
                                      contentBoxSize));
    }

    LogicalSize logicalDesiredSize(myWM, borderBoxISize, borderBoxBSize);
    aDesiredSize.SetSize(myWM, logicalDesiredSize);

    aDesiredSize.SetOverflowAreasToDesiredBounds();

    if (outerWrapperFrame) {
        ConsiderChildOverflow(aDesiredSize.mOverflowAreas, outerWrapperFrame);
    }

    FinishAndStoreOverflow(&aDesiredSize);

    aStatus = NS_FRAME_COMPLETE;

    NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
}
void
nsHTMLButtonControlFrame::ReflowButtonContents(nsPresContext* aPresContext,
                                               nsHTMLReflowMetrics& aButtonDesiredSize,
                                               const nsHTMLReflowState& aButtonReflowState,
                                               nsIFrame* aFirstKid)
{
  WritingMode wm = GetWritingMode();
  LogicalSize availSize = aButtonReflowState.ComputedSize(wm);
  availSize.BSize(wm) = NS_INTRINSICSIZE;

  // Buttons have some bonus renderer-determined border/padding,
  // which occupies part of the button's content-box area:
  LogicalMargin focusPadding =
    LogicalMargin(wm, mRenderer.GetAddedButtonBorderAndPadding());

  // See whether out availSize's inline-size is big enough.  If it's
  // smaller than our intrinsic min iSize, that means that the kid
  // wouldn't really fit.  In that case, we overflow into our internal
  // focuspadding (which other browsers don't have) so that there's a
  // little more space for it.
  // Note that GetMinISize includes the focusPadding.
  nscoord IOverflow = GetMinISize(aButtonReflowState.rendContext) -
                      aButtonReflowState.ComputedISize();
  nscoord IFocusPadding = focusPadding.IStartEnd(wm);
  nscoord focusPaddingReduction = std::min(IFocusPadding,
                                           std::max(IOverflow, 0));
  if (focusPaddingReduction > 0) {
    nscoord startReduction = focusPadding.IStart(wm);
    if (focusPaddingReduction != IFocusPadding) {
      startReduction = NSToCoordRound(startReduction *
                                      (float(focusPaddingReduction) /
                                       float(IFocusPadding)));
    }
    focusPadding.IStart(wm) -= startReduction;
    focusPadding.IEnd(wm) -= focusPaddingReduction - startReduction;
  }

  // shorthand for a value we need to use in a bunch of places
  const LogicalMargin& clbp = aButtonReflowState.ComputedLogicalBorderPadding();

  // Indent the child inside us by the focus border. We must do this separate
  // from the regular border.
  availSize.ISize(wm) -= focusPadding.IStartEnd(wm);

  LogicalPoint childPos(wm);
  childPos.I(wm) = focusPadding.IStart(wm) + clbp.IStart(wm);
  availSize.ISize(wm) = std::max(availSize.ISize(wm), 0);

  // Give child a clone of the button's reflow state, with height/width reduced
  // by focusPadding, so that descendants with height:100% don't protrude.
  nsHTMLReflowState adjustedButtonReflowState =
    CloneReflowStateWithReducedContentBox(aButtonReflowState,
                                          focusPadding.GetPhysicalMargin(wm));

  nsHTMLReflowState contentsReflowState(aPresContext,
                                        adjustedButtonReflowState,
                                        aFirstKid, availSize);

  nsReflowStatus contentsReflowStatus;
  nsHTMLReflowMetrics contentsDesiredSize(aButtonReflowState);
  childPos.B(wm) = 0; // This will be set properly later, after reflowing the
                      // child to determine its size.

  // We just pass a dummy containerSize here, as the child will be
  // repositioned later by FinishReflowChild.
  nsSize dummyContainerSize;
  ReflowChild(aFirstKid, aPresContext,
              contentsDesiredSize, contentsReflowState,
              wm, childPos, dummyContainerSize, 0, contentsReflowStatus);
  MOZ_ASSERT(NS_FRAME_IS_COMPLETE(contentsReflowStatus),
             "We gave button-contents frame unconstrained available height, "
             "so it should be complete");

  // Compute the button's content-box size:
  LogicalSize buttonContentBox(wm);
  if (aButtonReflowState.ComputedBSize() != NS_INTRINSICSIZE) {
    // Button has a fixed block-size -- that's its content-box bSize.
    buttonContentBox.BSize(wm) = aButtonReflowState.ComputedBSize();
  } else {
    // Button is intrinsically sized -- it should shrinkwrap the
    // button-contents' bSize, plus any focus-padding space:
    buttonContentBox.BSize(wm) =
      contentsDesiredSize.BSize(wm) + focusPadding.BStartEnd(wm);

    // Make sure we obey min/max-bSize in the case when we're doing intrinsic
    // sizing (we get it for free when we have a non-intrinsic
    // aButtonReflowState.ComputedBSize()).  Note that we do this before
    // adjusting for borderpadding, since mComputedMaxBSize and
    // mComputedMinBSize are content bSizes.
    buttonContentBox.BSize(wm) =
      NS_CSS_MINMAX(buttonContentBox.BSize(wm),
                    aButtonReflowState.ComputedMinBSize(),
                    aButtonReflowState.ComputedMaxBSize());
  }
  if (aButtonReflowState.ComputedISize() != NS_INTRINSICSIZE) {
    buttonContentBox.ISize(wm) = aButtonReflowState.ComputedISize();
  } else {
    buttonContentBox.ISize(wm) =
      contentsDesiredSize.ISize(wm) + focusPadding.IStartEnd(wm);
    buttonContentBox.ISize(wm) =
      NS_CSS_MINMAX(buttonContentBox.ISize(wm),
                    aButtonReflowState.ComputedMinISize(),
                    aButtonReflowState.ComputedMaxISize());
  }

  // Center child in the block-direction in the button
  // (technically, inside of the button's focus-padding area)
  nscoord extraSpace =
    buttonContentBox.BSize(wm) - focusPadding.BStartEnd(wm) -
    contentsDesiredSize.BSize(wm);

  childPos.B(wm) = std::max(0, extraSpace / 2);

  // Adjust childPos.B() to be in terms of the button's frame-rect, instead of
  // its focus-padding rect:
  childPos.B(wm) += focusPadding.BStart(wm) + clbp.BStart(wm);

  nsSize containerSize =
    (buttonContentBox + clbp.Size(wm)).GetPhysicalSize(wm);

  // Place the child
  FinishReflowChild(aFirstKid, aPresContext,
                    contentsDesiredSize, &contentsReflowState,
                    wm, childPos, containerSize, 0);

  // Make sure we have a useful 'ascent' value for the child
  if (contentsDesiredSize.BlockStartAscent() ==
      nsHTMLReflowMetrics::ASK_FOR_BASELINE) {
    WritingMode wm = aButtonReflowState.GetWritingMode();
    contentsDesiredSize.SetBlockStartAscent(aFirstKid->GetLogicalBaseline(wm));
  }

  // OK, we're done with the child frame.
  // Use what we learned to populate the button frame's reflow metrics.
  //  * Button's height & width are content-box size + border-box contribution:
  aButtonDesiredSize.SetSize(wm,
    LogicalSize(wm, aButtonReflowState.ComputedISize() + clbp.IStartEnd(wm),
                    buttonContentBox.BSize(wm) + clbp.BStartEnd(wm)));

  //  * Button's ascent is its child's ascent, plus the child's block-offset
  // within our frame... unless it's orthogonal, in which case we'll use the
  // contents inline-size as an approximation for now.
  // XXX is there a better strategy? should we include border-padding?
  if (aButtonDesiredSize.GetWritingMode().IsOrthogonalTo(wm)) {
    aButtonDesiredSize.SetBlockStartAscent(contentsDesiredSize.ISize(wm));
  } else {
    aButtonDesiredSize.SetBlockStartAscent(contentsDesiredSize.BlockStartAscent() +
                                           childPos.B(wm));
  }

  aButtonDesiredSize.SetOverflowAreasToDesiredBounds();
}
Esempio n. 15
0
void
nsColumnSetFrame::Reflow(nsPresContext*           aPresContext,
                         nsHTMLReflowMetrics&     aDesiredSize,
                         const nsHTMLReflowState& aReflowState,
                         nsReflowStatus&          aStatus)
{
    MarkInReflow();
    // Don't support interruption in columns
    nsPresContext::InterruptPreventer noInterrupts(aPresContext);

    DO_GLOBAL_REFLOW_COUNT("nsColumnSetFrame");
    DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);

    // Initialize OUT parameter
    aStatus = NS_FRAME_COMPLETE;

    // Our children depend on our block-size if we have a fixed block-size.
    if (aReflowState.ComputedBSize() != NS_AUTOHEIGHT) {
        AddStateBits(NS_FRAME_CONTAINS_RELATIVE_BSIZE);
    } else {
        RemoveStateBits(NS_FRAME_CONTAINS_RELATIVE_BSIZE);
    }

#ifdef DEBUG
    nsFrameList::Enumerator oc(GetChildList(kOverflowContainersList));
    for (; !oc.AtEnd(); oc.Next()) {
        MOZ_ASSERT(!IS_TRUE_OVERFLOW_CONTAINER(oc.get()));
    }
    nsFrameList::Enumerator eoc(GetChildList(kExcessOverflowContainersList));
    for (; !eoc.AtEnd(); eoc.Next()) {
        MOZ_ASSERT(!IS_TRUE_OVERFLOW_CONTAINER(eoc.get()));
    }
#endif

    nsOverflowAreas ocBounds;
    nsReflowStatus ocStatus = NS_FRAME_COMPLETE;
    if (GetPrevInFlow()) {
        ReflowOverflowContainerChildren(aPresContext, aReflowState, ocBounds, 0,
                                        ocStatus);
    }

    //------------ Handle Incremental Reflow -----------------

    // If inline size is unconstrained, set aForceAuto to true to allow
    // the columns to expand in the inline direction. (This typically
    // happens in orthogonal flows where the inline direction is the
    // container's block direction).
    ReflowConfig config =
        ChooseColumnStrategy(aReflowState,
                             aReflowState.ComputedISize() == NS_UNCONSTRAINEDSIZE);

    // If balancing, then we allow the last column to grow to unbounded
    // height during the first reflow. This gives us a way to estimate
    // what the average column height should be, because we can measure
    // the heights of all the columns and sum them up. But don't do this
    // if we have a next in flow because we don't want to suck all its
    // content back here and then have to push it out again!
    nsIFrame* nextInFlow = GetNextInFlow();
    bool unboundedLastColumn = config.mIsBalancing && !nextInFlow;
    nsCollapsingMargin carriedOutBottomMargin;
    ColumnBalanceData colData;
    colData.mHasExcessBSize = false;

    bool feasible = ReflowColumns(aDesiredSize, aReflowState, aStatus, config,
                                  unboundedLastColumn, &carriedOutBottomMargin,
                                  colData);

    // If we're not balancing, then we're already done, since we should have
    // reflown all of our children, and there is no need for a binary search to
    // determine proper column height.
    if (config.mIsBalancing && !aPresContext->HasPendingInterrupt()) {
        FindBestBalanceBSize(aReflowState, aPresContext, config, colData,
                             aDesiredSize, carriedOutBottomMargin,
                             unboundedLastColumn, feasible, aStatus);
    }

    if (aPresContext->HasPendingInterrupt() &&
            aReflowState.AvailableBSize() == NS_UNCONSTRAINEDSIZE) {
        // In this situation, we might be lying about our reflow status, because
        // our last kid (the one that got interrupted) was incomplete.  Fix that.
        aStatus = NS_FRAME_COMPLETE;
    }

    NS_ASSERTION(NS_FRAME_IS_FULLY_COMPLETE(aStatus) ||
                 aReflowState.AvailableBSize() != NS_UNCONSTRAINEDSIZE,
                 "Column set should be complete if the available block-size is unconstrained");

    // Merge overflow container bounds and status.
    aDesiredSize.mOverflowAreas.UnionWith(ocBounds);
    NS_MergeReflowStatusInto(&aStatus, ocStatus);

    FinishReflowWithAbsoluteFrames(aPresContext, aDesiredSize, aReflowState, aStatus, false);

    aDesiredSize.mCarriedOutBEndMargin = carriedOutBottomMargin;

    NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
}
void
nsHTMLButtonControlFrame::ReflowButtonContents(nsPresContext* aPresContext,
        nsHTMLReflowMetrics& aButtonDesiredSize,
        const nsHTMLReflowState& aButtonReflowState,
        nsIFrame* aFirstKid)
{
    WritingMode wm = GetWritingMode();
    bool isVertical = wm.IsVertical();
    LogicalSize availSize = aButtonReflowState.ComputedSize(wm);
    availSize.BSize(wm) = NS_INTRINSICSIZE;

    // Buttons have some bonus renderer-determined border/padding,
    // which occupies part of the button's content-box area:
    const LogicalMargin focusPadding =
        LogicalMargin(wm, mRenderer.GetAddedButtonBorderAndPadding());

    // shorthand for a value we need to use in a bunch of places
    const LogicalMargin& clbp = aButtonReflowState.ComputedLogicalBorderPadding();

    // Indent the child inside us by the focus border. We must do this separate
    // from the regular border.
    availSize.ISize(wm) -= focusPadding.IStartEnd(wm);

    // See whether out availSize's inline-size is big enough.  If it's smaller than
    // our intrinsic min iSize, that means that the kid wouldn't really fit; for a
    // better look in such cases we adjust the available iSize and our inline-start
    // offset to allow the kid to spill start-wards into our padding.
    nscoord ioffset = focusPadding.IStart(wm) + clbp.IStart(wm);
    nscoord extraISize = GetMinISize(aButtonReflowState.rendContext) -
                         aButtonReflowState.ComputedISize();
    if (extraISize > 0) {
        nscoord extraIStart = extraISize / 2;
        nscoord extraIEnd = extraISize - extraIStart;
        NS_ASSERTION(extraIEnd >=0, "How'd that happen?");

        // Do not allow the extras to be bigger than the relevant padding
        const LogicalMargin& padding = aButtonReflowState.ComputedLogicalPadding();
        extraIStart = std::min(extraIStart, padding.IStart(wm));
        extraIEnd = std::min(extraIEnd, padding.IEnd(wm));
        ioffset -= extraIStart;
        availSize.ISize(wm) = availSize.ISize(wm) + extraIStart + extraIEnd;
    }
    availSize.ISize(wm) = std::max(availSize.ISize(wm), 0);

    // Give child a clone of the button's reflow state, with height/width reduced
    // by focusPadding, so that descendants with height:100% don't protrude.
    nsHTMLReflowState adjustedButtonReflowState =
        CloneReflowStateWithReducedContentBox(aButtonReflowState,
                focusPadding.GetPhysicalMargin(wm));

    nsHTMLReflowState contentsReflowState(aPresContext,
                                          adjustedButtonReflowState,
                                          aFirstKid, availSize);

    nsReflowStatus contentsReflowStatus;
    nsHTMLReflowMetrics contentsDesiredSize(aButtonReflowState);
    nscoord boffset = focusPadding.BStart(wm) + clbp.BStart(wm);
    ReflowChild(aFirstKid, aPresContext,
                contentsDesiredSize, contentsReflowState,
                isVertical ? boffset : ioffset,
                isVertical ? ioffset : boffset,
                0, contentsReflowStatus);
    MOZ_ASSERT(NS_FRAME_IS_COMPLETE(contentsReflowStatus),
               "We gave button-contents frame unconstrained available height, "
               "so it should be complete");

    // Compute the button's content-box height:
    nscoord buttonContentBoxBSize = 0;
    if (aButtonReflowState.ComputedBSize() != NS_INTRINSICSIZE) {
        // Button has a fixed block-size -- that's its content-box bSize.
        buttonContentBoxBSize = aButtonReflowState.ComputedBSize();
    } else {
        // Button is intrinsically sized -- it should shrinkwrap the
        // button-contents' bSize, plus any focus-padding space:
        buttonContentBoxBSize =
            contentsDesiredSize.BSize(wm) + focusPadding.BStartEnd(wm);

        // Make sure we obey min/max-bSize in the case when we're doing intrinsic
        // sizing (we get it for free when we have a non-intrinsic
        // aButtonReflowState.ComputedBSize()).  Note that we do this before
        // adjusting for borderpadding, since mComputedMaxBSize and
        // mComputedMinBSize are content bSizes.
        buttonContentBoxBSize =
            NS_CSS_MINMAX(buttonContentBoxBSize,
                          aButtonReflowState.ComputedMinBSize(),
                          aButtonReflowState.ComputedMaxBSize());
    }

    // Center child in the block-direction in the button
    // (technically, inside of the button's focus-padding area)
    nscoord extraSpace =
        buttonContentBoxBSize - focusPadding.BStartEnd(wm) -
        contentsDesiredSize.BSize(wm);

    boffset = std::max(0, extraSpace / 2);

    // Adjust boffset to be in terms of the button's frame-rect, instead of
    // its focus-padding rect:
    boffset += focusPadding.BStart(wm) + clbp.BStart(wm);

    // Place the child
    FinishReflowChild(aFirstKid, aPresContext,
                      contentsDesiredSize, &contentsReflowState,
                      isVertical ? boffset : ioffset,
                      isVertical ? ioffset : boffset,
                      0);

    // Make sure we have a useful 'ascent' value for the child
    if (contentsDesiredSize.BlockStartAscent() ==
            nsHTMLReflowMetrics::ASK_FOR_BASELINE) {
        WritingMode wm = aButtonReflowState.GetWritingMode();
        contentsDesiredSize.SetBlockStartAscent(aFirstKid->GetLogicalBaseline(wm));
    }

    // OK, we're done with the child frame.
    // Use what we learned to populate the button frame's reflow metrics.
    //  * Button's height & width are content-box size + border-box contribution:
    aButtonDesiredSize.SetSize(wm,
                               LogicalSize(wm, aButtonReflowState.ComputedISize() + clbp.IStartEnd(wm),
                                           buttonContentBoxBSize + clbp.BStartEnd(wm)));

    //  * Button's ascent is its child's ascent, plus the child's block-offset
    // within our frame... unless it's orthogonal, in which case we'll use the
    // contents inline-size as an approximation for now.
    // XXX is there a better strategy? should we include border-padding?
    if (aButtonDesiredSize.GetWritingMode().IsOrthogonalTo(wm)) {
        aButtonDesiredSize.SetBlockStartAscent(contentsDesiredSize.ISize(wm));
    } else {
        aButtonDesiredSize.SetBlockStartAscent(contentsDesiredSize.BlockStartAscent() +
                                               boffset);
    }

    aButtonDesiredSize.SetOverflowAreasToDesiredBounds();
}
Esempio n. 17
0
nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
                                       nsPresContext* aPresContext,
                                       nsBlockFrame* aFrame,
                                       bool aBStartMarginRoot,
                                       bool aBEndMarginRoot,
                                       bool aBlockNeedsFloatManager,
                                       nscoord aConsumedBSize)
  : mBlock(aFrame),
    mPresContext(aPresContext),
    mReflowState(aReflowState),
    mContentArea(aReflowState.GetWritingMode()),
    mPushedFloats(nullptr),
    mOverflowTracker(nullptr),
    mBorderPadding(mReflowState.ComputedLogicalBorderPadding()),
    mPrevBEndMargin(),
    mLineNumber(0),
    mFlags(0),
    mFloatBreakType(NS_STYLE_CLEAR_NONE),
    mConsumedBSize(aConsumedBSize)
{
  WritingMode wm = aReflowState.GetWritingMode();
  SetFlag(BRS_ISFIRSTINFLOW, aFrame->GetPrevInFlow() == nullptr);
  SetFlag(BRS_ISOVERFLOWCONTAINER, IS_TRUE_OVERFLOW_CONTAINER(aFrame));

  nsIFrame::LogicalSides logicalSkipSides =
    aFrame->GetLogicalSkipSides(&aReflowState);
  mBorderPadding.ApplySkipSides(logicalSkipSides);

  // Note that mContainerWidth is the physical width!
  mContainerWidth = aReflowState.ComputedWidth() + mBorderPadding.LeftRight(wm);

  if ((aBStartMarginRoot && !logicalSkipSides.BStart()) ||
      0 != mBorderPadding.BStart(wm)) {
    SetFlag(BRS_ISBSTARTMARGINROOT, true);
    SetFlag(BRS_APPLYBSTARTMARGIN, true);
  }
  if ((aBEndMarginRoot && !logicalSkipSides.BEnd()) ||
      0 != mBorderPadding.BEnd(wm)) {
    SetFlag(BRS_ISBENDMARGINROOT, true);
  }
  if (aBlockNeedsFloatManager) {
    SetFlag(BRS_FLOAT_MGR, true);
  }
  
  mFloatManager = aReflowState.mFloatManager;

  NS_ASSERTION(mFloatManager,
               "FloatManager should be set in nsBlockReflowState" );
  if (mFloatManager) {
    // Save the coordinate system origin for later.
    mFloatManager->GetTranslation(mFloatManagerX, mFloatManagerY);
    mFloatManager->PushState(&mFloatManagerStateBefore); // never popped
  }

  mReflowStatus = NS_FRAME_COMPLETE;

  mNextInFlow = static_cast<nsBlockFrame*>(mBlock->GetNextInFlow());

  NS_WARN_IF_FALSE(NS_UNCONSTRAINEDSIZE != aReflowState.ComputedISize(),
                   "have unconstrained width; this should only result from "
                   "very large sizes, not attempts at intrinsic width "
                   "calculation");
  mContentArea.ISize(wm) = aReflowState.ComputedISize();

  // Compute content area height. Unlike the width, if we have a
  // specified style height we ignore it since extra content is
  // managed by the "overflow" property. When we don't have a
  // specified style height then we may end up limiting our height if
  // the availableHeight is constrained (this situation occurs when we
  // are paginated).
  if (NS_UNCONSTRAINEDSIZE != aReflowState.AvailableBSize()) {
    // We are in a paginated situation. The bottom edge is just inside
    // the bottom border and padding. The content area height doesn't
    // include either border or padding edge.
    mBEndEdge = aReflowState.AvailableBSize() - mBorderPadding.BEnd(wm);
    mContentArea.BSize(wm) = std::max(0, mBEndEdge - mBorderPadding.BStart(wm));
  }
  else {
    // When we are not in a paginated situation then we always use
    // an constrained height.
    SetFlag(BRS_UNCONSTRAINEDBSIZE, true);
    mContentArea.BSize(wm) = mBEndEdge = NS_UNCONSTRAINEDSIZE;
  }
  mContentArea.IStart(wm) = mBorderPadding.IStart(wm);
  mBCoord = mContentArea.BStart(wm) = mBorderPadding.BStart(wm);

  mPrevChild = nullptr;
  mCurrentLine = aFrame->end_lines();

  mMinLineHeight = aReflowState.CalcLineHeight();
}