Bumping manifests a=b2g-bump
[gecko.git] / layout / generic / nsPageFrame.cpp
blob132f10ec37847f021fdbf2b65a4be7ea64f47dee
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"
8 #include "mozilla/gfx/2D.h"
9 #include "nsDeviceContext.h"
10 #include "nsFontMetrics.h"
11 #include "nsLayoutUtils.h"
12 #include "nsPresContext.h"
13 #include "nsRenderingContext.h"
14 #include "nsGkAtoms.h"
15 #include "nsIPresShell.h"
16 #include "nsPageContentFrame.h"
17 #include "nsDisplayList.h"
18 #include "nsLayoutUtils.h" // for function BinarySearchForPosition
19 #include "nsSimplePageSequenceFrame.h" // for nsSharedPageData
20 #include "nsTextFormatter.h" // for page number localization formatting
21 #include "nsBidiUtils.h"
22 #include "nsIPrintSettings.h"
24 #include "prlog.h"
25 #ifdef PR_LOGGING
26 extern PRLogModuleInfo *GetLayoutPrintingLog();
27 #define PR_PL(_p1) PR_LOG(GetLayoutPrintingLog(), PR_LOG_DEBUG, _p1)
28 #else
29 #define PR_PL(_p1)
30 #endif
32 using namespace mozilla;
33 using namespace mozilla::gfx;
35 nsPageFrame*
36 NS_NewPageFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
38 return new (aPresShell) nsPageFrame(aContext);
41 NS_IMPL_FRAMEARENA_HELPERS(nsPageFrame)
43 nsPageFrame::nsPageFrame(nsStyleContext* aContext)
44 : nsContainerFrame(aContext)
48 nsPageFrame::~nsPageFrame()
52 void
53 nsPageFrame::Reflow(nsPresContext* aPresContext,
54 nsHTMLReflowMetrics& aDesiredSize,
55 const nsHTMLReflowState& aReflowState,
56 nsReflowStatus& aStatus)
58 DO_GLOBAL_REFLOW_COUNT("nsPageFrame");
59 DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
60 aStatus = NS_FRAME_COMPLETE; // initialize out parameter
62 NS_ASSERTION(mFrames.FirstChild() &&
63 nsGkAtoms::pageContentFrame == mFrames.FirstChild()->GetType(),
64 "pageFrame must have a pageContentFrame child");
66 // Resize our frame allowing it only to be as big as we are
67 // XXX Pay attention to the page's border and padding...
68 if (mFrames.NotEmpty()) {
69 nsIFrame* frame = mFrames.FirstChild();
70 // When the reflow size is NS_UNCONSTRAINEDSIZE it means we are reflowing
71 // a single page to print selection. So this means we want to use
72 // NS_UNCONSTRAINEDSIZE without altering it
73 nscoord avHeight;
74 if (mPD->mReflowSize.height == NS_UNCONSTRAINEDSIZE) {
75 avHeight = NS_UNCONSTRAINEDSIZE;
76 } else {
77 avHeight = mPD->mReflowSize.height;
79 nsSize maxSize(mPD->mReflowSize.width, avHeight);
80 float scale = aPresContext->GetPageScale();
81 maxSize.width = NSToCoordCeil(maxSize.width / scale);
82 if (maxSize.height != NS_UNCONSTRAINEDSIZE) {
83 maxSize.height = NSToCoordCeil(maxSize.height / scale);
85 // Get the number of Twips per pixel from the PresContext
86 nscoord onePixelInTwips = nsPresContext::CSSPixelsToAppUnits(1);
87 // insurance against infinite reflow, when reflowing less than a pixel
88 // XXX Shouldn't we do something more friendly when invalid margins
89 // are set?
90 if (maxSize.width < onePixelInTwips || maxSize.height < onePixelInTwips) {
91 aDesiredSize.ClearSize();
92 NS_WARNING("Reflow aborted; no space for content");
93 return;
96 nsHTMLReflowState kidReflowState(aPresContext, aReflowState, frame,
97 LogicalSize(frame->GetWritingMode(),
98 maxSize));
99 kidReflowState.mFlags.mIsTopOfPage = true;
100 kidReflowState.mFlags.mTableIsSplittable = true;
102 // Use the margins given in the @page rule.
103 // If a margin is 'auto', use the margin from the print settings for that side.
104 nsMargin pageContentMargin;
105 const nsStyleSides& marginStyle = kidReflowState.mStyleMargin->mMargin;
106 NS_FOR_CSS_SIDES(side) {
107 if (marginStyle.GetUnit(side) == eStyleUnit_Auto) {
108 pageContentMargin.Side(side) = mPD->mReflowMargin.Side(side);
109 } else {
110 pageContentMargin.Side(side) = kidReflowState.ComputedPhysicalMargin().Side(side);
115 nscoord maxWidth = maxSize.width - pageContentMargin.LeftRight() / scale;
116 nscoord maxHeight;
117 if (maxSize.height == NS_UNCONSTRAINEDSIZE) {
118 maxHeight = NS_UNCONSTRAINEDSIZE;
119 } else {
120 maxHeight = maxSize.height - pageContentMargin.TopBottom() / scale;
123 // Check the width and height, if they're too small we reset the margins
124 // back to the default.
125 if (maxWidth < onePixelInTwips ||
126 (maxHeight != NS_UNCONSTRAINEDSIZE && maxHeight < onePixelInTwips)) {
127 NS_FOR_CSS_SIDES(side) {
128 pageContentMargin.Side(side) = mPD->mReflowMargin.Side(side);
130 maxWidth = maxSize.width - pageContentMargin.LeftRight() / scale;
131 if (maxHeight != NS_UNCONSTRAINEDSIZE) {
132 maxHeight = maxSize.height - pageContentMargin.TopBottom() / scale;
136 kidReflowState.SetComputedWidth(maxWidth);
137 kidReflowState.SetComputedHeight(maxHeight);
139 // calc location of frame
140 nscoord xc = pageContentMargin.left;
141 nscoord yc = pageContentMargin.top;
143 // Get the child's desired size
144 ReflowChild(frame, aPresContext, aDesiredSize, kidReflowState, xc, yc, 0, aStatus);
146 // Place and size the child
147 FinishReflowChild(frame, aPresContext, aDesiredSize, &kidReflowState, xc, yc, 0);
149 NS_ASSERTION(!NS_FRAME_IS_FULLY_COMPLETE(aStatus) ||
150 !frame->GetNextInFlow(), "bad child flow list");
152 PR_PL(("PageFrame::Reflow %p ", this));
153 PR_PL(("[%d,%d][%d,%d]\n", aDesiredSize.Width(), aDesiredSize.Height(),
154 aReflowState.AvailableWidth(), aReflowState.AvailableHeight()));
156 // Return our desired size
157 WritingMode wm = aReflowState.GetWritingMode();
158 aDesiredSize.ISize(wm) = aReflowState.AvailableISize();
159 if (aReflowState.AvailableBSize() != NS_UNCONSTRAINEDSIZE) {
160 aDesiredSize.BSize(wm) = aReflowState.AvailableBSize();
163 aDesiredSize.SetOverflowAreasToDesiredBounds();
164 FinishAndStoreOverflow(&aDesiredSize);
166 PR_PL(("PageFrame::Reflow %p ", this));
167 PR_PL(("[%d,%d]\n", aReflowState.AvailableWidth(), aReflowState.AvailableHeight()));
169 NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
172 nsIAtom*
173 nsPageFrame::GetType() const
175 return nsGkAtoms::pageFrame;
178 #ifdef DEBUG_FRAME_DUMP
179 nsresult
180 nsPageFrame::GetFrameName(nsAString& aResult) const
182 return MakeFrameName(NS_LITERAL_STRING("Page"), aResult);
184 #endif
186 void
187 nsPageFrame::ProcessSpecialCodes(const nsString& aStr, nsString& aNewStr)
190 aNewStr = aStr;
192 // Search to see if the &D code is in the string
193 // then subst in the current date/time
194 NS_NAMED_LITERAL_STRING(kDate, "&D");
195 if (aStr.Find(kDate) != kNotFound) {
196 aNewStr.ReplaceSubstring(kDate.get(), mPD->mDateTimeStr.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 char16_t * uStr = nsTextFormatter::smprintf(mPD->mPageNumAndTotalsFormat.get(), 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 char16_t * uStr = nsTextFormatter::smprintf(mPD->mPageNumFormat.get(), 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 aNewStr.ReplaceSubstring(kTitle.get(), mPD->mDocTitle.get());
225 NS_NAMED_LITERAL_STRING(kDocURL, "&U");
226 if (aStr.Find(kDocURL) != kNotFound) {
227 aNewStr.ReplaceSubstring(kDocURL.get(), mPD->mDocURL.get());
230 NS_NAMED_LITERAL_STRING(kPageTotal, "&L");
231 if (aStr.Find(kPageTotal) != kNotFound) {
232 char16_t * uStr = nsTextFormatter::smprintf(mPD->mPageNumFormat.get(), mTotNumPages);
233 aNewStr.ReplaceSubstring(kPageTotal.get(), uStr);
234 nsMemory::Free(uStr);
239 //------------------------------------------------------------------------------
240 nscoord nsPageFrame::GetXPosition(nsRenderingContext& aRenderingContext,
241 nsFontMetrics& aFontMetrics,
242 const nsRect& aRect,
243 int32_t aJust,
244 const nsString& aStr)
246 nscoord width = nsLayoutUtils::AppUnitWidthOfStringBidi(aStr, this,
247 aFontMetrics,
248 aRenderingContext);
249 nscoord x = aRect.x;
250 switch (aJust) {
251 case nsIPrintSettings::kJustLeft:
252 x += mPD->mEdgePaperMargin.left;
253 break;
255 case nsIPrintSettings::kJustCenter:
256 x += (aRect.width - width) / 2;
257 break;
259 case nsIPrintSettings::kJustRight:
260 x += aRect.width - width - mPD->mEdgePaperMargin.right;
261 break;
262 } // switch
264 return x;
267 // Draw a header or footer
268 // @param aRenderingContext - rendering content ot draw into
269 // @param aHeaderFooter - indicates whether it is a header or footer
270 // @param aStrLeft - string for the left header or footer; can be empty
271 // @param aStrCenter - string for the center header or footer; can be empty
272 // @param aStrRight - string for the right header or footer; can be empty
273 // @param aRect - the rect of the page
274 // @param aAscent - the ascent of the font
275 // @param aHeight - the height of the font
276 void
277 nsPageFrame::DrawHeaderFooter(nsRenderingContext& aRenderingContext,
278 nsFontMetrics& aFontMetrics,
279 nsHeaderFooterEnum aHeaderFooter,
280 const nsString& aStrLeft,
281 const nsString& aStrCenter,
282 const nsString& aStrRight,
283 const nsRect& aRect,
284 nscoord aAscent,
285 nscoord aHeight)
287 int32_t numStrs = 0;
288 if (!aStrLeft.IsEmpty()) numStrs++;
289 if (!aStrCenter.IsEmpty()) numStrs++;
290 if (!aStrRight.IsEmpty()) numStrs++;
292 if (numStrs == 0) return;
293 nscoord strSpace = aRect.width / numStrs;
295 if (!aStrLeft.IsEmpty()) {
296 DrawHeaderFooter(aRenderingContext, aFontMetrics, aHeaderFooter,
297 nsIPrintSettings::kJustLeft, aStrLeft, aRect, aAscent,
298 aHeight, strSpace);
300 if (!aStrCenter.IsEmpty()) {
301 DrawHeaderFooter(aRenderingContext, aFontMetrics, aHeaderFooter,
302 nsIPrintSettings::kJustCenter, aStrCenter, aRect, aAscent,
303 aHeight, strSpace);
305 if (!aStrRight.IsEmpty()) {
306 DrawHeaderFooter(aRenderingContext, aFontMetrics, aHeaderFooter,
307 nsIPrintSettings::kJustRight, aStrRight, aRect, aAscent,
308 aHeight, strSpace);
312 // Draw a header or footer string
313 // @param aRenderingContext - rendering context to draw into
314 // @param aHeaderFooter - indicates whether it is a header or footer
315 // @param aJust - indicates where the string is located within the header/footer
316 // @param aStr - the string to be drawn
317 // @param aRect - the rect of the page
318 // @param aHeight - the height of the font
319 // @param aAscent - the ascent of the font
320 // @param aWidth - available width for the string
321 void
322 nsPageFrame::DrawHeaderFooter(nsRenderingContext& aRenderingContext,
323 nsFontMetrics& aFontMetrics,
324 nsHeaderFooterEnum aHeaderFooter,
325 int32_t aJust,
326 const nsString& aStr,
327 const nsRect& aRect,
328 nscoord aAscent,
329 nscoord aHeight,
330 nscoord aWidth)
333 nscoord contentWidth = aWidth - (mPD->mEdgePaperMargin.left + mPD->mEdgePaperMargin.right);
335 if ((aHeaderFooter == eHeader && aHeight < mPD->mReflowMargin.top) ||
336 (aHeaderFooter == eFooter && aHeight < mPD->mReflowMargin.bottom)) {
337 nsAutoString str;
338 ProcessSpecialCodes(aStr, str);
340 int32_t indx;
341 int32_t textWidth = 0;
342 const char16_t* text = str.get();
344 int32_t len = (int32_t)str.Length();
345 if (len == 0) {
346 return; // bail is empty string
348 // find how much text fits, the "position" is the size of the available area
349 if (nsLayoutUtils::BinarySearchForPosition(&aRenderingContext, aFontMetrics,
350 text, 0, 0, 0, len,
351 int32_t(contentWidth), indx, textWidth)) {
352 if (indx < len-1 ) {
353 // we can't fit in all the text
354 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 str.Truncate(indx-3);
362 str.AppendLiteral("...");
363 } else {
364 // We can only fit 3 or fewer chars. Just show nothing
365 str.Truncate();
368 } else {
369 return; // bail if couldn't find the correct length
372 if (HasRTLChars(str)) {
373 PresContext()->SetBidiEnabled();
376 // cacl the x and y positions of the text
377 nscoord x = GetXPosition(aRenderingContext, aFontMetrics, aRect, aJust, str);
378 nscoord y;
379 if (aHeaderFooter == eHeader) {
380 y = aRect.y + mPD->mEdgePaperMargin.top;
381 } else {
382 y = aRect.YMost() - aHeight - mPD->mEdgePaperMargin.bottom;
385 DrawTarget* drawTarget = aRenderingContext.GetDrawTarget();
386 gfxContext* gfx = aRenderingContext.ThebesContext();
388 // set up new clip and draw the text
389 gfx->Save();
390 gfx->Clip(NSRectToSnappedRect(aRect, PresContext()->AppUnitsPerDevPixel(),
391 *drawTarget));
392 aRenderingContext.ThebesContext()->SetColor(NS_RGB(0,0,0));
393 nsLayoutUtils::DrawString(this, aFontMetrics, &aRenderingContext,
394 str.get(), str.Length(),
395 nsPoint(x, y + aAscent));
396 gfx->Restore();
401 * Remove all leaf display items that are not for descendants of
402 * aBuilder->GetReferenceFrame() from aList.
403 * @param aPage the page we're constructing the display list for
404 * @param aExtraPage the page we constructed aList for
405 * @param aList the list that is modified in-place
407 static void
408 PruneDisplayListForExtraPage(nsDisplayListBuilder* aBuilder,
409 nsPageFrame* aPage, nsIFrame* aExtraPage,
410 nsDisplayList* aList)
412 nsDisplayList newList;
414 while (true) {
415 nsDisplayItem* i = aList->RemoveBottom();
416 if (!i)
417 break;
418 nsDisplayList* subList = i->GetSameCoordinateSystemChildren();
419 if (subList) {
420 PruneDisplayListForExtraPage(aBuilder, aPage, aExtraPage, subList);
421 i->UpdateBounds(aBuilder);
422 } else {
423 nsIFrame* f = i->Frame();
424 if (!nsLayoutUtils::IsProperAncestorFrameCrossDoc(aPage, f)) {
425 // We're throwing this away so call its destructor now. The memory
426 // is owned by aBuilder which destroys all items at once.
427 i->~nsDisplayItem();
428 continue;
431 newList.AppendToTop(i);
433 aList->AppendToTop(&newList);
436 static void
437 BuildDisplayListForExtraPage(nsDisplayListBuilder* aBuilder,
438 nsPageFrame* aPage, nsIFrame* aExtraPage,
439 const nsRect& aDirtyRect, nsDisplayList* aList)
441 // The only content in aExtraPage we care about is out-of-flow content whose
442 // placeholders have occurred in aPage. If
443 // NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO is not set, then aExtraPage has
444 // no such content.
445 if (!aExtraPage->HasAnyStateBits(NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO)) {
446 return;
448 nsDisplayList list;
449 aExtraPage->BuildDisplayListForStackingContext(aBuilder, aDirtyRect, &list);
450 PruneDisplayListForExtraPage(aBuilder, aPage, aExtraPage, &list);
451 aList->AppendToTop(&list);
454 static nsIFrame*
455 GetNextPage(nsIFrame* aPageContentFrame)
457 // XXX ugh
458 nsIFrame* pageFrame = aPageContentFrame->GetParent();
459 NS_ASSERTION(pageFrame->GetType() == nsGkAtoms::pageFrame,
460 "pageContentFrame has unexpected parent");
461 nsIFrame* nextPageFrame = pageFrame->GetNextSibling();
462 if (!nextPageFrame)
463 return nullptr;
464 NS_ASSERTION(nextPageFrame->GetType() == nsGkAtoms::pageFrame,
465 "pageFrame's sibling is not a page frame...");
466 nsIFrame* f = nextPageFrame->GetFirstPrincipalChild();
467 NS_ASSERTION(f, "pageFrame has no page content frame!");
468 NS_ASSERTION(f->GetType() == nsGkAtoms::pageContentFrame,
469 "pageFrame's child is not page content!");
470 return f;
473 static gfx::Matrix4x4 ComputePageTransform(nsIFrame* aFrame, float aAppUnitsPerPixel)
475 float scale = aFrame->PresContext()->GetPageScale();
476 return gfx::Matrix4x4::Scaling(scale, scale, 1);
479 class nsDisplayHeaderFooter : public nsDisplayItem {
480 public:
481 nsDisplayHeaderFooter(nsDisplayListBuilder* aBuilder, nsPageFrame *aFrame)
482 : nsDisplayItem(aBuilder, aFrame), mFrame(aFrame)
483 , mDisableSubpixelAA(false)
485 MOZ_COUNT_CTOR(nsDisplayHeaderFooter);
487 #ifdef NS_BUILD_REFCNT_LOGGING
488 virtual ~nsDisplayHeaderFooter() {
489 MOZ_COUNT_DTOR(nsDisplayHeaderFooter);
491 #endif
493 virtual void Paint(nsDisplayListBuilder* aBuilder,
494 nsRenderingContext* aCtx) MOZ_OVERRIDE {
495 mFrame->PaintHeaderFooter(*aCtx, ToReferenceFrame(), mDisableSubpixelAA);
497 NS_DISPLAY_DECL_NAME("HeaderFooter", nsDisplayItem::TYPE_HEADER_FOOTER)
499 virtual nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE {
500 bool snap;
501 return GetBounds(aBuilder, &snap);
504 virtual void DisableComponentAlpha() MOZ_OVERRIDE {
505 mDisableSubpixelAA = true;
507 protected:
508 nsPageFrame* mFrame;
509 bool mDisableSubpixelAA;
512 //------------------------------------------------------------------------------
513 void
514 nsPageFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
515 const nsRect& aDirtyRect,
516 const nsDisplayListSet& aLists)
518 nsDisplayListCollection set;
520 if (PresContext()->IsScreen()) {
521 DisplayBorderBackgroundOutline(aBuilder, aLists);
524 nsIFrame *child = mFrames.FirstChild();
525 float scale = PresContext()->GetPageScale();
526 nsRect clipRect(nsPoint(0, 0), child->GetSize());
527 // Note: this computation matches how we compute maxSize.height
528 // in nsPageFrame::Reflow
529 nscoord expectedPageContentHeight = NSToCoordCeil(GetSize().height / scale);
530 if (clipRect.height > expectedPageContentHeight) {
531 // We're doing print-selection, with one long page-content frame.
532 // Clip to the appropriate page-content slice for the current page.
533 NS_ASSERTION(mPageNum > 0, "page num should be positive");
534 // Note: The pageContentFrame's y-position has been set such that a zero
535 // y-value matches the top edge of the current page. So, to clip to the
536 // current page's content (in coordinates *relative* to the page content
537 // frame), we just negate its y-position and add the top margin.
538 clipRect.y = NSToCoordCeil((-child->GetRect().y +
539 mPD->mReflowMargin.top) / scale);
540 clipRect.height = expectedPageContentHeight;
541 NS_ASSERTION(clipRect.y < child->GetSize().height,
542 "Should be clipping to region inside the page content bounds");
544 clipRect += aBuilder->ToReferenceFrame(child);
546 nsDisplayList content;
548 DisplayListClipState::AutoSaveRestore clipState(aBuilder);
550 // Overwrite current clip, since we're going to wrap in a transform
551 // and the current clip is no longer meaningful.
552 clipState.Clear();
553 clipState.ClipContainingBlockDescendants(clipRect, nullptr);
555 nsRect dirtyRect = child->GetVisualOverflowRectRelativeToSelf();
556 child->BuildDisplayListForStackingContext(aBuilder, dirtyRect, &content);
558 // We may need to paint out-of-flow frames whose placeholders are
559 // on other pages. Add those pages to our display list. Note that
560 // out-of-flow frames can't be placed after their placeholders so
561 // we don't have to process earlier pages. The display lists for
562 // these extra pages are pruned so that only display items for the
563 // page we currently care about (which we would have reached by
564 // following placeholders to their out-of-flows) end up on the list.
565 nsIFrame* page = child;
566 while ((page = GetNextPage(page)) != nullptr) {
567 BuildDisplayListForExtraPage(aBuilder, this, page,
568 dirtyRect + child->GetOffsetTo(page), &content);
571 // Invoke AutoBuildingDisplayList to ensure that the correct dirtyRect
572 // is used to compute the visible rect if AddCanvasBackgroundColorItem
573 // creates a display item.
574 nsDisplayListBuilder::AutoBuildingDisplayList
575 building(aBuilder, child, dirtyRect, true);
577 // Add the canvas background color to the bottom of the list. This
578 // happens after we've built the list so that AddCanvasBackgroundColorItem
579 // can monkey with the contents if necessary.
580 nsRect backgroundRect =
581 nsRect(aBuilder->ToReferenceFrame(child), child->GetSize());
582 PresContext()->GetPresShell()->AddCanvasBackgroundColorItem(
583 *aBuilder, content, child, backgroundRect, NS_RGBA(0,0,0,0));
586 content.AppendNewToTop(new (aBuilder) nsDisplayTransform(aBuilder, child,
587 &content, content.GetVisibleRect(), ::ComputePageTransform));
589 set.Content()->AppendToTop(&content);
591 if (PresContext()->IsRootPaginatedDocument()) {
592 set.Content()->AppendNewToTop(new (aBuilder)
593 nsDisplayHeaderFooter(aBuilder, this));
596 set.MoveTo(aLists);
599 //------------------------------------------------------------------------------
600 void
601 nsPageFrame::SetPageNumInfo(int32_t aPageNumber, int32_t aTotalPages)
603 mPageNum = aPageNumber;
604 mTotNumPages = aTotalPages;
608 void
609 nsPageFrame::PaintHeaderFooter(nsRenderingContext& aRenderingContext,
610 nsPoint aPt, bool aDisableSubpixelAA)
612 nsPresContext* pc = PresContext();
614 if (!mPD->mPrintSettings) {
615 if (pc->Type() == nsPresContext::eContext_PrintPreview || pc->IsDynamic())
616 mPD->mPrintSettings = pc->GetPrintSettings();
617 if (!mPD->mPrintSettings)
618 return;
621 nsRect rect(aPt, mRect.Size());
622 aRenderingContext.ThebesContext()->SetColor(NS_RGB(0,0,0));
624 gfxContextAutoDisableSubpixelAntialiasing disable(aRenderingContext.ThebesContext(), aDisableSubpixelAA);
626 // Get the FontMetrics to determine width.height of strings
627 nsRefPtr<nsFontMetrics> fontMet;
628 pc->DeviceContext()->GetMetricsFor(mPD->mHeadFootFont, nullptr, false,
629 gfxFont::eHorizontal,
630 pc->GetUserFontSet(),
631 pc->GetTextPerfMetrics(),
632 *getter_AddRefs(fontMet));
634 nscoord ascent = 0;
635 nscoord visibleHeight = 0;
636 if (fontMet) {
637 visibleHeight = fontMet->MaxHeight();
638 ascent = fontMet->MaxAscent();
641 // print document headers and footers
642 nsXPIDLString headerLeft, headerCenter, headerRight;
643 mPD->mPrintSettings->GetHeaderStrLeft(getter_Copies(headerLeft));
644 mPD->mPrintSettings->GetHeaderStrCenter(getter_Copies(headerCenter));
645 mPD->mPrintSettings->GetHeaderStrRight(getter_Copies(headerRight));
646 DrawHeaderFooter(aRenderingContext, *fontMet, eHeader,
647 headerLeft, headerCenter, headerRight,
648 rect, ascent, visibleHeight);
650 nsXPIDLString footerLeft, footerCenter, footerRight;
651 mPD->mPrintSettings->GetFooterStrLeft(getter_Copies(footerLeft));
652 mPD->mPrintSettings->GetFooterStrCenter(getter_Copies(footerCenter));
653 mPD->mPrintSettings->GetFooterStrRight(getter_Copies(footerRight));
654 DrawHeaderFooter(aRenderingContext, *fontMet, eFooter,
655 footerLeft, footerCenter, footerRight,
656 rect, ascent, visibleHeight);
659 void
660 nsPageFrame::SetSharedPageData(nsSharedPageData* aPD)
662 mPD = aPD;
663 // Set the shared data into the page frame before reflow
664 nsPageContentFrame * pcf = static_cast<nsPageContentFrame*>(mFrames.FirstChild());
665 if (pcf) {
666 pcf->SetSharedPageData(mPD);
671 nsIFrame*
672 NS_NewPageBreakFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
674 NS_PRECONDITION(aPresShell, "null PresShell");
675 //check that we are only creating page break frames when printing
676 NS_ASSERTION(aPresShell->GetPresContext()->IsPaginated(), "created a page break frame while not printing");
678 return new (aPresShell) nsPageBreakFrame(aContext);
681 NS_IMPL_FRAMEARENA_HELPERS(nsPageBreakFrame)
683 nsPageBreakFrame::nsPageBreakFrame(nsStyleContext* aContext) :
684 nsLeafFrame(aContext), mHaveReflowed(false)
688 nsPageBreakFrame::~nsPageBreakFrame()
692 nscoord
693 nsPageBreakFrame::GetIntrinsicISize()
695 return nsPresContext::CSSPixelsToAppUnits(1);
698 nscoord
699 nsPageBreakFrame::GetIntrinsicBSize()
701 return 0;
704 void
705 nsPageBreakFrame::Reflow(nsPresContext* aPresContext,
706 nsHTMLReflowMetrics& aDesiredSize,
707 const nsHTMLReflowState& aReflowState,
708 nsReflowStatus& aStatus)
710 DO_GLOBAL_REFLOW_COUNT("nsPageBreakFrame");
711 DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
713 // Override reflow, since we don't want to deal with what our
714 // computed values are.
715 WritingMode wm = aReflowState.GetWritingMode();
716 LogicalSize finalSize(wm, GetIntrinsicISize(),
717 aReflowState.AvailableBSize() == NS_UNCONSTRAINEDSIZE ?
718 0 : aReflowState.AvailableBSize());
719 // round the height down to the nearest pixel
720 finalSize.BSize(wm) -=
721 finalSize.BSize(wm) % nsPresContext::CSSPixelsToAppUnits(1);
722 aDesiredSize.SetSize(wm, finalSize);
724 // Note: not using NS_FRAME_FIRST_REFLOW here, since it's not clear whether
725 // DidReflow will always get called before the next Reflow() call.
726 mHaveReflowed = true;
727 aStatus = NS_FRAME_COMPLETE;
730 nsIAtom*
731 nsPageBreakFrame::GetType() const
733 return nsGkAtoms::pageBreakFrame;
736 #ifdef DEBUG_FRAME_DUMP
737 nsresult
738 nsPageBreakFrame::GetFrameName(nsAString& aResult) const
740 return MakeFrameName(NS_LITERAL_STRING("PageBreak"), aResult);
742 #endif