示例#1
0
void
nsTableCellFrame::Reflow(nsPresContext*           aPresContext,
                         nsHTMLReflowMetrics&     aDesiredSize,
                         const nsHTMLReflowState& aReflowState,
                         nsReflowStatus&          aStatus)
{
  MarkInReflow();
  DO_GLOBAL_REFLOW_COUNT("nsTableCellFrame");
  DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);

  if (aReflowState.mFlags.mSpecialBSizeReflow) {
    FirstInFlow()->AddStateBits(NS_TABLE_CELL_HAD_SPECIAL_REFLOW);
  }

  // see if a special bsize reflow needs to occur due to having a pct height
  nsTableFrame::CheckRequestSpecialBSizeReflow(aReflowState);

  aStatus = NS_FRAME_COMPLETE;
  WritingMode wm = aReflowState.GetWritingMode();
  LogicalSize availSize(wm, aReflowState.AvailableISize(),
                            aReflowState.AvailableBSize());

  LogicalMargin borderPadding = aReflowState.ComputedLogicalPadding();
  LogicalMargin border = GetBorderWidth(wm);
  borderPadding += border;

  // reduce available space by insets, if we're in a constrained situation
  availSize.ISize(wm) -= borderPadding.IStartEnd(wm);
  if (NS_UNCONSTRAINEDSIZE != availSize.BSize(wm)) {
    availSize.BSize(wm) -= borderPadding.BStartEnd(wm);
  }

  // Try to reflow the child into the available space. It might not
  // fit or might need continuing.
  if (availSize.BSize(wm) < 0) {
    availSize.BSize(wm) = 1;
  }

  nsHTMLReflowMetrics kidSize(wm, aDesiredSize.mFlags);
  kidSize.ClearSize();
  SetPriorAvailISize(aReflowState.AvailableISize());
  nsIFrame* firstKid = mFrames.FirstChild();
  NS_ASSERTION(firstKid, "Frame construction error, a table cell always has an inner cell frame");
  nsTableFrame* tableFrame = GetTableFrame();

  if (aReflowState.mFlags.mSpecialBSizeReflow) {
    const_cast<nsHTMLReflowState&>(aReflowState).
      SetComputedBSize(BSize(wm) - borderPadding.BStartEnd(wm));
    DISPLAY_REFLOW_CHANGE();
  }
  else if (aPresContext->IsPaginated()) {
    nscoord computedUnpaginatedBSize =
      CalcUnpaginatedBSize(aPresContext, (nsTableCellFrame&)*this,
                           *tableFrame, borderPadding.BStartEnd(wm));
    if (computedUnpaginatedBSize > 0) {
      const_cast<nsHTMLReflowState&>(aReflowState).SetComputedBSize(computedUnpaginatedBSize);
      DISPLAY_REFLOW_CHANGE();
    }
  }
  else {
    SetHasPctOverBSize(false);
  }

  WritingMode kidWM = firstKid->GetWritingMode();
  nsHTMLReflowState kidReflowState(aPresContext, aReflowState, firstKid,
                                   availSize.ConvertTo(kidWM, wm));

  // Don't be a percent height observer if we're in the middle of
  // special-bsize reflow, in case we get an accidental NotifyPercentBSize()
  // call (which we shouldn't honor during special-bsize reflow)
  if (!aReflowState.mFlags.mSpecialBSizeReflow) {
    // mPercentBSizeObserver is for children of cells in quirks mode,
    // but only those than are tables in standards mode.  NeedsToObserve
    // will determine how far this is propagated to descendants.
    kidReflowState.mPercentBSizeObserver = this;
  }
  // Don't propagate special bsize reflow state to our kids
  kidReflowState.mFlags.mSpecialBSizeReflow = false;

  if (aReflowState.mFlags.mSpecialBSizeReflow ||
      FirstInFlow()->HasAnyStateBits(NS_TABLE_CELL_HAD_SPECIAL_REFLOW)) {
    // We need to force the kid to have mBResize set if we've had a
    // special reflow in the past, since the non-special reflow needs to
    // resize back to what it was without the special bsize reflow.
    kidReflowState.SetBResize(true);
  }

  nsSize containerSize =
    aReflowState.ComputedSizeAsContainerIfConstrained();

  LogicalPoint kidOrigin(wm, borderPadding.IStart(wm),
                         borderPadding.BStart(wm));
  nsRect origRect = firstKid->GetRect();
  nsRect origVisualOverflow = firstKid->GetVisualOverflowRect();
  bool firstReflow = firstKid->HasAnyStateBits(NS_FRAME_FIRST_REFLOW);

  ReflowChild(firstKid, aPresContext, kidSize, kidReflowState,
              wm, kidOrigin, containerSize, 0, aStatus);
  if (NS_FRAME_OVERFLOW_IS_INCOMPLETE(aStatus)) {
    // Don't pass OVERFLOW_INCOMPLETE through tables until they can actually handle it
    //XXX should paginate overflow as overflow, but not in this patch (bug 379349)
    NS_FRAME_SET_INCOMPLETE(aStatus);
    printf("Set table cell incomplete %p\n", static_cast<void*>(this));
  }

  // XXXbz is this invalidate actually needed, really?
  if (HasAnyStateBits(NS_FRAME_IS_DIRTY)) {
    InvalidateFrameSubtree();
  }

