layout/generic/nsPageFrame.cpp

branch
TOR_BUG_9701
changeset 15
b8a032363ba2
equal deleted inserted replaced
-1:000000000000 0:e571a152aefa
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/. */
5
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"
18
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
26
27 using namespace mozilla;
28
29 nsIFrame*
30 NS_NewPageFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
31 {
32 return new (aPresShell) nsPageFrame(aContext);
33 }
34
35 NS_IMPL_FRAMEARENA_HELPERS(nsPageFrame)
36
37 nsPageFrame::nsPageFrame(nsStyleContext* aContext)
38 : nsContainerFrame(aContext)
39 {
40 }
41
42 nsPageFrame::~nsPageFrame()
43 {
44 }
45
46 nsresult nsPageFrame::Reflow(nsPresContext* aPresContext,
47 nsHTMLReflowMetrics& aDesiredSize,
48 const nsHTMLReflowState& aReflowState,
49 nsReflowStatus& aStatus)
50 {
51 DO_GLOBAL_REFLOW_COUNT("nsPageFrame");
52 DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
53 aStatus = NS_FRAME_COMPLETE; // initialize out parameter
54
55 NS_ASSERTION(mFrames.FirstChild() &&
56 nsGkAtoms::pageContentFrame == mFrames.FirstChild()->GetType(),
57 "pageFrame must have a pageContentFrame child");
58
59 // Resize our frame allowing it only to be as big as we are
60 // XXX Pay attention to the page's border and padding...
61 if (mFrames.NotEmpty()) {
62 nsIFrame* frame = mFrames.FirstChild();
63 // When the reflow size is NS_UNCONSTRAINEDSIZE it means we are reflowing
64 // a single page to print selection. So this means we want to use
65 // NS_UNCONSTRAINEDSIZE without altering it
66 nscoord avHeight;
67 if (mPD->mReflowSize.height == NS_UNCONSTRAINEDSIZE) {
68 avHeight = NS_UNCONSTRAINEDSIZE;
69 } else {
70 avHeight = mPD->mReflowSize.height;
71 }
72 nsSize maxSize(mPD->mReflowSize.width, avHeight);
73 float scale = aPresContext->GetPageScale();
74 maxSize.width = NSToCoordCeil(maxSize.width / scale);
75 if (maxSize.height != NS_UNCONSTRAINEDSIZE) {
76 maxSize.height = NSToCoordCeil(maxSize.height / scale);
77 }
78 // Get the number of Twips per pixel from the PresContext
79 nscoord onePixelInTwips = nsPresContext::CSSPixelsToAppUnits(1);
80 // insurance against infinite reflow, when reflowing less than a pixel
81 // XXX Shouldn't we do something more friendly when invalid margins
82 // are set?
83 if (maxSize.width < onePixelInTwips || maxSize.height < onePixelInTwips) {
84 aDesiredSize.Width() = 0;
85 aDesiredSize.Height() = 0;
86 NS_WARNING("Reflow aborted; no space for content");
87 return NS_OK;
88 }
89
90 nsHTMLReflowState kidReflowState(aPresContext, aReflowState, frame, maxSize);
91 kidReflowState.mFlags.mIsTopOfPage = true;
92 kidReflowState.mFlags.mTableIsSplittable = true;
93
94 // Use the margins given in the @page rule.
95 // If a margin is 'auto', use the margin from the print settings for that side.
96 nsMargin pageContentMargin;
97 const nsStyleSides& marginStyle = kidReflowState.mStyleMargin->mMargin;
98 NS_FOR_CSS_SIDES(side) {
99 if (marginStyle.GetUnit(side) == eStyleUnit_Auto) {
100 pageContentMargin.Side(side) = mPD->mReflowMargin.Side(side);
101 } else {
102 pageContentMargin.Side(side) = kidReflowState.ComputedPhysicalMargin().Side(side);
103 }
104 }
105
106
107 nscoord maxWidth = maxSize.width - pageContentMargin.LeftRight() / scale;
108 nscoord maxHeight;
109 if (maxSize.height == NS_UNCONSTRAINEDSIZE) {
110 maxHeight = NS_UNCONSTRAINEDSIZE;
111 } else {
112 maxHeight = maxSize.height - pageContentMargin.TopBottom() / scale;
113 }
114
115 // Check the width and height, if they're too small we reset the margins
116 // back to the default.
117 if (maxWidth < onePixelInTwips ||
118 (maxHeight != NS_UNCONSTRAINEDSIZE && maxHeight < onePixelInTwips)) {
119 NS_FOR_CSS_SIDES(side) {
120 pageContentMargin.Side(side) = mPD->mReflowMargin.Side(side);
121 }
122 maxWidth = maxSize.width - pageContentMargin.LeftRight() / scale;
123 if (maxHeight != NS_UNCONSTRAINEDSIZE) {
124 maxHeight = maxSize.height - pageContentMargin.TopBottom() / scale;
125 }
126 }
127
128 kidReflowState.SetComputedWidth(maxWidth);
129 kidReflowState.SetComputedHeight(maxHeight);
130
131 // calc location of frame
132 nscoord xc = pageContentMargin.left;
133 nscoord yc = pageContentMargin.top;
134
135 // Get the child's desired size
136 ReflowChild(frame, aPresContext, aDesiredSize, kidReflowState, xc, yc, 0, aStatus);
137
138 // Place and size the child
139 FinishReflowChild(frame, aPresContext, aDesiredSize, &kidReflowState, xc, yc, 0);
140
141 NS_ASSERTION(!NS_FRAME_IS_FULLY_COMPLETE(aStatus) ||
142 !frame->GetNextInFlow(), "bad child flow list");
143 }
144 PR_PL(("PageFrame::Reflow %p ", this));
145 PR_PL(("[%d,%d][%d,%d]\n", aDesiredSize.Width(), aDesiredSize.Height(), aReflowState.AvailableWidth(), aReflowState.AvailableHeight()));
146
147 // Return our desired size
148 aDesiredSize.Width() = aReflowState.AvailableWidth();
149 if (aReflowState.AvailableHeight() != NS_UNCONSTRAINEDSIZE) {
150 aDesiredSize.Height() = aReflowState.AvailableHeight();
151 }
152
153 aDesiredSize.SetOverflowAreasToDesiredBounds();
154 FinishAndStoreOverflow(&aDesiredSize);
155
156 PR_PL(("PageFrame::Reflow %p ", this));
157 PR_PL(("[%d,%d]\n", aReflowState.AvailableWidth(), aReflowState.AvailableHeight()));
158
159 NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
160 return NS_OK;
161 }
162
163 nsIAtom*
164 nsPageFrame::GetType() const
165 {
166 return nsGkAtoms::pageFrame;
167 }
168
169 #ifdef DEBUG_FRAME_DUMP
170 nsresult
171 nsPageFrame::GetFrameName(nsAString& aResult) const
172 {
173 return MakeFrameName(NS_LITERAL_STRING("Page"), aResult);
174 }
175 #endif
176
177 void
178 nsPageFrame::ProcessSpecialCodes(const nsString& aStr, nsString& aNewStr)
179 {
180
181 aNewStr = aStr;
182
183 // Search to see if the &D code is in the string
184 // then subst in the current date/time
185 NS_NAMED_LITERAL_STRING(kDate, "&D");
186 if (aStr.Find(kDate) != kNotFound) {
187 aNewStr.ReplaceSubstring(kDate.get(), mPD->mDateTimeStr.get());
188 }
189
190 // NOTE: Must search for &PT before searching for &P
191 //
192 // Search to see if the "page number and page" total code are in the string
193 // and replace the page number and page total code with the actual
194 // values
195 NS_NAMED_LITERAL_STRING(kPageAndTotal, "&PT");
196 if (aStr.Find(kPageAndTotal) != kNotFound) {
197 char16_t * uStr = nsTextFormatter::smprintf(mPD->mPageNumAndTotalsFormat.get(), mPageNum, mTotNumPages);
198 aNewStr.ReplaceSubstring(kPageAndTotal.get(), uStr);
199 nsMemory::Free(uStr);
200 }
201
202 // Search to see if the page number code is in the string
203 // and replace the page number code with the actual value
204 NS_NAMED_LITERAL_STRING(kPage, "&P");
205 if (aStr.Find(kPage) != kNotFound) {
206 char16_t * uStr = nsTextFormatter::smprintf(mPD->mPageNumFormat.get(), mPageNum);
207 aNewStr.ReplaceSubstring(kPage.get(), uStr);
208 nsMemory::Free(uStr);
209 }
210
211 NS_NAMED_LITERAL_STRING(kTitle, "&T");
212 if (aStr.Find(kTitle) != kNotFound) {
213 aNewStr.ReplaceSubstring(kTitle.get(), mPD->mDocTitle.get());
214 }
215
216 NS_NAMED_LITERAL_STRING(kDocURL, "&U");
217 if (aStr.Find(kDocURL) != kNotFound) {
218 aNewStr.ReplaceSubstring(kDocURL.get(), mPD->mDocURL.get());
219 }
220
221 NS_NAMED_LITERAL_STRING(kPageTotal, "&L");
222 if (aStr.Find(kPageTotal) != kNotFound) {
223 char16_t * uStr = nsTextFormatter::smprintf(mPD->mPageNumFormat.get(), mTotNumPages);
224 aNewStr.ReplaceSubstring(kPageTotal.get(), uStr);
225 nsMemory::Free(uStr);
226 }
227 }
228
229
230 //------------------------------------------------------------------------------
231 nscoord nsPageFrame::GetXPosition(nsRenderingContext& aRenderingContext,
232 const nsRect& aRect,
233 int32_t aJust,
234 const nsString& aStr)
235 {
236 nscoord width = nsLayoutUtils::GetStringWidth(this, &aRenderingContext,
237 aStr.get(), aStr.Length());
238
239 nscoord x = aRect.x;
240 switch (aJust) {
241 case nsIPrintSettings::kJustLeft:
242 x += mPD->mEdgePaperMargin.left;
243 break;
244
245 case nsIPrintSettings::kJustCenter:
246 x += (aRect.width - width) / 2;
247 break;
248
249 case nsIPrintSettings::kJustRight:
250 x += aRect.width - width - mPD->mEdgePaperMargin.right;
251 break;
252 } // switch
253
254 return x;
255 }
256
257 // Draw a header or footer
258 // @param aRenderingContext - rendering content ot draw into
259 // @param aHeaderFooter - indicates whether it is a header or footer
260 // @param aStrLeft - string for the left header or footer; can be empty
261 // @param aStrCenter - string for the center header or footer; can be empty
262 // @param aStrRight - string for the right header or footer; can be empty
263 // @param aRect - the rect of the page
264 // @param aAscent - the ascent of the font
265 // @param aHeight - the height of the font
266 void
267 nsPageFrame::DrawHeaderFooter(nsRenderingContext& aRenderingContext,
268 nsHeaderFooterEnum aHeaderFooter,
269 const nsString& aStrLeft,
270 const nsString& aStrCenter,
271 const nsString& aStrRight,
272 const nsRect& aRect,
273 nscoord aAscent,
274 nscoord aHeight)
275 {
276 int32_t numStrs = 0;
277 if (!aStrLeft.IsEmpty()) numStrs++;
278 if (!aStrCenter.IsEmpty()) numStrs++;
279 if (!aStrRight.IsEmpty()) numStrs++;
280
281 if (numStrs == 0) return;
282 nscoord strSpace = aRect.width / numStrs;
283
284 if (!aStrLeft.IsEmpty()) {
285 DrawHeaderFooter(aRenderingContext, aHeaderFooter,
286 nsIPrintSettings::kJustLeft, aStrLeft, aRect, aAscent,
287 aHeight, strSpace);
288 }
289 if (!aStrCenter.IsEmpty()) {
290 DrawHeaderFooter(aRenderingContext, aHeaderFooter,
291 nsIPrintSettings::kJustCenter, aStrCenter, aRect, aAscent,
292 aHeight, strSpace);
293 }
294 if (!aStrRight.IsEmpty()) {
295 DrawHeaderFooter(aRenderingContext, aHeaderFooter,
296 nsIPrintSettings::kJustRight, aStrRight, aRect, aAscent,
297 aHeight, strSpace);
298 }
299 }
300
301 // Draw a header or footer string
302 // @param aRenderingContext - rendering context to draw into
303 // @param aHeaderFooter - indicates whether it is a header or footer
304 // @param aJust - indicates where the string is located within the header/footer
305 // @param aStr - the string to be drawn
306 // @param aRect - the rect of the page
307 // @param aHeight - the height of the font
308 // @param aAscent - the ascent of the font
309 // @param aWidth - available width for the string
310 void
311 nsPageFrame::DrawHeaderFooter(nsRenderingContext& aRenderingContext,
312 nsHeaderFooterEnum aHeaderFooter,
313 int32_t aJust,
314 const nsString& aStr,
315 const nsRect& aRect,
316 nscoord aAscent,
317 nscoord aHeight,
318 nscoord aWidth)
319 {
320
321 nscoord contentWidth = aWidth - (mPD->mEdgePaperMargin.left + mPD->mEdgePaperMargin.right);
322
323 if ((aHeaderFooter == eHeader && aHeight < mPD->mReflowMargin.top) ||
324 (aHeaderFooter == eFooter && aHeight < mPD->mReflowMargin.bottom)) {
325 nsAutoString str;
326 ProcessSpecialCodes(aStr, str);
327
328 int32_t indx;
329 int32_t textWidth = 0;
330 const char16_t* text = str.get();
331
332 int32_t len = (int32_t)str.Length();
333 if (len == 0) {
334 return; // bail is empty string
335 }
336 // find how much text fits, the "position" is the size of the available area
337 if (nsLayoutUtils::BinarySearchForPosition(&aRenderingContext, text, 0, 0, 0, len,
338 int32_t(contentWidth), indx, textWidth)) {
339 if (indx < len-1 ) {
340 // we can't fit in all the text
341 if (indx > 3) {
342 // But we can fit in at least 4 chars. Show all but 3 of them, then
343 // an ellipsis.
344 // XXXbz for non-plane0 text, this may be cutting things in the
345 // middle of a codepoint! Also, we have no guarantees that the three
346 // dots will fit in the space the three chars we removed took up with
347 // these font metrics!
348 str.Truncate(indx-3);
349 str.AppendLiteral("...");
350 } else {
351 // We can only fit 3 or fewer chars. Just show nothing
352 str.Truncate();
353 }
354 }
355 } else {
356 return; // bail if couldn't find the correct length
357 }
358
359 if (HasRTLChars(str)) {
360 PresContext()->SetBidiEnabled();
361 }
362
363 // cacl the x and y positions of the text
364 nscoord x = GetXPosition(aRenderingContext, aRect, aJust, str);
365 nscoord y;
366 if (aHeaderFooter == eHeader) {
367 y = aRect.y + mPD->mEdgePaperMargin.top;
368 } else {
369 y = aRect.YMost() - aHeight - mPD->mEdgePaperMargin.bottom;
370 }
371
372 // set up new clip and draw the text
373 aRenderingContext.PushState();
374 aRenderingContext.SetColor(NS_RGB(0,0,0));
375 aRenderingContext.IntersectClip(aRect);
376 nsLayoutUtils::DrawString(this, &aRenderingContext, str.get(), str.Length(), nsPoint(x, y + aAscent));
377 aRenderingContext.PopState();
378 }
379 }
380
381 /**
382 * Remove all leaf display items that are not for descendants of
383 * aBuilder->GetReferenceFrame() from aList.
384 * @param aPage the page we're constructing the display list for
385 * @param aExtraPage the page we constructed aList for
386 * @param aList the list that is modified in-place
387 */
388 static void
389 PruneDisplayListForExtraPage(nsDisplayListBuilder* aBuilder,
390 nsPageFrame* aPage, nsIFrame* aExtraPage,
391 nsDisplayList* aList)
392 {
393 nsDisplayList newList;
394
395 while (true) {
396 nsDisplayItem* i = aList->RemoveBottom();
397 if (!i)
398 break;
399 nsDisplayList* subList = i->GetSameCoordinateSystemChildren();
400 if (subList) {
401 PruneDisplayListForExtraPage(aBuilder, aPage, aExtraPage, subList);
402 i->UpdateBounds(aBuilder);
403 } else {
404 nsIFrame* f = i->Frame();
405 if (!nsLayoutUtils::IsProperAncestorFrameCrossDoc(aPage, f)) {
406 // We're throwing this away so call its destructor now. The memory
407 // is owned by aBuilder which destroys all items at once.
408 i->~nsDisplayItem();
409 continue;
410 }
411 }
412 newList.AppendToTop(i);
413 }
414 aList->AppendToTop(&newList);
415 }
416
417 static nsresult
418 BuildDisplayListForExtraPage(nsDisplayListBuilder* aBuilder,
419 nsPageFrame* aPage, nsIFrame* aExtraPage,
420 nsDisplayList* aList)
421 {
422 nsDisplayList list;
423 // Pass an empty dirty rect since we're only interested in finding
424 // placeholders whose out-of-flows are in the page
425 // aBuilder->GetReferenceFrame(), and the paths to those placeholders
426 // have already been marked as NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO.
427 // Note that we should still do a prune step since we don't want to
428 // rely on dirty-rect checking for correctness.
429 aExtraPage->BuildDisplayListForStackingContext(aBuilder, nsRect(), &list);
430 PruneDisplayListForExtraPage(aBuilder, aPage, aExtraPage, &list);
431 aList->AppendToTop(&list);
432 return NS_OK;
433 }
434
435 static nsIFrame*
436 GetNextPage(nsIFrame* aPageContentFrame)
437 {
438 // XXX ugh
439 nsIFrame* pageFrame = aPageContentFrame->GetParent();
440 NS_ASSERTION(pageFrame->GetType() == nsGkAtoms::pageFrame,
441 "pageContentFrame has unexpected parent");
442 nsIFrame* nextPageFrame = pageFrame->GetNextSibling();
443 if (!nextPageFrame)
444 return nullptr;
445 NS_ASSERTION(nextPageFrame->GetType() == nsGkAtoms::pageFrame,
446 "pageFrame's sibling is not a page frame...");
447 nsIFrame* f = nextPageFrame->GetFirstPrincipalChild();
448 NS_ASSERTION(f, "pageFrame has no page content frame!");
449 NS_ASSERTION(f->GetType() == nsGkAtoms::pageContentFrame,
450 "pageFrame's child is not page content!");
451 return f;
452 }
453
454 static void PaintHeaderFooter(nsIFrame* aFrame, nsRenderingContext* aCtx,
455 const nsRect& aDirtyRect, nsPoint aPt)
456 {
457 static_cast<nsPageFrame*>(aFrame)->PaintHeaderFooter(*aCtx, aPt);
458 }
459
460 static gfx3DMatrix ComputePageTransform(nsIFrame* aFrame, float aAppUnitsPerPixel)
461 {
462 float scale = aFrame->PresContext()->GetPageScale();
463 return gfx3DMatrix::ScalingMatrix(scale, scale, 1);
464 }
465
466 //------------------------------------------------------------------------------
467 void
468 nsPageFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
469 const nsRect& aDirtyRect,
470 const nsDisplayListSet& aLists)
471 {
472 nsDisplayListCollection set;
473
474 if (PresContext()->IsScreen()) {
475 DisplayBorderBackgroundOutline(aBuilder, aLists);
476 }
477
478 nsIFrame *child = mFrames.FirstChild();
479 float scale = PresContext()->GetPageScale();
480 nsRect clipRect(nsPoint(0, 0), child->GetSize());
481 // Note: this computation matches how we compute maxSize.height
482 // in nsPageFrame::Reflow
483 nscoord expectedPageContentHeight = NSToCoordCeil(GetSize().height / scale);
484 if (clipRect.height > expectedPageContentHeight) {
485 // We're doing print-selection, with one long page-content frame.
486 // Clip to the appropriate page-content slice for the current page.
487 NS_ASSERTION(mPageNum > 0, "page num should be positive");
488 // Note: The pageContentFrame's y-position has been set such that a zero
489 // y-value matches the top edge of the current page. So, to clip to the
490 // current page's content (in coordinates *relative* to the page content
491 // frame), we just negate its y-position and add the top margin.
492 clipRect.y = NSToCoordCeil((-child->GetRect().y +
493 mPD->mReflowMargin.top) / scale);
494 clipRect.height = expectedPageContentHeight;
495 NS_ASSERTION(clipRect.y < child->GetSize().height,
496 "Should be clipping to region inside the page content bounds");
497 }
498 clipRect += aBuilder->ToReferenceFrame(child);
499
500 nsDisplayList content;
501 {
502 DisplayListClipState::AutoSaveRestore clipState(aBuilder);
503
504 // Overwrite current clip, since we're going to wrap in a transform
505 // and the current clip is no longer meaningful.
506 clipState.Clear();
507 clipState.ClipContainingBlockDescendants(clipRect, nullptr);
508
509 child->BuildDisplayListForStackingContext(aBuilder,
510 child->GetVisualOverflowRectRelativeToSelf(), &content);
511
512 // We may need to paint out-of-flow frames whose placeholders are
513 // on other pages. Add those pages to our display list. Note that
514 // out-of-flow frames can't be placed after their placeholders so
515 // we don't have to process earlier pages. The display lists for
516 // these extra pages are pruned so that only display items for the
517 // page we currently care about (which we would have reached by
518 // following placeholders to their out-of-flows) end up on the list.
519 nsIFrame* page = child;
520 while ((page = GetNextPage(page)) != nullptr) {
521 BuildDisplayListForExtraPage(aBuilder, this, page, &content);
522 }
523
524 // Add the canvas background color to the bottom of the list. This
525 // happens after we've built the list so that AddCanvasBackgroundColorItem
526 // can monkey with the contents if necessary.
527 nsRect backgroundRect =
528 nsRect(aBuilder->ToReferenceFrame(child), child->GetSize());
529 PresContext()->GetPresShell()->AddCanvasBackgroundColorItem(
530 *aBuilder, content, child, backgroundRect, NS_RGBA(0,0,0,0));
531 }
532
533 content.AppendNewToTop(new (aBuilder) nsDisplayTransform(aBuilder, child, &content, ::ComputePageTransform));
534
535 set.Content()->AppendToTop(&content);
536
537 if (PresContext()->IsRootPaginatedDocument()) {
538 set.Content()->AppendNewToTop(new (aBuilder)
539 nsDisplayGeneric(aBuilder, this, ::PaintHeaderFooter,
540 "HeaderFooter",
541 nsDisplayItem::TYPE_HEADER_FOOTER));
542 }
543
544 set.MoveTo(aLists);
545 }
546
547 //------------------------------------------------------------------------------
548 void
549 nsPageFrame::SetPageNumInfo(int32_t aPageNumber, int32_t aTotalPages)
550 {
551 mPageNum = aPageNumber;
552 mTotNumPages = aTotalPages;
553 }
554
555
556 void
557 nsPageFrame::PaintHeaderFooter(nsRenderingContext& aRenderingContext,
558 nsPoint aPt)
559 {
560 nsPresContext* pc = PresContext();
561
562 if (!mPD->mPrintSettings) {
563 if (pc->Type() == nsPresContext::eContext_PrintPreview || pc->IsDynamic())
564 mPD->mPrintSettings = pc->GetPrintSettings();
565 if (!mPD->mPrintSettings)
566 return;
567 }
568
569 nsRect rect(aPt, mRect.Size());
570 aRenderingContext.SetColor(NS_RGB(0,0,0));
571
572 // Get the FontMetrics to determine width.height of strings
573 nsRefPtr<nsFontMetrics> fontMet;
574 pc->DeviceContext()->GetMetricsFor(mPD->mHeadFootFont, nullptr,
575 pc->GetUserFontSet(),
576 pc->GetTextPerfMetrics(),
577 *getter_AddRefs(fontMet));
578
579 aRenderingContext.SetFont(fontMet);
580
581 nscoord ascent = 0;
582 nscoord visibleHeight = 0;
583 if (fontMet) {
584 visibleHeight = fontMet->MaxHeight();
585 ascent = fontMet->MaxAscent();
586 }
587
588 // print document headers and footers
589 nsXPIDLString headerLeft, headerCenter, headerRight;
590 mPD->mPrintSettings->GetHeaderStrLeft(getter_Copies(headerLeft));
591 mPD->mPrintSettings->GetHeaderStrCenter(getter_Copies(headerCenter));
592 mPD->mPrintSettings->GetHeaderStrRight(getter_Copies(headerRight));
593 DrawHeaderFooter(aRenderingContext, eHeader,
594 headerLeft, headerCenter, headerRight,
595 rect, ascent, visibleHeight);
596
597 nsXPIDLString footerLeft, footerCenter, footerRight;
598 mPD->mPrintSettings->GetFooterStrLeft(getter_Copies(footerLeft));
599 mPD->mPrintSettings->GetFooterStrCenter(getter_Copies(footerCenter));
600 mPD->mPrintSettings->GetFooterStrRight(getter_Copies(footerRight));
601 DrawHeaderFooter(aRenderingContext, eFooter,
602 footerLeft, footerCenter, footerRight,
603 rect, ascent, visibleHeight);
604 }
605
606 void
607 nsPageFrame::SetSharedPageData(nsSharedPageData* aPD)
608 {
609 mPD = aPD;
610 // Set the shared data into the page frame before reflow
611 nsPageContentFrame * pcf = static_cast<nsPageContentFrame*>(mFrames.FirstChild());
612 if (pcf) {
613 pcf->SetSharedPageData(mPD);
614 }
615
616 }
617
618 nsIFrame*
619 NS_NewPageBreakFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
620 {
621 NS_PRECONDITION(aPresShell, "null PresShell");
622 //check that we are only creating page break frames when printing
623 NS_ASSERTION(aPresShell->GetPresContext()->IsPaginated(), "created a page break frame while not printing");
624
625 return new (aPresShell) nsPageBreakFrame(aContext);
626 }
627
628 NS_IMPL_FRAMEARENA_HELPERS(nsPageBreakFrame)
629
630 nsPageBreakFrame::nsPageBreakFrame(nsStyleContext* aContext) :
631 nsLeafFrame(aContext), mHaveReflowed(false)
632 {
633 }
634
635 nsPageBreakFrame::~nsPageBreakFrame()
636 {
637 }
638
639 nscoord
640 nsPageBreakFrame::GetIntrinsicWidth()
641 {
642 return nsPresContext::CSSPixelsToAppUnits(1);
643 }
644
645 nscoord
646 nsPageBreakFrame::GetIntrinsicHeight()
647 {
648 return 0;
649 }
650
651 nsresult
652 nsPageBreakFrame::Reflow(nsPresContext* aPresContext,
653 nsHTMLReflowMetrics& aDesiredSize,
654 const nsHTMLReflowState& aReflowState,
655 nsReflowStatus& aStatus)
656 {
657 DO_GLOBAL_REFLOW_COUNT("nsPageBreakFrame");
658 DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
659
660 // Override reflow, since we don't want to deal with what our
661 // computed values are.
662 aDesiredSize.Width() = GetIntrinsicWidth();
663 aDesiredSize.Height() = (aReflowState.AvailableHeight() == NS_UNCONSTRAINEDSIZE ?
664 0 : aReflowState.AvailableHeight());
665 // round the height down to the nearest pixel
666 aDesiredSize.Height() -=
667 aDesiredSize.Height() % nsPresContext::CSSPixelsToAppUnits(1);
668
669 // Note: not using NS_FRAME_FIRST_REFLOW here, since it's not clear whether
670 // DidReflow will always get called before the next Reflow() call.
671 mHaveReflowed = true;
672 aStatus = NS_FRAME_COMPLETE;
673 return NS_OK;
674 }
675
676 nsIAtom*
677 nsPageBreakFrame::GetType() const
678 {
679 return nsGkAtoms::pageBreakFrame;
680 }
681
682 #ifdef DEBUG_FRAME_DUMP
683 nsresult
684 nsPageBreakFrame::GetFrameName(nsAString& aResult) const
685 {
686 return MakeFrameName(NS_LITERAL_STRING("PageBreak"), aResult);
687 }
688 #endif

mercurial