layout/generic/nsPageFrame.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial