's should take precedence over non
  // auto-sided block elements. Therefore we don't honor the width,
  // height, border or padding attributes (the parent has to not apply
  // a margin for us also).
  //
  // Note that this is only done for html paragraphs. Its not
  // appropriate to apply it to other containers, especially XML
  // content!
  PRBool isHTMLParagraph = 0 != (mState & NS_BLOCK_IS_HTML_PARAGRAPH);
  if (isHTMLParagraph &&
      (aReflowState.mStyleDisplay->mDisplay == NS_STYLE_DISPLAY_BLOCK) &&
      (((0 == aState.mKidXMost) ||
        (0 == aState.mKidXMost - borderPadding.left)) &&
       (0 == aState.mY - borderPadding.top))) {
    // Zero out most everything
    aMetrics.width = 0;
    aMetrics.height = 0;
    aMetrics.ascent = 0;
    aMetrics.descent = 0;
    aMetrics.mCarriedOutBottomMargin = 0;
    // Note: Don't zero out the max-element-sizes: they will be zero
    // if this is truly empty, otherwise they won't because of a
    // floater.
    if (nsnull != aMetrics.maxElementSize) {
      aMetrics.maxElementSize->width = aState.mMaxElementSize.width;
      aMetrics.maxElementSize->height = aState.mMaxElementSize.height;
    }
  }
  else {
    // Compute final width
    nscoord maxWidth = 0, maxHeight = 0;
    nscoord minWidth = aState.mKidXMost + borderPadding.right;
    if (!HaveAutoWidth(aReflowState)) {
      // Use style defined width
      aMetrics.width = borderPadding.left + aReflowState.mComputedWidth +
        borderPadding.right;
      // XXX quote css1 section here
      if ((0 == aReflowState.mComputedWidth) && (aMetrics.width < minWidth)) {
        aMetrics.width = minWidth;
      }
      // When style defines the width use it for the max-element-size
      // because we can't shrink any smaller.
      maxWidth = aMetrics.width;
    }
    else {
      nscoord computedWidth = minWidth;
      PRBool compact = PR_FALSE;
#if 0
      if (NS_STYLE_DISPLAY_COMPACT == aReflowState.mStyleDisplay->mDisplay) {
        // If we are display: compact AND we have no lines or we have
        // exactly one line and that line is not a block line AND that
        // line doesn't end in a BR of any sort THEN we remain a compact
        // frame.
        if ((nsnull == mLines) ||
            ((nsnull == mLines->mNext) && !mLines->IsBlock() &&
             (NS_STYLE_CLEAR_NONE == mLines->GetBreakType())
             /*XXX && (computedWidth <= aState.mCompactMarginWidth) */
              )) {
          compact = PR_TRUE;
        }
      }
#endif
      // There are two options here. We either shrink wrap around our
      // contents or we fluff out to the maximum block width. Note:
      // We always shrink wrap when given an unconstrained width.
      if ((0 == (NS_BLOCK_SHRINK_WRAP & mState)) &&
          !aState.mUnconstrainedWidth && !aState.mShrinkWrapWidth &&
          !compact) {
        // Set our width to the max width if we aren't already that
        // wide. Note that the max-width has nothing to do with our
        // contents (CSS2 section XXX)
        computedWidth = borderPadding.left + aState.mContentArea.width +
          borderPadding.right;
      }
      // See if we should compute our max element size
      if (aState.mComputeMaxElementSize) {
        // Adjust the computedWidth
        if (aState.mNoWrap) {
          // When no-wrap is true the max-element-size.width is the
          // width of the widest line plus the right border. Note that
          // aState.mKidXMost already has the left border factored in
          maxWidth = aState.mKidXMost + borderPadding.right;
        }
        else {
          // Add in border and padding dimensions to already computed
          // max-element-size values.
          maxWidth = aState.mMaxElementSize.width +
            borderPadding.left + borderPadding.right;
        }
        if (computedWidth < maxWidth) {
          computedWidth = maxWidth;
        }
      }
      // Apply min/max values
      if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedMaxWidth) {
        nscoord computedMaxWidth = aReflowState.mComputedMaxWidth +
          borderPadding.left + borderPadding.right;
        if (computedWidth > computedMaxWidth) {
          computedWidth = computedMaxWidth;
        }
      }
      if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedMinWidth) {
        nscoord computedMinWidth = aReflowState.mComputedMinWidth +
          borderPadding.left + borderPadding.right;
        if (computedWidth < computedMinWidth) {
          computedWidth = computedMinWidth;
        }
      }
      aMetrics.width = computedWidth;
      // If we're shrink wrapping, then now that we know our final width we
      // need to do horizontal alignment of the inline lines and make sure
      // blocks are correctly sized and positioned. Any lines that need
      // final adjustment will have been marked as dirty
      if (aState.mShrinkWrapWidth && aState.mNeedResizeReflow) {
        // If the parent reflow state is also shrink wrap width, then
        // we don't need to do this, because it will reflow us after it
        // calculates the final width
        PRBool  parentIsShrinkWrapWidth = PR_FALSE;
        if (aReflowState.parentReflowState) {
          if (NS_SHRINKWRAPWIDTH == aReflowState.parentReflowState->mComputedWidth) {
            parentIsShrinkWrapWidth = PR_TRUE;
          }
        }
        if (!parentIsShrinkWrapWidth) {
          nsHTMLReflowState reflowState(aReflowState);
  
          reflowState.mComputedWidth = aMetrics.width - borderPadding.left -
                                       borderPadding.right;
          reflowState.reason = eReflowReason_Resize;
          reflowState.mSpaceManager->ClearRegions();
  
          nscoord oldDesiredWidth = aMetrics.width;
          nsBlockReflowState state(reflowState, aState.mPresContext, this, aMetrics,
                                   NS_BLOCK_MARGIN_ROOT & mState);
          ReflowDirtyLines(state);
          aState.mY = state.mY;
          NS_ASSERTION(oldDesiredWidth == aMetrics.width, "bad desired width");
        }
      }
    }
    if (aState.mShrinkWrapWidth) {
      PRBool  parentIsShrinkWrapWidth = PR_FALSE;
      if (aReflowState.parentReflowState) {
        if (NS_SHRINKWRAPWIDTH == aReflowState.parentReflowState->mComputedWidth) {
          parentIsShrinkWrapWidth = PR_TRUE;
        }
      }
    }
    // Compute final height
    if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedHeight) {
      // Use style defined height
      aMetrics.height = borderPadding.top + aReflowState.mComputedHeight +
        borderPadding.bottom;
      // When style defines the height use it for the max-element-size
      // because we can't shrink any smaller.
      maxHeight = aMetrics.height;
      // Don't carry out a bottom margin when our height is fixed
      // unless the bottom of the last line adjoins the bottom of our
      // content area.
      if (!aState.mIsBottomMarginRoot) {
        if (aState.mY + aState.mPrevBottomMargin != aMetrics.height) {
          aState.mPrevBottomMargin = 0;
        }
      }
    }
    else {
      nscoord autoHeight = aState.mY;
      // Shrink wrap our height around our contents.
      if (aState.mIsBottomMarginRoot) {
        // When we are a bottom-margin root make sure that our last
        // childs bottom margin is fully applied.
        // XXX check for a fit
        autoHeight += aState.mPrevBottomMargin;
      }
      autoHeight += borderPadding.bottom;
      // Apply min/max values
      if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedMaxHeight) {
        nscoord computedMaxHeight = aReflowState.mComputedMaxHeight +
          borderPadding.top + borderPadding.bottom;
        if (autoHeight > computedMaxHeight) {
          autoHeight = computedMaxHeight;
        }
      }
      if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedMinHeight) {
        nscoord computedMinHeight = aReflowState.mComputedMinHeight +
          borderPadding.top + borderPadding.bottom;
        if (autoHeight < computedMinHeight) {
          autoHeight = computedMinHeight;
        }
      }
      aMetrics.height = autoHeight;
      if (aState.mComputeMaxElementSize) {
        maxHeight = aState.mMaxElementSize.height +
          borderPadding.top + borderPadding.bottom;
      }
    }
    aMetrics.ascent = aMetrics.height;
    aMetrics.descent = 0;
    if (aState.mComputeMaxElementSize) {
      // Store away the final value
      aMetrics.maxElementSize->width = maxWidth;
      aMetrics.maxElementSize->height = maxHeight;
    }
    // Return bottom margin information
    aMetrics.mCarriedOutBottomMargin =
      aState.mIsBottomMarginRoot ? 0 : aState.mPrevBottomMargin;
#ifdef DEBUG
    if (CRAZY_WIDTH(aMetrics.width) || CRAZY_HEIGHT(aMetrics.height)) {
      ListTag(stdout);
      printf(": WARNING: desired:%d,%d\n", aMetrics.width, aMetrics.height);
    }
    if (aState.mComputeMaxElementSize &&
        ((maxWidth > aMetrics.width) || (maxHeight > aMetrics.height))) {
      ListTag(stdout);
      printf(": WARNING: max-element-size:%d,%d desired:%d,%d maxSize:%d,%d\n",
             maxWidth, maxHeight, aMetrics.width, aMetrics.height,
             aState.mReflowState.availableWidth,
             aState.mReflowState.availableHeight);
    }
#endif
#ifdef NOISY_MAX_ELEMENT_SIZE
    if (aState.mComputeMaxElementSize) {
      IndentBy(stdout, GetDepth());
      if (NS_UNCONSTRAINEDSIZE == aState.mReflowState.availableWidth) {
        printf("PASS1 ");
      }
      ListTag(stdout);
      printf(": max-element-size:%d,%d desired:%d,%d maxSize:%d,%d\n",
             maxWidth, maxHeight, aMetrics.width, aMetrics.height,
             aState.mReflowState.availableWidth,
             aState.mReflowState.availableHeight);
    }
#endif
  }
  // If we're requested to update our maximum width, then compute it
  if (aState.mComputeMaximumWidth) {
    // We need to add in for the right border/padding
    aMetrics.mMaximumWidth = aState.mMaximumWidth + borderPadding.right;
  }
  // Compute the combined area of our children
