Back to index

lightning-sunbird  0.9+nobinonly
nsBlockBandData.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is Mozilla Communicator client code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 #include "nsCOMPtr.h"
00038 #include "nsBlockBandData.h"
00039 #include "nsIFrame.h"
00040 #include "nsHTMLReflowState.h"
00041 #include "nsPresContext.h"
00042 #include "nsIPresShell.h"
00043 #include "nsLayoutAtoms.h"
00044 #include "nsVoidArray.h"
00045 
00046 nsBlockBandData::nsBlockBandData()
00047   : mSpaceManager(nsnull),
00048     mSpaceManagerX(0),
00049     mSpaceManagerY(0),
00050     mSpace(0, 0)
00051 {
00052   mSize = NS_BLOCK_BAND_DATA_TRAPS;
00053   mTrapezoids = mData;
00054 }
00055 
00056 nsBlockBandData::~nsBlockBandData()
00057 {
00058   if (mTrapezoids != mData) {
00059     delete [] mTrapezoids;
00060   }
00061 }
00062 
00063 nsresult
00064 nsBlockBandData::Init(nsSpaceManager* aSpaceManager,
00065                       const nsSize& aSpace)
00066 {
00067   NS_PRECONDITION(aSpaceManager, "null pointer");
00068 
00069   mSpaceManager = aSpaceManager;
00070   aSpaceManager->GetTranslation(mSpaceManagerX, mSpaceManagerY);
00071 
00072   mSpace = aSpace;
00073   mLeftFloats = 0;
00074   mRightFloats = 0;
00075   return NS_OK;
00076 }
00077 
00078 // Get the available reflow space for the current y coordinate. The
00079 // available space is relative to our coordinate system (0,0) is our
00080 // upper left corner.
00081 nsresult
00082 nsBlockBandData::GetAvailableSpace(nscoord aY, PRBool aRelaxHeightConstraint,
00083                                    nsRect& aResult)
00084 {
00085   // Get the raw band data for the given Y coordinate
00086   nsresult rv = GetBandData(aY, aRelaxHeightConstraint);
00087   if (NS_FAILED(rv)) { return rv; }
00088 
00089   // Compute the bounding rect of the available space, i.e. space
00090   // between any left and right floats.
00091   ComputeAvailSpaceRect();
00092   aResult = mAvailSpace;
00093 #ifdef REALLY_NOISY_COMPUTEAVAILSPACERECT
00094   printf("nsBBD %p GetAvailableSpace(%d) returing (%d, %d, %d, %d)\n",
00095           this, aY, aResult.x, aResult.y, aResult.width, aResult.height);
00096 #endif
00097   return NS_OK;
00098 }
00099 
00100 // the code below should never loop more than a very few times.
00101 // this is a safety valve to see if we've gone off the deep end
00102 #define ERROR_TOO_MANY_ITERATIONS 1000
00103 
00104 /* nsBlockBandData methods should never call mSpaceManager->GetBandData directly.
00105  * They should always call nsBlockBandData::GetBandData() instead.
00106  */
00107 nsresult
00108 nsBlockBandData::GetBandData(nscoord aY, PRBool aRelaxHeightConstraint)
00109 {
00110   NS_ASSERTION(mSpaceManager, "bad state, no space manager");
00111   PRInt32 iterations =0;
00112   nsSize space = mSpace;
00113   if (aRelaxHeightConstraint) {
00114     space.height = NS_UNCONSTRAINEDSIZE;
00115   }
00116   nsresult rv = mSpaceManager->GetBandData(aY, space, *this);
00117   while (NS_FAILED(rv)) {
00118     iterations++;
00119     if (iterations>ERROR_TOO_MANY_ITERATIONS)
00120     {
00121       NS_ASSERTION(PR_FALSE, "too many iterations in nsBlockBandData::GetBandData");
00122       return NS_ERROR_FAILURE;
00123     }
00124     // We need more space for our bands
00125     NS_ASSERTION(mTrapezoids, "bad state, no mTrapezoids");
00126     if (mTrapezoids && (mTrapezoids != mData)) {
00127       delete [] mTrapezoids;
00128     }
00129     PRInt32 newSize = mSize * 2;
00130     if (newSize<mCount) {
00131       newSize = mCount;
00132     }
00133     mTrapezoids = new nsBandTrapezoid[newSize];
00134     NS_POSTCONDITION(mTrapezoids, "failure allocating mTrapezoids");
00135     if (!mTrapezoids) {
00136       return NS_ERROR_OUT_OF_MEMORY;
00137     }
00138     mSize = newSize;
00139     rv = mSpaceManager->GetBandData(aY, space, *this);
00140   }
00141   NS_POSTCONDITION(mCount<=mSize, "bad state, count > size");
00142   return NS_OK;
00143 }
00144 
00145 
00146 
00153 void
00154 nsBlockBandData::ComputeAvailSpaceRect()
00155 {
00156 #ifdef REALLY_NOISY_COMPUTEAVAILSPACERECT
00157   printf("nsBlockBandData::ComputeAvailSpaceRect %p with count %d\n", this, mCount);
00158 #endif
00159   if (0 == mCount) {
00160     mAvailSpace.x = 0;
00161     mAvailSpace.y = 0;
00162     mAvailSpace.width = 0;
00163     mAvailSpace.height = 0;
00164     mLeftFloats = 0;
00165     mRightFloats = 0;
00166     return;
00167   }
00168 
00169   nsBandTrapezoid* trapezoid = mTrapezoids;
00170   // The trapezoid to the left of the first right-floated trapezoid.
00171   nsBandTrapezoid* rightTrapezoid = nsnull;
00172 
00173   PRInt32 leftFloats = 0;
00174   PRInt32 rightFloats = 0;
00175   if (mCount > 1) {
00176     // If there's more than one trapezoid that means there are floats
00177     PRInt32 i;
00178 
00179     // Examine each trapezoid in the band, counting up the number of
00180     // left and right floats. Use the right-most float to
00181     // determine where the right edge of the available space is.
00182     NS_PRECONDITION(mCount<=mSize, "bad state, count > size");
00183     for (i = 0; i < mCount; i++) {
00184       trapezoid = &mTrapezoids[i];
00185       if (trapezoid->mState != nsBandTrapezoid::Available) {
00186 #ifdef REALLY_NOISY_COMPUTEAVAILSPACERECT
00187         printf("band %p checking !Avail trap %p with frame %p\n", this, trapezoid, trapezoid->mFrame);
00188 #endif
00189         if (nsBandTrapezoid::OccupiedMultiple == trapezoid->mState) {
00190           PRInt32 j, numFrames = trapezoid->mFrames->Count();
00191           NS_ASSERTION(numFrames > 0, "bad trapezoid frame list");
00192           for (j = 0; j < numFrames; j++) {
00193             nsIFrame* f = (nsIFrame*) trapezoid->mFrames->ElementAt(j);
00194             const nsStyleDisplay* display = f->GetStyleDisplay();
00195             if (NS_STYLE_FLOAT_LEFT == display->mFloats) {
00196               leftFloats++;
00197             }
00198             else if (NS_STYLE_FLOAT_RIGHT == display->mFloats) {
00199               rightFloats++;
00200               if ((nsnull == rightTrapezoid) && (i > 0)) {
00201                 rightTrapezoid = &mTrapezoids[i - 1];
00202               }
00203             }
00204           }
00205         } else {
00206           const nsStyleDisplay* display = trapezoid->mFrame->GetStyleDisplay();
00207           if (NS_STYLE_FLOAT_LEFT == display->mFloats) {
00208             leftFloats++;
00209           }
00210           else if (NS_STYLE_FLOAT_RIGHT == display->mFloats) {
00211             rightFloats++;
00212             if ((nsnull == rightTrapezoid) && (i > 0)) {
00213               rightTrapezoid = &mTrapezoids[i - 1];
00214             }
00215           }
00216         }
00217       }
00218     }
00219   }
00220   else if (mTrapezoids[0].mState != nsBandTrapezoid::Available) {
00221     // We have a float using up all the available space
00222     leftFloats = 1;
00223   }
00224 #ifdef REALLY_NOISY_COMPUTEAVAILSPACERECT
00225   printf("band %p has floats %d, %d\n", this, leftFloats, rightFloats);
00226 #endif
00227   mLeftFloats = leftFloats;
00228   mRightFloats = rightFloats;
00229 
00230   // We look for available space in the last trapezoid before the
00231   // first right float, or in the last trapezoid if there is no right
00232   // float or no trapezoid before the first right float.
00233   if (nsnull != rightTrapezoid) {
00234     trapezoid = rightTrapezoid;
00235   }
00236   trapezoid->GetRect(mAvailSpace);
00237 
00238   // When there is no available space, we still need a proper X
00239   // coordinate to place objects that end up here anyway.
00240   if (nsBandTrapezoid::Available != trapezoid->mState) {
00241     if (nsBandTrapezoid::OccupiedMultiple == trapezoid->mState) {
00242       // It's not clear what coordinate to use when there is no
00243       // available space and the space is multiply occupied...So: If
00244       // any of the floats that are a part of the trapezoid are left
00245       // floats then we move over to the right edge of the
00246       // unavaliable space.
00247       PRInt32 j, numFrames = trapezoid->mFrames->Count();
00248       NS_ASSERTION(numFrames > 0, "bad trapezoid frame list");
00249       for (j = 0; j < numFrames; j++) {
00250         nsIFrame* f = (nsIFrame*) trapezoid->mFrames->ElementAt(j);
00251         const nsStyleDisplay* display = f->GetStyleDisplay();
00252         if (NS_STYLE_FLOAT_LEFT == display->mFloats) {
00253           mAvailSpace.x = mAvailSpace.XMost();
00254           break;
00255         }
00256       }
00257     }
00258     else {
00259       const nsStyleDisplay* display = trapezoid->mFrame->GetStyleDisplay();
00260       if (NS_STYLE_FLOAT_LEFT == display->mFloats) {
00261         mAvailSpace.x = mAvailSpace.XMost();
00262       }
00263     }
00264     mAvailSpace.width = 0;
00265   }
00266 
00267   // Fixup width
00268   if (NS_UNCONSTRAINEDSIZE == mSpace.width) {
00269     mAvailSpace.width = NS_UNCONSTRAINEDSIZE;
00270   }
00271 #ifdef REALLY_NOISY_COMPUTEAVAILSPACERECT
00272   printf("  ComputeAvailSpaceRect settting state mAvailSpace (%d,%d,%d,%d)\n", 
00273          mAvailSpace.x, mAvailSpace.y, mAvailSpace.width, mAvailSpace.height);
00274 #endif
00275 
00276 }
00277 
00278 #ifdef DEBUG
00279 void nsBlockBandData::List()
00280 {
00281   printf("nsBlockBandData %p sm=%p, sm coord = (%d,%d), mSpace = (%d,%d)\n",
00282           this, mSpaceManager, mSpaceManagerX, mSpaceManagerY,
00283           mSpace.width, mSpace.height);
00284   printf("  availSpace=(%d, %d, %d, %d), floats l=%d r=%d\n",
00285           mAvailSpace.x, mAvailSpace.y, mAvailSpace.width, mAvailSpace.height,
00286           mLeftFloats, mRightFloats);
00287 }
00288 #endif