Bug 574454 - Cleanup nsNativeThemeWin's GetMinimumWidgetSize a bit. r=roc.
[mozilla-central.git] / layout / generic / nsPageFrame.cpp
blobf9046caecd04161d05183457635699ed29f1a133
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(this, ::PaintPrintPreviewBackground, "PrintPreviewBackground",
428 nsDisplayItem::TYPE_PRINT_PREVIEW_BACKGROUND));
429 NS_ENSURE_SUCCESS(rv, rv);
432 rv = set.BorderBackground()->AppendNewToTop(new (aBuilder)
433 nsDisplayGeneric(this, ::PaintPageContent, "PageContent",
434 nsDisplayItem::TYPE_PAGE_CONTENT));
435 NS_ENSURE_SUCCESS(rv, rv);
437 if (PresContext()->IsRootPaginatedDocument()) {
438 rv = set.Content()->AppendNewToTop(new (aBuilder)
439 nsDisplayGeneric(this, ::PaintHeaderFooter, "HeaderFooter",
440 nsDisplayItem::TYPE_HEADER_FOOTER));
441 NS_ENSURE_SUCCESS(rv, rv);
444 set.MoveTo(aLists);
445 return NS_OK;
448 //------------------------------------------------------------------------------
449 void
450 nsPageFrame::SetPageNumInfo(PRInt32 aPageNumber, PRInt32 aTotalPages)
452 mPageNum = aPageNumber;
453 mTotNumPages = aTotalPages;
457 void
458 nsPageFrame::PaintPrintPreviewBackground(nsIRenderingContext& aRenderingContext,
459 nsPoint aPt)
461 // fill page with White
462 aRenderingContext.SetColor(NS_RGB(255,255,255));
463 // REVIEW: this used to have rect's width and height be the
464 // mClipRect if specialClipIsSet ... but that seems completely bogus
465 // and inconsistent with the painting of the shadow below
466 nsRect rect(aPt, GetSize());
467 rect.width -= mPD->mShadowSize.width;
468 rect.height -= mPD->mShadowSize.height;
469 aRenderingContext.FillRect(rect);
470 // draw line around outside of page
471 aRenderingContext.SetColor(NS_RGB(0,0,0));
472 aRenderingContext.DrawRect(rect);
474 if (mPD->mShadowSize.width > 0 && mPD->mShadowSize.height > 0) {
475 aRenderingContext.SetColor(NS_RGB(51,51,51));
476 nsRect r(aPt.x,aPt.y, mRect.width, mRect.height);
477 nsRect shadowRect;
478 shadowRect.x = r.x + r.width - mPD->mShadowSize.width;
479 shadowRect.y = r.y + mPD->mShadowSize.height;
480 shadowRect.width = mPD->mShadowSize.width;
481 shadowRect.height = r.height - mPD->mShadowSize.height;
482 aRenderingContext.FillRect(shadowRect);
484 shadowRect.x = r.x + mPD->mShadowSize.width;
485 shadowRect.y = r.y + r.height - mPD->mShadowSize.height;
486 shadowRect.width = r.width - mPD->mShadowSize.width;
487 shadowRect.height = mPD->mShadowSize.height;
488 aRenderingContext.FillRect(shadowRect);
492 void
493 nsPageFrame::PaintHeaderFooter(nsIRenderingContext& aRenderingContext,
494 nsPoint aPt)
496 nsPresContext* pc = PresContext();
498 if (!mPD->mPrintSettings) {
499 if (pc->Type() == nsPresContext::eContext_PrintPreview || pc->IsDynamic())
500 mPD->mPrintSettings = pc->GetPrintSettings();
501 if (!mPD->mPrintSettings)
502 return;
505 nsRect rect(aPt.x, aPt.y, mRect.width - mPD->mShadowSize.width,
506 mRect.height - mPD->mShadowSize.height);
508 aRenderingContext.SetColor(NS_RGB(0,0,0));
510 // Get the FontMetrics to determine width.height of strings
511 nsCOMPtr<nsIFontMetrics> fontMet;
512 pc->DeviceContext()->GetMetricsFor(*mPD->mHeadFootFont,
513 pc->GetUserFontSet(),
514 *getter_AddRefs(fontMet));
516 aRenderingContext.SetFont(fontMet);
518 nscoord ascent = 0;
519 nscoord visibleHeight = 0;
520 if (fontMet) {
521 fontMet->GetHeight(visibleHeight);
522 fontMet->GetMaxAscent(ascent);
525 // print document headers and footers
526 nsXPIDLString headerLeft, headerCenter, headerRight;
527 mPD->mPrintSettings->GetHeaderStrLeft(getter_Copies(headerLeft));
528 mPD->mPrintSettings->GetHeaderStrCenter(getter_Copies(headerCenter));
529 mPD->mPrintSettings->GetHeaderStrRight(getter_Copies(headerRight));
530 DrawHeaderFooter(aRenderingContext, eHeader,
531 headerLeft, headerCenter, headerRight,
532 rect, ascent, visibleHeight);
534 nsXPIDLString footerLeft, footerCenter, footerRight;
535 mPD->mPrintSettings->GetFooterStrLeft(getter_Copies(footerLeft));
536 mPD->mPrintSettings->GetFooterStrCenter(getter_Copies(footerCenter));
537 mPD->mPrintSettings->GetFooterStrRight(getter_Copies(footerRight));
538 DrawHeaderFooter(aRenderingContext, eFooter,
539 footerLeft, footerCenter, footerRight,
540 rect, ascent, visibleHeight);
543 //------------------------------------------------------------------------------
544 void
545 nsPageFrame::PaintPageContent(nsIRenderingContext& aRenderingContext,
546 const nsRect& aDirtyRect,
547 nsPoint aPt) {
548 nsIFrame* pageContentFrame = mFrames.FirstChild();
549 nsRect rect = aDirtyRect;
550 float scale = PresContext()->GetPageScale();
551 aRenderingContext.PushState();
552 nsPoint framePos = aPt + pageContentFrame->GetOffsetTo(this);
553 aRenderingContext.Translate(framePos.x, framePos.y);
554 // aPt translates to coords relative to this, then margins translate to
555 // pageContentFrame's coords
556 rect -= framePos;
557 aRenderingContext.Scale(scale, scale);
558 rect.ScaleRoundOut(1.0f / scale);
559 // Make sure we don't draw where we aren't supposed to draw, especially
560 // when printing selection
561 nsRect clipRect(nsPoint(0, 0), pageContentFrame->GetSize());
562 // Note: this computation matches how we compute maxSize.height
563 // in nsPageFrame::Reflow
564 nscoord expectedPageContentHeight =
565 NSToCoordCeil((GetSize().height - mPD->mReflowMargin.TopBottom()) / scale);
566 if (clipRect.height > expectedPageContentHeight) {
567 // We're doing print-selection, with one long page-content frame.
568 // Clip to the appropriate page-content slice for the current page.
569 NS_ASSERTION(mPageNum > 0, "page num should be positive");
570 // Note: The pageContentFrame's y-position has been set such that a zero
571 // y-value matches the top edge of the current page. So, to clip to the
572 // current page's content (in coordinates *relative* to the page content
573 // frame), we just negate its y-position and add the top margin.
574 clipRect.y = NSToCoordCeil((-pageContentFrame->GetRect().y +
575 mPD->mReflowMargin.top) / scale);
576 clipRect.height = expectedPageContentHeight;
577 NS_ASSERTION(clipRect.y < pageContentFrame->GetSize().height,
578 "Should be clipping to region inside the page content bounds");
580 aRenderingContext.SetClipRect(clipRect, nsClipCombine_kIntersect);
582 nsRect backgroundRect = nsRect(nsPoint(0, 0), pageContentFrame->GetSize());
583 nsCSSRendering::PaintBackground(PresContext(), aRenderingContext, this,
584 rect, backgroundRect,
585 nsCSSRendering::PAINTBG_SYNC_DECODE_IMAGES);
587 nsLayoutUtils::PaintFrame(&aRenderingContext, pageContentFrame,
588 nsRegion(rect), NS_RGBA(0,0,0,0),
589 nsLayoutUtils::PAINT_SYNC_DECODE_IMAGES);
591 aRenderingContext.PopState();
594 void
595 nsPageFrame::SetSharedPageData(nsSharedPageData* aPD)
597 mPD = aPD;
598 // Set the shared data into the page frame before reflow
599 nsPageContentFrame * pcf = static_cast<nsPageContentFrame*>(mFrames.FirstChild());
600 if (pcf) {
601 pcf->SetSharedPageData(mPD);
606 nsIFrame*
607 NS_NewPageBreakFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
609 NS_PRECONDITION(aPresShell, "null PresShell");
610 //check that we are only creating page break frames when printing
611 NS_ASSERTION(aPresShell->GetPresContext()->IsPaginated(), "created a page break frame while not printing");
613 return new (aPresShell) nsPageBreakFrame(aContext);
616 NS_IMPL_FRAMEARENA_HELPERS(nsPageBreakFrame)
618 nsPageBreakFrame::nsPageBreakFrame(nsStyleContext* aContext) :
619 nsLeafFrame(aContext), mHaveReflowed(PR_FALSE)
623 nsPageBreakFrame::~nsPageBreakFrame()
627 nscoord
628 nsPageBreakFrame::GetIntrinsicWidth()
630 return nsPresContext::CSSPixelsToAppUnits(1);
633 nscoord
634 nsPageBreakFrame::GetIntrinsicHeight()
636 return 0;
639 nsresult
640 nsPageBreakFrame::Reflow(nsPresContext* aPresContext,
641 nsHTMLReflowMetrics& aDesiredSize,
642 const nsHTMLReflowState& aReflowState,
643 nsReflowStatus& aStatus)
645 DO_GLOBAL_REFLOW_COUNT("nsPageBreakFrame");
646 DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
648 // Override reflow, since we don't want to deal with what our
649 // computed values are.
650 aDesiredSize.width = GetIntrinsicWidth();
651 aDesiredSize.height = (aReflowState.availableHeight == NS_UNCONSTRAINEDSIZE ?
652 0 : aReflowState.availableHeight);
653 // round the height down to the nearest pixel
654 aDesiredSize.height -=
655 aDesiredSize.height % nsPresContext::CSSPixelsToAppUnits(1);
657 // Note: not using NS_FRAME_FIRST_REFLOW here, since it's not clear whether
658 // DidReflow will always get called before the next Reflow() call.
659 mHaveReflowed = PR_TRUE;
660 aStatus = NS_FRAME_COMPLETE;
661 return NS_OK;
664 nsIAtom*
665 nsPageBreakFrame::GetType() const
667 return nsGkAtoms::pageBreakFrame;
670 #ifdef DEBUG
671 NS_IMETHODIMP
672 nsPageBreakFrame::GetFrameName(nsAString& aResult) const
674 return MakeFrameName(NS_LITERAL_STRING("PageBreak"), aResult);
676 #endif