// XXX_perf: This can be done incrementally
  nscoord xa = 0, ya = 0, xb = aMetrics.width, yb = aMetrics.height;
  if (NS_STYLE_OVERFLOW_HIDDEN != aReflowState.mStyleDisplay->mOverflow) {
    nsLineBox* line = mLines;
    while (nsnull != line) {
      // Compute min and max x/y values for the reflowed frame's
      // combined areas
      nsRect lineCombinedArea;
      line->GetCombinedArea(&lineCombinedArea);
      nscoord x = lineCombinedArea.x;
      nscoord y = lineCombinedArea.y;
      nscoord xmost = x + lineCombinedArea.width;
      nscoord ymost = y + lineCombinedArea.height;
      if (x < xa) {
        xa = x;
      }
      if (xmost > xb) {
        xb = xmost;
      }
      if (y < ya) {
        ya = y;
      }
      if (ymost > yb) {
        yb = ymost;
      }
      line = line->mNext;
    }
    // Factor the bullet in; normally the bullet will be factored into
    // the line-box's combined area. However, if the line is a block
    // line then it won't; if there are no lines, it won't. So just
    // factor it in anyway (it can't hurt if it was already done).
    if (mBullet) {
      nsRect r;
      mBullet->GetRect(r);
      if (r.x < xa) xa = r.x;
      if (r.y < ya) ya = r.y;
      nscoord xmost = r.XMost();
      if (xmost > xb) xb = xmost;
      nscoord ymost = r.YMost();
      if (ymost > yb) yb = ymost;
    }
  }
#ifdef NOISY_COMBINED_AREA
  ListTag(stdout);
  printf(": ca=%d,%d,%d,%d\n", xa, ya, xb-xa, yb-ya);
#endif
  // If the combined area of our children exceeds our bounding box
  // then set the NS_FRAME_OUTSIDE_CHILDREN flag, otherwise clear it.
  aMetrics.mOverflowArea.x = xa;
  aMetrics.mOverflowArea.y = ya;
  aMetrics.mOverflowArea.width = xb - xa;
  aMetrics.mOverflowArea.height = yb - ya;
  if ((aMetrics.mOverflowArea.x < 0) ||
      (aMetrics.mOverflowArea.y < 0) ||
      (aMetrics.mOverflowArea.XMost() > aMetrics.width) ||
      (aMetrics.mOverflowArea.YMost() > aMetrics.height)) {
    mState |= NS_FRAME_OUTSIDE_CHILDREN;
  }
  else {
    mState &= ~NS_FRAME_OUTSIDE_CHILDREN;
  }
}
nsresult
nsBlockFrame::PrepareInitialReflow(nsBlockReflowState& aState)
{
  PrepareResizeReflow(aState);
  return NS_OK;
}
nsresult
nsBlockFrame::PrepareChildIncrementalReflow(nsBlockReflowState& aState)
{
  // Determine the line being impacted
  PRBool isFloater;
  nsLineBox* prevLine;
  nsLineBox* line = FindLineFor(aState.mNextRCFrame, &prevLine, &isFloater);
  if (nsnull == line) {
    // This can't happen, but just in case it does...
    return PrepareResizeReflow(aState);
  }
  // XXX: temporary: If the child frame is a floater then punt
  if (isFloater) {
    return PrepareResizeReflow(aState);
  }
  // Figure out which line to mark dirty.
  MarkLineDirty(line, prevLine);
  return NS_OK;
}
nsresult
nsBlockFrame::MarkLineDirty(nsLineBox* aLine, nsLineBox* aPrevLine)
{
  // If the line that was affected is a block then just mark it dirty
  // so that we reflow it.
  if (aLine->IsBlock()) {
    aLine->MarkDirty();
#ifdef DEBUG
    if (gNoisyReflow) {
      IndentBy(stdout, gNoiseIndent);
      ListTag(stdout);
      printf(": mark line %p dirty\n", aLine);
    }
#endif
  }
  else {
    // Mark previous line dirty if its an inline line so that it can
    // maybe pullup something from the line just affected.
    if (aPrevLine && !aPrevLine->IsBlock()) {
      aPrevLine->MarkDirty();
#ifdef DEBUG
      if (gNoisyReflow) {
        IndentBy(stdout, gNoiseIndent);
        ListTag(stdout);
        printf(": mark prev-line %p dirty\n", aPrevLine);
      }
#endif
    }
    else {
      aLine->MarkDirty();
#ifdef DEBUG
      if (gNoisyReflow) {
        IndentBy(stdout, gNoiseIndent);
        ListTag(stdout);
        printf(": mark line %p dirty\n", aLine);
      }
#endif
    }
  }
  return NS_OK;
}
nsresult
nsBlockFrame::UpdateBulletPosition(nsBlockReflowState& aState)
{
  if (nsnull == mBullet) {
    // Don't bother if there is no bullet
    return NS_OK;
  }
  const nsStyleList* styleList;
  GetStyleData(eStyleStruct_List, (const nsStyleStruct*&) styleList);
  if (NS_STYLE_LIST_STYLE_POSITION_INSIDE == styleList->mListStylePosition) {
    if (HaveOutsideBullet()) {
      // We now have an inside bullet, but used to have an outside
      // bullet.  Adjust the frame line list
      nsLineBox* line = aState.NewLineBox(mBullet, 1, PR_FALSE);
      if (!line) {
        return NS_ERROR_OUT_OF_MEMORY;
      }
      line->mNext = mLines;
      mLines = line;
    }
    mState &= ~NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET;
  }
  else {
    if (!HaveOutsideBullet()) {
      // We now have an outside bullet, but used to have an inside
      // bullet. Take the bullet frame out of the first lines frame
      // list.
      if ((nsnull != mLines) && (mBullet == mLines->mFirstChild)) {
        nsIFrame* next;
        mBullet->GetNextSibling(&next);
        mBullet->SetNextSibling(nsnull);
        PRInt32 count = mLines->GetChildCount() - 1;
        NS_ASSERTION(count >= 0, "empty line w/o bullet");
        mLines->SetChildCount(count);
        if (0 == count) {
          nsLineBox* nextLine = mLines->mNext;
          aState.FreeLineBox(mLines);
          mLines = nextLine;
          if (nsnull != nextLine) {
            nextLine->MarkDirty();
          }
        }
        else {
          mLines->mFirstChild = next;
          mLines->MarkDirty();
        }
      }
    }
    mState |= NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET;
  }
#ifdef DEBUG
  VerifyLines(PR_TRUE);
#endif
  return NS_OK;
}
nsresult
nsBlockFrame::PrepareStyleChangedReflow(nsBlockReflowState& aState)
{
  nsresult rv = UpdateBulletPosition(aState);
  // Mark everything dirty
  nsLineBox* line = mLines;
  while (nsnull != line) {
    line->MarkDirty();
    line = line->mNext;
  }
  return rv;
}
nsresult
nsBlockFrame::PrepareResizeReflow(nsBlockReflowState& aState)
{
  // See if we can try and avoid marking all the lines as dirty
  PRBool  tryAndSkipLines = PR_FALSE;
  // See if this is this a constrained resize reflow
  if ((aState.mReflowState.reason == eReflowReason_Resize) &&
      (NS_UNCONSTRAINEDSIZE != aState.mReflowState.availableWidth)) {
    // If the text is left-aligned, then we try and avoid reflowing the lines
    const nsStyleText* styleText = (const nsStyleText*)
      mStyleContext->GetStyleData(eStyleStruct_Text);
    if ((NS_STYLE_TEXT_ALIGN_LEFT == styleText->mTextAlign) ||
        ((NS_STYLE_TEXT_ALIGN_DEFAULT == styleText->mTextAlign) &&
         (NS_STYLE_DIRECTION_LTR == aState.mReflowState.mStyleDisplay->mDirection))) {
      tryAndSkipLines = PR_TRUE;
    }
  }
#ifdef DEBUG
  if (gDisableResizeOpt) {
    tryAndSkipLines = PR_FALSE;
  }
  if (gNoisyReflow) {
    if (!tryAndSkipLines) {
      const nsStyleText* mStyleText = (const nsStyleText*)
        mStyleContext->GetStyleData(eStyleStruct_Text);
      IndentBy(stdout, gNoiseIndent);
      ListTag(stdout);
      printf(": marking all lines dirty: reason=%d availWidth=%d textAlign=%d\n",
             aState.mReflowState.reason,
             aState.mReflowState.availableWidth,
             mStyleText->mTextAlign);
    }
  }
#endif
  nsLineBox* line = mLines;
  if (tryAndSkipLines) {
    // The line's bounds are relative to the border edge of the frame
    nscoord newAvailWidth = aState.mReflowState.mComputedBorderPadding.left;
     
    if (NS_SHRINKWRAPWIDTH == aState.mReflowState.mComputedWidth) {
      newAvailWidth += aState.mReflowState.mComputedMaxWidth;
    } else {
      newAvailWidth += aState.mReflowState.mComputedWidth;
    }
#ifdef DEBUG
    if (gNoisyReflow) {
      IndentBy(stdout, gNoiseIndent);
      ListTag(stdout);
      printf(": trying to avoid marking all lines dirty\n");
    }
#endif
    
    PRBool notWrapping = aState.mNoWrap;
    while (nsnull != line) {
      if (line->IsBlock()) {
        // We have to let child blocks make their own decisions.
        line->MarkDirty();
      }
      else {
        // We can avoid reflowing *some* inline lines in some cases.
        if (notWrapping) {
          // When no-wrap is set then the only line-breaking that
          // occurs for inline lines is triggered by BR elements or by
          // newlines. Therefore, we don't need to reflow the line.
        }
        else if ((line->mNext && !line->HasBreak()) ||
                 line->HasFloaters() || line->IsImpactedByFloater() ||
                 line->HasPercentageChild() ||
                 (line->mBounds.XMost() > newAvailWidth)) {
          // When an inline line has:
          //
          //  - a next line and it doesn't end in a break, or
          //  - floaters, or
          //  - is impacted by a floater, or
          //  - is wider than the new available space
          //
          // Then we must reflow it.
          line->MarkDirty();
        }
#ifdef DEBUG
        if (gNoisyReflow && !line->IsDirty() && !notWrapping) {
          IndentBy(stdout, gNoiseIndent + 1);
          printf("skipped: line=%p next=%p %s %s %s%s%s breakType=%d xmost=%d\n",
                 line, line->mNext,
                 line->IsBlock() ? "block" : "inline",
                 aState.mNoWrap ? "no-wrap" : "wrapping",
                 line->HasBreak() ? "has-break " : "",
                 line->HasFloaters() ? "has-floaters " : "",
                 line->IsImpactedByFloater() ? "impacted " : "",
                 line->GetBreakType(),
                 line->mBounds.XMost());
        }
#endif
      }
      line = line->mNext;
    }
  }
  else {
    // Mark everything dirty
    while (nsnull != line) {
      line->MarkDirty();
      line = line->mNext;
    }
  }
  return NS_OK;
}
//----------------------------------------
nsLineBox*
nsBlockFrame::FindLineFor(nsIFrame* aFrame,
                          nsLineBox** aPrevLineResult,
                          PRBool* aIsFloaterResult)
{
  nsLineBox* prevLine = nsnull;
  nsLineBox* line = mLines;
  PRBool isFloater = PR_FALSE;
  while (nsnull != line) {
    if (line->Contains(aFrame)) {
      break;
    }
    if (line->HasFloaters()) {
      nsFloaterCache* fc = line->GetFirstFloater();
      while (fc) {
        if (aFrame == fc->mPlaceholder->GetOutOfFlowFrame()) {
          isFloater = PR_TRUE;
          goto done;
        }
        fc = fc->Next();
      }
    }
    prevLine = line;
    line = line->mNext;
  }
 done:
  *aIsFloaterResult = isFloater;
  *aPrevLineResult = prevLine;
  return line;
}
void
nsBlockFrame::RecoverStateFrom(nsBlockReflowState& aState,
                               nsLineBox* aLine,
                               nscoord aDeltaY,
                               nsRect* aDamageRect)
{
  PRBool applyTopMargin = PR_FALSE;
  if (aLine->IsBlock()) {
    nsIFrame* framePrevInFlow;
    aLine->mFirstChild->GetPrevInFlow(&framePrevInFlow);
    if (nsnull == framePrevInFlow) {
      applyTopMargin = ShouldApplyTopMargin(aState, aLine);
    }
  }
  aState.RecoverStateFrom(aLine, applyTopMargin, aDeltaY, aDamageRect);
}
/**
 * Propogate reflow "damage" from the just reflowed line (aLine) to
 * any subsequent lines that were affected. The only thing that causes
 * damage is a change to the impact that floaters make.
 */
