Back to index

lightning-sunbird  0.9+nobinonly
nsPageFrame.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.org 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 "nsPageFrame.h"
00038 #include "nsHTMLParts.h"
00039 #include "nsIContent.h"
00040 #include "nsPresContext.h"
00041 #include "nsStyleContext.h"
00042 #include "nsIRenderingContext.h"
00043 #include "nsHTMLAtoms.h"
00044 #include "nsLayoutAtoms.h"
00045 #include "nsIPresShell.h"
00046 #include "nsCSSFrameConstructor.h"
00047 #include "nsIDeviceContext.h"
00048 #include "nsReadableUtils.h"
00049 #include "nsPageContentFrame.h"
00050 #include "nsTextFrame.h" // for function BinarySearchForPosition
00051 
00052 #include "nsIView.h" // view flags for clipping
00053 #include "nsCSSRendering.h"
00054 
00055 #include "nsHTMLContainerFrame.h" // view creation
00056 
00057 #include "nsSimplePageSequence.h" // for nsSharedPageData
00058 #include "nsRegion.h"
00059 #include "nsIViewManager.h"
00060 
00061 // for page number localization formatting
00062 #include "nsTextFormatter.h"
00063 
00064 #ifdef IBMBIDI
00065 #include "nsBidiUtils.h"
00066 #include "nsBidiPresUtils.h"
00067 #endif
00068 
00069 // Temporary
00070 #include "nsIFontMetrics.h"
00071 
00072 // Print Options
00073 #include "nsIPrintSettings.h"
00074 #include "nsGfxCIID.h"
00075 #include "nsIServiceManager.h"
00076 
00077 // Widget Creation
00078 #include "nsIWidget.h"
00079 #include "nsWidgetsCID.h"
00080 static NS_DEFINE_CID(kCChildCID, NS_CHILD_CID);
00081 
00082 #if defined(DEBUG_rods) || defined(DEBUG_dcone)
00083 //#define DEBUG_PRINTING
00084 #endif
00085 
00086 #include "prlog.h"
00087 #ifdef PR_LOGGING 
00088 extern PRLogModuleInfo * kLayoutPrintingLogMod;
00089 #define PR_PL(_p1)  PR_LOG(kLayoutPrintingLogMod, PR_LOG_DEBUG, _p1)
00090 #else
00091 #define PR_PL(_p1)
00092 #endif
00093 
00094 // XXX Part of Temporary fix for Bug 127263
00095 PRBool nsPageFrame::mDoCreateWidget = PR_TRUE;
00096 
00097 nsresult
00098 NS_NewPageFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame)
00099 {
00100   NS_PRECONDITION(aNewFrame, "null OUT ptr");
00101 
00102   nsPageFrame* it = new (aPresShell) nsPageFrame;
00103   if (nsnull == it) {
00104     return NS_ERROR_OUT_OF_MEMORY;
00105   }
00106   *aNewFrame = it;
00107   return NS_OK;
00108 }
00109 
00110 nsPageFrame::nsPageFrame() :
00111   mSupressHF(PR_FALSE),
00112   mClipRect(-1, -1, -1, -1)
00113 {
00114 }
00115 
00116 nsPageFrame::~nsPageFrame()
00117 {
00118 }
00119 
00120 
00121 NS_IMETHODIMP
00122 nsPageFrame::SetInitialChildList(nsPresContext* aPresContext,
00123                                       nsIAtom*        aListName,
00124                                       nsIFrame*       aChildList)
00125 {
00126   nsIView* view = aChildList->GetView();
00127   if (view && mDoCreateWidget) {
00128     if (aPresContext->Type() == nsPresContext::eContext_PrintPreview &&
00129         view->GetNearestWidget(nsnull)) {
00130       view->CreateWidget(kCChildCID);  
00131     }
00132   }
00133 
00134   return nsContainerFrame::SetInitialChildList(aPresContext, aListName, aChildList);
00135 }
00136 
00137 NS_IMETHODIMP nsPageFrame::Reflow(nsPresContext*          aPresContext,
00138                                   nsHTMLReflowMetrics&     aDesiredSize,
00139                                   const nsHTMLReflowState& aReflowState,
00140                                   nsReflowStatus&          aStatus)
00141 {
00142   DO_GLOBAL_REFLOW_COUNT("nsPageFrame", aReflowState.reason);
00143   DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
00144   aStatus = NS_FRAME_COMPLETE;  // initialize out parameter
00145 
00146   if (eReflowReason_Incremental != aReflowState.reason) {
00147     // Do we have any children?
00148     // XXX We should use the overflow list instead...
00149     nsIFrame*           firstFrame  = mFrames.FirstChild();
00150     nsPageContentFrame* contentPage = NS_STATIC_CAST(nsPageContentFrame*, firstFrame);
00151     NS_ASSERTION(contentPage, "There should always be a content page");
00152     NS_ASSERTION(nsLayoutAtoms::pageContentFrame == firstFrame->GetType(),
00153                  "This frame isn't a pageContentFrame");
00154 
00155     if (contentPage && mPrevInFlow) {
00156       nsPageFrame*        prevPage        = NS_STATIC_CAST(nsPageFrame*, mPrevInFlow);
00157       nsPageContentFrame* prevContentPage = NS_STATIC_CAST(nsPageContentFrame*, prevPage->mFrames.FirstChild());
00158       nsIFrame*           prevLastChild   = prevContentPage->mFrames.LastChild();
00159 
00160       // Create a continuing child of the previous page's last child
00161       nsIFrame*     newFrame;
00162 
00163       nsresult rv = aPresContext->PresShell()->FrameConstructor()->
00164         CreateContinuingFrame(aPresContext, prevLastChild,
00165                               contentPage, &newFrame);
00166       if (NS_FAILED(rv)) {
00167         return rv;
00168       }
00169       // Make the new area frame the 1st child of the page content frame. There may already be
00170       // children placeholders which don't get reflowed but must not be destroyed until the 
00171       // page content frame is destroyed.
00172       contentPage->mFrames.InsertFrame(contentPage, nsnull, newFrame);
00173     }
00174 
00175     // Resize our frame allowing it only to be as big as we are
00176     // XXX Pay attention to the page's border and padding...
00177     if (mFrames.NotEmpty()) {
00178       nsIFrame* frame = mFrames.FirstChild();
00179       // When availableHeight is NS_UNCONSTRAINEDSIZE it means we are reflowing a single page
00180       // to print selection. So this means we want to use NS_UNCONSTRAINEDSIZE without altering it
00181       nscoord avHeight;
00182       if (aReflowState.availableHeight == NS_UNCONSTRAINEDSIZE) {
00183         avHeight = NS_UNCONSTRAINEDSIZE;
00184       } else {
00185         avHeight = mPD->mReflowRect.height - mPD->mReflowMargin.top - mPD->mReflowMargin.bottom;
00186       }
00187       nsSize  maxSize(mPD->mReflowRect.width - mPD->mReflowMargin.right - mPD->mReflowMargin.left, 
00188                       avHeight);
00189       // Get the number of Twips per pixel from the PresContext
00190       nscoord onePixelInTwips = aPresContext->IntScaledPixelsToTwips(1);
00191       NS_ASSERTION(maxSize.width >= onePixelInTwips, "maxSize.width must be >= 1 pixel");
00192       NS_ASSERTION(maxSize.height >= onePixelInTwips, "maxSize.height must be >= 1 pixel");
00193       // insurance against infinite reflow, when reflowing less than a pixel
00194       if (maxSize.width < onePixelInTwips || maxSize.height < onePixelInTwips) {
00195         aDesiredSize.width  = 0;
00196         aDesiredSize.height = 0;
00197         return NS_OK;
00198       }
00199 
00200       nsHTMLReflowState kidReflowState(aPresContext, aReflowState, frame, maxSize);
00201       kidReflowState.mFlags.mIsTopOfPage = PR_TRUE;
00202 
00203       // calc location of frame
00204       nscoord xc = mPD->mReflowMargin.left + mPD->mDeadSpaceMargin.left + mPD->mExtraMargin.left;
00205       nscoord yc = mPD->mReflowMargin.top + mPD->mDeadSpaceMargin.top + mPD->mExtraMargin.top;
00206 
00207       // Get the child's desired size
00208       ReflowChild(frame, aPresContext, aDesiredSize, kidReflowState, xc, yc, 0, aStatus);
00209 
00210 
00211       // Place and size the child
00212       FinishReflowChild(frame, aPresContext, &kidReflowState, aDesiredSize, xc, yc, 0);
00213 
00214       // Make sure the child is at least as tall as our max size (the containing window)
00215       if (aDesiredSize.height < aReflowState.availableHeight &&
00216           aReflowState.availableHeight != NS_UNCONSTRAINEDSIZE) {
00217         aDesiredSize.height = aReflowState.availableHeight;
00218       }
00219 
00220       nsIView* view = frame->GetView();
00221       if (view) {
00222         nsRegion region(nsRect(0, 0, aDesiredSize.width, aDesiredSize.height));
00223         view->GetViewManager()->SetViewChildClipRegion(view, &region);
00224       }
00225 
00226       NS_ASSERTION(!NS_FRAME_IS_COMPLETE(aStatus) ||
00227                    !frame->GetNextInFlow(), "bad child flow list");
00228     }
00229     PR_PL(("PageFrame::Reflow %p ", this));
00230     PR_PL(("[%d,%d][%d,%d]\n", aDesiredSize.width, aDesiredSize.height, aReflowState.availableWidth, aReflowState.availableHeight));
00231 
00232     // Return our desired size
00233     aDesiredSize.width = aReflowState.availableWidth;
00234     if (aReflowState.availableHeight != NS_UNCONSTRAINEDSIZE) {
00235       aDesiredSize.height = aReflowState.availableHeight;
00236     }
00237   }
00238   PR_PL(("PageFrame::Reflow %p ", this));
00239   PR_PL(("[%d,%d]\n", aReflowState.availableWidth, aReflowState.availableHeight));
00240 
00241   NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
00242   return NS_OK;
00243 }
00244 
00245 void nsPageFrame::SetClipRect(nsRect* aClipRect) 
00246 {
00247   mClipRect = *aClipRect; 
00248   nsIFrame*           firstFrame  = mFrames.FirstChild();
00249   nsPageContentFrame* contentPage = NS_STATIC_CAST(nsPageContentFrame*, firstFrame);
00250   NS_ASSERTION(contentPage, "There should always be a content page");
00251   contentPage->SetClipRect(aClipRect);
00252 }
00253 
00254 
00255 nsIAtom*
00256 nsPageFrame::GetType() const
00257 {
00258   return nsLayoutAtoms::pageFrame; 
00259 }
00260 
00261 #ifdef DEBUG
00262 NS_IMETHODIMP
00263 nsPageFrame::GetFrameName(nsAString& aResult) const
00264 {
00265   return MakeFrameName(NS_LITERAL_STRING("Page"), aResult);
00266 }
00267 #endif
00268 
00269 /* virtual */ PRBool
00270 nsPageFrame::IsContainingBlock() const
00271 {
00272   return PR_TRUE;
00273 }
00274 
00275 // done with static helper functions
00276 //------------------------------------------------------------------------------
00277 void 
00278 nsPageFrame::ProcessSpecialCodes(const nsString& aStr, nsString& aNewStr)
00279 {
00280 
00281   aNewStr = aStr;
00282 
00283   // Search to see if the &D code is in the string 
00284   // then subst in the current date/time
00285   NS_NAMED_LITERAL_STRING(kDate, "&D");
00286   if (aStr.Find(kDate) != kNotFound) {
00287     if (mPD->mDateTimeStr != nsnull) {
00288       aNewStr.ReplaceSubstring(kDate.get(), mPD->mDateTimeStr);
00289     } else {
00290       aNewStr.ReplaceSubstring(kDate.get(), EmptyString().get());
00291     }
00292   }
00293 
00294   // NOTE: Must search for &PT before searching for &P
00295   //
00296   // Search to see if the "page number and page" total code are in the string
00297   // and replace the page number and page total code with the actual
00298   // values
00299   NS_NAMED_LITERAL_STRING(kPageAndTotal, "&PT");
00300   if (aStr.Find(kPageAndTotal) != kNotFound) {
00301     PRUnichar * uStr = nsTextFormatter::smprintf(mPD->mPageNumAndTotalsFormat, mPageNum, mTotNumPages);
00302     aNewStr.ReplaceSubstring(kPageAndTotal.get(), uStr);
00303     nsMemory::Free(uStr);
00304   }
00305 
00306   // Search to see if the page number code is in the string
00307   // and replace the page number code with the actual value
00308   NS_NAMED_LITERAL_STRING(kPage, "&P");
00309   if (aStr.Find(kPage) != kNotFound) {
00310     PRUnichar * uStr = nsTextFormatter::smprintf(mPD->mPageNumFormat, mPageNum);
00311     aNewStr.ReplaceSubstring(kPage.get(), uStr);
00312     nsMemory::Free(uStr);
00313   }
00314 
00315   NS_NAMED_LITERAL_STRING(kTitle, "&T");
00316   if (aStr.Find(kTitle) != kNotFound) {
00317     if (mPD->mDocTitle != nsnull) {
00318       aNewStr.ReplaceSubstring(kTitle.get(), mPD->mDocTitle);
00319     } else {
00320       aNewStr.ReplaceSubstring(kTitle.get(), EmptyString().get());
00321     }
00322   }
00323 
00324   NS_NAMED_LITERAL_STRING(kDocURL, "&U");
00325   if (aStr.Find(kDocURL) != kNotFound) {
00326     if (mPD->mDocURL != nsnull) {
00327       aNewStr.ReplaceSubstring(kDocURL.get(), mPD->mDocURL);
00328     } else {
00329       aNewStr.ReplaceSubstring(kDocURL.get(), EmptyString().get());
00330     }
00331   }
00332 
00333   NS_NAMED_LITERAL_STRING(kPageTotal, "&L");
00334   if (aStr.Find(kPageTotal) != kNotFound) {
00335     PRUnichar * uStr = nsTextFormatter::smprintf(mPD->mPageNumFormat, mTotNumPages);
00336     aNewStr.ReplaceSubstring(kPageTotal.get(), uStr);
00337     nsMemory::Free(uStr);
00338   }
00339 }
00340 
00341 
00342 //------------------------------------------------------------------------------
00343 nscoord nsPageFrame::GetXPosition(nsIRenderingContext& aRenderingContext, 
00344                                   const nsRect&        aRect, 
00345                                   PRInt32              aJust,
00346                                   const nsString&      aStr)
00347 {
00348   PRInt32 width;
00349   aRenderingContext.GetWidth(aStr, width);
00350 
00351   nscoord x = aRect.x;
00352   switch (aJust) {
00353     case nsIPrintSettings::kJustLeft:
00354       x += mPD->mExtraMargin.left + mPD->mEdgePaperMargin.left;
00355       break;
00356 
00357     case nsIPrintSettings::kJustCenter:
00358       x += (aRect.width - width) / 2;
00359       break;
00360 
00361     case nsIPrintSettings::kJustRight:
00362       x += aRect.width - width - mPD->mExtraMargin.right - mPD->mEdgePaperMargin.right;
00363       break;
00364   } // switch
00365 
00366   NS_ASSERTION(x >= 0, "x can't be less than zero");
00367   x = PR_MAX(x, 0);
00368   return x;
00369 }
00370 
00371 //------------------------------------------------------------------------------
00372 // Draw a Header or footer text lrft,right or center justified
00373 // @parm aRenderingContext - rendering content ot draw into
00374 // @parm aHeaderFooter - indicates whether it is a header or footer
00375 // @parm aJust - indicates the justification of the text
00376 // @parm aStr - The string to be drawn
00377 // @parm aRect - the rect of the page
00378 // @parm aHeight - the height of the text
00379 // @parm aUseHalfThePage - indicates whether the text should limited to  the width
00380 //                         of the entire page or just half the page
00381 void
00382 nsPageFrame::DrawHeaderFooter(nsPresContext*      aPresContext,
00383                               nsIRenderingContext& aRenderingContext,
00384                               nsIFrame *           aFrame,
00385                               nsHeaderFooterEnum   aHeaderFooter,
00386                               PRInt32              aJust,
00387                               const nsString&      aStr1,
00388                               const nsString&      aStr2,
00389                               const nsString&      aStr3,
00390                               const nsRect&        aRect,
00391                               nscoord              aAscent,
00392                               nscoord              aHeight)
00393 {
00394   PRInt32 numStrs = 0;
00395   if (!aStr1.IsEmpty()) numStrs++;
00396   if (!aStr2.IsEmpty()) numStrs++;
00397   if (!aStr3.IsEmpty()) numStrs++;
00398 
00399   if (numStrs == 0) return;
00400   nscoord strSpace = aRect.width / numStrs;
00401 
00402   if (!aStr1.IsEmpty()) {
00403     DrawHeaderFooter(aPresContext, aRenderingContext, aFrame, aHeaderFooter, nsIPrintSettings::kJustLeft, aStr1, aRect, aAscent, aHeight, strSpace);
00404   }
00405   if (!aStr2.IsEmpty()) {
00406     DrawHeaderFooter(aPresContext, aRenderingContext, aFrame, aHeaderFooter, nsIPrintSettings::kJustCenter, aStr2, aRect, aAscent, aHeight, strSpace);
00407   }
00408   if (!aStr3.IsEmpty()) {
00409     DrawHeaderFooter(aPresContext, aRenderingContext, aFrame, aHeaderFooter, nsIPrintSettings::kJustRight, aStr3, aRect, aAscent, aHeight, strSpace);
00410   }
00411 }
00412 
00413 //------------------------------------------------------------------------------
00414 // Draw a Header or footer text lrft,right or center justified
00415 // @parm aRenderingContext - rendering content ot draw into
00416 // @parm aHeaderFooter - indicates whether it is a header or footer
00417 // @parm aJust - indicates the justification of the text
00418 // @parm aStr - The string to be drawn
00419 // @parm aRect - the rect of the page
00420 // @parm aHeight - the height of the text
00421 // @parm aWidth - available width for any one of the strings
00422 void
00423 nsPageFrame::DrawHeaderFooter(nsPresContext*      aPresContext,
00424                               nsIRenderingContext& aRenderingContext,
00425                               nsIFrame *           aFrame,
00426                               nsHeaderFooterEnum   aHeaderFooter,
00427                               PRInt32              aJust,
00428                               const nsString&      aStr,
00429                               const nsRect&        aRect,
00430                               nscoord              aAscent,
00431                               nscoord              aHeight,
00432                               nscoord              aWidth)
00433 {
00434 
00435   nscoord contentWidth = aWidth - (mPD->mEdgePaperMargin.left + mPD->mEdgePaperMargin.right);
00436 
00437   // first make sure we have a vaild string and that the height of the
00438   // text will fit in the margin
00439   if (!aStr.IsEmpty() && 
00440       ((aHeaderFooter == eHeader && aHeight < mMargin.top) ||
00441        (aHeaderFooter == eFooter && aHeight < mMargin.bottom))) {
00442     nsAutoString str;
00443     ProcessSpecialCodes(aStr, str);
00444 
00445     PRInt32 indx;
00446     PRInt32 textWidth = 0;
00447     const PRUnichar* text = str.get();
00448 
00449     PRInt32 len = (PRInt32)str.Length();
00450     if (len == 0) {
00451       return; // bail is empty string
00452     }
00453     // find how much text fits, the "position" is the size of the available area
00454     if (BinarySearchForPosition(&aRenderingContext, text, 0, 0, 0, len,
00455                                 PRInt32(contentWidth), indx, textWidth)) {
00456       if (indx < len-1 ) {
00457         // we can't fit in all the text
00458         if (indx > 3) {
00459           // But we can fit in at least 4 chars.  Show all but 3 of them, then
00460           // an ellipsis.
00461           // XXXbz for non-plane0 text, this may be cutting things in the
00462           // middle of a codepoint!  Also, we have no guarantees that the three
00463           // dots will fit in the space the three chars we removed took up with
00464           // these font metrics!
00465           str.Truncate(indx-3);
00466           str.AppendLiteral("...");
00467         } else {
00468           // We can only fit 3 or fewer chars.  Just show nothing
00469           str.Truncate();
00470         }
00471       }
00472     } else { 
00473       return; // bail if couldn't find the correct length
00474     }
00475 
00476     // cacl the x and y positions of the text
00477     nsRect rect(aRect);
00478     nscoord x = GetXPosition(aRenderingContext, rect, aJust, str);
00479     nscoord y;
00480     if (aHeaderFooter == eHeader) {
00481       y = rect.y + mPD->mExtraMargin.top + mPD->mEdgePaperMargin.top;
00482     } else {
00483       y = rect.y + rect.height - aHeight - mPD->mExtraMargin.bottom - mPD->mEdgePaperMargin.bottom;
00484     }
00485 
00486     // set up new clip and draw the text
00487     aRenderingContext.PushState();
00488     aRenderingContext.SetColor(NS_RGB(0,0,0));
00489     aRenderingContext.SetClipRect(rect, nsClipCombine_kReplace);
00490 #ifdef IBMBIDI
00491     nsresult rv = NS_ERROR_FAILURE;
00492 
00493     if (aPresContext->BidiEnabled()) {
00494       nsBidiPresUtils* bidiUtils = aPresContext->GetBidiUtils();
00495       
00496       if (bidiUtils) {
00497         // Base direction is always LTR for now. If bug 139337 is fixed, 
00498         // that should change.
00499         rv = bidiUtils->RenderText(str.get(), str.Length(), NSBIDI_LTR,
00500                                    aPresContext, aRenderingContext,
00501                                    x, y + aAscent);
00502       }
00503     }
00504     if (NS_FAILED(rv))
00505 #endif // IBMBIDI
00506     aRenderingContext.DrawString(str, x, y + aAscent);
00507     aRenderingContext.PopState();
00508 
00509 #ifdef DEBUG_PRINTING
00510     PR_PL(("Page: %p", this));
00511     PR_PL((" [%s]", NS_ConvertUCS2toUTF8(str).get()));
00512     char justStr[64];
00513     switch (aJust) {
00514       case nsIPrintSettings::kJustLeft:strcpy(justStr, "Left");break;
00515       case nsIPrintSettings::kJustCenter:strcpy(justStr, "Center");break;
00516       case nsIPrintSettings::kJustRight:strcpy(justStr, "Right");break;
00517     } // switch
00518     PR_PL((" HF: %s ", aHeaderFooter==eHeader?"Header":"Footer"));
00519     PR_PL((" JST: %s ", justStr));
00520     PR_PL((" x,y: %d,%d", x, y));
00521     PR_PL((" Hgt: %d \n", aHeight));
00522 #endif
00523   }
00524 }
00525 
00526 //------------------------------------------------------------------------------
00527 NS_IMETHODIMP
00528 nsPageFrame::Paint(nsPresContext*      aPresContext,
00529                    nsIRenderingContext& aRenderingContext,
00530                    const nsRect&        aDirtyRect,
00531                    nsFramePaintLayer    aWhichLayer,
00532                    PRUint32             aFlags)
00533 {
00534   aRenderingContext.PushState();
00535   aRenderingContext.SetColor(NS_RGB(255,255,255));
00536 
00537   nsRect rect;
00538   PRBool specialClipIsSet = mClipRect.width != -1 || mClipRect.height != -1;
00539 
00540   if (specialClipIsSet) {
00541 #ifdef DEBUG_PRINTING
00542     if (NS_FRAME_PAINT_LAYER_FOREGROUND == aWhichLayer) {
00543       printf("*** ClipRect: %5d,%5d,%5d,%5d\n", mClipRect.x, mClipRect.y, mClipRect.width, mClipRect.height);
00544     }
00545 #endif
00546     aRenderingContext.SetClipRect(mClipRect, nsClipCombine_kReplace);
00547     rect = mClipRect;
00548   } else {
00549     rect = mRect;
00550   }
00551 
00552   if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) {
00553 
00554     if (aPresContext->Type() == nsPresContext::eContext_PrintPreview) {
00555       // fill page with White
00556       aRenderingContext.SetColor(NS_RGB(255,255,255));
00557       rect.x = 0;
00558       rect.y = 0;
00559       rect.width  -= mPD->mShadowSize.width;
00560       rect.height -= mPD->mShadowSize.height;
00561       aRenderingContext.FillRect(rect);
00562       // draw line around outside of page
00563       aRenderingContext.SetColor(NS_RGB(0,0,0));
00564       aRenderingContext.DrawRect(rect);
00565 
00566       if (mPD->mShadowSize.width > 0 && mPD->mShadowSize.height > 0) {
00567         aRenderingContext.SetColor(NS_RGB(51,51,51));
00568         nsRect r(0,0, mRect.width, mRect.height);
00569         nsRect shadowRect;
00570         shadowRect.x = r.x + r.width - mPD->mShadowSize.width;
00571         shadowRect.y = r.y + mPD->mShadowSize.height;
00572         shadowRect.width  = mPD->mShadowSize.width;
00573         shadowRect.height = r.height - mPD->mShadowSize.height;
00574         aRenderingContext.FillRect(shadowRect);
00575 
00576         shadowRect.x = r.x + mPD->mShadowSize.width;
00577         shadowRect.y = r.y + r.height - mPD->mShadowSize.height;
00578         shadowRect.width  = r.width - mPD->mShadowSize.width;
00579         shadowRect.height = mPD->mShadowSize.height;
00580         aRenderingContext.FillRect(shadowRect);
00581       }
00582     }
00583   }
00584 
00585   if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) {
00586     DrawBackground(aPresContext,aRenderingContext,aDirtyRect);
00587   }
00588 
00589   nsresult rv = nsContainerFrame::Paint(aPresContext, aRenderingContext, aDirtyRect, aWhichLayer);
00590 
00591 #if defined(DEBUG_rods) || defined(DEBUG_dcone)
00592   if (NS_FRAME_PAINT_LAYER_FOREGROUND == aWhichLayer) {
00593     PR_PL(("PF::Paint    -> %p  SupHF: %s  Rect: [%5d,%5d,%5d,%5d] SC:%s\n", this, 
00594             mSupressHF?"Yes":"No", mRect.x, mRect.y, mRect.width, mRect.height, specialClipIsSet?"Yes":"No"));
00595     PR_PL(("PF::Paint    -> %p  SupHF: %s  Rect: [%5d,%5d,%5d,%5d] SC:%s\n", this, 
00596             mSupressHF?"Yes":"No", mRect.x, mRect.y, mRect.width, mRect.height, specialClipIsSet?"Yes":"No"));
00597   }
00598 #endif
00599 
00600   if (NS_FRAME_PAINT_LAYER_FOREGROUND == aWhichLayer && !mSupressHF) {
00601     // For PrintPreview the 
00602     if (!mPD->mPrintSettings) {
00603       if (aPresContext->Type() == nsPresContext::eContext_PrintPreview) {
00604         mPD->mPrintSettings = aPresContext->GetPrintSettings();
00605       }
00606     }
00607     NS_ASSERTION(mPD->mPrintSettings, "Must have a good PrintSettings here!");
00608 
00609     // get the current margin
00610     mPD->mPrintSettings->GetMarginInTwips(mMargin);
00611 
00612     rect.SetRect(0, 0, mRect.width - mPD->mShadowSize.width, mRect.height - mPD->mShadowSize.height);
00613 
00614     aRenderingContext.SetFont(*mPD->mHeadFootFont, nsnull);
00615     aRenderingContext.SetColor(NS_RGB(0,0,0));
00616 
00617     // Get the FontMetrics to determine width.height of strings
00618     nsCOMPtr<nsIFontMetrics> fontMet;
00619     aPresContext->DeviceContext()->GetMetricsFor(*mPD->mHeadFootFont, nsnull,
00620                                                  *getter_AddRefs(fontMet));
00621     nscoord ascent = 0;
00622     nscoord visibleHeight = 0;
00623     if (fontMet) {
00624       fontMet->GetHeight(visibleHeight);
00625       fontMet->GetMaxAscent(ascent);
00626     }
00627 
00628     // print document headers and footers
00629     PRUnichar * headers[3];
00630     mPD->mPrintSettings->GetHeaderStrLeft(&headers[0]);   // creates memory
00631     mPD->mPrintSettings->GetHeaderStrCenter(&headers[1]); // creates memory
00632     mPD->mPrintSettings->GetHeaderStrRight(&headers[2]);  // creates memory
00633     DrawHeaderFooter(aPresContext, aRenderingContext, this, eHeader, nsIPrintSettings::kJustLeft, 
00634                      nsAutoString(headers[0]), nsAutoString(headers[1]), nsAutoString(headers[2]), 
00635                      rect, ascent, visibleHeight);
00636     PRInt32 i;
00637     for (i=0;i<3;i++) nsMemory::Free(headers[i]);
00638 
00639     PRUnichar * footers[3];
00640     mPD->mPrintSettings->GetFooterStrLeft(&footers[0]);   // creates memory
00641     mPD->mPrintSettings->GetFooterStrCenter(&footers[1]); // creates memory
00642     mPD->mPrintSettings->GetFooterStrRight(&footers[2]);  // creates memory
00643     DrawHeaderFooter(aPresContext, aRenderingContext, this, eFooter, nsIPrintSettings::kJustRight, 
00644                      nsAutoString(footers[0]), nsAutoString(footers[1]), nsAutoString(footers[2]), 
00645                      rect, ascent, visibleHeight);
00646     for (i=0;i<3;i++) nsMemory::Free(footers[i]);
00647 
00648   }
00649 
00650   aRenderingContext.PopState();
00651 
00652   return rv;
00653 }
00654 
00655 //------------------------------------------------------------------------------
00656 void
00657 nsPageFrame::SetPageNumInfo(PRInt32 aPageNumber, PRInt32 aTotalPages) 
00658 { 
00659   mPageNum     = aPageNumber; 
00660   mTotNumPages = aTotalPages;
00661 }
00662 
00663 
00664 //------------------------------------------------------------------------------
00665 void
00666 nsPageFrame::DrawBackground(nsPresContext*      aPresContext,
00667                             nsIRenderingContext& aRenderingContext,
00668                             const nsRect&        aDirtyRect) 
00669 {
00670   nsSimplePageSequenceFrame* seqFrame = NS_STATIC_CAST(nsSimplePageSequenceFrame*, mParent);
00671   if (seqFrame != nsnull) {
00672     nsIFrame* pageContentFrame  = mFrames.FirstChild();
00673     NS_ASSERTION(pageContentFrame, "Must always be there.");
00674 
00675     const nsStyleBorder* border = GetStyleBorder();
00676     const nsStylePadding* padding = GetStylePadding();
00677 
00678     nsCSSRendering::PaintBackground(aPresContext, aRenderingContext, this,
00679                                     aDirtyRect, pageContentFrame->GetRect(), *border, *padding,
00680                                     PR_TRUE);
00681   }
00682 }
00683 
00684 void
00685 nsPageFrame::SetSharedPageData(nsSharedPageData* aPD) 
00686 { 
00687   mPD = aPD;
00688   // Set the shared data into the page frame before reflow
00689   nsPageContentFrame * pcf = NS_STATIC_CAST(nsPageContentFrame*, mFrames.FirstChild());
00690   if (pcf) {
00691     pcf->SetSharedPageData(mPD);
00692   }
00693 
00694 }
00695 
00696 nsresult
00697 NS_NewPageBreakFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame)
00698 {
00699   NS_PRECONDITION(aPresShell && aNewFrame, "null PresShell or OUT ptr");
00700 #ifdef DEBUG
00701   //check that we are only creating page break frames when printing
00702   NS_ASSERTION(aPresShell->GetPresContext()->IsPaginated(), "created a page break frame while not printing");
00703 #endif
00704 
00705   nsPageBreakFrame* it = new (aPresShell) nsPageBreakFrame;
00706   if (nsnull == it) {
00707     return NS_ERROR_OUT_OF_MEMORY;
00708   }
00709   *aNewFrame = it;
00710   return NS_OK;
00711 }
00712 
00713 nsPageBreakFrame::nsPageBreakFrame()
00714 : mHaveReflowed(PR_FALSE)
00715 {
00716 }
00717 
00718 nsPageBreakFrame::~nsPageBreakFrame()
00719 {
00720 }
00721 
00722 void 
00723 nsPageBreakFrame::GetDesiredSize(nsPresContext*          aPresContext,
00724                                  const nsHTMLReflowState& aReflowState,
00725                                  nsHTMLReflowMetrics&     aDesiredSize)
00726 {
00727   NS_PRECONDITION(aPresContext, "null pres context");
00728   nscoord onePixel = aPresContext->IntScaledPixelsToTwips(1);
00729 
00730   aDesiredSize.width  = onePixel;
00731   if (mHaveReflowed) {
00732     // If blocks reflow us a 2nd time trying to put us on a new page, then return
00733     // a desired height of 0 to avoid an extra page break. 
00734     aDesiredSize.height = 0;
00735   }
00736   else {
00737     aDesiredSize.height = aReflowState.availableHeight;
00738     // round the height down to the nearest pixel
00739     aDesiredSize.height -= aDesiredSize.height % onePixel;
00740   }
00741 
00742   if (aDesiredSize.mComputeMEW) {
00743     aDesiredSize.mMaxElementWidth  = onePixel;
00744   }
00745   aDesiredSize.ascent  = 0;
00746   aDesiredSize.descent = 0;
00747 }
00748 
00749 nsresult 
00750 nsPageBreakFrame::Reflow(nsPresContext*          aPresContext,
00751                          nsHTMLReflowMetrics&     aDesiredSize,
00752                          const nsHTMLReflowState& aReflowState,
00753                          nsReflowStatus&          aStatus)
00754 {
00755   NS_PRECONDITION(aPresContext, "null pres context");
00756   DO_GLOBAL_REFLOW_COUNT("nsTableFrame", aReflowState.reason);
00757   DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
00758 
00759   aStatus = NS_FRAME_COMPLETE; 
00760   GetDesiredSize(aPresContext, aReflowState, aDesiredSize);
00761   mHaveReflowed = PR_TRUE;
00762 
00763   return NS_OK;
00764 }
00765 
00766 nsIAtom*
00767 nsPageBreakFrame::GetType() const
00768 {
00769   return nsLayoutAtoms::pageBreakFrame; 
00770 }
00771 
00772