LCOV - app.info - layout/generic/nsBlockReflowContext.cpp

LCOV - code coverage report
| Current view: | directory - layout/generic - nsBlockReflowContext.cpp (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 140 | 0 | 0.0 %
| Date: | 2012-04-21 | Functions: | 5 | 0 | 0.0 %

           1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
           2                 : // vim:cindent:ts=2:et:sw=2:
           3                 : /* ***** BEGIN LICENSE BLOCK *****
           4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
           5                 :  *
           6                 :  * The contents of this file are subject to the Mozilla Public License Version
           7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
           8                 :  * the License. You may obtain a copy of the License at
           9                 :  * http://www.mozilla.org/MPL/
          10                 :  *
          11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
          12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
          13                 :  * for the specific language governing rights and limitations under the
          14                 :  * License.
          15                 :  *
          16                 :  * The Original Code is Mozilla Communicator client code.
          17                 :  *
          18                 :  * The Initial Developer of the Original Code is
          19                 :  * Netscape Communications Corporation.
          20                 :  * Portions created by the Initial Developer are Copyright (C) 1998
          21                 :  * the Initial Developer. All Rights Reserved.
          22                 :  *
          23                 :  * Contributor(s):
          24                 :  *   David Baron <dbaron@dbaron.org>
          25                 :  *
          26                 :  * Alternatively, the contents of this file may be used under the terms of
          27                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
          28                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
          29                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
          30                 :  * of those above. If you wish to allow use of your version of this file only
          31                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
          32                 :  * use your version of this file under the terms of the MPL, indicate your
          33                 :  * decision by deleting the provisions above and replace them with the notice
          34                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
          35                 :  * the provisions above, a recipient may use your version of this file under
          36                 :  * the terms of any one of the MPL, the GPL or the LGPL.
          37                 :  *
          38                 :  * ***** END LICENSE BLOCK ***** */
          39                 :
          40                 : /* class that a parent frame uses to reflow a block frame */
          41                 :
          42                 : #include "nsBlockReflowContext.h"
          43                 : #include "nsLineLayout.h"
          44                 : #include "nsFloatManager.h"
          45                 : #include "nsPresContext.h"
          46                 : #include "nsFrameManager.h"
          47                 : #include "nsIContent.h"
          48                 : #include "nsStyleContext.h"
          49                 : #include "nsContainerFrame.h"
          50                 : #include "nsBlockFrame.h"
          51                 : #include "nsLineBox.h"
          52                 : #include "nsIDOMHTMLTableCellElement.h"
          53                 : #include "nsIDOMHTMLBodyElement.h"
          54                 : #include "nsGkAtoms.h"
          55                 : #include "nsCOMPtr.h"
          56                 : #include "nsLayoutUtils.h"
          57                 :
          58                 : #ifdef NS_DEBUG
          59                 : #undef  NOISY_MAX_ELEMENT_SIZE
          60                 : #undef   REALLY_NOISY_MAX_ELEMENT_SIZE
          61                 : #undef  NOISY_VERTICAL_MARGINS
          62                 : #else
          63                 : #undef  NOISY_MAX_ELEMENT_SIZE
          64                 : #undef   REALLY_NOISY_MAX_ELEMENT_SIZE
          65                 : #undef  NOISY_VERTICAL_MARGINS
          66                 : #endif
          67                 :
          68               0 : nsBlockReflowContext::nsBlockReflowContext(nsPresContext* aPresContext,
          69                 :                                            const nsHTMLReflowState& aParentRS)
          70                 :   : mPresContext(aPresContext),
          71                 :     mOuterReflowState(aParentRS),
          72               0 :     mMetrics()
          73                 : {
          74               0 : }
          75                 :
          76               0 : static nsIFrame* DescendIntoBlockLevelFrame(nsIFrame* aFrame)
          77                 : {
          78               0 :   nsIAtom* type = aFrame->GetType();
          79               0 :   if (type == nsGkAtoms::columnSetFrame)
          80               0 :     return DescendIntoBlockLevelFrame(aFrame->GetFirstPrincipalChild());
          81               0 :   return aFrame;
          82                 : }
          83                 :
          84                 : bool
          85               0 : nsBlockReflowContext::ComputeCollapsedTopMargin(const nsHTMLReflowState& aRS,
          86                 :   nsCollapsingMargin* aMargin, nsIFrame* aClearanceFrame,
          87                 :   bool* aMayNeedRetry, bool* aBlockIsEmpty)
          88                 : {
          89                 :   // Include frame's top margin
          90               0 :   aMargin->Include(aRS.mComputedMargin.top);
          91                 :
          92                 :   // The inclusion of the bottom margin when empty is done by the caller
          93                 :   // since it doesn't need to be done by the top-level (non-recursive)
          94                 :   // caller.
          95                 :
          96                 : #ifdef NOISY_VERTICAL_MARGINS
          97                 :   nsFrame::ListTag(stdout, aRS.frame);
          98                 :   printf(": %d => %d\n", aRS.mComputedMargin.top, aMargin->get());
          99                 : #endif
         100                 :
         101               0 :   bool dirtiedLine = false;
         102               0 :   bool setBlockIsEmpty = false;
         103                 :
         104                 :   // Calculate the frame's generational top-margin from its child
         105                 :   // blocks. Note that if the frame has a non-zero top-border or
         106                 :   // top-padding then this step is skipped because it will be a margin
         107                 :   // root.  It is also skipped if the frame is a margin root for other
         108                 :   // reasons.
         109               0 :   nsIFrame* frame = DescendIntoBlockLevelFrame(aRS.frame);
         110               0 :   nsPresContext* prescontext = frame->PresContext();
         111               0 :   if (0 == aRS.mComputedBorderPadding.top &&
         112               0 :       nsLayoutUtils::GetAsBlock(frame) &&
         113               0 :       !nsBlockFrame::BlockIsMarginRoot(frame)) {
         114                 :     // iterate not just through the lines of 'block' but also its
         115                 :     // overflow lines and the normal and overflow lines of its next in
         116                 :     // flows. Note that this will traverse some frames more than once:
         117                 :     // for example, if A contains B and A->nextinflow contains
         118                 :     // B->nextinflow, we'll traverse B->nextinflow twice. But this is
         119                 :     // OK because our traversal is idempotent.
         120               0 :     for (nsBlockFrame* block = static_cast<nsBlockFrame*>(frame);
         121               0 :          block; block = static_cast<nsBlockFrame*>(block->GetNextInFlow())) {
         122               0 :       for (PRIntn overflowLines = false; overflowLines <= true; ++overflowLines) {
         123               0 :         nsBlockFrame::line_iterator line;
         124               0 :         nsBlockFrame::line_iterator line_end;
         125               0 :         bool anyLines = true;
         126               0 :         if (overflowLines) {
         127               0 :           nsBlockFrame::FrameLines* frames = block->GetOverflowLines();
         128               0 :           nsLineList* lines = frames ? &frames->mLines : nsnull;
         129               0 :           if (!lines) {
         130               0 :             anyLines = false;
         131                 :           } else {
         132               0 :             line = lines->begin();
         133               0 :             line_end = lines->end();
         134                 :           }
         135                 :         } else {
         136               0 :           line = block->begin_lines();
         137               0 :           line_end = block->end_lines();
         138                 :         }
         139               0 :         for (; anyLines && line != line_end; ++line) {
         140               0 :           if (!aClearanceFrame && line->HasClearance()) {
         141                 :             // If we don't have a clearance frame, then we're computing
         142                 :             // the collapsed margin in the first pass, assuming that all
         143                 :             // lines have no clearance. So clear their clearance flags.
         144               0 :             line->ClearHasClearance();
         145               0 :             line->MarkDirty();
         146               0 :             dirtiedLine = true;
         147                 :           }
         148                 :
         149                 :           bool isEmpty;
         150               0 :           if (line->IsInline()) {
         151               0 :             isEmpty = line->IsEmpty();
         152                 :           } else {
         153               0 :             nsIFrame* kid = line->mFirstChild;
         154               0 :             if (kid == aClearanceFrame) {
         155               0 :               line->SetHasClearance();
         156               0 :               line->MarkDirty();
         157               0 :               dirtiedLine = true;
         158               0 :               goto done;
         159                 :             }
         160                 :             // Here is where we recur. Now that we have determined that a
         161                 :             // generational collapse is required we need to compute the
         162                 :             // child blocks margin and so in so that we can look into
         163                 :             // it. For its margins to be computed we need to have a reflow
         164                 :             // state for it.
         165                 :
         166                 :             // We may have to construct an extra reflow state here if
         167                 :             // we drilled down through a block wrapper. At the moment
         168                 :             // we can only drill down one level so we only have to support
         169                 :             // one extra reflow state.
         170               0 :             const nsHTMLReflowState* outerReflowState = &aRS;
         171               0 :             if (frame != aRS.frame) {
         172               0 :               NS_ASSERTION(frame->GetParent() == aRS.frame,
         173                 :                            "Can only drill through one level of block wrapper");
         174               0 :               nsSize availSpace(aRS.ComputedWidth(), aRS.ComputedHeight());
         175                 :               outerReflowState = new nsHTMLReflowState(prescontext,
         176               0 :                                                        aRS, frame, availSpace);
         177                 :             }
         178                 :             {
         179                 :               nsSize availSpace(outerReflowState->ComputedWidth(),
         180               0 :                                 outerReflowState->ComputedHeight());
         181                 :               nsHTMLReflowState innerReflowState(prescontext,
         182                 :                                                  *outerReflowState, kid,
         183               0 :                                                  availSpace);
         184                 :               // Record that we're being optimistic by assuming the kid
         185                 :               // has no clearance
         186               0 :               if (kid->GetStyleDisplay()->mBreakType != NS_STYLE_CLEAR_NONE) {
         187               0 :                 *aMayNeedRetry = true;
         188                 :               }
         189               0 :               if (ComputeCollapsedTopMargin(innerReflowState, aMargin, aClearanceFrame, aMayNeedRetry, &isEmpty)) {
         190               0 :                 line->MarkDirty();
         191               0 :                 dirtiedLine = true;
         192                 :               }
         193               0 :               if (isEmpty)
         194               0 :                 aMargin->Include(innerReflowState.mComputedMargin.bottom);
         195                 :             }
         196               0 :             if (outerReflowState != &aRS) {
         197               0 :               delete const_cast<nsHTMLReflowState*>(outerReflowState);
         198                 :             }
         199                 :           }
         200               0 :           if (!isEmpty) {
         201               0 :             if (!setBlockIsEmpty && aBlockIsEmpty) {
         202               0 :               setBlockIsEmpty = true;
         203               0 :               *aBlockIsEmpty = false;
         204                 :             }
         205               0 :             goto done;
         206                 :           }
         207                 :         }
         208               0 :         if (!setBlockIsEmpty && aBlockIsEmpty) {
         209                 :           // The first time we reach here is when this is the first block
         210                 :           // and we have processed all its normal lines.
         211               0 :           setBlockIsEmpty = true;
         212                 :           // All lines are empty, or we wouldn't be here!
         213               0 :           *aBlockIsEmpty = aRS.frame->IsSelfEmpty();
         214                 :         }
         215                 :       }
         216                 :     }
         217                 :   done:
         218                 :     ;
         219                 :   }
         220                 :
         221               0 :   if (!setBlockIsEmpty && aBlockIsEmpty) {
         222               0 :     *aBlockIsEmpty = aRS.frame->IsEmpty();
         223                 :   }
         224                 :
         225                 : #ifdef NOISY_VERTICAL_MARGINS
         226                 :   nsFrame::ListTag(stdout, aRS.frame);
         227                 :   printf(": => %d\n", aMargin->get());
         228                 : #endif
         229                 :
         230               0 :   return dirtiedLine;
         231                 : }
         232                 :
         233                 : nsresult
         234               0 : nsBlockReflowContext::ReflowBlock(const nsRect&       aSpace,
         235                 :                                   bool                aApplyTopMargin,
         236                 :                                   nsCollapsingMargin& aPrevMargin,
         237                 :                                   nscoord             aClearance,
         238                 :                                   bool                aIsAdjacentWithTop,
         239                 :                                   nsLineBox*          aLine,
         240                 :                                   nsHTMLReflowState&  aFrameRS,
         241                 :                                   nsReflowStatus&     aFrameReflowStatus,
         242                 :                                   nsBlockReflowState& aState)
         243                 : {
         244               0 :   nsresult rv = NS_OK;
         245               0 :   mFrame = aFrameRS.frame;
         246               0 :   mSpace = aSpace;
         247                 :
         248               0 :   if (!aIsAdjacentWithTop) {
         249               0 :     aFrameRS.mFlags.mIsTopOfPage = false;  // make sure this is cleared
         250                 :   }
         251                 :
         252               0 :   if (aApplyTopMargin) {
         253               0 :     mTopMargin = aPrevMargin;
         254                 :
         255                 : #ifdef NOISY_VERTICAL_MARGINS
         256                 :     nsFrame::ListTag(stdout, mOuterReflowState.frame);
         257                 :     printf(": reflowing ");
         258                 :     nsFrame::ListTag(stdout, mFrame);
         259                 :     printf(" margin => %d, clearance => %d\n", mTopMargin.get(), aClearance);
         260                 : #endif
         261                 :
         262                 :     // Adjust the available height if its constrained so that the
         263                 :     // child frame doesn't think it can reflow into its margin area.
         264               0 :     if (NS_UNCONSTRAINEDSIZE != aFrameRS.availableHeight) {
         265               0 :       aFrameRS.availableHeight -= mTopMargin.get() + aClearance;
         266                 :     }
         267                 :   }
         268                 :
         269               0 :   nscoord tx = 0, ty = 0;
         270                 :   // The values of x and y do not matter for floats, so don't bother calculating
         271                 :   // them. Floats are guaranteed to have their own float manager, so tx and ty
         272                 :   // don't matter.  mX and mY don't matter becacuse they are only used in
         273                 :   // PlaceBlock, which is not used for floats.
         274               0 :   if (aLine) {
         275                 :     // Compute x/y coordinate where reflow will begin. Use the rules
         276                 :     // from 10.3.3 to determine what to apply. At this point in the
         277                 :     // reflow auto left/right margins will have a zero value.
         278                 :
         279               0 :     mX = tx = mSpace.x + aFrameRS.mComputedMargin.left;
         280               0 :     mY = ty = mSpace.y + mTopMargin.get() + aClearance;
         281                 :
         282               0 :     if ((mFrame->GetStateBits() & NS_BLOCK_FLOAT_MGR) == 0)
         283               0 :       aFrameRS.mBlockDelta = mOuterReflowState.mBlockDelta + ty - aLine->mBounds.y;
         284                 :   }
         285                 :
         286                 :   // Let frame know that we are reflowing it
         287               0 :   mFrame->WillReflow(mPresContext);
         288                 :
         289                 : #ifdef DEBUG
         290               0 :   mMetrics.width = nscoord(0xdeadbeef);
         291               0 :   mMetrics.height = nscoord(0xdeadbeef);
         292                 : #endif
         293                 :
         294               0 :   mOuterReflowState.mFloatManager->Translate(tx, ty);
         295               0 :   rv = mFrame->Reflow(mPresContext, mMetrics, aFrameRS, aFrameReflowStatus);
         296               0 :   mOuterReflowState.mFloatManager->Translate(-tx, -ty);
         297                 :
         298                 : #ifdef DEBUG
         299               0 :   if (!NS_INLINE_IS_BREAK_BEFORE(aFrameReflowStatus)) {
         300               0 :     if (CRAZY_WIDTH(mMetrics.width) || CRAZY_HEIGHT(mMetrics.height)) {
         301               0 :       printf("nsBlockReflowContext: ");
         302               0 :       nsFrame::ListTag(stdout, mFrame);
         303               0 :       printf(" metrics=%d,%d!\n", mMetrics.width, mMetrics.height);
         304                 :     }
         305               0 :     if ((mMetrics.width == nscoord(0xdeadbeef)) ||
         306                 :         (mMetrics.height == nscoord(0xdeadbeef))) {
         307               0 :       printf("nsBlockReflowContext: ");
         308               0 :       nsFrame::ListTag(stdout, mFrame);
         309               0 :       printf(" didn't set w/h %d,%d!\n", mMetrics.width, mMetrics.height);
         310                 :     }
         311                 :   }
         312                 : #endif
         313                 :
         314               0 :   if (!mFrame->HasOverflowAreas()) {
         315               0 :     mMetrics.SetOverflowAreasToDesiredBounds();
         316                 :   }
         317                 :
         318               0 :   if (!NS_INLINE_IS_BREAK_BEFORE(aFrameReflowStatus) ||
         319               0 :       (mFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
         320                 :     // If frame is complete and has a next-in-flow, we need to delete
         321                 :     // them now. Do not do this when a break-before is signaled because
         322                 :     // the frame is going to get reflowed again (and may end up wanting
         323                 :     // a next-in-flow where it ends up), unless it is an out of flow frame.
         324               0 :     if (NS_FRAME_IS_FULLY_COMPLETE(aFrameReflowStatus)) {
         325               0 :       nsIFrame* kidNextInFlow = mFrame->GetNextInFlow();
         326               0 :       if (nsnull != kidNextInFlow) {
         327                 :         // Remove all of the childs next-in-flows. Make sure that we ask
         328                 :         // the right parent to do the removal (it's possible that the
         329                 :         // parent is not this because we are executing pullup code).
         330                 :         // Floats will eventually be removed via nsBlockFrame::RemoveFloat
         331                 :         // which detaches the placeholder from the float.
         332                 : /* XXX promote DeleteChildsNextInFlow to nsIFrame to elminate this cast */
         333               0 :         aState.mOverflowTracker->Finish(mFrame);
         334               0 :         static_cast<nsContainerFrame*>(kidNextInFlow->GetParent())
         335               0 :           ->DeleteNextInFlowChild(mPresContext, kidNextInFlow, true);
         336                 :       }
         337                 :     }
         338                 :   }
         339                 :
         340               0 :   return rv;
         341                 : }
         342                 :
         343                 : /**
         344                 :  * Attempt to place the block frame within the available space.  If
         345                 :  * it fits, apply horizontal positioning (CSS 10.3.3), collapse
         346                 :  * margins (CSS2 8.3.1). Also apply relative positioning.
         347                 :  */
         348                 : bool
         349               0 : nsBlockReflowContext::PlaceBlock(const nsHTMLReflowState& aReflowState,
         350                 :                                  bool                     aForceFit,
         351                 :                                  nsLineBox*               aLine,
         352                 :                                  nsCollapsingMargin&      aBottomMarginResult,
         353                 :                                  nsRect&                  aInFlowBounds,
         354                 :                                  nsOverflowAreas&         aOverflowAreas,
         355                 :                                  nsReflowStatus           aReflowStatus)
         356                 : {
         357                 :   // Compute collapsed bottom margin value.
         358               0 :   if (NS_FRAME_IS_COMPLETE(aReflowStatus)) {
         359               0 :     aBottomMarginResult = mMetrics.mCarriedOutBottomMargin;
         360               0 :     aBottomMarginResult.Include(aReflowState.mComputedMargin.bottom);
         361                 :   } else {
         362                 :     // The used bottom-margin is set to zero above a break.
         363               0 :     aBottomMarginResult.Zero();
         364                 :   }
         365                 :
         366               0 :   nscoord x = mX;
         367               0 :   nscoord y = mY;
         368               0 :   nscoord backupContainingBlockAdvance = 0;
         369                 :
         370                 :   // Check whether the block's bottom margin collapses with its top
         371                 :   // margin. See CSS 2.1 section 8.3.1; those rules seem to match
         372                 :   // nsBlockFrame::IsEmpty(). Any such block must have zero height so
         373                 :   // check that first. Note that a block can have clearance and still
         374                 :   // have adjoining top/bottom margins, because the clearance goes
         375                 :   // above the top margin.
         376                 :   // Mark the frame as non-dirty; it has been reflowed (or we wouldn't
         377                 :   // be here), and we don't want to assert in CachedIsEmpty()
         378               0 :   mFrame->RemoveStateBits(NS_FRAME_IS_DIRTY);
         379               0 :   bool empty = 0 == mMetrics.height && aLine->CachedIsEmpty();
         380               0 :   if (empty) {
         381                 :     // Collapse the bottom margin with the top margin that was already
         382                 :     // applied.
         383               0 :     aBottomMarginResult.Include(mTopMargin);
         384                 :
         385                 : #ifdef NOISY_VERTICAL_MARGINS
         386                 :     printf("  ");
         387                 :     nsFrame::ListTag(stdout, mOuterReflowState.frame);
         388                 :     printf(": ");
         389                 :     nsFrame::ListTag(stdout, mFrame);
         390                 :     printf(" -- collapsing top & bottom margin together; y=%d spaceY=%d\n",
         391                 :            y, mSpace.y);
         392                 : #endif
         393                 :     // Section 8.3.1 of CSS 2.1 says that blocks with adjoining
         394                 :     // top/bottom margins whose top margin collapses with their
         395                 :     // parent's top margin should have their top border-edge at the
         396                 :     // top border-edge of their parent. We actually don't have to do
         397                 :     // anything special to make this happen. In that situation,
         398                 :     // nsBlockFrame::ShouldApplyTopMargin will have returned false,
         399                 :     // and mTopMargin and aClearance will have been zero in
         400                 :     // ReflowBlock.
         401                 :
         402                 :     // If we did apply our top margin, but now we're collapsing it
         403                 :     // into the bottom margin, we need to back up the containing
         404                 :     // block's y-advance by our top margin so that it doesn't get
         405                 :     // counted twice. Note that here we're allowing the line's bounds
         406                 :     // to become different from the block's position; we do this
         407                 :     // because the containing block will place the next line at the
         408                 :     // line's YMost, and it must place the next line at a different
         409                 :     // point from where this empty block will be.
         410               0 :     backupContainingBlockAdvance = mTopMargin.get();
         411                 :   }
         412                 :
         413                 :   // See if the frame fit. If it's the first frame or empty then it
         414                 :   // always fits. If the height is unconstrained then it always fits,
         415                 :   // even if there's some sort of integer overflow that makes y +
         416                 :   // mMetrics.height appear to go beyond the available height.
         417               0 :   if (!empty && !aForceFit && mSpace.height != NS_UNCONSTRAINEDSIZE) {
         418               0 :     nscoord yMost = y - backupContainingBlockAdvance + mMetrics.height;
         419               0 :     if (yMost > mSpace.YMost()) {
         420                 :       // didn't fit, we must acquit.
         421               0 :       mFrame->DidReflow(mPresContext, &aReflowState, NS_FRAME_REFLOW_FINISHED);
         422               0 :       return false;
         423                 :     }
         424                 :   }
         425                 :
         426                 :   aInFlowBounds = nsRect(x, y - backupContainingBlockAdvance,
         427               0 :                          mMetrics.width, mMetrics.height);
         428                 :
         429                 :   // Apply CSS relative positioning
         430               0 :   const nsStyleDisplay* styleDisp = mFrame->GetStyleDisplay();
         431               0 :   if (NS_STYLE_POSITION_RELATIVE == styleDisp->mPosition) {
         432               0 :     x += aReflowState.mComputedOffsets.left;
         433               0 :     y += aReflowState.mComputedOffsets.top;
         434                 :   }
         435                 :
         436                 :   // Now place the frame and complete the reflow process
         437               0 :   nsContainerFrame::FinishReflowChild(mFrame, mPresContext, &aReflowState, mMetrics, x, y, 0);
         438                 :
         439               0 :   aOverflowAreas = mMetrics.mOverflowAreas + nsPoint(x, y);
         440                 :
         441               0 :   return true;
         442                 : }

Generated by: LCOV version 1.7