Example #1
0
// XXXldb This behavior doesn't quite fit with CSS1 and CSS2 --
// technically we're supposed let the current line flow around the
// float as well unless it won't fit next to what we already have.
// But nobody else implements it that way...
PRBool
nsBlockReflowState::AddFloat(nsLineLayout&       aLineLayout,
                             nsPlaceholderFrame* aPlaceholder,
                             PRBool              aInitialReflow,
                             nsReflowStatus&     aReflowStatus)
{
  NS_PRECONDITION(mBlock->end_lines() != mCurrentLine, "null ptr");

  aReflowStatus = NS_FRAME_COMPLETE;
  // Allocate a nsFloatCache for the float
  nsFloatCache* fc = mFloatCacheFreeList.Alloc();
  fc->mPlaceholder = aPlaceholder;

  PRBool placed;

  // Now place the float immediately if possible. Otherwise stash it
  // away in mPendingFloats and place it later.
  if (aLineLayout.CanPlaceFloatNow()) {
    // Because we are in the middle of reflowing a placeholder frame
    // within a line (and possibly nested in an inline frame or two
    // that's a child of our block) we need to restore the space
    // manager's translation to the space that the block resides in
    // before placing the float.
    nscoord ox, oy;
    mSpaceManager->GetTranslation(ox, oy);
    nscoord dx = ox - mSpaceManagerX;
    nscoord dy = oy - mSpaceManagerY;
    mSpaceManager->Translate(-dx, -dy);

    // And then place it
    PRBool isLeftFloat;
    // force it to fit if we're at the top of the block and we can't
    // break before this
    PRBool forceFit = IsAdjacentWithTop() && !aLineLayout.LineIsBreakable();
    placed = FlowAndPlaceFloat(fc, &isLeftFloat, aReflowStatus, forceFit);
    NS_ASSERTION(placed || !forceFit,
                 "If we asked for force-fit, it should have been placed");
    if (forceFit || (placed && !NS_FRAME_IS_TRUNCATED(aReflowStatus))) {
      // Pass on updated available space to the current inline reflow engine
      GetAvailableSpace(mY, forceFit);
      aLineLayout.UpdateBand(mAvailSpaceRect.x + BorderPadding().left, mY,
                             mAvailSpaceRect.width,
                             mAvailSpaceRect.height,
                             isLeftFloat,
                             aPlaceholder->GetOutOfFlowFrame());
      
      // Record this float in the current-line list
      mCurrentLineFloats.Append(fc);
      // If we can't break here, hide the fact that it's truncated
      // XXX We can probably do this more cleanly
      aReflowStatus &= ~NS_FRAME_TRUNCATED;
    }
    else {
      if (IsAdjacentWithTop()) {
        // Pushing the line to the next page won't give us any more space;
        // therefore, we break.
        NS_ASSERTION(aLineLayout.LineIsBreakable(),
                     "We can't get here unless forceFit is false");
        aReflowStatus = NS_INLINE_LINE_BREAK_BEFORE();
      } else {
        // Make sure we propagate the truncated status; this signals the
        // block to push the line to the next page.
        aReflowStatus |= NS_FRAME_TRUNCATED;
      }
      delete fc;
    }

    // Restore coordinate system
    mSpaceManager->Translate(dx, dy);
  }
  else {
    // Always claim to be placed; we don't know whether we fit yet, so we
    // deal with this in PlaceBelowCurrentLineFloats
    placed = PR_TRUE;
    // This float will be placed after the line is done (it is a
    // below-current-line float).
    mBelowCurrentLineFloats.Append(fc);
    if (aPlaceholder->GetNextInFlow()) {
      // If the float might not be complete, mark it incomplete now to
      // prevent its next-in-flow placeholders being torn down. We will destroy any
      // placeholders later if PlaceBelowCurrentLineFloats finds the
      // float is complete.
      // Note that we could have unconstrained height and yet have
      // a next-in-flow placeholder --- for example columns can switch
      // from constrained height to unconstrained height.
      if (aPlaceholder->GetSplittableType() != NS_FRAME_NOT_SPLITTABLE) {
        aReflowStatus = NS_FRAME_NOT_COMPLETE;
      }
    }
  }
  return placed;
}
// XXXldb This behavior doesn't quite fit with CSS1 and CSS2 --
// technically we're supposed let the current line flow around the
// float as well unless it won't fit next to what we already have.
// But nobody else implements it that way...
PRBool
nsBlockReflowState::AddFloat(nsLineLayout*       aLineLayout,
                             nsIFrame*           aFloat,
                             nscoord             aAvailableWidth,
                             nsReflowStatus&     aReflowStatus)
{
  NS_PRECONDITION(!aLineLayout || mBlock->end_lines() != mCurrentLine, "null ptr");
  NS_PRECONDITION(aFloat->GetStateBits() & NS_FRAME_OUT_OF_FLOW,
                  "aFloat must be an out-of-flow frame");

  // Set the geometric parent of the float
  aFloat->SetParent(mBlock);

  aReflowStatus = NS_FRAME_COMPLETE;

  // Because we are in the middle of reflowing a placeholder frame
  // within a line (and possibly nested in an inline frame or two
  // that's a child of our block) we need to restore the space
  // manager's translation to the space that the block resides in
  // before placing the float.
  nscoord ox, oy;
  mFloatManager->GetTranslation(ox, oy);
  nscoord dx = ox - mFloatManagerX;
  nscoord dy = oy - mFloatManagerY;
  mFloatManager->Translate(-dx, -dy);

  PRBool placed;

  // Now place the float immediately if possible. Otherwise stash it
  // away in mPendingFloats and place it later.
  // If one or more floats has already been pushed to the next line,
  // don't let this one go on the current line, since that would violate
  // float ordering.
  nsRect floatAvailableSpace = GetFloatAvailableSpace().mRect;
  if (!aLineLayout ||
      (mBelowCurrentLineFloats.IsEmpty() &&
       (aLineLayout->LineIsEmpty() ||
        mBlock->ComputeFloatWidth(*this, floatAvailableSpace, aFloat)
        <= aAvailableWidth))) {
    // And then place it
    // force it to fit if we're at the top of the block and we can't
    // break before this
    PRBool forceFit = !aLineLayout ||
                      (IsAdjacentWithTop() && !aLineLayout->LineIsBreakable());
    placed = FlowAndPlaceFloat(aFloat, aReflowStatus, forceFit);
    NS_ASSERTION(placed || !forceFit,
                 "If we asked for force-fit, it should have been placed");
    if (forceFit || (placed && !NS_FRAME_IS_TRUNCATED(aReflowStatus))) {
      // Pass on updated available space to the current inline reflow engine
      nsFlowAreaRect floatAvailSpace =
        GetFloatAvailableSpace(mY, forceFit);
      nsRect availSpace(nsPoint(floatAvailSpace.mRect.x + BorderPadding().left,
                                mY),
                        floatAvailSpace.mRect.Size());
      if (aLineLayout) {
        aLineLayout->UpdateBand(availSpace, aFloat);
        // Record this float in the current-line list
        mCurrentLineFloats.Append(mFloatCacheFreeList.Alloc(aFloat));
      }
      // If we can't break here, hide the fact that it's truncated
      // XXX We can probably do this more cleanly
      aReflowStatus &= ~NS_FRAME_TRUNCATED;
    }
    else {
      if (IsAdjacentWithTop()) {
        // Pushing the line to the next page won't give us any more space;
        // therefore, we break.
        NS_ASSERTION(aLineLayout->LineIsBreakable(),
                     "We can't get here unless forceFit is false");
        aReflowStatus = NS_INLINE_LINE_BREAK_BEFORE();
      } else {
        // Make sure we propagate the truncated status; this signals the
        // block to push the line to the next page.
        aReflowStatus |= NS_FRAME_TRUNCATED;
      }
    }
  }
  else {
    // Always claim to be placed; we don't know whether we fit yet, so we
    // deal with this in PlaceBelowCurrentLineFloats
    placed = PR_TRUE;
    // This float will be placed after the line is done (it is a
    // below-current-line float).
    mBelowCurrentLineFloats.Append(mFloatCacheFreeList.Alloc(aFloat));
  }

  // Restore coordinate system
  mFloatManager->Translate(dx, dy);

  return placed;
}