void
nsBlockFrame::PropogateReflowDamage(nsBlockReflowState& aState,
                                    nsLineBox* aLine,
                                    const nsRect& aOldCombinedArea,
                                    nscoord aDeltaY)
{
  // See if the line has a relevant combined area, and if it does if
  // the combined area has changed.
  nsRect lineCombinedArea;
  aLine->GetCombinedArea(&lineCombinedArea);
  if (lineCombinedArea != aLine->mBounds) {
    if (lineCombinedArea != aOldCombinedArea) {
      // The line's combined-area changed. Therefore we need to damage
      // the lines below that were previously (or are now) impacted by
      // the change. It's possible that a floater shrunk or grew so
      // use the larger of the impacted area.
      nscoord newYMost = lineCombinedArea.YMost();
      nscoord oldYMost = aOldCombinedArea.YMost();
      nscoord impactYB = newYMost < oldYMost ? oldYMost : newYMost;
      nscoord impactYA = lineCombinedArea.y;
      // Loop over each subsequent line and mark them dirty if they
      // intersect the impacted area. Note: we cannot stop after the
      // first non-intersecting line because lines might be
      // overlapping because of negative margins.
      nsLineBox* next = aLine->mNext;
      while (nsnull != next) {
        nscoord lineYA = next->mBounds.y + aDeltaY;
        nscoord lineYB = lineYA + next->mBounds.height;
        if ((lineYB >= impactYA) && (lineYA < impactYB)) {
          next->MarkDirty();
        }
        next = next->mNext;
      }
    }
    else {
      // The line's combined area didn't change from last
      // time. Therefore just sliding subsequent lines will work.
      return;
    }
  }
  if (aDeltaY) {
    nsLineBox* next = aLine->mNext;
    while (nsnull != next) {
      if (!next->IsDirty()) {
        // Cases we need to find:
        //
        // 1. the line was impacted by a floater and now isn't
        // 2. the line wasn't impacted by a floater and now is
        //
        //XXXPerf: An optimization: if the line was and is completely
        //impacted by a floater and the floater hasn't changed size,
        //then we don't need to mark the line dirty.
        aState.GetAvailableSpace(next->mBounds.y + aDeltaY);
        PRBool wasImpactedByFloater = next->IsImpactedByFloater();
        PRBool isImpactedByFloater = aState.IsImpactedByFloater();
        if (wasImpactedByFloater != isImpactedByFloater) {
          next->MarkDirty();
        }
        else if (isImpactedByFloater) {
          //XXX: Maybe the floater itself changed size?
          if (next->IsBlock()) {
            //XXXPerf
            // Case:
            // It's possible that more/less of the line is impacted by
            // the floater than last time. So reflow.
            next->MarkDirty();
          }
        }
      }
      next = next->mNext;
    }
  }
}
static PRBool
WrappedLinesAreDirty(nsLineBox* aLine)
{
  if (aLine->IsInline()) {
    while (aLine->IsLineWrapped()) {
      aLine = aLine->mNext;
      if (!aLine) {
        break;
      }
      NS_ASSERTION(!aLine->IsBlock(), "didn't expect a block line");
      if (aLine->IsDirty()) {
        // we found a continuing line that is dirty
        return PR_TRUE;
      }
    }
  }
  return PR_FALSE;
}
/**
 * Reflow the dirty lines
 */
nsresult
nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
{
  nsresult rv = NS_OK;
  PRBool keepGoing = PR_TRUE;
#ifdef DEBUG
  if (gNoisyReflow) {
    if (aState.mReflowState.reason == eReflowReason_Incremental) {
      nsIReflowCommand::ReflowType type;
      aState.mReflowState.reflowCommand->GetType(type);
      IndentBy(stdout, gNoiseIndent);
      ListTag(stdout);
      printf(": incrementally reflowing dirty lines: type=%s(%d)",
             kReflowCommandType[type], type);
    }
    else {
      IndentBy(stdout, gNoiseIndent);
      ListTag(stdout);
      printf(": reflowing dirty lines");
    }
    printf(" computedWidth=%d\n", aState.mReflowState.mComputedWidth);
    gNoiseIndent++;
  }
#endif
  // Check whether this is an incremental reflow
  PRBool  incrementalReflow = aState.mReflowState.reason ==
                              eReflowReason_Incremental ||
                              aState.mReflowState.reason ==
                              eReflowReason_Dirty;
  
  // Reflow the lines that are already ours
  aState.mPrevLine = nsnull;
  nsLineBox* line = mLines;
  nscoord deltaY = 0;
  while (nsnull != line) {
#ifdef DEBUG
    if (gNoisyReflow) {
      nsRect lca;
      line->GetCombinedArea(&lca);
      IndentBy(stdout, gNoiseIndent);
      printf("line=%p mY=%d dirty=%s oldBounds={%d,%d,%d,%d} oldCombinedArea={%d,%d,%d,%d} deltaY=%d mPrevBottomMargin=%d\n",
             line, aState.mY, line->IsDirty() ? "yes" : "no",
             line->mBounds.x, line->mBounds.y,
             line->mBounds.width, line->mBounds.height,
             lca.x, lca.y, lca.width, lca.height,
             deltaY, aState.mPrevBottomMargin);
      gNoiseIndent++;
    }
#endif
    // If we're supposed to update our maximum width, then we'll also need to
    // reflow this line if it's line wrapped and any of the continuing lines
    // are dirty
    if (line->IsDirty() || (aState.mComputeMaximumWidth && ::WrappedLinesAreDirty(line))) {
      // Compute the dirty lines "before" YMost, after factoring in
      // the running deltaY value - the running value is implicit in
      // aState.mY.
      nscoord oldHeight = line->mBounds.height;
      nsRect oldCombinedArea;
      line->GetCombinedArea(&oldCombinedArea);
      // Reflow the dirty line. If it's an incremental reflow, then have
      // it invalidate the dirty area
      rv = ReflowLine(aState, line, &keepGoing, incrementalReflow);
      if (NS_FAILED(rv)) {
        return rv;
      }
      if (!keepGoing) {
        if (0 == line->GetChildCount()) {
          DeleteLine(aState, line);
        }
        break;
      }
      nscoord newHeight = line->mBounds.height;
      deltaY += newHeight - oldHeight;
      // If the next line is clean then check and see if reflowing the
      // current line "damaged" the next line. Damage occurs when the
      // current line contains floaters that intrude upon the
      // subsequent lines.
      nsLineBox* next = line->mNext;
      if ((nsnull != next) && !next->IsDirty()) {
        PropogateReflowDamage(aState, line, oldCombinedArea, deltaY);
      }
    }
    else {
      // XXX what if the slid line doesn't fit because we are in a
      // vertically constrained situation?
      // Recover state as if we reflowed this line
      nsRect  damageRect;
      RecoverStateFrom(aState, line, deltaY, incrementalReflow ?
                       &damageRect : 0);
      if (incrementalReflow && !damageRect.IsEmpty()) {
        Invalidate(aState.mPresContext, damageRect);
      }
    }
#ifdef DEBUG
    if (gNoisyReflow) {
      gNoiseIndent--;
      nsRect lca;
      line->GetCombinedArea(&lca);
      IndentBy(stdout, gNoiseIndent);
      printf("line=%p mY=%d newBounds={%d,%d,%d,%d} newCombinedArea={%d,%d,%d,%d} deltaY=%d mPrevBottomMargin=%d\n",
             line, aState.mY,
             line->mBounds.x, line->mBounds.y,
             line->mBounds.width, line->mBounds.height,
             lca.x, lca.y, lca.width, lca.height,
             deltaY, aState.mPrevBottomMargin);
    }
#endif
    // If this is an inline frame then its time to stop
    aState.mPrevLine = line;
    line = line->mNext;
    aState.AdvanceToNextLine();
  }
  // Pull data from a next-in-flow if we can
  while (keepGoing && (nsnull != aState.mNextInFlow)) {
    // Grab first line from our next-in-flow
    line = aState.mNextInFlow->mLines;
    if (nsnull == line) {
      aState.mNextInFlow = (nsBlockFrame*) aState.mNextInFlow->mNextInFlow;
      continue;
    }
    // XXX See if the line is not dirty; if it's not maybe we can
    // avoid the pullup if it can't fit?
    aState.mNextInFlow->mLines = line->mNext;
    line->mNext = nsnull;
    if (0 == line->GetChildCount()) {
      // The line is empty. Try the next one.
      NS_ASSERTION(nsnull == line->mFirstChild, "bad empty line");
      aState.FreeLineBox(line);
      continue;
    }
    // XXX move to a subroutine: run-in, overflow, pullframe and this do this
    // Make the children in the line ours.
    nsIFrame* frame = line->mFirstChild;
    nsIFrame* lastFrame = nsnull;
    PRInt32 n = line->GetChildCount();
    while (--n >= 0) {
      frame->SetParent(this);
      // When pushing and pulling frames we need to check for whether any
      // views need to be reparented
      nsHTMLContainerFrame::ReparentFrameView(aState.mPresContext, frame, mNextInFlow, this);
      lastFrame = frame;
      frame->GetNextSibling(&frame);
    }
    lastFrame->SetNextSibling(nsnull);
    // Add line to our line list
    if (nsnull == aState.mPrevLine) {
      NS_ASSERTION(nsnull == mLines, "bad aState.mPrevLine");
      mLines = line;
    }
    else {
      NS_ASSERTION(nsnull == aState.mPrevLine->mNext, "bad aState.mPrevLine");
      aState.mPrevLine->mNext = line;
      aState.mPrevChild->SetNextSibling(line->mFirstChild);
    }
    // Now reflow it and any lines that it makes during it's reflow
    // (we have to loop here because reflowing the line may case a new
    // line to be created; see SplitLine's callers for examples of
    // when this happens).
    while (nsnull != line) {
      rv = ReflowLine(aState, line, &keepGoing, incrementalReflow ?
                      PR_TRUE : PR_FALSE);
      if (NS_FAILED(rv)) {
        return rv;
      }
      if (!keepGoing) {
        if (0 == line->GetChildCount()) {
          DeleteLine(aState, line);
        }
        break;
      }
      // If this is an inline frame then its time to stop
      aState.mPrevLine = line;
      line = line->mNext;
      aState.AdvanceToNextLine();
    }
  }
  // Handle an odd-ball case: a list-item with no lines
  if (mBullet && HaveOutsideBullet() && !mLines) {
    nsHTMLReflowMetrics metrics(nsnull);
    ReflowBullet(aState, metrics);
    // There are no lines so we have to fake up some y motion so that
    // we end up with *some* height.
    aState.mY += metrics.height;
  }
#ifdef DEBUG
  if (gNoisyReflow) {
    gNoiseIndent--;
    IndentBy(stdout, gNoiseIndent);
    ListTag(stdout);
    printf(": done reflowing dirty lines (status=%x)\n",
           aState.mReflowStatus);
  }
#endif
  return rv;
}
void
nsBlockFrame::DeleteLine(nsBlockReflowState& aState,
                         nsLineBox* aLine)
{
  NS_PRECONDITION(0 == aLine->GetChildCount(), "can't delete !empty line");
  if (0 == aLine->GetChildCount()) {
    if (nsnull == aState.mPrevLine) {
      NS_ASSERTION(aLine == mLines, "huh");
      mLines = nsnull;
    }
    else {
      NS_ASSERTION(aState.mPrevLine->mNext == aLine, "bad prev-line");
      aState.mPrevLine->mNext = aLine->mNext;
    }
    aState.FreeLineBox(aLine);
  }
}
/**
 * Reflow a line. The line will either contain a single block frame
 * or contain 1 or more inline frames. aLineReflowStatus indicates
 * whether or not the caller should continue to reflow more lines.
 */
