CLOSED TREE: TraceMonkey merge head. (a=blockers)
[mozilla-central.git] / layout / generic / nsPageFrame.cpp
blob6fcb755c8f96c5c4a9d4236cb13ff05fcf87585b
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
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/
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.
15 * The Original Code is mozilla.org code.
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.
22 * Contributor(s):
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.
36 * ***** END LICENSE BLOCK ***** */
38 #include "nsPageFrame.h"
39 #include "nsPresContext.h"
40 #include "nsStyleContext.h"
41 #include "nsIRenderingContext.h"
42 #include "nsGkAtoms.h"
43 #include "nsIPresShell.h"
44 #include "nsCSSFrameConstructor.h"
45 #include "nsIDeviceContext.h"
46 #include "nsReadableUtils.h"
47 #include "nsPageContentFrame.h"
48 #include "nsDisplayList.h"
49 #include "nsLayoutUtils.h" // for function BinarySearchForPosition
50 #include "nsCSSRendering.h"
51 #include "nsSimplePageSequence.h" // for nsSharedPageData
52 #include "nsTextFormatter.h" // for page number localization formatting
53 #ifdef IBMBIDI
54 #include "nsBidiUtils.h"
55 #endif
56 #include "nsIFontMetrics.h"
57 #include "nsIPrintSettings.h"
58 #include "nsRegion.h"
60 #include "prlog.h"
61 #ifdef PR_LOGGING
62 extern PRLogModuleInfo * kLayoutPrintingLogMod;
63 #define PR_PL(_p1) PR_LOG(kLayoutPrintingLogMod, PR_LOG_DEBUG, _p1)
64 #else
65 #define PR_PL(_p1)
66 #endif
68 nsIFrame*
69 NS_NewPageFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
71 return new (aPresShell) nsPageFrame(aContext);
74 NS_IMPL_FRAMEARENA_HELPERS(nsPageFrame)
76 nsPageFrame::nsPageFrame(nsStyleContext* aContext)
77 : nsContainerFrame(aContext)
81 nsPageFrame::~nsPageFrame()
85 NS_IMETHODIMP nsPageFrame::Reflow(nsPresContext* aPresContext,
86 nsHTMLReflowMetrics& aDesiredSize,
87 const nsHTMLReflowState& aReflowState,
88 nsReflowStatus& aStatus)
90 DO_GLOBAL_REFLOW_COUNT("nsPageFrame");
91 DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
92 aStatus = NS_FRAME_COMPLETE; // initialize out parameter
94 NS_ASSERTION(mFrames.FirstChild() &&
95 nsGkAtoms::pageContentFrame == mFrames.FirstChild()->GetType(),
96 "pageFrame must have a pageContentFrame child");
98 // Resize our frame allowing it only to be as big as we are
99 // XXX Pay attention to the page's border and padding...
100 if (mFrames.NotEmpty()) {
101 nsIFrame* frame = mFrames.FirstChild();
102 // When the reflow size is NS_UNCONSTRAINEDSIZE it means we are reflowing
103 // a single page to print selection. So this means we want to use
104 // NS_UNCONSTRAINEDSIZE without altering it
105 nscoord avHeight;
106 if (mPD->mReflowSize.height == NS_UNCONSTRAINEDSIZE) {
107 avHeight = NS_UNCONSTRAINEDSIZE;
108 } else {
109 avHeight = mPD->mReflowSize.height - mPD->mReflowMargin.TopBottom();
111 nsSize maxSize(mPD->mReflowSize.width - mPD->mReflowMargin.LeftRight(),
112 avHeight);
113 float scale = aPresContext->GetPageScale();
114 maxSize.width = NSToCoordCeil(maxSize.width / scale);
115 if (maxSize.height != NS_UNCONSTRAINEDSIZE) {
116 maxSize.height = NSToCoordCeil(maxSize.height / scale);
118 // Get the number of Twips per pixel from the PresContext
119 nscoord onePixelInTwips = nsPresContext::CSSPixelsToAppUnits(1);
120 // insurance against infinite reflow, when reflowing less than a pixel
121 // XXX Shouldn't we do something more friendly when invalid margins
122 // are set?
123 if (maxSize.width < onePixelInTwips || maxSize.height < onePixelInTwips) {
124 aDesiredSize.width = 0;
125 aDesiredSize.height = 0;
126 NS_WARNING("Reflow aborted; no space for content");
127 return NS_OK;
130 nsHTMLReflowState kidReflowState(aPresContext, aReflowState, frame, maxSize);
131 kidReflowState.mFlags.mIsTopOfPage = PR_TRUE;
132 kidReflowState.mFlags.mTableIsSplittable = PR_TRUE;
134 // calc location of frame
135 nscoord xc = mPD->mReflowMargin.left + mPD->mExtraMargin.left;
136 nscoord yc = mPD->mReflowMargin.top + mPD->mExtraMargin.top;
138 // Get the child's desired size
139 ReflowChild(frame, aPresContext, aDesiredSize, kidReflowState, xc, yc, 0, aStatus);
141 // Place and size the child
142 FinishReflowChild(frame, aPresContext, &kidReflowState, aDesiredSize, xc, yc, 0);
144 NS_ASSERTION(!NS_FRAME_IS_FULLY_COMPLETE(aStatus) ||
145 !frame->GetNextInFlow(), "bad child flow list");
147 PR_PL(("PageFrame::Reflow %p ", this));
148 PR_PL(("[%d,%d][%d,%d]\n", aDesiredSize.width, aDesiredSize.height, aReflowState.availableWidth, aReflowState.availableHeight));
150 // Return our desired size
151 aDesiredSize.width = aReflowState.availableWidth;
152 if (aReflowState.availableHeight != NS_UNCONSTRAINEDSIZE) {
153 aDesiredSize.height = aReflowState.availableHeight;
155 PR_PL(("PageFrame::Reflow %p ", this));
156 PR_PL(("[%d,%d]\n", aReflowState.availableWidth, aReflowState.availableHeight));
158 NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
159 return NS_OK;
162 nsIAtom*
163 nsPageFrame::GetType() const
165 return nsGkAtoms::pageFrame;
168 #ifdef DEBUG
169 NS_IMETHODIMP
170 nsPageFrame::GetFrameName(nsAString& aResult) const
172 return MakeFrameName(NS_LITERAL_STRING("Page"), aResult);
174 #endif
176 /* virtual */ PRBool
177 nsPageFrame::IsContainingBlock() const
179 return PR_TRUE;
182 void
183 nsPageFrame::ProcessSpecialCodes(const nsString& aStr, nsString& aNewStr)
186 aNewStr = aStr;
188 // Search to see if the &D code is in the string
189 // then subst in the current date/time
190 NS_NAMED_LITERAL_STRING(kDate, "&D");
191 if (aStr.Find(kDate) != kNotFound) {
192 if (mPD->mDateTimeStr != nsnull) {
193 aNewStr.ReplaceSubstring(kDate.get(), mPD->mDateTimeStr);
194 } else {
195 aNewStr.ReplaceSubstring(kDate.get(), EmptyString().get());
199 // NOTE: Must search for &PT before searching for &P
201 // Search to see if the "page number and page" total code are in the string
202 // and replace the page number and page total code with the actual
203 // values
204 NS_NAMED_LITERAL_STRING(kPageAndTotal, "&PT");
205 if (aStr.Find(kPageAndTotal) != kNotFound) {
206 PRUnichar * uStr = nsTextFormatter::smprintf(mPD->mPageNumAndTotalsFormat, mPageNum, mTotNumPages);
207 aNewStr.ReplaceSubstring(kPageAndTotal.get(), uStr);
208 nsMemory::Free(uStr);
211 // Search to see if the page number code is in the string
212 // and replace the page number code with the actual value
213 NS_NAMED_LITERAL_STRING(kPage, "&P");
214 if (aStr.Find(kPage) != kNotFound) {
215 PRUnichar * uStr = nsTextFormatter::smprintf(mPD->mPageNumFormat, mPageNum);
216 aNewStr.ReplaceSubstring(kPage.get(), uStr);
217 nsMemory::Free(uStr);
220 NS_NAMED_LITERAL_STRING(kTitle, "&T");
221 if (aStr.Find(kTitle) != kNotFound) {
222 if (mPD->mDocTitle != nsnull) {
223 aNewStr.ReplaceSubstring(kTitle.get(), mPD->mDocTitle);
224 } else {
225 aNewStr.ReplaceSubstring(kTitle.get(), EmptyString().get());
229 NS_NAMED_LITERAL_STRING(kDocURL, "&U");
230 if (aStr.Find(kDocURL) != kNotFound) {
231 if (mPD->mDocURL != nsnull) {
232 aNewStr.ReplaceSubstring(kDocURL.get(), mPD->mDocURL);
233 } else {
234 aNewStr.ReplaceSubstring(kDocURL.get(), EmptyString().get());
238 NS_NAMED_LITERAL_STRING(kPageTotal, "&L");
239 if (aStr.Find(kPageTotal) != kNotFound) {
240 PRUnichar * uStr = nsTextFormatter::smprintf(mPD->mPageNumFormat, mTotNumPages);
241 aNewStr.ReplaceSubstring(kPageTotal.get(), uStr);
242 nsMemory::Free(uStr);
247 //------------------------------------------------------------------------------
248 nscoord nsPageFrame::GetXPosition(nsIRenderingContext& aRenderingContext,
249 const nsRect& aRect,
250 PRInt32 aJust,
251 const nsString& aStr)
253 nscoord width = nsLayoutUtils::GetStringWidth(this, &aRenderingContext,
254 aStr.get(), aStr.Length());
256 nscoord x = aRect.x;
257 switch (aJust) {
258 case nsIPrintSettings::kJustLeft:
259 x += mPD->mExtraMargin.left + mPD->mEdgePaperMargin.left;
260 break;
262 case nsIPrintSettings::kJustCenter:
263 x += (aRect.width - width) / 2;
264 break;
266 case nsIPrintSettings::kJustRight:
267 x += aRect.width - width - mPD->mExtraMargin.right - mPD->mEdgePaperMargin.right;
268 break;
269 } // switch
271 return x;
274 // Draw a header or footer
275 // @param aRenderingContext - rendering content ot draw into
276 // @param aHeaderFooter - indicates whether it is a header or footer
277 // @param aStrLeft - string for the left header or footer; can be empty
278 // @param aStrCenter - string for the center header or footer; can be empty
279 // @param aStrRight - string for the right header or footer; can be empty
280 // @param aRect - the rect of the page
281 // @param aAscent - the ascent of the font
282 // @param aHeight - the height of the font
283 void
284 nsPageFrame::DrawHeaderFooter(nsIRenderingContext& aRenderingContext,
285 nsHeaderFooterEnum aHeaderFooter,
286 const nsString& aStrLeft,
287 const nsString& aStrCenter,
288 const nsString& aStrRight,
289 const nsRect& aRect,
290 nscoord aAscent,
291 nscoord aHeight)
293 PRInt32 numStrs = 0;
294 if (!aStrLeft.IsEmpty()) numStrs++;
295 if (!aStrCenter.IsEmpty()) numStrs++;
296 if (!aStrRight.IsEmpty()) numStrs++;
298 if (numStrs == 0) return;
299 nscoord strSpace = aRect.width / numStrs;
301 if (!aStrLeft.IsEmpty()) {
302 DrawHeaderFooter(aRenderingContext, aHeaderFooter,
303 nsIPrintSettings::kJustLeft, aStrLeft, aRect, aAscent,
304 aHeight, strSpace);
306 if (!aStrCenter.IsEmpty()) {
307 DrawHeaderFooter(aRenderingContext, aHeaderFooter,
308 nsIPrintSettings::kJustCenter, aStrCenter, aRect, aAscent,
309 aHeight, strSpace);
311 if (!aStrRight.IsEmpty()) {
312 DrawHeaderFooter(aRenderingContext, aHeaderFooter,
313 nsIPrintSettings::kJustRight, aStrRight, aRect, aAscent,
314 aHeight, strSpace);
318 // Draw a header or footer string
319 // @param aRenderingContext - rendering context to draw into
320 // @param aHeaderFooter - indicates whether it is a header or footer
321 // @param aJust - indicates where the string is located within the header/footer
322 // @param aStr - the string to be drawn
323 // @param aRect - the rect of the page
324 // @param aHeight - the height of the font
325 // @param aAscent - the ascent of the font
326 // @param aWidth - available width for the string
327 void
328 nsPageFrame::DrawHeaderFooter(nsIRenderingContext& aRenderingContext,
329 nsHeaderFooterEnum aHeaderFooter,
330 PRInt32 aJust,
331 const nsString& aStr,
332 const nsRect& aRect,
333 nscoord aAscent,
334 nscoord aHeight,
335 nscoord aWidth)
338 nscoord contentWidth = aWidth - (mPD->mEdgePaperMargin.left + mPD->mEdgePaperMargin.right);
340 if ((aHeaderFooter == eHeader && aHeight < mPD->mReflowMargin.top) ||
341 (aHeaderFooter == eFooter && aHeight < mPD->mReflowMargin.bottom)) {
342 nsAutoString str;
343 ProcessSpecialCodes(aStr, str);
345 PRInt32 indx;
346 PRInt32 textWidth = 0;
347 const PRUnichar* text = str.get();
349 PRInt32 len = (PRInt32)str.Length();
350 if (len == 0) {
351 return; // bail is empty string
353 // find how much text fits, the "position" is the size of the available area
354 if (nsLayoutUtils::BinarySearchForPosition(&aRenderingContext, text, 0, 0, 0, len,
355 PRInt32(contentWidth), indx, textWidth)) {
356 if (indx < len-1 ) {
357 // we can't fit in all the text
358 if (indx > 3) {
359 // But we can fit in at least 4 chars. Show all but 3 of them, then
360 // an ellipsis.
361 // XXXbz for non-plane0 text, this may be cutting things in the
362 // middle of a codepoint! Also, we have no guarantees that the three
363 // dots will fit in the space the three chars we removed took up with
364 // these font metrics!
365 str.Truncate(indx-3);
366 str.AppendLiteral("...");
367 } else {
368 // We can only fit 3 or fewer chars. Just show nothing
369 str.Truncate();
372 } else {
373 return; // bail if couldn't find the correct length
376 if (HasRTLChars(str)) {
377 PresContext()->SetBidiEnabled();
380 // cacl the x and y positions of the text
381 nscoord x = GetXPosition(aRenderingContext, aRect, aJust, str);
382 nscoord y;
383 if (aHeaderFooter == eHeader) {
384 y = aRect.y + mPD->mExtraMargin.top + mPD->mEdgePaperMargin.top;
385 } else {
386 y = aRect.YMost() - aHeight - mPD->mExtraMargin.bottom - mPD->mEdgePaperMargin.bottom;
389 // set up new clip and draw the text
390 aRenderingContext.PushState();
391 aRenderingContext.SetColor(NS_RGB(0,0,0));
392 aRenderingContext.SetClipRect(aRect, nsClipCombine_kIntersect);
393 nsLayoutUtils::DrawString(this, &aRenderingContext, str.get(), str.Length(), nsPoint(x, y + aAscent));
394 aRenderingContext.PopState();
398 static void PaintPrintPreviewBackground(nsIFrame* aFrame, nsIRenderingContext* aCtx,
399 const nsRect& aDirtyRect, nsPoint aPt)
401 static_cast<nsPageFrame*>(aFrame)->PaintPrintPreviewBackground(*aCtx, aPt);
404 static void PaintPageContent(nsIFrame* aFrame, nsIRenderingContext* aCtx,
405 const nsRect& aDirtyRect, nsPoint aPt)
407 static_cast<nsPageFrame*>(aFrame)->PaintPageContent(*aCtx, aDirtyRect, aPt);
410 static void PaintHeaderFooter(nsIFrame* aFrame, nsIRenderingContext* aCtx,
411 const nsRect& aDirtyRect, nsPoint aPt)
413 static_cast<nsPageFrame*>(aFrame)->PaintHeaderFooter(*aCtx, aPt);
416 //------------------------------------------------------------------------------
417 NS_IMETHODIMP
418 nsPageFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
419 const nsRect& aDirtyRect,
420 const nsDisplayListSet& aLists)
422 nsDisplayListCollection set;
423 nsresult rv;
425 if (PresContext()->IsScreen()) {
426 rv = set.BorderBackground()->AppendNewToTop(new (aBuilder)
427 nsDisplayGeneric(aBuilder, this, ::PaintPrintPreviewBackground,
428 "PrintPreviewBackground",
429 nsDisplayItem::TYPE_PRINT_PREVIEW_BACKGROUND));
430 NS_ENSURE_SUCCESS(rv, rv);
433 rv = set.BorderBackground()->AppendNewToTop(new (aBuilder)
434 nsDisplayGeneric(aBuilder, this, ::PaintPageContent,
435 "PageContent",
436 nsDisplayItem::TYPE_PAGE_CONTENT));
437 NS_ENSURE_SUCCESS(rv, rv);
439 if (PresContext()->IsRootPaginatedDocument()) {
440 rv = set.Content()->AppendNewToTop(new (aBuilder)
441 nsDisplayGeneric(aBuilder, this, ::PaintHeaderFooter,
442 "HeaderFooter",
443 nsDisplayItem::TYPE_HEADER_FOOTER));
444 NS_ENSURE_SUCCESS(rv, rv);
447 set.MoveTo(aLists);
448 return NS_OK;
451 //------------------------------------------------------------------------------
452 void
453 nsPageFrame::SetPageNumInfo(PRInt32 aPageNumber, PRInt32 aTotalPages)
455 mPageNum = aPageNumber;
456 mTotNumPages = aTotalPages;
460 void
461 nsPageFrame::PaintPrintPreviewBackground(nsIRenderingContext& aRenderingContext,
462 nsPoint aPt)
464 // fill page with White
465 aRenderingContext.SetColor(NS_RGB(255,255,255));
466 // REVIEW: this used to have rect's width and height be the
467 // mClipRect if specialClipIsSet ... but that seems completely bogus
468 // and inconsistent with the painting of the shadow below
469 nsRect rect(aPt, GetSize());
470 rect.width -= mPD->mShadowSize.width;
471 rect.height -= mPD->mShadowSize.height;
472 aRenderingContext.FillRect(rect);
473 // draw line around outside of page
474 aRenderingContext.SetColor(NS_RGB(0,0,0));
475 aRenderingContext.DrawRect(rect);
477 if (mPD->mShadowSize.width > 0 && mPD->mShadowSize.height > 0) {
478 aRenderingContext.SetColor(NS_RGB(51,51,51));
479 nsRect r(aPt.x,aPt.y, mRect.width, mRect.height);
480 nsRect shadowRect;
481 shadowRect.x = r.x + r.width - mPD->mShadowSize.width;
482 shadowRect.y = r.y + mPD->mShadowSize.height;
483 shadowRect.width = mPD->mShadowSize.width;
484 shadowRect.height = r.height - mPD->mShadowSize.height;
485 aRenderingContext.FillRect(shadowRect);
487 shadowRect.x = r.x + mPD->mShadowSize.width;
488 shadowRect.y = r.y + r.height - mPD->mShadowSize.height;
489 shadowRect.width = r.width - mPD->mShadowSize.width;
490 shadowRect.height = mPD->mShadowSize.height;
491 aRenderingContext.FillRect(shadowRect);
495 void
496 nsPageFrame::PaintHeaderFooter(nsIRenderingContext& aRenderingContext,
497 nsPoint aPt)
499 nsPresContext* pc = PresContext();
501 if (!mPD->mPrintSettings) {
502 if (pc->Type() == nsPresContext::eContext_PrintPreview || pc->IsDynamic())
503 mPD->mPrintSettings = pc->GetPrintSettings();
504 if (!mPD->mPrintSettings)
505 return;
508 nsRect rect(aPt.x, aPt.y, mRect.width - mPD->mShadowSize.width,
509 mRect.height - mPD->mShadowSize.height);
511 aRenderingContext.SetColor(NS_RGB(0,0,0));
513 // Get the FontMetrics to determine width.height of strings
514 nsCOMPtr<nsIFontMetrics> fontMet;
515 pc->DeviceContext()->GetMetricsFor(*mPD->mHeadFootFont,
516 pc->GetUserFontSet(),
517 *getter_AddRefs(fontMet));
519 aRenderingContext.SetFont(fontMet);
521 nscoord ascent = 0;
522 nscoord visibleHeight = 0;
523 if (fontMet) {
524 fontMet->GetHeight(visibleHeight);
525 fontMet->GetMaxAscent(ascent);
528 // print document headers and footers
529 nsXPIDLString headerLeft, headerCenter, headerRight;
530 mPD->mPrintSettings->GetHeaderStrLeft(getter_Copies(headerLeft));
531 mPD->mPrintSettings->GetHeaderStrCenter(getter_Copies(headerCenter));
532 mPD->mPrintSettings->GetHeaderStrRight(getter_Copies(headerRight));
533 DrawHeaderFooter(aRenderingContext, eHeader,
534 headerLeft, headerCenter, headerRight,
535 rect, ascent, visibleHeight);
537 nsXPIDLString footerLeft, footerCenter, footerRight;
538 mPD->mPrintSettings->GetFooterStrLeft(getter_Copies(footerLeft));
539 mPD->mPrintSettings->GetFooterStrCenter(getter_Copies(footerCenter));
540 mPD->mPrintSettings->GetFooterStrRight(getter_Copies(footerRight));
541 DrawHeaderFooter(aRenderingContext, eFooter,
542 footerLeft, footerCenter, footerRight,
543 rect, ascent, visibleHeight);
546 //------------------------------------------------------------------------------
547 void
548 nsPageFrame::PaintPageContent(nsIRenderingContext& aRenderingContext,
549 const nsRect& aDirtyRect,
550 nsPoint aPt) {
551 nsIFrame* pageContentFrame = mFrames.FirstChild();
552 nsRect rect = aDirtyRect;
553 float scale = PresContext()->GetPageScale();
554 aRenderingContext.PushState();
555 nsPoint framePos = aPt + pageContentFrame->GetOffsetTo(this);
556 aRenderingContext.Translate(framePos.x, framePos.y);
557 // aPt translates to coords relative to this, then margins translate to
558 // pageContentFrame's coords
559 rect -= framePos;
560 aRenderingContext.Scale(scale, scale);
561 rect.ScaleRoundOut(1.0f / scale);
562 // Make sure we don't draw where we aren't supposed to draw, especially
563 // when printing selection
564 nsRect clipRect(nsPoint(0, 0), pageContentFrame->GetSize());
565 // Note: this computation matches how we compute maxSize.height
566 // in nsPageFrame::Reflow
567 nscoord expectedPageContentHeight =
568 NSToCoordCeil((GetSize().height - mPD->mReflowMargin.TopBottom()) / scale);
569 if (clipRect.height > expectedPageContentHeight) {
570 // We're doing print-selection, with one long page-content frame.
571 // Clip to the appropriate page-content slice for the current page.
572 NS_ASSERTION(mPageNum > 0, "page num should be positive");
573 // Note: The pageContentFrame's y-position has been set such that a zero
574 // y-value matches the top edge of the current page. So, to clip to the
575 // current page's content (in coordinates *relative* to the page content
576 // frame), we just negate its y-position and add the top margin.
577 clipRect.y = NSToCoordCeil((-pageContentFrame->GetRect().y +
578 mPD->mReflowMargin.top) / scale);
579 clipRect.height = expectedPageContentHeight;
580 NS_ASSERTION(clipRect.y < pageContentFrame->GetSize().height,
581 "Should be clipping to region inside the page content bounds");
583 aRenderingContext.SetClipRect(clipRect, nsClipCombine_kIntersect);
585 nsRect backgroundRect = nsRect(nsPoint(0, 0), pageContentFrame->GetSize());
586 nsCSSRendering::PaintBackground(PresContext(), aRenderingContext, this,
587 rect, backgroundRect,
588 nsCSSRendering::PAINTBG_SYNC_DECODE_IMAGES);
590 nsLayoutUtils::PaintFrame(&aRenderingContext, pageContentFrame,
591 nsRegion(rect), NS_RGBA(0,0,0,0),
592 nsLayoutUtils::PAINT_SYNC_DECODE_IMAGES);
594 aRenderingContext.PopState();
597 void
598 nsPageFrame::SetSharedPageData(nsSharedPageData* aPD)
600 mPD = aPD;
601 // Set the shared data into the page frame before reflow
602 nsPageContentFrame * pcf = static_cast<nsPageContentFrame*>(mFrames.FirstChild());
603 if (pcf) {
604 pcf->SetSharedPageData(mPD);
609 nsIFrame*
610 NS_NewPageBreakFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
612 NS_PRECONDITION(aPresShell, "null PresShell");
613 //check that we are only creating page break frames when printing
614 NS_ASSERTION(aPresShell->GetPresContext()->IsPaginated(), "created a page break frame while not printing");
616 return new (aPresShell) nsPageBreakFrame(aContext);
619 NS_IMPL_FRAMEARENA_HELPERS(nsPageBreakFrame)
621 nsPageBreakFrame::nsPageBreakFrame(nsStyleContext* aContext) :
622 nsLeafFrame(aContext), mHaveReflowed(PR_FALSE)
626 nsPageBreakFrame::~nsPageBreakFrame()
630 nscoord
631 nsPageBreakFrame::GetIntrinsicWidth()
633 return nsPresContext::CSSPixelsToAppUnits(1);
636 nscoord
637 nsPageBreakFrame::GetIntrinsicHeight()
639 return 0;
642 nsresult
643 nsPageBreakFrame::Reflow(nsPresContext* aPresContext,
644 nsHTMLReflowMetrics& aDesiredSize,
645 const nsHTMLReflowState& aReflowState,
646 nsReflowStatus& aStatus)
648 DO_GLOBAL_REFLOW_COUNT("nsPageBreakFrame");
649 DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
651 // Override reflow, since we don't want to deal with what our
652 // computed values are.
653 aDesiredSize.width = GetIntrinsicWidth();
654 aDesiredSize.height = (aReflowState.availableHeight == NS_UNCONSTRAINEDSIZE ?
655 0 : aReflowState.availableHeight);
656 // round the height down to the nearest pixel
657 aDesiredSize.height -=
658 aDesiredSize.height % nsPresContext::CSSPixelsToAppUnits(1);
660 // Note: not using NS_FRAME_FIRST_REFLOW here, since it's not clear whether
661 // DidReflow will always get called before the next Reflow() call.
662 mHaveReflowed = PR_TRUE;
663 aStatus = NS_FRAME_COMPLETE;
664 return NS_OK;
667 nsIAtom*
668 nsPageBreakFrame::GetType() const
670 return nsGkAtoms::pageBreakFrame;
673 #ifdef DEBUG
674 NS_IMETHODIMP
675 nsPageBreakFrame::GetFrameName(nsAString& aResult) const
677 return MakeFrameName(NS_LITERAL_STRING("PageBreak"), aResult);
679 #endif