Bumping manifests a=b2g-bump
[gecko.git] / layout / generic / nsPageFrame.cpp
blob5dc0f99b9746c808bcd1d91ef80d14b9d48c8d9a
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "nsPageFrame.h"
7 #include "nsPresContext.h"
8 #include "nsRenderingContext.h"
9 #include "nsGkAtoms.h"
10 #include "nsIPresShell.h"
11 #include "nsPageContentFrame.h"
12 #include "nsDisplayList.h"
13 #include "nsLayoutUtils.h" // for function BinarySearchForPosition
14 #include "nsSimplePageSequenceFrame.h" // for nsSharedPageData
15 #include "nsTextFormatter.h" // for page number localization formatting
16 #include "nsBidiUtils.h"
17 #include "nsIPrintSettings.h"
19 #include "prlog.h"
20 #ifdef PR_LOGGING
21 extern PRLogModuleInfo *GetLayoutPrintingLog();
22 #define PR_PL(_p1) PR_LOG(GetLayoutPrintingLog(), PR_LOG_DEBUG, _p1)
23 #else
24 #define PR_PL(_p1)
25 #endif
27 using namespace mozilla;
29 nsPageFrame*
30 NS_NewPageFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
32 return new (aPresShell) nsPageFrame(aContext);
35 NS_IMPL_FRAMEARENA_HELPERS(nsPageFrame)
37 nsPageFrame::nsPageFrame(nsStyleContext* aContext)
38 : nsContainerFrame(aContext)
42 nsPageFrame::~nsPageFrame()
46 void
47 nsPageFrame::Reflow(nsPresContext* aPresContext,
48 nsHTMLReflowMetrics& aDesiredSize,
49 const nsHTMLReflowState& aReflowState,
50 nsReflowStatus& aStatus)
52 DO_GLOBAL_REFLOW_COUNT("nsPageFrame");
53 DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
54 aStatus = NS_FRAME_COMPLETE; // initialize out parameter
56 NS_ASSERTION(mFrames.FirstChild() &&
57 nsGkAtoms::pageContentFrame == mFrames.FirstChild()->GetType(),
58 "pageFrame must have a pageContentFrame child");
60 // Resize our frame allowing it only to be as big as we are
61 // XXX Pay attention to the page's border and padding...
62 if (mFrames.NotEmpty()) {
63 nsIFrame* frame = mFrames.FirstChild();
64 // When the reflow size is NS_UNCONSTRAINEDSIZE it means we are reflowing
65 // a single page to print selection. So this means we want to use
66 // NS_UNCONSTRAINEDSIZE without altering it
67 nscoord avHeight;
68 if (mPD->mReflowSize.height == NS_UNCONSTRAINEDSIZE) {
69 avHeight = NS_UNCONSTRAINEDSIZE;
70 } else {
71 avHeight = mPD->mReflowSize.height;
73 nsSize maxSize(mPD->mReflowSize.width, avHeight);
74 float scale = aPresContext->GetPageScale();
75 maxSize.width = NSToCoordCeil(maxSize.width / scale);
76 if (maxSize.height != NS_UNCONSTRAINEDSIZE) {
77 maxSize.height = NSToCoordCeil(maxSize.height / scale);
79 // Get the number of Twips per pixel from the PresContext
80 nscoord onePixelInTwips = nsPresContext::CSSPixelsToAppUnits(1);
81 // insurance against infinite reflow, when reflowing less than a pixel
82 // XXX Shouldn't we do something more friendly when invalid margins
83 // are set?
84 if (maxSize.width < onePixelInTwips || maxSize.height < onePixelInTwips) {
85 aDesiredSize.ClearSize();
86 NS_WARNING("Reflow aborted; no space for content");
87 return;
90 nsHTMLReflowState kidReflowState(aPresContext, aReflowState, frame,
91 LogicalSize(frame->GetWritingMode(),
92 maxSize));
93 kidReflowState.mFlags.mIsTopOfPage = true;
94 kidReflowState.mFlags.mTableIsSplittable = true;
96 // Use the margins given in the @page rule.
97 // If a margin is 'auto', use the margin from the print settings for that side.
98 nsMargin pageContentMargin;
99 const nsStyleSides& marginStyle = kidReflowState.mStyleMargin->mMargin;
100 NS_FOR_CSS_SIDES(side) {
101 if (marginStyle.GetUnit(side) == eStyleUnit_Auto) {
102 pageContentMargin.Side(side) = mPD->mReflowMargin.Side(side);
103 } else {
104 pageContentMargin.Side(side) = kidReflowState.ComputedPhysicalMargin().Side(side);
109 nscoord maxWidth = maxSize.width - pageContentMargin.LeftRight() / scale;
110 nscoord maxHeight;
111 if (maxSize.height == NS_UNCONSTRAINEDSIZE) {
112 maxHeight = NS_UNCONSTRAINEDSIZE;
113 } else {
114 maxHeight = maxSize.height - pageContentMargin.TopBottom() / scale;
117 // Check the width and height, if they're too small we reset the margins
118 // back to the default.
119 if (maxWidth < onePixelInTwips ||
120 (maxHeight != NS_UNCONSTRAINEDSIZE && maxHeight < onePixelInTwips)) {
121 NS_FOR_CSS_SIDES(side) {
122 pageContentMargin.Side(side) = mPD->mReflowMargin.Side(side);
124 maxWidth = maxSize.width - pageContentMargin.LeftRight() / scale;
125 if (maxHeight != NS_UNCONSTRAINEDSIZE) {
126 maxHeight = maxSize.height - pageContentMargin.TopBottom() / scale;
130 kidReflowState.SetComputedWidth(maxWidth);
131 kidReflowState.SetComputedHeight(maxHeight);
133 // calc location of frame
134 nscoord xc = pageContentMargin.left;
135 nscoord yc = pageContentMargin.top;
137 // Get the child's desired size
138 ReflowChild(frame, aPresContext, aDesiredSize, kidReflowState, xc, yc, 0, aStatus);
140 // Place and size the child
141 FinishReflowChild(frame, aPresContext, aDesiredSize, &kidReflowState, xc, yc, 0);
143 NS_ASSERTION(!NS_FRAME_IS_FULLY_COMPLETE(aStatus) ||
144 !frame->GetNextInFlow(), "bad child flow list");
146 PR_PL(("PageFrame::Reflow %p ", this));
147 PR_PL(("[%d,%d][%d,%d]\n", aDesiredSize.Width(), aDesiredSize.Height(),
148 aReflowState.AvailableWidth(), aReflowState.AvailableHeight()));
150 // Return our desired size
151 WritingMode wm = aReflowState.GetWritingMode();
152 aDesiredSize.ISize(wm) = aReflowState.AvailableISize();
153 if (aReflowState.AvailableBSize() != NS_UNCONSTRAINEDSIZE) {
154 aDesiredSize.BSize(wm) = aReflowState.AvailableBSize();
157 aDesiredSize.SetOverflowAreasToDesiredBounds();
158 FinishAndStoreOverflow(&aDesiredSize);
160 PR_PL(("PageFrame::Reflow %p ", this));
161 PR_PL(("[%d,%d]\n", aReflowState.AvailableWidth(), aReflowState.AvailableHeight()));
163 NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
166 nsIAtom*
167 nsPageFrame::GetType() const
169 return nsGkAtoms::pageFrame;
172 #ifdef DEBUG_FRAME_DUMP
173 nsresult
174 nsPageFrame::GetFrameName(nsAString& aResult) const
176 return MakeFrameName(NS_LITERAL_STRING("Page"), aResult);
178 #endif
180 void
181 nsPageFrame::ProcessSpecialCodes(const nsString& aStr, nsString& aNewStr)
184 aNewStr = aStr;
186 // Search to see if the &D code is in the string
187 // then subst in the current date/time
188 NS_NAMED_LITERAL_STRING(kDate, "&D");
189 if (aStr.Find(kDate) != kNotFound) {
190 aNewStr.ReplaceSubstring(kDate.get(), mPD->mDateTimeStr.get());
193 // NOTE: Must search for &PT before searching for &P
195 // Search to see if the "page number and page" total code are in the string
196 // and replace the page number and page total code with the actual
197 // values
198 NS_NAMED_LITERAL_STRING(kPageAndTotal, "&PT");
199 if (aStr.Find(kPageAndTotal) != kNotFound) {
200 char16_t * uStr = nsTextFormatter::smprintf(mPD->mPageNumAndTotalsFormat.get(), mPageNum, mTotNumPages);
201 aNewStr.ReplaceSubstring(kPageAndTotal.get(), uStr);
202 nsMemory::Free(uStr);
205 // Search to see if the page number code is in the string
206 // and replace the page number code with the actual value
207 NS_NAMED_LITERAL_STRING(kPage, "&P");
208 if (aStr.Find(kPage) != kNotFound) {
209 char16_t * uStr = nsTextFormatter::smprintf(mPD->mPageNumFormat.get(), mPageNum);
210 aNewStr.ReplaceSubstring(kPage.get(), uStr);
211 nsMemory::Free(uStr);
214 NS_NAMED_LITERAL_STRING(kTitle, "&T");
215 if (aStr.Find(kTitle) != kNotFound) {
216 aNewStr.ReplaceSubstring(kTitle.get(), mPD->mDocTitle.get());
219 NS_NAMED_LITERAL_STRING(kDocURL, "&U");
220 if (aStr.Find(kDocURL) != kNotFound) {
221 aNewStr.ReplaceSubstring(kDocURL.get(), mPD->mDocURL.get());
224 NS_NAMED_LITERAL_STRING(kPageTotal, "&L");
225 if (aStr.Find(kPageTotal) != kNotFound) {
226 char16_t * uStr = nsTextFormatter::smprintf(mPD->mPageNumFormat.get(), mTotNumPages);
227 aNewStr.ReplaceSubstring(kPageTotal.get(), uStr);
228 nsMemory::Free(uStr);
233 //------------------------------------------------------------------------------
234 nscoord nsPageFrame::GetXPosition(nsRenderingContext& aRenderingContext,
235 const nsRect& aRect,
236 int32_t aJust,
237 const nsString& aStr)
239 nscoord width = nsLayoutUtils::GetStringWidth(this, &aRenderingContext,
240 aStr.get(), aStr.Length());
242 nscoord x = aRect.x;
243 switch (aJust) {
244 case nsIPrintSettings::kJustLeft:
245 x += mPD->mEdgePaperMargin.left;
246 break;
248 case nsIPrintSettings::kJustCenter:
249 x += (aRect.width - width) / 2;
250 break;
252 case nsIPrintSettings::kJustRight:
253 x += aRect.width - width - mPD->mEdgePaperMargin.right;
254 break;
255 } // switch
257 return x;
260 // Draw a header or footer
261 // @param aRenderingContext - rendering content ot draw into
262 // @param aHeaderFooter - indicates whether it is a header or footer
263 // @param aStrLeft - string for the left header or footer; can be empty
264 // @param aStrCenter - string for the center header or footer; can be empty
265 // @param aStrRight - string for the right header or footer; can be empty
266 // @param aRect - the rect of the page
267 // @param aAscent - the ascent of the font
268 // @param aHeight - the height of the font
269 void
270 nsPageFrame::DrawHeaderFooter(nsRenderingContext& aRenderingContext,
271 nsHeaderFooterEnum aHeaderFooter,
272 const nsString& aStrLeft,
273 const nsString& aStrCenter,
274 const nsString& aStrRight,
275 const nsRect& aRect,
276 nscoord aAscent,
277 nscoord aHeight)
279 int32_t numStrs = 0;
280 if (!aStrLeft.IsEmpty()) numStrs++;
281 if (!aStrCenter.IsEmpty()) numStrs++;
282 if (!aStrRight.IsEmpty()) numStrs++;
284 if (numStrs == 0) return;
285 nscoord strSpace = aRect.width / numStrs;
287 if (!aStrLeft.IsEmpty()) {
288 DrawHeaderFooter(aRenderingContext, aHeaderFooter,
289 nsIPrintSettings::kJustLeft, aStrLeft, aRect, aAscent,
290 aHeight, strSpace);
292 if (!aStrCenter.IsEmpty()) {
293 DrawHeaderFooter(aRenderingContext, aHeaderFooter,
294 nsIPrintSettings::kJustCenter, aStrCenter, aRect, aAscent,
295 aHeight, strSpace);
297 if (!aStrRight.IsEmpty()) {
298 DrawHeaderFooter(aRenderingContext, aHeaderFooter,
299 nsIPrintSettings::kJustRight, aStrRight, aRect, aAscent,
300 aHeight, strSpace);
304 // Draw a header or footer string
305 // @param aRenderingContext - rendering context to draw into
306 // @param aHeaderFooter - indicates whether it is a header or footer
307 // @param aJust - indicates where the string is located within the header/footer
308 // @param aStr - the string to be drawn
309 // @param aRect - the rect of the page
310 // @param aHeight - the height of the font
311 // @param aAscent - the ascent of the font
312 // @param aWidth - available width for the string
313 void
314 nsPageFrame::DrawHeaderFooter(nsRenderingContext& aRenderingContext,
315 nsHeaderFooterEnum aHeaderFooter,
316 int32_t aJust,
317 const nsString& aStr,
318 const nsRect& aRect,
319 nscoord aAscent,
320 nscoord aHeight,
321 nscoord aWidth)
324 nscoord contentWidth = aWidth - (mPD->mEdgePaperMargin.left + mPD->mEdgePaperMargin.right);
326 if ((aHeaderFooter == eHeader && aHeight < mPD->mReflowMargin.top) ||
327 (aHeaderFooter == eFooter && aHeight < mPD->mReflowMargin.bottom)) {
328 nsAutoString str;
329 ProcessSpecialCodes(aStr, str);
331 int32_t indx;
332 int32_t textWidth = 0;
333 const char16_t* text = str.get();
335 int32_t len = (int32_t)str.Length();
336 if (len == 0) {
337 return; // bail is empty string
339 // find how much text fits, the "position" is the size of the available area
340 if (nsLayoutUtils::BinarySearchForPosition(&aRenderingContext, text, 0, 0, 0, len,
341 int32_t(contentWidth), indx, textWidth)) {
342 if (indx < len-1 ) {
343 // we can't fit in all the text
344 if (indx > 3) {
345 // But we can fit in at least 4 chars. Show all but 3 of them, then
346 // an ellipsis.
347 // XXXbz for non-plane0 text, this may be cutting things in the
348 // middle of a codepoint! Also, we have no guarantees that the three
349 // dots will fit in the space the three chars we removed took up with
350 // these font metrics!
351 str.Truncate(indx-3);
352 str.AppendLiteral("...");
353 } else {
354 // We can only fit 3 or fewer chars. Just show nothing
355 str.Truncate();
358 } else {
359 return; // bail if couldn't find the correct length
362 if (HasRTLChars(str)) {
363 PresContext()->SetBidiEnabled();
366 // cacl the x and y positions of the text
367 nscoord x = GetXPosition(aRenderingContext, aRect, aJust, str);
368 nscoord y;
369 if (aHeaderFooter == eHeader) {
370 y = aRect.y + mPD->mEdgePaperMargin.top;
371 } else {
372 y = aRect.YMost() - aHeight - mPD->mEdgePaperMargin.bottom;
375 // set up new clip and draw the text
376 aRenderingContext.PushState();
377 aRenderingContext.SetColor(NS_RGB(0,0,0));
378 aRenderingContext.IntersectClip(aRect);
379 nsLayoutUtils::DrawString(this, &aRenderingContext, str.get(), str.Length(), nsPoint(x, y + aAscent));
380 aRenderingContext.PopState();
385 * Remove all leaf display items that are not for descendants of
386 * aBuilder->GetReferenceFrame() from aList.
387 * @param aPage the page we're constructing the display list for
388 * @param aExtraPage the page we constructed aList for
389 * @param aList the list that is modified in-place
391 static void
392 PruneDisplayListForExtraPage(nsDisplayListBuilder* aBuilder,
393 nsPageFrame* aPage, nsIFrame* aExtraPage,
394 nsDisplayList* aList)
396 nsDisplayList newList;
398 while (true) {
399 nsDisplayItem* i = aList->RemoveBottom();
400 if (!i)
401 break;
402 nsDisplayList* subList = i->GetSameCoordinateSystemChildren();
403 if (subList) {
404 PruneDisplayListForExtraPage(aBuilder, aPage, aExtraPage, subList);
405 i->UpdateBounds(aBuilder);
406 } else {
407 nsIFrame* f = i->Frame();
408 if (!nsLayoutUtils::IsProperAncestorFrameCrossDoc(aPage, f)) {
409 // We're throwing this away so call its destructor now. The memory
410 // is owned by aBuilder which destroys all items at once.
411 i->~nsDisplayItem();
412 continue;
415 newList.AppendToTop(i);
417 aList->AppendToTop(&newList);
420 static void
421 BuildDisplayListForExtraPage(nsDisplayListBuilder* aBuilder,
422 nsPageFrame* aPage, nsIFrame* aExtraPage,
423 const nsRect& aDirtyRect, nsDisplayList* aList)
425 // The only content in aExtraPage we care about is out-of-flow content whose
426 // placeholders have occurred in aPage. If
427 // NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO is not set, then aExtraPage has
428 // no such content.
429 if (!aExtraPage->HasAnyStateBits(NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO)) {
430 return;
432 nsDisplayList list;
433 aExtraPage->BuildDisplayListForStackingContext(aBuilder, aDirtyRect, &list);
434 PruneDisplayListForExtraPage(aBuilder, aPage, aExtraPage, &list);
435 aList->AppendToTop(&list);
438 static nsIFrame*
439 GetNextPage(nsIFrame* aPageContentFrame)
441 // XXX ugh
442 nsIFrame* pageFrame = aPageContentFrame->GetParent();
443 NS_ASSERTION(pageFrame->GetType() == nsGkAtoms::pageFrame,
444 "pageContentFrame has unexpected parent");
445 nsIFrame* nextPageFrame = pageFrame->GetNextSibling();
446 if (!nextPageFrame)
447 return nullptr;
448 NS_ASSERTION(nextPageFrame->GetType() == nsGkAtoms::pageFrame,
449 "pageFrame's sibling is not a page frame...");
450 nsIFrame* f = nextPageFrame->GetFirstPrincipalChild();
451 NS_ASSERTION(f, "pageFrame has no page content frame!");
452 NS_ASSERTION(f->GetType() == nsGkAtoms::pageContentFrame,
453 "pageFrame's child is not page content!");
454 return f;
457 static void PaintHeaderFooter(nsIFrame* aFrame, nsRenderingContext* aCtx,
458 const nsRect& aDirtyRect, nsPoint aPt)
460 static_cast<nsPageFrame*>(aFrame)->PaintHeaderFooter(*aCtx, aPt);
463 static gfx::Matrix4x4 ComputePageTransform(nsIFrame* aFrame, float aAppUnitsPerPixel)
465 float scale = aFrame->PresContext()->GetPageScale();
466 return gfx::Matrix4x4().Scale(scale, scale, 1);
469 //------------------------------------------------------------------------------
470 void
471 nsPageFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
472 const nsRect& aDirtyRect,
473 const nsDisplayListSet& aLists)
475 nsDisplayListCollection set;
477 if (PresContext()->IsScreen()) {
478 DisplayBorderBackgroundOutline(aBuilder, aLists);
481 nsIFrame *child = mFrames.FirstChild();
482 float scale = PresContext()->GetPageScale();
483 nsRect clipRect(nsPoint(0, 0), child->GetSize());
484 // Note: this computation matches how we compute maxSize.height
485 // in nsPageFrame::Reflow
486 nscoord expectedPageContentHeight = NSToCoordCeil(GetSize().height / scale);
487 if (clipRect.height > expectedPageContentHeight) {
488 // We're doing print-selection, with one long page-content frame.
489 // Clip to the appropriate page-content slice for the current page.
490 NS_ASSERTION(mPageNum > 0, "page num should be positive");
491 // Note: The pageContentFrame's y-position has been set such that a zero
492 // y-value matches the top edge of the current page. So, to clip to the
493 // current page's content (in coordinates *relative* to the page content
494 // frame), we just negate its y-position and add the top margin.
495 clipRect.y = NSToCoordCeil((-child->GetRect().y +
496 mPD->mReflowMargin.top) / scale);
497 clipRect.height = expectedPageContentHeight;
498 NS_ASSERTION(clipRect.y < child->GetSize().height,
499 "Should be clipping to region inside the page content bounds");
501 clipRect += aBuilder->ToReferenceFrame(child);
503 nsDisplayList content;
505 DisplayListClipState::AutoSaveRestore clipState(aBuilder);
507 // Overwrite current clip, since we're going to wrap in a transform
508 // and the current clip is no longer meaningful.
509 clipState.Clear();
510 clipState.ClipContainingBlockDescendants(clipRect, nullptr);
512 nsRect dirtyRect = child->GetVisualOverflowRectRelativeToSelf();
513 child->BuildDisplayListForStackingContext(aBuilder, dirtyRect, &content);
515 // We may need to paint out-of-flow frames whose placeholders are
516 // on other pages. Add those pages to our display list. Note that
517 // out-of-flow frames can't be placed after their placeholders so
518 // we don't have to process earlier pages. The display lists for
519 // these extra pages are pruned so that only display items for the
520 // page we currently care about (which we would have reached by
521 // following placeholders to their out-of-flows) end up on the list.
522 nsIFrame* page = child;
523 while ((page = GetNextPage(page)) != nullptr) {
524 BuildDisplayListForExtraPage(aBuilder, this, page,
525 dirtyRect + child->GetOffsetTo(page), &content);
528 // Invoke AutoBuildingDisplayList to ensure that the correct dirtyRect
529 // is used to compute the visible rect if AddCanvasBackgroundColorItem
530 // creates a display item.
531 nsDisplayListBuilder::AutoBuildingDisplayList
532 building(aBuilder, child, dirtyRect, true);
534 // Add the canvas background color to the bottom of the list. This
535 // happens after we've built the list so that AddCanvasBackgroundColorItem
536 // can monkey with the contents if necessary.
537 nsRect backgroundRect =
538 nsRect(aBuilder->ToReferenceFrame(child), child->GetSize());
539 PresContext()->GetPresShell()->AddCanvasBackgroundColorItem(
540 *aBuilder, content, child, backgroundRect, NS_RGBA(0,0,0,0));
543 content.AppendNewToTop(new (aBuilder) nsDisplayTransform(aBuilder, child,
544 &content, content.GetVisibleRect(), ::ComputePageTransform));
546 set.Content()->AppendToTop(&content);
548 if (PresContext()->IsRootPaginatedDocument()) {
549 set.Content()->AppendNewToTop(new (aBuilder)
550 nsDisplayGeneric(aBuilder, this, ::PaintHeaderFooter,
551 "HeaderFooter",
552 nsDisplayItem::TYPE_HEADER_FOOTER));
555 set.MoveTo(aLists);
558 //------------------------------------------------------------------------------
559 void
560 nsPageFrame::SetPageNumInfo(int32_t aPageNumber, int32_t aTotalPages)
562 mPageNum = aPageNumber;
563 mTotNumPages = aTotalPages;
567 void
568 nsPageFrame::PaintHeaderFooter(nsRenderingContext& aRenderingContext,
569 nsPoint aPt)
571 nsPresContext* pc = PresContext();
573 if (!mPD->mPrintSettings) {
574 if (pc->Type() == nsPresContext::eContext_PrintPreview || pc->IsDynamic())
575 mPD->mPrintSettings = pc->GetPrintSettings();
576 if (!mPD->mPrintSettings)
577 return;
580 nsRect rect(aPt, mRect.Size());
581 aRenderingContext.SetColor(NS_RGB(0,0,0));
583 // Get the FontMetrics to determine width.height of strings
584 nsRefPtr<nsFontMetrics> fontMet;
585 pc->DeviceContext()->GetMetricsFor(mPD->mHeadFootFont, nullptr,
586 pc->GetUserFontSet(),
587 pc->GetTextPerfMetrics(),
588 *getter_AddRefs(fontMet));
590 aRenderingContext.SetFont(fontMet);
592 nscoord ascent = 0;
593 nscoord visibleHeight = 0;
594 if (fontMet) {
595 visibleHeight = fontMet->MaxHeight();
596 ascent = fontMet->MaxAscent();
599 // print document headers and footers
600 nsXPIDLString headerLeft, headerCenter, headerRight;
601 mPD->mPrintSettings->GetHeaderStrLeft(getter_Copies(headerLeft));
602 mPD->mPrintSettings->GetHeaderStrCenter(getter_Copies(headerCenter));
603 mPD->mPrintSettings->GetHeaderStrRight(getter_Copies(headerRight));
604 DrawHeaderFooter(aRenderingContext, eHeader,
605 headerLeft, headerCenter, headerRight,
606 rect, ascent, visibleHeight);
608 nsXPIDLString footerLeft, footerCenter, footerRight;
609 mPD->mPrintSettings->GetFooterStrLeft(getter_Copies(footerLeft));
610 mPD->mPrintSettings->GetFooterStrCenter(getter_Copies(footerCenter));
611 mPD->mPrintSettings->GetFooterStrRight(getter_Copies(footerRight));
612 DrawHeaderFooter(aRenderingContext, eFooter,
613 footerLeft, footerCenter, footerRight,
614 rect, ascent, visibleHeight);
617 void
618 nsPageFrame::SetSharedPageData(nsSharedPageData* aPD)
620 mPD = aPD;
621 // Set the shared data into the page frame before reflow
622 nsPageContentFrame * pcf = static_cast<nsPageContentFrame*>(mFrames.FirstChild());
623 if (pcf) {
624 pcf->SetSharedPageData(mPD);
629 nsIFrame*
630 NS_NewPageBreakFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
632 NS_PRECONDITION(aPresShell, "null PresShell");
633 //check that we are only creating page break frames when printing
634 NS_ASSERTION(aPresShell->GetPresContext()->IsPaginated(), "created a page break frame while not printing");
636 return new (aPresShell) nsPageBreakFrame(aContext);
639 NS_IMPL_FRAMEARENA_HELPERS(nsPageBreakFrame)
641 nsPageBreakFrame::nsPageBreakFrame(nsStyleContext* aContext) :
642 nsLeafFrame(aContext), mHaveReflowed(false)
646 nsPageBreakFrame::~nsPageBreakFrame()
650 nscoord
651 nsPageBreakFrame::GetIntrinsicISize()
653 return nsPresContext::CSSPixelsToAppUnits(1);
656 nscoord
657 nsPageBreakFrame::GetIntrinsicBSize()
659 return 0;
662 void
663 nsPageBreakFrame::Reflow(nsPresContext* aPresContext,
664 nsHTMLReflowMetrics& aDesiredSize,
665 const nsHTMLReflowState& aReflowState,
666 nsReflowStatus& aStatus)
668 DO_GLOBAL_REFLOW_COUNT("nsPageBreakFrame");
669 DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
671 // Override reflow, since we don't want to deal with what our
672 // computed values are.
673 WritingMode wm = aReflowState.GetWritingMode();
674 LogicalSize finalSize(wm, GetIntrinsicISize(),
675 aReflowState.AvailableBSize() == NS_UNCONSTRAINEDSIZE ?
676 0 : aReflowState.AvailableBSize());
677 // round the height down to the nearest pixel
678 finalSize.BSize(wm) -=
679 finalSize.BSize(wm) % nsPresContext::CSSPixelsToAppUnits(1);
680 aDesiredSize.SetSize(wm, finalSize);
682 // Note: not using NS_FRAME_FIRST_REFLOW here, since it's not clear whether
683 // DidReflow will always get called before the next Reflow() call.
684 mHaveReflowed = true;
685 aStatus = NS_FRAME_COMPLETE;
688 nsIAtom*
689 nsPageBreakFrame::GetType() const
691 return nsGkAtoms::pageBreakFrame;
694 #ifdef DEBUG_FRAME_DUMP
695 nsresult
696 nsPageBreakFrame::GetFrameName(nsAString& aResult) const
698 return MakeFrameName(NS_LITERAL_STRING("PageBreak"), aResult);
700 #endif