nsresult
nsBlockFrame::ReflowLine(nsBlockReflowState& aState,
                         nsLineBox* aLine,
                         PRBool* aKeepReflowGoing,
                         PRBool aDamageDirtyArea)
{
  nsresult rv = NS_OK;
  NS_ABORT_IF_FALSE(aLine->GetChildCount(), "reflowing empty line");
  // Setup the line-layout for the new line
  aState.mCurrentLine = aLine;
  aLine->ClearDirty();
  // Now that we know what kind of line we have, reflow it
  nsRect oldCombinedArea;
  aLine->GetCombinedArea(&oldCombinedArea);
  if (aLine->IsBlock()) {
    rv = ReflowBlockFrame(aState, aLine, aKeepReflowGoing);
    
    // We expect blocks to damage any area inside their bounds that is
    // dirty; however, if the frame changes size or position then we
    // need to do some repainting
    if (aDamageDirtyArea) {
      nsRect lineCombinedArea;
      aLine->GetCombinedArea(&lineCombinedArea);
      if ((oldCombinedArea.x != lineCombinedArea.x) ||
          (oldCombinedArea.y != lineCombinedArea.y)) {
        // The block has moved, and so do be safe we need to repaint
        // XXX We need to improve on this...
        nsRect  dirtyRect;
        dirtyRect.UnionRect(oldCombinedArea, lineCombinedArea);
        Invalidate(aState.mPresContext, dirtyRect);
      } else {
        if (oldCombinedArea.width != lineCombinedArea.width) {
          nsRect  dirtyRect;
          // Just damage the vertical strip that was either added or went
          // away
          dirtyRect.x = PR_MIN(oldCombinedArea.XMost(),
                               lineCombinedArea.XMost());
          dirtyRect.y = lineCombinedArea.y;
          dirtyRect.width = PR_MAX(oldCombinedArea.XMost(),
                                   lineCombinedArea.XMost()) -
                            dirtyRect.x;
          dirtyRect.height = PR_MAX(oldCombinedArea.height,
                                    lineCombinedArea.height);
          Invalidate(aState.mPresContext, dirtyRect);
        }
        if (oldCombinedArea.height != lineCombinedArea.height) {
          nsRect  dirtyRect;
          
          // Just damage the horizontal strip that was either added or went
          // away
          dirtyRect.x = lineCombinedArea.x;
          dirtyRect.y = PR_MIN(oldCombinedArea.YMost(),
                               lineCombinedArea.YMost());
          dirtyRect.width = PR_MAX(oldCombinedArea.width,
                                   lineCombinedArea.width);
          dirtyRect.height = PR_MAX(oldCombinedArea.YMost(),
                                    lineCombinedArea.YMost()) -
                             dirtyRect.y;
          Invalidate(aState.mPresContext, dirtyRect);
        }
      }
    }
  }
  else {
    aLine->SetLineWrapped(PR_FALSE);
    // If we're supposed to update the maximum width, then we'll need to reflow
    // the line with an unconstrained width (which will give us the new maximum
    // width), then we'll reflow it again with the constrained width.
    // We only do this if this is a beginning line, i.e., don't do this for
    // lines associated with content that line wrapped (see ReflowDirtyLines()
    // for details).
    // XXX This approach doesn't work when floaters are involved in which case
    // we'll either need to recover the floater state that applies to the
    // unconstrained reflow or keep it around in a separate space manager...
    PRBool  isBeginningLine = !aState.mPrevLine || !aState.mPrevLine->IsLineWrapped();
    if (aState.mComputeMaximumWidth && isBeginningLine) {
      nscoord oldY = aState.mY;
      nscoord oldPrevBottomMargin = aState.mPrevBottomMargin;
      // First reflow the line with an unconstrained width
      ReflowInlineFrames(aState, aLine, aKeepReflowGoing, PR_TRUE);
      // Update the line's maximum width
      aLine->mMaximumWidth = aLine->mBounds.XMost();
      aState.UpdateMaximumWidth(aLine->mMaximumWidth);
      // Remove any floaters associated with the line from the space
      // manager
      aLine->RemoveFloatersFromSpaceManager(aState.mSpaceManager);
      // Now reflow the line again this time without having it compute
      // the maximum width
      aState.mY = oldY;
      aState.mPrevBottomMargin = oldPrevBottomMargin;
      rv = ReflowInlineFrames(aState, aLine, aKeepReflowGoing);
    } else {
      rv = ReflowInlineFrames(aState, aLine, aKeepReflowGoing);
    }
    // We don't really know what changed in the line, so use the union
    // of the old and new combined areas
    if (aDamageDirtyArea) {
      nsRect combinedArea;
      aLine->GetCombinedArea(&combinedArea);
      nsRect dirtyRect;
      dirtyRect.UnionRect(oldCombinedArea, combinedArea);
      Invalidate(aState.mPresContext, dirtyRect);
    }
  }
  return rv;
}
/**
 * Pull frame from the next available location (one of our lines or
 * one of our next-in-flows lines).
 */
nsresult
nsBlockFrame::PullFrame(nsBlockReflowState& aState,
                        nsLineBox* aLine,
                        nsIFrame*& aFrameResult)
{
  nsresult rv = NS_OK;
  PRBool stopPulling;
  aFrameResult = nsnull;
  // First check our remaining lines
  while (nsnull != aLine->mNext) {
    rv = PullFrame(aState, aLine, &aLine->mNext, PR_FALSE,
                   aFrameResult, stopPulling);
    if (NS_FAILED(rv) || stopPulling) {
      return rv;
    }
  }
  // Pull frames from the next-in-flow(s) until we can't
  nsBlockFrame* nextInFlow = aState.mNextInFlow;
  while (nsnull != nextInFlow) {
    nsLineBox* line = nextInFlow->mLines;
    if (nsnull == line) {
      nextInFlow = (nsBlockFrame*) nextInFlow->mNextInFlow;
      aState.mNextInFlow = nextInFlow;
      continue;
    }
    rv = PullFrame(aState, aLine, &nextInFlow->mLines, PR_TRUE,
                   aFrameResult, stopPulling);
    if (NS_FAILED(rv) || stopPulling) {
      return rv;
    }
  }
  return rv;
}
/**
 * Try to pull a frame out of a line pointed at by aFromList. If a
 * frame is pulled then aPulled will be set to PR_TRUE. In addition,
 * if aUpdateGeometricParent is set then the pulled frames geometric
 * parent will be updated (e.g. when pulling from a next-in-flows line
 * list).
 *
 * Note: pulling a frame from a line that is a place-holder frame
 * doesn't automatically remove the corresponding floater from the
 * line's floater array. This happens indirectly: either the line gets
 * emptied (and destroyed) or the line gets reflowed (because we mark
 * it dirty) and the code at the top of ReflowLine empties the
 * array. So eventually, it will be removed, just not right away.
 */
