CLOSED TREE: TraceMonkey merge head. (a=blockers)
[mozilla-central.git] / layout / generic / nsViewportFrame.cpp
blobdb96f8c794db4967e0fe1320d0ded49dc34ec41a
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
24 * Alternatively, the contents of this file may be used under the terms of
25 * either of the GNU General Public License Version 2 or later (the "GPL"),
26 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
39 * rendering object that is the root of the frame tree, which contains
40 * the document's scrollbars and contains fixed-positioned elements
43 #include "nsCOMPtr.h"
44 #include "nsViewportFrame.h"
45 #include "nsHTMLParts.h"
46 #include "nsGkAtoms.h"
47 #include "nsIScrollableFrame.h"
48 #include "nsDisplayList.h"
49 #include "FrameLayerBuilder.h"
51 using namespace mozilla;
53 nsIFrame*
54 NS_NewViewportFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
56 return new (aPresShell) ViewportFrame(aContext);
59 NS_IMPL_FRAMEARENA_HELPERS(ViewportFrame)
61 NS_IMETHODIMP
62 ViewportFrame::Init(nsIContent* aContent,
63 nsIFrame* aParent,
64 nsIFrame* aPrevInFlow)
66 return Super::Init(aContent, aParent, aPrevInFlow);
69 void
70 ViewportFrame::DestroyFrom(nsIFrame* aDestructRoot)
72 mFixedContainer.DestroyFrames(this, aDestructRoot);
73 nsContainerFrame::DestroyFrom(aDestructRoot);
76 NS_IMETHODIMP
77 ViewportFrame::SetInitialChildList(nsIAtom* aListName,
78 nsFrameList& aChildList)
80 nsresult rv = NS_OK;
82 // See which child list to add the frames to
83 #ifdef NS_DEBUG
84 nsFrame::VerifyDirtyBitSet(aChildList);
85 #endif
86 if (nsGkAtoms::fixedList == aListName) {
87 rv = mFixedContainer.SetInitialChildList(this, aListName, aChildList);
89 else {
90 rv = nsContainerFrame::SetInitialChildList(aListName, aChildList);
93 return rv;
96 NS_IMETHODIMP
97 ViewportFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
98 const nsRect& aDirtyRect,
99 const nsDisplayListSet& aLists)
101 // We don't need any special painting or event handling. We just need to
102 // mark our visible out-of-flow frames (i.e., the fixed position frames) so
103 // that display list construction is guaranteed to recurse into their
104 // ancestors.
105 aBuilder->MarkFramesForDisplayList(this, mFixedContainer.GetChildList(),
106 aDirtyRect);
108 nsIFrame* kid = mFrames.FirstChild();
109 if (!kid)
110 return NS_OK;
112 // make the kid's BorderBackground our own. This ensures that the canvas
113 // frame's background becomes our own background and therefore appears
114 // below negative z-index elements.
115 return BuildDisplayListForChild(aBuilder, kid, aDirtyRect, aLists);
118 NS_IMETHODIMP
119 ViewportFrame::AppendFrames(nsIAtom* aListName,
120 nsFrameList& aFrameList)
122 nsresult rv = NS_OK;
124 if (nsGkAtoms::fixedList == aListName) {
125 rv = mFixedContainer.AppendFrames(this, aListName, aFrameList);
127 else {
128 NS_ASSERTION(!aListName, "unexpected child list");
129 NS_ASSERTION(GetChildList(nsnull).IsEmpty(), "Shouldn't have any kids!");
130 rv = nsContainerFrame::AppendFrames(aListName, aFrameList);
133 return rv;
136 NS_IMETHODIMP
137 ViewportFrame::InsertFrames(nsIAtom* aListName,
138 nsIFrame* aPrevFrame,
139 nsFrameList& aFrameList)
141 nsresult rv = NS_OK;
143 if (nsGkAtoms::fixedList == aListName) {
144 rv = mFixedContainer.InsertFrames(this, aListName, aPrevFrame, aFrameList);
146 else {
147 NS_ASSERTION(!aListName, "unexpected child list");
148 NS_ASSERTION(GetChildList(nsnull).IsEmpty(), "Shouldn't have any kids!");
149 rv = nsContainerFrame::InsertFrames(aListName, aPrevFrame, aFrameList);
152 return rv;
155 NS_IMETHODIMP
156 ViewportFrame::RemoveFrame(nsIAtom* aListName,
157 nsIFrame* aOldFrame)
159 nsresult rv = NS_OK;
161 if (nsGkAtoms::fixedList == aListName) {
162 mFixedContainer.RemoveFrame(this, aListName, aOldFrame);
163 rv = NS_OK;
165 else {
166 NS_ASSERTION(!aListName, "unexpected child list");
167 rv = nsContainerFrame::RemoveFrame(aListName, aOldFrame);
170 return rv;
173 nsIAtom*
174 ViewportFrame::GetAdditionalChildListName(PRInt32 aIndex) const
176 NS_PRECONDITION(aIndex >= 0, "illegal index");
178 if (0 == aIndex) {
179 return nsGkAtoms::fixedList;
182 return nsnull;
185 nsFrameList
186 ViewportFrame::GetChildList(nsIAtom* aListName) const
188 if (nsGkAtoms::fixedList == aListName)
189 return mFixedContainer.GetChildList();
191 return nsContainerFrame::GetChildList(aListName);
194 /* virtual */ nscoord
195 ViewportFrame::GetMinWidth(nsIRenderingContext *aRenderingContext)
197 nscoord result;
198 DISPLAY_MIN_WIDTH(this, result);
199 if (mFrames.IsEmpty())
200 result = 0;
201 else
202 result = mFrames.FirstChild()->GetMinWidth(aRenderingContext);
204 // XXXldb Deal with mFixedContainer (matters for SizeToContent)!
206 return result;
209 /* virtual */ nscoord
210 ViewportFrame::GetPrefWidth(nsIRenderingContext *aRenderingContext)
212 nscoord result;
213 DISPLAY_PREF_WIDTH(this, result);
214 if (mFrames.IsEmpty())
215 result = 0;
216 else
217 result = mFrames.FirstChild()->GetPrefWidth(aRenderingContext);
219 // XXXldb Deal with mFixedContainer (matters for SizeToContent)!
221 return result;
224 nsPoint
225 ViewportFrame::AdjustReflowStateForScrollbars(nsHTMLReflowState* aReflowState) const
227 // Calculate how much room is available for fixed frames. That means
228 // determining if the viewport is scrollable and whether the vertical and/or
229 // horizontal scrollbars are visible
231 // Get our prinicpal child frame and see if we're scrollable
232 nsIFrame* kidFrame = mFrames.FirstChild();
233 nsIScrollableFrame *scrollingFrame = do_QueryFrame(kidFrame);
235 if (scrollingFrame) {
236 nsMargin scrollbars = scrollingFrame->GetActualScrollbarSizes();
237 aReflowState->SetComputedWidth(aReflowState->ComputedWidth() -
238 scrollbars.LeftRight());
239 aReflowState->availableWidth -= scrollbars.LeftRight();
240 aReflowState->SetComputedHeightWithoutResettingResizeFlags(
241 aReflowState->ComputedHeight() - scrollbars.TopBottom());
242 return nsPoint(scrollbars.left, scrollbars.top);
244 return nsPoint(0, 0);
247 NS_IMETHODIMP
248 ViewportFrame::Reflow(nsPresContext* aPresContext,
249 nsHTMLReflowMetrics& aDesiredSize,
250 const nsHTMLReflowState& aReflowState,
251 nsReflowStatus& aStatus)
253 DO_GLOBAL_REFLOW_COUNT("ViewportFrame");
254 DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
255 NS_FRAME_TRACE_REFLOW_IN("ViewportFrame::Reflow");
257 // Initialize OUT parameters
258 aStatus = NS_FRAME_COMPLETE;
260 // Because |Reflow| sets mComputedHeight on the child to
261 // availableHeight.
262 AddStateBits(NS_FRAME_CONTAINS_RELATIVE_HEIGHT);
264 // Set our size up front, since some parts of reflow depend on it
265 // being already set. Note that the computed height may be
266 // unconstrained; that's ok. Consumers should watch out for that.
267 SetSize(nsSize(aReflowState.ComputedWidth(), aReflowState.ComputedHeight()));
269 // Reflow the main content first so that the placeholders of the
270 // fixed-position frames will be in the right places on an initial
271 // reflow.
272 nscoord kidHeight = 0;
274 nsresult rv = NS_OK;
276 if (mFrames.NotEmpty()) {
277 // Deal with a non-incremental reflow or an incremental reflow
278 // targeted at our one-and-only principal child frame.
279 if (aReflowState.ShouldReflowAllKids() ||
280 aReflowState.mFlags.mVResize ||
281 NS_SUBTREE_DIRTY(mFrames.FirstChild())) {
282 // Reflow our one-and-only principal child frame
283 nsIFrame* kidFrame = mFrames.FirstChild();
284 nsHTMLReflowMetrics kidDesiredSize;
285 nsSize availableSpace(aReflowState.availableWidth,
286 aReflowState.availableHeight);
287 nsHTMLReflowState kidReflowState(aPresContext, aReflowState,
288 kidFrame, availableSpace);
290 // Reflow the frame
291 kidReflowState.SetComputedHeight(aReflowState.ComputedHeight());
292 rv = ReflowChild(kidFrame, aPresContext, kidDesiredSize, kidReflowState,
293 0, 0, 0, aStatus);
294 kidHeight = kidDesiredSize.height;
296 FinishReflowChild(kidFrame, aPresContext, nsnull, kidDesiredSize, 0, 0, 0);
297 } else {
298 kidHeight = mFrames.FirstChild()->GetSize().height;
302 NS_ASSERTION(aReflowState.availableWidth != NS_UNCONSTRAINEDSIZE,
303 "shouldn't happen anymore");
305 // Return the max size as our desired size
306 aDesiredSize.width = aReflowState.availableWidth;
307 // Being flowed initially at an unconstrained height means we should
308 // return our child's intrinsic size.
309 aDesiredSize.height = aReflowState.ComputedHeight() != NS_UNCONSTRAINEDSIZE
310 ? aReflowState.ComputedHeight()
311 : kidHeight;
313 // Make a copy of the reflow state and change the computed width and height
314 // to reflect the available space for the fixed items
315 nsHTMLReflowState reflowState(aReflowState);
316 nsPoint offset = AdjustReflowStateForScrollbars(&reflowState);
318 #ifdef DEBUG
319 NS_ASSERTION(mFixedContainer.GetChildList().IsEmpty() ||
320 (offset.x == 0 && offset.y == 0),
321 "We don't handle correct positioning of fixed frames with "
322 "scrollbars in odd positions");
323 #endif
325 // Just reflow all the fixed-pos frames.
326 rv = mFixedContainer.Reflow(this, aPresContext, reflowState, aStatus,
327 reflowState.ComputedWidth(),
328 reflowState.ComputedHeight(),
329 PR_FALSE, PR_TRUE, PR_TRUE, // XXX could be optimized
330 nsnull /* ignore overflow */);
332 // If we were dirty then do a repaint
333 if (GetStateBits() & NS_FRAME_IS_DIRTY) {
334 nsRect damageRect(0, 0, aDesiredSize.width, aDesiredSize.height);
335 Invalidate(damageRect);
338 // XXX Should we do something to clip our children to this?
339 aDesiredSize.SetOverflowAreasToDesiredBounds();
341 NS_FRAME_TRACE_REFLOW_OUT("ViewportFrame::Reflow", aStatus);
342 NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
343 return rv;
346 nsIAtom*
347 ViewportFrame::GetType() const
349 return nsGkAtoms::viewportFrame;
352 /* virtual */ PRBool
353 ViewportFrame::IsContainingBlock() const
355 return PR_TRUE;
358 void
359 ViewportFrame::InvalidateInternal(const nsRect& aDamageRect,
360 nscoord aX, nscoord aY, nsIFrame* aForChild,
361 PRUint32 aFlags)
363 nsRect r = aDamageRect + nsPoint(aX, aY);
364 nsPresContext* presContext = PresContext();
365 presContext->NotifyInvalidation(r, aFlags);
367 if ((mState & NS_FRAME_HAS_CONTAINER_LAYER) &&
368 !(aFlags & INVALIDATE_NO_THEBES_LAYERS)) {
369 FrameLayerBuilder::InvalidateThebesLayerContents(this, r);
370 // Don't need to invalidate any more Thebes layers
371 aFlags |= INVALIDATE_NO_THEBES_LAYERS;
372 if (aFlags & INVALIDATE_ONLY_THEBES_LAYERS) {
373 return;
377 nsIFrame* parent = nsLayoutUtils::GetCrossDocParentFrame(this);
378 if (parent) {
379 if (!presContext->PresShell()->IsActive())
380 return;
381 nsPoint pt = -parent->GetOffsetToCrossDoc(this);
382 PRInt32 ourAPD = presContext->AppUnitsPerDevPixel();
383 PRInt32 parentAPD = parent->PresContext()->AppUnitsPerDevPixel();
384 r = r.ConvertAppUnitsRoundOut(ourAPD, parentAPD);
385 parent->InvalidateInternal(r, pt.x, pt.y, this,
386 aFlags | INVALIDATE_CROSS_DOC);
387 return;
389 InvalidateRoot(r, aFlags);
392 #ifdef DEBUG
393 NS_IMETHODIMP
394 ViewportFrame::GetFrameName(nsAString& aResult) const
396 return MakeFrameName(NS_LITERAL_STRING("Viewport"), aResult);
398 #endif