Ejemplo n.º 1
0
// Return the inline-size that the float (including margins) will take up
// in the writing mode of the containing block. If this returns
// NS_UNCONSTRAINEDSIZE, we're dealing with an orthogonal block that
// has block-size:auto, and we'll need to actually reflow it to find out
// how much inline-size it will occupy in the containing block's mode.
static nscoord
FloatMarginISize(const nsHTMLReflowState& aCBReflowState,
                 nscoord aFloatAvailableISize,
                 nsIFrame *aFloat,
                 const nsCSSOffsetState& aFloatOffsetState)
{
  AutoMaybeDisableFontInflation an(aFloat);
  WritingMode wm = aFloatOffsetState.GetWritingMode();

  LogicalSize floatSize =
    aFloat->ComputeSize(
              aCBReflowState.rendContext,
              wm,
              aCBReflowState.ComputedSize(wm),
              aFloatAvailableISize,
              aFloatOffsetState.ComputedLogicalMargin().Size(wm),
              aFloatOffsetState.ComputedLogicalBorderPadding().Size(wm) -
                aFloatOffsetState.ComputedLogicalPadding().Size(wm),
              aFloatOffsetState.ComputedLogicalPadding().Size(wm),
              nsIFrame::ComputeSizeFlags::eShrinkWrap);

  WritingMode cbwm = aCBReflowState.GetWritingMode();
  nscoord floatISize = floatSize.ConvertTo(cbwm, wm).ISize(cbwm);
  if (floatISize == NS_UNCONSTRAINEDSIZE) {
    return NS_UNCONSTRAINEDSIZE; // reflow is needed to get the true size
  }

  return floatISize +
         aFloatOffsetState.ComputedLogicalMargin().Size(wm).
           ConvertTo(cbwm, wm).ISize(cbwm) +
         aFloatOffsetState.ComputedLogicalBorderPadding().Size(wm).
           ConvertTo(cbwm, wm).ISize(cbwm);
}
Ejemplo n.º 2
0
// Only reflow the selected child ...
void
nsMathMLSelectedFrame::Reflow(nsPresContext*          aPresContext,
                              nsHTMLReflowMetrics&     aDesiredSize,
                              const nsHTMLReflowState& aReflowState,
                              nsReflowStatus&          aStatus)
{
  aStatus = NS_FRAME_COMPLETE;
  aDesiredSize.ClearSize();
  aDesiredSize.SetBlockStartAscent(0);
  mBoundingMetrics = nsBoundingMetrics();
  nsIFrame* childFrame = GetSelectedFrame();
  if (childFrame) {
    WritingMode wm = childFrame->GetWritingMode();
    LogicalSize availSize = aReflowState.ComputedSize(wm);
    availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE;
    nsHTMLReflowState childReflowState(aPresContext, aReflowState,
                                       childFrame, availSize);
    ReflowChild(childFrame, aPresContext, aDesiredSize,
                childReflowState, aStatus);
    SaveReflowAndBoundingMetricsFor(childFrame, aDesiredSize,
                                    aDesiredSize.mBoundingMetrics);
    mBoundingMetrics = aDesiredSize.mBoundingMetrics;
  }
  FinalizeReflow(*aReflowState.rendContext, aDesiredSize);
  NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
}
Ejemplo n.º 3
0
void
nsMeterFrame::ReflowBarFrame(nsIFrame*                aBarFrame,
                             nsPresContext*           aPresContext,
                             const nsHTMLReflowState& aReflowState,
                             nsReflowStatus&          aStatus)
{
  bool vertical = ResolvedOrientationIsVertical();
  WritingMode wm = aBarFrame->GetWritingMode();
  LogicalSize availSize = aReflowState.ComputedSize(wm);
  availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE;
  nsHTMLReflowState reflowState(aPresContext, aReflowState,
                                aBarFrame, availSize);
  nscoord size = vertical ? aReflowState.ComputedHeight()
                          : aReflowState.ComputedWidth();
  nscoord xoffset = aReflowState.ComputedPhysicalBorderPadding().left;
  nscoord yoffset = aReflowState.ComputedPhysicalBorderPadding().top;

  // NOTE: Introduce a new function getPosition in the content part ?
  HTMLMeterElement* meterElement = static_cast<HTMLMeterElement*>(mContent);

  double max = meterElement->Max();
  double min = meterElement->Min();
  double value = meterElement->Value();

  double position = max - min;
  position = position != 0 ? (value - min) / position : 1;

  size = NSToCoordRound(size * position);

  if (!vertical && (wm.IsVertical() ? wm.IsVerticalRL() : !wm.IsBidiLTR())) {
    xoffset += aReflowState.ComputedWidth() - size;
  }

  // The bar position is *always* constrained.
  if (vertical) {
    // We want the bar to begin at the bottom.
    yoffset += aReflowState.ComputedHeight() - size;

    size -= reflowState.ComputedPhysicalMargin().TopBottom() +
            reflowState.ComputedPhysicalBorderPadding().TopBottom();
    size = std::max(size, 0);
    reflowState.SetComputedHeight(size);
  } else {
    size -= reflowState.ComputedPhysicalMargin().LeftRight() +
            reflowState.ComputedPhysicalBorderPadding().LeftRight();
    size = std::max(size, 0);
    reflowState.SetComputedWidth(size);
  }

  xoffset += reflowState.ComputedPhysicalMargin().left;
  yoffset += reflowState.ComputedPhysicalMargin().top;

  nsHTMLReflowMetrics barDesiredSize(reflowState);
  ReflowChild(aBarFrame, aPresContext, barDesiredSize, reflowState, xoffset,
              yoffset, 0, aStatus);
  FinishReflowChild(aBarFrame, aPresContext, barDesiredSize, &reflowState,
                    xoffset, yoffset, 0);
}
Ejemplo n.º 4
0
static nscoord
FloatMarginWidth(const nsHTMLReflowState& aCBReflowState,
                 nscoord aFloatAvailableWidth,
                 nsIFrame *aFloat,
                 const nsCSSOffsetState& aFloatOffsetState)
{
  AutoMaybeDisableFontInflation an(aFloat);
  WritingMode fosWM = aFloatOffsetState.GetWritingMode();
  return aFloat->ComputeSize(
    aCBReflowState.rendContext,
    fosWM,
    aCBReflowState.ComputedSize(fosWM),
    aFloatAvailableWidth,
    aFloatOffsetState.ComputedLogicalMargin().Size(fosWM),
    aFloatOffsetState.ComputedLogicalBorderPadding().Size(fosWM),
    aFloatOffsetState.ComputedLogicalPadding().Size(fosWM),
    true).Width(fosWM) +
  aFloatOffsetState.ComputedPhysicalMargin().LeftRight() +
  aFloatOffsetState.ComputedPhysicalBorderPadding().LeftRight();
}
Ejemplo n.º 5
0
void
nsMathMLTokenFrame::Reflow(nsPresContext*          aPresContext,
                           nsHTMLReflowMetrics&     aDesiredSize,
                           const nsHTMLReflowState& aReflowState,
                           nsReflowStatus&          aStatus)
{
  MarkInReflow();
  mPresentationData.flags &= ~NS_MATHML_ERROR;

  // initializations needed for empty markup like <mtag></mtag>
  aDesiredSize.ClearSize();
  aDesiredSize.SetBlockStartAscent(0);
  aDesiredSize.mBoundingMetrics = nsBoundingMetrics();

  nsIFrame* childFrame = GetFirstPrincipalChild();
  while (childFrame) {
    // ask our children to compute their bounding metrics
    nsHTMLReflowMetrics childDesiredSize(aReflowState.GetWritingMode(),
                                         aDesiredSize.mFlags
                                         | NS_REFLOW_CALC_BOUNDING_METRICS);
    WritingMode wm = childFrame->GetWritingMode();
    LogicalSize availSize = aReflowState.ComputedSize(wm);
    availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE;
    nsHTMLReflowState childReflowState(aPresContext, aReflowState,
                                       childFrame, availSize);
    ReflowChild(childFrame, aPresContext, childDesiredSize,
                childReflowState, aStatus);
    //NS_ASSERTION(NS_FRAME_IS_COMPLETE(aStatus), "bad status");
    SaveReflowAndBoundingMetricsFor(childFrame, childDesiredSize,
                                    childDesiredSize.mBoundingMetrics);

    childFrame = childFrame->GetNextSibling();
  }

  // place and size children
  FinalizeReflow(aReflowState.rendContext->GetDrawTarget(), aDesiredSize);

  aStatus = NS_FRAME_COMPLETE;
  NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
}
void
nsHTMLButtonControlFrame::ReflowButtonContents(nsPresContext* aPresContext,
                                               nsHTMLReflowMetrics& aButtonDesiredSize,
                                               const nsHTMLReflowState& aButtonReflowState,
                                               nsIFrame* aFirstKid)
{
  // Buttons have some bonus renderer-determined border/padding,
  // which occupies part of the button's content-box area:
  const nsMargin focusPadding = mRenderer.GetAddedButtonBorderAndPadding();

  WritingMode wm = aFirstKid->GetWritingMode();
  LogicalSize availSize = aButtonReflowState.ComputedSize(GetWritingMode());
  availSize.BSize(wm) = NS_INTRINSICSIZE;

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

  // See whether out availSize's width is big enough.  If it's smaller than our
  // intrinsic min width, that means that the kid wouldn't really fit; for a
  // better look in such cases we adjust the available width and our left
  // offset to allow the kid to spill left into our padding.
  nscoord xoffset = focusPadding.left +
    aButtonReflowState.ComputedPhysicalBorderPadding().left;
  nscoord extrawidth = GetMinISize(aButtonReflowState.rendContext) -
    aButtonReflowState.ComputedWidth();
  if (extrawidth > 0) {
    nscoord extraleft = extrawidth / 2;
    nscoord extraright = extrawidth - extraleft;
    NS_ASSERTION(extraright >=0, "How'd that happen?");

    // Do not allow the extras to be bigger than the relevant padding
    extraleft = std::min(extraleft, aButtonReflowState.ComputedPhysicalPadding().left);
    extraright = std::min(extraright, aButtonReflowState.ComputedPhysicalPadding().right);
    xoffset -= extraleft;
    availSize.Width(wm) = availSize.Width(wm) + extraleft + extraright;
  }
  availSize.Width(wm) = std::max(availSize.Width(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);

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

  nsReflowStatus contentsReflowStatus;
  nsHTMLReflowMetrics contentsDesiredSize(aButtonReflowState);
  ReflowChild(aFirstKid, aPresContext,
              contentsDesiredSize, contentsReflowState,
              xoffset,
              focusPadding.top + aButtonReflowState.ComputedPhysicalBorderPadding().top,
              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 buttonContentBoxHeight = 0;
  if (aButtonReflowState.ComputedHeight() != NS_INTRINSICSIZE) {
    // Button has a fixed height -- that's its content-box height.
    buttonContentBoxHeight = aButtonReflowState.ComputedHeight();
  } else {
    // Button is intrinsically sized -- it should shrinkwrap the
    // button-contents' height, plus any focus-padding space:
    buttonContentBoxHeight =
      contentsDesiredSize.Height() + focusPadding.TopBottom();

    // Make sure we obey min/max-height in the case when we're doing intrinsic
    // sizing (we get it for free when we have a non-intrinsic
    // aButtonReflowState.ComputedHeight()).  Note that we do this before
    // adjusting for borderpadding, since mComputedMaxHeight and
    // mComputedMinHeight are content heights.
    buttonContentBoxHeight =
      NS_CSS_MINMAX(buttonContentBoxHeight,
                    aButtonReflowState.ComputedMinHeight(),
                    aButtonReflowState.ComputedMaxHeight());
  }

  // Center child vertically in the button
  // (technically, inside of the button's focus-padding area)
  nscoord extraSpace =
    buttonContentBoxHeight - focusPadding.TopBottom() -
    contentsDesiredSize.Height();

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

  // Adjust yoffset to be in terms of the button's frame-rect, instead of
  // its focus-padding rect:
  yoffset += focusPadding.top + aButtonReflowState.ComputedPhysicalBorderPadding().top;

  // Place the child
  FinishReflowChild(aFirstKid, aPresContext,
                    contentsDesiredSize, &contentsReflowState,
                    xoffset, yoffset, 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.Width() = aButtonReflowState.ComputedWidth() +
    aButtonReflowState.ComputedPhysicalBorderPadding().LeftRight();

  aButtonDesiredSize.Height() = buttonContentBoxHeight +
    aButtonReflowState.ComputedPhysicalBorderPadding().TopBottom();

  //  * Button's ascent is its child's ascent, plus the child's y-offset
  // within our frame:
  aButtonDesiredSize.SetBlockStartAscent(contentsDesiredSize.BlockStartAscent() +
                                         yoffset);

  aButtonDesiredSize.SetOverflowAreasToDesiredBounds();
}
Ejemplo n.º 7
0
void
nsMathMLmrootFrame::Reflow(nsPresContext*          aPresContext,
                           nsHTMLReflowMetrics&     aDesiredSize,
                           const nsHTMLReflowState& aReflowState,
                           nsReflowStatus&          aStatus)
{
  MarkInReflow();
  nsReflowStatus childStatus;

  mPresentationData.flags &= ~NS_MATHML_ERROR;
  aDesiredSize.ClearSize();
  aDesiredSize.SetBlockStartAscent(0);

  nsBoundingMetrics bmSqr, bmBase, bmIndex;
  DrawTarget* drawTarget = aReflowState.rendContext->GetDrawTarget();

  //////////////////
  // Reflow Children

  int32_t count = 0;
  nsIFrame* baseFrame = nullptr;
  nsIFrame* indexFrame = nullptr;
  nsHTMLReflowMetrics baseSize(aReflowState);
  nsHTMLReflowMetrics indexSize(aReflowState);
  nsIFrame* childFrame = mFrames.FirstChild();
  while (childFrame) {
    // ask our children to compute their bounding metrics 
    nsHTMLReflowMetrics childDesiredSize(aReflowState,
                                         aDesiredSize.mFlags
                                         | NS_REFLOW_CALC_BOUNDING_METRICS);
    WritingMode wm = childFrame->GetWritingMode();
    LogicalSize availSize = aReflowState.ComputedSize(wm);
    availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE;
    nsHTMLReflowState childReflowState(aPresContext, aReflowState,
                                       childFrame, availSize);
    ReflowChild(childFrame, aPresContext,
                     childDesiredSize, childReflowState, childStatus);
    //NS_ASSERTION(NS_FRAME_IS_COMPLETE(childStatus), "bad status");
    if (0 == count) {
      // base 
      baseFrame = childFrame;
      baseSize = childDesiredSize;
      bmBase = childDesiredSize.mBoundingMetrics;
    }
    else if (1 == count) {
      // index
      indexFrame = childFrame;
      indexSize = childDesiredSize;
      bmIndex = childDesiredSize.mBoundingMetrics;
    }
    count++;
    childFrame = childFrame->GetNextSibling();
  }
  if (2 != count) {
    // report an error, encourage people to get their markups in order
    ReportChildCountError();
    ReflowError(drawTarget, aDesiredSize);
    aStatus = NS_FRAME_COMPLETE;
    NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
    // Call DidReflow() for the child frames we successfully did reflow.
    DidReflowChildren(mFrames.FirstChild(), childFrame);
    return;
  }

  ////////////
  // Prepare the radical symbol and the overline bar

  float fontSizeInflation = nsLayoutUtils::FontSizeInflationFor(this);
  RefPtr<nsFontMetrics> fm =
    nsLayoutUtils::GetFontMetricsForFrame(this, fontSizeInflation);

  nscoord ruleThickness, leading, psi;
  GetRadicalParameters(fm, StyleFont()->mMathDisplay ==
                       NS_MATHML_DISPLAYSTYLE_BLOCK,
                       ruleThickness, leading, psi);

  // built-in: adjust clearance psi to emulate \mathstrut using '1' (TexBook, p.131)
  char16_t one = '1';
  nsBoundingMetrics bmOne =
    nsLayoutUtils::AppUnitBoundsOfString(&one, 1, *fm, drawTarget);
  if (bmOne.ascent > bmBase.ascent)
    psi += bmOne.ascent - bmBase.ascent;

  // make sure that the rule appears on on screen
  nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1);
  if (ruleThickness < onePixel) {
    ruleThickness = onePixel;
  }

  // adjust clearance psi to get an exact number of pixels -- this
  // gives a nicer & uniform look on stacked radicals (bug 130282)
  nscoord delta = psi % onePixel;
  if (delta)
    psi += onePixel - delta; // round up

  // Stretch the radical symbol to the appropriate height if it is not big enough.
  nsBoundingMetrics contSize = bmBase;
  contSize.descent = bmBase.ascent + bmBase.descent + psi;
  contSize.ascent = ruleThickness;

  // height(radical) should be >= height(base) + psi + ruleThickness
  nsBoundingMetrics radicalSize;
  mSqrChar.Stretch(aPresContext, drawTarget,
                   fontSizeInflation,
                   NS_STRETCH_DIRECTION_VERTICAL, 
                   contSize, radicalSize,
                   NS_STRETCH_LARGER,
                   StyleVisibility()->mDirection);
  // radicalSize have changed at this point, and should match with
  // the bounding metrics of the char
  mSqrChar.GetBoundingMetrics(bmSqr);

  // Update the desired size for the container (like msqrt, index is not yet included)
  // the baseline will be that of the base.
  mBoundingMetrics.ascent = bmBase.ascent + psi + ruleThickness;
  mBoundingMetrics.descent = 
    std::max(bmBase.descent,
           (bmSqr.ascent + bmSqr.descent - mBoundingMetrics.ascent));
  mBoundingMetrics.width = bmSqr.width + bmBase.width;
  mBoundingMetrics.leftBearing = bmSqr.leftBearing;
  mBoundingMetrics.rightBearing = bmSqr.width + 
    std::max(bmBase.width, bmBase.rightBearing); // take also care of the rule

  aDesiredSize.SetBlockStartAscent(mBoundingMetrics.ascent + leading);
  aDesiredSize.Height() = aDesiredSize.BlockStartAscent() +
    std::max(baseSize.Height() - baseSize.BlockStartAscent(),
             mBoundingMetrics.descent + ruleThickness);
  aDesiredSize.Width() = mBoundingMetrics.width;

  /////////////
  // Re-adjust the desired size to include the index.
  
  // the index is raised by some fraction of the height
  // of the radical, see \mroot macro in App. B, TexBook
  float raiseIndexPercent = 0.6f;
  gfxFont* mathFont = fm->GetThebesFontGroup()->GetFirstMathFont();
  if (mathFont) {
    raiseIndexPercent =
      mathFont->GetMathConstant(gfxFontEntry::RadicalDegreeBottomRaisePercent);
  }
  nscoord raiseIndexDelta = NSToCoordRound(raiseIndexPercent *
                                           (bmSqr.ascent + bmSqr.descent));
  nscoord indexRaisedAscent = mBoundingMetrics.ascent // top of radical 
    - (bmSqr.ascent + bmSqr.descent) // to bottom of radical
    + raiseIndexDelta + bmIndex.ascent + bmIndex.descent; // to top of raised index

  nscoord indexClearance = 0;
  if (mBoundingMetrics.ascent < indexRaisedAscent) {
    indexClearance = 
      indexRaisedAscent - mBoundingMetrics.ascent; // excess gap introduced by a tall index 
    mBoundingMetrics.ascent = indexRaisedAscent;
    nscoord descent = aDesiredSize.Height() - aDesiredSize.BlockStartAscent();
    aDesiredSize.SetBlockStartAscent(mBoundingMetrics.ascent + leading);
    aDesiredSize.Height() = aDesiredSize.BlockStartAscent() + descent;
  }

  nscoord dxIndex, dxSqr;
  GetRadicalXOffsets(bmIndex.width, bmSqr.width, fm, &dxIndex, &dxSqr);

  mBoundingMetrics.width = dxSqr + bmSqr.width + bmBase.width;
  mBoundingMetrics.leftBearing = 
    std::min(dxIndex + bmIndex.leftBearing, dxSqr + bmSqr.leftBearing);
  mBoundingMetrics.rightBearing = dxSqr + bmSqr.width +
    std::max(bmBase.width, bmBase.rightBearing);

  aDesiredSize.Width() = mBoundingMetrics.width;
  aDesiredSize.mBoundingMetrics = mBoundingMetrics;
  GatherAndStoreOverflow(&aDesiredSize);

  // place the index
  nscoord dx = dxIndex;
  nscoord dy = aDesiredSize.BlockStartAscent() -
    (indexRaisedAscent + indexSize.BlockStartAscent() - bmIndex.ascent);
  FinishReflowChild(indexFrame, aPresContext, indexSize, nullptr,
                    MirrorIfRTL(aDesiredSize.Width(), indexSize.Width(), dx),
                    dy, 0);

  // place the radical symbol and the radical bar
  dx = dxSqr;
  dy = indexClearance + leading; // leave a leading at the top
  mSqrChar.SetRect(nsRect(MirrorIfRTL(aDesiredSize.Width(), bmSqr.width, dx),
                          dy, bmSqr.width, bmSqr.ascent + bmSqr.descent));
  dx += bmSqr.width;
  mBarRect.SetRect(MirrorIfRTL(aDesiredSize.Width(), bmBase.width, dx),
                   dy, bmBase.width, ruleThickness);

  // place the base
  dy = aDesiredSize.BlockStartAscent() - baseSize.BlockStartAscent();
  FinishReflowChild(baseFrame, aPresContext, baseSize, nullptr,
                    MirrorIfRTL(aDesiredSize.Width(), baseSize.Width(), dx),
                    dy, 0);

  mReference.x = 0;
  mReference.y = aDesiredSize.BlockStartAscent();

  aStatus = NS_FRAME_COMPLETE;
  NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
}
Ejemplo n.º 8
0
void
nsRangeFrame::ReflowAnonymousContent(nsPresContext*           aPresContext,
                                     nsHTMLReflowMetrics&     aDesiredSize,
                                     const nsHTMLReflowState& aReflowState)
{
  // The width/height of our content box, which is the available width/height
  // for our anonymous content:
  nscoord rangeFrameContentBoxWidth = aReflowState.ComputedWidth();
  nscoord rangeFrameContentBoxHeight = aReflowState.ComputedHeight();
  if (rangeFrameContentBoxHeight == NS_AUTOHEIGHT) {
    rangeFrameContentBoxHeight = 0;
  }

  nsIFrame* trackFrame = mTrackDiv->GetPrimaryFrame();

  if (trackFrame) { // display:none?

    // Position the track:
    // The idea here is that we allow content authors to style the width,
    // height, border and padding of the track, but we ignore margin and
    // positioning properties and do the positioning ourself to keep the center
    // of the track's border box on the center of the nsRangeFrame's content
    // box.

    WritingMode wm = trackFrame->GetWritingMode();
    LogicalSize availSize = aReflowState.ComputedSize(wm);
    availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE;
    nsHTMLReflowState trackReflowState(aPresContext, aReflowState,
                                       trackFrame, availSize);

    // Find the x/y position of the track frame such that it will be positioned
    // as described above. These coordinates are with respect to the
    // nsRangeFrame's border-box.
    nscoord trackX = rangeFrameContentBoxWidth / 2;
    nscoord trackY = rangeFrameContentBoxHeight / 2;

    // Account for the track's border and padding (we ignore its margin):
    trackX -= trackReflowState.ComputedPhysicalBorderPadding().left +
                trackReflowState.ComputedWidth() / 2;
    trackY -= trackReflowState.ComputedPhysicalBorderPadding().top +
                trackReflowState.ComputedHeight() / 2;

    // Make relative to our border box instead of our content box:
    trackX += aReflowState.ComputedPhysicalBorderPadding().left;
    trackY += aReflowState.ComputedPhysicalBorderPadding().top;

    nsReflowStatus frameStatus;
    nsHTMLReflowMetrics trackDesiredSize(aReflowState);
    ReflowChild(trackFrame, aPresContext, trackDesiredSize,
                trackReflowState, trackX, trackY, 0, frameStatus);
    MOZ_ASSERT(NS_FRAME_IS_FULLY_COMPLETE(frameStatus),
               "We gave our child unconstrained height, so it should be complete");
    FinishReflowChild(trackFrame, aPresContext, trackDesiredSize,
                      &trackReflowState, trackX, trackY, 0);
  }

  nsIFrame* thumbFrame = mThumbDiv->GetPrimaryFrame();

  if (thumbFrame) { // display:none?
    WritingMode wm = thumbFrame->GetWritingMode();
    LogicalSize availSize = aReflowState.ComputedSize(wm);
    availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE;
    nsHTMLReflowState thumbReflowState(aPresContext, aReflowState,
                                       thumbFrame, availSize);

    // Where we position the thumb depends on its size, so we first reflow
    // the thumb at {0,0} to obtain its size, then position it afterwards.

    nsReflowStatus frameStatus;
    nsHTMLReflowMetrics thumbDesiredSize(aReflowState);
    ReflowChild(thumbFrame, aPresContext, thumbDesiredSize,
                thumbReflowState, 0, 0, 0, frameStatus);
    MOZ_ASSERT(NS_FRAME_IS_FULLY_COMPLETE(frameStatus),
               "We gave our child unconstrained height, so it should be complete");
    FinishReflowChild(thumbFrame, aPresContext, thumbDesiredSize,
                      &thumbReflowState, 0, 0, 0);
    DoUpdateThumbPosition(thumbFrame, nsSize(aDesiredSize.Width(),
                                             aDesiredSize.Height()));
  }

  nsIFrame* rangeProgressFrame = mProgressDiv->GetPrimaryFrame();

  if (rangeProgressFrame) { // display:none?
    WritingMode wm = rangeProgressFrame->GetWritingMode();
    LogicalSize availSize = aReflowState.ComputedSize(wm);
    availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE;
    nsHTMLReflowState progressReflowState(aPresContext, aReflowState,
                                          rangeProgressFrame, availSize);

    // We first reflow the range-progress frame at {0,0} to obtain its
    // unadjusted dimensions, then we adjust it to so that the appropriate edge
    // ends at the thumb.

    nsReflowStatus frameStatus;
    nsHTMLReflowMetrics progressDesiredSize(aReflowState);
    ReflowChild(rangeProgressFrame, aPresContext,
                progressDesiredSize, progressReflowState, 0, 0,
                0, frameStatus);
    MOZ_ASSERT(NS_FRAME_IS_FULLY_COMPLETE(frameStatus),
               "We gave our child unconstrained height, so it should be complete");
    FinishReflowChild(rangeProgressFrame, aPresContext,
                      progressDesiredSize, &progressReflowState, 0, 0, 0);
    DoUpdateRangeProgressFrame(rangeProgressFrame, nsSize(aDesiredSize.Width(),
                                                          aDesiredSize.Height()));
  }
}
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();
}
Ejemplo n.º 10
0
void
nsProgressFrame::ReflowBarFrame(nsIFrame*                aBarFrame,
                                nsPresContext*           aPresContext,
                                const nsHTMLReflowState& aReflowState,
                                nsReflowStatus&          aStatus)
{
  bool vertical = ResolvedOrientationIsVertical();
  WritingMode wm = aBarFrame->GetWritingMode();
  LogicalSize availSize = aReflowState.ComputedSize(wm);
  availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE;
  nsHTMLReflowState reflowState(aPresContext, aReflowState,
                                aBarFrame, availSize);
  nscoord size = vertical ? aReflowState.ComputedHeight()
                          : aReflowState.ComputedWidth();
  nscoord xoffset = aReflowState.ComputedPhysicalBorderPadding().left;
  nscoord yoffset = aReflowState.ComputedPhysicalBorderPadding().top;

  double position = static_cast<HTMLProgressElement*>(mContent)->Position();

  // Force the bar's size to match the current progress.
  // When indeterminate, the progress' size will be 100%.
  if (position >= 0.0) {
    size *= position;
  }

  if (!vertical && (wm.IsVertical() ? wm.IsVerticalRL() : !wm.IsBidiLTR())) {
    xoffset += aReflowState.ComputedWidth() - size;
  }

  // The bar size is fixed in these cases:
  // - the progress position is determined: the bar size is fixed according
  //   to it's value.
  // - the progress position is indeterminate and the bar appearance should be
  //   shown as native: the bar size is forced to 100%.
  // Otherwise (when the progress is indeterminate and the bar appearance isn't
  // native), the bar size isn't fixed and can be set by the author.
  if (position != -1 || ShouldUseNativeStyle()) {
    if (vertical) {
      // We want the bar to begin at the bottom.
      yoffset += aReflowState.ComputedHeight() - size;

      size -= reflowState.ComputedPhysicalMargin().TopBottom() +
              reflowState.ComputedPhysicalBorderPadding().TopBottom();
      size = std::max(size, 0);
      reflowState.SetComputedHeight(size);
    } else {
      size -= reflowState.ComputedPhysicalMargin().LeftRight() +
              reflowState.ComputedPhysicalBorderPadding().LeftRight();
      size = std::max(size, 0);
      reflowState.SetComputedWidth(size);
    }
  } else if (vertical) {
    // For vertical progress bars, we need to position the bar specificly when
    // the width isn't constrained (position == -1 and !ShouldUseNativeStyle())
    // because aReflowState.ComputedHeight() - size == 0.
    yoffset += aReflowState.ComputedHeight() - reflowState.ComputedHeight();
  }

  xoffset += reflowState.ComputedPhysicalMargin().left;
  yoffset += reflowState.ComputedPhysicalMargin().top;

  nsHTMLReflowMetrics barDesiredSize(aReflowState);
  ReflowChild(aBarFrame, aPresContext, barDesiredSize, reflowState, xoffset,
              yoffset, 0, aStatus);
  FinishReflowChild(aBarFrame, aPresContext, barDesiredSize, &reflowState,
                    xoffset, yoffset, 0);
}
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();
}
Ejemplo n.º 12
0
void
nsNumberControlFrame::Reflow(nsPresContext* aPresContext,
                             nsHTMLReflowMetrics& aDesiredSize,
                             const nsHTMLReflowState& aReflowState,
                             nsReflowStatus& aStatus)
{
  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);
  }

  // The width of our content box, which is the available width
  // for our anonymous content:
  const nscoord contentBoxWidth = aReflowState.ComputedWidth();
  nscoord contentBoxHeight = aReflowState.ComputedHeight();

  nsIFrame* outerWrapperFrame = mOuterWrapper->GetPrimaryFrame();

  if (!outerWrapperFrame) { // display:none?
    if (contentBoxHeight == NS_INTRINSICSIZE) {
      contentBoxHeight = 0;
    }
  } else {
    NS_ASSERTION(outerWrapperFrame == mFrames.FirstChild(), "huh?");

    nsHTMLReflowMetrics wrappersDesiredSize(aReflowState);

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

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

    // offsets of wrapper frame
    nscoord xoffset = aReflowState.ComputedPhysicalBorderPadding().left +
                        wrapperReflowState.ComputedPhysicalMargin().left;
    nscoord yoffset = aReflowState.ComputedPhysicalBorderPadding().top +
                        wrapperReflowState.ComputedPhysicalMargin().top;

    nsReflowStatus childStatus;
    ReflowChild(outerWrapperFrame, aPresContext, wrappersDesiredSize,
                wrapperReflowState, xoffset, yoffset, 0, childStatus);
    MOZ_ASSERT(NS_FRAME_IS_FULLY_COMPLETE(childStatus),
               "We gave our child unconstrained height, so it should be complete");

    nscoord wrappersMarginBoxHeight = wrappersDesiredSize.Height() +
      wrapperReflowState.ComputedPhysicalMargin().TopBottom();

    if (contentBoxHeight == NS_INTRINSICSIZE) {
      // We are intrinsically sized -- we should shrinkwrap the outer wrapper's
      // height:
      contentBoxHeight = wrappersMarginBoxHeight;

      // Make sure we obey min/max-height in the case when we're doing intrinsic
      // sizing (we get it for free when we have a non-intrinsic
      // aReflowState.ComputedHeight()).  Note that we do this before
      // adjusting for borderpadding, since mComputedMaxHeight and
      // mComputedMinHeight are content heights.
      contentBoxHeight =
        NS_CSS_MINMAX(contentBoxHeight,
                      aReflowState.ComputedMinHeight(),
                      aReflowState.ComputedMaxHeight());
    }

    // Center child vertically
    nscoord extraSpace = contentBoxHeight - wrappersMarginBoxHeight;
    yoffset += std::max(0, extraSpace / 2);

    // Place the child
    FinishReflowChild(outerWrapperFrame, aPresContext, wrappersDesiredSize,
                      &wrapperReflowState, xoffset, yoffset, 0);

    aDesiredSize.SetBlockStartAscent(
       wrappersDesiredSize.BlockStartAscent() +
       outerWrapperFrame->BStart(aReflowState.GetWritingMode(),
                                 contentBoxWidth));
  }

  aDesiredSize.Width() = contentBoxWidth +
                         aReflowState.ComputedPhysicalBorderPadding().LeftRight();
  aDesiredSize.Height() = contentBoxHeight +
                          aReflowState.ComputedPhysicalBorderPadding().TopBottom();

  aDesiredSize.SetOverflowAreasToDesiredBounds();

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

  FinishAndStoreOverflow(&aDesiredSize);

  aStatus = NS_FRAME_COMPLETE;

  NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
}
Ejemplo n.º 13
0
bool
nsBlockReflowContext::ComputeCollapsedBStartMargin(const nsHTMLReflowState& aRS,
                                                   nsCollapsingMargin* aMargin,
                                                   nsIFrame* aClearanceFrame,
                                                   bool* aMayNeedRetry,
                                                   bool* aBlockIsEmpty)
{
  WritingMode wm = aRS.GetWritingMode();
  WritingMode parentWM = mMetrics.GetWritingMode();

  // Include block-start element of frame's margin
  aMargin->Include(aRS.ComputedLogicalMargin().ConvertTo(parentWM, wm).BStart(parentWM));

  // The inclusion of the block-end margin when empty is done by the caller
  // since it doesn't need to be done by the top-level (non-recursive)
  // caller.

#ifdef NOISY_BLOCKDIR_MARGINS
  nsFrame::ListTag(stdout, aRS.frame);
  printf(": %d => %d\n", aRS.ComputedLogicalMargin().BStart(wm), aMargin->get());
#endif

  bool dirtiedLine = false;
  bool setBlockIsEmpty = false;

  // Calculate the frame's generational block-start-margin from its child
  // blocks. Note that if the frame has a non-zero block-start-border or
  // block-start-padding then this step is skipped because it will be a margin
  // root.  It is also skipped if the frame is a margin root for other
  // reasons.
  nsIFrame* frame = DescendIntoBlockLevelFrame(aRS.frame);
  nsPresContext* prescontext = frame->PresContext();
  nsBlockFrame* block = nullptr;
  if (0 == aRS.ComputedLogicalBorderPadding().BStart(wm)) {
    block = nsLayoutUtils::GetAsBlock(frame);
    if (block) {
      bool bStartMarginRoot, unused;
      block->IsMarginRoot(&bStartMarginRoot, &unused);
      if (bStartMarginRoot) {
        block = nullptr;
      }
    }
  }

  // iterate not just through the lines of 'block' but also its
  // overflow lines and the normal and overflow lines of its next in
  // flows. Note that this will traverse some frames more than once:
  // for example, if A contains B and A->nextinflow contains
  // B->nextinflow, we'll traverse B->nextinflow twice. But this is
  // OK because our traversal is idempotent.
  for ( ;block; block = static_cast<nsBlockFrame*>(block->GetNextInFlow())) {
    for (int overflowLines = 0; overflowLines <= 1; ++overflowLines) {
      nsBlockFrame::line_iterator line;
      nsBlockFrame::line_iterator line_end;
      bool anyLines = true;
      if (overflowLines) {
        nsBlockFrame::FrameLines* frames = block->GetOverflowLines();
        nsLineList* lines = frames ? &frames->mLines : nullptr;
        if (!lines) {
          anyLines = false;
        } else {
          line = lines->begin();
          line_end = lines->end();
        }
      } else {
        line = block->begin_lines();
        line_end = block->end_lines();
      }
      for (; anyLines && line != line_end; ++line) {
        if (!aClearanceFrame && line->HasClearance()) {
          // If we don't have a clearance frame, then we're computing
          // the collapsed margin in the first pass, assuming that all
          // lines have no clearance. So clear their clearance flags.
          line->ClearHasClearance();
          line->MarkDirty();
          dirtiedLine = true;
        }

        bool isEmpty;
        if (line->IsInline()) {
          isEmpty = line->IsEmpty();
        } else {
          nsIFrame* kid = line->mFirstChild;
          if (kid == aClearanceFrame) {
            line->SetHasClearance();
            line->MarkDirty();
            dirtiedLine = true;
            goto done;
          }
          // Here is where we recur. Now that we have determined that a
          // generational collapse is required we need to compute the
          // child blocks margin and so in so that we can look into
          // it. For its margins to be computed we need to have a reflow
          // state for it.

          // We may have to construct an extra reflow state here if
          // we drilled down through a block wrapper. At the moment
          // we can only drill down one level so we only have to support
          // one extra reflow state.
          const nsHTMLReflowState* outerReflowState = &aRS;
          if (frame != aRS.frame) {
            NS_ASSERTION(frame->GetParent() == aRS.frame,
                         "Can only drill through one level of block wrapper");
            LogicalSize availSpace = aRS.ComputedSize(frame->GetWritingMode());
            outerReflowState = new nsHTMLReflowState(prescontext,
                                                     aRS, frame, availSpace);
          }
          {
            LogicalSize availSpace =
              outerReflowState->ComputedSize(kid->GetWritingMode());
            nsHTMLReflowState innerReflowState(prescontext,
                                               *outerReflowState, kid,
                                               availSpace);
            // Record that we're being optimistic by assuming the kid
            // has no clearance
            if (kid->StyleDisplay()->mBreakType != NS_STYLE_CLEAR_NONE) {
              *aMayNeedRetry = true;
            }
            if (ComputeCollapsedBStartMargin(innerReflowState, aMargin,
                                             aClearanceFrame, aMayNeedRetry,
                                             &isEmpty)) {
              line->MarkDirty();
              dirtiedLine = true;
            }
            if (isEmpty) {
              WritingMode innerWM = innerReflowState.GetWritingMode();
              LogicalMargin innerMargin =
                innerReflowState.ComputedLogicalMargin().ConvertTo(parentWM, innerWM);
              aMargin->Include(innerMargin.BEnd(parentWM));
            }
          }
          if (outerReflowState != &aRS) {
            delete const_cast<nsHTMLReflowState*>(outerReflowState);
          }
        }
        if (!isEmpty) {
          if (!setBlockIsEmpty && aBlockIsEmpty) {
            setBlockIsEmpty = true;
            *aBlockIsEmpty = false;
          }
          goto done;
        }
      }
      if (!setBlockIsEmpty && aBlockIsEmpty) {
        // The first time we reach here is when this is the first block
        // and we have processed all its normal lines.
        setBlockIsEmpty = true;
        // All lines are empty, or we wouldn't be here!
        *aBlockIsEmpty = aRS.frame->IsSelfEmpty();
      }
    }
  }
  done:

  if (!setBlockIsEmpty && aBlockIsEmpty) {
    *aBlockIsEmpty = aRS.frame->IsEmpty();
  }
  
#ifdef NOISY_BLOCKDIR_MARGINS
  nsFrame::ListTag(stdout, aRS.frame);
  printf(": => %d\n", aMargin->get());
#endif

  return dirtiedLine;
}
Ejemplo n.º 14
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);
}
Ejemplo n.º 15
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);
}
void
nsAbsoluteContainingBlock::ReflowAbsoluteFrame(nsIFrame*                aDelegatingFrame,
                                               nsPresContext*           aPresContext,
                                               const nsHTMLReflowState& aReflowState,
                                               const nsRect&            aContainingBlock,
                                               bool                     aConstrainHeight,
                                               nsIFrame*                aKidFrame,
                                               nsReflowStatus&          aStatus,
                                               nsOverflowAreas*         aOverflowAreas)
{
#ifdef DEBUG
  if (nsBlockFrame::gNoisyReflow) {
    nsFrame::IndentBy(stdout,nsBlockFrame::gNoiseIndent);
    printf("abs pos ");
    if (aKidFrame) {
      nsAutoString name;
      aKidFrame->GetFrameName(name);
      printf("%s ", NS_LossyConvertUTF16toASCII(name).get());
    }

    char width[16];
    char height[16];
    PrettyUC(aReflowState.AvailableWidth(), width);
    PrettyUC(aReflowState.AvailableHeight(), height);
    printf(" a=%s,%s ", width, height);
    PrettyUC(aReflowState.ComputedWidth(), width);
    PrettyUC(aReflowState.ComputedHeight(), height);
    printf("c=%s,%s \n", width, height);
  }
  AutoNoisyIndenter indent(nsBlockFrame::gNoisy);
#endif // DEBUG

  WritingMode wm = aKidFrame->GetWritingMode();
  nscoord availISize = LogicalSize(wm, aContainingBlock.Size()).ISize(wm);
  if (availISize == -1) {
    NS_ASSERTION(aReflowState.ComputedSize(wm).ISize(wm) !=
                   NS_UNCONSTRAINEDSIZE,
                 "Must have a useful inline-size _somewhere_");
    availISize =
      aReflowState.ComputedSizeWithPadding(wm).ISize(wm);
  }

  nsHTMLReflowMetrics kidDesiredSize(aReflowState);
  nsHTMLReflowState kidReflowState(aPresContext, aReflowState, aKidFrame,
                                   LogicalSize(wm, availISize,
                                               NS_UNCONSTRAINEDSIZE),
                                   aContainingBlock.width,
                                   aContainingBlock.height);

  // Get the border values
  const nsMargin& border = aReflowState.mStyleBorder->GetComputedBorder();

  bool constrainHeight = (aReflowState.AvailableHeight() != NS_UNCONSTRAINEDSIZE)
    && aConstrainHeight
       // Don't split if told not to (e.g. for fixed frames)
    && (aDelegatingFrame->GetType() != nsGkAtoms::inlineFrame)
       //XXX we don't handle splitting frames for inline absolute containing blocks yet
    && (aKidFrame->GetRect().y <= aReflowState.AvailableHeight());
       // Don't split things below the fold. (Ideally we shouldn't *have*
       // anything totally below the fold, but we can't position frames
       // across next-in-flow breaks yet.
  if (constrainHeight) {
    kidReflowState.AvailableHeight() = aReflowState.AvailableHeight() - border.top
                                     - kidReflowState.ComputedPhysicalMargin().top;
    if (NS_AUTOOFFSET != kidReflowState.ComputedPhysicalOffsets().top)
      kidReflowState.AvailableHeight() -= kidReflowState.ComputedPhysicalOffsets().top;
  }

  // Do the reflow
  aKidFrame->Reflow(aPresContext, kidDesiredSize, kidReflowState, aStatus);

  // If we're solving for 'left' or 'top', then compute it now that we know the
  // width/height
  if ((NS_AUTOOFFSET == kidReflowState.ComputedPhysicalOffsets().left) ||
      (NS_AUTOOFFSET == kidReflowState.ComputedPhysicalOffsets().top)) {
    nscoord aContainingBlockWidth = aContainingBlock.width;
    nscoord aContainingBlockHeight = aContainingBlock.height;

    if (-1 == aContainingBlockWidth) {
      // Get the containing block width/height
      kidReflowState.ComputeContainingBlockRectangle(aPresContext,
                                                     &aReflowState,
                                                     aContainingBlockWidth,
                                                     aContainingBlockHeight);
    }

    if (NS_AUTOOFFSET == kidReflowState.ComputedPhysicalOffsets().left) {
      NS_ASSERTION(NS_AUTOOFFSET != kidReflowState.ComputedPhysicalOffsets().right,
                   "Can't solve for both left and right");
      kidReflowState.ComputedPhysicalOffsets().left = aContainingBlockWidth -
                                             kidReflowState.ComputedPhysicalOffsets().right -
                                             kidReflowState.ComputedPhysicalMargin().right -
                                             kidDesiredSize.Width() -
                                             kidReflowState.ComputedPhysicalMargin().left;
    }
    if (NS_AUTOOFFSET == kidReflowState.ComputedPhysicalOffsets().top) {
      kidReflowState.ComputedPhysicalOffsets().top = aContainingBlockHeight -
                                            kidReflowState.ComputedPhysicalOffsets().bottom -
                                            kidReflowState.ComputedPhysicalMargin().bottom -
                                            kidDesiredSize.Height() -
                                            kidReflowState.ComputedPhysicalMargin().top;
    }
  }

  // Position the child relative to our padding edge
  nsRect  rect(border.left + kidReflowState.ComputedPhysicalOffsets().left + kidReflowState.ComputedPhysicalMargin().left,
               border.top + kidReflowState.ComputedPhysicalOffsets().top + kidReflowState.ComputedPhysicalMargin().top,
               kidDesiredSize.Width(), kidDesiredSize.Height());

  // Offset the frame rect by the given origin of the absolute containing block.
  // If the frame is auto-positioned on both sides of an axis, it will be
  // positioned based on its containing block and we don't need to offset.
  if (aContainingBlock.TopLeft() != nsPoint(0, 0)) {
    if (!(kidReflowState.mStylePosition->mOffset.GetLeftUnit() == eStyleUnit_Auto &&
          kidReflowState.mStylePosition->mOffset.GetRightUnit() == eStyleUnit_Auto)) {
      rect.x += aContainingBlock.x;
    }
    if (!(kidReflowState.mStylePosition->mOffset.GetTopUnit() == eStyleUnit_Auto &&
          kidReflowState.mStylePosition->mOffset.GetBottomUnit() == eStyleUnit_Auto)) {
      rect.y += aContainingBlock.y;
    }
  }

  aKidFrame->SetRect(rect);

  nsView* view = aKidFrame->GetView();
  if (view) {
    // Size and position the view and set its opacity, visibility, content
    // transparency, and clip
    nsContainerFrame::SyncFrameViewAfterReflow(aPresContext, aKidFrame, view,
                                               kidDesiredSize.VisualOverflow());
  } else {
    nsContainerFrame::PositionChildViews(aKidFrame);
  }

  aKidFrame->DidReflow(aPresContext, &kidReflowState, nsDidReflowStatus::FINISHED);

#ifdef DEBUG
  if (nsBlockFrame::gNoisyReflow) {
    nsFrame::IndentBy(stdout,nsBlockFrame::gNoiseIndent - 1);
    printf("abs pos ");
    if (aKidFrame) {
      nsAutoString name;
      aKidFrame->GetFrameName(name);
      printf("%s ", NS_LossyConvertUTF16toASCII(name).get());
    }
    printf("%p rect=%d,%d,%d,%d\n", static_cast<void*>(aKidFrame),
           rect.x, rect.y, rect.width, rect.height);
  }
#endif

  if (aOverflowAreas) {
    aOverflowAreas->UnionWith(kidDesiredSize.mOverflowAreas + rect.TopLeft());
  }
}
void
nsMathMLmfencedFrame::Reflow(nsPresContext*          aPresContext,
                             nsHTMLReflowMetrics&     aDesiredSize,
                             const nsHTMLReflowState& aReflowState,
                             nsReflowStatus&          aStatus)
{
  MarkInReflow();
  mPresentationData.flags &= ~NS_MATHML_ERROR;
  aDesiredSize.ClearSize();
  aDesiredSize.SetBlockStartAscent(0);
  aDesiredSize.mBoundingMetrics = nsBoundingMetrics();

  int32_t i;
  const nsStyleFont* font = StyleFont();
  float fontSizeInflation = nsLayoutUtils::FontSizeInflationFor(this);
  RefPtr<nsFontMetrics> fm;
  nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm),
                                        fontSizeInflation);
  nscoord axisHeight, em;
  GetAxisHeight(*aReflowState.rendContext, fm, axisHeight);
  GetEmHeight(fm, em);
  // leading to be left at the top and the bottom of stretched chars
  nscoord leading = NSToCoordRound(0.2f * em); 

  /////////////
  // Reflow children
  // Asking each child to cache its bounding metrics

  // Note that we don't use the base method nsMathMLContainerFrame::Reflow()
  // because we want to stretch our fences, separators and stretchy frames using
  // the *same* initial aDesiredSize.mBoundingMetrics. If we were to use the base
  // method here, our stretchy frames will be stretched and placed, and we may
  // end up stretching our fences/separators with a different aDesiredSize.
  // XXX The above decision was revisited in bug 121748 and this code can be
  // refactored to use nsMathMLContainerFrame::Reflow() at some stage.

  nsReflowStatus childStatus;
  nsIFrame* firstChild = GetFirstPrincipalChild();
  nsIFrame* childFrame = firstChild;
  nscoord ascent = 0, descent = 0;
  if (firstChild || mOpenChar || mCloseChar || mSeparatorsCount > 0) {
    // We use the ASCII metrics to get our minimum height. This way,
    // if we have borders or a background, they will fit better with
    // other elements on the line.
    ascent = fm->MaxAscent();
    descent = fm->MaxDescent();
  }
  while (childFrame) {
    nsHTMLReflowMetrics childDesiredSize(aReflowState,
                                         aDesiredSize.mFlags
                                         | NS_REFLOW_CALC_BOUNDING_METRICS);
    WritingMode wm = childFrame->GetWritingMode();
    LogicalSize availSize = aReflowState.ComputedSize(wm);
    availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE;
    nsHTMLReflowState childReflowState(aPresContext, aReflowState,
                                       childFrame, availSize);
    ReflowChild(childFrame, aPresContext, childDesiredSize,
                childReflowState, childStatus);
    //NS_ASSERTION(NS_FRAME_IS_COMPLETE(childStatus), "bad status");
    SaveReflowAndBoundingMetricsFor(childFrame, childDesiredSize,
                                    childDesiredSize.mBoundingMetrics);

    mozilla::WritingMode outerWM = aReflowState.GetWritingMode();
    nscoord childDescent = childDesiredSize.BSize(outerWM) -
                           childDesiredSize.BlockStartAscent();
    if (descent < childDescent)
      descent = childDescent;
    if (ascent < childDesiredSize.BlockStartAscent())
      ascent = childDesiredSize.BlockStartAscent();

    childFrame = childFrame->GetNextSibling();
  }

  /////////////
  // Ask stretchy children to stretch themselves

  nsBoundingMetrics containerSize;
  nsStretchDirection stretchDir = NS_STRETCH_DIRECTION_VERTICAL;

  GetPreferredStretchSize(*aReflowState.rendContext,
                          0, /* i.e., without embellishments */
                          stretchDir, containerSize);
  childFrame = firstChild;
  while (childFrame) {
    nsIMathMLFrame* mathmlChild = do_QueryFrame(childFrame);
    if (mathmlChild) {
      nsHTMLReflowMetrics childDesiredSize(aReflowState);
      // retrieve the metrics that was stored at the previous pass
      GetReflowAndBoundingMetricsFor(childFrame, childDesiredSize,
                                     childDesiredSize.mBoundingMetrics);
      
      mathmlChild->Stretch(*aReflowState.rendContext, 
                           stretchDir, containerSize, childDesiredSize);
      // store the updated metrics
      SaveReflowAndBoundingMetricsFor(childFrame, childDesiredSize,
                                      childDesiredSize.mBoundingMetrics);
      
      nscoord childDescent = childDesiredSize.Height() - childDesiredSize.BlockStartAscent();
      if (descent < childDescent)
        descent = childDescent;
      if (ascent < childDesiredSize.BlockStartAscent())
        ascent = childDesiredSize.BlockStartAscent();
    }
    childFrame = childFrame->GetNextSibling();
  }

  // bug 121748: for surrounding fences & separators, use a size that covers everything
  GetPreferredStretchSize(*aReflowState.rendContext,
                          STRETCH_CONSIDER_EMBELLISHMENTS,
                          stretchDir, containerSize);

  bool isRTL = StyleVisibility()->mDirection;

  // To achieve a minimum size of "1", the container should be enlarged by the
  // unstretched metrics of the fences and separators.
  ApplyUnstretchedMetrics(aPresContext, *aReflowState.rendContext,
                          fontSizeInflation, mOpenChar,
                          containerSize, isRTL);
  for (i = 0; i < mSeparatorsCount; i++) {
    ApplyUnstretchedMetrics(aPresContext, *aReflowState.rendContext,
                            fontSizeInflation, &mSeparatorsChar[i],
                            containerSize, isRTL);
  }
  ApplyUnstretchedMetrics(aPresContext, *aReflowState.rendContext,
                          fontSizeInflation, mCloseChar,
                          containerSize, isRTL);

  //////////////////////////////////////////
  // Prepare the opening fence, separators, and closing fence, and
  // adjust the origin of children.

  // we need to center around the axis
  nscoord delta = std::max(containerSize.ascent - axisHeight, 
                         containerSize.descent + axisHeight);
  containerSize.ascent = delta + axisHeight;
  containerSize.descent = delta - axisHeight;

  /////////////////
  // opening fence ...
  ReflowChar(aPresContext, *aReflowState.rendContext, *fm,
             fontSizeInflation, mOpenChar,
             NS_MATHML_OPERATOR_FORM_PREFIX, font->mScriptLevel, 
             axisHeight, leading, em, containerSize, ascent, descent, isRTL);
  /////////////////
  // separators ...
  for (i = 0; i < mSeparatorsCount; i++) {
    ReflowChar(aPresContext, *aReflowState.rendContext, *fm,
               fontSizeInflation, &mSeparatorsChar[i],
               NS_MATHML_OPERATOR_FORM_INFIX, font->mScriptLevel,
               axisHeight, leading, em, containerSize, ascent, descent, isRTL);
  }
  /////////////////
  // closing fence ...
  ReflowChar(aPresContext, *aReflowState.rendContext, *fm,
             fontSizeInflation, mCloseChar,
             NS_MATHML_OPERATOR_FORM_POSTFIX, font->mScriptLevel,
             axisHeight, leading, em, containerSize, ascent, descent, isRTL);

  //////////////////
  // Adjust the origins of each child.
  // and update our bounding metrics

  i = 0;
  nscoord dx = 0;
  nsBoundingMetrics bm;
  bool firstTime = true;
  nsMathMLChar *leftChar, *rightChar;
  if (isRTL) {
    leftChar = mCloseChar;
    rightChar = mOpenChar;
  } else {
    leftChar = mOpenChar;
    rightChar = mCloseChar;
  }

  if (leftChar) {
    PlaceChar(leftChar, ascent, bm, dx);
    aDesiredSize.mBoundingMetrics = bm;
    firstTime = false;
  }

  if (isRTL) {
    childFrame = this->GetLastChild(nsIFrame::kPrincipalList);
  } else {
    childFrame = firstChild;
  }
  while (childFrame) {
    nsHTMLReflowMetrics childSize(aReflowState);
    GetReflowAndBoundingMetricsFor(childFrame, childSize, bm);
    if (firstTime) {
      firstTime = false;
      aDesiredSize.mBoundingMetrics  = bm;
    }
    else  
      aDesiredSize.mBoundingMetrics += bm;

    FinishReflowChild(childFrame, aPresContext, childSize, nullptr,
                      dx, ascent - childSize.BlockStartAscent(), 0);
    dx += childSize.Width();

    if (i < mSeparatorsCount) {
      PlaceChar(&mSeparatorsChar[isRTL ? mSeparatorsCount - 1 - i : i],
                ascent, bm, dx);
      aDesiredSize.mBoundingMetrics += bm;
    }
    i++;

    if (isRTL) {
      childFrame = childFrame->GetPrevSibling();
    } else {
      childFrame = childFrame->GetNextSibling();
    }
  }

  if (rightChar) {
    PlaceChar(rightChar, ascent, bm, dx);
    if (firstTime)
      aDesiredSize.mBoundingMetrics  = bm;
    else  
      aDesiredSize.mBoundingMetrics += bm;
  }

  aDesiredSize.Width() = aDesiredSize.mBoundingMetrics.width;
  aDesiredSize.Height() = ascent + descent;
  aDesiredSize.SetBlockStartAscent(ascent);

  SetBoundingMetrics(aDesiredSize.mBoundingMetrics);
  SetReference(nsPoint(0, aDesiredSize.BlockStartAscent()));

  // see if we should fix the spacing
  FixInterFrameSpacing(aDesiredSize);

  // Finished with these:
  ClearSavedChildMetrics();

  // Set our overflow area
  GatherAndStoreOverflow(&aDesiredSize);

  aStatus = NS_FRAME_COMPLETE;
  NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
}
void
nsAbsoluteContainingBlock::ReflowAbsoluteFrame(nsIFrame*                aDelegatingFrame,
                                               nsPresContext*           aPresContext,
                                               const nsHTMLReflowState& aReflowState,
                                               const nsRect&            aContainingBlock,
                                               AbsPosReflowFlags        aFlags,
                                               nsIFrame*                aKidFrame,
                                               nsReflowStatus&          aStatus,
                                               nsOverflowAreas*         aOverflowAreas)
{
#ifdef DEBUG
  if (nsBlockFrame::gNoisyReflow) {
    nsFrame::IndentBy(stdout,nsBlockFrame::gNoiseIndent);
    printf("abs pos ");
    if (aKidFrame) {
      nsAutoString name;
      aKidFrame->GetFrameName(name);
      printf("%s ", NS_LossyConvertUTF16toASCII(name).get());
    }

    char width[16];
    char height[16];
    PrettyUC(aReflowState.AvailableWidth(), width, 16);
    PrettyUC(aReflowState.AvailableHeight(), height, 16);
    printf(" a=%s,%s ", width, height);
    PrettyUC(aReflowState.ComputedWidth(), width, 16);
    PrettyUC(aReflowState.ComputedHeight(), height, 16);
    printf("c=%s,%s \n", width, height);
  }
  AutoNoisyIndenter indent(nsBlockFrame::gNoisy);
#endif // DEBUG

  WritingMode wm = aKidFrame->GetWritingMode();
  LogicalSize logicalCBSize(wm, aContainingBlock.Size());
  nscoord availISize = logicalCBSize.ISize(wm);
  if (availISize == -1) {
    NS_ASSERTION(aReflowState.ComputedSize(wm).ISize(wm) !=
                   NS_UNCONSTRAINEDSIZE,
                 "Must have a useful inline-size _somewhere_");
    availISize =
      aReflowState.ComputedSizeWithPadding(wm).ISize(wm);
  }

  uint32_t rsFlags = 0;
  if (aFlags & AbsPosReflowFlags::eIsGridContainerCB) {
    // When a grid container generates the abs.pos. CB for a *child* then
    // the static-position is the CB origin (i.e. of the grid area rect).
    // https://drafts.csswg.org/css-grid/#static-position
    nsIFrame* placeholder =
      aPresContext->PresShell()->GetPlaceholderFrameFor(aKidFrame);
    if (placeholder && placeholder->GetParent() == aDelegatingFrame) {
      rsFlags |= nsHTMLReflowState::STATIC_POS_IS_CB_ORIGIN;
    }
  }
  nsHTMLReflowState kidReflowState(aPresContext, aReflowState, aKidFrame,
                                   LogicalSize(wm, availISize,
                                               NS_UNCONSTRAINEDSIZE),
                                   &logicalCBSize, rsFlags);

  // Get the border values
  WritingMode outerWM = aReflowState.GetWritingMode();
  const LogicalMargin border(outerWM,
                             aReflowState.mStyleBorder->GetComputedBorder());
  const LogicalMargin margin =
    kidReflowState.ComputedLogicalMargin().ConvertTo(outerWM, wm);
  bool constrainBSize = (aReflowState.AvailableBSize() != NS_UNCONSTRAINEDSIZE)
    && (aFlags & AbsPosReflowFlags::eConstrainHeight)
       // Don't split if told not to (e.g. for fixed frames)
    && (aDelegatingFrame->GetType() != nsGkAtoms::inlineFrame)
       //XXX we don't handle splitting frames for inline absolute containing blocks yet
    && (aKidFrame->GetLogicalRect(aContainingBlock.Size()).BStart(wm) <=
        aReflowState.AvailableBSize());
       // Don't split things below the fold. (Ideally we shouldn't *have*
       // anything totally below the fold, but we can't position frames
       // across next-in-flow breaks yet.
  if (constrainBSize) {
    kidReflowState.AvailableBSize() =
      aReflowState.AvailableBSize() - border.ConvertTo(wm, outerWM).BStart(wm) -
      kidReflowState.ComputedLogicalMargin().BStart(wm);
    if (NS_AUTOOFFSET != kidReflowState.ComputedLogicalOffsets().BStart(wm)) {
      kidReflowState.AvailableBSize() -=
        kidReflowState.ComputedLogicalOffsets().BStart(wm);
    }
  }

  // Do the reflow
  nsHTMLReflowMetrics kidDesiredSize(kidReflowState);
  aKidFrame->Reflow(aPresContext, kidDesiredSize, kidReflowState, aStatus);

  const LogicalSize kidSize = kidDesiredSize.Size(wm).ConvertTo(outerWM, wm);

  LogicalMargin offsets =
    kidReflowState.ComputedLogicalOffsets().ConvertTo(outerWM, wm);

  // If we're solving for start in either inline or block direction,
  // then compute it now that we know the dimensions.
  if ((NS_AUTOOFFSET == offsets.IStart(outerWM)) ||
      (NS_AUTOOFFSET == offsets.BStart(outerWM))) {
    if (-1 == logicalCBSize.ISize(wm)) {
      // Get the containing block width/height
      logicalCBSize =
        kidReflowState.ComputeContainingBlockRectangle(aPresContext,
                                                       &aReflowState);
    }

    if (NS_AUTOOFFSET == offsets.IStart(outerWM)) {
      NS_ASSERTION(NS_AUTOOFFSET != offsets.IEnd(outerWM),
                   "Can't solve for both start and end");
      offsets.IStart(outerWM) =
        logicalCBSize.ConvertTo(outerWM, wm).ISize(outerWM) -
        offsets.IEnd(outerWM) - margin.IStartEnd(outerWM) -
        kidSize.ISize(outerWM);
    }
    if (NS_AUTOOFFSET == offsets.BStart(outerWM)) {
      offsets.BStart(outerWM) =
        logicalCBSize.ConvertTo(outerWM, wm).BSize(outerWM) -
        offsets.BEnd(outerWM) - margin.BStartEnd(outerWM) -
        kidSize.BSize(outerWM);
    }
    kidReflowState.SetComputedLogicalOffsets(offsets.ConvertTo(wm, outerWM));
  }

  // Position the child relative to our padding edge
  LogicalRect rect(outerWM,
                   border.IStart(outerWM) + offsets.IStart(outerWM) +
                     margin.IStart(outerWM),
                   border.BStart(outerWM) + offsets.BStart(outerWM) +
                     margin.BStart(outerWM),
                   kidSize.ISize(outerWM), kidSize.BSize(outerWM));
  nsRect r =
    rect.GetPhysicalRect(outerWM, logicalCBSize.GetPhysicalSize(wm) +
                         border.Size(outerWM).GetPhysicalSize(outerWM));

  // Offset the frame rect by the given origin of the absolute containing block.
  // If the frame is auto-positioned on both sides of an axis, it will be
  // positioned based on its containing block and we don't need to offset
  // (unless the caller demands it (the STATIC_POS_IS_CB_ORIGIN case)).
  if (aContainingBlock.TopLeft() != nsPoint(0, 0)) {
    const nsStyleSides& offsets = kidReflowState.mStylePosition->mOffset;
    if (!(offsets.GetLeftUnit() == eStyleUnit_Auto &&
          offsets.GetRightUnit() == eStyleUnit_Auto) ||
        (rsFlags & nsHTMLReflowState::STATIC_POS_IS_CB_ORIGIN)) {
      r.x += aContainingBlock.x;
    }
    if (!(offsets.GetTopUnit() == eStyleUnit_Auto &&
          offsets.GetBottomUnit() == eStyleUnit_Auto) ||
        (rsFlags & nsHTMLReflowState::STATIC_POS_IS_CB_ORIGIN)) {
      r.y += aContainingBlock.y;
    }
  }

  aKidFrame->SetRect(r);

  nsView* view = aKidFrame->GetView();
  if (view) {
    // Size and position the view and set its opacity, visibility, content
    // transparency, and clip
    nsContainerFrame::SyncFrameViewAfterReflow(aPresContext, aKidFrame, view,
                                               kidDesiredSize.VisualOverflow());
  } else {
    nsContainerFrame::PositionChildViews(aKidFrame);
  }

  aKidFrame->DidReflow(aPresContext, &kidReflowState,
                       nsDidReflowStatus::FINISHED);

#ifdef DEBUG
  if (nsBlockFrame::gNoisyReflow) {
    nsFrame::IndentBy(stdout,nsBlockFrame::gNoiseIndent - 1);
    printf("abs pos ");
    if (aKidFrame) {
      nsAutoString name;
      aKidFrame->GetFrameName(name);
      printf("%s ", NS_LossyConvertUTF16toASCII(name).get());
    }
    printf("%p rect=%d,%d,%d,%d\n", static_cast<void*>(aKidFrame),
           r.x, r.y, r.width, r.height);
  }
#endif

  if (aOverflowAreas) {
    aOverflowAreas->UnionWith(kidDesiredSize.mOverflowAreas + r.TopLeft());
  }
}
Ejemplo n.º 19
0
void
nsTableOuterFrame::Reflow(nsPresContext*           aPresContext,
                                    nsHTMLReflowMetrics&     aDesiredSize,
                                    const nsHTMLReflowState& aOuterRS,
                                    nsReflowStatus&          aStatus)
{
  DO_GLOBAL_REFLOW_COUNT("nsTableOuterFrame");
  DISPLAY_REFLOW(aPresContext, this, aOuterRS, aDesiredSize, aStatus);

  uint8_t captionSide = GetCaptionSide();

  // Initialize out parameters
  aDesiredSize.ClearSize();
  aStatus = NS_FRAME_COMPLETE;

  if (!(GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
    // Set up our kids.  They're already present, on an overflow list, 
    // or there are none so we'll create them now
    MoveOverflowToChildList();
  }

  // Use longs to get more-aligned space.
  #define LONGS_IN_HTMLRS \
    ((sizeof(nsHTMLReflowState) + sizeof(long) - 1) / sizeof(long))
  long captionRSSpace[LONGS_IN_HTMLRS];
  nsHTMLReflowState *captionRS =
    static_cast<nsHTMLReflowState*>((void*)captionRSSpace);
  long innerRSSpace[LONGS_IN_HTMLRS];
  nsHTMLReflowState *innerRS =
    static_cast<nsHTMLReflowState*>((void*) innerRSSpace);

  nsRect origInnerRect = InnerTableFrame()->GetRect();
  nsRect origInnerVisualOverflow = InnerTableFrame()->GetVisualOverflowRect();
  bool innerFirstReflow =
    (InnerTableFrame()->GetStateBits() & NS_FRAME_FIRST_REFLOW) != 0;
  nsRect origCaptionRect;
  nsRect origCaptionVisualOverflow;
  bool captionFirstReflow;
  if (mCaptionFrames.NotEmpty()) {
    origCaptionRect = mCaptionFrames.FirstChild()->GetRect();
    origCaptionVisualOverflow =
      mCaptionFrames.FirstChild()->GetVisualOverflowRect();
    captionFirstReflow =
      (mCaptionFrames.FirstChild()->GetStateBits() & NS_FRAME_FIRST_REFLOW) != 0;
  }
  
  // ComputeAutoSize has to match this logic.
  WritingMode wm;
  if (captionSide == NO_SIDE) {
    // We don't have a caption.
    wm = InnerTableFrame()->GetWritingMode();
    OuterBeginReflowChild(aPresContext, InnerTableFrame(), aOuterRS,
                          innerRSSpace, aOuterRS.ComputedSize(wm).ISize(wm));
  } else if (captionSide == NS_STYLE_CAPTION_SIDE_LEFT ||
             captionSide == NS_STYLE_CAPTION_SIDE_RIGHT) {
    // nsTableCaptionFrame::ComputeAutoSize takes care of making side
    // captions small.  Compute the caption's size first, and tell the
    // table to fit in what's left.
    wm = mCaptionFrames.FirstChild()->GetWritingMode();
    OuterBeginReflowChild(aPresContext, mCaptionFrames.FirstChild(), aOuterRS,
                          captionRSSpace, aOuterRS.ComputedSize(wm).ISize(wm));
    nscoord innerAvailISize = aOuterRS.ComputedSize(wm).ISize(wm) -
      captionRS->ComputedSizeWithMarginBorderPadding(wm).ISize(wm);
    OuterBeginReflowChild(aPresContext, InnerTableFrame(), aOuterRS,
                          innerRSSpace, innerAvailISize);

  } else if (captionSide == NS_STYLE_CAPTION_SIDE_TOP ||
             captionSide == NS_STYLE_CAPTION_SIDE_BOTTOM) {
    // Compute the table's size first, and then prevent the caption from
    // being wider unless it has to be.
    //
    // Note that CSS 2.1 (but not 2.0) says:
    //   The width of the anonymous box is the border-edge width of the
    //   table box inside it
    // We don't actually make our anonymous box that width (if we did,
    // it would break 'auto' margins), but this effectively does that.
    wm = InnerTableFrame()->GetWritingMode();
    OuterBeginReflowChild(aPresContext, InnerTableFrame(), aOuterRS,
                          innerRSSpace, aOuterRS.ComputedSize(wm).ISize(wm));
    // It's good that CSS 2.1 says not to include margins, since we
    // can't, since they already been converted so they exactly
    // fill the available width (ignoring the margin on one side if
    // neither are auto).  (We take advantage of that later when we call
    // GetCaptionOrigin, though.)
    nscoord innerBorderWidth =
      innerRS->ComputedSizeWithBorderPadding(wm).ISize(wm);
    OuterBeginReflowChild(aPresContext, mCaptionFrames.FirstChild(), aOuterRS,
                          captionRSSpace, innerBorderWidth);
  } else {
    NS_ASSERTION(captionSide == NS_STYLE_CAPTION_SIDE_TOP_OUTSIDE ||
                 captionSide == NS_STYLE_CAPTION_SIDE_BOTTOM_OUTSIDE,
                 "unexpected caption-side");
    // Size the table and the caption independently.
    wm = mCaptionFrames.FirstChild()->GetWritingMode();
    OuterBeginReflowChild(aPresContext, mCaptionFrames.FirstChild(), aOuterRS,
                          captionRSSpace, aOuterRS.ComputedSize(wm).ISize(wm));
    wm = InnerTableFrame()->GetWritingMode();
    OuterBeginReflowChild(aPresContext, InnerTableFrame(), aOuterRS,
                          innerRSSpace, aOuterRS.ComputedSize(wm).ISize(wm));
  }

  // First reflow the caption.
  nsHTMLReflowMetrics captionMet(captionRS->GetWritingMode());
  nsSize captionSize;
  nsMargin captionMargin;
  if (mCaptionFrames.NotEmpty()) {
    nsReflowStatus capStatus; // don't let the caption cause incomplete
    OuterDoReflowChild(aPresContext, mCaptionFrames.FirstChild(),
                       *captionRS, captionMet, capStatus);
    captionSize.width = captionMet.Width();
    captionSize.height = captionMet.Height();
    captionMargin = captionRS->ComputedPhysicalMargin();
    // Now that we know the height of the caption, reduce the available height
    // for the table frame if we are height constrained and the caption is above
    // or below the inner table.
    if (NS_UNCONSTRAINEDSIZE != aOuterRS.AvailableHeight()) {
      nscoord captionHeight = 0;
      switch (captionSide) {
        case NS_STYLE_CAPTION_SIDE_TOP:
        case NS_STYLE_CAPTION_SIDE_BOTTOM:
        case NS_STYLE_CAPTION_SIDE_TOP_OUTSIDE:
        case NS_STYLE_CAPTION_SIDE_BOTTOM_OUTSIDE: {
          captionHeight = captionSize.height + captionMargin.TopBottom();
          break;
        }
      }
      innerRS->AvailableHeight() =
        std::max(0, innerRS->AvailableHeight() - captionHeight);
    }
  } else {
    captionSize.SizeTo(0,0);
    captionMargin.SizeTo(0,0,0,0);
  }

  // Then, now that we know how much to reduce the width of the inner
  // table to account for side captions, reflow the inner table.
  nsHTMLReflowMetrics innerMet(innerRS->GetWritingMode());
  OuterDoReflowChild(aPresContext, InnerTableFrame(), *innerRS,
                     innerMet, aStatus);
  nsSize innerSize;
  innerSize.width = innerMet.Width();
  innerSize.height = innerMet.Height();
  nsMargin innerMargin = innerRS->ComputedPhysicalMargin();

  nsSize   containSize = GetContainingBlockSize(aOuterRS);

  // Now that we've reflowed both we can place them.
  // XXXldb Most of the input variables here are now uninitialized!

  // XXX Need to recompute inner table's auto margins for the case of side
  // captions.  (Caption's are broken too, but that should be fixed earlier.)

  if (mCaptionFrames.NotEmpty()) {
    nsPoint captionOrigin;
    GetCaptionOrigin(captionSide, containSize, innerSize, 
                     innerMargin, captionSize, captionMargin, captionOrigin);
    FinishReflowChild(mCaptionFrames.FirstChild(), aPresContext, captionMet,
                      captionRS, captionOrigin.x, captionOrigin.y, 0);
    captionRS->~nsHTMLReflowState();
  }
  // XXX If the height is constrained then we need to check whether
  // everything still fits...

  nsPoint innerOrigin;
  GetInnerOrigin(captionSide, containSize, captionSize, 
                 captionMargin, innerSize, innerMargin, innerOrigin);
  FinishReflowChild(InnerTableFrame(), aPresContext, innerMet, innerRS,
                    innerOrigin.x, innerOrigin.y, 0);
  innerRS->~nsHTMLReflowState();

  nsTableFrame::InvalidateTableFrame(InnerTableFrame(), origInnerRect,
                                     origInnerVisualOverflow, innerFirstReflow);
  if (mCaptionFrames.NotEmpty()) {
    nsTableFrame::InvalidateTableFrame(mCaptionFrames.FirstChild(), origCaptionRect,
                                       origCaptionVisualOverflow,
                                       captionFirstReflow);
  }

  UpdateReflowMetrics(captionSide, aDesiredSize, innerMargin, captionMargin);

  if (GetPrevInFlow()) {
    ReflowOverflowContainerChildren(aPresContext, aOuterRS,
                                    aDesiredSize.mOverflowAreas, 0,
                                    aStatus);
  }

  FinishReflowWithAbsoluteFrames(aPresContext, aDesiredSize, aOuterRS, aStatus);

  // Return our desired rect

  NS_FRAME_SET_TRUNCATION(aStatus, aOuterRS, aDesiredSize);
}