Back to index

lightning-sunbird  0.9+nobinonly
nsSimplePageSequence.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 "nsCOMPtr.h" 
00038 #include "nsReadableUtils.h"
00039 #include "nsSimplePageSequence.h"
00040 #include "nsPresContext.h"
00041 #include "nsIRenderingContext.h"
00042 #include "nsHTMLAtoms.h"
00043 #include "nsIDeviceContext.h"
00044 #include "nsIViewManager.h"
00045 #include "nsIPresShell.h"
00046 #include "nsIFontMetrics.h"
00047 #include "nsIPrintSettings.h"
00048 #include "nsPageFrame.h"
00049 #include "nsStyleConsts.h"
00050 #include "nsRegion.h"
00051 #include "nsLayoutAtoms.h"
00052 #include "nsCSSFrameConstructor.h"
00053 #include "nsContentUtils.h"
00054 
00055 // DateTime Includes
00056 #include "nsDateTimeFormatCID.h"
00057 static NS_DEFINE_CID(kDateTimeFormatCID, NS_DATETIMEFORMAT_CID);
00058 
00059 #define OFFSET_NOT_SET -1
00060 
00061 // Print Options
00062 #include "nsIPrintSettings.h"
00063 #include "nsIPrintOptions.h"
00064 #include "nsGfxCIID.h"
00065 #include "nsIServiceManager.h"
00066 
00067 static const char sPrintOptionsContractID[] = "@mozilla.org/gfx/printsettings-service;1";
00068 
00069 //
00070 
00071 #include "prlog.h"
00072 #ifdef PR_LOGGING 
00073 PRLogModuleInfo * kLayoutPrintingLogMod = PR_NewLogModule("printing-layout");
00074 #define PR_PL(_p1)  PR_LOG(kLayoutPrintingLogMod, PR_LOG_DEBUG, _p1)
00075 #else
00076 #define PR_PL(_p1)
00077 #endif
00078 
00079 // This object a shared by all the nsPageFrames 
00080 // parented to a SimplePageSequenceFrame
00081 nsSharedPageData::nsSharedPageData() :
00082   mDateTimeStr(nsnull),
00083   mHeadFootFont(nsnull),
00084   mPageNumFormat(nsnull),
00085   mPageNumAndTotalsFormat(nsnull),
00086   mDocTitle(nsnull),
00087   mDocURL(nsnull),
00088   mReflowRect(0,0,0,0),
00089   mReflowMargin(0,0,0,0),
00090   mShadowSize(0,0),
00091   mDeadSpaceMargin(0,0,0,0),
00092   mExtraMargin(0,0,0,0),
00093   mEdgePaperMargin(0,0,0,0),
00094   mPageContentXMost(0),
00095   mPageContentSize(0)
00096 {
00097 }
00098 
00099 nsSharedPageData::~nsSharedPageData()
00100 {
00101   nsMemory::Free(mDateTimeStr);
00102   if (mHeadFootFont) delete mHeadFootFont;
00103   nsMemory::Free(mPageNumFormat);
00104   nsMemory::Free(mPageNumAndTotalsFormat);
00105   if (mDocTitle) nsMemory::Free(mDocTitle);
00106   if (mDocURL) nsMemory::Free(mDocURL);
00107 }
00108 
00109 nsresult
00110 NS_NewSimplePageSequenceFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame)
00111 {
00112   NS_PRECONDITION(aNewFrame, "null OUT ptr");
00113   if (nsnull == aNewFrame) {
00114     return NS_ERROR_NULL_POINTER;
00115   }
00116   nsSimplePageSequenceFrame*  it = new (aPresShell) nsSimplePageSequenceFrame;
00117   if (nsnull == it) {
00118     return NS_ERROR_OUT_OF_MEMORY;
00119   }
00120   *aNewFrame = it;
00121   return NS_OK;
00122 }
00123 
00124 nsSimplePageSequenceFrame::nsSimplePageSequenceFrame() :
00125   mIsPrintingSelection(PR_FALSE),
00126   mTotalPages(-1),
00127   mSelectionHeight(-1),
00128   mYSelOffset(0)
00129 {
00130   mStartOffset = OFFSET_NOT_SET;
00131   mEndOffset   = OFFSET_NOT_SET;
00132 
00133   nscoord halfInch = NS_INCHES_TO_TWIPS(0.5);
00134   mMargin.SizeTo(halfInch, halfInch, halfInch, halfInch);
00135 
00136   mPageData = new nsSharedPageData();
00137   NS_ASSERTION(mPageData != nsnull, "Can't be null!");
00138   if (mPageData->mHeadFootFont == nsnull) {
00139     mPageData->mHeadFootFont = new nsFont("serif", NS_FONT_STYLE_NORMAL,NS_FONT_VARIANT_NORMAL,
00140                                NS_FONT_WEIGHT_NORMAL,0,NSIntPointsToTwips(10));
00141   }
00142 
00143   // XXX this code and the object data member "mIsPrintingSelection" is only needed
00144   // for the hack for printing selection where we make the page the max size
00145   nsresult rv;
00146   mPageData->mPrintOptions = do_GetService(sPrintOptionsContractID, &rv);
00147   if (NS_SUCCEEDED(rv) && mPageData->mPrintOptions) {
00148     // now get the default font form the print options
00149     mPageData->mPrintOptions->GetDefaultFont(*mPageData->mHeadFootFont);
00150   }
00151   mSkipPageBegin = PR_FALSE;
00152   mSkipPageEnd   = PR_FALSE;
00153   mPrintThisPage = PR_FALSE;
00154   mOffsetX       = 0;
00155   mOffsetY       = 0;
00156 
00157   // Doing this here so we only have to go get these formats once
00158   SetPageNumberFormat("pagenumber",  "%1$d", PR_TRUE);
00159   SetPageNumberFormat("pageofpages", "%1$d of %2$d", PR_FALSE);
00160 }
00161 
00162 nsSimplePageSequenceFrame::~nsSimplePageSequenceFrame()
00163 {
00164   if (mPageData) delete mPageData;
00165 }
00166 
00167 nsresult
00168 nsSimplePageSequenceFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr)
00169 {
00170   NS_PRECONDITION(0 != aInstancePtr, "null ptr");
00171   if (NULL == aInstancePtr) {
00172     return NS_ERROR_NULL_POINTER;
00173   }
00174   if (aIID.Equals(NS_GET_IID(nsIPageSequenceFrame))) {
00175     *aInstancePtr = (void*)(nsIPageSequenceFrame*)this;
00176     return NS_OK;
00177   }
00178   return nsContainerFrame::QueryInterface(aIID, aInstancePtr);
00179 }
00180 
00181 //----------------------------------------------------------------------
00182 
00183 // Creates a continuing page frame
00184 nsresult
00185 nsSimplePageSequenceFrame::CreateContinuingPageFrame(nsPresContext* aPresContext,
00186                                                      nsIFrame*       aPageFrame,
00187                                                      nsIFrame**      aContinuingPage)
00188 {
00189   // Create the continuing frame
00190   return aPresContext->PresShell()->FrameConstructor()->
00191     CreateContinuingFrame(aPresContext, aPageFrame, this, aContinuingPage);
00192 }
00193 
00194 void
00195 nsSimplePageSequenceFrame::GetEdgePaperMarginCoord(char* aPrefName,
00196                                                    nscoord& aCoord)
00197 {
00198   nsresult rv = mPageData->mPrintOptions->
00199     GetPrinterPrefInt(mPageData->mPrintSettings, 
00200                       NS_ConvertASCIItoUCS2(aPrefName).get(),
00201                       &aCoord);
00202 
00203   if (NS_SUCCEEDED(rv)) {
00204     nscoord inchInTwips = NS_INCHES_TO_TWIPS(1.0);
00205     aCoord = PR_MAX(NS_INCHES_TO_TWIPS(float(aCoord)/100.0f), 0);
00206     aCoord = PR_MIN(aCoord, inchInTwips); // an inch is still probably excessive
00207   }
00208 }
00209 
00210 void
00211 nsSimplePageSequenceFrame::GetEdgePaperMargin(nsMargin& aMargin)
00212 {
00213   aMargin.SizeTo(0,0,0,0);
00214   GetEdgePaperMarginCoord("print_edge_top",    aMargin.top);
00215   GetEdgePaperMarginCoord("print_edge_left",   aMargin.left);
00216   GetEdgePaperMarginCoord("print_edge_bottom", aMargin.bottom);
00217   GetEdgePaperMarginCoord("print_edge_right",  aMargin.right);
00218 }
00219 
00220 NS_IMETHODIMP
00221 nsSimplePageSequenceFrame::Reflow(nsPresContext*          aPresContext,
00222                                   nsHTMLReflowMetrics&     aDesiredSize,
00223                                   const nsHTMLReflowState& aReflowState,
00224                                   nsReflowStatus&          aStatus)
00225 {
00226   DO_GLOBAL_REFLOW_COUNT("nsSimplePageSequenceFrame", aReflowState.reason);
00227   DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
00228   NS_FRAME_TRACE_REFLOW_IN("nsSimplePageSequenceFrame::Reflow");
00229 
00230   aStatus = NS_FRAME_COMPLETE;  // we're always complete
00231 
00232   // absolutely ignore all other types of reflows
00233   // we only want to have done the Initial Reflow
00234   if (eReflowReason_Resize == aReflowState.reason ||
00235       eReflowReason_Incremental == aReflowState.reason ||
00236       eReflowReason_StyleChange == aReflowState.reason ||
00237       eReflowReason_Dirty == aReflowState.reason) {
00238     // Return our desired size
00239     aDesiredSize.height  = mSize.height;
00240     aDesiredSize.width   = mSize.width;
00241     aDesiredSize.ascent  = aDesiredSize.height;
00242     aDesiredSize.descent = 0;
00243     return NS_OK;
00244   }
00245 
00246   // Turn on the scaling of twips so any of the scrollbars
00247   // in the UI no longer get scaled
00248   PRBool isPrintPreview =
00249     aPresContext->Type() == nsPresContext::eContext_PrintPreview;
00250   if (isPrintPreview) {
00251     aPresContext->SetScalingOfTwips(PR_TRUE);
00252   }
00253 
00254   // See if we can get a Print Settings from the Context
00255   if (!mPageData->mPrintSettings &&
00256       aPresContext->Medium() == nsLayoutAtoms::print) {
00257       mPageData->mPrintSettings = aPresContext->GetPrintSettings();
00258   }
00259 
00260   // now get out margins
00261   if (mPageData->mPrintSettings) {
00262     mPageData->mPrintSettings->GetMarginInTwips(mMargin);
00263     PRInt16 printType;
00264     mPageData->mPrintSettings->GetPrintRange(&printType);
00265     mPrintRangeType = printType;
00266     mIsPrintingSelection = nsIPrintSettings::kRangeSelection == printType;
00267   }
00268 
00269   // *** Special Override ***
00270   // If this is a sub-sdoc (meaning it doesn't take the whole page)
00271   // and if this Document is in the upper left hand corner
00272   // we need to suppress the top margin or it will reflow too small
00273   // Start by getting the actual printer page dimensions to see if we are not a whole page
00274   nscoord width, height;
00275   aPresContext->DeviceContext()->GetDeviceSurfaceDimensions(width, height);
00276 
00277   // Compute the size of each page and the x coordinate that each page will
00278   // be placed at
00279   nsRect  pageSize;
00280   nsRect  adjSize;
00281   aPresContext->GetPageDim(&pageSize, &adjSize);
00282 
00283   GetEdgePaperMargin(mPageData->mEdgePaperMargin);
00284   nscoord extraThreshold = PR_MAX(pageSize.width, pageSize.height)/10;
00285   PRInt32 gapInTwips = nsContentUtils::GetIntPref("print.print_extra_margin");
00286 
00287   gapInTwips = PR_MAX(gapInTwips, 0);
00288   gapInTwips = PR_MIN(gapInTwips, extraThreshold); // clamp to 1/10 of the largest dim of the page
00289 
00290   nscoord extraGap = nscoord(gapInTwips);
00291 
00292   nscoord  deadSpaceGap;
00293   GetDeadSpaceValue(&deadSpaceGap);
00294 
00295   nsMargin deadSpaceMargin(0,0,0,0);
00296   nsMargin extraMargin(0,0,0,0);
00297   nsSize   shadowSize(0,0);
00298   if (isPrintPreview) {
00299     if (adjSize.width == width && adjSize.height == height) {
00300       deadSpaceMargin.SizeTo(deadSpaceGap, deadSpaceGap, deadSpaceGap, deadSpaceGap);
00301       extraMargin.SizeTo(extraGap, extraGap, extraGap, extraGap);
00302       nscoord fourPixels = aPresContext->IntScaledPixelsToTwips(4);
00303       shadowSize.SizeTo(fourPixels, fourPixels);
00304     }
00305   }
00306 
00307   mPageData->mShadowSize      = shadowSize;
00308   mPageData->mExtraMargin     = extraMargin;
00309   mPageData->mDeadSpaceMargin = deadSpaceMargin;
00310 
00311   PRBool suppressLeftMargin   = PR_FALSE;
00312   PRBool suppressRightMargin  = PR_FALSE;
00313   PRBool suppressTopMargin    = PR_FALSE;
00314   PRBool suppressBottomMargin = PR_FALSE;
00315 
00316   if (pageSize != adjSize &&
00317       (adjSize.x != 0 || adjSize.y != 0 || adjSize.width != 0 || adjSize.height != 0)) {
00318     suppressLeftMargin   = pageSize.x != adjSize.x || (pageSize.x == adjSize.x && !adjSize.x);
00319     suppressTopMargin    = pageSize.y != adjSize.y || (pageSize.y == adjSize.y && !adjSize.y);
00320     if (pageSize.width  != adjSize.width) {
00321       suppressRightMargin = PR_TRUE;
00322       pageSize.width = adjSize.width;
00323     }
00324     if (pageSize.height != adjSize.height) {
00325       suppressBottomMargin = PR_TRUE;
00326       pageSize.height = adjSize.height;
00327     }
00328   }
00329 
00330   // XXX - Hack Alert
00331   // OK,  so ther eis a selection, we will print the entire selection 
00332   // on one page and then crop the page.
00333   // This means you can never print any selection that is longer than one page
00334   // put it keeps it from page breaking in the middle of your print of the selection
00335   // (see also nsDocumentViewer.cpp)
00336   if (mIsPrintingSelection) {
00337     pageSize.height = NS_UNCONSTRAINEDSIZE;
00338     suppressLeftMargin = PR_FALSE;
00339     suppressTopMargin = PR_FALSE;
00340     suppressRightMargin = PR_FALSE;
00341     suppressBottomMargin = PR_FALSE;
00342   }
00343 
00344 
00345   // only use this local margin for sizing, 
00346   // not for positioning
00347   nsMargin margin(suppressLeftMargin?0:mMargin.left,
00348                   suppressTopMargin?0:mMargin.top,
00349                   suppressRightMargin?0:mMargin.right,
00350                   suppressBottomMargin?0:mMargin.bottom);
00351 
00352   nscoord x = deadSpaceMargin.left;
00353   nscoord y = deadSpaceMargin.top;// Running y-offset for each page
00354 
00355   nsSize reflowPageSize(0,0);
00356 
00357   // See if it's an incremental reflow command
00358   if (eReflowReason_Incremental == aReflowState.reason) {
00359     // XXX Skip Incremental reflow, 
00360     // in fact, all we want is the initial reflow
00361     y = mRect.height;
00362   } else {
00363     // XXX Part of Temporary fix for Bug 127263
00364     nsPageFrame::SetCreateWidget(PR_TRUE);
00365 
00366     nsReflowReason  reflowReason = aReflowState.reason;
00367 
00368     SetPageSizes(pageSize, margin);
00369 
00370     // Tile the pages vertically
00371     nsHTMLReflowMetrics kidSize(nsnull);
00372     for (nsIFrame* kidFrame = mFrames.FirstChild(); nsnull != kidFrame; ) {
00373       // Reflow the page
00374       // The availableHeight always comes in NS_UNCONSTRAINEDSIZE, so we need to check
00375       // the "adjusted rect" to see if that is being reflowed NS_UNCONSTRAINEDSIZE or not
00376       // When it is NS_UNCONSTRAINEDSIZE it means we are reflowing a single page
00377       // to print selection. So this means we want to use NS_UNCONSTRAINEDSIZE without altering it
00378       nsRect actualRect;
00379       nsRect adjRect;
00380       aPresContext->GetPageDim(&actualRect, &adjRect);
00381       nscoord avHeight;
00382       if (adjRect.height == NS_UNCONSTRAINEDSIZE) {
00383         avHeight = NS_UNCONSTRAINEDSIZE;
00384       } else {
00385         avHeight = pageSize.height+deadSpaceMargin.top+deadSpaceMargin.bottom+shadowSize.height+extraMargin.top+extraMargin.bottom;
00386       }
00387       nsSize availSize(pageSize.width+deadSpaceMargin.right+deadSpaceMargin.left+shadowSize.width+extraMargin.right+extraMargin.left, 
00388                        avHeight);
00389       nsHTMLReflowState kidReflowState(aPresContext, aReflowState, kidFrame,
00390                                        availSize, reflowReason);
00391       nsReflowStatus  status;
00392 
00393       kidReflowState.mComputedWidth  = kidReflowState.availableWidth;
00394       //kidReflowState.mComputedHeight = kidReflowState.availableHeight;
00395       PR_PL(("AV W: %d   H: %d\n", kidReflowState.availableWidth, kidReflowState.availableHeight));
00396 
00397       // Set the shared data into the page frame before reflow
00398       nsPageFrame * pf = NS_STATIC_CAST(nsPageFrame*, kidFrame);
00399       pf->SetSharedPageData(mPageData);
00400 
00401       // Place and size the page. If the page is narrower than our
00402       // max width then center it horizontally
00403       ReflowChild(kidFrame, aPresContext, kidSize, kidReflowState, x, y, 0, status);
00404 
00405       reflowPageSize.SizeTo(kidSize.width, kidSize.height);
00406 
00407       FinishReflowChild(kidFrame, aPresContext, nsnull, kidSize, x, y, 0);
00408       y += kidSize.height;
00409 
00410       // XXX Temporary fix for Bug 127263
00411       // This tells the nsPageFrame class to stop creating clipping widgets
00412       // once we reach the 32k boundary for positioning
00413       if (nsPageFrame::GetCreateWidget()) {
00414         float t2p;
00415         t2p = aPresContext->TwipsToPixels();
00416         nscoord xp = NSTwipsToIntPixels(x, t2p);
00417         nscoord yp = NSTwipsToIntPixels(y, t2p);
00418         nsPageFrame::SetCreateWidget(xp < 0x8000 && yp < 0x8000);
00419       }
00420 
00421       // Leave a slight gap between the pages
00422       y += deadSpaceGap;
00423 
00424       // Is the page complete?
00425       nsIFrame* kidNextInFlow = kidFrame->GetNextInFlow();
00426 
00427       if (NS_FRAME_IS_COMPLETE(status)) {
00428         NS_ASSERTION(nsnull == kidNextInFlow, "bad child flow list");
00429       } else if (nsnull == kidNextInFlow) {
00430         // The page isn't complete and it doesn't have a next-in-flow, so
00431         // create a continuing page
00432         nsIFrame* continuingPage;
00433         nsresult rv = CreateContinuingPageFrame(aPresContext, kidFrame,
00434                                                 &continuingPage);
00435         if (NS_FAILED(rv)) {
00436           break;
00437         }
00438         // Add it to our child list
00439         kidFrame->SetNextSibling(continuingPage);
00440         reflowReason = eReflowReason_Initial;
00441       }
00442 
00443       // Get the next page
00444       kidFrame = kidFrame->GetNextSibling();
00445     }
00446 
00447     // Get Total Page Count
00448     nsIFrame* page;
00449     PRInt32 pageTot = 0;
00450     for (page = mFrames.FirstChild(); page; page = page->GetNextSibling()) {
00451       pageTot++;
00452     }
00453 
00454     // Set Page Number Info
00455     PRInt32 pageNum = 1;
00456     for (page = mFrames.FirstChild(); page; page = page->GetNextSibling()) {
00457       nsPageFrame * pf = NS_STATIC_CAST(nsPageFrame*, page);
00458       if (pf != nsnull) {
00459         pf->SetPageNumInfo(pageNum, pageTot);
00460       }
00461       pageNum++;
00462     }
00463 
00464     // Create current Date/Time String
00465     if (!mDateFormatter)
00466       mDateFormatter = do_CreateInstance(kDateTimeFormatCID);
00467 #ifndef WINCE
00468     NS_ENSURE_TRUE(mDateFormatter, NS_ERROR_FAILURE);
00469 
00470     nsAutoString formattedDateString;
00471     time_t ltime;
00472     time( &ltime );
00473     if (NS_SUCCEEDED(mDateFormatter->FormatTime(nsnull /* nsILocale* locale */,
00474                                                 kDateFormatShort,
00475                                                 kTimeFormatNoSeconds,
00476                                                 ltime,
00477                                                 formattedDateString))) {
00478       PRUnichar * uStr = ToNewUnicode(formattedDateString);
00479       SetDateTimeStr(uStr); // memory will be freed
00480     }
00481 #endif
00482   }
00483 
00484   // Return our desired size
00485   aDesiredSize.height  = y;
00486   aDesiredSize.width   = reflowPageSize.width+deadSpaceMargin.right+shadowSize.width+extraMargin.right+extraMargin.left;
00487   aDesiredSize.ascent  = aDesiredSize.height;
00488   aDesiredSize.descent = 0;
00489 
00490   // cache the size so we can set the desired size 
00491   // for the other reflows that happen
00492   mSize.width  = aDesiredSize.width;
00493   mSize.height = aDesiredSize.height;
00494 
00495   // Turn off the scaling of twips so any of the scrollbars
00496   // in the document get scaled
00497   if (isPrintPreview) {
00498     aPresContext->SetScalingOfTwips(PR_FALSE);
00499   }
00500 
00501   NS_FRAME_TRACE_REFLOW_OUT("nsSimplePageSequeceFrame::Reflow", aStatus);
00502   NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
00503   return NS_OK;
00504 }
00505 
00506 //----------------------------------------------------------------------
00507 
00508 #ifdef DEBUG
00509 NS_IMETHODIMP
00510 nsSimplePageSequenceFrame::GetFrameName(nsAString& aResult) const
00511 {
00512   return MakeFrameName(NS_LITERAL_STRING("SimplePageSequence"), aResult);
00513 }
00514 #endif
00515 
00516 //----------------------------------------------------------------------
00517 
00518 NS_IMETHODIMP
00519 nsSimplePageSequenceFrame::SetOffsets(nscoord aStartOffset, nscoord aEndOffset)
00520 {
00521   mStartOffset = aStartOffset;
00522   mEndOffset   = aEndOffset;
00523   return NS_OK;
00524 }
00525 //====================================================================
00526 //== Asynch Printing
00527 //====================================================================
00528 NS_IMETHODIMP
00529 nsSimplePageSequenceFrame::GetCurrentPageNum(PRInt32* aPageNum)
00530 {
00531   NS_ENSURE_ARG_POINTER(aPageNum);
00532 
00533   *aPageNum = mPageNum;
00534   return NS_OK;
00535 }
00536 
00537 NS_IMETHODIMP
00538 nsSimplePageSequenceFrame::GetNumPages(PRInt32* aNumPages)
00539 {
00540   NS_ENSURE_ARG_POINTER(aNumPages);
00541 
00542   *aNumPages = mTotalPages;
00543   return NS_OK;
00544 }
00545 
00546 NS_IMETHODIMP
00547 nsSimplePageSequenceFrame::IsDoingPrintRange(PRBool* aDoing)
00548 {
00549   NS_ENSURE_ARG_POINTER(aDoing);
00550 
00551   *aDoing = mDoingPageRange;
00552   return NS_OK;
00553 }
00554 
00555 NS_IMETHODIMP
00556 nsSimplePageSequenceFrame::GetPrintRange(PRInt32* aFromPage, PRInt32* aToPage)
00557 {
00558   NS_ENSURE_ARG_POINTER(aFromPage);
00559   NS_ENSURE_ARG_POINTER(aToPage);
00560 
00561   *aFromPage = mFromPageNum;
00562   *aToPage   = mToPageNum;
00563   return NS_OK;
00564 }
00565 
00566 // Helper Function
00567 void 
00568 nsSimplePageSequenceFrame::SetPageNumberFormat(const char* aPropName, const char* aDefPropVal, PRBool aPageNumOnly)
00569 {
00570   // Doing this here so we only have to go get these formats once
00571   nsXPIDLString pageNumberFormat;
00572   // Now go get the Localized Page Formating String
00573   nsresult rv =
00574     nsContentUtils::GetLocalizedString(nsContentUtils::ePRINTING_PROPERTIES,
00575                                        aPropName, pageNumberFormat);
00576   if (NS_FAILED(rv)) { // back stop formatting
00577     pageNumberFormat.AssignASCII(aDefPropVal);
00578   }
00579 
00580   // Sets the format into a static data memeber which will own the memory and free it
00581   PRUnichar* uStr = ToNewUnicode(pageNumberFormat);
00582   if (uStr != nsnull) {
00583     SetPageNumberFormat(uStr, aPageNumOnly); // nsPageFrame will own the memory
00584   }
00585 
00586 }
00587 
00588 NS_IMETHODIMP
00589 nsSimplePageSequenceFrame::StartPrint(nsPresContext*   aPresContext,
00590                                       nsIPrintSettings* aPrintSettings,
00591                                       PRUnichar*        aDocTitle,
00592                                       PRUnichar*        aDocURL)
00593 {
00594   NS_ENSURE_ARG_POINTER(aPresContext);
00595   NS_ENSURE_ARG_POINTER(aPrintSettings);
00596 
00597   if (!mPageData->mPrintSettings) {
00598     mPageData->mPrintSettings = aPrintSettings;
00599   }
00600 
00601   // Only set them if they are not null
00602   if (aDocTitle) mPageData->mDocTitle = aDocTitle;
00603   if (aDocURL) mPageData->mDocURL   = aDocURL;
00604 
00605   aPrintSettings->GetMarginInTwips(mMargin);
00606 
00607   aPrintSettings->GetStartPageRange(&mFromPageNum);
00608   aPrintSettings->GetEndPageRange(&mToPageNum);
00609   aPrintSettings->GetMarginInTwips(mMargin);
00610 
00611   mDoingPageRange = nsIPrintSettings::kRangeSpecifiedPageRange == mPrintRangeType ||
00612                     nsIPrintSettings::kRangeSelection == mPrintRangeType;
00613 
00614   // If printing a range of pages make sure at least the starting page
00615   // number is valid
00616   PRInt32 totalPages = mFrames.GetLength();
00617 
00618   if (mDoingPageRange) {
00619     if (mFromPageNum > totalPages) {
00620       return NS_ERROR_INVALID_ARG;
00621     }
00622   }
00623 
00624   // Begin printing of the document
00625   nsresult rv = NS_OK;
00626 
00627 #if defined(DEBUG_rods) || defined(DEBUG_dcone)
00628   {
00629     nsIView* seqView = GetView();
00630     nsRect rect = GetRect();
00631     PR_PL(("Seq Frame: %p - [%5d,%5d,%5d,%5d] ", this, rect.x, rect.y, rect.width, rect.height));
00632     PR_PL(("view: %p ", seqView));
00633     if (seqView) {
00634       nsRect viewRect = seqView->GetBounds();
00635       PR_PL((" [%5d,%5d,%5d,%5d]", viewRect.x, viewRect.y, viewRect.width, viewRect.height));
00636     }
00637     PR_PL(("\n"));
00638   }
00639 
00640   {
00641     PRInt32 pageNum = 1;
00642     for (nsIFrame* page = mFrames.FirstChild(); page;
00643          page = page->GetNextSibling()) {
00644       nsIView* view = page->GetView();
00645       NS_ASSERTION(view, "no page view");
00646       nsRect rect = page->GetRect();
00647       nsRect viewRect = view->GetBounds();
00648       PR_PL((" Page: %p  No: %d - [%5d,%5d,%5d,%5d] ", page, pageNum, rect.x, rect.y, rect.width, rect.height));
00649       PR_PL((" [%5d,%5d,%5d,%5d]\n", viewRect.x, viewRect.y, viewRect.width, viewRect.height));
00650       pageNum++;
00651     }
00652   }
00653   //printf("***** Setting aPresContext %p is painting selection %d\n", aPresContext, nsIPrintSettings::kRangeSelection == mPrintRangeType);
00654 #endif
00655 
00656   // Determine if we are rendering only the selection
00657   aPresContext->SetIsRenderingOnlySelection(nsIPrintSettings::kRangeSelection == mPrintRangeType);
00658 
00659 
00660   if (mDoingPageRange) {
00661     // XXX because of the hack for making the selection all print on one page
00662     // we must make sure that the page is sized correctly before printing.
00663     PRInt32 width, height;
00664     aPresContext->DeviceContext()->GetDeviceSurfaceDimensions(width, height);
00665 
00666     PRInt32 pageNum = 1;
00667     nscoord y = 0;//mMargin.top;
00668 
00669     for (nsIFrame* page = mFrames.FirstChild(); page;
00670          page = page->GetNextSibling()) {
00671       nsIView* view = page->GetView();
00672       NS_ASSERTION(view, "no page view");
00673 
00674       nsIViewManager* vm = view->GetViewManager();
00675       NS_ASSERTION(vm, "no view manager");
00676 
00677       if (pageNum < mFromPageNum || pageNum > mToPageNum) {
00678         // Hide the pages that won't be printed to the Viewmanager
00679         // doesn't put them in the display list. Also, makde
00680         // sure the child views don't get asked to print
00681         // but my guess is that there won't be any
00682         vm->SetViewVisibility(view, nsViewVisibility_kHide);
00683         nsRegion emptyRegion;
00684         vm->SetViewChildClipRegion(view, &emptyRegion);
00685       } else {
00686         nsRect rect = page->GetRect();
00687         rect.y = y;
00688         rect.height = height;
00689         page->SetRect(rect);
00690 
00691         nsRect viewRect = view->GetBounds();
00692         viewRect.y = y;
00693         viewRect.height = height;
00694         vm->MoveViewTo(view, viewRect.x, viewRect.y);
00695         viewRect.x = 0;
00696         viewRect.y = 0;
00697         vm->ResizeView(view, viewRect);
00698         y += rect.height + mMargin.top + mMargin.bottom;
00699       }
00700       pageNum++;
00701     }
00702 
00703     // adjust total number of pages
00704     if (nsIPrintSettings::kRangeSelection != mPrintRangeType) {
00705       totalPages = pageNum - 1;
00706     }
00707   }
00708 
00709   // XXX - This wouldn't have to be done each time
00710   // but it isn't that expensive and this the best place 
00711   // to have access to a localized file properties file
00712   // 
00713   // Note: because this is done here it makes a little bit harder
00714   // to have UI for setting the header/footer font name and size
00715   //
00716   // Get default font name and size to be used for the headers and footers
00717   nsXPIDLString fontName;
00718   rv = nsContentUtils::GetLocalizedString(nsContentUtils::ePRINTING_PROPERTIES,
00719                                          "fontname", fontName);
00720   if (NS_FAILED(rv)) {
00721     fontName.AssignLiteral("serif");
00722   }
00723 
00724   nsXPIDLString fontSizeStr;
00725   nscoord      pointSize = 10;;
00726   rv = nsContentUtils::GetLocalizedString(nsContentUtils::ePRINTING_PROPERTIES,
00727                                           "fontsize", fontSizeStr);
00728   if (NS_SUCCEEDED(rv)) {
00729     PRInt32 errCode;
00730     pointSize = fontSizeStr.ToInteger(&errCode);
00731     if (NS_FAILED(errCode)) {
00732       pointSize = 10;
00733     }
00734   }
00735   mPageData->mPrintOptions->SetFontNamePointSize(fontName, pointSize);
00736 
00737   // Doing this here so we only have to go get these formats once
00738   SetPageNumberFormat("pagenumber",  "%1$d", PR_TRUE);
00739   SetPageNumberFormat("pageofpages", "%1$d of %2$d", PR_FALSE);
00740 
00741   mPageNum          = 1;
00742   mPrintedPageNum   = 1;
00743   mCurrentPageFrame = mFrames.FirstChild();
00744 
00745   if (mTotalPages == -1) {
00746     mTotalPages = totalPages;
00747   }
00748 
00749   return rv;
00750 }
00751 
00752 NS_IMETHODIMP
00753 nsSimplePageSequenceFrame::PrintNextPage(nsPresContext*  aPresContext)
00754 {
00755   NS_ENSURE_ARG_POINTER(aPresContext);
00756 
00757   // Print each specified page
00758   // pageNum keeps track of the current page and what pages are printing
00759   //
00760   // printedPageNum keeps track of the current page number to be printed
00761   // Note: When print al the pages or a page range the printed page shows the
00762   // actual page number, when printing selection it prints the page number starting
00763   // with the first page of the selection. For example if the user has a 
00764   // selection that starts on page 2 and ends on page 3, the page numbers when
00765   // print are 1 and then two (which is different than printing a page range, where
00766   // the page numbers would have been 2 and then 3)
00767 
00768   if (mCurrentPageFrame == nsnull) {
00769     return NS_ERROR_FAILURE;
00770   }
00771 
00772   PRBool printEvenPages, printOddPages;
00773   mPageData->mPrintSettings->GetPrintOptions(nsIPrintSettings::kPrintEvenPages, &printEvenPages);
00774   mPageData->mPrintSettings->GetPrintOptions(nsIPrintSettings::kPrintOddPages, &printOddPages);
00775 
00776   // Begin printing of the document
00777   nsIDeviceContext *dc = aPresContext->DeviceContext();
00778   NS_ASSERTION(dc, "nsIDeviceContext can't be NULL!");
00779 
00780   nsIViewManager* vm = aPresContext->GetViewManager();
00781   NS_ASSERTION(vm, "nsIViewManager can't be NULL!");
00782 
00783   nsresult rv = NS_OK;
00784 
00785   // See whether we should print this page
00786   mPrintThisPage = PR_TRUE;
00787 
00788   // If printing a range of pages check whether the page number is in the
00789   // range of pages to print
00790   if (mDoingPageRange) {
00791     if (mPageNum < mFromPageNum) {
00792       mPrintThisPage = PR_FALSE;
00793     } else if (mPageNum > mToPageNum) {
00794       mPageNum++;
00795       mCurrentPageFrame = nsnull;
00796       return NS_OK;
00797     }
00798   }
00799 
00800   // Check for printing of odd and even pages
00801   if (mPageNum & 0x1) {
00802     if (!printOddPages) {
00803       mPrintThisPage = PR_FALSE;  // don't print odd numbered page
00804     }
00805   } else {
00806     if (!printEvenPages) {
00807       mPrintThisPage = PR_FALSE;  // don't print even numbered page
00808     }
00809   }
00810 
00811   if (mPrintThisPage) {
00812     // XXX This is temporary fix for printing more than one page of a selection
00813     // This does a poor man's "dump" pagination (see Bug 89353)
00814     // It has laid out as one long page and now we are just moving or view up/down 
00815     // one page at a time and printing the contents of what is exposed by the rect.
00816     // currently this does not work for IFrames
00817     // I will soon improve this to work with IFrames 
00818     PRBool  continuePrinting = PR_TRUE;
00819     PRInt32 width, height;
00820     dc->GetDeviceSurfaceDimensions(width, height);
00821     nsRect clipRect(0, 0, width, height);
00822     nsRect slidingRect(-1, -1, -1, -1);
00823     height -= mMargin.top + mMargin.bottom;
00824     width  -= mMargin.left + mMargin.right;
00825     nscoord selectionY = height;
00826     nsIView* containerView = nsnull;
00827     nsRect   containerRect;
00828     if (mSelectionHeight > -1) {
00829       nsIFrame* childFrame = mFrames.FirstChild();
00830       nsIFrame* conFrame = childFrame->GetFirstChild(nsnull);
00831       containerView = conFrame->GetView();
00832       NS_ASSERTION(containerView, "Container view can't be null!");
00833       containerRect = containerView->GetBounds();
00834       containerRect.y -= mYSelOffset;
00835       slidingRect.SetRect(0,mYSelOffset,width,height);
00836       
00837       vm->MoveViewTo(containerView, containerRect.x, containerRect.y);
00838       nsRect r(0, 0, containerRect.width, containerRect.height);
00839       vm->ResizeView(containerView, r, PR_FALSE);
00840       clipRect.SetRect(mMargin.left, mMargin.right, width, height);
00841     }
00842 
00843     while (continuePrinting) {
00844       if (!mSkipPageBegin) {
00845         PR_PL(("\n"));
00846         PR_PL(("***************** BeginPage *****************\n"));
00847         rv = dc->BeginPage();
00848         if (NS_FAILED(rv)) {
00849           return rv;
00850         }
00851       }
00852 
00853       // cast the frame to be a page frame
00854       nsPageFrame * pf = NS_STATIC_CAST(nsPageFrame*, mCurrentPageFrame);
00855       if (pf != nsnull) {
00856         pf->SetPageNumInfo(mPrintedPageNum, mTotalPages);
00857         pf->SetSharedPageData(mPageData);
00858         if (mSelectionHeight > -1) {
00859           pf->SetClipRect(&slidingRect);
00860         }
00861       }
00862 
00863       // Print the page
00864       nsIView* view = mCurrentPageFrame->GetView();
00865 
00866       NS_ASSERTION(view, "no page view");
00867 
00868       PR_PL(("SeqFr::Paint -> %p PageNo: %d  View: %p", pf, mPageNum, view));
00869       PR_PL((" At: %d,%d\n", mMargin.left+mOffsetX, mMargin.top+mOffsetY));
00870 
00871       vm->SetViewContentTransparency(view, PR_FALSE);
00872 
00873       vm->Display(view, mOffsetX, mOffsetY, clipRect);
00874 
00875       // this view was printed and since display set the origin 
00876       // 0,0 there is a danger that this view can be printed again
00877       // If it is a sibling to another page/view.  Setting the visibility
00878       // to hide will keep this page from printing again - dwc
00879       //
00880       // XXX Doesn't seem like we need to do this anymore
00881       //view->SetVisibility(nsViewVisibility_kHide);
00882 
00883       if (!mSkipPageEnd) {
00884         PR_PL(("***************** End Page (PrintNextPage) *****************\n"));
00885         rv = dc->EndPage();
00886         if (NS_FAILED(rv)) {
00887           return rv;
00888         }
00889       }
00890 
00891       if (mSelectionHeight > -1 && selectionY < mSelectionHeight) {
00892         selectionY += height;
00893 
00894         mPrintedPageNum++;
00895         pf->SetPageNumInfo(mPrintedPageNum, mTotalPages);
00896         containerRect.y -= height;
00897         containerRect.height += height;
00898         vm->MoveViewTo(containerView, containerRect.x, containerRect.y);
00899         nsRect r(0, 0, containerRect.width, containerRect.height);
00900         vm->ResizeView(containerView, r, PR_FALSE);
00901         if (pf != nsnull) {
00902           slidingRect.y += height;
00903         }
00904 
00905       } else {
00906         continuePrinting = PR_FALSE;
00907       }
00908     }
00909   }
00910 
00911   if (!mSkipPageEnd) {
00912     if (nsIPrintSettings::kRangeSelection != mPrintRangeType ||
00913         (nsIPrintSettings::kRangeSelection == mPrintRangeType && mPrintThisPage)) {
00914       mPrintedPageNum++;
00915     }
00916 
00917     mPageNum++;
00918     mCurrentPageFrame = mCurrentPageFrame->GetNextSibling();
00919   }
00920 
00921   return rv;
00922 }
00923 
00924 NS_IMETHODIMP
00925 nsSimplePageSequenceFrame::DoPageEnd(nsPresContext*  aPresContext)
00926 {
00927        nsresult rv = NS_OK;
00928        
00929   if (mPrintThisPage) {
00930     if(mSkipPageEnd){
00931            PR_PL(("***************** End Page (DoPageEnd) *****************\n"));
00932       nsresult rv = aPresContext->DeviceContext()->EndPage();
00933            if (NS_FAILED(rv)) {
00934              return rv;
00935       }
00936     }
00937   }
00938 
00939   if (nsIPrintSettings::kRangeSelection != mPrintRangeType ||
00940       (nsIPrintSettings::kRangeSelection == mPrintRangeType && mPrintThisPage)) {
00941     mPrintedPageNum++;
00942   }
00943 
00944   mPageNum++;
00945   
00946   if (mCurrentPageFrame) {
00947     mCurrentPageFrame = mCurrentPageFrame->GetNextSibling();
00948   }
00949   
00950   return rv;
00951 }
00952 
00953 NS_IMETHODIMP
00954 nsSimplePageSequenceFrame::SuppressHeadersAndFooters(PRBool aDoSup)
00955 {
00956   for (nsIFrame* f = mFrames.FirstChild(); f; f = f->GetNextSibling()) {
00957     nsPageFrame * pf = NS_STATIC_CAST(nsPageFrame*, f);
00958     if (pf != nsnull) {
00959       pf->SuppressHeadersAndFooters(aDoSup);
00960     }
00961   }
00962   return NS_OK;
00963 }
00964 
00965 NS_IMETHODIMP
00966 nsSimplePageSequenceFrame::SetClipRect(nsPresContext*  aPresContext, nsRect* aRect)
00967 {
00968   for (nsIFrame* f = mFrames.FirstChild(); f; f = f->GetNextSibling()) {
00969     nsPageFrame * pf = NS_STATIC_CAST(nsPageFrame*, f);
00970     if (pf != nsnull) {
00971       pf->SetClipRect(aRect);
00972     }
00973   }
00974   return NS_OK;
00975 }
00976 
00977 //------------------------------------------------------------------------------
00978 NS_IMETHODIMP
00979 nsSimplePageSequenceFrame::Paint(nsPresContext*      aPresContext,
00980                                  nsIRenderingContext& aRenderingContext,
00981                                  const nsRect&        aDirtyRect,
00982                                  nsFramePaintLayer    aWhichLayer)
00983 {
00984   aRenderingContext.PushState();
00985   aRenderingContext.SetColor(NS_RGB(255,255,255));
00986 
00987 
00988   if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) {
00989     nsRect rect = mRect;
00990     aRenderingContext.SetColor(NS_RGB(255,255,255));
00991     rect.x = 0;
00992     rect.y = 0;
00993     aRenderingContext.FillRect(rect);
00994   }
00995 
00996   nsresult rv = nsContainerFrame::Paint(aPresContext, aRenderingContext, aDirtyRect, aWhichLayer);
00997 
00998   aRenderingContext.PopState();
00999   return rv;
01000 }
01001 
01002 nsIAtom*
01003 nsSimplePageSequenceFrame::GetType() const
01004 {
01005   return nsLayoutAtoms::sequenceFrame; 
01006 }
01007 
01008 //------------------------------------------------------------------------------
01009 void
01010 nsSimplePageSequenceFrame::SetPageNumberFormat(PRUnichar * aFormatStr, PRBool aForPageNumOnly)
01011 { 
01012   NS_ASSERTION(aFormatStr != nsnull, "Format string cannot be null!");
01013   NS_ASSERTION(mPageData != nsnull, "mPageData string cannot be null!");
01014 
01015   if (aForPageNumOnly) {
01016     if (mPageData->mPageNumFormat != nsnull) {
01017       nsMemory::Free(mPageData->mPageNumFormat);
01018     }
01019     mPageData->mPageNumFormat = aFormatStr;
01020   } else {
01021     if (mPageData->mPageNumAndTotalsFormat != nsnull) {
01022       nsMemory::Free(mPageData->mPageNumAndTotalsFormat);
01023     }
01024     mPageData->mPageNumAndTotalsFormat = aFormatStr;
01025   }
01026 }
01027 
01028 //------------------------------------------------------------------------------
01029 void
01030 nsSimplePageSequenceFrame::SetDateTimeStr(PRUnichar * aDateTimeStr)
01031 { 
01032   NS_ASSERTION(aDateTimeStr != nsnull, "DateTime string cannot be null!");
01033   NS_ASSERTION(mPageData != nsnull, "mPageData string cannot be null!");
01034 
01035   if (mPageData->mDateTimeStr != nsnull) {
01036     nsMemory::Free(mPageData->mDateTimeStr);
01037   }
01038   mPageData->mDateTimeStr = aDateTimeStr;
01039 }
01040 
01041 //------------------------------------------------------------------------------
01042 void
01043 nsSimplePageSequenceFrame::SetPageSizes(const nsRect& aRect, const nsMargin& aMarginRect)
01044 { 
01045   NS_ASSERTION(mPageData != nsnull, "mPageData string cannot be null!");
01046 
01047   mPageData->mReflowRect   = aRect;
01048   mPageData->mReflowMargin = aMarginRect;
01049 }
01050 
01051 //------------------------------------------------------------------------------
01052 // For Shrink To Fit
01053 //
01054 // Return the percentage that the page needs to shrink to 
01055 //
01056 NS_IMETHODIMP
01057 nsSimplePageSequenceFrame::GetSTFPercent(float& aSTFPercent)
01058 {
01059   NS_ENSURE_TRUE(mPageData, NS_ERROR_UNEXPECTED);
01060   aSTFPercent = 1.0f;
01061   if (mPageData && (mPageData->mPageContentXMost > mPageData->mPageContentSize)) {
01062     aSTFPercent = float(mPageData->mPageContentSize) / float(mPageData->mPageContentXMost);
01063   }
01064   return NS_OK;
01065 }