Exemplo n.º 1
0
/**
 * Attempt to place the block frame within the available space.  If
 * it fits, apply horizontal positioning (CSS 10.3.3), collapse
 * margins (CSS2 8.3.1). Also apply relative positioning.
 */
bool
nsBlockReflowContext::PlaceBlock(const nsHTMLReflowState& aReflowState,
                                 bool                     aForceFit,
                                 nsLineBox*               aLine,
                                 nsCollapsingMargin&      aBottomMarginResult,
                                 nsRect&                  aInFlowBounds,
                                 nsOverflowAreas&         aOverflowAreas,
                                 nsReflowStatus           aReflowStatus)
{
  // Compute collapsed bottom margin value.
  if (NS_FRAME_IS_COMPLETE(aReflowStatus)) {
    aBottomMarginResult = mMetrics.mCarriedOutBottomMargin;
    aBottomMarginResult.Include(aReflowState.ComputedPhysicalMargin().bottom);
  } else {
    // The used bottom-margin is set to zero above a break.
    aBottomMarginResult.Zero();
  }

  nsPoint position(mX, mY);
  nscoord backupContainingBlockAdvance = 0;

  // Check whether the block's bottom margin collapses with its top
  // margin. See CSS 2.1 section 8.3.1; those rules seem to match
  // nsBlockFrame::IsEmpty(). Any such block must have zero height so
  // check that first. Note that a block can have clearance and still
  // have adjoining top/bottom margins, because the clearance goes
  // above the top margin.
  // Mark the frame as non-dirty; it has been reflowed (or we wouldn't
  // be here), and we don't want to assert in CachedIsEmpty()
  mFrame->RemoveStateBits(NS_FRAME_IS_DIRTY);
  bool empty = 0 == mMetrics.Height() && aLine->CachedIsEmpty();
  if (empty) {
    // Collapse the bottom margin with the top margin that was already
    // applied.
    aBottomMarginResult.Include(mTopMargin);

#ifdef NOISY_VERTICAL_MARGINS
    printf("  ");
    nsFrame::ListTag(stdout, mOuterReflowState.frame);
    printf(": ");
    nsFrame::ListTag(stdout, mFrame);
    printf(" -- collapsing top & bottom margin together; y=%d spaceY=%d\n",
           position.y, mSpace.y);
#endif
    // Section 8.3.1 of CSS 2.1 says that blocks with adjoining
    // top/bottom margins whose top margin collapses with their
    // parent's top margin should have their top border-edge at the
    // top border-edge of their parent. We actually don't have to do
    // anything special to make this happen. In that situation,
    // nsBlockFrame::ShouldApplyTopMargin will have returned false,
    // and mTopMargin and aClearance will have been zero in
    // ReflowBlock.

    // If we did apply our top margin, but now we're collapsing it
    // into the bottom margin, we need to back up the containing
    // block's y-advance by our top margin so that it doesn't get
    // counted twice. Note that here we're allowing the line's bounds
    // to become different from the block's position; we do this
    // because the containing block will place the next line at the
    // line's YMost, and it must place the next line at a different
    // point from where this empty block will be.
    backupContainingBlockAdvance = mTopMargin.get();
  }

  // See if the frame fit. If it's the first frame or empty then it
  // always fits. If the height is unconstrained then it always fits,
  // even if there's some sort of integer overflow that makes y +
  // mMetrics.Height() appear to go beyond the available height.
  if (!empty && !aForceFit && mSpace.height != NS_UNCONSTRAINEDSIZE) {
    nscoord yMost = position.y - backupContainingBlockAdvance + mMetrics.Height();
    if (yMost > mSpace.YMost()) {
      // didn't fit, we must acquit.
      mFrame->DidReflow(mPresContext, &aReflowState, nsDidReflowStatus::FINISHED);
      return false;
    }
  }

  aInFlowBounds = nsRect(position.x, position.y - backupContainingBlockAdvance,
                         mMetrics.Width(), mMetrics.Height());
  
  aReflowState.ApplyRelativePositioning(&position);
  
  // Now place the frame and complete the reflow process
  nsContainerFrame::FinishReflowChild(mFrame, mPresContext, mMetrics,
                                      &aReflowState, position.x, position.y, 0);

  aOverflowAreas = mMetrics.mOverflowAreas + position;

  return true;
}
Exemplo n.º 2
0
/**
 * Attempt to place the block frame within the available space.  If
 * it fits, apply inline-dir ("horizontal") positioning (CSS 10.3.3),
 * collapse margins (CSS2 8.3.1). Also apply relative positioning.
 */
