1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/generic/nsPageFrame.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,688 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "nsPageFrame.h" 1.10 +#include "nsPresContext.h" 1.11 +#include "nsRenderingContext.h" 1.12 +#include "nsGkAtoms.h" 1.13 +#include "nsIPresShell.h" 1.14 +#include "nsPageContentFrame.h" 1.15 +#include "nsDisplayList.h" 1.16 +#include "nsLayoutUtils.h" // for function BinarySearchForPosition 1.17 +#include "nsSimplePageSequenceFrame.h" // for nsSharedPageData 1.18 +#include "nsTextFormatter.h" // for page number localization formatting 1.19 +#include "nsBidiUtils.h" 1.20 +#include "nsIPrintSettings.h" 1.21 + 1.22 +#include "prlog.h" 1.23 +#ifdef PR_LOGGING 1.24 +extern PRLogModuleInfo *GetLayoutPrintingLog(); 1.25 +#define PR_PL(_p1) PR_LOG(GetLayoutPrintingLog(), PR_LOG_DEBUG, _p1) 1.26 +#else 1.27 +#define PR_PL(_p1) 1.28 +#endif 1.29 + 1.30 +using namespace mozilla; 1.31 + 1.32 +nsIFrame* 1.33 +NS_NewPageFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) 1.34 +{ 1.35 + return new (aPresShell) nsPageFrame(aContext); 1.36 +} 1.37 + 1.38 +NS_IMPL_FRAMEARENA_HELPERS(nsPageFrame) 1.39 + 1.40 +nsPageFrame::nsPageFrame(nsStyleContext* aContext) 1.41 +: nsContainerFrame(aContext) 1.42 +{ 1.43 +} 1.44 + 1.45 +nsPageFrame::~nsPageFrame() 1.46 +{ 1.47 +} 1.48 + 1.49 +nsresult nsPageFrame::Reflow(nsPresContext* aPresContext, 1.50 + nsHTMLReflowMetrics& aDesiredSize, 1.51 + const nsHTMLReflowState& aReflowState, 1.52 + nsReflowStatus& aStatus) 1.53 +{ 1.54 + DO_GLOBAL_REFLOW_COUNT("nsPageFrame"); 1.55 + DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); 1.56 + aStatus = NS_FRAME_COMPLETE; // initialize out parameter 1.57 + 1.58 + NS_ASSERTION(mFrames.FirstChild() && 1.59 + nsGkAtoms::pageContentFrame == mFrames.FirstChild()->GetType(), 1.60 + "pageFrame must have a pageContentFrame child"); 1.61 + 1.62 + // Resize our frame allowing it only to be as big as we are 1.63 + // XXX Pay attention to the page's border and padding... 1.64 + if (mFrames.NotEmpty()) { 1.65 + nsIFrame* frame = mFrames.FirstChild(); 1.66 + // When the reflow size is NS_UNCONSTRAINEDSIZE it means we are reflowing 1.67 + // a single page to print selection. So this means we want to use 1.68 + // NS_UNCONSTRAINEDSIZE without altering it 1.69 + nscoord avHeight; 1.70 + if (mPD->mReflowSize.height == NS_UNCONSTRAINEDSIZE) { 1.71 + avHeight = NS_UNCONSTRAINEDSIZE; 1.72 + } else { 1.73 + avHeight = mPD->mReflowSize.height; 1.74 + } 1.75 + nsSize maxSize(mPD->mReflowSize.width, avHeight); 1.76 + float scale = aPresContext->GetPageScale(); 1.77 + maxSize.width = NSToCoordCeil(maxSize.width / scale); 1.78 + if (maxSize.height != NS_UNCONSTRAINEDSIZE) { 1.79 + maxSize.height = NSToCoordCeil(maxSize.height / scale); 1.80 + } 1.81 + // Get the number of Twips per pixel from the PresContext 1.82 + nscoord onePixelInTwips = nsPresContext::CSSPixelsToAppUnits(1); 1.83 + // insurance against infinite reflow, when reflowing less than a pixel 1.84 + // XXX Shouldn't we do something more friendly when invalid margins 1.85 + // are set? 1.86 + if (maxSize.width < onePixelInTwips || maxSize.height < onePixelInTwips) { 1.87 + aDesiredSize.Width() = 0; 1.88 + aDesiredSize.Height() = 0; 1.89 + NS_WARNING("Reflow aborted; no space for content"); 1.90 + return NS_OK; 1.91 + } 1.92 + 1.93 + nsHTMLReflowState kidReflowState(aPresContext, aReflowState, frame, maxSize); 1.94 + kidReflowState.mFlags.mIsTopOfPage = true; 1.95 + kidReflowState.mFlags.mTableIsSplittable = true; 1.96 + 1.97 + // Use the margins given in the @page rule. 1.98 + // If a margin is 'auto', use the margin from the print settings for that side. 1.99 + nsMargin pageContentMargin; 1.100 + const nsStyleSides& marginStyle = kidReflowState.mStyleMargin->mMargin; 1.101 + NS_FOR_CSS_SIDES(side) { 1.102 + if (marginStyle.GetUnit(side) == eStyleUnit_Auto) { 1.103 + pageContentMargin.Side(side) = mPD->mReflowMargin.Side(side); 1.104 + } else { 1.105 + pageContentMargin.Side(side) = kidReflowState.ComputedPhysicalMargin().Side(side); 1.106 + } 1.107 + } 1.108 + 1.109 + 1.110 + nscoord maxWidth = maxSize.width - pageContentMargin.LeftRight() / scale; 1.111 + nscoord maxHeight; 1.112 + if (maxSize.height == NS_UNCONSTRAINEDSIZE) { 1.113 + maxHeight = NS_UNCONSTRAINEDSIZE; 1.114 + } else { 1.115 + maxHeight = maxSize.height - pageContentMargin.TopBottom() / scale; 1.116 + } 1.117 + 1.118 + // Check the width and height, if they're too small we reset the margins 1.119 + // back to the default. 1.120 + if (maxWidth < onePixelInTwips || 1.121 + (maxHeight != NS_UNCONSTRAINEDSIZE && maxHeight < onePixelInTwips)) { 1.122 + NS_FOR_CSS_SIDES(side) { 1.123 + pageContentMargin.Side(side) = mPD->mReflowMargin.Side(side); 1.124 + } 1.125 + maxWidth = maxSize.width - pageContentMargin.LeftRight() / scale; 1.126 + if (maxHeight != NS_UNCONSTRAINEDSIZE) { 1.127 + maxHeight = maxSize.height - pageContentMargin.TopBottom() / scale; 1.128 + } 1.129 + } 1.130 + 1.131 + kidReflowState.SetComputedWidth(maxWidth); 1.132 + kidReflowState.SetComputedHeight(maxHeight); 1.133 + 1.134 + // calc location of frame 1.135 + nscoord xc = pageContentMargin.left; 1.136 + nscoord yc = pageContentMargin.top; 1.137 + 1.138 + // Get the child's desired size 1.139 + ReflowChild(frame, aPresContext, aDesiredSize, kidReflowState, xc, yc, 0, aStatus); 1.140 + 1.141 + // Place and size the child 1.142 + FinishReflowChild(frame, aPresContext, aDesiredSize, &kidReflowState, xc, yc, 0); 1.143 + 1.144 + NS_ASSERTION(!NS_FRAME_IS_FULLY_COMPLETE(aStatus) || 1.145 + !frame->GetNextInFlow(), "bad child flow list"); 1.146 + } 1.147 + PR_PL(("PageFrame::Reflow %p ", this)); 1.148 + PR_PL(("[%d,%d][%d,%d]\n", aDesiredSize.Width(), aDesiredSize.Height(), aReflowState.AvailableWidth(), aReflowState.AvailableHeight())); 1.149 + 1.150 + // Return our desired size 1.151 + aDesiredSize.Width() = aReflowState.AvailableWidth(); 1.152 + if (aReflowState.AvailableHeight() != NS_UNCONSTRAINEDSIZE) { 1.153 + aDesiredSize.Height() = aReflowState.AvailableHeight(); 1.154 + } 1.155 + 1.156 + aDesiredSize.SetOverflowAreasToDesiredBounds(); 1.157 + FinishAndStoreOverflow(&aDesiredSize); 1.158 + 1.159 + PR_PL(("PageFrame::Reflow %p ", this)); 1.160 + PR_PL(("[%d,%d]\n", aReflowState.AvailableWidth(), aReflowState.AvailableHeight())); 1.161 + 1.162 + NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); 1.163 + return NS_OK; 1.164 +} 1.165 + 1.166 +nsIAtom* 1.167 +nsPageFrame::GetType() const 1.168 +{ 1.169 + return nsGkAtoms::pageFrame; 1.170 +} 1.171 + 1.172 +#ifdef DEBUG_FRAME_DUMP 1.173 +nsresult 1.174 +nsPageFrame::GetFrameName(nsAString& aResult) const 1.175 +{ 1.176 + return MakeFrameName(NS_LITERAL_STRING("Page"), aResult); 1.177 +} 1.178 +#endif 1.179 + 1.180 +void 1.181 +nsPageFrame::ProcessSpecialCodes(const nsString& aStr, nsString& aNewStr) 1.182 +{ 1.183 + 1.184 + aNewStr = aStr; 1.185 + 1.186 + // Search to see if the &D code is in the string 1.187 + // then subst in the current date/time 1.188 + NS_NAMED_LITERAL_STRING(kDate, "&D"); 1.189 + if (aStr.Find(kDate) != kNotFound) { 1.190 + aNewStr.ReplaceSubstring(kDate.get(), mPD->mDateTimeStr.get()); 1.191 + } 1.192 + 1.193 + // NOTE: Must search for &PT before searching for &P 1.194 + // 1.195 + // Search to see if the "page number and page" total code are in the string 1.196 + // and replace the page number and page total code with the actual 1.197 + // values 1.198 + NS_NAMED_LITERAL_STRING(kPageAndTotal, "&PT"); 1.199 + if (aStr.Find(kPageAndTotal) != kNotFound) { 1.200 + char16_t * uStr = nsTextFormatter::smprintf(mPD->mPageNumAndTotalsFormat.get(), mPageNum, mTotNumPages); 1.201 + aNewStr.ReplaceSubstring(kPageAndTotal.get(), uStr); 1.202 + nsMemory::Free(uStr); 1.203 + } 1.204 + 1.205 + // Search to see if the page number code is in the string 1.206 + // and replace the page number code with the actual value 1.207 + NS_NAMED_LITERAL_STRING(kPage, "&P"); 1.208 + if (aStr.Find(kPage) != kNotFound) { 1.209 + char16_t * uStr = nsTextFormatter::smprintf(mPD->mPageNumFormat.get(), mPageNum); 1.210 + aNewStr.ReplaceSubstring(kPage.get(), uStr); 1.211 + nsMemory::Free(uStr); 1.212 + } 1.213 + 1.214 + NS_NAMED_LITERAL_STRING(kTitle, "&T"); 1.215 + if (aStr.Find(kTitle) != kNotFound) { 1.216 + aNewStr.ReplaceSubstring(kTitle.get(), mPD->mDocTitle.get()); 1.217 + } 1.218 + 1.219 + NS_NAMED_LITERAL_STRING(kDocURL, "&U"); 1.220 + if (aStr.Find(kDocURL) != kNotFound) { 1.221 + aNewStr.ReplaceSubstring(kDocURL.get(), mPD->mDocURL.get()); 1.222 + } 1.223 + 1.224 + NS_NAMED_LITERAL_STRING(kPageTotal, "&L"); 1.225 + if (aStr.Find(kPageTotal) != kNotFound) { 1.226 + char16_t * uStr = nsTextFormatter::smprintf(mPD->mPageNumFormat.get(), mTotNumPages); 1.227 + aNewStr.ReplaceSubstring(kPageTotal.get(), uStr); 1.228 + nsMemory::Free(uStr); 1.229 + } 1.230 +} 1.231 + 1.232 + 1.233 +//------------------------------------------------------------------------------ 1.234 +nscoord nsPageFrame::GetXPosition(nsRenderingContext& aRenderingContext, 1.235 + const nsRect& aRect, 1.236 + int32_t aJust, 1.237 + const nsString& aStr) 1.238 +{ 1.239 + nscoord width = nsLayoutUtils::GetStringWidth(this, &aRenderingContext, 1.240 + aStr.get(), aStr.Length()); 1.241 + 1.242 + nscoord x = aRect.x; 1.243 + switch (aJust) { 1.244 + case nsIPrintSettings::kJustLeft: 1.245 + x += mPD->mEdgePaperMargin.left; 1.246 + break; 1.247 + 1.248 + case nsIPrintSettings::kJustCenter: 1.249 + x += (aRect.width - width) / 2; 1.250 + break; 1.251 + 1.252 + case nsIPrintSettings::kJustRight: 1.253 + x += aRect.width - width - mPD->mEdgePaperMargin.right; 1.254 + break; 1.255 + } // switch 1.256 + 1.257 + return x; 1.258 +} 1.259 + 1.260 +// Draw a header or footer 1.261 +// @param aRenderingContext - rendering content ot draw into 1.262 +// @param aHeaderFooter - indicates whether it is a header or footer 1.263 +// @param aStrLeft - string for the left header or footer; can be empty 1.264 +// @param aStrCenter - string for the center header or footer; can be empty 1.265 +// @param aStrRight - string for the right header or footer; can be empty 1.266 +// @param aRect - the rect of the page 1.267 +// @param aAscent - the ascent of the font 1.268 +// @param aHeight - the height of the font 1.269 +void 1.270 +nsPageFrame::DrawHeaderFooter(nsRenderingContext& aRenderingContext, 1.271 + nsHeaderFooterEnum aHeaderFooter, 1.272 + const nsString& aStrLeft, 1.273 + const nsString& aStrCenter, 1.274 + const nsString& aStrRight, 1.275 + const nsRect& aRect, 1.276 + nscoord aAscent, 1.277 + nscoord aHeight) 1.278 +{ 1.279 + int32_t numStrs = 0; 1.280 + if (!aStrLeft.IsEmpty()) numStrs++; 1.281 + if (!aStrCenter.IsEmpty()) numStrs++; 1.282 + if (!aStrRight.IsEmpty()) numStrs++; 1.283 + 1.284 + if (numStrs == 0) return; 1.285 + nscoord strSpace = aRect.width / numStrs; 1.286 + 1.287 + if (!aStrLeft.IsEmpty()) { 1.288 + DrawHeaderFooter(aRenderingContext, aHeaderFooter, 1.289 + nsIPrintSettings::kJustLeft, aStrLeft, aRect, aAscent, 1.290 + aHeight, strSpace); 1.291 + } 1.292 + if (!aStrCenter.IsEmpty()) { 1.293 + DrawHeaderFooter(aRenderingContext, aHeaderFooter, 1.294 + nsIPrintSettings::kJustCenter, aStrCenter, aRect, aAscent, 1.295 + aHeight, strSpace); 1.296 + } 1.297 + if (!aStrRight.IsEmpty()) { 1.298 + DrawHeaderFooter(aRenderingContext, aHeaderFooter, 1.299 + nsIPrintSettings::kJustRight, aStrRight, aRect, aAscent, 1.300 + aHeight, strSpace); 1.301 + } 1.302 +} 1.303 + 1.304 +// Draw a header or footer string 1.305 +// @param aRenderingContext - rendering context to draw into 1.306 +// @param aHeaderFooter - indicates whether it is a header or footer 1.307 +// @param aJust - indicates where the string is located within the header/footer 1.308 +// @param aStr - the string to be drawn 1.309 +// @param aRect - the rect of the page 1.310 +// @param aHeight - the height of the font 1.311 +// @param aAscent - the ascent of the font 1.312 +// @param aWidth - available width for the string 1.313 +void 1.314 +nsPageFrame::DrawHeaderFooter(nsRenderingContext& aRenderingContext, 1.315 + nsHeaderFooterEnum aHeaderFooter, 1.316 + int32_t aJust, 1.317 + const nsString& aStr, 1.318 + const nsRect& aRect, 1.319 + nscoord aAscent, 1.320 + nscoord aHeight, 1.321 + nscoord aWidth) 1.322 +{ 1.323 + 1.324 + nscoord contentWidth = aWidth - (mPD->mEdgePaperMargin.left + mPD->mEdgePaperMargin.right); 1.325 + 1.326 + if ((aHeaderFooter == eHeader && aHeight < mPD->mReflowMargin.top) || 1.327 + (aHeaderFooter == eFooter && aHeight < mPD->mReflowMargin.bottom)) { 1.328 + nsAutoString str; 1.329 + ProcessSpecialCodes(aStr, str); 1.330 + 1.331 + int32_t indx; 1.332 + int32_t textWidth = 0; 1.333 + const char16_t* text = str.get(); 1.334 + 1.335 + int32_t len = (int32_t)str.Length(); 1.336 + if (len == 0) { 1.337 + return; // bail is empty string 1.338 + } 1.339 + // find how much text fits, the "position" is the size of the available area 1.340 + if (nsLayoutUtils::BinarySearchForPosition(&aRenderingContext, text, 0, 0, 0, len, 1.341 + int32_t(contentWidth), indx, textWidth)) { 1.342 + if (indx < len-1 ) { 1.343 + // we can't fit in all the text 1.344 + if (indx > 3) { 1.345 + // But we can fit in at least 4 chars. Show all but 3 of them, then 1.346 + // an ellipsis. 1.347 + // XXXbz for non-plane0 text, this may be cutting things in the 1.348 + // middle of a codepoint! Also, we have no guarantees that the three 1.349 + // dots will fit in the space the three chars we removed took up with 1.350 + // these font metrics! 1.351 + str.Truncate(indx-3); 1.352 + str.AppendLiteral("..."); 1.353 + } else { 1.354 + // We can only fit 3 or fewer chars. Just show nothing 1.355 + str.Truncate(); 1.356 + } 1.357 + } 1.358 + } else { 1.359 + return; // bail if couldn't find the correct length 1.360 + } 1.361 + 1.362 + if (HasRTLChars(str)) { 1.363 + PresContext()->SetBidiEnabled(); 1.364 + } 1.365 + 1.366 + // cacl the x and y positions of the text 1.367 + nscoord x = GetXPosition(aRenderingContext, aRect, aJust, str); 1.368 + nscoord y; 1.369 + if (aHeaderFooter == eHeader) { 1.370 + y = aRect.y + mPD->mEdgePaperMargin.top; 1.371 + } else { 1.372 + y = aRect.YMost() - aHeight - mPD->mEdgePaperMargin.bottom; 1.373 + } 1.374 + 1.375 + // set up new clip and draw the text 1.376 + aRenderingContext.PushState(); 1.377 + aRenderingContext.SetColor(NS_RGB(0,0,0)); 1.378 + aRenderingContext.IntersectClip(aRect); 1.379 + nsLayoutUtils::DrawString(this, &aRenderingContext, str.get(), str.Length(), nsPoint(x, y + aAscent)); 1.380 + aRenderingContext.PopState(); 1.381 + } 1.382 +} 1.383 + 1.384 +/** 1.385 + * Remove all leaf display items that are not for descendants of 1.386 + * aBuilder->GetReferenceFrame() from aList. 1.387 + * @param aPage the page we're constructing the display list for 1.388 + * @param aExtraPage the page we constructed aList for 1.389 + * @param aList the list that is modified in-place 1.390 + */ 1.391 +static void 1.392 +PruneDisplayListForExtraPage(nsDisplayListBuilder* aBuilder, 1.393 + nsPageFrame* aPage, nsIFrame* aExtraPage, 1.394 + nsDisplayList* aList) 1.395 +{ 1.396 + nsDisplayList newList; 1.397 + 1.398 + while (true) { 1.399 + nsDisplayItem* i = aList->RemoveBottom(); 1.400 + if (!i) 1.401 + break; 1.402 + nsDisplayList* subList = i->GetSameCoordinateSystemChildren(); 1.403 + if (subList) { 1.404 + PruneDisplayListForExtraPage(aBuilder, aPage, aExtraPage, subList); 1.405 + i->UpdateBounds(aBuilder); 1.406 + } else { 1.407 + nsIFrame* f = i->Frame(); 1.408 + if (!nsLayoutUtils::IsProperAncestorFrameCrossDoc(aPage, f)) { 1.409 + // We're throwing this away so call its destructor now. The memory 1.410 + // is owned by aBuilder which destroys all items at once. 1.411 + i->~nsDisplayItem(); 1.412 + continue; 1.413 + } 1.414 + } 1.415 + newList.AppendToTop(i); 1.416 + } 1.417 + aList->AppendToTop(&newList); 1.418 +} 1.419 + 1.420 +static nsresult 1.421 +BuildDisplayListForExtraPage(nsDisplayListBuilder* aBuilder, 1.422 + nsPageFrame* aPage, nsIFrame* aExtraPage, 1.423 + nsDisplayList* aList) 1.424 +{ 1.425 + nsDisplayList list; 1.426 + // Pass an empty dirty rect since we're only interested in finding 1.427 + // placeholders whose out-of-flows are in the page 1.428 + // aBuilder->GetReferenceFrame(), and the paths to those placeholders 1.429 + // have already been marked as NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO. 1.430 + // Note that we should still do a prune step since we don't want to 1.431 + // rely on dirty-rect checking for correctness. 1.432 + aExtraPage->BuildDisplayListForStackingContext(aBuilder, nsRect(), &list); 1.433 + PruneDisplayListForExtraPage(aBuilder, aPage, aExtraPage, &list); 1.434 + aList->AppendToTop(&list); 1.435 + return NS_OK; 1.436 +} 1.437 + 1.438 +static nsIFrame* 1.439 +GetNextPage(nsIFrame* aPageContentFrame) 1.440 +{ 1.441 + // XXX ugh 1.442 + nsIFrame* pageFrame = aPageContentFrame->GetParent(); 1.443 + NS_ASSERTION(pageFrame->GetType() == nsGkAtoms::pageFrame, 1.444 + "pageContentFrame has unexpected parent"); 1.445 + nsIFrame* nextPageFrame = pageFrame->GetNextSibling(); 1.446 + if (!nextPageFrame) 1.447 + return nullptr; 1.448 + NS_ASSERTION(nextPageFrame->GetType() == nsGkAtoms::pageFrame, 1.449 + "pageFrame's sibling is not a page frame..."); 1.450 + nsIFrame* f = nextPageFrame->GetFirstPrincipalChild(); 1.451 + NS_ASSERTION(f, "pageFrame has no page content frame!"); 1.452 + NS_ASSERTION(f->GetType() == nsGkAtoms::pageContentFrame, 1.453 + "pageFrame's child is not page content!"); 1.454 + return f; 1.455 +} 1.456 + 1.457 +static void PaintHeaderFooter(nsIFrame* aFrame, nsRenderingContext* aCtx, 1.458 + const nsRect& aDirtyRect, nsPoint aPt) 1.459 +{ 1.460 + static_cast<nsPageFrame*>(aFrame)->PaintHeaderFooter(*aCtx, aPt); 1.461 +} 1.462 + 1.463 +static gfx3DMatrix ComputePageTransform(nsIFrame* aFrame, float aAppUnitsPerPixel) 1.464 +{ 1.465 + float scale = aFrame->PresContext()->GetPageScale(); 1.466 + return gfx3DMatrix::ScalingMatrix(scale, scale, 1); 1.467 +} 1.468 + 1.469 +//------------------------------------------------------------------------------ 1.470 +void 1.471 +nsPageFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, 1.472 + const nsRect& aDirtyRect, 1.473 + const nsDisplayListSet& aLists) 1.474 +{ 1.475 + nsDisplayListCollection set; 1.476 + 1.477 + if (PresContext()->IsScreen()) { 1.478 + DisplayBorderBackgroundOutline(aBuilder, aLists); 1.479 + } 1.480 + 1.481 + nsIFrame *child = mFrames.FirstChild(); 1.482 + float scale = PresContext()->GetPageScale(); 1.483 + nsRect clipRect(nsPoint(0, 0), child->GetSize()); 1.484 + // Note: this computation matches how we compute maxSize.height 1.485 + // in nsPageFrame::Reflow 1.486 + nscoord expectedPageContentHeight = NSToCoordCeil(GetSize().height / scale); 1.487 + if (clipRect.height > expectedPageContentHeight) { 1.488 + // We're doing print-selection, with one long page-content frame. 1.489 + // Clip to the appropriate page-content slice for the current page. 1.490 + NS_ASSERTION(mPageNum > 0, "page num should be positive"); 1.491 + // Note: The pageContentFrame's y-position has been set such that a zero 1.492 + // y-value matches the top edge of the current page. So, to clip to the 1.493 + // current page's content (in coordinates *relative* to the page content 1.494 + // frame), we just negate its y-position and add the top margin. 1.495 + clipRect.y = NSToCoordCeil((-child->GetRect().y + 1.496 + mPD->mReflowMargin.top) / scale); 1.497 + clipRect.height = expectedPageContentHeight; 1.498 + NS_ASSERTION(clipRect.y < child->GetSize().height, 1.499 + "Should be clipping to region inside the page content bounds"); 1.500 + } 1.501 + clipRect += aBuilder->ToReferenceFrame(child); 1.502 + 1.503 + nsDisplayList content; 1.504 + { 1.505 + DisplayListClipState::AutoSaveRestore clipState(aBuilder); 1.506 + 1.507 + // Overwrite current clip, since we're going to wrap in a transform 1.508 + // and the current clip is no longer meaningful. 1.509 + clipState.Clear(); 1.510 + clipState.ClipContainingBlockDescendants(clipRect, nullptr); 1.511 + 1.512 + child->BuildDisplayListForStackingContext(aBuilder, 1.513 + child->GetVisualOverflowRectRelativeToSelf(), &content); 1.514 + 1.515 + // We may need to paint out-of-flow frames whose placeholders are 1.516 + // on other pages. Add those pages to our display list. Note that 1.517 + // out-of-flow frames can't be placed after their placeholders so 1.518 + // we don't have to process earlier pages. The display lists for 1.519 + // these extra pages are pruned so that only display items for the 1.520 + // page we currently care about (which we would have reached by 1.521 + // following placeholders to their out-of-flows) end up on the list. 1.522 + nsIFrame* page = child; 1.523 + while ((page = GetNextPage(page)) != nullptr) { 1.524 + BuildDisplayListForExtraPage(aBuilder, this, page, &content); 1.525 + } 1.526 + 1.527 + // Add the canvas background color to the bottom of the list. This 1.528 + // happens after we've built the list so that AddCanvasBackgroundColorItem 1.529 + // can monkey with the contents if necessary. 1.530 + nsRect backgroundRect = 1.531 + nsRect(aBuilder->ToReferenceFrame(child), child->GetSize()); 1.532 + PresContext()->GetPresShell()->AddCanvasBackgroundColorItem( 1.533 + *aBuilder, content, child, backgroundRect, NS_RGBA(0,0,0,0)); 1.534 + } 1.535 + 1.536 + content.AppendNewToTop(new (aBuilder) nsDisplayTransform(aBuilder, child, &content, ::ComputePageTransform)); 1.537 + 1.538 + set.Content()->AppendToTop(&content); 1.539 + 1.540 + if (PresContext()->IsRootPaginatedDocument()) { 1.541 + set.Content()->AppendNewToTop(new (aBuilder) 1.542 + nsDisplayGeneric(aBuilder, this, ::PaintHeaderFooter, 1.543 + "HeaderFooter", 1.544 + nsDisplayItem::TYPE_HEADER_FOOTER)); 1.545 + } 1.546 + 1.547 + set.MoveTo(aLists); 1.548 +} 1.549 + 1.550 +//------------------------------------------------------------------------------ 1.551 +void 1.552 +nsPageFrame::SetPageNumInfo(int32_t aPageNumber, int32_t aTotalPages) 1.553 +{ 1.554 + mPageNum = aPageNumber; 1.555 + mTotNumPages = aTotalPages; 1.556 +} 1.557 + 1.558 + 1.559 +void 1.560 +nsPageFrame::PaintHeaderFooter(nsRenderingContext& aRenderingContext, 1.561 + nsPoint aPt) 1.562 +{ 1.563 + nsPresContext* pc = PresContext(); 1.564 + 1.565 + if (!mPD->mPrintSettings) { 1.566 + if (pc->Type() == nsPresContext::eContext_PrintPreview || pc->IsDynamic()) 1.567 + mPD->mPrintSettings = pc->GetPrintSettings(); 1.568 + if (!mPD->mPrintSettings) 1.569 + return; 1.570 + } 1.571 + 1.572 + nsRect rect(aPt, mRect.Size()); 1.573 + aRenderingContext.SetColor(NS_RGB(0,0,0)); 1.574 + 1.575 + // Get the FontMetrics to determine width.height of strings 1.576 + nsRefPtr<nsFontMetrics> fontMet; 1.577 + pc->DeviceContext()->GetMetricsFor(mPD->mHeadFootFont, nullptr, 1.578 + pc->GetUserFontSet(), 1.579 + pc->GetTextPerfMetrics(), 1.580 + *getter_AddRefs(fontMet)); 1.581 + 1.582 + aRenderingContext.SetFont(fontMet); 1.583 + 1.584 + nscoord ascent = 0; 1.585 + nscoord visibleHeight = 0; 1.586 + if (fontMet) { 1.587 + visibleHeight = fontMet->MaxHeight(); 1.588 + ascent = fontMet->MaxAscent(); 1.589 + } 1.590 + 1.591 + // print document headers and footers 1.592 + nsXPIDLString headerLeft, headerCenter, headerRight; 1.593 + mPD->mPrintSettings->GetHeaderStrLeft(getter_Copies(headerLeft)); 1.594 + mPD->mPrintSettings->GetHeaderStrCenter(getter_Copies(headerCenter)); 1.595 + mPD->mPrintSettings->GetHeaderStrRight(getter_Copies(headerRight)); 1.596 + DrawHeaderFooter(aRenderingContext, eHeader, 1.597 + headerLeft, headerCenter, headerRight, 1.598 + rect, ascent, visibleHeight); 1.599 + 1.600 + nsXPIDLString footerLeft, footerCenter, footerRight; 1.601 + mPD->mPrintSettings->GetFooterStrLeft(getter_Copies(footerLeft)); 1.602 + mPD->mPrintSettings->GetFooterStrCenter(getter_Copies(footerCenter)); 1.603 + mPD->mPrintSettings->GetFooterStrRight(getter_Copies(footerRight)); 1.604 + DrawHeaderFooter(aRenderingContext, eFooter, 1.605 + footerLeft, footerCenter, footerRight, 1.606 + rect, ascent, visibleHeight); 1.607 +} 1.608 + 1.609 +void 1.610 +nsPageFrame::SetSharedPageData(nsSharedPageData* aPD) 1.611 +{ 1.612 + mPD = aPD; 1.613 + // Set the shared data into the page frame before reflow 1.614 + nsPageContentFrame * pcf = static_cast<nsPageContentFrame*>(mFrames.FirstChild()); 1.615 + if (pcf) { 1.616 + pcf->SetSharedPageData(mPD); 1.617 + } 1.618 + 1.619 +} 1.620 + 1.621 +nsIFrame* 1.622 +NS_NewPageBreakFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) 1.623 +{ 1.624 + NS_PRECONDITION(aPresShell, "null PresShell"); 1.625 + //check that we are only creating page break frames when printing 1.626 + NS_ASSERTION(aPresShell->GetPresContext()->IsPaginated(), "created a page break frame while not printing"); 1.627 + 1.628 + return new (aPresShell) nsPageBreakFrame(aContext); 1.629 +} 1.630 + 1.631 +NS_IMPL_FRAMEARENA_HELPERS(nsPageBreakFrame) 1.632 + 1.633 +nsPageBreakFrame::nsPageBreakFrame(nsStyleContext* aContext) : 1.634 + nsLeafFrame(aContext), mHaveReflowed(false) 1.635 +{ 1.636 +} 1.637 + 1.638 +nsPageBreakFrame::~nsPageBreakFrame() 1.639 +{ 1.640 +} 1.641 + 1.642 +nscoord 1.643 +nsPageBreakFrame::GetIntrinsicWidth() 1.644 +{ 1.645 + return nsPresContext::CSSPixelsToAppUnits(1); 1.646 +} 1.647 + 1.648 +nscoord 1.649 +nsPageBreakFrame::GetIntrinsicHeight() 1.650 +{ 1.651 + return 0; 1.652 +} 1.653 + 1.654 +nsresult 1.655 +nsPageBreakFrame::Reflow(nsPresContext* aPresContext, 1.656 + nsHTMLReflowMetrics& aDesiredSize, 1.657 + const nsHTMLReflowState& aReflowState, 1.658 + nsReflowStatus& aStatus) 1.659 +{ 1.660 + DO_GLOBAL_REFLOW_COUNT("nsPageBreakFrame"); 1.661 + DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); 1.662 + 1.663 + // Override reflow, since we don't want to deal with what our 1.664 + // computed values are. 1.665 + aDesiredSize.Width() = GetIntrinsicWidth(); 1.666 + aDesiredSize.Height() = (aReflowState.AvailableHeight() == NS_UNCONSTRAINEDSIZE ? 1.667 + 0 : aReflowState.AvailableHeight()); 1.668 + // round the height down to the nearest pixel 1.669 + aDesiredSize.Height() -= 1.670 + aDesiredSize.Height() % nsPresContext::CSSPixelsToAppUnits(1); 1.671 + 1.672 + // Note: not using NS_FRAME_FIRST_REFLOW here, since it's not clear whether 1.673 + // DidReflow will always get called before the next Reflow() call. 1.674 + mHaveReflowed = true; 1.675 + aStatus = NS_FRAME_COMPLETE; 1.676 + return NS_OK; 1.677 +} 1.678 + 1.679 +nsIAtom* 1.680 +nsPageBreakFrame::GetType() const 1.681 +{ 1.682 + return nsGkAtoms::pageBreakFrame; 1.683 +} 1.684 + 1.685 +#ifdef DEBUG_FRAME_DUMP 1.686 +nsresult 1.687 +nsPageBreakFrame::GetFrameName(nsAString& aResult) const 1.688 +{ 1.689 + return MakeFrameName(NS_LITERAL_STRING("PageBreak"), aResult); 1.690 +} 1.691 +#endif