nsresult
nsBlockFrame::PullFrame(nsBlockReflowState& aState,
                        nsLineBox* aLine,
                        nsLineBox** aFromList,
                        PRBool aUpdateGeometricParent,
                        nsIFrame*& aFrameResult,
                        PRBool& aStopPulling)
{
  nsLineBox* fromLine = *aFromList;
  NS_ABORT_IF_FALSE(fromLine, "bad line to pull from");
  NS_ABORT_IF_FALSE(fromLine->GetChildCount(), "empty line");
  NS_ABORT_IF_FALSE(aLine->GetChildCount(), "empty line");
  if (fromLine->IsBlock()) {
    // If our line is not empty and the child in aFromLine is a block
    // then we cannot pull up the frame into this line. In this case
    // we stop pulling.
    aStopPulling = PR_TRUE;
    aFrameResult = nsnull;
  }
  else {
    // Take frame from fromLine
    nsIFrame* frame = fromLine->mFirstChild;
    aLine->SetChildCount(aLine->GetChildCount() + 1);
    PRInt32 fromLineChildCount = fromLine->GetChildCount();
    if (0 != --fromLineChildCount) {
      // Mark line dirty now that we pulled a child
      fromLine->SetChildCount(fromLineChildCount);
      fromLine->MarkDirty();
      frame->GetNextSibling(&fromLine->mFirstChild);
    }
    else {
      // Free up the fromLine now that it's empty
      *aFromList = fromLine->mNext;
      aState.FreeLineBox(fromLine);
    }
    // Change geometric parents
    if (aUpdateGeometricParent) {
      // Before we set the new parent frame get the current parent
      nsIFrame* oldParentFrame;
      frame->GetParent(&oldParentFrame);
      frame->SetParent(this);
      // When pushing and pulling frames we need to check for whether any
      // views need to be reparented
      NS_ASSERTION(oldParentFrame != this, "unexpected parent frame");
      nsHTMLContainerFrame::ReparentFrameView(aState.mPresContext, frame, oldParentFrame, this);
      
      // The frame is being pulled from a next-in-flow; therefore we
      // need to add it to our sibling list.
      if (nsnull != aState.mPrevChild) {
        aState.mPrevChild->SetNextSibling(frame);
      }
      frame->SetNextSibling(nsnull);
    }
    // Stop pulling because we found a frame to pull
    aStopPulling = PR_TRUE;
    aFrameResult = frame;
#ifdef DEBUG
    VerifyLines(PR_TRUE);
#endif
  }
  return NS_OK;
}
static void
PlaceFrameView(nsIPresContext* aPresContext,
               nsIFrame*       aFrame)
{
  nsIView*  view;
  aFrame->GetView(aPresContext, &view);
  if (view) {
    nsContainerFrame::SyncFrameViewAfterReflow(aPresContext, aFrame, view, nsnull);
  } else {
    nsContainerFrame::PositionChildViews(aPresContext, aFrame);
  }
}
void
nsBlockFrame::SlideLine(nsBlockReflowState& aState,
                        nsLineBox* aLine, nscoord aDY)
{
  // Adjust line state
  aLine->SlideBy(aDY);
  // Adjust the frames in the line
  nsIFrame* kid = aLine->mFirstChild;
  if (!kid) {
    return;
  }
  if (aLine->IsBlock()) {
    nsRect r;
    kid->GetRect(r);
    if (aDY) {
      r.y += aDY;
      kid->SetRect(aState.mPresContext, r);
    }
    // Make sure the frame's view and any child views are updated
    ::PlaceFrameView(aState.mPresContext, kid);
    // If the child has any floaters that impact the space-manager,
    // place them now so that they are present in the space-manager
    // again (they were removed by the space-manager's frame when
    // the reflow began).
    nsBlockFrame* bf;
    nsresult rv = kid->QueryInterface(kBlockFrameCID, (void**) &bf);
    if (NS_SUCCEEDED(rv)) {
      // Translate spacemanager to the child blocks upper-left corner
      // so that when it places its floaters (which are relative to
      // it) the right coordinates are used. Note that we have already
      // been translated by our border+padding so factor that in to
      // get the right translation.
      const nsMargin& bp = aState.BorderPadding();
      nscoord dx = r.x - bp.left;
      nscoord dy = r.y - bp.top;
      aState.mSpaceManager->Translate(dx, dy);
      bf->UpdateSpaceManager(aState.mPresContext, aState.mSpaceManager);
      aState.mSpaceManager->Translate(-dx, -dy);
    }
  }
  else {
    // Adjust the Y coordinate of the frames in the line.
    // Note: we need to re-position views even if aDY is 0, because
    // one of our parent frames may have moved and so the view's position
    // relative to its parent may have changed
    nsRect r;
    PRInt32 n = aLine->GetChildCount();
    while (--n >= 0) {
      if (aDY) {
        kid->GetRect(r);
        r.y += aDY;
        kid->SetRect(aState.mPresContext, r);
      }
      // Make sure the frame's view and any child views are updated
      ::PlaceFrameView(aState.mPresContext, kid);
      kid->GetNextSibling(&kid);
    }
  }
}
nsresult
nsBlockFrame::UpdateSpaceManager(nsIPresContext* aPresContext,
                                 nsISpaceManager* aSpaceManager)
{
  nsLineBox* line = mLines;
  while (nsnull != line) {
    // Place the floaters in the spacemanager
    if (line->HasFloaters()) {
      nsFloaterCache* fc = line->GetFirstFloater();
      while (fc) {
        nsIFrame* floater = fc->mPlaceholder->GetOutOfFlowFrame();
        aSpaceManager->AddRectRegion(floater, fc->mRegion);
#ifdef NOISY_SPACEMANAGER
        nscoord tx, ty;
        aSpaceManager->GetTranslation(tx, ty);
        nsFrame::ListTag(stdout, this);
        printf(": UpdateSpaceManager: AddRectRegion: txy=%d,%d {%d,%d,%d,%d}\n",
               tx, ty,
               fc->mRegion.x, fc->mRegion.y,
               fc->mRegion.width, fc->mRegion.height);
#endif
        fc = fc->Next();
      }
    }
    // Tell kids about the move too
    if (line->mFirstChild && line->IsBlock()) {
      // If the child has any floaters that impact the space-manager,
      // place them now so that they are present in the space-manager
      // again (they were removed by the space-manager's frame when
      // the reflow began).
      nsBlockFrame* bf;
      nsresult rv = line->mFirstChild->QueryInterface(kBlockFrameCID,
                                                      (void**) &bf);
      if (NS_SUCCEEDED(rv)) {
        nsPoint origin;
        bf->GetOrigin(origin);
        // Translate spacemanager to the child blocks upper-left
        // corner so that when it places its floaters (which are
        // relative to it) the right coordinates are used.
        aSpaceManager->Translate(origin.x, origin.y);
        bf->UpdateSpaceManager(aPresContext, aSpaceManager);
        aSpaceManager->Translate(-origin.x, -origin.y);
      }
    }
    
    line = line->mNext;
  }
  return NS_OK;
}
NS_IMETHODIMP 
nsBlockFrame::AttributeChanged(nsIPresContext* aPresContext,
                               nsIContent*     aChild,
                               PRInt32         aNameSpaceID,
                               nsIAtom*        aAttribute,
                               PRInt32         aHint)
{
  nsresult rv = nsBlockFrameSuper::AttributeChanged(aPresContext, aChild,
                                                    aNameSpaceID, aAttribute, aHint);
  if (NS_OK != rv) {
    return rv;
  }
  if (nsHTMLAtoms::start == aAttribute) {
    // XXX Not sure if this is necessary anymore
    RenumberLists();
    nsCOMPtr ... ). This is where
      // the second case can happen.
      if (HaveOutsideBullet() &&
          ((aLine == mLines) ||
           ((0 == mLines->mBounds.height) && (aLine == mLines->mNext)))) {
        // Reflow the bullet
        nsHTMLReflowMetrics metrics(nsnull);
        ReflowBullet(aState, metrics);
        // For bullets that are placed next to a child block, there will
        // be no correct ascent value. Therefore, make one up...
        nscoord ascent = 0;
        const nsStyleFont* font;
        frame->GetStyleData(eStyleStruct_Font,
                            (const nsStyleStruct*&) font);
        nsIRenderingContext& rc = *aState.mReflowState.rendContext;
        rc.SetFont(font->mFont);
        nsIFontMetrics* fm;
        rv = rc.GetFontMetrics(fm);
        if (NS_SUCCEEDED(rv) && (nsnull != fm)) {
          fm->GetMaxAscent(ascent);
          NS_RELEASE(fm);
        }
        rv = NS_OK;
        // Tall bullets won't look particularly nice here...
        nsRect bbox;
        mBullet->GetRect(bbox);
        nscoord bulletTopMargin = applyTopMargin ? collapsedBottomMargin : 0;
        bbox.y = aState.BorderPadding().top + ascent -
          metrics.ascent + bulletTopMargin;
        mBullet->SetRect(aState.mPresContext, bbox);
      }
    }
    else {
      // None of the block fits. Determine the correct reflow status.
      if (aLine == mLines) {
        // If it's our very first line then we need to be pushed to
        // our parents next-in-flow. Therefore, return break-before
        // status for our reflow status.
        aState.mReflowStatus = NS_INLINE_LINE_BREAK_BEFORE();
      }
      else {
        // Push the line that didn't fit and any lines that follow it
        // to our next-in-flow.
        PushLines(aState);
        aState.mReflowStatus = NS_FRAME_NOT_COMPLETE;
      }
    }
  }
