1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either of the GNU General Public License Version 2 or later (the "GPL"),
26 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 : #include "nsCOMPtr.h"
38 : #include "nsReadableUtils.h"
39 : #include "nsSimplePageSequence.h"
40 : #include "nsPresContext.h"
41 : #include "gfxContext.h"
42 : #include "nsRenderingContext.h"
43 : #include "nsGkAtoms.h"
44 : #include "nsIPresShell.h"
45 : #include "nsIPrintSettings.h"
46 : #include "nsPageFrame.h"
47 : #include "nsStyleConsts.h"
48 : #include "nsRegion.h"
49 : #include "nsCSSFrameConstructor.h"
50 : #include "nsContentUtils.h"
51 : #include "nsDisplayList.h"
52 : #include "mozilla/Preferences.h"
53 :
54 : // DateTime Includes
55 : #include "nsDateTimeFormatCID.h"
56 :
57 : #define OFFSET_NOT_SET -1
58 :
59 : // Print Options
60 : #include "nsIPrintOptions.h"
61 : #include "nsGfxCIID.h"
62 : #include "nsIServiceManager.h"
63 :
64 : using namespace mozilla;
65 :
66 : static const char sPrintOptionsContractID[] = "@mozilla.org/gfx/printsettings-service;1";
67 :
68 : //
69 :
70 : #include "prlog.h"
71 : #ifdef PR_LOGGING
72 1464 : PRLogModuleInfo * kLayoutPrintingLogMod = PR_NewLogModule("printing-layout");
73 : #define PR_PL(_p1) PR_LOG(kLayoutPrintingLogMod, PR_LOG_DEBUG, _p1)
74 : #else
75 : #define PR_PL(_p1)
76 : #endif
77 :
78 : // This object a shared by all the nsPageFrames
79 : // parented to a SimplePageSequenceFrame
80 0 : nsSharedPageData::nsSharedPageData() :
81 : mDateTimeStr(nsnull),
82 : mHeadFootFont(nsnull),
83 : mPageNumFormat(nsnull),
84 : mPageNumAndTotalsFormat(nsnull),
85 : mDocTitle(nsnull),
86 : mDocURL(nsnull),
87 : mReflowSize(0,0),
88 : mReflowMargin(0,0,0,0),
89 : mExtraMargin(0,0,0,0),
90 : mEdgePaperMargin(0,0,0,0),
91 : mPageContentXMost(0),
92 0 : mPageContentSize(0)
93 : {
94 0 : }
95 :
96 0 : nsSharedPageData::~nsSharedPageData()
97 : {
98 0 : nsMemory::Free(mDateTimeStr);
99 0 : delete mHeadFootFont;
100 0 : nsMemory::Free(mPageNumFormat);
101 0 : nsMemory::Free(mPageNumAndTotalsFormat);
102 0 : if (mDocTitle) nsMemory::Free(mDocTitle);
103 0 : if (mDocURL) nsMemory::Free(mDocURL);
104 0 : }
105 :
106 : nsIFrame*
107 0 : NS_NewSimplePageSequenceFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
108 : {
109 0 : return new (aPresShell) nsSimplePageSequenceFrame(aContext);
110 : }
111 :
112 0 : NS_IMPL_FRAMEARENA_HELPERS(nsSimplePageSequenceFrame)
113 :
114 0 : nsSimplePageSequenceFrame::nsSimplePageSequenceFrame(nsStyleContext* aContext) :
115 : nsContainerFrame(aContext),
116 : mTotalPages(-1),
117 : mSelectionHeight(-1),
118 0 : mYSelOffset(0)
119 : {
120 0 : nscoord halfInch = PresContext()->CSSTwipsToAppUnits(NS_INCHES_TO_TWIPS(0.5));
121 0 : mMargin.SizeTo(halfInch, halfInch, halfInch, halfInch);
122 :
123 : // XXX Unsafe to assume successful allocation
124 0 : mPageData = new nsSharedPageData();
125 : mPageData->mHeadFootFont =
126 : new nsFont(*PresContext()->GetDefaultFont(kGenericFont_serif,
127 0 : aContext->GetStyleFont()->mLanguage));
128 0 : mPageData->mHeadFootFont->size = nsPresContext::CSSPointsToAppUnits(10);
129 :
130 : nsresult rv;
131 0 : mPageData->mPrintOptions = do_GetService(sPrintOptionsContractID, &rv);
132 :
133 : // Doing this here so we only have to go get these formats once
134 0 : SetPageNumberFormat("pagenumber", "%1$d", true);
135 0 : SetPageNumberFormat("pageofpages", "%1$d of %2$d", false);
136 0 : }
137 :
138 0 : nsSimplePageSequenceFrame::~nsSimplePageSequenceFrame()
139 : {
140 0 : delete mPageData;
141 0 : }
142 :
143 0 : NS_QUERYFRAME_HEAD(nsSimplePageSequenceFrame)
144 0 : NS_QUERYFRAME_ENTRY(nsIPageSequenceFrame)
145 0 : NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
146 :
147 : //----------------------------------------------------------------------
148 :
149 : void
150 0 : nsSimplePageSequenceFrame::SetDesiredSize(nsHTMLReflowMetrics& aDesiredSize,
151 : const nsHTMLReflowState& aReflowState,
152 : nscoord aWidth,
153 : nscoord aHeight)
154 : {
155 : // Aim to fill the whole size of the document, not only so we
156 : // can act as a background in print preview but also handle overflow
157 : // in child page frames correctly.
158 : // Use availableWidth so we don't cause a needless horizontal scrollbar.
159 : aDesiredSize.width = NS_MAX(aReflowState.availableWidth,
160 0 : nscoord(aWidth * PresContext()->GetPrintPreviewScale()));
161 0 : aDesiredSize.height = NS_MAX(aReflowState.ComputedHeight(),
162 0 : nscoord(aHeight * PresContext()->GetPrintPreviewScale()));
163 0 : }
164 :
165 : NS_IMETHODIMP
166 0 : nsSimplePageSequenceFrame::Reflow(nsPresContext* aPresContext,
167 : nsHTMLReflowMetrics& aDesiredSize,
168 : const nsHTMLReflowState& aReflowState,
169 : nsReflowStatus& aStatus)
170 : {
171 0 : NS_PRECONDITION(aPresContext->IsRootPaginatedDocument(),
172 : "A Page Sequence is only for real pages");
173 0 : DO_GLOBAL_REFLOW_COUNT("nsSimplePageSequenceFrame");
174 0 : DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
175 0 : NS_FRAME_TRACE_REFLOW_IN("nsSimplePageSequenceFrame::Reflow");
176 :
177 0 : aStatus = NS_FRAME_COMPLETE; // we're always complete
178 :
179 : // Don't do incremental reflow until we've taught tables how to do
180 : // it right in paginated mode.
181 0 : if (!(GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
182 : // Return our desired size
183 0 : SetDesiredSize(aDesiredSize, aReflowState, mSize.width, mSize.height);
184 0 : aDesiredSize.SetOverflowAreasToDesiredBounds();
185 0 : FinishAndStoreOverflow(&aDesiredSize);
186 0 : return NS_OK;
187 : }
188 :
189 : // See if we can get a Print Settings from the Context
190 0 : if (!mPageData->mPrintSettings &&
191 0 : aPresContext->Medium() == nsGkAtoms::print) {
192 0 : mPageData->mPrintSettings = aPresContext->GetPrintSettings();
193 : }
194 :
195 : // now get out margins & edges
196 0 : if (mPageData->mPrintSettings) {
197 0 : nsIntMargin unwriteableTwips;
198 0 : mPageData->mPrintSettings->GetUnwriteableMarginInTwips(unwriteableTwips);
199 0 : NS_ASSERTION(unwriteableTwips.left >= 0 && unwriteableTwips.top >= 0 &&
200 : unwriteableTwips.right >= 0 && unwriteableTwips.bottom >= 0,
201 : "Unwriteable twips should be non-negative");
202 :
203 0 : nsIntMargin marginTwips;
204 0 : mPageData->mPrintSettings->GetMarginInTwips(marginTwips);
205 0 : mMargin = aPresContext->CSSTwipsToAppUnits(marginTwips + unwriteableTwips);
206 :
207 : PRInt16 printType;
208 0 : mPageData->mPrintSettings->GetPrintRange(&printType);
209 0 : mPrintRangeType = printType;
210 :
211 0 : nsIntMargin edgeTwips;
212 0 : mPageData->mPrintSettings->GetEdgeInTwips(edgeTwips);
213 :
214 : // sanity check the values. three inches are sometimes needed
215 0 : PRInt32 inchInTwips = NS_INCHES_TO_INT_TWIPS(3.0);
216 0 : edgeTwips.top = clamped(edgeTwips.top, 0, inchInTwips);
217 0 : edgeTwips.bottom = clamped(edgeTwips.bottom, 0, inchInTwips);
218 0 : edgeTwips.left = clamped(edgeTwips.left, 0, inchInTwips);
219 0 : edgeTwips.right = clamped(edgeTwips.right, 0, inchInTwips);
220 :
221 : mPageData->mEdgePaperMargin =
222 0 : aPresContext->CSSTwipsToAppUnits(edgeTwips + unwriteableTwips);
223 : }
224 :
225 : // *** Special Override ***
226 : // If this is a sub-sdoc (meaning it doesn't take the whole page)
227 : // and if this Document is in the upper left hand corner
228 : // we need to suppress the top margin or it will reflow too small
229 :
230 0 : nsSize pageSize = aPresContext->GetPageSize();
231 :
232 0 : mPageData->mReflowSize = pageSize;
233 : // If we're printing a selection, we need to reflow with
234 : // unconstrained height, to make sure we'll get to the selection
235 : // even if it's beyond the first page of content.
236 0 : if (nsIPrintSettings::kRangeSelection == mPrintRangeType) {
237 0 : mPageData->mReflowSize.height = NS_UNCONSTRAINEDSIZE;
238 : }
239 0 : mPageData->mReflowMargin = mMargin;
240 :
241 : // Compute the size of each page and the x coordinate that each page will
242 : // be placed at
243 0 : nscoord extraThreshold = NS_MAX(pageSize.width, pageSize.height)/10;
244 0 : PRInt32 gapInTwips = Preferences::GetInt("print.print_extra_margin");
245 0 : gapInTwips = NS_MAX(0, gapInTwips);
246 :
247 0 : nscoord extraGap = aPresContext->CSSTwipsToAppUnits(gapInTwips);
248 0 : extraGap = NS_MIN(extraGap, extraThreshold); // clamp to 1/10 of the largest dim of the page
249 :
250 0 : nsMargin extraMargin(0,0,0,0);
251 0 : if (aPresContext->IsScreen()) {
252 0 : extraMargin.SizeTo(extraGap, extraGap, extraGap, extraGap);
253 : }
254 :
255 0 : mPageData->mExtraMargin = extraMargin;
256 :
257 : // We use the CSS "margin" property on the -moz-page pseudoelement
258 : // to determine the space between each page in print preview.
259 : // Keep a running y-offset for each page.
260 0 : nscoord y = 0;
261 0 : nscoord maxXMost = 0;
262 :
263 0 : nsSize availSize(pageSize.width + extraMargin.LeftRight(),
264 0 : pageSize.height + extraMargin.TopBottom());
265 :
266 : // Tile the pages vertically
267 0 : nsHTMLReflowMetrics kidSize;
268 0 : for (nsIFrame* kidFrame = mFrames.FirstChild(); nsnull != kidFrame; ) {
269 : // Set the shared data into the page frame before reflow
270 0 : nsPageFrame * pf = static_cast<nsPageFrame*>(kidFrame);
271 0 : pf->SetSharedPageData(mPageData);
272 :
273 : // Reflow the page
274 : nsHTMLReflowState kidReflowState(aPresContext, aReflowState, kidFrame,
275 0 : availSize);
276 : nsReflowStatus status;
277 :
278 0 : kidReflowState.SetComputedWidth(kidReflowState.availableWidth);
279 : //kidReflowState.SetComputedHeight(kidReflowState.availableHeight);
280 0 : PR_PL(("AV W: %d H: %d\n", kidReflowState.availableWidth, kidReflowState.availableHeight));
281 :
282 0 : nsMargin pageCSSMargin = kidReflowState.mComputedMargin;
283 0 : y += pageCSSMargin.top;
284 0 : const nscoord x = pageCSSMargin.left;
285 :
286 : // Place and size the page. If the page is narrower than our
287 : // max width then center it horizontally
288 0 : ReflowChild(kidFrame, aPresContext, kidSize, kidReflowState, x, y, 0, status);
289 :
290 0 : FinishReflowChild(kidFrame, aPresContext, nsnull, kidSize, x, y, 0);
291 0 : y += kidSize.height;
292 0 : y += pageCSSMargin.bottom;
293 :
294 0 : maxXMost = NS_MAX(maxXMost, x + kidSize.width + pageCSSMargin.right);
295 :
296 : // Is the page complete?
297 0 : nsIFrame* kidNextInFlow = kidFrame->GetNextInFlow();
298 :
299 0 : if (NS_FRAME_IS_FULLY_COMPLETE(status)) {
300 0 : NS_ASSERTION(!kidNextInFlow, "bad child flow list");
301 0 : } else if (!kidNextInFlow) {
302 : // The page isn't complete and it doesn't have a next-in-flow, so
303 : // create a continuing page.
304 : nsIFrame* continuingPage;
305 : nsresult rv = aPresContext->PresShell()->FrameConstructor()->
306 0 : CreateContinuingFrame(aPresContext, kidFrame, this, &continuingPage);
307 0 : if (NS_FAILED(rv)) {
308 : break;
309 : }
310 :
311 : // Add it to our child list
312 0 : mFrames.InsertFrame(nsnull, kidFrame, continuingPage);
313 : }
314 :
315 : // Get the next page
316 0 : kidFrame = kidFrame->GetNextSibling();
317 : }
318 :
319 : // Get Total Page Count
320 : nsIFrame* page;
321 0 : PRInt32 pageTot = 0;
322 0 : for (page = mFrames.FirstChild(); page; page = page->GetNextSibling()) {
323 0 : pageTot++;
324 : }
325 :
326 : // Set Page Number Info
327 0 : PRInt32 pageNum = 1;
328 0 : for (page = mFrames.FirstChild(); page; page = page->GetNextSibling()) {
329 0 : nsPageFrame * pf = static_cast<nsPageFrame*>(page);
330 0 : if (pf != nsnull) {
331 0 : pf->SetPageNumInfo(pageNum, pageTot);
332 : }
333 0 : pageNum++;
334 : }
335 :
336 : // Create current Date/Time String
337 0 : if (!mDateFormatter)
338 0 : mDateFormatter = do_CreateInstance(NS_DATETIMEFORMAT_CONTRACTID);
339 :
340 0 : NS_ENSURE_TRUE(mDateFormatter, NS_ERROR_FAILURE);
341 :
342 0 : nsAutoString formattedDateString;
343 : time_t ltime;
344 0 : time( <ime );
345 0 : if (NS_SUCCEEDED(mDateFormatter->FormatTime(nsnull /* nsILocale* locale */,
346 : kDateFormatShort,
347 : kTimeFormatNoSeconds,
348 : ltime,
349 : formattedDateString))) {
350 0 : PRUnichar * uStr = ToNewUnicode(formattedDateString);
351 0 : SetDateTimeStr(uStr); // memory will be freed
352 : }
353 :
354 : // Return our desired size
355 : // Adjust the reflow size by PrintPreviewScale so the scrollbars end up the
356 : // correct size
357 0 : SetDesiredSize(aDesiredSize, aReflowState, maxXMost, y);
358 :
359 0 : aDesiredSize.SetOverflowAreasToDesiredBounds();
360 0 : FinishAndStoreOverflow(&aDesiredSize);
361 :
362 : // cache the size so we can set the desired size
363 : // for the other reflows that happen
364 0 : mSize.width = maxXMost;
365 0 : mSize.height = y;
366 :
367 0 : NS_FRAME_TRACE_REFLOW_OUT("nsSimplePageSequeceFrame::Reflow", aStatus);
368 0 : NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
369 0 : return NS_OK;
370 : }
371 :
372 : //----------------------------------------------------------------------
373 :
374 : #ifdef DEBUG
375 : NS_IMETHODIMP
376 0 : nsSimplePageSequenceFrame::GetFrameName(nsAString& aResult) const
377 : {
378 0 : return MakeFrameName(NS_LITERAL_STRING("SimplePageSequence"), aResult);
379 : }
380 : #endif
381 :
382 : //====================================================================
383 : //== Asynch Printing
384 : //====================================================================
385 : NS_IMETHODIMP
386 0 : nsSimplePageSequenceFrame::GetCurrentPageNum(PRInt32* aPageNum)
387 : {
388 0 : NS_ENSURE_ARG_POINTER(aPageNum);
389 :
390 0 : *aPageNum = mPageNum;
391 0 : return NS_OK;
392 : }
393 :
394 : NS_IMETHODIMP
395 0 : nsSimplePageSequenceFrame::GetNumPages(PRInt32* aNumPages)
396 : {
397 0 : NS_ENSURE_ARG_POINTER(aNumPages);
398 :
399 0 : *aNumPages = mTotalPages;
400 0 : return NS_OK;
401 : }
402 :
403 : NS_IMETHODIMP
404 0 : nsSimplePageSequenceFrame::IsDoingPrintRange(bool* aDoing)
405 : {
406 0 : NS_ENSURE_ARG_POINTER(aDoing);
407 :
408 0 : *aDoing = mDoingPageRange;
409 0 : return NS_OK;
410 : }
411 :
412 : NS_IMETHODIMP
413 0 : nsSimplePageSequenceFrame::GetPrintRange(PRInt32* aFromPage, PRInt32* aToPage)
414 : {
415 0 : NS_ENSURE_ARG_POINTER(aFromPage);
416 0 : NS_ENSURE_ARG_POINTER(aToPage);
417 :
418 0 : *aFromPage = mFromPageNum;
419 0 : *aToPage = mToPageNum;
420 0 : return NS_OK;
421 : }
422 :
423 : // Helper Function
424 : void
425 0 : nsSimplePageSequenceFrame::SetPageNumberFormat(const char* aPropName, const char* aDefPropVal, bool aPageNumOnly)
426 : {
427 : // Doing this here so we only have to go get these formats once
428 0 : nsXPIDLString pageNumberFormat;
429 : // Now go get the Localized Page Formating String
430 : nsresult rv =
431 : nsContentUtils::GetLocalizedString(nsContentUtils::ePRINTING_PROPERTIES,
432 0 : aPropName, pageNumberFormat);
433 0 : if (NS_FAILED(rv)) { // back stop formatting
434 0 : pageNumberFormat.AssignASCII(aDefPropVal);
435 : }
436 :
437 : // Sets the format into a static data member which will own the memory and free it
438 0 : PRUnichar* uStr = ToNewUnicode(pageNumberFormat);
439 0 : if (uStr != nsnull) {
440 0 : SetPageNumberFormat(uStr, aPageNumOnly); // nsPageFrame will own the memory
441 : }
442 :
443 0 : }
444 :
445 : NS_IMETHODIMP
446 0 : nsSimplePageSequenceFrame::StartPrint(nsPresContext* aPresContext,
447 : nsIPrintSettings* aPrintSettings,
448 : PRUnichar* aDocTitle,
449 : PRUnichar* aDocURL)
450 : {
451 0 : NS_ENSURE_ARG_POINTER(aPresContext);
452 0 : NS_ENSURE_ARG_POINTER(aPrintSettings);
453 :
454 0 : if (!mPageData->mPrintSettings) {
455 0 : mPageData->mPrintSettings = aPrintSettings;
456 : }
457 :
458 : // Only set them if they are not null
459 0 : if (aDocTitle) mPageData->mDocTitle = aDocTitle;
460 0 : if (aDocURL) mPageData->mDocURL = aDocURL;
461 :
462 0 : aPrintSettings->GetStartPageRange(&mFromPageNum);
463 0 : aPrintSettings->GetEndPageRange(&mToPageNum);
464 0 : aPrintSettings->GetPageRanges(mPageRanges);
465 :
466 : mDoingPageRange = nsIPrintSettings::kRangeSpecifiedPageRange == mPrintRangeType ||
467 0 : nsIPrintSettings::kRangeSelection == mPrintRangeType;
468 :
469 : // If printing a range of pages make sure at least the starting page
470 : // number is valid
471 0 : PRInt32 totalPages = mFrames.GetLength();
472 :
473 0 : if (mDoingPageRange) {
474 0 : if (mFromPageNum > totalPages) {
475 0 : return NS_ERROR_INVALID_ARG;
476 : }
477 : }
478 :
479 : // Begin printing of the document
480 0 : nsresult rv = NS_OK;
481 :
482 : // Determine if we are rendering only the selection
483 0 : aPresContext->SetIsRenderingOnlySelection(nsIPrintSettings::kRangeSelection == mPrintRangeType);
484 :
485 :
486 0 : if (mDoingPageRange) {
487 : // XXX because of the hack for making the selection all print on one page
488 : // we must make sure that the page is sized correctly before printing.
489 0 : nscoord height = aPresContext->GetPageSize().height;
490 :
491 0 : PRInt32 pageNum = 1;
492 0 : nscoord y = 0;//mMargin.top;
493 :
494 0 : for (nsIFrame* page = mFrames.FirstChild(); page;
495 : page = page->GetNextSibling()) {
496 0 : if (pageNum >= mFromPageNum && pageNum <= mToPageNum) {
497 0 : nsRect rect = page->GetRect();
498 0 : rect.y = y;
499 0 : rect.height = height;
500 0 : page->SetRect(rect);
501 0 : y += rect.height + mMargin.top + mMargin.bottom;
502 : }
503 0 : pageNum++;
504 : }
505 :
506 : // adjust total number of pages
507 0 : if (nsIPrintSettings::kRangeSelection != mPrintRangeType) {
508 0 : totalPages = pageNum - 1;
509 : }
510 : }
511 :
512 0 : mPageNum = 1;
513 0 : mCurrentPageFrame = mFrames.FirstChild();
514 :
515 0 : if (mTotalPages == -1) {
516 0 : mTotalPages = totalPages;
517 : }
518 :
519 0 : return rv;
520 : }
521 :
522 : NS_IMETHODIMP
523 0 : nsSimplePageSequenceFrame::PrintNextPage()
524 : {
525 : // Print each specified page
526 : // pageNum keeps track of the current page and what pages are printing
527 : //
528 : // printedPageNum keeps track of the current page number to be printed
529 : // Note: When print al the pages or a page range the printed page shows the
530 : // actual page number, when printing selection it prints the page number starting
531 : // with the first page of the selection. For example if the user has a
532 : // selection that starts on page 2 and ends on page 3, the page numbers when
533 : // print are 1 and then two (which is different than printing a page range, where
534 : // the page numbers would have been 2 and then 3)
535 :
536 0 : if (mCurrentPageFrame == nsnull) {
537 0 : return NS_ERROR_FAILURE;
538 : }
539 :
540 : bool printEvenPages, printOddPages;
541 0 : mPageData->mPrintSettings->GetPrintOptions(nsIPrintSettings::kPrintEvenPages, &printEvenPages);
542 0 : mPageData->mPrintSettings->GetPrintOptions(nsIPrintSettings::kPrintOddPages, &printOddPages);
543 :
544 : // Begin printing of the document
545 0 : nsDeviceContext *dc = PresContext()->DeviceContext();
546 :
547 0 : nsresult rv = NS_OK;
548 :
549 : // See whether we should print this page
550 0 : mPrintThisPage = true;
551 :
552 : // If printing a range of pages check whether the page number is in the
553 : // range of pages to print
554 0 : if (mDoingPageRange) {
555 0 : if (mPageNum < mFromPageNum) {
556 0 : mPrintThisPage = false;
557 0 : } else if (mPageNum > mToPageNum) {
558 0 : mPageNum++;
559 0 : mCurrentPageFrame = nsnull;
560 0 : return NS_OK;
561 : } else {
562 0 : PRInt32 length = mPageRanges.Length();
563 :
564 : // Page ranges are pairs (start, end)
565 0 : if (length && (length % 2 == 0)) {
566 0 : mPrintThisPage = false;
567 :
568 : PRInt32 i;
569 0 : for (i = 0; i < length; i += 2) {
570 0 : if (mPageRanges[i] <= mPageNum && mPageNum <= mPageRanges[i+1]) {
571 0 : mPrintThisPage = true;
572 0 : break;
573 : }
574 : }
575 : }
576 : }
577 : }
578 :
579 : // Check for printing of odd and even pages
580 0 : if (mPageNum & 0x1) {
581 0 : if (!printOddPages) {
582 0 : mPrintThisPage = false; // don't print odd numbered page
583 : }
584 : } else {
585 0 : if (!printEvenPages) {
586 0 : mPrintThisPage = false; // don't print even numbered page
587 : }
588 : }
589 :
590 0 : if (nsIPrintSettings::kRangeSelection == mPrintRangeType) {
591 0 : mPrintThisPage = true;
592 : }
593 :
594 0 : if (mPrintThisPage) {
595 : // XXX This is temporary fix for printing more than one page of a selection
596 : // This does a poor man's "dump" pagination (see Bug 89353)
597 : // It has laid out as one long page and now we are just moving or view up/down
598 : // one page at a time and printing the contents of what is exposed by the rect.
599 : // currently this does not work for IFrames
600 : // I will soon improve this to work with IFrames
601 0 : bool continuePrinting = true;
602 : nscoord width, height;
603 0 : width = PresContext()->GetPageSize().width;
604 0 : height = PresContext()->GetPageSize().height;
605 0 : height -= mMargin.top + mMargin.bottom;
606 0 : width -= mMargin.left + mMargin.right;
607 0 : nscoord selectionY = height;
608 0 : nsIFrame* conFrame = mCurrentPageFrame->GetFirstPrincipalChild();
609 0 : if (mSelectionHeight >= 0) {
610 0 : conFrame->SetPosition(conFrame->GetPosition() + nsPoint(0, -mYSelOffset));
611 0 : nsContainerFrame::PositionChildViews(conFrame);
612 : }
613 :
614 : // cast the frame to be a page frame
615 0 : nsPageFrame * pf = static_cast<nsPageFrame*>(mCurrentPageFrame);
616 0 : pf->SetPageNumInfo(mPageNum, mTotalPages);
617 0 : pf->SetSharedPageData(mPageData);
618 :
619 0 : PRInt32 printedPageNum = 1;
620 0 : while (continuePrinting) {
621 0 : if (PresContext()->IsRootPaginatedDocument()) {
622 0 : PR_PL(("\n"));
623 0 : PR_PL(("***************** BeginPage *****************\n"));
624 0 : rv = dc->BeginPage();
625 0 : NS_ENSURE_SUCCESS(rv, rv);
626 : }
627 :
628 0 : PR_PL(("SeqFr::PrintNextPage -> %p PageNo: %d", pf, mPageNum));
629 :
630 0 : nsRefPtr<nsRenderingContext> renderingContext;
631 0 : dc->CreateRenderingContext(*getter_AddRefs(renderingContext));
632 0 : NS_ENSURE_TRUE(renderingContext, NS_ERROR_OUT_OF_MEMORY);
633 :
634 : nsRect drawingRect(nsPoint(0, 0),
635 0 : mCurrentPageFrame->GetSize());
636 0 : nsRegion drawingRegion(drawingRect);
637 : nsLayoutUtils::PaintFrame(renderingContext, mCurrentPageFrame,
638 : drawingRegion, NS_RGBA(0,0,0,0),
639 0 : nsLayoutUtils::PAINT_SYNC_DECODE_IMAGES);
640 :
641 0 : if (mSelectionHeight >= 0 && selectionY < mSelectionHeight) {
642 0 : selectionY += height;
643 0 : printedPageNum++;
644 0 : pf->SetPageNumInfo(printedPageNum, mTotalPages);
645 0 : conFrame->SetPosition(conFrame->GetPosition() + nsPoint(0, -height));
646 0 : nsContainerFrame::PositionChildViews(conFrame);
647 :
648 0 : PR_PL(("***************** End Page (PrintNextPage) *****************\n"));
649 0 : rv = dc->EndPage();
650 0 : NS_ENSURE_SUCCESS(rv, rv);
651 : } else {
652 0 : continuePrinting = false;
653 : }
654 : }
655 : }
656 0 : return rv;
657 : }
658 :
659 : NS_IMETHODIMP
660 0 : nsSimplePageSequenceFrame::DoPageEnd()
661 : {
662 0 : nsresult rv = NS_OK;
663 0 : if (PresContext()->IsRootPaginatedDocument() && mPrintThisPage) {
664 0 : PR_PL(("***************** End Page (DoPageEnd) *****************\n"));
665 0 : rv = PresContext()->DeviceContext()->EndPage();
666 0 : NS_ENSURE_SUCCESS(rv, rv);
667 : }
668 :
669 0 : mPageNum++;
670 :
671 0 : if (mCurrentPageFrame) {
672 0 : mCurrentPageFrame = mCurrentPageFrame->GetNextSibling();
673 : }
674 :
675 0 : return rv;
676 : }
677 :
678 0 : static void PaintPageSequence(nsIFrame* aFrame, nsRenderingContext* aCtx,
679 : const nsRect& aDirtyRect, nsPoint aPt)
680 : {
681 0 : static_cast<nsSimplePageSequenceFrame*>(aFrame)->PaintPageSequence(*aCtx, aDirtyRect, aPt);
682 0 : }
683 :
684 : //------------------------------------------------------------------------------
685 : void
686 0 : nsSimplePageSequenceFrame::PaintPageSequence(nsRenderingContext& aRenderingContext,
687 : const nsRect& aDirtyRect,
688 : nsPoint aPt) {
689 0 : nsRect rect = aDirtyRect;
690 0 : float scale = PresContext()->GetPrintPreviewScale();
691 0 : aRenderingContext.PushState();
692 0 : nsPoint framePos = aPt;
693 0 : aRenderingContext.Translate(framePos);
694 0 : rect -= framePos;
695 0 : aRenderingContext.Scale(scale, scale);
696 0 : rect.ScaleRoundOut(1.0f / scale);
697 :
698 : // Now the rect and the rendering coordinates are are relative to this frame.
699 : // Loop over the pages and paint them.
700 0 : nsIFrame* child = GetFirstPrincipalChild();
701 0 : while (child) {
702 0 : nsPoint pt = child->GetPosition();
703 : // The rendering context has to be translated before each call to PaintFrame
704 0 : aRenderingContext.PushState();
705 0 : aRenderingContext.Translate(pt);
706 : nsLayoutUtils::PaintFrame(&aRenderingContext, child,
707 0 : nsRegion(rect - pt), NS_RGBA(0,0,0,0),
708 0 : nsLayoutUtils::PAINT_SYNC_DECODE_IMAGES);
709 0 : aRenderingContext.PopState();
710 0 : child = child->GetNextSibling();
711 : }
712 :
713 0 : aRenderingContext.PopState();
714 0 : }
715 :
716 : NS_IMETHODIMP
717 0 : nsSimplePageSequenceFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
718 : const nsRect& aDirtyRect,
719 : const nsDisplayListSet& aLists)
720 : {
721 0 : nsresult rv = DisplayBorderBackgroundOutline(aBuilder, aLists);
722 0 : NS_ENSURE_SUCCESS(rv, rv);
723 :
724 : rv = aLists.Content()->AppendNewToTop(new (aBuilder)
725 : nsDisplayGeneric(aBuilder, this, ::PaintPageSequence, "PageSequence",
726 0 : nsDisplayItem::TYPE_PAGE_SEQUENCE));
727 0 : NS_ENSURE_SUCCESS(rv, rv);
728 :
729 0 : return NS_OK;
730 : }
731 :
732 : nsIAtom*
733 0 : nsSimplePageSequenceFrame::GetType() const
734 : {
735 0 : return nsGkAtoms::sequenceFrame;
736 : }
737 :
738 : //------------------------------------------------------------------------------
739 : void
740 0 : nsSimplePageSequenceFrame::SetPageNumberFormat(PRUnichar * aFormatStr, bool aForPageNumOnly)
741 : {
742 0 : NS_ASSERTION(aFormatStr != nsnull, "Format string cannot be null!");
743 0 : NS_ASSERTION(mPageData != nsnull, "mPageData string cannot be null!");
744 :
745 0 : if (aForPageNumOnly) {
746 0 : if (mPageData->mPageNumFormat != nsnull) {
747 0 : nsMemory::Free(mPageData->mPageNumFormat);
748 : }
749 0 : mPageData->mPageNumFormat = aFormatStr;
750 : } else {
751 0 : if (mPageData->mPageNumAndTotalsFormat != nsnull) {
752 0 : nsMemory::Free(mPageData->mPageNumAndTotalsFormat);
753 : }
754 0 : mPageData->mPageNumAndTotalsFormat = aFormatStr;
755 : }
756 0 : }
757 :
758 : //------------------------------------------------------------------------------
759 : void
760 0 : nsSimplePageSequenceFrame::SetDateTimeStr(PRUnichar * aDateTimeStr)
761 : {
762 0 : NS_ASSERTION(aDateTimeStr != nsnull, "DateTime string cannot be null!");
763 0 : NS_ASSERTION(mPageData != nsnull, "mPageData string cannot be null!");
764 :
765 0 : if (mPageData->mDateTimeStr != nsnull) {
766 0 : nsMemory::Free(mPageData->mDateTimeStr);
767 : }
768 0 : mPageData->mDateTimeStr = aDateTimeStr;
769 0 : }
770 :
771 : //------------------------------------------------------------------------------
772 : // For Shrink To Fit
773 : //
774 : // Return the percentage that the page needs to shrink to
775 : //
776 : NS_IMETHODIMP
777 0 : nsSimplePageSequenceFrame::GetSTFPercent(float& aSTFPercent)
778 : {
779 0 : NS_ENSURE_TRUE(mPageData, NS_ERROR_UNEXPECTED);
780 0 : aSTFPercent = 1.0f;
781 0 : if (mPageData && (mPageData->mPageContentXMost > mPageData->mPageContentSize)) {
782 0 : aSTFPercent = float(mPageData->mPageContentSize) / float(mPageData->mPageContentXMost);
783 : }
784 0 : return NS_OK;
785 4392 : }
|