Back to index

lightning-sunbird  0.9+nobinonly
nsLineLayout.h
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
00002  * vim:cindent:ts=2:et:sw=2:
00003  *
00004  * ***** BEGIN LICENSE BLOCK *****
00005  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00006  *
00007  * The contents of this file are subject to the Mozilla Public License Version
00008  * 1.1 (the "License"); you may not use this file except in compliance with
00009  * the License. You may obtain a copy of the License at
00010  * http://www.mozilla.org/MPL/
00011  *
00012  * Software distributed under the License is distributed on an "AS IS" basis,
00013  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00014  * for the specific language governing rights and limitations under the
00015  * License.
00016  *
00017  * The Original Code is Mozilla Communicator client code.
00018  *
00019  * The Initial Developer of the Original Code is
00020  * Netscape Communications Corporation.
00021  * Portions created by the Initial Developer are Copyright (C) 1998
00022  * the Initial Developer. All Rights Reserved.
00023  *
00024  * Contributor(s):
00025  *   Steve Clark <buster@netscape.com>
00026  *
00027  * Alternatively, the contents of this file may be used under the terms of
00028  * either of the GNU General Public License Version 2 or later (the "GPL"),
00029  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00030  * in which case the provisions of the GPL or the LGPL are applicable instead
00031  * of those above. If you wish to allow use of your version of this file only
00032  * under the terms of either the GPL or the LGPL, and not to allow others to
00033  * use your version of this file under the terms of the MPL, indicate your
00034  * decision by deleting the provisions above and replace them with the notice
00035  * and other provisions required by the GPL or the LGPL. If you do not delete
00036  * the provisions above, a recipient may use your version of this file under
00037  * the terms of any one of the MPL, the GPL or the LGPL.
00038  *
00039  * ***** END LICENSE BLOCK *****
00040  * This Original Code has been modified by IBM Corporation. Modifications made by IBM 
00041  * described herein are Copyright (c) International Business Machines Corporation, 2000.
00042  * Modifications to Mozilla code or documentation identified per MPL Section 3.3
00043  *
00044  * Date             Modified by     Description of modification
00045  * 04/20/2000       IBM Corp.      OS/2 VisualAge build.
00046  */
00047 #ifndef nsLineLayout_h___
00048 #define nsLineLayout_h___
00049 
00050 #include "nsFrame.h"
00051 #include "nsDeque.h"
00052 #include "nsLineBox.h"
00053 #include "nsBlockReflowState.h"
00054 #include "plarena.h"
00055 
00056 class nsSpaceManager;
00057 class nsPlaceholderFrame;
00058 struct nsStyleText;
00059 
00060 class nsLineLayout {
00061 public:
00062   nsLineLayout(nsPresContext* aPresContext,
00063                nsSpaceManager* aSpaceManager,
00064                const nsHTMLReflowState* aOuterReflowState,
00065                PRBool aComputeMaxElementWidth);
00066   ~nsLineLayout();
00067 
00068   class ArenaDeque : public nsDeque
00069   {
00070   public:
00071     ArenaDeque() : nsDeque(nsnull) {}
00072     void *operator new(size_t, PLArenaPool &pool);
00073     void  operator delete(void *) {} // Dont do anything.  Its Arena memory
00074   };
00075 
00076   void Init(nsBlockReflowState* aState, nscoord aMinLineHeight,
00077             PRInt32 aLineNumber) {
00078     mBlockRS = aState;
00079     mMinLineHeight = aMinLineHeight;
00080     mLineNumber = aLineNumber;
00081   }
00082 
00083   PRInt32 GetColumn() {
00084     return mColumn;
00085   }
00086 
00087   void SetColumn(PRInt32 aNewColumn) {
00088     mColumn = aNewColumn;
00089   }
00090   
00091   PRInt32 GetLineNumber() const {
00092     return mLineNumber;
00093   }
00094 
00095   void BeginLineReflow(nscoord aX, nscoord aY,
00096                        nscoord aWidth, nscoord aHeight,
00097                        PRBool aImpactedByFloats,
00098                        PRBool aIsTopOfPage);
00099 
00100   void EndLineReflow();
00101 
00102   void UpdateBand(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight,
00103                   PRBool aPlacedLeftFloat,
00104                   nsIFrame* aFloatFrame);
00105 
00106   nsresult BeginSpan(nsIFrame* aFrame,
00107                      const nsHTMLReflowState* aSpanReflowState,
00108                      nscoord aLeftEdge,
00109                      nscoord aRightEdge);
00110 
00111   void EndSpan(nsIFrame* aFrame, nsSize& aSizeResult,
00112                nscoord* aMaxElementWidth);
00113 
00114   PRInt32 GetCurrentSpanCount() const;
00115 
00116   void SplitLineTo(PRInt32 aNewCount);
00117 
00118   PRBool IsZeroHeight();
00119 
00120   // Reflows the frame and returns the reflow status. aPushedFrame is PR_TRUE
00121   // if the frame is pushed to the next line because it doesn't fit
00122   nsresult ReflowFrame(nsIFrame* aFrame,
00123                        nsReflowStatus& aReflowStatus,
00124                        nsHTMLReflowMetrics* aMetrics,
00125                        PRBool& aPushedFrame);
00126 
00127   nsresult AddBulletFrame(nsIFrame* aFrame,
00128                           const nsHTMLReflowMetrics& aMetrics);
00129 
00130   void RemoveBulletFrame(nsIFrame* aFrame) {
00131     PushFrame(aFrame);
00132   }
00133 
00134   void VerticalAlignLine(nsLineBox* aLineBox,
00135                          nscoord* aMaxElementWidthResult);
00136 
00137   PRBool TrimTrailingWhiteSpace();
00138 
00139   PRBool HorizontalAlignFrames(nsRect& aLineBounds,
00140                                PRBool aAllowJustify,
00141                                PRBool aShrinkWrapWidth);
00142 
00148   void RelativePositionFrames(nsRect& aCombinedArea);
00149 
00150   //----------------------------------------
00151 
00152   // Supporting methods and data for flags
00153 protected:
00154 #define LL_ENDSINWHITESPACE            0x00000001
00155 #define LL_UNDERSTANDSNWHITESPACE      0x00000002
00156 #define LL_FIRSTLETTERSTYLEOK          0x00000008
00157 #define LL_ISTOPOFPAGE                 0x00000010
00158 #define LL_UPDATEDBAND                 0x00000020
00159 #define LL_IMPACTEDBYFLOATS            0x00000040
00160 #define LL_LASTFLOATWASLETTERFRAME     0x00000080
00161 #define LL_CANPLACEFLOAT               0x00000100
00162 #define LL_LINEENDSINBR                0x00000200
00163 #define LL_LASTFLAG                    LL_LINEENDSINBR
00164 
00165   PRUint16 mFlags;
00166 
00167   void SetFlag(PRUint32 aFlag, PRBool aValue)
00168   {
00169     NS_ASSERTION(aFlag<=LL_LASTFLAG, "bad flag");
00170     NS_ASSERTION(aValue==PR_FALSE || aValue==PR_TRUE, "bad value");
00171     if (aValue) { // set flag
00172       mFlags |= aFlag;
00173     }
00174     else {        // unset flag
00175       mFlags &= ~aFlag;
00176     }
00177   }
00178 
00179   PRBool GetFlag(PRUint32 aFlag) const
00180   {
00181     NS_ASSERTION(aFlag<=LL_LASTFLAG, "bad flag");
00182     PRBool result = (mFlags & aFlag);
00183     if (result) return PR_TRUE;
00184     return PR_FALSE;
00185   }
00186 
00187 public:
00188 
00189   // Support methods for white-space compression and word-wrapping
00190   // during line reflow
00191 
00192   void SetEndsInWhiteSpace(PRBool aState) {
00193     SetFlag(LL_ENDSINWHITESPACE, aState);
00194   }
00195 
00196   PRBool GetEndsInWhiteSpace() const {
00197     return GetFlag(LL_ENDSINWHITESPACE);
00198   }
00199 
00200   void SetUnderstandsWhiteSpace(PRBool aSetting) {
00201     SetFlag(LL_UNDERSTANDSNWHITESPACE, aSetting);
00202   }
00203 
00204   void SetTextJustificationWeights(PRInt32 aNumSpaces, PRInt32 aNumLetters) {
00205     mTextJustificationNumSpaces = aNumSpaces;
00206     mTextJustificationNumLetters = aNumLetters;
00207   }
00208 
00209   void RecordWordFrame(nsIFrame* aWordFrame) {
00210     if(mWordFrames || AllocateDeque())
00211       mWordFrames->Push(aWordFrame);
00212   }
00213 
00214   PRBool InWord() const {
00215     return mWordFrames && 0 != mWordFrames->GetSize();
00216   }
00217 
00218   void ForgetWordFrame(nsIFrame* aFrame);
00219 
00220   void ForgetWordFrames() {
00221     if(mWordFrames) {
00222       mWordFrames->Empty();
00223     }
00224   }
00225 
00226   nsIFrame* FindNextText(nsPresContext* aPresContext, nsIFrame* aFrame);
00227 
00228   PRBool CanPlaceFloatNow() const;
00229 
00230   PRBool LineIsBreakable() const;
00231 
00232   PRBool GetLineEndsInBR() const 
00233   { 
00234     return GetFlag(LL_LINEENDSINBR); 
00235   }
00236 
00237   void SetLineEndsInBR(PRBool aOn) 
00238   { 
00239     SetFlag(LL_LINEENDSINBR, aOn); 
00240   }
00241 
00242   PRBool InStrictMode() const
00243   {
00244     return mCompatMode != eCompatibility_NavQuirks;
00245   }
00246 
00247   nsCompatibility GetCompatMode() const
00248   {
00249     return mCompatMode;
00250   }
00251 
00252   //----------------------------------------
00253   // Inform the line-layout about the presence of a floating frame
00254   // XXX get rid of this: use get-frame-type?
00255   PRBool InitFloat(nsPlaceholderFrame* aFrame, nsReflowStatus& aReflowStatus) {
00256     return mBlockRS->InitFloat(*this, aFrame, aReflowStatus);
00257   }
00258 
00259   PRBool AddFloat(nsPlaceholderFrame* aFrame, nsReflowStatus& aReflowStatus) {
00260     return mBlockRS->AddFloat(*this, aFrame, PR_FALSE, aReflowStatus);
00261   }
00262 
00263   //----------------------------------------
00264 
00265   PRBool GetFirstLetterStyleOK() const {
00266     return GetFlag(LL_FIRSTLETTERSTYLEOK);
00267   }
00268 
00269   void SetFirstLetterStyleOK(PRBool aSetting) {
00270     SetFlag(LL_FIRSTLETTERSTYLEOK, aSetting);
00271   }
00272 
00273   void SetFirstLetterFrame(nsIFrame* aFrame) {
00274     mFirstLetterFrame = aFrame;
00275   }
00276 
00277   //----------------------------------------
00278 
00279   static PRBool TreatFrameAsBlock(nsIFrame* aFrame);
00280 
00281   static PRBool IsPercentageUnitSides(const nsStyleSides* aSides);
00282 
00283   static PRBool IsPercentageAwareReplacedElement(nsPresContext *aPresContext, 
00284                                                  nsIFrame       *aFrame);
00285 
00286 
00287   //----------------------------------------
00288 
00289   nsPresContext* mPresContext;
00290 
00291   nsIFrame* GetLineContainerFrame() const { return mBlockReflowState->frame; }
00292   
00293 protected:
00294   // This state is constant for a given block frame doing line layout
00295   nsSpaceManager* mSpaceManager;
00296   const nsStyleText* mStyleText; // for the block
00297   const nsHTMLReflowState* mBlockReflowState;
00298 
00299   // XXX remove this when landing bug 154892 (splitting absolute positioned frames)
00300   friend class nsInlineFrame;
00301 
00302   nsBlockReflowState* mBlockRS;/* XXX hack! */
00303   nsCompatibility mCompatMode;
00304   nscoord mMinLineHeight;
00305   PRPackedBool mComputeMaxElementWidth;
00306   PRUint8 mTextAlign;
00307 
00308   PRUint8 mPlacedFloats;
00309   
00310   // The amount of text indent that we applied to this line, needed for
00311   // max-element-size calculation.
00312   nscoord mTextIndent;
00313 
00314   // This state varies during the reflow of a line but is line
00315   // "global" state not span "local" state.
00316   nsIFrame* mFirstLetterFrame;
00317   PRInt32 mLineNumber;
00318   PRInt32 mColumn;
00319   PRInt32 mTextJustificationNumSpaces;
00320   PRInt32 mTextJustificationNumLetters;
00321 
00322   nsLineBox* mLineBox;
00323 
00324   PRInt32 mTotalPlacedFrames;
00325   ArenaDeque *mWordFrames;
00326   PRBool  AllocateDeque();
00327 
00328   nscoord mTopEdge;
00329   nscoord mMaxTopBoxHeight;
00330   nscoord mMaxBottomBoxHeight;
00331 
00332   // Final computed line-height value after VerticalAlignFrames for
00333   // the block has been called.
00334   nscoord mFinalLineHeight;
00335 
00336   // Per-frame data recorded by the line-layout reflow logic. This
00337   // state is the state needed to post-process the line after reflow
00338   // has completed (vertical alignment, horizontal alignment,
00339   // justification and relative positioning).
00340 
00341   struct PerSpanData;
00342   struct PerFrameData;
00343   friend struct PerSpanData;
00344   friend struct PerFrameData;
00345   struct PerFrameData {
00346     // link to next/prev frame in same span
00347     PerFrameData* mNext;
00348     PerFrameData* mPrev;
00349 
00350     // pointer to child span data if this is an inline container frame
00351     PerSpanData* mSpan;
00352 
00353     // The frame and its type
00354     nsIFrame* mFrame;
00355     nsCSSFrameType mFrameType;
00356 
00357     // From metrics
00358     nscoord mAscent, mDescent;
00359     nsRect mBounds;
00360     nscoord mMaxElementWidth;
00361     nsRect mCombinedArea;
00362 
00363     // From reflow-state
00364     nsMargin mMargin;
00365     nsMargin mBorderPadding;
00366     nsMargin mOffsets;
00367 
00368     // state for text justification
00369     PRInt32 mJustificationNumSpaces;
00370     PRInt32 mJustificationNumLetters;
00371     
00372     // Other state we use
00373     PRUint8 mVerticalAlign;
00374 
00375 // PerFrameData flags
00376 #define PFD_RELATIVEPOS                 0x00000001
00377 #define PFD_ISTEXTFRAME                 0x00000002
00378 #define PFD_ISNONEMPTYTEXTFRAME         0x00000004
00379 #define PFD_ISNONWHITESPACETEXTFRAME    0x00000008
00380 #define PFD_ISLETTERFRAME               0x00000010
00381 #define PFD_ISSTICKY                    0x00000020
00382 #define PFD_ISBULLET                    0x00000040
00383 #define PFD_ISPLACEHOLDERFRAME          0x00000080
00384 #define PFD_LASTFLAG                    PFD_ISPLACEHOLDERFRAME
00385 
00386     PRPackedBool mFlags;
00387 
00388     void SetFlag(PRUint32 aFlag, PRBool aValue)
00389     {
00390       NS_ASSERTION(aFlag<=PFD_LASTFLAG, "bad flag");
00391       NS_ASSERTION(aValue==PR_FALSE || aValue==PR_TRUE, "bad value");
00392       if (aValue) { // set flag
00393         mFlags |= aFlag;
00394       }
00395       else {        // unset flag
00396         mFlags &= ~aFlag;
00397       }
00398     }
00399 
00400     PRBool GetFlag(PRUint32 aFlag) const
00401     {
00402       NS_ASSERTION(aFlag<=PFD_LASTFLAG, "bad flag");
00403       PRBool result = (mFlags & aFlag);
00404       if (result) return PR_TRUE;
00405       return PR_FALSE;
00406     }
00407 
00408 
00409     PerFrameData* Last() {
00410       PerFrameData* pfd = this;
00411       while (pfd->mNext) {
00412         pfd = pfd->mNext;
00413       }
00414       return pfd;
00415     }
00416   };
00417   PerFrameData* mFrameFreeList;
00418 
00419   struct PerSpanData {
00420     union {
00421       PerSpanData* mParent;
00422       PerSpanData* mNextFreeSpan;
00423     };
00424     PerFrameData* mFrame;
00425     PerFrameData* mFirstFrame;
00426     PerFrameData* mLastFrame;
00427 
00428     const nsHTMLReflowState* mReflowState;
00429     PRPackedBool mNoWrap;
00430     PRUint8 mDirection;
00431     PRPackedBool mChangedFrameDirection;
00432     PRPackedBool mZeroEffectiveSpanBox;
00433     PRPackedBool mContainsFloat;
00434 
00435     nscoord mLeftEdge;
00436     nscoord mX;
00437     nscoord mRightEdge;
00438 
00439     nscoord mTopLeading, mBottomLeading;
00440     nscoord mLogicalHeight;
00441     nscoord mMinY, mMaxY;
00442 
00443     void AppendFrame(PerFrameData* pfd) {
00444       if (nsnull == mLastFrame) {
00445         mFirstFrame = pfd;
00446       }
00447       else {
00448         mLastFrame->mNext = pfd;
00449         pfd->mPrev = mLastFrame;
00450       }
00451       mLastFrame = pfd;
00452     }
00453   };
00454   PerSpanData* mSpanFreeList;
00455   PerSpanData* mRootSpan;
00456   PerSpanData* mCurrentSpan;
00457   PRInt32 mSpanDepth;
00458 #ifdef DEBUG
00459   PRInt32 mSpansAllocated, mSpansFreed;
00460   PRInt32 mFramesAllocated, mFramesFreed;
00461 #endif
00462   PLArenaPool mArena; // Per span and per frame data
00463 
00464   nsresult NewPerFrameData(PerFrameData** aResult);
00465 
00466   nsresult NewPerSpanData(PerSpanData** aResult);
00467 
00468   void FreeSpan(PerSpanData* psd);
00469 
00470   PRBool InBlockContext() const {
00471     return mSpanDepth == 0;
00472   }
00473 
00474   void PushFrame(nsIFrame* aFrame);
00475 
00476   void ApplyStartMargin(PerFrameData* pfd,
00477                         nsHTMLReflowState& aReflowState);
00478 
00479   PRBool CanPlaceFrame(PerFrameData* pfd,
00480                        const nsHTMLReflowState& aReflowState,
00481                        PRBool aNotSafeToBreak,
00482                        nsHTMLReflowMetrics& aMetrics,
00483                        nsReflowStatus& aStatus);
00484 
00485   void PlaceFrame(PerFrameData* pfd,
00486                   nsHTMLReflowMetrics& aMetrics);
00487 
00488   void UpdateFrames();
00489 
00490   void VerticalAlignFrames(PerSpanData* psd);
00491 
00492   void PlaceTopBottomFrames(PerSpanData* psd,
00493                             nscoord aDistanceFromTop,
00494                             nscoord aLineHeight);
00495 
00496   void RelativePositionFrames(PerSpanData* psd, nsRect& aCombinedArea);
00497 
00498   PRBool TrimTrailingWhiteSpaceIn(PerSpanData* psd, nscoord* aDeltaWidth);
00499 
00500 
00501   void ComputeJustificationWeights(PerSpanData* psd, PRInt32* numSpaces, PRInt32* numLetters);
00502 
00503   struct FrameJustificationState {
00504     PRInt32 mTotalNumSpaces;
00505     PRInt32 mTotalNumLetters;
00506     nscoord mTotalWidthForSpaces;
00507     nscoord mTotalWidthForLetters;
00508     PRInt32 mNumSpacesProcessed;
00509     PRInt32 mNumLettersProcessed;
00510     nscoord mWidthForSpacesProcessed;
00511     nscoord mWidthForLettersProcessed;
00512   };
00513   nscoord ApplyFrameJustification(PerSpanData* aPSD, FrameJustificationState* aState);
00514 
00515 
00516 #ifdef DEBUG
00517   void DumpPerSpanData(PerSpanData* psd, PRInt32 aIndent);
00518 #endif
00519 };
00520 
00521 #endif /* nsLineLayout_h___ */