#ifdef DEBUG
  VerifyLines(PR_TRUE);
#endif
  return rv;
}
#define LINE_REFLOW_OK   0
#define LINE_REFLOW_STOP 1
#define LINE_REFLOW_REDO 2
nsresult
nsBlockFrame::ReflowInlineFrames(nsBlockReflowState& aState,
                                 nsLineBox* aLine,
                                 PRBool* aKeepReflowGoing,
                                 PRBool aUpdateMaximumWidth)
{
  nsresult rv = NS_OK;
  *aKeepReflowGoing = PR_TRUE;
#ifdef DEBUG
  PRInt32 spins = 0;
#endif
  PRUint8 lineReflowStatus = LINE_REFLOW_REDO;
  while (LINE_REFLOW_REDO == lineReflowStatus) {
    // Prevent overflowing limited thread stacks by creating
    // nsLineLayout from the heap when the frame tree depth gets
    // large.
    if (aState.mReflowState.mReflowDepth > 30) {//XXX layout-tune.h?
      rv = DoReflowInlineFramesMalloc(aState, aLine, aKeepReflowGoing,
                                      &lineReflowStatus,
                                      aUpdateMaximumWidth);
    }
    else {
      rv = DoReflowInlineFramesAuto(aState, aLine, aKeepReflowGoing,
                                    &lineReflowStatus,
                                    aUpdateMaximumWidth);
    }
    if (NS_FAILED(rv)) {
      break;
    }
#ifdef DEBUG
    spins++;
    if (1000 == spins) {
      ListTag(stdout);
      printf(": yikes! spinning on a line over 1000 times!\n");
      NS_ABORT();
    }
#endif
  }
  return rv;
}
nsresult
nsBlockFrame::DoReflowInlineFramesMalloc(nsBlockReflowState& aState,
                                         nsLineBox* aLine,
                                         PRBool* aKeepReflowGoing,
                                         PRUint8* aLineReflowStatus,
                                         PRBool aUpdateMaximumWidth)
{
  nsLineLayout* ll = new nsLineLayout(aState.mPresContext,
                                      aState.mReflowState.mSpaceManager,
                                      &aState.mReflowState,
                                      aState.mComputeMaxElementSize);
  if (!ll) {
    return NS_ERROR_OUT_OF_MEMORY;
  }
  ll->Init(&aState, aState.mMinLineHeight, aState.mLineNumber);
  ll->SetReflowTextRuns(mTextRuns);
  nsresult rv = DoReflowInlineFrames(aState, *ll, aLine, aKeepReflowGoing,
                                     aLineReflowStatus, aUpdateMaximumWidth);
  ll->EndLineReflow();
  delete ll;
  return rv;
}
nsresult
nsBlockFrame::DoReflowInlineFramesAuto(nsBlockReflowState& aState,
                                       nsLineBox* aLine,
                                       PRBool* aKeepReflowGoing,
                                       PRUint8* aLineReflowStatus,
                                       PRBool aUpdateMaximumWidth)
{
  nsLineLayout lineLayout(aState.mPresContext,
                          aState.mReflowState.mSpaceManager,
                          &aState.mReflowState,
                          aState.mComputeMaxElementSize);
  lineLayout.Init(&aState, aState.mMinLineHeight, aState.mLineNumber);
  lineLayout.SetReflowTextRuns(mTextRuns);
  nsresult rv = DoReflowInlineFrames(aState, lineLayout, aLine,
                                     aKeepReflowGoing, aLineReflowStatus,
                                     aUpdateMaximumWidth);
  lineLayout.EndLineReflow();
  return rv;
}
nsresult
nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState,
                                   nsLineLayout& aLineLayout,
                                   nsLineBox* aLine,
                                   PRBool* aKeepReflowGoing,
                                   PRUint8* aLineReflowStatus,
                                   PRBool aUpdateMaximumWidth)
{
  // Forget all of the floaters on the line
  aLine->FreeFloaters(aState.mFloaterCacheFreeList);
  aState.mFloaterCombinedArea.SetRect(0, 0, 0, 0);
  aState.mRightFloaterCombinedArea.SetRect(0, 0, 0, 0);
  // Setup initial coordinate system for reflowing the inline frames
  // into. Apply a previous block frame's bottom margin first.
  aState.mY += aState.mPrevBottomMargin;
  aState.GetAvailableSpace();
  PRBool impactedByFloaters = aState.IsImpactedByFloater();
  aLine->SetLineIsImpactedByFloater(impactedByFloaters);
  const nsMargin& borderPadding = aState.BorderPadding();
  nscoord x = aState.mAvailSpaceRect.x + borderPadding.left;
  nscoord availWidth = aState.mAvailSpaceRect.width;
  nscoord availHeight;
  if (aState.mUnconstrainedHeight) {
    availHeight = NS_UNCONSTRAINEDSIZE;
  }
  else {
    /* XXX get the height right! */
    availHeight = aState.mAvailSpaceRect.height;
  }
  if (aUpdateMaximumWidth) {
    availWidth = NS_UNCONSTRAINEDSIZE;
  }
  aLineLayout.BeginLineReflow(x, aState.mY,
                              availWidth, availHeight,
                              impactedByFloaters,
                              PR_FALSE /*XXX isTopOfPage*/);
  // XXX Unfortunately we need to know this before reflowing the first
  // inline frame in the line. FIX ME.
  if ((0 == aLineLayout.GetLineNumber()) &&
      (NS_BLOCK_HAS_FIRST_LETTER_STYLE & mState)) {
    aLineLayout.SetFirstLetterStyleOK(PR_TRUE);
  }
  // Reflow the frames that are already on the line first
  nsresult rv = NS_OK;
  PRUint8 lineReflowStatus = LINE_REFLOW_OK;
  PRInt32 i;
  nsIFrame* frame = aLine->mFirstChild;
  for (i = 0; i < aLine->GetChildCount(); i++) {      
    rv = ReflowInlineFrame(aState, aLineLayout, aLine, frame,
                           &lineReflowStatus);
    if (NS_FAILED(rv)) {
      return rv;
    }
    if (LINE_REFLOW_OK != lineReflowStatus) {
      // It is possible that one or more of next lines are empty
      // (because of DeleteChildsNextInFlow). If so, delete them now
      // in case we are finished.
      nsLineBox* nextLine = aLine->mNext;
      while ((nsnull != nextLine) && (0 == nextLine->GetChildCount())) {
        // XXX Is this still necessary now that DeleteChildsNextInFlow
        // uses DoRemoveFrame?
        aLine->mNext = nextLine->mNext;
        NS_ASSERTION(nsnull == nextLine->mFirstChild, "bad empty line");
        aState.FreeLineBox(nextLine);
        nextLine = aLine->mNext;
      }
      break;
    }
    frame->GetNextSibling(&frame);
  }
  // Pull frames and reflow them until we can't
  while (LINE_REFLOW_OK == lineReflowStatus) {
    rv = PullFrame(aState, aLine, frame);
    if (NS_FAILED(rv)) {
      return rv;
    }
    if (nsnull == frame) {
      break;
    }
    while (LINE_REFLOW_OK == lineReflowStatus) {
      PRInt32 oldCount = aLine->GetChildCount();
      rv = ReflowInlineFrame(aState, aLineLayout, aLine, frame,
                             &lineReflowStatus);
      if (NS_FAILED(rv)) {
        return rv;
      }
      if (aLine->GetChildCount() != oldCount) {
        // We just created a continuation for aFrame AND its going
        // to end up on this line (e.g. :first-letter
        // situation). Therefore we have to loop here before trying
        // to pull another frame.
        frame->GetNextSibling(&frame);
      }
      else {
        break;
      }
    }
  }
  if (LINE_REFLOW_REDO == lineReflowStatus) {
    // This happens only when we have a line that is impacted by
    // floaters and the first element in the line doesn't fit with
    // the floaters.
    //
    // What we do is to advance past the first floater we find and
    // then reflow the line all over again.
    NS_ASSERTION(aState.IsImpactedByFloater(),
                 "redo line on totally empty line");
    NS_ASSERTION(NS_UNCONSTRAINEDSIZE != aState.mAvailSpaceRect.height,
                 "unconstrained height on totally empty line");
    aState.mY += aState.mAvailSpaceRect.height;
    // XXX: a small optimization can be done here when paginating:
    // if the new Y coordinate is past the end of the block then
    // push the line and return now instead of later on after we are
    // past the floater.
  }
  else {
    // If we are propogating out a break-before status then there is
    // no point in placing the line.
    if (!NS_INLINE_IS_BREAK_BEFORE(aState.mReflowStatus)) {
      rv = PlaceLine(aState, aLineLayout, aLine, aKeepReflowGoing, aUpdateMaximumWidth);
    }
  }
  *aLineReflowStatus = lineReflowStatus;
  return rv;
}
/**
 * Reflow an inline frame. The reflow status is mapped from the frames
 * reflow status to the lines reflow status (not to our reflow status).
 * The line reflow status is simple: PR_TRUE means keep placing frames
 * on the line; PR_FALSE means don't (the line is done). If the line
 * has some sort of breaking affect then aLine's break-type will be set
 * to something other than NS_STYLE_CLEAR_NONE.
 */
