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 :
38 : #include "nsPageFrame.h"
39 : #include "nsPresContext.h"
40 : #include "nsStyleContext.h"
41 : #include "nsRenderingContext.h"
42 : #include "nsGkAtoms.h"
43 : #include "nsIPresShell.h"
44 : #include "nsCSSFrameConstructor.h"
45 : #include "nsReadableUtils.h"
46 : #include "nsPageContentFrame.h"
47 : #include "nsDisplayList.h"
48 : #include "nsLayoutUtils.h" // for function BinarySearchForPosition
49 : #include "nsCSSRendering.h"
50 : #include "nsSimplePageSequence.h" // for nsSharedPageData
51 : #include "nsTextFormatter.h" // for page number localization formatting
52 : #ifdef IBMBIDI
53 : #include "nsBidiUtils.h"
54 : #endif
55 : #include "nsIPrintSettings.h"
56 : #include "nsRegion.h"
57 :
58 : #include "prlog.h"
59 : #ifdef PR_LOGGING
60 : extern PRLogModuleInfo * kLayoutPrintingLogMod;
61 : #define PR_PL(_p1) PR_LOG(kLayoutPrintingLogMod, PR_LOG_DEBUG, _p1)
62 : #else
63 : #define PR_PL(_p1)
64 : #endif
65 :
66 : nsIFrame*
67 0 : NS_NewPageFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
68 : {
69 0 : return new (aPresShell) nsPageFrame(aContext);
70 : }
71 :
72 0 : NS_IMPL_FRAMEARENA_HELPERS(nsPageFrame)
73 :
74 0 : nsPageFrame::nsPageFrame(nsStyleContext* aContext)
75 0 : : nsContainerFrame(aContext)
76 : {
77 0 : }
78 :
79 0 : nsPageFrame::~nsPageFrame()
80 : {
81 0 : }
82 :
83 0 : NS_IMETHODIMP nsPageFrame::Reflow(nsPresContext* aPresContext,
84 : nsHTMLReflowMetrics& aDesiredSize,
85 : const nsHTMLReflowState& aReflowState,
86 : nsReflowStatus& aStatus)
87 : {
88 0 : DO_GLOBAL_REFLOW_COUNT("nsPageFrame");
89 0 : DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
90 0 : aStatus = NS_FRAME_COMPLETE; // initialize out parameter
91 :
92 0 : NS_ASSERTION(mFrames.FirstChild() &&
93 : nsGkAtoms::pageContentFrame == mFrames.FirstChild()->GetType(),
94 : "pageFrame must have a pageContentFrame child");
95 :
96 : // Resize our frame allowing it only to be as big as we are
97 : // XXX Pay attention to the page's border and padding...
98 0 : if (mFrames.NotEmpty()) {
99 0 : nsIFrame* frame = mFrames.FirstChild();
100 : // When the reflow size is NS_UNCONSTRAINEDSIZE it means we are reflowing
101 : // a single page to print selection. So this means we want to use
102 : // NS_UNCONSTRAINEDSIZE without altering it
103 : nscoord avHeight;
104 0 : if (mPD->mReflowSize.height == NS_UNCONSTRAINEDSIZE) {
105 0 : avHeight = NS_UNCONSTRAINEDSIZE;
106 : } else {
107 0 : avHeight = mPD->mReflowSize.height - mPD->mReflowMargin.TopBottom();
108 : }
109 0 : nsSize maxSize(mPD->mReflowSize.width - mPD->mReflowMargin.LeftRight(),
110 0 : avHeight);
111 0 : float scale = aPresContext->GetPageScale();
112 0 : maxSize.width = NSToCoordCeil(maxSize.width / scale);
113 0 : if (maxSize.height != NS_UNCONSTRAINEDSIZE) {
114 0 : maxSize.height = NSToCoordCeil(maxSize.height / scale);
115 : }
116 : // Get the number of Twips per pixel from the PresContext
117 0 : nscoord onePixelInTwips = nsPresContext::CSSPixelsToAppUnits(1);
118 : // insurance against infinite reflow, when reflowing less than a pixel
119 : // XXX Shouldn't we do something more friendly when invalid margins
120 : // are set?
121 0 : if (maxSize.width < onePixelInTwips || maxSize.height < onePixelInTwips) {
122 0 : aDesiredSize.width = 0;
123 0 : aDesiredSize.height = 0;
124 0 : NS_WARNING("Reflow aborted; no space for content");
125 0 : return NS_OK;
126 : }
127 :
128 0 : nsHTMLReflowState kidReflowState(aPresContext, aReflowState, frame, maxSize);
129 0 : kidReflowState.mFlags.mIsTopOfPage = true;
130 0 : kidReflowState.mFlags.mTableIsSplittable = true;
131 :
132 : // calc location of frame
133 0 : nscoord xc = mPD->mReflowMargin.left + mPD->mExtraMargin.left;
134 0 : nscoord yc = mPD->mReflowMargin.top + mPD->mExtraMargin.top;
135 :
136 : // Get the child's desired size
137 0 : ReflowChild(frame, aPresContext, aDesiredSize, kidReflowState, xc, yc, 0, aStatus);
138 :
139 : // Place and size the child
140 0 : FinishReflowChild(frame, aPresContext, &kidReflowState, aDesiredSize, xc, yc, 0);
141 :
142 0 : NS_ASSERTION(!NS_FRAME_IS_FULLY_COMPLETE(aStatus) ||
143 : !frame->GetNextInFlow(), "bad child flow list");
144 : }
145 0 : PR_PL(("PageFrame::Reflow %p ", this));
146 0 : PR_PL(("[%d,%d][%d,%d]\n", aDesiredSize.width, aDesiredSize.height, aReflowState.availableWidth, aReflowState.availableHeight));
147 :
148 : // Return our desired size
149 0 : aDesiredSize.width = aReflowState.availableWidth;
150 0 : if (aReflowState.availableHeight != NS_UNCONSTRAINEDSIZE) {
151 0 : aDesiredSize.height = aReflowState.availableHeight;
152 : }
153 :
154 0 : aDesiredSize.SetOverflowAreasToDesiredBounds();
155 0 : FinishAndStoreOverflow(&aDesiredSize);
156 :
157 0 : PR_PL(("PageFrame::Reflow %p ", this));
158 0 : PR_PL(("[%d,%d]\n", aReflowState.availableWidth, aReflowState.availableHeight));
159 :
160 0 : NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
161 0 : return NS_OK;
162 : }
163 :
164 : nsIAtom*
165 0 : nsPageFrame::GetType() const
166 : {
167 0 : return nsGkAtoms::pageFrame;
168 : }
169 :
170 : #ifdef DEBUG
171 : NS_IMETHODIMP
172 0 : nsPageFrame::GetFrameName(nsAString& aResult) const
173 : {
174 0 : return MakeFrameName(NS_LITERAL_STRING("Page"), aResult);
175 : }
176 : #endif
177 :
178 : void
179 0 : nsPageFrame::ProcessSpecialCodes(const nsString& aStr, nsString& aNewStr)
180 : {
181 :
182 0 : aNewStr = aStr;
183 :
184 : // Search to see if the &D code is in the string
185 : // then subst in the current date/time
186 0 : NS_NAMED_LITERAL_STRING(kDate, "&D");
187 0 : if (aStr.Find(kDate) != kNotFound) {
188 0 : if (mPD->mDateTimeStr != nsnull) {
189 0 : aNewStr.ReplaceSubstring(kDate.get(), mPD->mDateTimeStr);
190 : } else {
191 0 : aNewStr.ReplaceSubstring(kDate.get(), EmptyString().get());
192 : }
193 : }
194 :
195 : // NOTE: Must search for &PT before searching for &P
196 : //
197 : // Search to see if the "page number and page" total code are in the string
198 : // and replace the page number and page total code with the actual
199 : // values
200 0 : NS_NAMED_LITERAL_STRING(kPageAndTotal, "&PT");
201 0 : if (aStr.Find(kPageAndTotal) != kNotFound) {
202 0 : PRUnichar * uStr = nsTextFormatter::smprintf(mPD->mPageNumAndTotalsFormat, mPageNum, mTotNumPages);
203 0 : aNewStr.ReplaceSubstring(kPageAndTotal.get(), uStr);
204 0 : nsMemory::Free(uStr);
205 : }
206 :
207 : // Search to see if the page number code is in the string
208 : // and replace the page number code with the actual value
209 0 : NS_NAMED_LITERAL_STRING(kPage, "&P");
210 0 : if (aStr.Find(kPage) != kNotFound) {
211 0 : PRUnichar * uStr = nsTextFormatter::smprintf(mPD->mPageNumFormat, mPageNum);
212 0 : aNewStr.ReplaceSubstring(kPage.get(), uStr);
213 0 : nsMemory::Free(uStr);
214 : }
215 :
216 0 : NS_NAMED_LITERAL_STRING(kTitle, "&T");
217 0 : if (aStr.Find(kTitle) != kNotFound) {
218 0 : if (mPD->mDocTitle != nsnull) {
219 0 : aNewStr.ReplaceSubstring(kTitle.get(), mPD->mDocTitle);
220 : } else {
221 0 : aNewStr.ReplaceSubstring(kTitle.get(), EmptyString().get());
222 : }
223 : }
224 :
225 0 : NS_NAMED_LITERAL_STRING(kDocURL, "&U");
226 0 : if (aStr.Find(kDocURL) != kNotFound) {
227 0 : if (mPD->mDocURL != nsnull) {
228 0 : aNewStr.ReplaceSubstring(kDocURL.get(), mPD->mDocURL);
229 : } else {
230 0 : aNewStr.ReplaceSubstring(kDocURL.get(), EmptyString().get());
231 : }
232 : }
233 :
234 0 : NS_NAMED_LITERAL_STRING(kPageTotal, "&L");
235 0 : if (aStr.Find(kPageTotal) != kNotFound) {
236 0 : PRUnichar * uStr = nsTextFormatter::smprintf(mPD->mPageNumFormat, mTotNumPages);
237 0 : aNewStr.ReplaceSubstring(kPageTotal.get(), uStr);
238 0 : nsMemory::Free(uStr);
239 : }
240 0 : }
241 :
242 :
243 : //------------------------------------------------------------------------------
244 0 : nscoord nsPageFrame::GetXPosition(nsRenderingContext& aRenderingContext,
245 : const nsRect& aRect,
246 : PRInt32 aJust,
247 : const nsString& aStr)
248 : {
249 : nscoord width = nsLayoutUtils::GetStringWidth(this, &aRenderingContext,
250 0 : aStr.get(), aStr.Length());
251 :
252 0 : nscoord x = aRect.x;
253 0 : switch (aJust) {
254 : case nsIPrintSettings::kJustLeft:
255 0 : x += mPD->mExtraMargin.left + mPD->mEdgePaperMargin.left;
256 0 : break;
257 :
258 : case nsIPrintSettings::kJustCenter:
259 0 : x += (aRect.width - width) / 2;
260 0 : break;
261 :
262 : case nsIPrintSettings::kJustRight:
263 0 : x += aRect.width - width - mPD->mExtraMargin.right - mPD->mEdgePaperMargin.right;
264 0 : break;
265 : } // switch
266 :
267 0 : return x;
268 : }
269 :
270 : // Draw a header or footer
271 : // @param aRenderingContext - rendering content ot draw into
272 : // @param aHeaderFooter - indicates whether it is a header or footer
273 : // @param aStrLeft - string for the left header or footer; can be empty
274 : // @param aStrCenter - string for the center header or footer; can be empty
275 : // @param aStrRight - string for the right header or footer; can be empty
276 : // @param aRect - the rect of the page
277 : // @param aAscent - the ascent of the font
278 : // @param aHeight - the height of the font
279 : void
280 0 : nsPageFrame::DrawHeaderFooter(nsRenderingContext& aRenderingContext,
281 : nsHeaderFooterEnum aHeaderFooter,
282 : const nsString& aStrLeft,
283 : const nsString& aStrCenter,
284 : const nsString& aStrRight,
285 : const nsRect& aRect,
286 : nscoord aAscent,
287 : nscoord aHeight)
288 : {
289 0 : PRInt32 numStrs = 0;
290 0 : if (!aStrLeft.IsEmpty()) numStrs++;
291 0 : if (!aStrCenter.IsEmpty()) numStrs++;
292 0 : if (!aStrRight.IsEmpty()) numStrs++;
293 :
294 0 : if (numStrs == 0) return;
295 0 : nscoord strSpace = aRect.width / numStrs;
296 :
297 0 : if (!aStrLeft.IsEmpty()) {
298 : DrawHeaderFooter(aRenderingContext, aHeaderFooter,
299 : nsIPrintSettings::kJustLeft, aStrLeft, aRect, aAscent,
300 0 : aHeight, strSpace);
301 : }
302 0 : if (!aStrCenter.IsEmpty()) {
303 : DrawHeaderFooter(aRenderingContext, aHeaderFooter,
304 : nsIPrintSettings::kJustCenter, aStrCenter, aRect, aAscent,
305 0 : aHeight, strSpace);
306 : }
307 0 : if (!aStrRight.IsEmpty()) {
308 : DrawHeaderFooter(aRenderingContext, aHeaderFooter,
309 : nsIPrintSettings::kJustRight, aStrRight, aRect, aAscent,
310 0 : aHeight, strSpace);
311 : }
312 : }
313 :
314 : // Draw a header or footer string
315 : // @param aRenderingContext - rendering context to draw into
316 : // @param aHeaderFooter - indicates whether it is a header or footer
317 : // @param aJust - indicates where the string is located within the header/footer
318 : // @param aStr - the string to be drawn
319 : // @param aRect - the rect of the page
320 : // @param aHeight - the height of the font
321 : // @param aAscent - the ascent of the font
322 : // @param aWidth - available width for the string
323 : void
324 0 : nsPageFrame::DrawHeaderFooter(nsRenderingContext& aRenderingContext,
325 : nsHeaderFooterEnum aHeaderFooter,
326 : PRInt32 aJust,
327 : const nsString& aStr,
328 : const nsRect& aRect,
329 : nscoord aAscent,
330 : nscoord aHeight,
331 : nscoord aWidth)
332 : {
333 :
334 0 : nscoord contentWidth = aWidth - (mPD->mEdgePaperMargin.left + mPD->mEdgePaperMargin.right);
335 :
336 0 : if ((aHeaderFooter == eHeader && aHeight < mPD->mReflowMargin.top) ||
337 : (aHeaderFooter == eFooter && aHeight < mPD->mReflowMargin.bottom)) {
338 0 : nsAutoString str;
339 0 : ProcessSpecialCodes(aStr, str);
340 :
341 : PRInt32 indx;
342 0 : PRInt32 textWidth = 0;
343 0 : const PRUnichar* text = str.get();
344 :
345 0 : PRInt32 len = (PRInt32)str.Length();
346 0 : if (len == 0) {
347 : return; // bail is empty string
348 : }
349 : // find how much text fits, the "position" is the size of the available area
350 0 : if (nsLayoutUtils::BinarySearchForPosition(&aRenderingContext, text, 0, 0, 0, len,
351 : PRInt32(contentWidth), indx, textWidth)) {
352 0 : if (indx < len-1 ) {
353 : // we can't fit in all the text
354 0 : if (indx > 3) {
355 : // But we can fit in at least 4 chars. Show all but 3 of them, then
356 : // an ellipsis.
357 : // XXXbz for non-plane0 text, this may be cutting things in the
358 : // middle of a codepoint! Also, we have no guarantees that the three
359 : // dots will fit in the space the three chars we removed took up with
360 : // these font metrics!
361 0 : str.Truncate(indx-3);
362 0 : str.AppendLiteral("...");
363 : } else {
364 : // We can only fit 3 or fewer chars. Just show nothing
365 0 : str.Truncate();
366 : }
367 : }
368 : } else {
369 : return; // bail if couldn't find the correct length
370 : }
371 :
372 0 : if (HasRTLChars(str)) {
373 0 : PresContext()->SetBidiEnabled();
374 : }
375 :
376 : // cacl the x and y positions of the text
377 0 : nscoord x = GetXPosition(aRenderingContext, aRect, aJust, str);
378 : nscoord y;
379 0 : if (aHeaderFooter == eHeader) {
380 0 : y = aRect.y + mPD->mExtraMargin.top + mPD->mEdgePaperMargin.top;
381 : } else {
382 0 : y = aRect.YMost() - aHeight - mPD->mExtraMargin.bottom - mPD->mEdgePaperMargin.bottom;
383 : }
384 :
385 : // set up new clip and draw the text
386 0 : aRenderingContext.PushState();
387 0 : aRenderingContext.SetColor(NS_RGB(0,0,0));
388 0 : aRenderingContext.IntersectClip(aRect);
389 0 : nsLayoutUtils::DrawString(this, &aRenderingContext, str.get(), str.Length(), nsPoint(x, y + aAscent));
390 0 : aRenderingContext.PopState();
391 : }
392 : }
393 :
394 0 : static void PaintPageContent(nsIFrame* aFrame, nsRenderingContext* aCtx,
395 : const nsRect& aDirtyRect, nsPoint aPt)
396 : {
397 0 : static_cast<nsPageFrame*>(aFrame)->PaintPageContent(*aCtx, aDirtyRect, aPt);
398 0 : }
399 :
400 0 : static void PaintHeaderFooter(nsIFrame* aFrame, nsRenderingContext* aCtx,
401 : const nsRect& aDirtyRect, nsPoint aPt)
402 : {
403 0 : static_cast<nsPageFrame*>(aFrame)->PaintHeaderFooter(*aCtx, aPt);
404 0 : }
405 :
406 : //------------------------------------------------------------------------------
407 : NS_IMETHODIMP
408 0 : nsPageFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
409 : const nsRect& aDirtyRect,
410 : const nsDisplayListSet& aLists)
411 : {
412 0 : nsDisplayListCollection set;
413 : nsresult rv;
414 :
415 0 : if (PresContext()->IsScreen()) {
416 0 : rv = DisplayBorderBackgroundOutline(aBuilder, aLists);
417 0 : NS_ENSURE_SUCCESS(rv, rv);
418 : }
419 :
420 : rv = set.BorderBackground()->AppendNewToTop(new (aBuilder)
421 : nsDisplayGeneric(aBuilder, this, ::PaintPageContent,
422 : "PageContent",
423 0 : nsDisplayItem::TYPE_PAGE_CONTENT));
424 0 : NS_ENSURE_SUCCESS(rv, rv);
425 :
426 0 : if (PresContext()->IsRootPaginatedDocument()) {
427 : rv = set.Content()->AppendNewToTop(new (aBuilder)
428 : nsDisplayGeneric(aBuilder, this, ::PaintHeaderFooter,
429 : "HeaderFooter",
430 0 : nsDisplayItem::TYPE_HEADER_FOOTER));
431 0 : NS_ENSURE_SUCCESS(rv, rv);
432 : }
433 :
434 0 : set.MoveTo(aLists);
435 0 : return NS_OK;
436 : }
437 :
438 : //------------------------------------------------------------------------------
439 : void
440 0 : nsPageFrame::SetPageNumInfo(PRInt32 aPageNumber, PRInt32 aTotalPages)
441 : {
442 0 : mPageNum = aPageNumber;
443 0 : mTotNumPages = aTotalPages;
444 0 : }
445 :
446 :
447 : void
448 0 : nsPageFrame::PaintHeaderFooter(nsRenderingContext& aRenderingContext,
449 : nsPoint aPt)
450 : {
451 0 : nsPresContext* pc = PresContext();
452 :
453 0 : if (!mPD->mPrintSettings) {
454 0 : if (pc->Type() == nsPresContext::eContext_PrintPreview || pc->IsDynamic())
455 0 : mPD->mPrintSettings = pc->GetPrintSettings();
456 0 : if (!mPD->mPrintSettings)
457 0 : return;
458 : }
459 :
460 0 : nsRect rect(aPt, mRect.Size());
461 0 : aRenderingContext.SetColor(NS_RGB(0,0,0));
462 :
463 : // Get the FontMetrics to determine width.height of strings
464 0 : nsRefPtr<nsFontMetrics> fontMet;
465 : pc->DeviceContext()->GetMetricsFor(*mPD->mHeadFootFont, nsnull,
466 : pc->GetUserFontSet(),
467 0 : *getter_AddRefs(fontMet));
468 :
469 0 : aRenderingContext.SetFont(fontMet);
470 :
471 0 : nscoord ascent = 0;
472 0 : nscoord visibleHeight = 0;
473 0 : if (fontMet) {
474 0 : visibleHeight = fontMet->MaxHeight();
475 0 : ascent = fontMet->MaxAscent();
476 : }
477 :
478 : // print document headers and footers
479 0 : nsXPIDLString headerLeft, headerCenter, headerRight;
480 0 : mPD->mPrintSettings->GetHeaderStrLeft(getter_Copies(headerLeft));
481 0 : mPD->mPrintSettings->GetHeaderStrCenter(getter_Copies(headerCenter));
482 0 : mPD->mPrintSettings->GetHeaderStrRight(getter_Copies(headerRight));
483 : DrawHeaderFooter(aRenderingContext, eHeader,
484 : headerLeft, headerCenter, headerRight,
485 0 : rect, ascent, visibleHeight);
486 :
487 0 : nsXPIDLString footerLeft, footerCenter, footerRight;
488 0 : mPD->mPrintSettings->GetFooterStrLeft(getter_Copies(footerLeft));
489 0 : mPD->mPrintSettings->GetFooterStrCenter(getter_Copies(footerCenter));
490 0 : mPD->mPrintSettings->GetFooterStrRight(getter_Copies(footerRight));
491 : DrawHeaderFooter(aRenderingContext, eFooter,
492 : footerLeft, footerCenter, footerRight,
493 0 : rect, ascent, visibleHeight);
494 : }
495 :
496 : //------------------------------------------------------------------------------
497 : void
498 0 : nsPageFrame::PaintPageContent(nsRenderingContext& aRenderingContext,
499 : const nsRect& aDirtyRect,
500 : nsPoint aPt) {
501 0 : nsIFrame* pageContentFrame = mFrames.FirstChild();
502 0 : nsRect rect = aDirtyRect;
503 0 : float scale = PresContext()->GetPageScale();
504 0 : aRenderingContext.PushState();
505 0 : nsPoint framePos = aPt + pageContentFrame->GetOffsetTo(this);
506 0 : aRenderingContext.Translate(framePos);
507 : // aPt translates to coords relative to this, then margins translate to
508 : // pageContentFrame's coords
509 0 : rect -= framePos;
510 0 : aRenderingContext.Scale(scale, scale);
511 0 : rect.ScaleRoundOut(1.0f / scale);
512 : // Make sure we don't draw where we aren't supposed to draw, especially
513 : // when printing selection
514 0 : nsRect clipRect(nsPoint(0, 0), pageContentFrame->GetSize());
515 : // Note: this computation matches how we compute maxSize.height
516 : // in nsPageFrame::Reflow
517 : nscoord expectedPageContentHeight =
518 0 : NSToCoordCeil((GetSize().height - mPD->mReflowMargin.TopBottom()) / scale);
519 0 : if (clipRect.height > expectedPageContentHeight) {
520 : // We're doing print-selection, with one long page-content frame.
521 : // Clip to the appropriate page-content slice for the current page.
522 0 : NS_ASSERTION(mPageNum > 0, "page num should be positive");
523 : // Note: The pageContentFrame's y-position has been set such that a zero
524 : // y-value matches the top edge of the current page. So, to clip to the
525 : // current page's content (in coordinates *relative* to the page content
526 : // frame), we just negate its y-position and add the top margin.
527 0 : clipRect.y = NSToCoordCeil((-pageContentFrame->GetRect().y +
528 0 : mPD->mReflowMargin.top) / scale);
529 0 : clipRect.height = expectedPageContentHeight;
530 0 : NS_ASSERTION(clipRect.y < pageContentFrame->GetSize().height,
531 : "Should be clipping to region inside the page content bounds");
532 : }
533 0 : aRenderingContext.IntersectClip(clipRect);
534 :
535 0 : nsRect backgroundRect = nsRect(nsPoint(0, 0), pageContentFrame->GetSize());
536 : nsCSSRendering::PaintBackground(PresContext(), aRenderingContext, this,
537 : rect, backgroundRect,
538 0 : nsCSSRendering::PAINTBG_SYNC_DECODE_IMAGES);
539 :
540 : nsLayoutUtils::PaintFrame(&aRenderingContext, pageContentFrame,
541 0 : nsRegion(rect), NS_RGBA(0,0,0,0),
542 0 : nsLayoutUtils::PAINT_SYNC_DECODE_IMAGES);
543 :
544 0 : aRenderingContext.PopState();
545 0 : }
546 :
547 : void
548 0 : nsPageFrame::SetSharedPageData(nsSharedPageData* aPD)
549 : {
550 0 : mPD = aPD;
551 : // Set the shared data into the page frame before reflow
552 0 : nsPageContentFrame * pcf = static_cast<nsPageContentFrame*>(mFrames.FirstChild());
553 0 : if (pcf) {
554 0 : pcf->SetSharedPageData(mPD);
555 : }
556 :
557 0 : }
558 :
559 : nsIFrame*
560 0 : NS_NewPageBreakFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
561 : {
562 0 : NS_PRECONDITION(aPresShell, "null PresShell");
563 : //check that we are only creating page break frames when printing
564 0 : NS_ASSERTION(aPresShell->GetPresContext()->IsPaginated(), "created a page break frame while not printing");
565 :
566 0 : return new (aPresShell) nsPageBreakFrame(aContext);
567 : }
568 :
569 0 : NS_IMPL_FRAMEARENA_HELPERS(nsPageBreakFrame)
570 :
571 0 : nsPageBreakFrame::nsPageBreakFrame(nsStyleContext* aContext) :
572 0 : nsLeafFrame(aContext), mHaveReflowed(false)
573 : {
574 0 : }
575 :
576 0 : nsPageBreakFrame::~nsPageBreakFrame()
577 : {
578 0 : }
579 :
580 : nscoord
581 0 : nsPageBreakFrame::GetIntrinsicWidth()
582 : {
583 0 : return nsPresContext::CSSPixelsToAppUnits(1);
584 : }
585 :
586 : nscoord
587 0 : nsPageBreakFrame::GetIntrinsicHeight()
588 : {
589 0 : return 0;
590 : }
591 :
592 : nsresult
593 0 : nsPageBreakFrame::Reflow(nsPresContext* aPresContext,
594 : nsHTMLReflowMetrics& aDesiredSize,
595 : const nsHTMLReflowState& aReflowState,
596 : nsReflowStatus& aStatus)
597 : {
598 0 : DO_GLOBAL_REFLOW_COUNT("nsPageBreakFrame");
599 0 : DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
600 :
601 : // Override reflow, since we don't want to deal with what our
602 : // computed values are.
603 0 : aDesiredSize.width = GetIntrinsicWidth();
604 : aDesiredSize.height = (aReflowState.availableHeight == NS_UNCONSTRAINEDSIZE ?
605 0 : 0 : aReflowState.availableHeight);
606 : // round the height down to the nearest pixel
607 : aDesiredSize.height -=
608 0 : aDesiredSize.height % nsPresContext::CSSPixelsToAppUnits(1);
609 :
610 : // Note: not using NS_FRAME_FIRST_REFLOW here, since it's not clear whether
611 : // DidReflow will always get called before the next Reflow() call.
612 0 : mHaveReflowed = true;
613 0 : aStatus = NS_FRAME_COMPLETE;
614 0 : return NS_OK;
615 : }
616 :
617 : nsIAtom*
618 0 : nsPageBreakFrame::GetType() const
619 : {
620 0 : return nsGkAtoms::pageBreakFrame;
621 : }
622 :
623 : #ifdef DEBUG
624 : NS_IMETHODIMP
625 0 : nsPageBreakFrame::GetFrameName(nsAString& aResult) const
626 : {
627 0 : return MakeFrameName(NS_LITERAL_STRING("PageBreak"), aResult);
628 : }
629 : #endif
|