1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "nsPageContentFrame.h"
7 #include "nsCSSFrameConstructor.h"
8 #include "nsPresContext.h"
9 #include "nsGkAtoms.h"
10 #include "nsIPresShell.h"
11 #include "nsSimplePageSequenceFrame.h"
12 
13 using namespace mozilla;
14 
NS_NewPageContentFrame(nsIPresShell * aPresShell,nsStyleContext * aContext)15 nsPageContentFrame* NS_NewPageContentFrame(nsIPresShell* aPresShell,
16                                            nsStyleContext* aContext) {
17   return new (aPresShell) nsPageContentFrame(aContext);
18 }
19 
NS_IMPL_FRAMEARENA_HELPERS(nsPageContentFrame)20 NS_IMPL_FRAMEARENA_HELPERS(nsPageContentFrame)
21 
22 void nsPageContentFrame::Reflow(nsPresContext* aPresContext,
23                                 ReflowOutput& aDesiredSize,
24                                 const ReflowInput& aReflowInput,
25                                 nsReflowStatus& aStatus) {
26   MarkInReflow();
27   DO_GLOBAL_REFLOW_COUNT("nsPageContentFrame");
28   DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
29   MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
30 
31   if (GetPrevInFlow() && (GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
32     nsresult rv =
33         aPresContext->PresShell()->FrameConstructor()->ReplicateFixedFrames(
34             this);
35     if (NS_FAILED(rv)) {
36       return;
37     }
38   }
39 
40   // Set our size up front, since some parts of reflow depend on it
41   // being already set.  Note that the computed height may be
42   // unconstrained; that's ok.  Consumers should watch out for that.
43   nsSize maxSize(aReflowInput.ComputedWidth(), aReflowInput.ComputedHeight());
44   SetSize(maxSize);
45 
46   // A PageContentFrame must always have one child: the canvas frame.
47   // Resize our frame allowing it only to be as big as we are
48   // XXX Pay attention to the page's border and padding...
49   if (mFrames.NotEmpty()) {
50     nsIFrame* frame = mFrames.FirstChild();
51     WritingMode wm = frame->GetWritingMode();
52     LogicalSize logicalSize(wm, maxSize);
53     ReflowInput kidReflowInput(aPresContext, aReflowInput, frame, logicalSize);
54     kidReflowInput.SetComputedBSize(logicalSize.BSize(wm));
55 
56     // Reflow the page content area
57     ReflowChild(frame, aPresContext, aDesiredSize, kidReflowInput, 0, 0, 0,
58                 aStatus);
59 
60     // The document element's background should cover the entire canvas, so
61     // take into account the combined area and any space taken up by
62     // absolutely positioned elements
63     nsMargin padding(0, 0, 0, 0);
64 
65     // XXXbz this screws up percentage padding (sets padding to zero
66     // in the percentage padding case)
67     kidReflowInput.mStylePadding->GetPadding(padding);
68 
69     // This is for shrink-to-fit, and therefore we want to use the
70     // scrollable overflow, since the purpose of shrink to fit is to
71     // make the content that ought to be reachable (represented by the
72     // scrollable overflow) fit in the page.
73     if (frame->HasOverflowAreas()) {
74       // The background covers the content area and padding area, so check
75       // for children sticking outside the child frame's padding edge
76       nscoord xmost = aDesiredSize.ScrollableOverflow().XMost();
77       if (xmost > aDesiredSize.Width()) {
78         nscoord widthToFit =
79             xmost + padding.right +
80             kidReflowInput.mStyleBorder->GetComputedBorderWidth(eSideRight);
81         float ratio = float(maxSize.width) / widthToFit;
82         NS_ASSERTION(ratio >= 0.0 && ratio < 1.0,
83                      "invalid shrink-to-fit ratio");
84         mPD->mShrinkToFitRatio = std::min(mPD->mShrinkToFitRatio, ratio);
85       }
86     }
87 
88     // Place and size the child
89     FinishReflowChild(frame, aPresContext, aDesiredSize, &kidReflowInput, 0, 0,
90                       0);
91 
92     NS_ASSERTION(aPresContext->IsDynamic() || !aStatus.IsFullyComplete() ||
93                      !frame->GetNextInFlow(),
94                  "bad child flow list");
95   }
96 
97   // Reflow our fixed frames
98   nsReflowStatus fixedStatus;
99   ReflowAbsoluteFrames(aPresContext, aDesiredSize, aReflowInput, fixedStatus);
100   NS_ASSERTION(fixedStatus.IsComplete(),
101                "fixed frames can be truncated, but not incomplete");
102 
103   // Return our desired size
104   WritingMode wm = aReflowInput.GetWritingMode();
105   aDesiredSize.ISize(wm) = aReflowInput.ComputedISize();
106   if (aReflowInput.ComputedBSize() != NS_UNCONSTRAINEDSIZE) {
107     aDesiredSize.BSize(wm) = aReflowInput.ComputedBSize();
108   }
109   FinishAndStoreOverflow(&aDesiredSize);
110 
111   NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aDesiredSize);
112 }
113 
AppendDirectlyOwnedAnonBoxes(nsTArray<OwnedAnonBox> & aResult)114 void nsPageContentFrame::AppendDirectlyOwnedAnonBoxes(
115     nsTArray<OwnedAnonBox>& aResult) {
116   MOZ_ASSERT(mFrames.FirstChild(),
117              "pageContentFrame must have a canvasFrame child");
118   aResult.AppendElement(mFrames.FirstChild());
119 }
120 
121 #ifdef DEBUG_FRAME_DUMP
GetFrameName(nsAString & aResult) const122 nsresult nsPageContentFrame::GetFrameName(nsAString& aResult) const {
123   return MakeFrameName(NS_LITERAL_STRING("PageContent"), aResult);
124 }
125 #endif
126