nsresult
nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
                                nsLineLayout& aLineLayout,
                                nsLineBox* aLine,
                                nsIFrame* aFrame,
                                PRUint8* aLineReflowStatus)
{
  *aLineReflowStatus = LINE_REFLOW_OK;
  // If it's currently ok to be reflowing in first-letter style then
  // we must be about to reflow a frame that has first-letter style.
  PRBool reflowingFirstLetter = aLineLayout.GetFirstLetterStyleOK();
#ifdef NOISY_FIRST_LETTER
  ListTag(stdout);
  printf(": reflowing ");
  nsFrame::ListTag(stdout, aFrame);
  printf(" reflowingFirstLetter=%s\n", reflowingFirstLetter ? "on" : "off");
#endif
  // Reflow the inline frame
  nsReflowStatus frameReflowStatus;
  PRBool         pushedFrame;
  nsresult rv = aLineLayout.ReflowFrame(aFrame, &aState.mNextRCFrame,
                                        frameReflowStatus, nsnull, pushedFrame);
  if (NS_FAILED(rv)) {
    return rv;
  }
#ifdef REALLY_NOISY_REFLOW_CHILD
  nsFrame::ListTag(stdout, aFrame);
  printf(": status=%x\n", frameReflowStatus);
#endif
#if defined(REFLOW_STATUS_COVERAGE)
  RecordReflowStatus(PR_FALSE, frameReflowStatus);
#endif
  // Send post-reflow notification
  aState.mPrevChild = aFrame;
  // Process the child frames reflow status. There are 5 cases:
  // complete, not-complete, break-before, break-after-complete,
  // break-after-not-complete. There are two situations: we are a
  // block or we are an inline. This makes a total of 10 cases
  // (fortunately, there is some overlap).
  aLine->SetBreakType(NS_STYLE_CLEAR_NONE);
  if (NS_INLINE_IS_BREAK(frameReflowStatus)) {
    // Always abort the line reflow (because a line break is the
    // minimal amount of break we do).
    *aLineReflowStatus = LINE_REFLOW_STOP;
    // XXX what should aLine's break-type be set to in all these cases?
    PRUint8 breakType = NS_INLINE_GET_BREAK_TYPE(frameReflowStatus);
    NS_ASSERTION(breakType != NS_STYLE_CLEAR_NONE, "bad break type");
    NS_ASSERTION(NS_STYLE_CLEAR_PAGE != breakType, "no page breaks yet");
    if (NS_INLINE_IS_BREAK_BEFORE(frameReflowStatus)) {
      // Break-before cases.
      if (aFrame == aLine->mFirstChild) {
        // If we break before the first frame on the line then we must
        // be trying to place content where theres no room (e.g. on a
        // line with wide floaters). Inform the caller to reflow the
        // line after skipping past a floater.
        *aLineReflowStatus = LINE_REFLOW_REDO;
      }
      else {
        // It's not the first child on this line so go ahead and split
        // the line. We will see the frame again on the next-line.
        rv = SplitLine(aState, aLineLayout, aLine, aFrame);
        if (NS_FAILED(rv)) {
          return rv;
        }
        // If we're splitting the line because the frame didn't fit and it
        // was pushed, then mark the line as having word wrapped. We need to
        // know that if we're shrink wrapping our width
        if (pushedFrame) {
          aLine->SetLineWrapped(PR_TRUE);
        }
      }
    }
    else {
      // Break-after cases
      if (breakType == NS_STYLE_CLEAR_LINE) {
        if (!aLineLayout.GetLineEndsInBR()) {
          breakType = NS_STYLE_CLEAR_NONE;
        }
      }
      aLine->SetBreakType(breakType);
      if (NS_FRAME_IS_NOT_COMPLETE(frameReflowStatus)) {
        // Create a continuation for the incomplete frame. Note that the
        // frame may already have a continuation.
        PRBool madeContinuation;
        rv = CreateContinuationFor(aState, aLine, aFrame, madeContinuation);
        if (NS_FAILED(rv)) {
          return rv;
        }
        // Remember that the line has wrapped
        aLine->SetLineWrapped(PR_TRUE);
      }
      // Split line, but after the frame just reflowed
      nsIFrame* nextFrame;
      aFrame->GetNextSibling(&nextFrame);
      rv = SplitLine(aState, aLineLayout, aLine, nextFrame);
      if (NS_FAILED(rv)) {
        return rv;
      }
      // Mark next line dirty in case SplitLine didn't end up
      // pushing any frames.
      nsLineBox* next = aLine->mNext;
      if ((nsnull != next) && !next->IsBlock()) {
        next->MarkDirty();
      }
    }
  }
  else if (NS_FRAME_IS_NOT_COMPLETE(frameReflowStatus)) {
    // Frame is not-complete, no special breaking status
    // Create a continuation for the incomplete frame. Note that the
    // frame may already have a continuation.
    PRBool madeContinuation;
    rv = CreateContinuationFor(aState, aLine, aFrame, madeContinuation);
    if (NS_FAILED(rv)) {
      return rv;
    }
    // Remember that the line has wrapped
    aLine->SetLineWrapped(PR_TRUE);
    
    // If we are reflowing the first letter frame then don't split the
    // line and don't stop the line reflow...
    PRBool splitLine = !reflowingFirstLetter;
    if (reflowingFirstLetter) {
      nsCOMPtr ... ).
  //
  // For this code, only the first case is possible because this
  // method is used for placing a line of inline frames. If the rare
  // case is happening then the worst that will happen is that the
  // bullet frame will be reflowed twice.
  PRBool addedBullet = PR_FALSE;
  if (HaveOutsideBullet() && (aLine == mLines) &&
      (!aLineLayout.IsZeroHeight() || !aLine->mNext)) {
    nsHTMLReflowMetrics metrics(nsnull);
    ReflowBullet(aState, metrics);
    aLineLayout.AddBulletFrame(mBullet, metrics);
    addedBullet = PR_TRUE;
  }
  nsSize maxElementSize;
  aLineLayout.VerticalAlignFrames(aLine->mBounds, maxElementSize);
  // See if we're shrink wrapping the width
  if (aState.mShrinkWrapWidth) {
    // When determining the line's width we also need to include any
    // right floaters that impact us. This represents the shrink wrap
    // width of the line
    if (aState.IsImpactedByFloater() && !aLine->IsLineWrapped()) {
      NS_ASSERTION(aState.mContentArea.width >= aState.mAvailSpaceRect.XMost(), "bad state");
      aLine->mBounds.width += aState.mContentArea.width - aState.mAvailSpaceRect.XMost();
    }
  }
#ifdef DEBUG
	{
		static nscoord lastHeight = 0;
	  if (CRAZY_HEIGHT(aLine->mBounds.y)) {
	  	lastHeight = aLine->mBounds.y;
	  	if (abs(aLine->mBounds.y - lastHeight) > CRAZY_H/10) {
		    nsFrame::ListTag(stdout);
		    printf(": line=%p y=%d line.bounds.height=%d\n",
		           aLine, aLine->mBounds.y, aLine->mBounds.height);
	    }
	  }
	  else {
	  	lastHeight = 0;
	  }
  }
#endif
  // Only block frames horizontally align their children because
  // inline frames "shrink-wrap" around their children (therefore
  // there is no extra horizontal space).
#if XXX_fix_me
  PRBool allowJustify = PR_TRUE;
  if (NS_STYLE_TEXT_ALIGN_JUSTIFY == aState.mStyleText->mTextAlign) {
    allowJustify = ShouldJustifyLine(aState, aLine);
  }
#else
  PRBool allowJustify = PR_FALSE;
#endif
  PRBool successful;
  nsRect combinedArea;
  successful = aLineLayout.HorizontalAlignFrames(aLine->mBounds, allowJustify,
                                                 aState.mShrinkWrapWidth);
  if (!successful) {
    // Mark the line dirty and then later once we've determined the width
    // we can do the horizontal alignment
    aLine->MarkDirty();
    aState.mNeedResizeReflow = PR_TRUE;
  }
  aLineLayout.RelativePositionFrames(combinedArea);
  aLine->SetCombinedArea(combinedArea);
  if (addedBullet) {
    aLineLayout.RemoveBulletFrame(mBullet);
  }
  // Inline lines do not have margins themselves; however they are
  // impacted by prior block margins. If this line ends up having some
  // height then we zero out the previous bottom margin value that was
  // already applied to the line's starting Y coordinate. Otherwise we
  // leave it be so that the previous blocks bottom margin can be
  // collapsed with a block that follows.
  nscoord newY;
  if (aLine->mBounds.height > 0) {
    // This line has some height. Therefore the application of the
    // previous-bottom-margin should stick.
    aState.mPrevBottomMargin = 0;
    newY = aLine->mBounds.YMost();
  }
  else {
    // Don't let the previous-bottom-margin value affect the newY
    // coordinate (it was applied in ReflowInlineFrames speculatively)
    // since the line is empty.
    nscoord dy = -aState.mPrevBottomMargin;
    newY = aState.mY + dy;
    aLine->SlideBy(dy);
  }
  // See if the line fit. If it doesn't we need to push it. Our first
  // line will always fit.
  if ((mLines != aLine) && (newY > aState.mBottomEdge)) {
    // Push this line and all of it's children and anything else that
    // follows to our next-in-flow
    PushLines(aState);
    // Stop reflow and whack the reflow status if reflow hasn't
    // already been stopped.
    if (*aKeepReflowGoing) {
      NS_ASSERTION(NS_FRAME_COMPLETE == aState.mReflowStatus,
                   "lost reflow status");
      aState.mReflowStatus = NS_FRAME_NOT_COMPLETE;
      *aKeepReflowGoing = PR_FALSE;
    }
    return rv;
  }
  aState.mY = newY;
  if (aState.mComputeMaxElementSize) {
#ifdef NOISY_MAX_ELEMENT_SIZE
    IndentBy(stdout, GetDepth());
    if (NS_UNCONSTRAINEDSIZE == aState.mReflowState.availableWidth) {
      printf("PASS1 ");
    }
    ListTag(stdout);
    printf(": line.floaters=%s%s band.floaterCount=%d\n",
           aLine->mFloaters.NotEmpty() ? "yes" : "no",
           aState.mHaveRightFloaters ? "(have right floaters)" : "",
           aState.mBand.GetFloaterCount());
#endif
    if (0 != aState.mBand.GetFloaterCount()) {
      // Add in floater impacts to the lines max-element-size
      ComputeLineMaxElementSize(aState, aLine, &maxElementSize);
    }
  }
  
  // If we're reflowing the line just to get incrementally update the
  // maximum width, then don't post-place the line. It's doing work we
  // don't need, and it will update things like aState.mKidXMost that
  // we don't want updated...
  if (!aUpdateMaximumWidth) {
    PostPlaceLine(aState, aLine, maxElementSize);
  }
  // Add the already placed current-line floaters to the line
  aLine->AppendFloaters(aState.mCurrentLineFloaters);
  // Any below current line floaters to place?
  if (aState.mBelowCurrentLineFloaters.NotEmpty()) {
    // Reflow the below-current-line floaters, then add them to the
    // lines floater list.
    aState.PlaceBelowCurrentLineFloaters(aState.mBelowCurrentLineFloaters);
    aLine->AppendFloaters(aState.mBelowCurrentLineFloaters);
  }
  // When a line has floaters, factor them into the combined-area
  // computations.
  if (aLine->HasFloaters()) {
    // Combine the floater combined area (stored in aState) and the
    // value computed by the line layout code.
    nsRect lineCombinedArea;
    aLine->GetCombinedArea(&lineCombinedArea);
#ifdef NOISY_COMBINED_AREA
    ListTag(stdout);
    printf(": lineCA=%d,%d,%d,%d floaterCA=%d,%d,%d,%d\n",
           lineCombinedArea.x, lineCombinedArea.y,
           lineCombinedArea.width, lineCombinedArea.height,
           aState.mFloaterCombinedArea.x, aState.mFloaterCombinedArea.y,
           aState.mFloaterCombinedArea.width,
           aState.mFloaterCombinedArea.height);
#endif
    CombineRects(aState.mFloaterCombinedArea, lineCombinedArea);
    if (aState.mHaveRightFloaters &&
        (aState.mUnconstrainedWidth || aState.mShrinkWrapWidth)) {
      // We are reflowing in an unconstrained situation or shrink wrapping and
      // have some right floaters. They were placed at the infinite right edge
      // which will cause the combined area to be unusable.
      //
      // To solve this issue, we pretend that the right floaters ended up just
      // past the end of the line. Note that the right floater combined area
      // we computed as we were going will have as its X coordinate the left
      // most edge of all the right floaters. Therefore, to accomplish our goal
      // all we do is set that X value to the lines XMost value.
#ifdef NOISY_COMBINED_AREA
      printf("  ==> rightFloaterCA=%d,%d,%d,%d lineXMost=%d\n",
             aState.mRightFloaterCombinedArea.x,
             aState.mRightFloaterCombinedArea.y,
             aState.mRightFloaterCombinedArea.width,
             aState.mRightFloaterCombinedArea.height,
             aLine->mBounds.XMost());
#endif
      aState.mRightFloaterCombinedArea.x = aLine->mBounds.XMost();
      CombineRects(aState.mRightFloaterCombinedArea, lineCombinedArea);
      if (aState.mShrinkWrapWidth) {
        // Mark the line dirty so we come back and re-place the floater once
        // the shrink wrap width is determined
        aLine->MarkDirty();
        aState.mNeedResizeReflow = PR_TRUE;
      }
    }
    aLine->SetCombinedArea(lineCombinedArea);
#ifdef NOISY_COMBINED_AREA
    printf("  ==> final lineCA=%d,%d,%d,%d\n",
           lineCombinedArea.x, lineCombinedArea.y,
           lineCombinedArea.width, lineCombinedArea.height);
#endif
    aState.mHaveRightFloaters = PR_FALSE;
  }
  // Apply break-after clearing if necessary
  PRUint8 breakType = aLine->GetBreakType();
  switch (breakType) {
  case NS_STYLE_CLEAR_LEFT:
  case NS_STYLE_CLEAR_RIGHT:
  case NS_STYLE_CLEAR_LEFT_AND_RIGHT:
    aState.ClearFloaters(aState.mY, breakType);
    break;
  }
  return rv;
}
// Compute the line's max-element-size by adding into the raw value
// computed by reflowing the contents of the line (aMaxElementSize)
// the impact of floaters on this line or the preceeding lines.
void
nsBlockFrame::ComputeLineMaxElementSize(nsBlockReflowState& aState,
                                        nsLineBox* aLine,
                                        nsSize* aMaxElementSize)
{
  nscoord maxWidth, maxHeight;
  aState.mBand.GetMaxElementSize(aState.mPresContext, &maxWidth, &maxHeight);
#ifdef NOISY_MAX_ELEMENT_SIZE
  IndentBy(stdout, GetDepth());
  if (NS_UNCONSTRAINEDSIZE == aState.mReflowState.availableWidth) {
    printf("PASS1 ");
  }
  ListTag(stdout);
  printf(": maxFloaterSize=%d,%d\n", maxWidth, maxHeight);
#endif
  // If the floaters are wider than the content, then use the maximum
  // floater width as the maximum width.
  //
  // It used to be the case that we would always place some content
  // next to a floater, regardless of the amount of available space
  // after subtracing off the floaters sizes. This can lead to content
  // overlapping floaters, so we no longer do this (and pass CSS2's
  // conformance tests). This is not how navigator 4-1 used to do
  // things.
  if (maxWidth > aMaxElementSize->width) {
    aMaxElementSize->width = maxWidth;
  }
  // Only update the max-element-size's height value if the floater is
  // part of the current line.
  if (aLine->HasFloaters()) {
    // If the maximum-height of the tallest floater is larger than the
    // maximum-height of the content then update the max-element-size
    // height
    if (maxHeight > aMaxElementSize->height) {
      aMaxElementSize->height = maxHeight;
    }
  }
}
void
nsBlockFrame::PostPlaceLine(nsBlockReflowState& aState,
                            nsLineBox* aLine,
                            const nsSize& aMaxElementSize)
{
  // If it's inline elements, then make sure the views are correctly
  // positioned and sized
  if (aLine->IsInline()) {
    nsIFrame* frame = aLine->mFirstChild;
    for (PRInt32 i = 0; i < aLine->GetChildCount(); i++) {
      ::PlaceFrameView(aState.mPresContext, frame);
      frame->GetNextSibling(&frame);
    }
  }
  // Update max-element-size
  if (aState.mComputeMaxElementSize) {
    aState.UpdateMaxElementSize(aMaxElementSize);
    // We also cache the max element width in the line. This is needed for
    // incremental reflow
    aLine->mMaxElementWidth = aMaxElementSize.width;
  }
  // If this is an unconstrained reflow, then cache the line width in the
  // line. We'll need this during incremental reflow if we're asked to
  // calculate the maximum width
  if (aState.mUnconstrainedWidth) {
    aLine->mMaximumWidth = aLine->mBounds.XMost();
  }
  // Update xmost
  nscoord xmost = aLine->mBounds.XMost();
#ifdef DEBUG
  if (CRAZY_WIDTH(xmost)) {
    ListTag(stdout);
    printf(": line=%p xmost=%d\n", aLine, xmost);
  }
#endif
  // If we're shrink wrapping our width and the line was wrapped,
  // then make sure we take up all of the available width
  if (aState.mShrinkWrapWidth && aLine->IsLineWrapped()) {
    aState.mKidXMost = aState.BorderPadding().left + aState.mContentArea.width;
  }
  else if (xmost > aState.mKidXMost) {
    aState.mKidXMost = xmost;
  }
}
void
nsBlockFrame::PushLines(nsBlockReflowState& aState)
{
  NS_ASSERTION(nsnull != aState.mPrevLine, "bad push");
  nsLineBox* lastLine = aState.mPrevLine;
  nsLineBox* nextLine = lastLine->mNext;
  if (nextLine) {
    lastLine->mNext = nsnull;
    SetOverflowLines(aState.mPresContext, nextLine);
  
    // Mark all the overflow lines dirty so that they get reflowed when
    // they are pulled up by our next-in-flow.
    while (nsnull != nextLine) {
      nextLine->MarkDirty();
      nextLine = nextLine->mNext;
    }
  }
  // Break frame sibling list
  nsIFrame* lastFrame = lastLine->LastChild();
  lastFrame->SetNextSibling(nsnull);
#ifdef DEBUG
  VerifyOverflowSituation(aState.mPresContext);
#endif
}
PRBool
nsBlockFrame::DrainOverflowLines(nsIPresContext* aPresContext)
{
#ifdef DEBUG
  VerifyOverflowSituation(aPresContext);
#endif
  PRBool drained = PR_FALSE;
  nsLineBox* overflowLines;
  // First grab the prev-in-flows overflow lines
  nsBlockFrame* prevBlock = (nsBlockFrame*) mPrevInFlow;
  if (nsnull != prevBlock) {
    overflowLines = prevBlock->GetOverflowLines(aPresContext, PR_TRUE);
    if (nsnull != overflowLines) {
      drained = PR_TRUE;
      // Make all the frames on the overflow line list mine
      nsIFrame* lastFrame = nsnull;
      nsIFrame* frame = overflowLines->mFirstChild;
      while (nsnull != frame) {
        frame->SetParent(this);
        // When pushing and pulling frames we need to check for whether any
        // views need to be reparented
        nsHTMLContainerFrame::ReparentFrameView(aPresContext, frame, prevBlock, this);
        // Get the next frame
        lastFrame = frame;
        frame->GetNextSibling(&frame);
      }
      // Join the line lists
      if (nsnull == mLines) {
        mLines = overflowLines;
      }
      else {
        // Join the sibling lists together
        lastFrame->SetNextSibling(mLines->mFirstChild);
        // Place overflow lines at the front of our line list
        nsLineBox* lastLine = nsLineBox::LastLine(overflowLines);
        lastLine->mNext = mLines;
        mLines = overflowLines;
      }
    }
  }
  // Now grab our own overflow lines
  overflowLines = GetOverflowLines(aPresContext, PR_TRUE);
  if (overflowLines) {
    // This can happen when we reflow and not everything fits and then
    // we are told to reflow again before a next-in-flow is created
    // and reflows.
    nsLineBox* lastLine = nsLineBox::LastLine(mLines);
    if (nsnull == lastLine) {
      mLines = overflowLines;
    }
    else {
      lastLine->mNext = overflowLines;
      nsIFrame* lastFrame = lastLine->LastChild();
      lastFrame->SetNextSibling(overflowLines->mFirstChild);
    }
    drained = PR_TRUE;
  }
  return drained;
}
nsLineBox*
nsBlockFrame::GetOverflowLines(nsIPresContext* aPresContext,
                               PRBool          aRemoveProperty)
{
  nsCOMPtr