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
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.
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
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
;
54 NS_NewViewportFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
)
56 return new (aPresShell
) ViewportFrame(aContext
);
59 NS_IMPL_FRAMEARENA_HELPERS(ViewportFrame
)
62 ViewportFrame::Init(nsIContent
* aContent
,
64 nsIFrame
* aPrevInFlow
)
66 return Super::Init(aContent
, aParent
, aPrevInFlow
);
70 ViewportFrame::DestroyFrom(nsIFrame
* aDestructRoot
)
72 mFixedContainer
.DestroyFrames(this, aDestructRoot
);
73 nsContainerFrame::DestroyFrom(aDestructRoot
);
77 ViewportFrame::SetInitialChildList(nsIAtom
* aListName
,
78 nsFrameList
& aChildList
)
82 // See which child list to add the frames to
84 nsFrame::VerifyDirtyBitSet(aChildList
);
86 if (nsGkAtoms::fixedList
== aListName
) {
87 rv
= mFixedContainer
.SetInitialChildList(this, aListName
, aChildList
);
90 rv
= nsContainerFrame::SetInitialChildList(aListName
, aChildList
);
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
105 aBuilder
->MarkFramesForDisplayList(this, mFixedContainer
.GetChildList(),
108 nsIFrame
* kid
= mFrames
.FirstChild();
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
);
119 ViewportFrame::AppendFrames(nsIAtom
* aListName
,
120 nsFrameList
& aFrameList
)
124 if (nsGkAtoms::fixedList
== aListName
) {
125 rv
= mFixedContainer
.AppendFrames(this, aListName
, aFrameList
);
128 NS_ASSERTION(!aListName
, "unexpected child list");
129 NS_ASSERTION(GetChildList(nsnull
).IsEmpty(), "Shouldn't have any kids!");
130 rv
= nsContainerFrame::AppendFrames(aListName
, aFrameList
);
137 ViewportFrame::InsertFrames(nsIAtom
* aListName
,
138 nsIFrame
* aPrevFrame
,
139 nsFrameList
& aFrameList
)
143 if (nsGkAtoms::fixedList
== aListName
) {
144 rv
= mFixedContainer
.InsertFrames(this, aListName
, aPrevFrame
, aFrameList
);
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
);
156 ViewportFrame::RemoveFrame(nsIAtom
* aListName
,
161 if (nsGkAtoms::fixedList
== aListName
) {
162 mFixedContainer
.RemoveFrame(this, aListName
, aOldFrame
);
166 NS_ASSERTION(!aListName
, "unexpected child list");
167 rv
= nsContainerFrame::RemoveFrame(aListName
, aOldFrame
);
174 ViewportFrame::GetAdditionalChildListName(PRInt32 aIndex
) const
176 NS_PRECONDITION(aIndex
>= 0, "illegal index");
179 return nsGkAtoms::fixedList
;
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
)
198 DISPLAY_MIN_WIDTH(this, result
);
199 if (mFrames
.IsEmpty())
202 result
= mFrames
.FirstChild()->GetMinWidth(aRenderingContext
);
204 // XXXldb Deal with mFixedContainer (matters for SizeToContent)!
209 /* virtual */ nscoord
210 ViewportFrame::GetPrefWidth(nsIRenderingContext
*aRenderingContext
)
213 DISPLAY_PREF_WIDTH(this, result
);
214 if (mFrames
.IsEmpty())
217 result
= mFrames
.FirstChild()->GetPrefWidth(aRenderingContext
);
219 // XXXldb Deal with mFixedContainer (matters for SizeToContent)!
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);
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
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
272 nscoord kidHeight
= 0;
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
);
291 kidReflowState
.SetComputedHeight(aReflowState
.ComputedHeight());
292 rv
= ReflowChild(kidFrame
, aPresContext
, kidDesiredSize
, kidReflowState
,
294 kidHeight
= kidDesiredSize
.height
;
296 FinishReflowChild(kidFrame
, aPresContext
, nsnull
, kidDesiredSize
, 0, 0, 0);
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()
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
);
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");
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
);
347 ViewportFrame::GetType() const
349 return nsGkAtoms::viewportFrame
;
353 ViewportFrame::IsContainingBlock() const
359 ViewportFrame::InvalidateInternal(const nsRect
& aDamageRect
,
360 nscoord aX
, nscoord aY
, nsIFrame
* aForChild
,
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
) {
377 nsIFrame
* parent
= nsLayoutUtils::GetCrossDocParentFrame(this);
379 if (!presContext
->PresShell()->IsActive())
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
);
389 InvalidateRoot(r
, aFlags
);
394 ViewportFrame::GetFrameName(nsAString
& aResult
) const
396 return MakeFrameName(NS_LITERAL_STRING("Viewport"), aResult
);