bool
nsBlockReflowContext::PlaceBlock(const nsHTMLReflowState&  aReflowState,
                                 bool                      aForceFit,
                                 nsLineBox*                aLine,
                                 nsCollapsingMargin&       aBEndMarginResult,
                                 nsOverflowAreas&          aOverflowAreas,
                                 nsReflowStatus            aReflowStatus)
{
  // Compute collapsed block-end margin value.
  WritingMode wm = aReflowState.GetWritingMode();
  WritingMode parentWM = mMetrics.GetWritingMode();
  if (NS_FRAME_IS_COMPLETE(aReflowStatus)) {
    aBEndMarginResult = mMetrics.mCarriedOutBEndMargin;
    aBEndMarginResult.Include(aReflowState.ComputedLogicalMargin().
      ConvertTo(parentWM, wm).BEnd(parentWM));
  } else {
    // The used block-end-margin is set to zero before a break.
    aBEndMarginResult.Zero();
  }

  nscoord backupContainingBlockAdvance = 0;

  // Check whether the block's block-end margin collapses with its block-start
  // margin. See CSS 2.1 section 8.3.1; those rules seem to match
  // nsBlockFrame::IsEmpty(). Any such block must have zero block-size so
  // check that first. Note that a block can have clearance and still
  // have adjoining block-start/end margins, because the clearance goes
  // above the block-start margin.
  // Mark the frame as non-dirty; it has been reflowed (or we wouldn't
  // be here), and we don't want to assert in CachedIsEmpty()
  mFrame->RemoveStateBits(NS_FRAME_IS_DIRTY);
  bool empty = 0 == mMetrics.BSize(parentWM) && aLine->CachedIsEmpty();
  if (empty) {
    // Collapse the block-end margin with the block-start margin that was
    // already applied.
    aBEndMarginResult.Include(mBStartMargin);

#ifdef NOISY_BLOCKDIR_MARGINS
    printf("  ");
    nsFrame::ListTag(stdout, mOuterReflowState.frame);
    printf(": ");
    nsFrame::ListTag(stdout, mFrame);
    printf(" -- collapsing block start & end margin together; BStart=%d spaceBStart=%d\n",
           mBCoord, mSpace.BStart(mWritingMode));
#endif
    // Section 8.3.1 of CSS 2.1 says that blocks with adjoining
    // "top/bottom" (i.e. block-start/end) margins whose top margin collapses
    // with their parent's top margin should have their top border-edge at the
    // top border-edge of their parent. We actually don't have to do
    // anything special to make this happen. In that situation,
    // nsBlockFrame::ShouldApplyBStartMargin will have returned false,
    // and mBStartMargin and aClearance will have been zero in
    // ReflowBlock.

    // If we did apply our block-start margin, but now we're collapsing it
    // into the block-end margin, we need to back up the containing
    // block's bCoord-advance by our block-start margin so that it doesn't get
    // counted twice. Note that here we're allowing the line's bounds
    // to become different from the block's position; we do this
    // because the containing block will place the next line at the
    // line's BEnd, and it must place the next line at a different
    // point from where this empty block will be.
    backupContainingBlockAdvance = mBStartMargin.get();
  }

  // See if the frame fit. If it's the first frame or empty then it
  // always fits. If the block-size is unconstrained then it always fits,
  // even if there's some sort of integer overflow that makes bCoord +
  // mMetrics.BSize() appear to go beyond the available block size.
  if (!empty && !aForceFit &&
      mSpace.BSize(mWritingMode) != NS_UNCONSTRAINEDSIZE) {
    nscoord bEnd = mBCoord -
                   backupContainingBlockAdvance + mMetrics.BSize(mWritingMode);
    if (bEnd > mSpace.BEnd(mWritingMode)) {
      // didn't fit, we must acquit.
      mFrame->DidReflow(mPresContext, &aReflowState,
                        nsDidReflowStatus::FINISHED);
      return false;
    }
  }

  aLine->SetBounds(mWritingMode,
                   mICoord, mBCoord - backupContainingBlockAdvance,
                   mMetrics.ISize(mWritingMode), mMetrics.BSize(mWritingMode),
                   mContainerSize);

  WritingMode frameWM = mFrame->GetWritingMode();
  LogicalPoint logPos =
    LogicalPoint(mWritingMode, mICoord, mBCoord).
      ConvertTo(frameWM, mWritingMode,
                mContainerSize - mMetrics.PhysicalSize());

  // ApplyRelativePositioning in right-to-left writing modes needs to
  // know the updated frame width
  mFrame->SetSize(mWritingMode, mMetrics.Size(mWritingMode));
  aReflowState.ApplyRelativePositioning(&logPos, mContainerSize);

  // Now place the frame and complete the reflow process
  nsContainerFrame::FinishReflowChild(mFrame, mPresContext, mMetrics,
                                      &aReflowState, frameWM, logPos,
                                      mContainerSize, 0);

  aOverflowAreas = mMetrics.mOverflowAreas + mFrame->GetPosition();

  return true;
}