layout/generic/nsPageFrame.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "nsPageFrame.h"
     7 #include "nsPresContext.h"
     8 #include "nsRenderingContext.h"
     9 #include "nsGkAtoms.h"
    10 #include "nsIPresShell.h"
    11 #include "nsPageContentFrame.h"
    12 #include "nsDisplayList.h"
    13 #include "nsLayoutUtils.h" // for function BinarySearchForPosition
    14 #include "nsSimplePageSequenceFrame.h" // for nsSharedPageData
    15 #include "nsTextFormatter.h" // for page number localization formatting
    16 #include "nsBidiUtils.h"
    17 #include "nsIPrintSettings.h"
    19 #include "prlog.h"
    20 #ifdef PR_LOGGING 
    21 extern PRLogModuleInfo *GetLayoutPrintingLog();
    22 #define PR_PL(_p1)  PR_LOG(GetLayoutPrintingLog(), PR_LOG_DEBUG, _p1)
    23 #else
    24 #define PR_PL(_p1)
    25 #endif
    27 using namespace mozilla;
    29 nsIFrame*
    30 NS_NewPageFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
    31 {
    32   return new (aPresShell) nsPageFrame(aContext);
    33 }
    35 NS_IMPL_FRAMEARENA_HELPERS(nsPageFrame)
    37 nsPageFrame::nsPageFrame(nsStyleContext* aContext)
    38 : nsContainerFrame(aContext)
    39 {
    40 }
    42 nsPageFrame::~nsPageFrame()
    43 {
    44 }
    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
    55   NS_ASSERTION(mFrames.FirstChild() &&
    56                nsGkAtoms::pageContentFrame == mFrames.FirstChild()->GetType(),
    57                "pageFrame must have a pageContentFrame child");
    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     }
    90     nsHTMLReflowState kidReflowState(aPresContext, aReflowState, frame, maxSize);
    91     kidReflowState.mFlags.mIsTopOfPage = true;
    92     kidReflowState.mFlags.mTableIsSplittable = true;
    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     }
   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     }
   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     }
   128     kidReflowState.SetComputedWidth(maxWidth);
   129     kidReflowState.SetComputedHeight(maxHeight);
   131     // calc location of frame
   132     nscoord xc = pageContentMargin.left;
   133     nscoord yc = pageContentMargin.top;
   135     // Get the child's desired size
   136     ReflowChild(frame, aPresContext, aDesiredSize, kidReflowState, xc, yc, 0, aStatus);
   138     // Place and size the child
   139     FinishReflowChild(frame, aPresContext, aDesiredSize, &kidReflowState, xc, yc, 0);
   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()));
   147   // Return our desired size
   148   aDesiredSize.Width() = aReflowState.AvailableWidth();
   149   if (aReflowState.AvailableHeight() != NS_UNCONSTRAINEDSIZE) {
   150     aDesiredSize.Height() = aReflowState.AvailableHeight();
   151   }
   153   aDesiredSize.SetOverflowAreasToDesiredBounds();
   154   FinishAndStoreOverflow(&aDesiredSize);
   156   PR_PL(("PageFrame::Reflow %p ", this));
   157   PR_PL(("[%d,%d]\n", aReflowState.AvailableWidth(), aReflowState.AvailableHeight()));
   159   NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
   160   return NS_OK;
   161 }
   163 nsIAtom*
   164 nsPageFrame::GetType() const
   165 {
   166   return nsGkAtoms::pageFrame; 
   167 }
   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
   177 void 
   178 nsPageFrame::ProcessSpecialCodes(const nsString& aStr, nsString& aNewStr)
   179 {
   181   aNewStr = aStr;
   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   }
   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   }
   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   }
   211   NS_NAMED_LITERAL_STRING(kTitle, "&T");
   212   if (aStr.Find(kTitle) != kNotFound) {
   213     aNewStr.ReplaceSubstring(kTitle.get(), mPD->mDocTitle.get());
   214   }
   216   NS_NAMED_LITERAL_STRING(kDocURL, "&U");
   217   if (aStr.Find(kDocURL) != kNotFound) {
   218     aNewStr.ReplaceSubstring(kDocURL.get(), mPD->mDocURL.get());
   219   }
   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 }
   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());
   239   nscoord x = aRect.x;
   240   switch (aJust) {
   241     case nsIPrintSettings::kJustLeft:
   242       x += mPD->mEdgePaperMargin.left;
   243       break;
   245     case nsIPrintSettings::kJustCenter:
   246       x += (aRect.width - width) / 2;
   247       break;
   249     case nsIPrintSettings::kJustRight:
   250       x += aRect.width - width - mPD->mEdgePaperMargin.right;
   251       break;
   252   } // switch
   254   return x;
   255 }
   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++;
   281   if (numStrs == 0) return;
   282   nscoord strSpace = aRect.width / numStrs;
   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 }
   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 {
   321   nscoord contentWidth = aWidth - (mPD->mEdgePaperMargin.left + mPD->mEdgePaperMargin.right);
   323   if ((aHeaderFooter == eHeader && aHeight < mPD->mReflowMargin.top) ||
   324       (aHeaderFooter == eFooter && aHeight < mPD->mReflowMargin.bottom)) {
   325     nsAutoString str;
   326     ProcessSpecialCodes(aStr, str);
   328     int32_t indx;
   329     int32_t textWidth = 0;
   330     const char16_t* text = str.get();
   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     }
   359     if (HasRTLChars(str)) {
   360       PresContext()->SetBidiEnabled();
   361     }
   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     }
   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 }
   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;
   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 }
   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 }
   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 }
   454 static void PaintHeaderFooter(nsIFrame* aFrame, nsRenderingContext* aCtx,
   455                               const nsRect& aDirtyRect, nsPoint aPt)
   456 {
   457   static_cast<nsPageFrame*>(aFrame)->PaintHeaderFooter(*aCtx, aPt);
   458 }
   460 static gfx3DMatrix ComputePageTransform(nsIFrame* aFrame, float aAppUnitsPerPixel)
   461 {
   462   float scale = aFrame->PresContext()->GetPageScale();
   463   return gfx3DMatrix::ScalingMatrix(scale, scale, 1);
   464 }
   466 //------------------------------------------------------------------------------
   467 void
   468 nsPageFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
   469                               const nsRect&           aDirtyRect,
   470                               const nsDisplayListSet& aLists)
   471 {
   472   nsDisplayListCollection set;
   474   if (PresContext()->IsScreen()) {
   475     DisplayBorderBackgroundOutline(aBuilder, aLists);
   476   }
   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);
   500   nsDisplayList content;
   501   {
   502     DisplayListClipState::AutoSaveRestore clipState(aBuilder);
   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);
   509     child->BuildDisplayListForStackingContext(aBuilder,
   510       child->GetVisualOverflowRectRelativeToSelf(), &content);
   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     }
   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   }
   533   content.AppendNewToTop(new (aBuilder) nsDisplayTransform(aBuilder, child, &content, ::ComputePageTransform));
   535   set.Content()->AppendToTop(&content);
   537   if (PresContext()->IsRootPaginatedDocument()) {
   538     set.Content()->AppendNewToTop(new (aBuilder)
   539         nsDisplayGeneric(aBuilder, this, ::PaintHeaderFooter,
   540                          "HeaderFooter",
   541                          nsDisplayItem::TYPE_HEADER_FOOTER));
   542   }
   544   set.MoveTo(aLists);
   545 }
   547 //------------------------------------------------------------------------------
   548 void
   549 nsPageFrame::SetPageNumInfo(int32_t aPageNumber, int32_t aTotalPages) 
   550 { 
   551   mPageNum     = aPageNumber; 
   552   mTotNumPages = aTotalPages;
   553 }
   556 void
   557 nsPageFrame::PaintHeaderFooter(nsRenderingContext& aRenderingContext,
   558                                nsPoint aPt)
   559 {
   560   nsPresContext* pc = PresContext();
   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   }
   569   nsRect rect(aPt, mRect.Size());
   570   aRenderingContext.SetColor(NS_RGB(0,0,0));
   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));
   579   aRenderingContext.SetFont(fontMet);
   581   nscoord ascent = 0;
   582   nscoord visibleHeight = 0;
   583   if (fontMet) {
   584     visibleHeight = fontMet->MaxHeight();
   585     ascent = fontMet->MaxAscent();
   586   }
   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);
   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 }
   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   }
   616 }
   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");
   625   return new (aPresShell) nsPageBreakFrame(aContext);
   626 }
   628 NS_IMPL_FRAMEARENA_HELPERS(nsPageBreakFrame)
   630 nsPageBreakFrame::nsPageBreakFrame(nsStyleContext* aContext) :
   631   nsLeafFrame(aContext), mHaveReflowed(false)
   632 {
   633 }
   635 nsPageBreakFrame::~nsPageBreakFrame()
   636 {
   637 }
   639 nscoord
   640 nsPageBreakFrame::GetIntrinsicWidth()
   641 {
   642   return nsPresContext::CSSPixelsToAppUnits(1);
   643 }
   645 nscoord
   646 nsPageBreakFrame::GetIntrinsicHeight()
   647 {
   648   return 0;
   649 }
   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);
   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);
   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 }
   676 nsIAtom*
   677 nsPageBreakFrame::GetType() const
   678 {
   679   return nsGkAtoms::pageBreakFrame; 
   680 }
   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