Bumping manifests a=b2g-bump
[gecko.git] / layout / generic / nsViewportFrame.cpp
blobdb006087908c4d6c2b61d6052c202daf1ca7eee3
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 /*
7 * rendering object that is the root of the frame tree, which contains
8 * the document's scrollbars and contains fixed-positioned elements
9 */
11 #include "nsViewportFrame.h"
12 #include "nsGkAtoms.h"
13 #include "nsIScrollableFrame.h"
14 #include "nsSubDocumentFrame.h"
15 #include "nsAbsoluteContainingBlock.h"
16 #include "GeckoProfiler.h"
18 using namespace mozilla;
20 ViewportFrame*
21 NS_NewViewportFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
23 return new (aPresShell) ViewportFrame(aContext);
26 NS_IMPL_FRAMEARENA_HELPERS(ViewportFrame)
27 NS_QUERYFRAME_HEAD(ViewportFrame)
28 NS_QUERYFRAME_ENTRY(ViewportFrame)
29 NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
31 void
32 ViewportFrame::Init(nsIContent* aContent,
33 nsContainerFrame* aParent,
34 nsIFrame* aPrevInFlow)
36 Super::Init(aContent, aParent, aPrevInFlow);
38 nsIFrame* parent = nsLayoutUtils::GetCrossDocParentFrame(this);
39 if (parent) {
40 nsFrameState state = parent->GetStateBits();
42 mState |= state & (NS_FRAME_IN_POPUP);
46 void
47 ViewportFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
48 const nsRect& aDirtyRect,
49 const nsDisplayListSet& aLists)
51 PROFILER_LABEL("ViewportFrame", "BuildDisplayList",
52 js::ProfileEntry::Category::GRAPHICS);
54 nsIFrame* kid = mFrames.FirstChild();
55 if (!kid)
56 return;
58 // make the kid's BorderBackground our own. This ensures that the canvas
59 // frame's background becomes our own background and therefore appears
60 // below negative z-index elements.
61 BuildDisplayListForChild(aBuilder, kid, aDirtyRect, aLists);
64 #ifdef DEBUG
65 void
66 ViewportFrame::SetInitialChildList(ChildListID aListID,
67 nsFrameList& aChildList)
69 nsFrame::VerifyDirtyBitSet(aChildList);
70 nsContainerFrame::SetInitialChildList(aListID, aChildList);
73 void
74 ViewportFrame::AppendFrames(ChildListID aListID,
75 nsFrameList& aFrameList)
77 NS_ASSERTION(aListID == kPrincipalList, "unexpected child list");
78 NS_ASSERTION(GetChildList(aListID).IsEmpty(), "Shouldn't have any kids!");
79 nsContainerFrame::AppendFrames(aListID, aFrameList);
82 void
83 ViewportFrame::InsertFrames(ChildListID aListID,
84 nsIFrame* aPrevFrame,
85 nsFrameList& aFrameList)
87 NS_ASSERTION(aListID == kPrincipalList, "unexpected child list");
88 NS_ASSERTION(GetChildList(aListID).IsEmpty(), "Shouldn't have any kids!");
89 nsContainerFrame::InsertFrames(aListID, aPrevFrame, aFrameList);
92 void
93 ViewportFrame::RemoveFrame(ChildListID aListID,
94 nsIFrame* aOldFrame)
96 NS_ASSERTION(aListID == kPrincipalList, "unexpected child list");
97 nsContainerFrame::RemoveFrame(aListID, aOldFrame);
99 #endif
101 /* virtual */ nscoord
102 ViewportFrame::GetMinISize(nsRenderingContext *aRenderingContext)
104 nscoord result;
105 DISPLAY_MIN_WIDTH(this, result);
106 if (mFrames.IsEmpty())
107 result = 0;
108 else
109 result = mFrames.FirstChild()->GetMinISize(aRenderingContext);
111 return result;
114 /* virtual */ nscoord
115 ViewportFrame::GetPrefISize(nsRenderingContext *aRenderingContext)
117 nscoord result;
118 DISPLAY_PREF_WIDTH(this, result);
119 if (mFrames.IsEmpty())
120 result = 0;
121 else
122 result = mFrames.FirstChild()->GetPrefISize(aRenderingContext);
124 return result;
127 nsPoint
128 ViewportFrame::AdjustReflowStateForScrollbars(nsHTMLReflowState* aReflowState) const
130 // Get our prinicpal child frame and see if we're scrollable
131 nsIFrame* kidFrame = mFrames.FirstChild();
132 nsIScrollableFrame* scrollingFrame = do_QueryFrame(kidFrame);
134 if (scrollingFrame) {
135 nsMargin scrollbars = scrollingFrame->GetActualScrollbarSizes();
136 aReflowState->SetComputedWidth(aReflowState->ComputedWidth() -
137 scrollbars.LeftRight());
138 aReflowState->AvailableWidth() -= scrollbars.LeftRight();
139 aReflowState->SetComputedHeightWithoutResettingResizeFlags(
140 aReflowState->ComputedHeight() - scrollbars.TopBottom());
141 return nsPoint(scrollbars.left, scrollbars.top);
143 return nsPoint(0, 0);
146 nsRect
147 ViewportFrame::AdjustReflowStateAsContainingBlock(nsHTMLReflowState* aReflowState) const
149 #ifdef DEBUG
150 nsPoint offset =
151 #endif
152 AdjustReflowStateForScrollbars(aReflowState);
154 NS_ASSERTION(GetAbsoluteContainingBlock()->GetChildList().IsEmpty() ||
155 (offset.x == 0 && offset.y == 0),
156 "We don't handle correct positioning of fixed frames with "
157 "scrollbars in odd positions");
159 // If a scroll position clamping scroll-port size has been set, layout
160 // fixed position elements to this size instead of the computed size.
161 nsRect rect(0, 0, aReflowState->ComputedWidth(), aReflowState->ComputedHeight());
162 nsIPresShell* ps = PresContext()->PresShell();
163 if (ps->IsScrollPositionClampingScrollPortSizeSet()) {
164 rect.SizeTo(ps->GetScrollPositionClampingScrollPortSize());
167 // Make sure content document fixed-position margins are respected.
168 rect.Deflate(ps->GetContentDocumentFixedPositionMargins());
169 return rect;
172 void
173 ViewportFrame::Reflow(nsPresContext* aPresContext,
174 nsHTMLReflowMetrics& aDesiredSize,
175 const nsHTMLReflowState& aReflowState,
176 nsReflowStatus& aStatus)
178 DO_GLOBAL_REFLOW_COUNT("ViewportFrame");
179 DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
180 NS_FRAME_TRACE_REFLOW_IN("ViewportFrame::Reflow");
182 // Initialize OUT parameters
183 aStatus = NS_FRAME_COMPLETE;
185 // Because |Reflow| sets mComputedHeight on the child to
186 // availableHeight.
187 AddStateBits(NS_FRAME_CONTAINS_RELATIVE_HEIGHT);
189 // Set our size up front, since some parts of reflow depend on it
190 // being already set. Note that the computed height may be
191 // unconstrained; that's ok. Consumers should watch out for that.
192 SetSize(nsSize(aReflowState.ComputedWidth(), aReflowState.ComputedHeight()));
194 // Reflow the main content first so that the placeholders of the
195 // fixed-position frames will be in the right places on an initial
196 // reflow.
197 nscoord kidBSize = 0;
198 WritingMode wm = aReflowState.GetWritingMode();
200 if (mFrames.NotEmpty()) {
201 // Deal with a non-incremental reflow or an incremental reflow
202 // targeted at our one-and-only principal child frame.
203 if (aReflowState.ShouldReflowAllKids() ||
204 aReflowState.mFlags.mVResize ||
205 NS_SUBTREE_DIRTY(mFrames.FirstChild())) {
206 // Reflow our one-and-only principal child frame
207 nsIFrame* kidFrame = mFrames.FirstChild();
208 nsHTMLReflowMetrics kidDesiredSize(aReflowState);
209 WritingMode wm = kidFrame->GetWritingMode();
210 LogicalSize availableSpace = aReflowState.AvailableSize(wm);
211 nsHTMLReflowState kidReflowState(aPresContext, aReflowState,
212 kidFrame, availableSpace);
214 // Reflow the frame
215 kidReflowState.SetComputedHeight(aReflowState.ComputedHeight());
216 ReflowChild(kidFrame, aPresContext, kidDesiredSize, kidReflowState,
217 0, 0, 0, aStatus);
218 kidBSize = kidDesiredSize.BSize(wm);
220 FinishReflowChild(kidFrame, aPresContext, kidDesiredSize, nullptr, 0, 0, 0);
221 } else {
222 kidBSize = LogicalSize(wm, mFrames.FirstChild()->GetSize()).BSize(wm);
226 NS_ASSERTION(aReflowState.AvailableWidth() != NS_UNCONSTRAINEDSIZE,
227 "shouldn't happen anymore");
229 // Return the max size as our desired size
230 LogicalSize maxSize(wm, aReflowState.AvailableISize(),
231 // Being flowed initially at an unconstrained block size
232 // means we should return our child's intrinsic size.
233 aReflowState.ComputedBSize() != NS_UNCONSTRAINEDSIZE
234 ? aReflowState.ComputedBSize()
235 : kidBSize);
236 aDesiredSize.SetSize(wm, maxSize);
237 aDesiredSize.SetOverflowAreasToDesiredBounds();
239 if (mFrames.NotEmpty()) {
240 ConsiderChildOverflow(aDesiredSize.mOverflowAreas, mFrames.FirstChild());
243 if (IsAbsoluteContainer()) {
244 // Make a copy of the reflow state and change the computed width and height
245 // to reflect the available space for the fixed items
246 nsHTMLReflowState reflowState(aReflowState);
248 if (reflowState.AvailableBSize() == NS_UNCONSTRAINEDSIZE) {
249 // We have an intrinsic-height document with abs-pos/fixed-pos children.
250 // Set the available height and mComputedHeight to our chosen height.
251 reflowState.AvailableBSize() = maxSize.BSize(wm);
252 // Not having border/padding simplifies things
253 NS_ASSERTION(reflowState.ComputedPhysicalBorderPadding() == nsMargin(0,0,0,0),
254 "Viewports can't have border/padding");
255 reflowState.SetComputedBSize(maxSize.BSize(wm));
258 nsRect rect = AdjustReflowStateAsContainingBlock(&reflowState);
260 // Just reflow all the fixed-pos frames.
261 GetAbsoluteContainingBlock()->Reflow(this, aPresContext, reflowState, aStatus,
262 rect,
263 false, true, true, // XXX could be optimized
264 &aDesiredSize.mOverflowAreas);
267 // If we were dirty then do a repaint
268 if (GetStateBits() & NS_FRAME_IS_DIRTY) {
269 InvalidateFrame();
272 // Clipping is handled by the document container (e.g., nsSubDocumentFrame),
273 // so we don't need to change our overflow areas.
274 bool overflowChanged = FinishAndStoreOverflow(&aDesiredSize);
275 if (overflowChanged) {
276 // We may need to alert our container to get it to pick up the
277 // overflow change.
278 nsSubDocumentFrame* container = static_cast<nsSubDocumentFrame*>
279 (nsLayoutUtils::GetCrossDocParentFrame(this));
280 if (container && !container->ShouldClipSubdocument()) {
281 container->PresContext()->PresShell()->
282 FrameNeedsReflow(container, nsIPresShell::eResize, NS_FRAME_IS_DIRTY);
286 NS_FRAME_TRACE_REFLOW_OUT("ViewportFrame::Reflow", aStatus);
287 NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
290 nsIAtom*
291 ViewportFrame::GetType() const
293 return nsGkAtoms::viewportFrame;
296 #ifdef DEBUG_FRAME_DUMP
297 nsresult
298 ViewportFrame::GetFrameName(nsAString& aResult) const
300 return MakeFrameName(NS_LITERAL_STRING("Viewport"), aResult);
302 #endif