#ifdef DEBUG
  DebugCheckChildSize(firstKid, kidSize);
#endif

  // 0 dimensioned cells need to be treated specially in Standard/NavQuirks mode
  // see testcase "emptyCells.html"
  nsIFrame* prevInFlow = GetPrevInFlow();
  bool isEmpty;
  if (prevInFlow) {
    isEmpty = static_cast<nsTableCellFrame*>(prevInFlow)->GetContentEmpty();
  } else {
    isEmpty = !CellHasVisibleContent(kidSize.Height(), tableFrame, firstKid);
  }
  SetContentEmpty(isEmpty);

  // Place the child
  FinishReflowChild(firstKid, aPresContext, kidSize, &kidReflowState,
                    wm, kidOrigin, containerSize, 0);

  nsTableFrame::InvalidateTableFrame(firstKid, origRect, origVisualOverflow,
                                     firstReflow);

  // first, compute the bsize which can be set w/o being restricted by
  // available bsize
  LogicalSize cellSize(wm);
  cellSize.BSize(wm) = kidSize.BSize(wm);

  if (NS_UNCONSTRAINEDSIZE != cellSize.BSize(wm)) {
    cellSize.BSize(wm) += borderPadding.BStartEnd(wm);
  }

  // next determine the cell's isize
  cellSize.ISize(wm) = kidSize.ISize(wm);      // at this point, we've factored in the cell's style attributes

  // factor in border and padding
  if (NS_UNCONSTRAINEDSIZE != cellSize.ISize(wm)) {
    cellSize.ISize(wm) += borderPadding.IStartEnd(wm);
  }

  // set the cell's desired size and max element size
  aDesiredSize.SetSize(wm, cellSize);

  // the overflow area will be computed when BlockDirAlignChild() gets called

  if (aReflowState.mFlags.mSpecialBSizeReflow) {
    if (aDesiredSize.BSize(wm) > BSize(wm)) {
      // set a bit indicating that the pct bsize contents exceeded
      // the height that they could honor in the pass 2 reflow
      SetHasPctOverBSize(true);
    }
    if (NS_UNCONSTRAINEDSIZE == aReflowState.AvailableBSize()) {
      aDesiredSize.BSize(wm) = BSize(wm);
    }
  }

  // If our parent is in initial reflow, it'll handle invalidating our
  // entire overflow rect.
  if (!GetParent()->HasAnyStateBits(NS_FRAME_FIRST_REFLOW) &&
      nsSize(aDesiredSize.Width(), aDesiredSize.Height()) != mRect.Size()) {
    InvalidateFrame();
  }

  // remember the desired size for this reflow
  SetDesiredSize(aDesiredSize);

  // Any absolutely-positioned children will get reflowed in
  // nsFrame::FixupPositionedTableParts in another pass, so propagate our
  // dirtiness to them before our parent clears our dirty bits.
  PushDirtyBitToAbsoluteFrames();

  NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
}
void
nsGridContainerFrame::ReflowChildren(GridItemCSSOrderIterator&  aIter,
                                     const LogicalRect&         aContentArea,
                                     const nsTArray<TrackSize>& aColSizes,
                                     const nsTArray<TrackSize>& aRowSizes,
                                     nsHTMLReflowMetrics&       aDesiredSize,
                                     const nsHTMLReflowState&   aReflowState,
                                     nsReflowStatus&            aStatus)
{
  WritingMode wm = aReflowState.GetWritingMode();
  const LogicalPoint gridOrigin(aContentArea.Origin(wm));
  const nscoord gridWidth = aContentArea.Width(wm);
  nsPresContext* pc = PresContext();
  for (; !aIter.AtEnd(); aIter.Next()) {
    nsIFrame* child = *aIter;
    GridArea* area = GetGridAreaForChild(child);
    MOZ_ASSERT(area && area->IsDefinite());
    LogicalRect cb = ContainingBlockFor(wm, *area, aColSizes, aRowSizes);
    cb += gridOrigin;
    nsHTMLReflowState childRS(pc, aReflowState, child, cb.Size(wm));
    const LogicalMargin margin = childRS.ComputedLogicalMargin();
    if (childRS.ComputedBSize() == NS_AUTOHEIGHT) {
      // XXX the start of an align-self:stretch impl.  Needs min-/max-bsize
      // clamping though, and check the prop value is actually 'stretch'!
      LogicalMargin bp = childRS.ComputedLogicalBorderPadding();
      bp.ApplySkipSides(child->GetLogicalSkipSides());
      nscoord bSize = cb.BSize(wm) - bp.BStartEnd(wm) - margin.BStartEnd(wm);
      childRS.SetComputedBSize(std::max(bSize, 0));
    }
    LogicalPoint childPos = cb.Origin(wm);
    childPos.I(wm) += margin.IStart(wm);
    childPos.B(wm) += margin.BStart(wm);
    nsHTMLReflowMetrics childSize(childRS);
    nsReflowStatus childStatus;
    ReflowChild(child, pc, childSize, childRS, wm, childPos,
                gridWidth, 0, childStatus);
    FinishReflowChild(child, pc, childSize, &childRS, wm, childPos,
                      gridWidth, 0);
    ConsiderChildOverflow(aDesiredSize.mOverflowAreas, child);
    // XXX deal with 'childStatus' not being COMPLETE
  }

  if (IsAbsoluteContainer()) {
    nsFrameList children(GetChildList(GetAbsoluteListID()));
    if (!children.IsEmpty()) {
      LogicalMargin pad(aReflowState.ComputedLogicalPadding());
      pad.ApplySkipSides(GetLogicalSkipSides(&aReflowState));
      // 'gridOrigin' is the origin of the grid (the start of the first track),
      // with respect to the grid container's padding-box (CB).
      const LogicalPoint gridOrigin(wm, pad.IStart(wm), pad.BStart(wm));
      const LogicalRect gridCB(wm, 0, 0,
                               aContentArea.ISize(wm) + pad.IStartEnd(wm),
                               aContentArea.BSize(wm) + pad.BStartEnd(wm));
      for (nsFrameList::Enumerator e(children); !e.AtEnd(); e.Next()) {
        nsIFrame* child = e.get();
        GridArea* area = GetGridAreaForChild(child);
        MOZ_ASSERT(area);
        LogicalRect itemCB(ContainingBlockForAbsPos(wm, *area,
                                                    aColSizes, aRowSizes,
                                                    gridOrigin, gridCB));
        // nsAbsoluteContainingBlock::Reflow uses physical coordinates.
        nsRect* cb = static_cast<nsRect*>(child->Properties().Get(
                       GridItemContainingBlockRect()));
        if (!cb) {
          cb = new nsRect;
          child->Properties().Set(GridItemContainingBlockRect(), cb);
        }
        *cb = itemCB.GetPhysicalRect(wm, gridWidth);
      }
      // This rect isn't used at all for layout so we use it to optimize
      // away the virtual GetType() call in the callee in most cases.
      // @see nsAbsoluteContainingBlock::Reflow
      nsRect dummyRect(0, 0, VERY_LIKELY_A_GRID_CONTAINER, 0);
      GetAbsoluteContainingBlock()->Reflow(this, pc, aReflowState, aStatus,
                                           dummyRect, true,
                                           true, true, // XXX could be optimized
                                           &aDesiredSize.mOverflowAreas);
    }
  }
}
示例#3
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);
}
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();
}